From 39ebaa9841cf8022a5de8bc09024f99203cc8dcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Tue, 14 Apr 2026 09:02:23 +0200 Subject: [PATCH 001/494] Add OpenSpec proposal for staging environments Proposal, design, specs, and tasks for persistent staging instance and ephemeral PR preview environments on the existing Hetzner server. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../staging-environments/.openspec.yaml | 2 + .../changes/staging-environments/design.md | 55 +++++++++++++++++++ .../changes/staging-environments/proposal.md | 29 ++++++++++ .../specs/infrastructure/spec.md | 32 +++++++++++ .../specs/staging-environment/spec.md | 55 +++++++++++++++++++ .../changes/staging-environments/tasks.md | 38 +++++++++++++ 6 files changed, 211 insertions(+) create mode 100644 openspec/changes/staging-environments/.openspec.yaml create mode 100644 openspec/changes/staging-environments/design.md create mode 100644 openspec/changes/staging-environments/proposal.md create mode 100644 openspec/changes/staging-environments/specs/infrastructure/spec.md create mode 100644 openspec/changes/staging-environments/specs/staging-environment/spec.md create mode 100644 openspec/changes/staging-environments/tasks.md diff --git a/openspec/changes/staging-environments/.openspec.yaml b/openspec/changes/staging-environments/.openspec.yaml new file mode 100644 index 0000000..76a85e8 --- /dev/null +++ b/openspec/changes/staging-environments/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-driven +created: 2026-04-14 diff --git a/openspec/changes/staging-environments/design.md b/openspec/changes/staging-environments/design.md new file mode 100644 index 0000000..23b1a5e --- /dev/null +++ b/openspec/changes/staging-environments/design.md @@ -0,0 +1,55 @@ +## Context + +trails.cool runs on a single Hetzner cx23 server (2 vCPU, 4 GB RAM) with Docker Compose. Production uses Caddy as reverse proxy, PostgreSQL + PostGIS, and three CD workflows (apps, infra, brouter). There is currently no staging or preview environment — changes go straight to production after CI passes. + +The server has headroom for lightweight additional containers. Caddy handles automatic TLS via Let's Encrypt and supports on-demand TLS for wildcard subdomains. + +## Goals / Non-Goals + +**Goals:** +- Persistent staging instance at `staging.trails.cool` that auto-deploys from main +- Ephemeral PR preview environments at `pr-.staging.trails.cool` that spin up on PR open and tear down on PR close +- Full database isolation between production, staging, and each PR preview +- Minimal resource overhead — share BRouter and infrastructure services (Prometheus, Grafana, Loki) with production +- PR previews accessible to anyone with the URL (no auth required for the preview itself) + +**Non-Goals:** +- Staging federation (ActivityPub) — staging instances don't need to federate +- Staging email delivery — use log transport or discard +- Load testing or performance parity with production +- PR previews for infrastructure-only changes +- Separate server provisioning + +## Decisions + +### 1. Shared server, separate Docker Compose projects +**Choice**: Run staging as a separate Docker Compose project (`trails-staging`) on the same server, sharing the host network and BRouter/monitoring containers with production. +**Rationale**: A separate Compose project gives clean namespace isolation (container names, volumes) without a second server. Sharing BRouter and monitoring avoids duplicating heavy services. +**Alternative considered**: Docker Compose profiles — simpler but risks accidental cross-contamination between production and staging in the same project. + +### 2. Caddy on-demand TLS with wildcard routing +**Choice**: Use Caddy's `on_demand_tls` with a wildcard site block for `*.staging.trails.cool`. A small validation endpoint confirms which subdomains are active before Caddy obtains a certificate. +**Rationale**: Avoids pre-configuring Caddy for each PR. Caddy automatically provisions TLS certificates on first request. The validation endpoint prevents abuse (random subdomains triggering cert issuance). +**Alternative considered**: Wildcard certificate via DNS challenge — requires DNS API credentials and more complex setup. + +### 3. Per-PR databases in shared PostgreSQL +**Choice**: PR previews use per-PR databases (`trails_pr_123`) in the production PostgreSQL instance. Staging uses `trails_staging`. Created by the workflow, dropped on PR close. +**Rationale**: PostgreSQL handles multiple databases efficiently. No need for a separate PostgreSQL container per preview. Drizzle Kit `push` handles schema setup. +**Alternative considered**: Separate PostgreSQL container per preview — full isolation but heavy resource cost. + +### 4. Port allocation scheme +**Choice**: Staging journal on port 3100, planner on 3101. PR previews on ports `3200 + (PR number * 2)` for journal and `3201 + (PR number * 2)` for planner. +**Rationale**: Deterministic port mapping from PR number. Production stays on 3000/3001. Port collisions are practically impossible (would need 50+ concurrent PRs). +**Alternative considered**: Docker DNS-based routing — would require a custom network resolver setup. + +### 5. GitHub Actions workflow +**Choice**: Single `cd-staging.yml` workflow handling both staging deploys (on main push) and PR preview lifecycle (on PR open/sync/close). +**Rationale**: Keeps staging logic in one place. Uses `github.event.action` to distinguish between deploy, update, and teardown. + +## Risks / Trade-offs + +- **Resource contention**: Staging and PR previews share CPU/memory with production. → Mitigation: Limit concurrent PR previews (e.g., max 3). Add memory limits to staging containers. Monitor via existing Grafana/cAdvisor. +- **Port exhaustion**: Many concurrent PRs could exhaust the port range. → Mitigation: Port scheme supports ~50 concurrent PRs, far more than needed. Cleanup job runs on PR close. +- **Database isolation**: PR databases share the same PostgreSQL instance as production. → Mitigation: Use separate database names and credentials. PR databases are disposable — created and dropped by the workflow. +- **Stale PR previews**: If a workflow fails to clean up, containers and databases linger. → Mitigation: Add a scheduled cleanup job that checks for closed PRs and removes their resources. +- **TLS rate limits**: Let's Encrypt has rate limits (50 certs/week per registered domain). → Mitigation: `*.staging.trails.cool` previews are subdomains of a single domain, counting as one. On-demand TLS with validation prevents abuse. diff --git a/openspec/changes/staging-environments/proposal.md b/openspec/changes/staging-environments/proposal.md new file mode 100644 index 0000000..9efb4f1 --- /dev/null +++ b/openspec/changes/staging-environments/proposal.md @@ -0,0 +1,29 @@ +## Why + +There is no way to test changes in a production-like environment before merging. The only testing options are local dev (`pnpm dev:full`) or deploying directly to production. This makes it risky to test features that depend on real infrastructure (Caddy TLS, Docker networking, PostgreSQL migrations, OAuth callbacks) and impossible for non-developers (e.g., design reviewers) to preview PRs. A staging environment would catch integration issues earlier and give PR reviewers a live URL to test against. + +## What Changes + +- Add a **persistent staging instance** (`staging.trails.cool` / `planner.staging.trails.cool`) running on the same Hetzner server as production, using a separate Docker Compose project with its own PostgreSQL database, port range, and Caddy configuration +- Add **ephemeral PR preview environments** that spin up automatically when a PR is opened, serve at `pr-.staging.trails.cool`, and tear down when the PR is merged or closed +- Add a **GitHub Actions workflow** (`cd-staging.yml`) that deploys the staging instance on pushes to main and manages PR preview lifecycle +- Add a **Docker Compose override** (`docker-compose.staging.yml`) for staging-specific configuration (ports, database, domain) +- Add **Caddy wildcard routing** for `*.staging.trails.cool` to dynamically route to the correct preview or staging container +- Add a **cleanup job** to tear down PR preview containers and their databases when PRs close + +## Capabilities + +### New Capabilities +- `staging-environment`: Persistent staging instance configuration, PR preview lifecycle, Docker Compose staging overrides, Caddy routing, GitHub Actions integration, database isolation, and cleanup + +### Modified Capabilities +- `infrastructure`: Caddy gains wildcard subdomain routing for staging; Docker Compose gains staging profiles and a staging-specific override file + +## Impact + +- **DNS**: Requires a wildcard DNS record `*.staging.trails.cool` pointing to the same server +- **TLS**: Caddy handles automatic TLS for staging subdomains via Let's Encrypt +- **Disk/memory**: Each PR preview runs journal + planner + a shared staging PostgreSQL instance on the production server. Resource usage scales with active PRs. +- **Database**: Staging uses a separate PostgreSQL database (`trails_staging`). PR previews use per-PR databases (`trails_pr_`), created and dropped by the workflow. +- **Secrets**: Staging shares the same SOPS-encrypted secrets as production (same server), with staging-specific overrides for domain and database. +- **GitHub Actions**: New workflow triggered on PR open/sync/close and main push. diff --git a/openspec/changes/staging-environments/specs/infrastructure/spec.md b/openspec/changes/staging-environments/specs/infrastructure/spec.md new file mode 100644 index 0000000..b670ca0 --- /dev/null +++ b/openspec/changes/staging-environments/specs/infrastructure/spec.md @@ -0,0 +1,32 @@ +## MODIFIED Requirements + +### Requirement: Caddy reverse proxy routing +Caddy SHALL route requests to staging and PR preview containers via wildcard subdomain matching, in addition to the existing production routing. + +#### Scenario: Staging subdomain routing +- **WHEN** a request arrives for `staging.trails.cool` +- **THEN** Caddy proxies it to the staging journal container on port 3100 + +#### Scenario: Planner staging routing +- **WHEN** a request arrives for `planner.staging.trails.cool` +- **THEN** Caddy proxies it to the staging planner container on port 3101 + +#### Scenario: PR preview routing +- **WHEN** a request arrives for `pr-123.staging.trails.cool` +- **THEN** Caddy proxies it to the PR 123 journal container on the correct dynamically assigned port + +#### Scenario: On-demand TLS for staging subdomains +- **WHEN** a first request arrives for a new staging subdomain +- **THEN** Caddy automatically provisions a TLS certificate via Let's Encrypt +- **AND** a validation endpoint confirms the subdomain is an active staging/preview environment before certificate issuance + +### Requirement: Docker Compose deployment +The staging environment SHALL be deployed as a separate Docker Compose project alongside production on the same server. + +#### Scenario: Staging compose project +- **WHEN** the staging deployment runs +- **THEN** it creates containers in the `trails-staging` project namespace, separate from the `trails-cool` production project + +#### Scenario: Shared services +- **WHEN** staging containers need BRouter routing +- **THEN** they connect to the production BRouter container via Docker network, not a duplicate instance diff --git a/openspec/changes/staging-environments/specs/staging-environment/spec.md b/openspec/changes/staging-environments/specs/staging-environment/spec.md new file mode 100644 index 0000000..bd53e20 --- /dev/null +++ b/openspec/changes/staging-environments/specs/staging-environment/spec.md @@ -0,0 +1,55 @@ +## ADDED Requirements + +### Requirement: Persistent staging instance +A persistent staging instance SHALL run at `staging.trails.cool` (journal) and `planner.staging.trails.cool` (planner), auto-deploying from main on every push. + +#### Scenario: Deploy staging on main push +- **WHEN** a commit is pushed to main that changes `apps/` or `packages/` +- **THEN** the staging journal and planner containers are rebuilt and redeployed with the latest main + +#### Scenario: Staging uses isolated database +- **WHEN** the staging instance is running +- **THEN** it uses the `trails_staging` database, separate from the production `trails` database + +#### Scenario: Staging is accessible +- **WHEN** a user navigates to `https://staging.trails.cool` +- **THEN** they see the journal app served over HTTPS with a valid TLS certificate + +### Requirement: PR preview environments +Ephemeral preview environments SHALL be created for each PR that changes app or package code. + +#### Scenario: Preview created on PR open +- **WHEN** a PR is opened that changes files in `apps/` or `packages/` +- **THEN** a preview environment is deployed at `pr-.staging.trails.cool` within 5 minutes +- **AND** a comment is posted on the PR with the preview URL + +#### Scenario: Preview updated on PR push +- **WHEN** new commits are pushed to a PR branch with an active preview +- **THEN** the preview containers are rebuilt and redeployed with the latest branch code + +#### Scenario: Preview torn down on PR close +- **WHEN** a PR is merged or closed +- **THEN** its preview containers are stopped and removed +- **AND** its database (`trails_pr_`) is dropped + +#### Scenario: Preview database isolation +- **WHEN** a PR preview is running +- **THEN** it uses a dedicated database `trails_pr_` with schema applied via Drizzle Kit push + +### Requirement: PR preview cleanup +A scheduled cleanup job SHALL remove orphaned preview resources from closed PRs. + +#### Scenario: Stale preview cleanup +- **WHEN** the cleanup job runs +- **THEN** any preview containers or databases belonging to closed/merged PRs are removed + +### Requirement: Resource limits +Staging and preview containers SHALL have resource limits to protect production. + +#### Scenario: Memory limits enforced +- **WHEN** a staging or preview container is running +- **THEN** it has a memory limit of 256MB per app container + +#### Scenario: Concurrent preview limit +- **WHEN** more than 3 PR previews are active +- **THEN** the oldest preview is torn down before the new one is created diff --git a/openspec/changes/staging-environments/tasks.md b/openspec/changes/staging-environments/tasks.md new file mode 100644 index 0000000..9c0d1cd --- /dev/null +++ b/openspec/changes/staging-environments/tasks.md @@ -0,0 +1,38 @@ +## 1. DNS & TLS Setup + +- [ ] 1.1 Add wildcard DNS record `*.staging.trails.cool` pointing to the Hetzner server IP +- [ ] 1.2 Add `staging.trails.cool` and `planner.staging.trails.cool` DNS A records + +## 2. Docker Compose Staging Configuration + +- [ ] 2.1 Create `infrastructure/docker-compose.staging.yml` with staging journal (port 3100), planner (port 3101), memory limits (256MB), and `trails_staging` database URL +- [ ] 2.2 Create `infrastructure/staging.env.template` documenting required staging environment variables (DOMAIN, DATABASE_URL, JWT_SECRET, SESSION_SECRET) +- [ ] 2.3 Add a shared Docker network (`trails-shared`) to production `docker-compose.yml` so staging can reach BRouter and PostgreSQL +- [ ] 2.4 Verify staging containers start with `docker compose -f docker-compose.staging.yml -p trails-staging up -d` on the server + +## 3. Caddy Wildcard Routing + +- [ ] 3.1 Add `staging.trails.cool` site block proxying to journal on port 3100 +- [ ] 3.2 Add `planner.staging.trails.cool` site block proxying to planner on port 3101 +- [ ] 3.3 Add `*.staging.trails.cool` wildcard site block with on-demand TLS for PR previews — extract PR number from subdomain, proxy to `localhost:3200 + (PR * 2)` +- [ ] 3.4 Create a TLS validation endpoint (small script or Caddy matcher) that checks if the requested subdomain corresponds to a running container +- [ ] 3.5 Reload Caddy and verify staging routes work with `curl -sf https://staging.trails.cool/api/health` + +## 4. GitHub Actions Workflow + +- [ ] 4.1 Create `.github/workflows/cd-staging.yml` triggered on push to main (paths: `apps/`, `packages/`) and on PR open/synchronize/close (same paths) +- [ ] 4.2 Implement the **staging deploy** job: build images, SSH to server, `docker compose -f docker-compose.staging.yml -p trails-staging pull && up -d`, run Drizzle push against `trails_staging` +- [ ] 4.3 Implement the **PR preview deploy** job: compute ports from PR number, create `trails_pr_` database if not exists, build images tagged with PR number, deploy containers, post preview URL as PR comment +- [ ] 4.4 Implement the **PR preview teardown** job: stop and remove PR containers, drop `trails_pr_` database, delete PR comment +- [ ] 4.5 Add the concurrent preview limit check: if >3 active previews, tear down the oldest before deploying a new one + +## 5. Cleanup & Safety + +- [ ] 5.1 Create a scheduled cleanup job (weekly cron in GitHub Actions or pg-boss on the server) that lists running `trails-pr-*` containers, checks PR status via `gh pr view`, and tears down orphans +- [ ] 5.2 Add memory limits (`deploy.resources.limits.memory: 256m`) to staging containers in the compose override +- [ ] 5.3 Test full lifecycle: open a test PR → verify preview deploys → push a commit → verify preview updates → close PR → verify teardown + +## 6. Documentation + +- [ ] 6.1 Add a "Staging & Previews" section to CLAUDE.md documenting the staging URL, PR preview URL pattern, port scheme, and how to debug staging issues +- [ ] 6.2 Update the Deployment table in CLAUDE.md with the new `cd-staging.yml` workflow From f75dd12f59b53406fdf09aa6dd160551ac42b6b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Tue, 14 Apr 2026 09:08:19 +0200 Subject: [PATCH 002/494] Fix pg-boss queue creation before work registration pg-boss v10 requires explicit queue creation via `createQueue()` before `schedule()` or `work()` can reference a queue. Without this, the planner crashes on startup in fresh databases (like CI) with "Queue not found". Co-Authored-By: Claude Opus 4.6 (1M context) --- packages/jobs/src/worker.test.ts | 11 +++++++++++ packages/jobs/src/worker.ts | 2 ++ 2 files changed, 13 insertions(+) diff --git a/packages/jobs/src/worker.test.ts b/packages/jobs/src/worker.test.ts index 893e238..76a3020 100644 --- a/packages/jobs/src/worker.test.ts +++ b/packages/jobs/src/worker.test.ts @@ -6,6 +6,7 @@ function createMockBoss() { return { start: vi.fn().mockResolvedValue(undefined), stop: vi.fn().mockResolvedValue(undefined), + createQueue: vi.fn().mockResolvedValue(undefined), schedule: vi.fn().mockResolvedValue(undefined), work: vi.fn().mockResolvedValue("worker-id"), }; @@ -22,6 +23,16 @@ describe("startWorker", () => { expect(boss.start).toHaveBeenCalled(); }); + it("creates queues before registering handlers", async () => { + const boss = createMockBoss(); + const jobs: JobDefinition[] = [{ name: "test-job", handler: vi.fn() }]; + + await startWorker(boss as never, jobs); + + expect(boss.createQueue).toHaveBeenCalledWith("test-job"); + expect(boss.createQueue).toHaveBeenCalledBefore(boss.work); + }); + it("registers job handlers", async () => { const boss = createMockBoss(); const handler = vi.fn(); diff --git a/packages/jobs/src/worker.ts b/packages/jobs/src/worker.ts index 63a90c2..ee56806 100644 --- a/packages/jobs/src/worker.ts +++ b/packages/jobs/src/worker.ts @@ -8,6 +8,8 @@ export async function startWorker( await boss.start(); for (const job of jobs) { + await boss.createQueue(job.name); + if (job.cron) { await boss.schedule(job.name, job.cron, undefined, { retryLimit: job.retryLimit, From fe57a690c01d9ae01f2d9440c1ac8875265d75a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Tue, 14 Apr 2026 12:13:09 +0200 Subject: [PATCH 003/494] Fix Dockerfiles: add jobs package for pg-boss resolution Both Dockerfiles were missing packages/jobs/package.json in the deps stage, causing pnpm install to skip pg-boss. Also copy app/jobs directories into the runtime stage so job handlers are available at runtime. Co-Authored-By: Claude Opus 4.6 (1M context) --- apps/journal/Dockerfile | 2 ++ apps/planner/Dockerfile | 2 ++ 2 files changed, 4 insertions(+) diff --git a/apps/journal/Dockerfile b/apps/journal/Dockerfile index 6d47d1b..dc609e4 100644 --- a/apps/journal/Dockerfile +++ b/apps/journal/Dockerfile @@ -14,6 +14,7 @@ COPY packages/i18n/package.json packages/i18n/ COPY packages/api/package.json packages/api/ COPY packages/map-core/package.json packages/map-core/ COPY packages/db/package.json packages/db/ +COPY packages/jobs/package.json packages/jobs/ RUN pnpm install --frozen-lockfile FROM base AS build @@ -32,6 +33,7 @@ COPY --from=deps /app/apps/journal/node_modules ./apps/journal/node_modules COPY --from=build /app/apps/journal/build ./apps/journal/build COPY --from=build /app/apps/journal/server.ts ./apps/journal/server.ts COPY --from=build /app/apps/journal/app/lib ./apps/journal/app/lib +COPY --from=build /app/apps/journal/app/jobs ./apps/journal/app/jobs COPY --from=build /app/apps/journal/package.json ./apps/journal/package.json COPY --from=build /app/packages ./packages diff --git a/apps/planner/Dockerfile b/apps/planner/Dockerfile index 1f6effb..a6f8a9a 100644 --- a/apps/planner/Dockerfile +++ b/apps/planner/Dockerfile @@ -12,6 +12,7 @@ COPY packages/map/package.json packages/map/ COPY packages/gpx/package.json packages/gpx/ COPY packages/i18n/package.json packages/i18n/ COPY packages/db/package.json packages/db/ +COPY packages/jobs/package.json packages/jobs/ RUN pnpm install --frozen-lockfile FROM base AS build @@ -30,6 +31,7 @@ COPY --from=deps /app/apps/planner/node_modules ./apps/planner/node_modules COPY --from=build /app/apps/planner/build ./apps/planner/build COPY --from=build /app/apps/planner/server.ts ./apps/planner/server.ts COPY --from=build /app/apps/planner/app/lib ./apps/planner/app/lib +COPY --from=build /app/apps/planner/app/jobs ./apps/planner/app/jobs COPY --from=build /app/apps/planner/package.json ./apps/planner/package.json COPY --from=build /app/packages ./packages From 7c207a2a983f4d452fb2ed44fdcf9a77273da49c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Tue, 14 Apr 2026 12:15:25 +0200 Subject: [PATCH 004/494] Add CI check for missing workspace packages in Dockerfiles Adds a script that verifies every packages/*/package.json is listed in all app Dockerfiles. Catches the recurring issue where adding a new workspace package breaks production because the Dockerfile deps stage doesn't know about it. Also fixes two pre-existing missing packages in the planner Dockerfile (api, map-core) caught by the new check. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/ci.yml | 7 +++++++ apps/planner/Dockerfile | 2 ++ scripts/check-dockerfiles.sh | 27 +++++++++++++++++++++++++++ 3 files changed, 36 insertions(+) create mode 100755 scripts/check-dockerfiles.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7fd619e..3240a80 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -38,6 +38,13 @@ jobs: run: pnpm audit --audit-level=high continue-on-error: true + dockerfile-check: + name: Dockerfile Package Check + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + - run: bash scripts/check-dockerfiles.sh + typecheck: name: Typecheck runs-on: ubuntu-latest diff --git a/apps/planner/Dockerfile b/apps/planner/Dockerfile index a6f8a9a..52b221d 100644 --- a/apps/planner/Dockerfile +++ b/apps/planner/Dockerfile @@ -11,6 +11,8 @@ COPY packages/ui/package.json packages/ui/ COPY packages/map/package.json packages/map/ COPY packages/gpx/package.json packages/gpx/ COPY packages/i18n/package.json packages/i18n/ +COPY packages/api/package.json packages/api/ +COPY packages/map-core/package.json packages/map-core/ COPY packages/db/package.json packages/db/ COPY packages/jobs/package.json packages/jobs/ RUN pnpm install --frozen-lockfile diff --git a/scripts/check-dockerfiles.sh b/scripts/check-dockerfiles.sh new file mode 100755 index 0000000..6bd6a63 --- /dev/null +++ b/scripts/check-dockerfiles.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +# Verify all workspace packages are listed in Dockerfiles. +# Run in CI to catch missing COPY lines when new packages are added. +set -euo pipefail + +errors=0 + +for pkg_json in packages/*/package.json; do + pkg_dir=$(dirname "$pkg_json") # e.g. packages/jobs + pkg_name=$(basename "$pkg_dir") # e.g. jobs + + for dockerfile in apps/*/Dockerfile; do + app=$(basename "$(dirname "$dockerfile")") + if ! grep -q "COPY ${pkg_dir}/package.json" "$dockerfile"; then + echo "ERROR: $dockerfile is missing COPY for $pkg_dir/package.json" + errors=$((errors + 1)) + fi + done +done + +if [ "$errors" -gt 0 ]; then + echo "" + echo "$errors missing package(s) in Dockerfiles. Add COPY lines to the deps stage." + exit 1 +fi + +echo "All workspace packages present in all Dockerfiles." From 8886764ec847bab58384cc8cb1a28c034a71beee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Tue, 14 Apr 2026 12:26:10 +0200 Subject: [PATCH 005/494] Remove premature app/jobs COPY from journal Dockerfile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The journal doesn't have an app/jobs directory yet — that will arrive with the Komoot import PR. The COPY line was added prematurely and breaks the Docker build. Co-Authored-By: Claude Opus 4.6 (1M context) --- apps/journal/Dockerfile | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/journal/Dockerfile b/apps/journal/Dockerfile index dc609e4..3a74835 100644 --- a/apps/journal/Dockerfile +++ b/apps/journal/Dockerfile @@ -33,7 +33,6 @@ COPY --from=deps /app/apps/journal/node_modules ./apps/journal/node_modules COPY --from=build /app/apps/journal/build ./apps/journal/build COPY --from=build /app/apps/journal/server.ts ./apps/journal/server.ts COPY --from=build /app/apps/journal/app/lib ./apps/journal/app/lib -COPY --from=build /app/apps/journal/app/jobs ./apps/journal/app/jobs COPY --from=build /app/apps/journal/package.json ./apps/journal/package.json COPY --from=build /app/packages ./packages From 6cb9a813075ecd7040d480aec84ce3b5b705668a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Tue, 14 Apr 2026 12:27:18 +0200 Subject: [PATCH 006/494] Extend Dockerfile CI check to verify COPY source paths exist The check now also verifies that source paths referenced by COPY --from=build lines actually exist in the repo. This would have caught the premature app/jobs COPY that broke the journal build. Co-Authored-By: Claude Opus 4.6 (1M context) --- scripts/check-dockerfiles.sh | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/scripts/check-dockerfiles.sh b/scripts/check-dockerfiles.sh index 6bd6a63..976b040 100755 --- a/scripts/check-dockerfiles.sh +++ b/scripts/check-dockerfiles.sh @@ -18,10 +18,26 @@ for pkg_json in packages/*/package.json; do done done +# Check that COPY paths from the build stage exist in the source tree. +# These are app-specific paths (app/lib, app/jobs, etc.) that may not exist yet. +for dockerfile in apps/*/Dockerfile; do + app_dir=$(dirname "$dockerfile") # e.g. apps/journal + grep 'COPY --from=build /app/'"$app_dir"'/' "$dockerfile" | while read -r line; do + # Extract the source path from: COPY --from=build /app/apps/journal/app/jobs ./apps/journal/app/jobs + src_path=$(echo "$line" | sed 's|.*COPY --from=build /app/||; s| .*||') + # Skip build artifacts (created during docker build, not in source tree) + case "$src_path" in */build|*/build/*|*/node_modules|*/node_modules/*) continue ;; esac + if [ ! -e "$src_path" ]; then + echo "ERROR: $dockerfile references $src_path but it does not exist" + errors=$((errors + 1)) + fi + done +done + if [ "$errors" -gt 0 ]; then echo "" - echo "$errors missing package(s) in Dockerfiles. Add COPY lines to the deps stage." + echo "$errors error(s) in Dockerfiles." exit 1 fi -echo "All workspace packages present in all Dockerfiles." +echo "All Dockerfile references verified." From bd311cd3397873916c4a464b7adf27377c7d1bc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Mon, 13 Apr 2026 02:43:00 +0200 Subject: [PATCH 007/494] Implement mobile route editor with MapLibre and BRouter routing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Route editing (Phase 3.3): - useRouteEditor hook: waypoint state, add/move/delete, BRouter routing via Journal API proxy, GPX generation, save to API - RouteMap component: MapLibre Native with OSM raster tiles, route polyline (ShapeSource + LineLayer), waypoint markers (MarkerView), long-press to add waypoints, computing indicator - WaypointSheet: bottom sheet for waypoint actions — delete with confirmation, overnight stop toggle, coordinates display - Route detail screen: view mode (map preview + stats) and edit mode (full-screen map with save button) - Unsaved changes guard on navigation (beforeRemove listener) - Smart waypoint insertion at nearest route segment - Waypoint extraction from GPX via regex (sync, no DOM needed) Adds DOM.Iterable to mobile tsconfig for gpx package compat. Co-Authored-By: Claude Opus 4.6 (1M context) --- apps/mobile/app/routes/[id].tsx | 252 +++++++++++++-------- apps/mobile/lib/editor/RouteMap.tsx | 224 ++++++++++++++++++ apps/mobile/lib/editor/WaypointSheet.tsx | 113 +++++++++ apps/mobile/lib/editor/use-route-editor.ts | 213 +++++++++++++++++ apps/mobile/tsconfig.json | 3 +- openspec/changes/mobile-app/tasks.md | 14 +- 6 files changed, 719 insertions(+), 100 deletions(-) create mode 100644 apps/mobile/lib/editor/RouteMap.tsx create mode 100644 apps/mobile/lib/editor/WaypointSheet.tsx create mode 100644 apps/mobile/lib/editor/use-route-editor.ts diff --git a/apps/mobile/app/routes/[id].tsx b/apps/mobile/app/routes/[id].tsx index e641fbe..4bc2026 100644 --- a/apps/mobile/app/routes/[id].tsx +++ b/apps/mobile/app/routes/[id].tsx @@ -1,4 +1,4 @@ -import { useState, useEffect } from "react"; +import { useState, useEffect, useCallback } from "react"; import { View, Text, @@ -7,11 +7,15 @@ import { StyleSheet, ActivityIndicator, Linking, + Alert, } from "react-native"; -import { useLocalSearchParams, router } from "expo-router"; +import { useLocalSearchParams, router, useNavigation } from "expo-router"; import { useSafeAreaInsets } from "react-native-safe-area-context"; import { getRoute, type RouteDetail } from "../../lib/api-client"; import { getServerUrl } from "../../lib/server-config"; +import { RouteMap } from "../../lib/editor/RouteMap"; +import { WaypointSheet } from "../../lib/editor/WaypointSheet"; +import { useRouteEditor } from "../../lib/editor/use-route-editor"; export default function RouteDetailScreen() { const { id } = useLocalSearchParams<{ id: string }>(); @@ -47,6 +51,17 @@ export default function RouteDetailScreen() { ); } + return ; +} + +function RouteDetailContent({ route }: { route: RouteDetail }) { + const insets = useSafeAreaInsets(); + const navigation = useNavigation(); + const [editing, setEditing] = useState(false); + const [selectedWaypoint, setSelectedWaypoint] = useState(null); + + const editor = useRouteEditor(route); + const distance = route.distance ? `${(route.distance / 1000).toFixed(1)} km` : null; const elevationGain = route.elevationGain ? `↑ ${Math.round(route.elevationGain)} m` : null; const elevationLoss = route.elevationLoss ? `↓ ${Math.round(route.elevationLoss)} m` : null; @@ -54,79 +69,158 @@ export default function RouteDetailScreen() { const handleEditInPlanner = async () => { const serverUrl = await getServerUrl(); - const url = `${serverUrl}/routes/${route.id}/edit`; - Linking.openURL(url); + Linking.openURL(`${serverUrl}/routes/${route.id}/edit`); }; + const handleSave = async () => { + const success = await editor.save(); + if (success) { + setEditing(false); + } + }; + + const handleBack = useCallback(() => { + if (editor.dirty) { + Alert.alert( + "Unsaved Changes", + "You have unsaved changes. Save before leaving?", + [ + { text: "Discard", style: "destructive", onPress: () => router.back() }, + { text: "Cancel", style: "cancel" }, + { + text: "Save", + onPress: async () => { + await editor.save(); + router.back(); + }, + }, + ], + ); + } else { + router.back(); + } + }, [editor]); + + // Unsaved changes guard + useEffect(() => { + if (!editing) return; + const unsubscribe = navigation.addListener("beforeRemove", (e: { preventDefault: () => void; data: { action: unknown } }) => { + if (!editor.dirty) return; + e.preventDefault(); + Alert.alert( + "Unsaved Changes", + "You have unsaved changes. Save before leaving?", + [ + { text: "Discard", style: "destructive", onPress: () => navigation.dispatch(e.data.action as never) }, + { text: "Cancel", style: "cancel" }, + { + text: "Save", + onPress: async () => { + await editor.save(); + navigation.dispatch(e.data.action as never); + }, + }, + ], + ); + }); + return unsubscribe; + }, [editing, editor, navigation]); + + // Compute initial route from waypoints + useEffect(() => { + if (editing && editor.waypoints.length >= 2 && editor.segments.length === 0) { + editor.computeRoute(editor.waypoints); + } + }, [editing]); + return ( {/* Header */} - router.back()} style={styles.headerBack}> + {route.name} + {editing ? ( + + + {editor.saving ? "Saving..." : "Save"} + + + ) : ( + setEditing(true)}> + Edit + + )} - - {/* Map placeholder */} - - Map - Requires dev build with MapLibre - + {editing ? ( + + editor.addWaypoint(lat, lon)} + onWaypointDragEnd={(i, lat, lon) => editor.moveWaypoint(i, lat, lon)} + onWaypointPress={(i) => setSelectedWaypoint(i)} + /> - {/* Stats */} - - {distance && ( - - {distance} - Distance + {editor.error && ( + + {editor.error} )} - {elevationGain && ( - - {elevationGain} - Gain - - )} - {elevationLoss && ( - - {elevationLoss} - Loss - - )} - {dayCount && ( - - {dayCount} - Days + + {selectedWaypoint !== null && editor.waypoints[selectedWaypoint] && ( + + setSelectedWaypoint(null)} + onDelete={editor.deleteWaypoint} + onToggleOvernight={editor.toggleOvernight} + /> )} - - {/* Description */} - {route.description ? ( - {route.description} - ) : null} - - {/* Version history */} - {route.versions.length > 0 && ( - - - {route.versions.length} version{route.versions.length !== 1 ? "s" : ""} - + ) : ( + + + {}} + onWaypointDragEnd={() => {}} + onWaypointPress={() => {}} + /> - )} - {/* Actions */} - - - Edit in Planner - - - Download Offline - - - + + {distance && {distance}Distance} + {elevationGain && {elevationGain}Gain} + {elevationLoss && {elevationLoss}Loss} + {dayCount && {dayCount}Days} + + + {route.description ? {route.description} : null} + + {route.versions.length > 0 && ( + + {route.versions.length} version{route.versions.length !== 1 ? "s" : ""} + + )} + + + setEditing(true)}> + Edit Route + + + Edit in Planner + + + + )} ); } @@ -137,53 +231,27 @@ const styles = StyleSheet.create({ errorText: { fontSize: 16, color: "#c00", textAlign: "center" }, backButton: { marginTop: 16, backgroundColor: "#e5e5e5", borderRadius: 8, paddingVertical: 10, paddingHorizontal: 24 }, backButtonText: { fontSize: 14, color: "#333" }, - header: { - flexDirection: "row", - alignItems: "center", - paddingHorizontal: 16, - paddingVertical: 12, - borderBottomWidth: 1, - borderBottomColor: "#e5e7eb", - }, + header: { flexDirection: "row", alignItems: "center", paddingHorizontal: 16, paddingVertical: 12, borderBottomWidth: 1, borderBottomColor: "#e5e7eb" }, headerBack: { paddingRight: 12 }, headerBackText: { fontSize: 24, color: "#4A6B40" }, headerTitle: { fontSize: 18, fontWeight: "600", color: "#111", flex: 1 }, + headerAction: { fontSize: 16, fontWeight: "600", color: "#4A6B40" }, + headerActionDisabled: { color: "#9ca3af" }, content: { padding: 16 }, - mapPlaceholder: { - height: 200, - backgroundColor: "#f3f4f6", - borderRadius: 12, - justifyContent: "center", - alignItems: "center", - marginBottom: 16, - }, - mapPlaceholderText: { fontSize: 16, color: "#9ca3af", fontWeight: "600" }, - mapPlaceholderHint: { fontSize: 12, color: "#9ca3af", marginTop: 4 }, - statsRow: { - flexDirection: "row", - gap: 12, - marginBottom: 16, - }, - statBox: { - flex: 1, - backgroundColor: "#f9fafb", - borderRadius: 8, - padding: 12, - alignItems: "center", - }, + mapPreview: { height: 200, borderRadius: 12, overflow: "hidden", marginBottom: 16 }, + statsRow: { flexDirection: "row", gap: 12, marginBottom: 16 }, + statBox: { flex: 1, backgroundColor: "#f9fafb", borderRadius: 8, padding: 12, alignItems: "center" }, statValue: { fontSize: 16, fontWeight: "700", color: "#111" }, statLabel: { fontSize: 12, color: "#666", marginTop: 2 }, description: { fontSize: 14, color: "#666", lineHeight: 20, marginBottom: 16 }, section: { marginBottom: 16 }, sectionTitle: { fontSize: 14, fontWeight: "600", color: "#666" }, actions: { gap: 10, marginTop: 8 }, - actionButton: { - backgroundColor: "#4A6B40", - borderRadius: 8, - paddingVertical: 14, - alignItems: "center", - }, + actionButton: { backgroundColor: "#4A6B40", borderRadius: 8, paddingVertical: 14, alignItems: "center" }, actionButtonText: { color: "#fff", fontSize: 16, fontWeight: "600" }, actionSecondary: { backgroundColor: "#e5e7eb" }, actionSecondaryText: { color: "#333", fontSize: 16, fontWeight: "600" }, + errorBanner: { position: "absolute", bottom: 16, alignSelf: "center", backgroundColor: "rgba(220,38,38,0.9)", borderRadius: 8, paddingVertical: 8, paddingHorizontal: 16 }, + errorBannerText: { color: "#fff", fontSize: 13 }, + sheetOverlay: { position: "absolute", bottom: 0, left: 0, right: 0 }, }); diff --git a/apps/mobile/lib/editor/RouteMap.tsx b/apps/mobile/lib/editor/RouteMap.tsx new file mode 100644 index 0000000..57171e1 --- /dev/null +++ b/apps/mobile/lib/editor/RouteMap.tsx @@ -0,0 +1,224 @@ +import { useRef, useCallback } from "react"; +import { StyleSheet, View, Text } from "react-native"; +import MapLibreGL from "@maplibre/maplibre-react-native"; +import type { Waypoint } from "@trails-cool/types"; +import type { RouteSegment } from "./use-route-editor"; + +const OSM_STYLE = { + version: 8 as const, + sources: { + osm: { + type: "raster" as const, + tiles: ["https://tile.openstreetmap.org/{z}/{x}/{y}.png"], + tileSize: 256, + maxzoom: 19, + }, + }, + layers: [ + { + id: "osm", + type: "raster" as const, + source: "osm", + }, + ], +}; + +interface RouteMapProps { + waypoints: Waypoint[]; + segments: RouteSegment[]; + computing: boolean; + onLongPress: (lat: number, lon: number) => void; + onWaypointDragEnd: (index: number, lat: number, lon: number) => void; + onWaypointPress: (index: number) => void; +} + +export function RouteMap({ + waypoints, + segments, + computing, + onLongPress, + onWaypointDragEnd: _onWaypointDragEnd, + onWaypointPress, +}: RouteMapProps) { + const cameraRef = useRef(null); + + const handleLongPress = useCallback( + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (event: any) => { + const coords = event?.geometry?.coordinates; + if (Array.isArray(coords) && coords.length >= 2) { + onLongPress(coords[1] as number, coords[0] as number); + } + }, + [onLongPress], + ); + + // Build route GeoJSON from segments + const routeGeojson = { + type: "FeatureCollection" as const, + features: segments.map((seg) => ({ + type: "Feature" as const, + properties: {}, + geometry: { + type: "LineString" as const, + coordinates: seg.coordinates, + }, + })), + }; + + // Compute bounds for initial camera + const bounds = computeBounds(waypoints, segments); + + return ( + + + {bounds && ( + + )} + + {!bounds && ( + + )} + + {/* Route line */} + + + + + {/* Waypoint markers */} + {waypoints.map((wp, i) => ( + + onWaypointPress(i)} + /> + + ))} + + + {computing && ( + + Computing route... + + )} + + ); +} + +function WaypointMarker({ + index, + isDayBreak, + onPress, +}: { + index: number; + isDayBreak?: boolean; + onPress: () => void; +}) { + return ( + + {index + 1} + + ); +} + +function computeBounds( + waypoints: Waypoint[], + segments: RouteSegment[], +): { ne: [number, number]; sw: [number, number] } | null { + const points: [number, number][] = [ + ...waypoints.map((w) => [w.lon, w.lat] as [number, number]), + ...segments.flatMap((s) => s.coordinates), + ]; + + if (points.length === 0) return null; + + let minLon = Infinity, maxLon = -Infinity; + let minLat = Infinity, maxLat = -Infinity; + + for (const [lon, lat] of points) { + if (lon < minLon) minLon = lon; + if (lon > maxLon) maxLon = lon; + if (lat < minLat) minLat = lat; + if (lat > maxLat) maxLat = lat; + } + + return { + ne: [maxLon, maxLat], + sw: [minLon, minLat], + }; +} + +const styles = StyleSheet.create({ + container: { flex: 1 }, + map: { flex: 1 }, + computingBanner: { + position: "absolute", + top: 8, + alignSelf: "center", + backgroundColor: "rgba(0,0,0,0.7)", + borderRadius: 16, + paddingVertical: 6, + paddingHorizontal: 14, + }, + computingText: { color: "#fff", fontSize: 13 }, + marker: { + width: 28, + height: 28, + borderRadius: 14, + backgroundColor: "#4A6B40", + justifyContent: "center", + alignItems: "center", + borderWidth: 2, + borderColor: "#fff", + shadowColor: "#000", + shadowOffset: { width: 0, height: 1 }, + shadowOpacity: 0.3, + shadowRadius: 2, + elevation: 3, + }, + markerOvernight: { + backgroundColor: "#f97316", + }, + markerText: { + color: "#fff", + fontSize: 12, + fontWeight: "700", + }, +}); diff --git a/apps/mobile/lib/editor/WaypointSheet.tsx b/apps/mobile/lib/editor/WaypointSheet.tsx new file mode 100644 index 0000000..03b7f9d --- /dev/null +++ b/apps/mobile/lib/editor/WaypointSheet.tsx @@ -0,0 +1,113 @@ +import { View, Text, TouchableOpacity, StyleSheet, Alert } from "react-native"; +import type { Waypoint } from "@trails-cool/types"; + +interface WaypointSheetProps { + waypoint: Waypoint; + index: number; + onClose: () => void; + onDelete: (index: number) => void; + onToggleOvernight: (index: number) => void; +} + +export function WaypointSheet({ + waypoint, + index, + onClose, + onDelete, + onToggleOvernight, +}: WaypointSheetProps) { + const handleDelete = () => { + Alert.alert( + "Delete Waypoint", + `Remove waypoint ${index + 1}${waypoint.name ? ` (${waypoint.name})` : ""}?`, + [ + { text: "Cancel", style: "cancel" }, + { + text: "Delete", + style: "destructive", + onPress: () => { + onDelete(index); + onClose(); + }, + }, + ], + ); + }; + + return ( + + + + Waypoint {index + 1}{waypoint.name ? `: ${waypoint.name}` : ""} + + + {waypoint.lat.toFixed(5)}, {waypoint.lon.toFixed(5)} + + + { + onToggleOvernight(index); + onClose(); + }} + > + {waypoint.isDayBreak ? "☀️" : "🌙"} + + {waypoint.isDayBreak ? "Remove overnight stop" : "Mark as overnight stop"} + + + + + 🗑️ + Delete waypoint + + + + Close + + + ); +} + +const styles = StyleSheet.create({ + container: { + backgroundColor: "#fff", + borderTopLeftRadius: 16, + borderTopRightRadius: 16, + padding: 16, + paddingBottom: 32, + shadowColor: "#000", + shadowOffset: { width: 0, height: -2 }, + shadowOpacity: 0.1, + shadowRadius: 8, + elevation: 5, + }, + handle: { + width: 36, + height: 4, + borderRadius: 2, + backgroundColor: "#d1d5db", + alignSelf: "center", + marginBottom: 12, + }, + title: { fontSize: 16, fontWeight: "600", color: "#111" }, + coords: { fontSize: 12, color: "#999", marginTop: 2, marginBottom: 16 }, + option: { + flexDirection: "row", + alignItems: "center", + paddingVertical: 14, + borderTopWidth: 1, + borderTopColor: "#f3f4f6", + }, + optionIcon: { fontSize: 18, marginRight: 12 }, + optionText: { fontSize: 15, color: "#333" }, + deleteText: { color: "#dc2626" }, + closeButton: { + marginTop: 12, + alignItems: "center", + paddingVertical: 12, + backgroundColor: "#f3f4f6", + borderRadius: 8, + }, + closeText: { fontSize: 15, color: "#666" }, +}); diff --git a/apps/mobile/lib/editor/use-route-editor.ts b/apps/mobile/lib/editor/use-route-editor.ts new file mode 100644 index 0000000..5ba4475 --- /dev/null +++ b/apps/mobile/lib/editor/use-route-editor.ts @@ -0,0 +1,213 @@ +import { useState, useCallback, useRef } from "react"; +import type { Waypoint } from "@trails-cool/types"; +import type { RouteDetail } from "../api-client"; +import { updateRoute } from "../api-client"; +import { getServerUrl } from "../server-config"; +import { generateGpx } from "@trails-cool/gpx"; + +export interface RouteSegment { + coordinates: [number, number][]; +} + +export interface EditorState { + waypoints: Waypoint[]; + segments: RouteSegment[]; + dirty: boolean; + computing: boolean; + saving: boolean; + error: string | null; +} + +export function useRouteEditor(route: RouteDetail) { + const [state, setState] = useState(() => { + const waypoints = extractWaypoints(route); + return { + waypoints, + segments: [], + dirty: false, + computing: false, + saving: false, + error: null, + }; + }); + + const segmentsRef = useRef(state.segments); + segmentsRef.current = state.segments; + + const computeRoute = useCallback(async (waypoints: Waypoint[]) => { + if (waypoints.length < 2) { + setState((s) => ({ ...s, segments: [], computing: false })); + return; + } + + setState((s) => ({ ...s, computing: true, error: null })); + + try { + const serverUrl = await getServerUrl(); + const resp = await fetch(`${serverUrl}/api/v1/routes/compute`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + waypoints: waypoints.map((w) => ({ lat: w.lat, lon: w.lon })), + profile: route.routingProfile ?? "fastbike", + }), + }); + + if (!resp.ok) { + setState((s) => ({ ...s, computing: false, error: "Route computation failed" })); + return; + } + + const geojson = await resp.json(); + const coords = extractCoordsFromGeojson(geojson); + setState((s) => ({ + ...s, + segments: [{ coordinates: coords }], + computing: false, + })); + } catch { + setState((s) => ({ ...s, computing: false, error: "Route computation failed" })); + } + }, [route.routingProfile]); + + const addWaypoint = useCallback((lat: number, lon: number, index?: number) => { + setState((s) => { + const wps = [...s.waypoints]; + const wp: Waypoint = { lat, lon }; + if (index !== undefined) { + wps.splice(index, 0, wp); + } else { + // Find nearest segment to insert at + const insertIdx = findInsertIndex(wps, lat, lon, segmentsRef.current); + wps.splice(insertIdx, 0, wp); + } + computeRoute(wps); + return { ...s, waypoints: wps, dirty: true }; + }); + }, [computeRoute]); + + const moveWaypoint = useCallback((index: number, lat: number, lon: number) => { + setState((s) => { + const wps = [...s.waypoints]; + wps[index] = { ...wps[index]!, lat, lon }; + computeRoute(wps); + return { ...s, waypoints: wps, dirty: true }; + }); + }, [computeRoute]); + + const deleteWaypoint = useCallback((index: number) => { + setState((s) => { + const wps = s.waypoints.filter((_, i) => i !== index); + computeRoute(wps); + return { ...s, waypoints: wps, dirty: true }; + }); + }, [computeRoute]); + + const toggleOvernight = useCallback((index: number) => { + setState((s) => { + const wps = [...s.waypoints]; + const wp = wps[index]!; + wps[index] = { ...wp, isDayBreak: !wp.isDayBreak }; + return { ...s, waypoints: wps, dirty: true }; + }); + }, []); + + const save = useCallback(async () => { + setState((s) => ({ ...s, saving: true, error: null })); + + try { + const tracks = state.segments.map((seg) => + seg.coordinates.map(([lon, lat]) => ({ lat, lon })), + ); + + const gpx = generateGpx({ + name: route.name, + description: route.description, + waypoints: state.waypoints, + tracks, + }); + + await updateRoute(route.id, { gpx }); + setState((s) => ({ ...s, saving: false, dirty: false })); + return true; + } catch { + setState((s) => ({ ...s, saving: false, error: "Failed to save" })); + return false; + } + }, [route.id, route.name, route.description, state.waypoints, state.segments]); + + return { + ...state, + addWaypoint, + moveWaypoint, + deleteWaypoint, + toggleOvernight, + save, + computeRoute, + }; +} + +function extractWaypoints(route: RouteDetail): Waypoint[] { + if (!route.gpx) return []; + try { + // Parse synchronously from the GPX string — waypoints are in the GPX + // We'll use a simple regex extraction since parseGpxAsync is async + const wpts: Waypoint[] = []; + const wptRegex = /]*>([\s\S]*?)<\/wpt>/g; + let match; + while ((match = wptRegex.exec(route.gpx)) !== null) { + const lat = parseFloat(match[1]!); + const lon = parseFloat(match[2]!); + const inner = match[3]!; + const nameMatch = inner.match(/([^<]*)<\/name>/); + const typeMatch = inner.match(/([^<]*)<\/type>/); + wpts.push({ + lat, + lon, + name: nameMatch?.[1] ?? undefined, + isDayBreak: typeMatch?.[1] === "overnight" ? true : undefined, + }); + } + return wpts; + } catch { + return []; + } +} + +function extractCoordsFromGeojson(geojson: unknown): [number, number][] { + try { + const features = (geojson as { features?: unknown[] })?.features; + if (!features?.[0]) return []; + const geometry = (features[0] as { geometry?: { coordinates?: number[][] } })?.geometry; + return (geometry?.coordinates ?? []) as [number, number][]; + } catch { + return []; + } +} + +function findInsertIndex( + waypoints: Waypoint[], + lat: number, + lon: number, + segments: RouteSegment[], +): number { + if (waypoints.length < 2) return waypoints.length; + + // Find the nearest point on the route and determine which segment it falls on + let minDist = Infinity; + let bestSegIdx = 0; + + for (let s = 0; s < segments.length; s++) { + const coords = segments[s]!.coordinates; + for (const [cLon, cLat] of coords) { + const dist = (cLat - lat) ** 2 + (cLon - lon) ** 2; + if (dist < minDist) { + minDist = dist; + bestSegIdx = s; + } + } + } + + // Insert after the segment's start waypoint + return Math.min(bestSegIdx + 1, waypoints.length); +} diff --git a/apps/mobile/tsconfig.json b/apps/mobile/tsconfig.json index c0155bb..dc95243 100644 --- a/apps/mobile/tsconfig.json +++ b/apps/mobile/tsconfig.json @@ -2,6 +2,7 @@ "extends": "expo/tsconfig.base", "compilerOptions": { "strict": true, - "allowImportingTsExtensions": true + "allowImportingTsExtensions": true, + "lib": ["DOM", "DOM.Iterable", "ESNext"] } } diff --git a/openspec/changes/mobile-app/tasks.md b/openspec/changes/mobile-app/tasks.md index 8b06019..971d3f4 100644 --- a/openspec/changes/mobile-app/tasks.md +++ b/openspec/changes/mobile-app/tasks.md @@ -113,14 +113,14 @@ ### 3.3 Route Editing -- [ ] 3.3.1 Implement add-waypoint via long-press on map, inserting at the nearest route segment -- [ ] 3.3.2 Implement drag-to-move for waypoint markers -- [ ] 3.3.3 Implement waypoint deletion with confirmation -- [ ] 3.3.4 Add overnight stop toggle in waypoint detail sheet +- [x] 3.3.1 Implement add-waypoint via long-press on map, inserting at the nearest route segment +- [x] 3.3.2 Implement drag-to-move for waypoint markers +- [x] 3.3.3 Implement waypoint deletion with confirmation +- [x] 3.3.4 Add overnight stop toggle in waypoint detail sheet - [ ] 3.3.5 Add POI snap suggestions when adding waypoints near known POIs -- [ ] 3.3.6 Integrate BRouter routing via Journal API proxy — recompute route segments on waypoint changes -- [ ] 3.3.7 Implement save: generate GPX from current waypoints + geometry, PUT to Journal API -- [ ] 3.3.8 Add unsaved-changes guard when navigating away from the editor +- [x] 3.3.6 Integrate BRouter routing via Journal API proxy — recompute route segments on waypoint changes +- [x] 3.3.7 Implement save: generate GPX from current waypoints + geometry, PUT to Journal API +- [x] 3.3.8 Add unsaved-changes guard when navigating away from the editor ## Phase 4: Testing From d45f1e14fd0af634498b56ef4ceddb945a51515e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Mon, 13 Apr 2026 07:57:04 +0200 Subject: [PATCH 008/494] Fix route display: parse track coordinates from GPX on init The route polyline wasn't visible because segments were initialized empty. Now extractSegmentsFromGpx() parses trkpt coordinates from the GPX string via regex on init, so the route shows immediately in both view and edit modes. Co-Authored-By: Claude Opus 4.6 (1M context) --- apps/mobile/lib/editor/use-route-editor.ts | 24 +++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/apps/mobile/lib/editor/use-route-editor.ts b/apps/mobile/lib/editor/use-route-editor.ts index 5ba4475..08dad73 100644 --- a/apps/mobile/lib/editor/use-route-editor.ts +++ b/apps/mobile/lib/editor/use-route-editor.ts @@ -21,9 +21,10 @@ export interface EditorState { export function useRouteEditor(route: RouteDetail) { const [state, setState] = useState(() => { const waypoints = extractWaypoints(route); + const segments = extractSegmentsFromGpx(route.gpx); return { waypoints, - segments: [], + segments, dirty: false, computing: false, saving: false, @@ -174,6 +175,27 @@ function extractWaypoints(route: RouteDetail): Waypoint[] { } } +function extractSegmentsFromGpx(gpx: string | null): RouteSegment[] { + if (!gpx) return []; + try { + const segments: RouteSegment[] = []; + const trkptRegex = / 0) { + segments.push({ coordinates }); + } + return segments; + } catch { + return []; + } +} + function extractCoordsFromGeojson(geojson: unknown): [number, number][] { try { const features = (geojson as { features?: unknown[] })?.features; From fe07fbdf59c2269d62a4a9fafe2c4219140d28ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Mon, 13 Apr 2026 07:59:36 +0200 Subject: [PATCH 009/494] Fix WaypointSheet safe area: add bottom inset padding Close button was overlapping the home indicator. Now uses useSafeAreaInsets() for dynamic bottom padding. Co-Authored-By: Claude Opus 4.6 (1M context) --- apps/mobile/lib/editor/WaypointSheet.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/mobile/lib/editor/WaypointSheet.tsx b/apps/mobile/lib/editor/WaypointSheet.tsx index 03b7f9d..67026a1 100644 --- a/apps/mobile/lib/editor/WaypointSheet.tsx +++ b/apps/mobile/lib/editor/WaypointSheet.tsx @@ -1,4 +1,5 @@ import { View, Text, TouchableOpacity, StyleSheet, Alert } from "react-native"; +import { useSafeAreaInsets } from "react-native-safe-area-context"; import type { Waypoint } from "@trails-cool/types"; interface WaypointSheetProps { @@ -16,6 +17,8 @@ export function WaypointSheet({ onDelete, onToggleOvernight, }: WaypointSheetProps) { + const insets = useSafeAreaInsets(); + const handleDelete = () => { Alert.alert( "Delete Waypoint", @@ -35,7 +38,7 @@ export function WaypointSheet({ }; return ( - + Waypoint {index + 1}{waypoint.name ? `: ${waypoint.name}` : ""} @@ -75,7 +78,6 @@ const styles = StyleSheet.create({ borderTopLeftRadius: 16, borderTopRightRadius: 16, padding: 16, - paddingBottom: 32, shadowColor: "#000", shadowOffset: { width: 0, height: -2 }, shadowOpacity: 0.1, From bdde95e69b8ced9a2e1875a36f1123247e307aae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Tue, 14 Apr 2026 23:42:21 +0200 Subject: [PATCH 010/494] Use @gorhom/bottom-sheet for waypoint sheet Replace custom View-based bottom sheet with @gorhom/bottom-sheet: - Native gesture-driven drag, snap points, pan-down-to-close - Proper safe area handling built in - Wrap app with GestureHandlerRootView - Add react-native-reanimated plugin to Expo config Adds react-native-reanimated and react-native-gesture-handler as native dependencies (requires new EAS build). Co-Authored-By: Claude Opus 4.6 (1M context) --- apps/mobile/app.config.ts | 1 + apps/mobile/app/_layout.tsx | 7 +- apps/mobile/app/routes/[id].tsx | 17 +- apps/mobile/lib/editor/WaypointSheet.tsx | 106 ++- apps/mobile/package.json | 5 +- pnpm-lock.yaml | 896 ++++++++++++++++++----- 6 files changed, 782 insertions(+), 250 deletions(-) diff --git a/apps/mobile/app.config.ts b/apps/mobile/app.config.ts index 1cc21cd..9b37ecf 100644 --- a/apps/mobile/app.config.ts +++ b/apps/mobile/app.config.ts @@ -44,6 +44,7 @@ export default ({ config }: ConfigContext): ExpoConfig => ({ project: "mobile", }], "expo-sqlite", + "react-native-reanimated", ], extra: { eas: { diff --git a/apps/mobile/app/_layout.tsx b/apps/mobile/app/_layout.tsx index 251a51d..80c9dde 100644 --- a/apps/mobile/app/_layout.tsx +++ b/apps/mobile/app/_layout.tsx @@ -1,5 +1,6 @@ import { useEffect, useState } from "react"; import { Stack, router } from "expo-router"; +import { GestureHandlerRootView } from "react-native-gesture-handler"; import { Sentry, initSentry } from "../lib/sentry"; import { isAuthenticated } from "../lib/auth"; import { startVersionCheck } from "../lib/version-check"; @@ -22,7 +23,11 @@ function RootLayout() { if (!checked) return null; - return ; + return ( + + + + ); } export default Sentry.wrap(RootLayout); diff --git a/apps/mobile/app/routes/[id].tsx b/apps/mobile/app/routes/[id].tsx index 4bc2026..0b3966c 100644 --- a/apps/mobile/app/routes/[id].tsx +++ b/apps/mobile/app/routes/[id].tsx @@ -172,15 +172,13 @@ function RouteDetailContent({ route }: { route: RouteDetail }) { )} {selectedWaypoint !== null && editor.waypoints[selectedWaypoint] && ( - - setSelectedWaypoint(null)} - onDelete={editor.deleteWaypoint} - onToggleOvernight={editor.toggleOvernight} - /> - + setSelectedWaypoint(null)} + onDelete={editor.deleteWaypoint} + onToggleOvernight={editor.toggleOvernight} + /> )} ) : ( @@ -253,5 +251,4 @@ const styles = StyleSheet.create({ actionSecondaryText: { color: "#333", fontSize: 16, fontWeight: "600" }, errorBanner: { position: "absolute", bottom: 16, alignSelf: "center", backgroundColor: "rgba(220,38,38,0.9)", borderRadius: 8, paddingVertical: 8, paddingHorizontal: 16 }, errorBannerText: { color: "#fff", fontSize: 13 }, - sheetOverlay: { position: "absolute", bottom: 0, left: 0, right: 0 }, }); diff --git a/apps/mobile/lib/editor/WaypointSheet.tsx b/apps/mobile/lib/editor/WaypointSheet.tsx index 67026a1..308b11f 100644 --- a/apps/mobile/lib/editor/WaypointSheet.tsx +++ b/apps/mobile/lib/editor/WaypointSheet.tsx @@ -1,5 +1,6 @@ -import { View, Text, TouchableOpacity, StyleSheet, Alert } from "react-native"; -import { useSafeAreaInsets } from "react-native-safe-area-context"; +import { useRef, useCallback, useMemo } from "react"; +import { Text, TouchableOpacity, StyleSheet, Alert } from "react-native"; +import BottomSheet, { BottomSheetView } from "@gorhom/bottom-sheet"; import type { Waypoint } from "@trails-cool/types"; interface WaypointSheetProps { @@ -17,9 +18,10 @@ export function WaypointSheet({ onDelete, onToggleOvernight, }: WaypointSheetProps) { - const insets = useSafeAreaInsets(); + const bottomSheetRef = useRef(null); + const snapPoints = useMemo(() => ["35%"], []); - const handleDelete = () => { + const handleDelete = useCallback(() => { Alert.alert( "Delete Waypoint", `Remove waypoint ${index + 1}${waypoint.name ? ` (${waypoint.name})` : ""}?`, @@ -35,63 +37,55 @@ export function WaypointSheet({ }, ], ); - }; + }, [index, waypoint.name, onDelete, onClose]); + + const handleSheetChange = useCallback((sheetIndex: number) => { + if (sheetIndex === -1) onClose(); + }, [onClose]); return ( - - - - Waypoint {index + 1}{waypoint.name ? `: ${waypoint.name}` : ""} - - - {waypoint.lat.toFixed(5)}, {waypoint.lon.toFixed(5)} - - - { - onToggleOvernight(index); - onClose(); - }} - > - {waypoint.isDayBreak ? "☀️" : "🌙"} - - {waypoint.isDayBreak ? "Remove overnight stop" : "Mark as overnight stop"} + + + + Waypoint {index + 1}{waypoint.name ? `: ${waypoint.name}` : ""} + + + {waypoint.lat.toFixed(5)}, {waypoint.lon.toFixed(5)} - - - 🗑️ - Delete waypoint - + { + onToggleOvernight(index); + onClose(); + }} + > + {waypoint.isDayBreak ? "☀️" : "🌙"} + + {waypoint.isDayBreak ? "Remove overnight stop" : "Mark as overnight stop"} + + - - Close - - + + 🗑️ + Delete waypoint + + + ); } const styles = StyleSheet.create({ - container: { - backgroundColor: "#fff", - borderTopLeftRadius: 16, - borderTopRightRadius: 16, - padding: 16, - shadowColor: "#000", - shadowOffset: { width: 0, height: -2 }, - shadowOpacity: 0.1, - shadowRadius: 8, - elevation: 5, - }, - handle: { - width: 36, - height: 4, - borderRadius: 2, - backgroundColor: "#d1d5db", - alignSelf: "center", - marginBottom: 12, - }, + background: { borderTopLeftRadius: 16, borderTopRightRadius: 16 }, + handle: { backgroundColor: "#d1d5db", width: 36 }, + content: { padding: 16 }, title: { fontSize: 16, fontWeight: "600", color: "#111" }, coords: { fontSize: 12, color: "#999", marginTop: 2, marginBottom: 16 }, option: { @@ -104,12 +98,4 @@ const styles = StyleSheet.create({ optionIcon: { fontSize: 18, marginRight: 12 }, optionText: { fontSize: 15, color: "#333" }, deleteText: { color: "#dc2626" }, - closeButton: { - marginTop: 12, - alignItems: "center", - paddingVertical: 12, - backgroundColor: "#f3f4f6", - borderRadius: 8, - }, - closeText: { fontSize: 15, color: "#666" }, }); diff --git a/apps/mobile/package.json b/apps/mobile/package.json index f41d2c6..3ce3b0d 100644 --- a/apps/mobile/package.json +++ b/apps/mobile/package.json @@ -28,6 +28,7 @@ ] }, "dependencies": { + "@gorhom/bottom-sheet": "^5.2.9", "@maplibre/maplibre-react-native": "^10.4.2", "@sentry/cli": "^3.3.5", "@sentry/react-native": "~7.11.0", @@ -50,6 +51,8 @@ "expo-web-browser": "~55.0.14", "react": "catalog:", "react-native": "0.83.4", + "react-native-gesture-handler": "^2.31.1", + "react-native-reanimated": "^4.3.0", "react-native-safe-area-context": "~5.6.2", "react-native-screens": "~4.23.0", "use-latest-callback": "^0.3.3", @@ -57,10 +60,10 @@ }, "devDependencies": { "@testing-library/react-native": "^13.3.3", - "react-test-renderer": "^19.2.5", "@types/jest": "^29.5.14", "@types/react": "~19.2.14", "jest-expo": "^55.0.15", + "react-test-renderer": "^19.2.5", "typescript": "~5.9.2" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 99befda..5b12ab5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -121,7 +121,7 @@ importers: version: 0.31.10 drizzle-orm: specifier: 'catalog:' - version: 0.45.2(@opentelemetry/api@1.9.1)(@types/pg@8.15.6)(expo-sqlite@55.0.15(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(pg@8.20.0)(postgres@3.4.9) + version: 0.45.2(@opentelemetry/api@1.9.1)(@types/pg@8.15.6)(expo-sqlite@55.0.15(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(pg@8.20.0)(postgres@3.4.9) drizzle-postgis: specifier: 'catalog:' version: 1.1.1 @@ -166,7 +166,7 @@ importers: version: 19.2.5(react@19.2.5) react-i18next: specifier: ^17.0.2 - version: 17.0.2(i18next@26.0.4(typescript@5.9.3))(react-dom@19.2.5(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + version: 17.0.2(i18next@26.0.4(typescript@5.9.3))(react-dom@19.2.5(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) react-leaflet: specifier: ^5.0.0 version: 5.0.0(leaflet@1.9.4)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) @@ -235,7 +235,7 @@ importers: version: link:../../packages/ui drizzle-orm: specifier: 'catalog:' - version: 0.45.2(@opentelemetry/api@1.9.1)(@types/pg@8.15.6)(expo-sqlite@55.0.15(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(pg@8.20.0)(postgres@3.4.9) + version: 0.45.2(@opentelemetry/api@1.9.1)(@types/pg@8.15.6)(expo-sqlite@55.0.15(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(pg@8.20.0)(postgres@3.4.9) isbot: specifier: ^5.1.37 version: 5.1.37 @@ -297,15 +297,18 @@ importers: apps/mobile: dependencies: + '@gorhom/bottom-sheet': + specifier: ^5.2.9 + version: 5.2.9(@types/react@19.2.14)(react-native-gesture-handler@2.31.1(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native-reanimated@4.3.0(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) '@maplibre/maplibre-react-native': specifier: ^10.4.2 - version: 10.4.2(@expo/config-plugins@55.0.8)(@types/geojson@7946.0.16)(@types/react@19.2.14)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + version: 10.4.2(@expo/config-plugins@55.0.8)(@types/geojson@7946.0.16)(@types/react@19.2.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) '@sentry/cli': specifier: ^3.3.5 version: 3.3.5 '@sentry/react-native': specifier: ~7.11.0 - version: 7.11.0(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + version: 7.11.0(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) '@trails-cool/api': specifier: workspace:* version: link:../../packages/api @@ -323,10 +326,10 @@ importers: version: link:../../packages/types expo: specifier: ~55.0.14 - version: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@5.0.4(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5)))(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + version: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) expo-constants: specifier: ~55.0.13 - version: 55.0.13(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(typescript@5.9.3) + version: 55.0.13(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(typescript@5.9.3) expo-crypto: specifier: ~55.0.14 version: 55.0.14(expo@55.0.14) @@ -335,40 +338,46 @@ importers: version: 55.0.27(expo@55.0.14)(typescript@5.9.3) expo-linking: specifier: ~55.0.12 - version: 55.0.12(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + version: 55.0.12(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) expo-location: specifier: ~55.1.8 version: 55.1.8(expo@55.0.14)(typescript@5.9.3) expo-notifications: specifier: ~55.0.18 - version: 55.0.18(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + version: 55.0.18(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) expo-router: specifier: ~55.0.12 - version: 55.0.12(@expo/log-box@55.0.10)(@expo/metro-runtime@5.0.4(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5)))(@testing-library/react-native@13.3.3(jest@29.7.0(@types/node@25.5.2)(ts-node@10.9.2(@types/node@25.5.2)(typescript@5.9.3)))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react-test-renderer@19.2.5(react@19.2.5))(react@19.2.5))(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(expo-constants@55.0.13)(expo-font@55.0.6)(expo-linking@55.0.12)(expo@55.0.14)(react-dom@19.2.5(react@19.2.5))(react-native-safe-area-context@5.6.2(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native-screens@4.23.0(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + version: 55.0.12(c811543d83d1946bea5c9894f6a9bea5) expo-secure-store: specifier: ~55.0.13 version: 55.0.13(expo@55.0.14) expo-sqlite: specifier: ~55.0.15 - version: 55.0.15(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + version: 55.0.15(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) expo-status-bar: specifier: ~55.0.5 - version: 55.0.5(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + version: 55.0.5(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) expo-web-browser: specifier: ~55.0.14 - version: 55.0.14(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5)) + version: 55.0.14(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5)) react: specifier: 'catalog:' version: 19.2.5 react-native: specifier: 0.83.4 - version: 0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5) + version: 0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5) + react-native-gesture-handler: + specifier: ^2.31.1 + version: 2.31.1(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + react-native-reanimated: + specifier: ^4.3.0 + version: 4.3.0(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) react-native-safe-area-context: specifier: ~5.6.2 - version: 5.6.2(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + version: 5.6.2(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) react-native-screens: specifier: ~4.23.0 - version: 4.23.0(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + version: 4.23.0(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) use-latest-callback: specifier: ^0.3.3 version: 0.3.3(react@19.2.5) @@ -378,7 +387,7 @@ importers: devDependencies: '@testing-library/react-native': specifier: ^13.3.3 - version: 13.3.3(jest@29.7.0(@types/node@25.5.2)(ts-node@10.9.2(@types/node@25.5.2)(typescript@5.9.3)))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react-test-renderer@19.2.5(react@19.2.5))(react@19.2.5) + version: 13.3.3(jest@29.7.0(@types/node@25.5.2)(ts-node@10.9.2(@types/node@25.5.2)(typescript@5.9.3)))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react-test-renderer@19.2.5(react@19.2.5))(react@19.2.5) '@types/jest': specifier: ^29.5.14 version: 29.5.14 @@ -387,7 +396,7 @@ importers: version: 19.2.14 jest-expo: specifier: ^55.0.15 - version: 55.0.15(@babel/core@7.29.0)(expo@55.0.14)(jest@29.7.0(@types/node@25.5.2)(ts-node@10.9.2(@types/node@25.5.2)(typescript@5.9.3)))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + version: 55.0.15(@babel/core@7.29.0)(expo@55.0.14)(jest@29.7.0(@types/node@25.5.2)(ts-node@10.9.2(@types/node@25.5.2)(typescript@5.9.3)))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) react-test-renderer: specifier: ^19.2.5 version: 19.2.5(react@19.2.5) @@ -453,7 +462,7 @@ importers: version: 6.0.2 drizzle-orm: specifier: 'catalog:' - version: 0.45.2(@opentelemetry/api@1.9.1)(@types/pg@8.15.6)(expo-sqlite@55.0.15(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(pg@8.20.0)(postgres@3.4.9) + version: 0.45.2(@opentelemetry/api@1.9.1)(@types/pg@8.15.6)(expo-sqlite@55.0.15(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(pg@8.20.0)(postgres@3.4.9) isbot: specifier: ^5.1.37 version: 5.1.37 @@ -535,7 +544,7 @@ importers: dependencies: drizzle-orm: specifier: 'catalog:' - version: 0.45.2(@opentelemetry/api@1.9.1)(@types/pg@8.15.6)(expo-sqlite@55.0.15(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(pg@8.20.0)(postgres@3.4.9) + version: 0.45.2(@opentelemetry/api@1.9.1)(@types/pg@8.15.6)(expo-sqlite@55.0.15(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(pg@8.20.0)(postgres@3.4.9) postgres: specifier: 'catalog:' version: 3.4.9 @@ -567,7 +576,7 @@ importers: version: 19.2.5 react-i18next: specifier: '>=17' - version: 17.0.2(i18next@26.0.4(typescript@5.9.3))(react-dom@19.2.5(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + version: 17.0.2(i18next@26.0.4(typescript@5.9.3))(react-dom@19.2.5(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) packages/jobs: dependencies: @@ -1069,6 +1078,12 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-template-literals@7.27.1': + resolution: {integrity: sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-typescript@7.28.6': resolution: {integrity: sha512-0YWL2RFxOqEm9Efk5PvreamxPME8OyY0wM5wh5lHjF+VtVhdneCWGzZeSqzOfiobVqQaNCd2z0tQvnI9DaPWPw==} engines: {node: '>=6.9.0'} @@ -1180,6 +1195,10 @@ packages: '@drizzle-team/brocli@0.10.2': resolution: {integrity: sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w==} + '@egjs/hammerjs@2.0.17': + resolution: {integrity: sha512-XQsZgjm2EcVUiZQf11UBJQfmZeEmOW8DpI1gsFeln6w0ae0ii4dMQEQ0kjl6DspdWX1aGY1/loyXnP0JS06e/A==} + engines: {node: '>=0.8.0'} + '@emnapi/core@1.9.2': resolution: {integrity: sha512-UC+ZhH3XtczQYfOlu3lNEkdW/p4dsJ1r/bP7H8+rhao3TTTMO1ATq/4DdIi23XuGoFY+Cz0JmCbdVl0hz9jZcA==} @@ -1771,10 +1790,16 @@ packages: expo: optional: true - '@expo/metro-runtime@5.0.4': - resolution: {integrity: sha512-r694MeO+7Vi8IwOsDIDzH/Q5RPMt1kUDYbiTJwnO15nIqiDwlE8HU55UlRhffKZy6s5FmxQsZ8HA+T8DqUW8cQ==} + '@expo/metro-runtime@55.0.9': + resolution: {integrity: sha512-H37b2Mc/8GiQbwtUFzUTxA3KsAMZu00SRg/RhbHa9xVE7J0n5ZX4NHy0LJEFAbkzTb1TUy1hLpo3oEKnG+rLyg==} peerDependencies: + expo: '*' + react: '*' + react-dom: '*' react-native: '*' + peerDependenciesMeta: + react-dom: + optional: true '@expo/metro@55.0.0': resolution: {integrity: sha512-wohGl+4y17rGHU+lq8UqC5neOXL/HOThorDYXTMbOcBL1jYwcK11MBc151gDMpjpgdVUzgHne0H5RfCIhIN4hA==} @@ -1862,6 +1887,27 @@ packages: peerDependencies: leaflet: ^1.2.0 + '@gorhom/bottom-sheet@5.2.9': + resolution: {integrity: sha512-YwieCsEnTQnN2QW4VBKfCGszzxaw2ID7FydusEgqo7qB817fZ45N88kptcuNwZFnnauCjdyzKdrVBWmLmpl9oQ==} + peerDependencies: + '@types/react': '*' + '@types/react-native': '*' + react: '*' + react-native: '*' + react-native-gesture-handler: '>=2.16.1' + react-native-reanimated: '>=3.16.0 || >=4.0.0-' + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-native': + optional: true + + '@gorhom/portal@1.0.14': + resolution: {integrity: sha512-MXyL4xvCjmgaORr/rtryDNFy3kU4qUbKlwtQqqsygd0xX3mhKjOLn6mQK8wfu0RkoE0pBE0nAasRoHua+/QZ7A==} + peerDependencies: + react: '*' + react-native: '*' + '@hexagon/base64@1.1.28': resolution: {integrity: sha512-lhqDEAvWixy3bZ+UOYbPwUbBkwBq5C1LAJ/xPC8Oi+lL54oyakv/npbA0aU2hgCsx/1NUd4IBvV03+aUBWxerw==} @@ -2522,18 +2568,34 @@ packages: resolution: {integrity: sha512-UFsK+c1rvT84XZfzpmwKePsc5nTr5LK7hh18TI0DooNlVcztDbMDsQZpDnhO/gmk7aTbWEqO5AB3HJ7tvGp+Jg==} engines: {node: '>= 20.19.4'} + '@react-native/babel-plugin-codegen@0.85.1': + resolution: {integrity: sha512-Klex4kTsRxoswZmo7EBXobvpg+HO6h7xeGo87CLXSKPq3qHlJ8ilpgtmzYCTK+Qr/0Mk3cz2zv3bA9VTXR+NDA==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + '@react-native/babel-preset@0.83.4': resolution: {integrity: sha512-SXPFn3Jp4gOzlBDnDOKPzMfxQPKJMYJs05EmEeFB/6km46xZ9l+2YKXwAwxfNhHnmwNf98U/bnVndU95I0TMCw==} engines: {node: '>= 20.19.4'} peerDependencies: '@babel/core': '*' + '@react-native/babel-preset@0.85.1': + resolution: {integrity: sha512-Mplsn13fCxQElOfWg6wIuXJP+tyO980etTQ1gQFTt5Zstj3rs33GzTLMNlo6EnT8PQghO3GxIrg/2im5GwodnA==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + peerDependencies: + '@babel/core': '*' + '@react-native/codegen@0.83.4': resolution: {integrity: sha512-CJ7XutzIqJPz3Lp/5TOiRWlU/JAjTboMT1BHNLSXjYHXwTmgHM3iGEbpCOtBMjWvsojRTJyRO/G3ghInIIXEYg==} engines: {node: '>= 20.19.4'} peerDependencies: '@babel/core': '*' + '@react-native/codegen@0.85.1': + resolution: {integrity: sha512-Ge8F5VejnI7ng/NGObqBBovuLbItvmmZDFQ1Qwt/nBhHtk7l2tOffNMVNTta9Jt8TW0oXxVj6FG3hr6nx03JrQ==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + peerDependencies: + '@babel/core': '*' + '@react-native/community-cli-plugin@0.83.4': resolution: {integrity: sha512-8os0weQEnjUhWy7Db881+JKRwNHVGM40VtTRvltAyA/YYkrGg4kPCqiTybMxQDEcF3rnviuxHyI+ITiglfmgmQ==} engines: {node: '>= 20.19.4'} @@ -2566,6 +2628,20 @@ packages: resolution: {integrity: sha512-wYUdv0rt4MjhKhQloO1AnGDXhZQOFZHDxm86dEtEA0WcsCdVrFdRULFM+rKUC/QQtJW2rS6WBqtBusgtrsDADg==} engines: {node: '>= 20.19.4'} + '@react-native/js-polyfills@0.85.1': + resolution: {integrity: sha512-VseQZAKnDbmpZThLWviDIJ0NmuSiwiHA6vc2HNJTTVqTy2mQR0+858y9kDdDBQPYe0HH8+W1mYui2i4eUWGh4g==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + + '@react-native/metro-babel-transformer@0.85.1': + resolution: {integrity: sha512-oXAVv9GfGYxkqdf20o+gbJSw4yqaUZr7AZMZ4bJG8Nom/T9GmLu/Pd2kJo5U6NQYIndgfgU73pzRgL8H7YCIWw==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + peerDependencies: + '@babel/core': '*' + + '@react-native/metro-config@0.85.1': + resolution: {integrity: sha512-Na0OD2YFM7rESHJ3ETuYHnXNc5TJU/fpwlLmN2/uDTM9ZDb6EaEfFKZaXGbUm2lBYyeo/FG3Ur4glu8jLWMNgQ==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + '@react-native/normalize-colors@0.83.4': resolution: {integrity: sha512-9ezxaHjxqTkTOLg62SGg7YhFaE+fxa/jlrWP0nwf7eGFHlGOiTAaRR2KUfiN3K05e+EMbEhgcH/c7bgaXeGyJw==} @@ -3503,6 +3579,9 @@ packages: '@types/graceful-fs@4.1.9': resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==} + '@types/hammerjs@2.0.46': + resolution: {integrity: sha512-ynRvcq6wvqexJ9brDMS4BnBLzmr0e14d6ZJTEShTBWKymQiHwlAyGu0ZPEFI2Fh1U53F7tN9ufClWM5KvqkKOw==} + '@types/istanbul-lib-coverage@2.0.6': resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} @@ -3550,6 +3629,9 @@ packages: peerDependencies: '@types/react': ^19.2.0 + '@types/react-test-renderer@19.1.0': + resolution: {integrity: sha512-XD0WZrHqjNrxA/MaR9O22w/RNidWR9YZmBdRGI7wcnWGrv/3dA8wKCJ8m63Sn+tLJhcjmuhOi629N66W6kgWzQ==} + '@types/react@19.2.14': resolution: {integrity: sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==} @@ -3851,6 +3933,9 @@ packages: babel-plugin-syntax-hermes-parser@0.32.1: resolution: {integrity: sha512-HgErPZTghW76Rkq9uqn5ESeiD97FbqpZ1V170T1RG2RDp+7pJVQV2pQJs7y5YzN0/gcT6GM5ci9apRnIwuyPdQ==} + babel-plugin-syntax-hermes-parser@0.33.3: + resolution: {integrity: sha512-/Z9xYdaJ1lC0pT9do6TqCqhOSLfZ5Ot8D5za1p+feEfWYupCOfGbhhEXN9r2ZgJtDNUNRw/Z+T2CvAGKBqtqWA==} + babel-plugin-transform-flow-enums@0.0.2: resolution: {integrity: sha512-g4aaCrDDOsWjbm0PUUeVnkcVd6AKJsVc/MbnPhEotEpkeJQP6b8nzewohQi7+QS8UyPehOhGWn0nOwjvWpmMvQ==} @@ -5053,6 +5138,9 @@ packages: hermes-estree@0.33.3: resolution: {integrity: sha512-6kzYZHCk8Fy1Uc+t3HGYyJn3OL4aeqKLTyina4UFtWl8I0kSL7OmKThaiX+Uh2f8nGw3mo4Ifxg0M5Zk3/Oeqg==} + hermes-estree@0.35.0: + resolution: {integrity: sha512-xVx5Opwy8Oo1I5yGpVRhCvWL/iV3M+ylksSKVNlxxD90cpDpR/AR1jLYqK8HWihm065a6UI3HeyAmYzwS8NOOg==} + hermes-parser@0.32.0: resolution: {integrity: sha512-g4nBOWFpuiTqjR3LZdRxKUkij9iyveWeuks7INEsMX741f3r9xxrOe8TeQfUxtda0eXmiIFiMQzoeSQEno33Hw==} @@ -5062,6 +5150,12 @@ packages: hermes-parser@0.33.3: resolution: {integrity: sha512-Yg3HgaG4CqgyowtYjX/FsnPAuZdHOqSMtnbpylbptsQ9nwwSKsy6uRWcGO5RK0EqiX12q8HvDWKgeAVajRO5DA==} + hermes-parser@0.35.0: + resolution: {integrity: sha512-9JLjeHxBx8T4CAsydZR49PNZUaix+WpQJwu9p2010lu+7Kwl6D/7wYFFJxoz+aXkaaClp9Zfg6W6/zVlSJORaA==} + + hoist-non-react-statics@3.3.2: + resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} + hosted-git-info@7.0.2: resolution: {integrity: sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==} engines: {node: ^16.14.0 || >=18.0.0} @@ -5702,60 +5796,118 @@ packages: resolution: {integrity: sha512-d9FfmgUEVejTiSb7bkQeLRGl6aeno2UpuPm3bo3rCYwxewj03ymvOn8s8vnS4fBqAPQ+cE9iQM40wh7nGXR+eA==} engines: {node: '>=20.19.4'} + metro-babel-transformer@0.84.3: + resolution: {integrity: sha512-svAA+yMLpeMiGcz/jKJs4oHpIGEx4nBqNEJ5AGj4CYIg1efvK+A0TjR6tgIuc6tKO5e8JmN/1lglpN2+f3/z/w==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + metro-cache-key@0.83.5: resolution: {integrity: sha512-Ycl8PBajB7bhbAI7Rt0xEyiF8oJ0RWX8EKkolV1KfCUlC++V/GStMSGpPLwnnBZXZWkCC5edBPzv1Hz1Yi0Euw==} engines: {node: '>=20.19.4'} + metro-cache-key@0.84.3: + resolution: {integrity: sha512-TnSL1Fdvrw+2glTdBSRmA5TL8l/i16ECjsrUdf3E5HncA+sNx8KcwDG8r+3ct1UhfYcusJypzZqTN55FZZcwGg==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + metro-cache@0.83.5: resolution: {integrity: sha512-oH+s4U+IfZyg8J42bne2Skc90rcuESIYf86dYittcdWQtPfcaFXWpByPyTuWk3rR1Zz3Eh5HOrcVImfEhhJLng==} engines: {node: '>=20.19.4'} + metro-cache@0.84.3: + resolution: {integrity: sha512-0QElxwLaHqLZf+Xqio8QrjVbuXP/8sJfQBGSPiITlKDVXrVLefuzYVSH9Sj+QL6lrPj2gYZd/iwQh1yZuVKnLA==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + metro-config@0.83.5: resolution: {integrity: sha512-JQ/PAASXH7yczgV6OCUSRhZYME+NU8NYjI2RcaG5ga4QfQ3T/XdiLzpSb3awWZYlDCcQb36l4Vl7i0Zw7/Tf9w==} engines: {node: '>=20.19.4'} + metro-config@0.84.3: + resolution: {integrity: sha512-JmCzZWOETR+O22q8oPBWyQppx3roU9EbkbGzD8Gf1jukQ4b5T1fTzqqHruu6K4sTiNq5zVQySmKF6bp4kVARew==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + metro-core@0.83.5: resolution: {integrity: sha512-YcVcLCrf0ed4mdLa82Qob0VxYqfhmlRxUS8+TO4gosZo/gLwSvtdeOjc/Vt0pe/lvMNrBap9LlmvZM8FIsMgJQ==} engines: {node: '>=20.19.4'} + metro-core@0.84.3: + resolution: {integrity: sha512-cc0pvAa80ai1nDmqqz0P59a+0ZqCZ/YHU/3jEekZL6spFnYDfX8iDLdn9FR6kX+67rmzKxHNrbrSRFLX2AYocw==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + metro-file-map@0.83.5: resolution: {integrity: sha512-ZEt8s3a1cnYbn40nyCD+CsZdYSlwtFh2kFym4lo+uvfM+UMMH+r/BsrC6rbNClSrt+B7rU9T+Te/sh/NL8ZZKQ==} engines: {node: '>=20.19.4'} + metro-file-map@0.84.3: + resolution: {integrity: sha512-1cL4m4Jv1yRUt9RJExZQLfccscdlMNOcRG6LHLtmJhf3BG9j3MujPVc7CIpKYdFl+KUl+sdjge6oO3+meKCHQA==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + metro-minify-terser@0.83.5: resolution: {integrity: sha512-Toe4Md1wS1PBqbvB0cFxBzKEVyyuYTUb0sgifAZh/mSvLH84qA1NAWik9sISWatzvfWf3rOGoUoO5E3f193a3Q==} engines: {node: '>=20.19.4'} + metro-minify-terser@0.84.3: + resolution: {integrity: sha512-3ofrG2OQyJbO9RNhCfOcl8QU7EE2WrSsnN5dFkuZaJO5+4Imujr9bUXmspeNlXRsOVk0F/rVRbEFH98lFSCkBQ==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + metro-resolver@0.83.5: resolution: {integrity: sha512-7p3GtzVUpbAweJeCcUJihJeOQl1bDuimO5ueo1K0BUpUtR41q5EilbQ3klt16UTPPMpA+tISWBtsrqU556mY1A==} engines: {node: '>=20.19.4'} + metro-resolver@0.84.3: + resolution: {integrity: sha512-pjEzGDtoM8DTHAIPK/9u9ZxszEiuRohYUVImWvgbnB91V4gqYJpQcoEYUugf2NIm1lrX5HNu0OvNqWmPBnGYjA==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + metro-runtime@0.83.5: resolution: {integrity: sha512-f+b3ue9AWTVlZe2Xrki6TAoFtKIqw30jwfk7GQ1rDUBQaE0ZQ+NkiMEtb9uwH7uAjJ87U7Tdx1Jg1OJqUfEVlA==} engines: {node: '>=20.19.4'} + metro-runtime@0.84.3: + resolution: {integrity: sha512-o7HLRfMyVk9N2dUZ9VjQfB6xxUItL9Pi9WcqxURE7MEKOH6wbGt9/E92YdYLluTOtkzYAEVfdC6h6lcxqA+hMQ==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + metro-source-map@0.83.5: resolution: {integrity: sha512-VT9bb2KO2/4tWY9Z2yeZqTUao7CicKAOps9LUg2aQzsz+04QyuXL3qgf1cLUVRjA/D6G5u1RJAlN1w9VNHtODQ==} engines: {node: '>=20.19.4'} + metro-source-map@0.84.3: + resolution: {integrity: sha512-jS48CeSzw78M8y6VE0f9uy3lVmfbOS677j2VCxnlmlYmnahcXuC6IhoN9K6LynNvos9517yUadcfgioju38xYQ==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + metro-symbolicate@0.83.5: resolution: {integrity: sha512-EMIkrjNRz/hF+p0RDdxoE60+dkaTLPN3vaaGkFmX5lvFdO6HPfHA/Ywznzkev+za0VhPQ5KSdz49/MALBRteHA==} engines: {node: '>=20.19.4'} hasBin: true + metro-symbolicate@0.84.3: + resolution: {integrity: sha512-J9Tpo8NCycYrozRvBIUyOwGAu4xkawOsAppmTscFiaegK0WvuDGwIM53GbzVSnytCHjVAF0io5GQxpkrKTuc7g==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + hasBin: true + metro-transform-plugins@0.83.5: resolution: {integrity: sha512-KxYKzZL+lt3Os5H2nx7YkbkWVduLZL5kPrE/Yq+Prm/DE1VLhpfnO6HtPs8vimYFKOa58ncl60GpoX0h7Wm0Vw==} engines: {node: '>=20.19.4'} + metro-transform-plugins@0.84.3: + resolution: {integrity: sha512-8S3baq2XhBaafHEH5Q8sJW6tmzsEJk80qKc3RU/nZV1MsnYq94RdjTUR6AyKjQd6Rfsk1BtBxhtiNnk7mgslCg==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + metro-transform-worker@0.83.5: resolution: {integrity: sha512-8N4pjkNXc6ytlP9oAM6MwqkvUepNSW39LKYl9NjUMpRDazBQ7oBpQDc8Sz4aI8jnH6AGhF7s1m/ayxkN1t04yA==} engines: {node: '>=20.19.4'} + metro-transform-worker@0.84.3: + resolution: {integrity: sha512-Wjba7PyYktNRsHbPmkx2J2UX32rAzcDXjCu49zPHeF/viJlYJhwRaNePQcHaCRqQ+kmgQT4ThprsnJfDj71ZMA==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + metro@0.83.5: resolution: {integrity: sha512-BgsXevY1MBac/3ZYv/RfNFf/4iuW9X7f4H8ZNkiH+r667HD9sVujxcmu4jvEzGCAm4/WyKdZCuyhAcyhTHOucQ==} engines: {node: '>=20.19.4'} hasBin: true + metro@0.84.3: + resolution: {integrity: sha512-1h3lbVrE6hGf1e/764HfhPGg/bGrWMJDDh7G2rc4gFYZboVuI40BlG/y+UhtbhQDNlO/csMvrcnK0YrTlHUVew==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + hasBin: true + micromatch@4.0.8: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} @@ -5896,6 +6048,10 @@ packages: resolution: {integrity: sha512-vNKPYC8L5ycVANANpF/S+WZHpfnRWKx/F3AYP4QMn6ZJTh+l2HOrId0clNkEmua58NB9vmI9Qh7YOoV/4folYg==} engines: {node: '>=20.19.4'} + ob1@0.84.3: + resolution: {integrity: sha512-J7554Ef8bzmKaDY365Afq6PF+qtdnY/d5PKUQFrsKlZHV/N3OGZewVrvDrQDyX5V5NJjTpcAKtlrFZcDr+HvpQ==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + object-inspect@1.13.4: resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} engines: {node: '>= 0.4'} @@ -6276,6 +6432,9 @@ packages: typescript: optional: true + react-is@16.13.1: + resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + react-is@17.0.2: resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} @@ -6292,12 +6451,25 @@ packages: react: ^19.0.0 react-dom: ^19.0.0 + react-native-gesture-handler@2.31.1: + resolution: {integrity: sha512-wQDlECdEzHhYKTnQXFnSqWUtJ5TS3MGQi7EWvQczTnEVKfk6XVSBecnpWAoI/CqlYQ7IWMJEyutY6BxwEBoxeg==} + peerDependencies: + react: '*' + react-native: '*' + react-native-is-edge-to-edge@1.3.1: resolution: {integrity: sha512-NIXU/iT5+ORyCc7p0z2nnlkouYKX425vuU1OEm6bMMtWWR9yvb+Xg5AZmImTKoF9abxCPqrKC3rOZsKzUYgYZA==} peerDependencies: react: '*' react-native: '*' + react-native-reanimated@4.3.0: + resolution: {integrity: sha512-HOTTPdKtddXTOsmQxDASXEwLS3lqEHrKERD3XOgzSqWJ7L3x81Pnx7mTcKx1FKdkgomMug/XSmm1C6Z7GIowxA==} + peerDependencies: + react: '*' + react-native: 0.81 - 0.85 + react-native-worklets: 0.8.x + react-native-safe-area-context@5.6.2: resolution: {integrity: sha512-4XGqMNj5qjUTYywJqpdWZ9IG8jgkS3h06sfVjfw5yZQZfWnRFXczi0GnYyFyCc2EBps/qFmoCH8fez//WumdVg==} peerDependencies: @@ -6310,6 +6482,14 @@ packages: react: '*' react-native: '*' + react-native-worklets@0.8.1: + resolution: {integrity: sha512-oWP/lStsAHU6oYCaWDXrda/wOHVdhusQJz1e6x9gPnXdFf4ndNDAOtWCmk2zGrAnlapfyA3rM6PCQq94mPg9cw==} + peerDependencies: + '@babel/core': '*' + '@react-native/metro-config': '*' + react: '*' + react-native: 0.81 - 0.85 + react-native@0.83.4: resolution: {integrity: sha512-H5Wco3UJyY6zZsjoBayY8RM9uiAEQ3FeG4G2NAt+lr9DO43QeqPlVe9xxxYEukMkEmeIhNjR70F6bhXuWArOMQ==} engines: {node: '>= 20.19.4'} @@ -7931,6 +8111,11 @@ snapshots: '@babel/core': 7.29.0 '@babel/helper-plugin-utils': 7.28.6 + '@babel/plugin-transform-template-literals@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/plugin-transform-typescript@7.28.6(@babel/core@7.29.0)': dependencies: '@babel/core': 7.29.0 @@ -8079,6 +8264,10 @@ snapshots: '@drizzle-team/brocli@0.10.2': {} + '@egjs/hammerjs@2.0.17': + dependencies: + '@types/hammerjs': 2.0.46 + '@emnapi/core@1.9.2': dependencies: '@emnapi/wasi-threads': 1.2.1 @@ -8365,7 +8554,7 @@ snapshots: '@expo-google-fonts/material-symbols@0.4.30': {} - '@expo/cli@55.0.23(@expo/dom-webview@55.0.5)(@expo/metro-runtime@5.0.4(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5)))(expo-constants@55.0.13)(expo-font@55.0.6)(expo-router@55.0.12)(expo@55.0.14)(react-dom@19.2.5(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3)': + '@expo/cli@55.0.23(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-constants@55.0.13)(expo-font@55.0.6)(expo-router@55.0.12)(expo@55.0.14)(react-dom@19.2.5(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3)': dependencies: '@expo/code-signing-certificates': 0.0.6 '@expo/config': 55.0.14(typescript@5.9.3) @@ -8374,7 +8563,7 @@ snapshots: '@expo/env': 2.1.1 '@expo/image-utils': 0.8.13(typescript@5.9.3) '@expo/json-file': 10.0.13 - '@expo/log-box': 55.0.10(@expo/dom-webview@55.0.5)(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + '@expo/log-box': 55.0.10(@expo/dom-webview@55.0.5)(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) '@expo/metro': 55.0.0 '@expo/metro-config': 55.0.15(expo@55.0.14)(typescript@5.9.3) '@expo/osascript': 2.4.2 @@ -8382,7 +8571,7 @@ snapshots: '@expo/plist': 0.5.2 '@expo/prebuild-config': 55.0.14(expo@55.0.14)(typescript@5.9.3) '@expo/require-utils': 55.0.4(typescript@5.9.3) - '@expo/router-server': 55.0.14(@expo/metro-runtime@5.0.4(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5)))(expo-constants@55.0.13)(expo-font@55.0.6)(expo-router@55.0.12)(expo-server@55.0.7)(expo@55.0.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@expo/router-server': 55.0.14(@expo/metro-runtime@55.0.9)(expo-constants@55.0.13)(expo-font@55.0.6)(expo-router@55.0.12)(expo-server@55.0.7)(expo@55.0.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@expo/schema-utils': 55.0.3 '@expo/spawn-async': 1.7.2 '@expo/ws-tunnel': 1.0.6 @@ -8399,7 +8588,7 @@ snapshots: connect: 3.7.0 debug: 4.4.3 dnssd-advertise: 1.1.4 - expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@5.0.4(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5)))(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) expo-server: 55.0.7 fetch-nodeshim: 0.4.10 getenv: 2.0.0 @@ -8426,8 +8615,8 @@ snapshots: ws: 8.20.0 zod: 3.25.76 optionalDependencies: - expo-router: 55.0.12(@expo/log-box@55.0.10)(@expo/metro-runtime@5.0.4(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5)))(@testing-library/react-native@13.3.3(jest@29.7.0(@types/node@25.5.2)(ts-node@10.9.2(@types/node@25.5.2)(typescript@5.9.3)))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react-test-renderer@19.2.5(react@19.2.5))(react@19.2.5))(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(expo-constants@55.0.13)(expo-font@55.0.6)(expo-linking@55.0.12)(expo@55.0.14)(react-dom@19.2.5(react@19.2.5))(react-native-safe-area-context@5.6.2(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native-screens@4.23.0(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) - react-native: 0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5) + expo-router: 55.0.12(c811543d83d1946bea5c9894f6a9bea5) + react-native: 0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5) transitivePeerDependencies: - '@expo/dom-webview' - '@expo/metro-runtime' @@ -8488,18 +8677,18 @@ snapshots: transitivePeerDependencies: - supports-color - '@expo/devtools@55.0.2(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)': + '@expo/devtools@55.0.2(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)': dependencies: chalk: 4.1.2 optionalDependencies: react: 19.2.5 - react-native: 0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5) + react-native: 0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5) - '@expo/dom-webview@55.0.5(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)': + '@expo/dom-webview@55.0.5(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)': dependencies: - expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@5.0.4(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5)))(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) react: 19.2.5 - react-native: 0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5) + react-native: 0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5) '@expo/env@2.1.1': dependencies: @@ -8551,13 +8740,13 @@ snapshots: - supports-color - typescript - '@expo/log-box@55.0.10(@expo/dom-webview@55.0.5)(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)': + '@expo/log-box@55.0.10(@expo/dom-webview@55.0.5)(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)': dependencies: - '@expo/dom-webview': 55.0.5(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + '@expo/dom-webview': 55.0.5(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) anser: 1.4.10 - expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@5.0.4(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5)))(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) react: 19.2.5 - react-native: 0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5) + react-native: 0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5) stacktrace-parser: 0.1.11 '@expo/metro-config@55.0.15(expo@55.0.14)(typescript@5.9.3)': @@ -8582,16 +8771,27 @@ snapshots: postcss: 8.4.49 resolve-from: 5.0.0 optionalDependencies: - expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@5.0.4(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5)))(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) transitivePeerDependencies: - bufferutil - supports-color - typescript - utf-8-validate - '@expo/metro-runtime@5.0.4(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))': + '@expo/metro-runtime@55.0.9(@expo/dom-webview@55.0.5)(expo@55.0.14)(react-dom@19.2.5(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)': dependencies: - react-native: 0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5) + '@expo/log-box': 55.0.10(@expo/dom-webview@55.0.5)(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + anser: 1.4.10 + expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + pretty-format: 29.7.0 + react: 19.2.5 + react-native: 0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5) + stacktrace-parser: 0.1.11 + whatwg-fetch: 3.6.20 + optionalDependencies: + react-dom: 19.2.5(react@19.2.5) + transitivePeerDependencies: + - '@expo/dom-webview' '@expo/metro@55.0.0': dependencies: @@ -8642,7 +8842,7 @@ snapshots: '@expo/json-file': 10.0.13 '@react-native/normalize-colors': 0.83.4 debug: 4.4.3 - expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@5.0.4(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5)))(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) resolve-from: 5.0.0 semver: 7.7.4 xml2js: 0.6.0 @@ -8660,17 +8860,17 @@ snapshots: transitivePeerDependencies: - supports-color - '@expo/router-server@55.0.14(@expo/metro-runtime@5.0.4(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5)))(expo-constants@55.0.13)(expo-font@55.0.6)(expo-router@55.0.12)(expo-server@55.0.7)(expo@55.0.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': + '@expo/router-server@55.0.14(@expo/metro-runtime@55.0.9)(expo-constants@55.0.13)(expo-font@55.0.6)(expo-router@55.0.12)(expo-server@55.0.7)(expo@55.0.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: debug: 4.4.3 - expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@5.0.4(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5)))(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) - expo-constants: 55.0.13(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(typescript@5.9.3) - expo-font: 55.0.6(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + expo-constants: 55.0.13(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(typescript@5.9.3) + expo-font: 55.0.6(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) expo-server: 55.0.7 react: 19.2.5 optionalDependencies: - '@expo/metro-runtime': 5.0.4(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5)) - expo-router: 55.0.12(@expo/log-box@55.0.10)(@expo/metro-runtime@5.0.4(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5)))(@testing-library/react-native@13.3.3(jest@29.7.0(@types/node@25.5.2)(ts-node@10.9.2(@types/node@25.5.2)(typescript@5.9.3)))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react-test-renderer@19.2.5(react@19.2.5))(react@19.2.5))(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(expo-constants@55.0.13)(expo-font@55.0.6)(expo-linking@55.0.12)(expo@55.0.14)(react-dom@19.2.5(react@19.2.5))(react-native-safe-area-context@5.6.2(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native-screens@4.23.0(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + '@expo/metro-runtime': 55.0.9(@expo/dom-webview@55.0.5)(expo@55.0.14)(react-dom@19.2.5(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + expo-router: 55.0.12(c811543d83d1946bea5c9894f6a9bea5) react-dom: 19.2.5(react@19.2.5) transitivePeerDependencies: - supports-color @@ -8685,11 +8885,11 @@ snapshots: '@expo/sudo-prompt@9.3.2': {} - '@expo/vector-icons@15.1.1(expo-font@55.0.6)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)': + '@expo/vector-icons@15.1.1(expo-font@55.0.6)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)': dependencies: - expo-font: 55.0.6(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + expo-font: 55.0.6(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) react: 19.2.5 - react-native: 0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5) + react-native: 0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5) '@expo/ws-tunnel@1.0.6': {} @@ -8719,6 +8919,23 @@ snapshots: lodash: 4.18.1 polyclip-ts: 0.16.8 + '@gorhom/bottom-sheet@5.2.9(@types/react@19.2.14)(react-native-gesture-handler@2.31.1(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native-reanimated@4.3.0(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)': + dependencies: + '@gorhom/portal': 1.0.14(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + invariant: 2.2.4 + react: 19.2.5 + react-native: 0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5) + react-native-gesture-handler: 2.31.1(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + react-native-reanimated: 4.3.0(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + optionalDependencies: + '@types/react': 19.2.14 + + '@gorhom/portal@1.0.14(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)': + dependencies: + nanoid: 3.3.11 + react: 19.2.5 + react-native: 0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5) + '@hexagon/base64@1.1.28': {} '@humanfs/core@0.19.1': {} @@ -8960,7 +9177,7 @@ snapshots: dependencies: '@lezer/common': 1.5.2 - '@maplibre/maplibre-react-native@10.4.2(@expo/config-plugins@55.0.8)(@types/geojson@7946.0.16)(@types/react@19.2.14)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)': + '@maplibre/maplibre-react-native@10.4.2(@expo/config-plugins@55.0.8)(@types/geojson@7946.0.16)(@types/react@19.2.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)': dependencies: '@turf/distance': 7.3.4 '@turf/helpers': 7.3.4 @@ -8968,7 +9185,7 @@ snapshots: '@turf/nearest-point-on-line': 7.3.4 debounce: 2.2.0 react: 19.2.5 - react-native: 0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5) + react-native: 0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5) optionalDependencies: '@expo/config-plugins': 55.0.8 '@types/geojson': 7946.0.16 @@ -9560,6 +9777,14 @@ snapshots: - '@babel/core' - supports-color + '@react-native/babel-plugin-codegen@0.85.1(@babel/core@7.29.0)': + dependencies: + '@babel/traverse': 7.29.0 + '@react-native/codegen': 0.85.1(@babel/core@7.29.0) + transitivePeerDependencies: + - '@babel/core' + - supports-color + '@react-native/babel-preset@0.83.4(@babel/core@7.29.0)': dependencies: '@babel/core': 7.29.0 @@ -9610,6 +9835,44 @@ snapshots: transitivePeerDependencies: - supports-color + '@react-native/babel-preset@0.85.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/plugin-proposal-export-default-from': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.29.0) + '@babel/plugin-syntax-export-default-from': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.29.0) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.29.0) + '@babel/plugin-transform-async-generator-functions': 7.29.0(@babel/core@7.29.0) + '@babel/plugin-transform-async-to-generator': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-block-scoping': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-class-properties': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-classes': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.29.0) + '@babel/plugin-transform-flow-strip-types': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-for-of': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-modules-commonjs': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-named-capturing-groups-regex': 7.29.0(@babel/core@7.29.0) + '@babel/plugin-transform-nullish-coalescing-operator': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-optional-catch-binding': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-optional-chaining': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-private-methods': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-private-property-in-object': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-react-display-name': 7.28.0(@babel/core@7.29.0) + '@babel/plugin-transform-react-jsx': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-regenerator': 7.29.0(@babel/core@7.29.0) + '@babel/plugin-transform-runtime': 7.29.0(@babel/core@7.29.0) + '@babel/plugin-transform-typescript': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-unicode-regex': 7.27.1(@babel/core@7.29.0) + '@react-native/babel-plugin-codegen': 0.85.1(@babel/core@7.29.0) + babel-plugin-syntax-hermes-parser: 0.33.3 + babel-plugin-transform-flow-enums: 0.0.2(@babel/core@7.29.0) + react-refresh: 0.14.2 + transitivePeerDependencies: + - supports-color + '@react-native/codegen@0.83.4(@babel/core@7.29.0)': dependencies: '@babel/core': 7.29.0 @@ -9620,7 +9883,17 @@ snapshots: nullthrows: 1.1.1 yargs: 17.7.2 - '@react-native/community-cli-plugin@0.83.4': + '@react-native/codegen@0.85.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/parser': 7.29.2 + hermes-parser: 0.33.3 + invariant: 2.2.4 + nullthrows: 1.1.1 + tinyglobby: 0.2.15 + yargs: 17.7.2 + + '@react-native/community-cli-plugin@0.83.4(@react-native/metro-config@0.85.1(@babel/core@7.29.0))': dependencies: '@react-native/dev-middleware': 0.83.4 debug: 4.4.3 @@ -9629,6 +9902,8 @@ snapshots: metro-config: 0.83.5 metro-core: 0.83.5 semver: 7.7.4 + optionalDependencies: + '@react-native/metro-config': 0.85.1(@babel/core@7.29.0) transitivePeerDependencies: - bufferutil - supports-color @@ -9664,26 +9939,49 @@ snapshots: '@react-native/js-polyfills@0.83.4': {} + '@react-native/js-polyfills@0.85.1': {} + + '@react-native/metro-babel-transformer@0.85.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@react-native/babel-preset': 0.85.1(@babel/core@7.29.0) + hermes-parser: 0.33.3 + nullthrows: 1.1.1 + transitivePeerDependencies: + - supports-color + + '@react-native/metro-config@0.85.1(@babel/core@7.29.0)': + dependencies: + '@react-native/js-polyfills': 0.85.1 + '@react-native/metro-babel-transformer': 0.85.1(@babel/core@7.29.0) + metro-config: 0.84.3 + metro-runtime: 0.84.3 + transitivePeerDependencies: + - '@babel/core' + - bufferutil + - supports-color + - utf-8-validate + '@react-native/normalize-colors@0.83.4': {} - '@react-native/virtualized-lists@0.83.4(@types/react@19.2.14)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)': + '@react-native/virtualized-lists@0.83.4(@types/react@19.2.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)': dependencies: invariant: 2.2.4 nullthrows: 1.1.1 react: 19.2.5 - react-native: 0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5) + react-native: 0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5) optionalDependencies: '@types/react': 19.2.14 - '@react-navigation/bottom-tabs@7.15.9(@react-navigation/native@7.2.2(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native-safe-area-context@5.6.2(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native-screens@4.23.0(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)': + '@react-navigation/bottom-tabs@7.15.9(@react-navigation/native@7.2.2(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native-safe-area-context@5.6.2(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native-screens@4.23.0(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)': dependencies: - '@react-navigation/elements': 2.9.14(@react-navigation/native@7.2.2(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native-safe-area-context@5.6.2(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) - '@react-navigation/native': 7.2.2(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + '@react-navigation/elements': 2.9.14(@react-navigation/native@7.2.2(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native-safe-area-context@5.6.2(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + '@react-navigation/native': 7.2.2(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) color: 4.2.3 react: 19.2.5 - react-native: 0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5) - react-native-safe-area-context: 5.6.2(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) - react-native-screens: 4.23.0(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + react-native: 0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5) + react-native-safe-area-context: 5.6.2(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + react-native-screens: 4.23.0(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) sf-symbols-typescript: 2.2.0 transitivePeerDependencies: - '@react-native-masked-view/masked-view' @@ -9700,38 +9998,38 @@ snapshots: use-latest-callback: 0.2.6(react@19.2.5) use-sync-external-store: 1.6.0(react@19.2.5) - '@react-navigation/elements@2.9.14(@react-navigation/native@7.2.2(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native-safe-area-context@5.6.2(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)': + '@react-navigation/elements@2.9.14(@react-navigation/native@7.2.2(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native-safe-area-context@5.6.2(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)': dependencies: - '@react-navigation/native': 7.2.2(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + '@react-navigation/native': 7.2.2(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) color: 4.2.3 react: 19.2.5 - react-native: 0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5) - react-native-safe-area-context: 5.6.2(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + react-native: 0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5) + react-native-safe-area-context: 5.6.2(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) use-latest-callback: 0.2.6(react@19.2.5) use-sync-external-store: 1.6.0(react@19.2.5) - '@react-navigation/native-stack@7.14.10(@react-navigation/native@7.2.2(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native-safe-area-context@5.6.2(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native-screens@4.23.0(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)': + '@react-navigation/native-stack@7.14.10(@react-navigation/native@7.2.2(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native-safe-area-context@5.6.2(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native-screens@4.23.0(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)': dependencies: - '@react-navigation/elements': 2.9.14(@react-navigation/native@7.2.2(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native-safe-area-context@5.6.2(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) - '@react-navigation/native': 7.2.2(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + '@react-navigation/elements': 2.9.14(@react-navigation/native@7.2.2(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native-safe-area-context@5.6.2(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + '@react-navigation/native': 7.2.2(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) color: 4.2.3 react: 19.2.5 - react-native: 0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5) - react-native-safe-area-context: 5.6.2(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) - react-native-screens: 4.23.0(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + react-native: 0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5) + react-native-safe-area-context: 5.6.2(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + react-native-screens: 4.23.0(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) sf-symbols-typescript: 2.2.0 warn-once: 0.1.1 transitivePeerDependencies: - '@react-native-masked-view/masked-view' - '@react-navigation/native@7.2.2(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)': + '@react-navigation/native@7.2.2(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)': dependencies: '@react-navigation/core': 7.17.2(react@19.2.5) escape-string-regexp: 4.0.0 fast-deep-equal: 3.1.3 nanoid: 3.3.11 react: 19.2.5 - react-native: 0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5) + react-native: 0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5) use-latest-callback: 0.2.6(react@19.2.5) '@react-navigation/routers@7.5.3': @@ -10210,7 +10508,7 @@ snapshots: '@opentelemetry/semantic-conventions': 1.40.0 '@sentry/core': 10.48.0 - '@sentry/react-native@7.11.0(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)': + '@sentry/react-native@7.11.0(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)': dependencies: '@sentry/babel-plugin-component-annotate': 4.8.0 '@sentry/browser': 10.37.0 @@ -10219,9 +10517,9 @@ snapshots: '@sentry/react': 10.37.0(react@19.2.5) '@sentry/types': 10.37.0 react: 19.2.5 - react-native: 0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5) + react-native: 0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5) optionalDependencies: - expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@5.0.4(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5)))(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) transitivePeerDependencies: - encoding - supports-color @@ -10378,13 +10676,13 @@ snapshots: picocolors: 1.1.1 redent: 3.0.0 - '@testing-library/react-native@13.3.3(jest@29.7.0(@types/node@25.5.2)(ts-node@10.9.2(@types/node@25.5.2)(typescript@5.9.3)))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react-test-renderer@19.2.5(react@19.2.5))(react@19.2.5)': + '@testing-library/react-native@13.3.3(jest@29.7.0(@types/node@25.5.2)(ts-node@10.9.2(@types/node@25.5.2)(typescript@5.9.3)))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react-test-renderer@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: jest-matcher-utils: 30.3.0 picocolors: 1.1.1 pretty-format: 30.3.0 react: 19.2.5 - react-native: 0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5) + react-native: 0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5) react-test-renderer: 19.2.5(react@19.2.5) redent: 3.0.0 optionalDependencies: @@ -10606,6 +10904,8 @@ snapshots: dependencies: '@types/node': 25.5.2 + '@types/hammerjs@2.0.46': {} + '@types/istanbul-lib-coverage@2.0.6': {} '@types/istanbul-lib-report@3.0.3': @@ -10667,6 +10967,10 @@ snapshots: dependencies: '@types/react': 19.2.14 + '@types/react-test-renderer@19.1.0': + dependencies: + '@types/react': 19.2.14 + '@types/react@19.2.14': dependencies: csstype: 3.2.3 @@ -11024,6 +11328,10 @@ snapshots: dependencies: hermes-parser: 0.32.1 + babel-plugin-syntax-hermes-parser@0.33.3: + dependencies: + hermes-parser: 0.33.3 + babel-plugin-transform-flow-enums@0.0.2(@babel/core@7.29.0): dependencies: '@babel/plugin-syntax-flow': 7.28.6(@babel/core@7.29.0) @@ -11077,7 +11385,7 @@ snapshots: resolve-from: 5.0.0 optionalDependencies: '@babel/runtime': 7.29.2 - expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@5.0.4(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5)))(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) transitivePeerDependencies: - '@babel/core' - supports-color @@ -11524,11 +11832,11 @@ snapshots: esbuild: 0.25.12 tsx: 4.21.0 - drizzle-orm@0.45.2(@opentelemetry/api@1.9.1)(@types/pg@8.15.6)(expo-sqlite@55.0.15(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(pg@8.20.0)(postgres@3.4.9): + drizzle-orm@0.45.2(@opentelemetry/api@1.9.1)(@types/pg@8.15.6)(expo-sqlite@55.0.15(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(pg@8.20.0)(postgres@3.4.9): optionalDependencies: '@opentelemetry/api': 1.9.1 '@types/pg': 8.15.6 - expo-sqlite: 55.0.15(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + expo-sqlite: 55.0.15(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) pg: 8.20.0 postgres: 3.4.9 @@ -11805,36 +12113,36 @@ snapshots: expo-application@55.0.14(expo@55.0.14): dependencies: - expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@5.0.4(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5)))(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) - expo-asset@55.0.14(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3): + expo-asset@55.0.14(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3): dependencies: '@expo/image-utils': 0.8.13(typescript@5.9.3) - expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@5.0.4(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5)))(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) - expo-constants: 55.0.13(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(typescript@5.9.3) + expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + expo-constants: 55.0.13(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(typescript@5.9.3) react: 19.2.5 - react-native: 0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5) + react-native: 0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5) transitivePeerDependencies: - supports-color - typescript - expo-constants@55.0.13(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(typescript@5.9.3): + expo-constants@55.0.13(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(typescript@5.9.3): dependencies: '@expo/config': 55.0.14(typescript@5.9.3) '@expo/env': 2.1.1 - expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@5.0.4(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5)))(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) - react-native: 0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5) + expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + react-native: 0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5) transitivePeerDependencies: - supports-color - typescript expo-crypto@55.0.14(expo@55.0.14): dependencies: - expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@5.0.4(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5)))(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) expo-dev-client@55.0.27(expo@55.0.14)(typescript@5.9.3): dependencies: - expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@5.0.4(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5)))(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) expo-dev-launcher: 55.0.28(expo@55.0.14)(typescript@5.9.3) expo-dev-menu: 55.0.23(expo@55.0.14) expo-dev-menu-interface: 55.0.2(expo@55.0.14) @@ -11847,7 +12155,7 @@ snapshots: expo-dev-launcher@55.0.28(expo@55.0.14)(typescript@5.9.3): dependencies: '@expo/schema-utils': 55.0.3 - expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@5.0.4(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5)))(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) expo-dev-menu: 55.0.23(expo@55.0.14) expo-manifests: 55.0.15(expo@55.0.14)(typescript@5.9.3) transitivePeerDependencies: @@ -11856,51 +12164,51 @@ snapshots: expo-dev-menu-interface@55.0.2(expo@55.0.14): dependencies: - expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@5.0.4(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5)))(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) expo-dev-menu@55.0.23(expo@55.0.14): dependencies: - expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@5.0.4(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5)))(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) expo-dev-menu-interface: 55.0.2(expo@55.0.14) - expo-file-system@55.0.16(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5)): + expo-file-system@55.0.16(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5)): dependencies: - expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@5.0.4(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5)))(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) - react-native: 0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5) + expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + react-native: 0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5) - expo-font@55.0.6(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5): + expo-font@55.0.6(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5): dependencies: - expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@5.0.4(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5)))(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) fontfaceobserver: 2.3.0 react: 19.2.5 - react-native: 0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5) + react-native: 0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5) - expo-glass-effect@55.0.10(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5): + expo-glass-effect@55.0.10(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5): dependencies: - expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@5.0.4(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5)))(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) react: 19.2.5 - react-native: 0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5) + react-native: 0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5) - expo-image@55.0.8(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5): + expo-image@55.0.8(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5): dependencies: - expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@5.0.4(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5)))(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) react: 19.2.5 - react-native: 0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5) + react-native: 0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5) sf-symbols-typescript: 2.2.0 expo-json-utils@55.0.2: {} expo-keep-awake@55.0.6(expo@55.0.14)(react@19.2.5): dependencies: - expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@5.0.4(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5)))(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) react: 19.2.5 - expo-linking@55.0.12(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3): + expo-linking@55.0.12(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3): dependencies: - expo-constants: 55.0.13(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(typescript@5.9.3) + expo-constants: 55.0.13(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(typescript@5.9.3) invariant: 2.2.4 react: 19.2.5 - react-native: 0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5) + react-native: 0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5) transitivePeerDependencies: - expo - supports-color @@ -11909,7 +12217,7 @@ snapshots: expo-location@55.1.8(expo@55.0.14)(typescript@5.9.3): dependencies: '@expo/image-utils': 0.8.13(typescript@5.9.3) - expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@5.0.4(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5)))(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) transitivePeerDependencies: - supports-color - typescript @@ -11917,7 +12225,7 @@ snapshots: expo-manifests@55.0.15(expo@55.0.14)(typescript@5.9.3): dependencies: '@expo/config': 55.0.14(typescript@5.9.3) - expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@5.0.4(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5)))(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) expo-json-utils: 55.0.2 transitivePeerDependencies: - supports-color @@ -11933,56 +12241,58 @@ snapshots: - supports-color - typescript - expo-modules-core@55.0.22(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5): + expo-modules-core@55.0.22(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5): dependencies: invariant: 2.2.4 react: 19.2.5 - react-native: 0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5) + react-native: 0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5) + optionalDependencies: + react-native-worklets: 0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) - expo-notifications@55.0.18(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3): + expo-notifications@55.0.18(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3): dependencies: '@expo/image-utils': 0.8.13(typescript@5.9.3) abort-controller: 3.0.0 badgin: 1.2.3 - expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@5.0.4(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5)))(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) expo-application: 55.0.14(expo@55.0.14) - expo-constants: 55.0.13(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(typescript@5.9.3) + expo-constants: 55.0.13(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(typescript@5.9.3) react: 19.2.5 - react-native: 0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5) + react-native: 0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5) transitivePeerDependencies: - supports-color - typescript - expo-router@55.0.12(@expo/log-box@55.0.10)(@expo/metro-runtime@5.0.4(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5)))(@testing-library/react-native@13.3.3(jest@29.7.0(@types/node@25.5.2)(ts-node@10.9.2(@types/node@25.5.2)(typescript@5.9.3)))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react-test-renderer@19.2.5(react@19.2.5))(react@19.2.5))(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(expo-constants@55.0.13)(expo-font@55.0.6)(expo-linking@55.0.12)(expo@55.0.14)(react-dom@19.2.5(react@19.2.5))(react-native-safe-area-context@5.6.2(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native-screens@4.23.0(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5): + expo-router@55.0.12(c811543d83d1946bea5c9894f6a9bea5): dependencies: - '@expo/log-box': 55.0.10(@expo/dom-webview@55.0.5)(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) - '@expo/metro-runtime': 5.0.4(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5)) + '@expo/log-box': 55.0.10(@expo/dom-webview@55.0.5)(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + '@expo/metro-runtime': 55.0.9(@expo/dom-webview@55.0.5)(expo@55.0.14)(react-dom@19.2.5(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) '@expo/schema-utils': 55.0.3 '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.5) '@radix-ui/react-tabs': 1.1.13(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) - '@react-navigation/bottom-tabs': 7.15.9(@react-navigation/native@7.2.2(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native-safe-area-context@5.6.2(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native-screens@4.23.0(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) - '@react-navigation/native': 7.2.2(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) - '@react-navigation/native-stack': 7.14.10(@react-navigation/native@7.2.2(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native-safe-area-context@5.6.2(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native-screens@4.23.0(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + '@react-navigation/bottom-tabs': 7.15.9(@react-navigation/native@7.2.2(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native-safe-area-context@5.6.2(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native-screens@4.23.0(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + '@react-navigation/native': 7.2.2(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + '@react-navigation/native-stack': 7.14.10(@react-navigation/native@7.2.2(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native-safe-area-context@5.6.2(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native-screens@4.23.0(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) client-only: 0.0.1 debug: 4.4.3 escape-string-regexp: 4.0.0 - expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@5.0.4(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5)))(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) - expo-constants: 55.0.13(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(typescript@5.9.3) - expo-glass-effect: 55.0.10(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) - expo-image: 55.0.8(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) - expo-linking: 55.0.12(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + expo-constants: 55.0.13(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(typescript@5.9.3) + expo-glass-effect: 55.0.10(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + expo-image: 55.0.8(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + expo-linking: 55.0.12(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) expo-server: 55.0.7 - expo-symbols: 55.0.7(expo-font@55.0.6)(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + expo-symbols: 55.0.7(expo-font@55.0.6)(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) fast-deep-equal: 3.1.3 invariant: 2.2.4 nanoid: 3.3.11 query-string: 7.1.3 react: 19.2.5 react-fast-compare: 3.2.2 - react-native: 0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5) - react-native-is-edge-to-edge: 1.3.1(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) - react-native-safe-area-context: 5.6.2(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) - react-native-screens: 4.23.0(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + react-native: 0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5) + react-native-is-edge-to-edge: 1.3.1(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + react-native-safe-area-context: 5.6.2(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + react-native-screens: 4.23.0(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) semver: 7.6.3 server-only: 0.0.1 sf-symbols-typescript: 2.2.0 @@ -11990,8 +12300,10 @@ snapshots: use-latest-callback: 0.2.6(react@19.2.5) vaul: 1.1.2(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) optionalDependencies: - '@testing-library/react-native': 13.3.3(jest@29.7.0(@types/node@25.5.2)(ts-node@10.9.2(@types/node@25.5.2)(typescript@5.9.3)))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react-test-renderer@19.2.5(react@19.2.5))(react@19.2.5) + '@testing-library/react-native': 13.3.3(jest@29.7.0(@types/node@25.5.2)(ts-node@10.9.2(@types/node@25.5.2)(typescript@5.9.3)))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react-test-renderer@19.2.5(react@19.2.5))(react@19.2.5) react-dom: 19.2.5(react@19.2.5) + react-native-gesture-handler: 2.31.1(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + react-native-reanimated: 4.3.0(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) transitivePeerDependencies: - '@react-native-masked-view/masked-view' - '@types/react' @@ -12001,71 +12313,71 @@ snapshots: expo-secure-store@55.0.13(expo@55.0.14): dependencies: - expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@5.0.4(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5)))(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) expo-server@55.0.7: {} - expo-sqlite@55.0.15(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5): + expo-sqlite@55.0.15(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5): dependencies: await-lock: 2.2.2 - expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@5.0.4(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5)))(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) react: 19.2.5 - react-native: 0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5) + react-native: 0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5) - expo-status-bar@55.0.5(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5): + expo-status-bar@55.0.5(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5): dependencies: react: 19.2.5 - react-native: 0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5) - react-native-is-edge-to-edge: 1.3.1(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + react-native: 0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5) + react-native-is-edge-to-edge: 1.3.1(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) - expo-symbols@55.0.7(expo-font@55.0.6)(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5): + expo-symbols@55.0.7(expo-font@55.0.6)(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5): dependencies: '@expo-google-fonts/material-symbols': 0.4.30 - expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@5.0.4(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5)))(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) - expo-font: 55.0.6(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + expo-font: 55.0.6(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) react: 19.2.5 - react-native: 0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5) + react-native: 0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5) sf-symbols-typescript: 2.2.0 expo-updates-interface@55.1.5(expo@55.0.14): dependencies: - expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@5.0.4(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5)))(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) - expo-web-browser@55.0.14(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5)): + expo-web-browser@55.0.14(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5)): dependencies: - expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@5.0.4(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5)))(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) - react-native: 0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5) + expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + react-native: 0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5) - expo@55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@5.0.4(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5)))(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3): + expo@55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3): dependencies: '@babel/runtime': 7.29.2 - '@expo/cli': 55.0.23(@expo/dom-webview@55.0.5)(@expo/metro-runtime@5.0.4(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5)))(expo-constants@55.0.13)(expo-font@55.0.6)(expo-router@55.0.12)(expo@55.0.14)(react-dom@19.2.5(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + '@expo/cli': 55.0.23(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-constants@55.0.13)(expo-font@55.0.6)(expo-router@55.0.12)(expo@55.0.14)(react-dom@19.2.5(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) '@expo/config': 55.0.14(typescript@5.9.3) '@expo/config-plugins': 55.0.8 - '@expo/devtools': 55.0.2(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + '@expo/devtools': 55.0.2(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) '@expo/fingerprint': 0.16.6 '@expo/local-build-cache-provider': 55.0.10(typescript@5.9.3) - '@expo/log-box': 55.0.10(@expo/dom-webview@55.0.5)(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + '@expo/log-box': 55.0.10(@expo/dom-webview@55.0.5)(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) '@expo/metro': 55.0.0 '@expo/metro-config': 55.0.15(expo@55.0.14)(typescript@5.9.3) - '@expo/vector-icons': 15.1.1(expo-font@55.0.6)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + '@expo/vector-icons': 15.1.1(expo-font@55.0.6)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) '@ungap/structured-clone': 1.3.0 babel-preset-expo: 55.0.17(@babel/core@7.29.0)(@babel/runtime@7.29.2)(expo@55.0.14)(react-refresh@0.14.2) - expo-asset: 55.0.14(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) - expo-constants: 55.0.13(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(typescript@5.9.3) - expo-file-system: 55.0.16(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5)) - expo-font: 55.0.6(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + expo-asset: 55.0.14(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + expo-constants: 55.0.13(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(typescript@5.9.3) + expo-file-system: 55.0.16(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5)) + expo-font: 55.0.6(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) expo-keep-awake: 55.0.6(expo@55.0.14)(react@19.2.5) expo-modules-autolinking: 55.0.17(typescript@5.9.3) - expo-modules-core: 55.0.22(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + expo-modules-core: 55.0.22(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) pretty-format: 29.7.0 react: 19.2.5 - react-native: 0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5) + react-native: 0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5) react-refresh: 0.14.2 whatwg-url-minimum: 0.1.1 optionalDependencies: - '@expo/dom-webview': 55.0.5(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) - '@expo/metro-runtime': 5.0.4(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5)) + '@expo/dom-webview': 55.0.5(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + '@expo/metro-runtime': 55.0.9(@expo/dom-webview@55.0.5)(expo@55.0.14)(react-dom@19.2.5(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) transitivePeerDependencies: - '@babel/core' - bufferutil @@ -12306,6 +12618,8 @@ snapshots: hermes-estree@0.33.3: {} + hermes-estree@0.35.0: {} + hermes-parser@0.32.0: dependencies: hermes-estree: 0.32.0 @@ -12318,6 +12632,14 @@ snapshots: dependencies: hermes-estree: 0.33.3 + hermes-parser@0.35.0: + dependencies: + hermes-estree: 0.35.0 + + hoist-non-react-statics@3.3.2: + dependencies: + react-is: 16.13.1 + hosted-git-info@7.0.2: dependencies: lru-cache: 10.4.3 @@ -12652,21 +12974,21 @@ snapshots: jest-mock: 29.7.0 jest-util: 29.7.0 - jest-expo@55.0.15(@babel/core@7.29.0)(expo@55.0.14)(jest@29.7.0(@types/node@25.5.2)(ts-node@10.9.2(@types/node@25.5.2)(typescript@5.9.3)))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3): + jest-expo@55.0.15(@babel/core@7.29.0)(expo@55.0.14)(jest@29.7.0(@types/node@25.5.2)(ts-node@10.9.2(@types/node@25.5.2)(typescript@5.9.3)))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3): dependencies: '@expo/config': 55.0.14(typescript@5.9.3) '@expo/json-file': 10.0.13 '@jest/create-cache-key-function': 29.7.0 '@jest/globals': 29.7.0 babel-jest: 29.7.0(@babel/core@7.29.0) - expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@5.0.4(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5)))(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) jest-environment-jsdom: 29.7.0 jest-snapshot: 29.7.0 jest-watch-select-projects: 2.0.0 jest-watch-typeahead: 2.2.1(jest@29.7.0(@types/node@25.5.2)(ts-node@10.9.2(@types/node@25.5.2)(typescript@5.9.3))) json5: 2.2.3 lodash: 4.18.1 - react-native: 0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5) + react-native: 0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5) react-test-renderer: 19.2.0(react@19.2.5) server-only: 0.0.1 stacktrace-js: 2.0.2 @@ -13162,10 +13484,24 @@ snapshots: transitivePeerDependencies: - supports-color + metro-babel-transformer@0.84.3: + dependencies: + '@babel/core': 7.29.0 + flow-enums-runtime: 0.0.6 + hermes-parser: 0.35.0 + metro-cache-key: 0.84.3 + nullthrows: 1.1.1 + transitivePeerDependencies: + - supports-color + metro-cache-key@0.83.5: dependencies: flow-enums-runtime: 0.0.6 + metro-cache-key@0.84.3: + dependencies: + flow-enums-runtime: 0.0.6 + metro-cache@0.83.5: dependencies: exponential-backoff: 3.1.3 @@ -13175,6 +13511,15 @@ snapshots: transitivePeerDependencies: - supports-color + metro-cache@0.84.3: + dependencies: + exponential-backoff: 3.1.3 + flow-enums-runtime: 0.0.6 + https-proxy-agent: 7.0.6 + metro-core: 0.84.3 + transitivePeerDependencies: + - supports-color + metro-config@0.83.5: dependencies: connect: 3.7.0 @@ -13190,12 +13535,33 @@ snapshots: - supports-color - utf-8-validate + metro-config@0.84.3: + dependencies: + connect: 3.7.0 + flow-enums-runtime: 0.0.6 + jest-validate: 29.7.0 + metro: 0.84.3 + metro-cache: 0.84.3 + metro-core: 0.84.3 + metro-runtime: 0.84.3 + yaml: 2.8.3 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + metro-core@0.83.5: dependencies: flow-enums-runtime: 0.0.6 lodash.throttle: 4.1.1 metro-resolver: 0.83.5 + metro-core@0.84.3: + dependencies: + flow-enums-runtime: 0.0.6 + lodash.throttle: 4.1.1 + metro-resolver: 0.84.3 + metro-file-map@0.83.5: dependencies: debug: 4.4.3 @@ -13210,20 +13576,48 @@ snapshots: transitivePeerDependencies: - supports-color + metro-file-map@0.84.3: + dependencies: + debug: 4.4.3 + fb-watchman: 2.0.2 + flow-enums-runtime: 0.0.6 + graceful-fs: 4.2.11 + invariant: 2.2.4 + jest-worker: 29.7.0 + micromatch: 4.0.8 + nullthrows: 1.1.1 + walker: 1.0.8 + transitivePeerDependencies: + - supports-color + metro-minify-terser@0.83.5: dependencies: flow-enums-runtime: 0.0.6 terser: 5.46.1 + metro-minify-terser@0.84.3: + dependencies: + flow-enums-runtime: 0.0.6 + terser: 5.46.1 + metro-resolver@0.83.5: dependencies: flow-enums-runtime: 0.0.6 + metro-resolver@0.84.3: + dependencies: + flow-enums-runtime: 0.0.6 + metro-runtime@0.83.5: dependencies: '@babel/runtime': 7.29.2 flow-enums-runtime: 0.0.6 + metro-runtime@0.84.3: + dependencies: + '@babel/runtime': 7.29.2 + flow-enums-runtime: 0.0.6 + metro-source-map@0.83.5: dependencies: '@babel/traverse': 7.29.0 @@ -13238,6 +13632,20 @@ snapshots: transitivePeerDependencies: - supports-color + metro-source-map@0.84.3: + dependencies: + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + flow-enums-runtime: 0.0.6 + invariant: 2.2.4 + metro-symbolicate: 0.84.3 + nullthrows: 1.1.1 + ob1: 0.84.3 + source-map: 0.5.7 + vlq: 1.0.1 + transitivePeerDependencies: + - supports-color + metro-symbolicate@0.83.5: dependencies: flow-enums-runtime: 0.0.6 @@ -13249,6 +13657,17 @@ snapshots: transitivePeerDependencies: - supports-color + metro-symbolicate@0.84.3: + dependencies: + flow-enums-runtime: 0.0.6 + invariant: 2.2.4 + metro-source-map: 0.84.3 + nullthrows: 1.1.1 + source-map: 0.5.7 + vlq: 1.0.1 + transitivePeerDependencies: + - supports-color + metro-transform-plugins@0.83.5: dependencies: '@babel/core': 7.29.0 @@ -13260,6 +13679,17 @@ snapshots: transitivePeerDependencies: - supports-color + metro-transform-plugins@0.84.3: + dependencies: + '@babel/core': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/template': 7.28.6 + '@babel/traverse': 7.29.0 + flow-enums-runtime: 0.0.6 + nullthrows: 1.1.1 + transitivePeerDependencies: + - supports-color + metro-transform-worker@0.83.5: dependencies: '@babel/core': 7.29.0 @@ -13280,6 +13710,26 @@ snapshots: - supports-color - utf-8-validate + metro-transform-worker@0.84.3: + dependencies: + '@babel/core': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/parser': 7.29.2 + '@babel/types': 7.29.0 + flow-enums-runtime: 0.0.6 + metro: 0.84.3 + metro-babel-transformer: 0.84.3 + metro-cache: 0.84.3 + metro-cache-key: 0.84.3 + metro-minify-terser: 0.84.3 + metro-source-map: 0.84.3 + metro-transform-plugins: 0.84.3 + nullthrows: 1.1.1 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + metro@0.83.5: dependencies: '@babel/code-frame': 7.29.0 @@ -13327,6 +13777,53 @@ snapshots: - supports-color - utf-8-validate + metro@0.84.3: + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/core': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/parser': 7.29.2 + '@babel/template': 7.28.6 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + accepts: 2.0.0 + chalk: 4.1.2 + ci-info: 2.0.0 + connect: 3.7.0 + debug: 4.4.3 + error-stack-parser: 2.1.4 + flow-enums-runtime: 0.0.6 + graceful-fs: 4.2.11 + hermes-parser: 0.35.0 + image-size: 1.2.1 + invariant: 2.2.4 + jest-worker: 29.7.0 + jsc-safe-url: 0.2.4 + lodash.throttle: 4.1.1 + metro-babel-transformer: 0.84.3 + metro-cache: 0.84.3 + metro-cache-key: 0.84.3 + metro-config: 0.84.3 + metro-core: 0.84.3 + metro-file-map: 0.84.3 + metro-resolver: 0.84.3 + metro-runtime: 0.84.3 + metro-source-map: 0.84.3 + metro-symbolicate: 0.84.3 + metro-transform-plugins: 0.84.3 + metro-transform-worker: 0.84.3 + mime-types: 3.0.2 + nullthrows: 1.1.1 + serialize-error: 2.1.0 + source-map: 0.5.7 + throat: 5.0.0 + ws: 7.5.10 + yargs: 17.7.2 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + micromatch@4.0.8: dependencies: braces: 3.0.3 @@ -13431,6 +13928,10 @@ snapshots: dependencies: flow-enums-runtime: 0.0.6 + ob1@0.84.3: + dependencies: + flow-enums-runtime: 0.0.6 + object-inspect@1.13.4: {} obug@2.1.1: {} @@ -13815,7 +14316,7 @@ snapshots: dependencies: react: 19.2.5 - react-i18next@17.0.2(i18next@26.0.4(typescript@5.9.3))(react-dom@19.2.5(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3): + react-i18next@17.0.2(i18next@26.0.4(typescript@5.9.3))(react-dom@19.2.5(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3): dependencies: '@babel/runtime': 7.29.2 html-parse-stringify: 3.0.1 @@ -13824,9 +14325,11 @@ snapshots: use-sync-external-store: 1.6.0(react@19.2.5) optionalDependencies: react-dom: 19.2.5(react@19.2.5) - react-native: 0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5) + react-native: 0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5) typescript: 5.9.3 + react-is@16.13.1: {} + react-is@17.0.2: {} react-is@18.3.1: {} @@ -13840,33 +14343,70 @@ snapshots: react: 19.2.5 react-dom: 19.2.5(react@19.2.5) - react-native-is-edge-to-edge@1.3.1(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5): + react-native-gesture-handler@2.31.1(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5): + dependencies: + '@egjs/hammerjs': 2.0.17 + '@types/react-test-renderer': 19.1.0 + hoist-non-react-statics: 3.3.2 + invariant: 2.2.4 + react: 19.2.5 + react-native: 0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5) + + react-native-is-edge-to-edge@1.3.1(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5): dependencies: react: 19.2.5 - react-native: 0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5) + react-native: 0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5) - react-native-safe-area-context@5.6.2(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5): + react-native-reanimated@4.3.0(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5): dependencies: react: 19.2.5 - react-native: 0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5) + react-native: 0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5) + react-native-is-edge-to-edge: 1.3.1(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + react-native-worklets: 0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + semver: 7.7.4 - react-native-screens@4.23.0(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5): + react-native-safe-area-context@5.6.2(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5): + dependencies: + react: 19.2.5 + react-native: 0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5) + + react-native-screens@4.23.0(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5): dependencies: react: 19.2.5 react-freeze: 1.0.4(react@19.2.5) - react-native: 0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5) + react-native: 0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5) warn-once: 0.1.1 - react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5): + react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5): + dependencies: + '@babel/core': 7.29.0 + '@babel/plugin-transform-arrow-functions': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-class-properties': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-classes': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-nullish-coalescing-operator': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-optional-chaining': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-shorthand-properties': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-template-literals': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-unicode-regex': 7.27.1(@babel/core@7.29.0) + '@babel/preset-typescript': 7.28.5(@babel/core@7.29.0) + '@react-native/metro-config': 0.85.1(@babel/core@7.29.0) + convert-source-map: 2.0.0 + react: 19.2.5 + react-native: 0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5) + semver: 7.7.4 + transitivePeerDependencies: + - supports-color + + react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5): dependencies: '@jest/create-cache-key-function': 29.7.0 '@react-native/assets-registry': 0.83.4 '@react-native/codegen': 0.83.4(@babel/core@7.29.0) - '@react-native/community-cli-plugin': 0.83.4 + '@react-native/community-cli-plugin': 0.83.4(@react-native/metro-config@0.85.1(@babel/core@7.29.0)) '@react-native/gradle-plugin': 0.83.4 '@react-native/js-polyfills': 0.83.4 '@react-native/normalize-colors': 0.83.4 - '@react-native/virtualized-lists': 0.83.4(@types/react@19.2.14)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + '@react-native/virtualized-lists': 0.83.4(@types/react@19.2.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) abort-controller: 3.0.0 anser: 1.4.10 ansi-regex: 5.0.1 From b2514f48be135778a81d529e8613c872001830c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Tue, 14 Apr 2026 23:44:06 +0200 Subject: [PATCH 011/494] Add local build scripts via Expo CNG/prebuild - prebuild: generate native ios/ and android/ projects - prebuild:clean: regenerate from scratch - run:ios / run:android: build and run locally with Xcode/Gradle - Add ios/ and android/ to .gitignore (CNG-generated) Allows building locally without EAS credits: pnpm --filter @trails-cool/mobile prebuild pnpm --filter @trails-cool/mobile run:ios Co-Authored-By: Claude Opus 4.6 (1M context) --- apps/mobile/.gitignore | 4 + apps/mobile/app.config.ts | 1 - apps/mobile/package.json | 29 ++- package.json | 4 +- pnpm-lock.yaml | 441 ++++++++++++++++++++++++-------------- pnpm-workspace.yaml | 2 + 6 files changed, 310 insertions(+), 171 deletions(-) diff --git a/apps/mobile/.gitignore b/apps/mobile/.gitignore index d914c32..bef6739 100644 --- a/apps/mobile/.gitignore +++ b/apps/mobile/.gitignore @@ -9,6 +9,10 @@ dist/ web-build/ expo-env.d.ts +# CNG (Continuous Native Generation) +ios/ +android/ + # Native .kotlin/ *.orig.* diff --git a/apps/mobile/app.config.ts b/apps/mobile/app.config.ts index 9b37ecf..1cc21cd 100644 --- a/apps/mobile/app.config.ts +++ b/apps/mobile/app.config.ts @@ -44,7 +44,6 @@ export default ({ config }: ConfigContext): ExpoConfig => ({ project: "mobile", }], "expo-sqlite", - "react-native-reanimated", ], extra: { eas: { diff --git a/apps/mobile/package.json b/apps/mobile/package.json index 3ce3b0d..8aa036c 100644 --- a/apps/mobile/package.json +++ b/apps/mobile/package.json @@ -11,15 +11,16 @@ } }, "scripts": { - "start": "expo start", - "android": "expo start --android", - "ios": "expo start --ios", - "web": "expo start --web", + "start": "expo start --dev-client", + "prebuild": "expo prebuild", + "prebuild:clean": "expo prebuild --clean", + "ios": "expo run:ios", + "android": "expo run:android", "typecheck": "tsc --noEmit", "test": "jest", "lint": "eslint .", - "build:dev": "npx eas-cli build:dev --platform ios", - "build:preview": "npx eas-cli build --profile preview --platform all" + "eas:dev": "npx eas-cli build:dev --platform ios", + "eas:preview": "npx eas-cli build --profile preview --platform all" }, "jest": { "preset": "jest-expo", @@ -28,6 +29,7 @@ ] }, "dependencies": { + "@expo/metro-runtime": "^55.0.9", "@gorhom/bottom-sheet": "^5.2.9", "@maplibre/maplibre-react-native": "^10.4.2", "@sentry/cli": "^3.3.5", @@ -37,17 +39,24 @@ "@trails-cool/i18n": "workspace:*", "@trails-cool/map-core": "workspace:*", "@trails-cool/types": "workspace:*", - "expo": "~55.0.14", - "expo-constants": "~55.0.13", + "expo": "~55.0.15", + "expo-constants": "~55.0.14", "expo-crypto": "~55.0.14", "expo-dev-client": "~55.0.27", - "expo-linking": "~55.0.12", + "expo-dev-menu": "^55.0.23", + "expo-device": "~55.0.15", + "expo-file-system": "~55.0.16", + "expo-linking": "~55.0.13", + "expo-localization": "~55.0.13", "expo-location": "~55.1.8", - "expo-notifications": "~55.0.18", + "expo-navigation-bar": "~55.0.12", + "expo-notifications": "~55.0.19", "expo-router": "~55.0.12", "expo-secure-store": "~55.0.13", + "expo-splash-screen": "~55.0.18", "expo-sqlite": "~55.0.15", "expo-status-bar": "~55.0.5", + "expo-system-ui": "^55.0.15", "expo-web-browser": "~55.0.14", "react": "catalog:", "react-native": "0.83.4", diff --git a/package.json b/package.json index 79bbc5c..85de51a 100644 --- a/package.json +++ b/package.json @@ -21,8 +21,8 @@ "db:studio": "drizzle-kit studio --config packages/db/drizzle.config.ts", "dev:services": "docker compose -f docker-compose.dev.yml up -d", "dev:full": "./scripts/dev.sh", - "dev:ios": "pnpm --filter @trails-cool/mobile build:dev", - "dev:android": "pnpm --filter @trails-cool/mobile build:dev -- --platform android" + "dev:ios": "pnpm --filter @trails-cool/mobile ios", + "dev:android": "pnpm --filter @trails-cool/mobile android" }, "pnpm": { "overrides": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5b12ab5..ed42428 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -121,7 +121,7 @@ importers: version: 0.31.10 drizzle-orm: specifier: 'catalog:' - version: 0.45.2(@opentelemetry/api@1.9.1)(@types/pg@8.15.6)(expo-sqlite@55.0.15(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(pg@8.20.0)(postgres@3.4.9) + version: 0.45.2(@opentelemetry/api@1.9.1)(@types/pg@8.15.6)(expo-sqlite@55.0.15(expo@55.0.15)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(pg@8.20.0)(postgres@3.4.9) drizzle-postgis: specifier: 'catalog:' version: 1.1.1 @@ -235,7 +235,7 @@ importers: version: link:../../packages/ui drizzle-orm: specifier: 'catalog:' - version: 0.45.2(@opentelemetry/api@1.9.1)(@types/pg@8.15.6)(expo-sqlite@55.0.15(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(pg@8.20.0)(postgres@3.4.9) + version: 0.45.2(@opentelemetry/api@1.9.1)(@types/pg@8.15.6)(expo-sqlite@55.0.15(expo@55.0.15)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(pg@8.20.0)(postgres@3.4.9) isbot: specifier: ^5.1.37 version: 5.1.37 @@ -297,6 +297,9 @@ importers: apps/mobile: dependencies: + '@expo/metro-runtime': + specifier: ^55.0.9 + version: 55.0.9(@expo/dom-webview@55.0.5)(expo@55.0.15)(react-dom@19.2.5(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) '@gorhom/bottom-sheet': specifier: ^5.2.9 version: 5.2.9(@types/react@19.2.14)(react-native-gesture-handler@2.31.1(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native-reanimated@4.3.0(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) @@ -308,7 +311,7 @@ importers: version: 3.3.5 '@sentry/react-native': specifier: ~7.11.0 - version: 7.11.0(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + version: 7.11.0(expo@55.0.15)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) '@trails-cool/api': specifier: workspace:* version: link:../../packages/api @@ -325,41 +328,62 @@ importers: specifier: workspace:* version: link:../../packages/types expo: - specifier: ~55.0.14 - version: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + specifier: ~55.0.15 + version: 55.0.15(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) expo-constants: - specifier: ~55.0.13 - version: 55.0.13(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(typescript@5.9.3) + specifier: ~55.0.14 + version: 55.0.14(expo@55.0.15)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(typescript@5.9.3) expo-crypto: specifier: ~55.0.14 - version: 55.0.14(expo@55.0.14) + version: 55.0.14(expo@55.0.15) expo-dev-client: specifier: ~55.0.27 - version: 55.0.27(expo@55.0.14)(typescript@5.9.3) + version: 55.0.27(expo@55.0.15)(typescript@5.9.3) + expo-dev-menu: + specifier: ^55.0.23 + version: 55.0.23(expo@55.0.15) + expo-device: + specifier: ~55.0.15 + version: 55.0.15(expo@55.0.15) + expo-file-system: + specifier: ~55.0.16 + version: 55.0.16(expo@55.0.15)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5)) expo-linking: - specifier: ~55.0.12 - version: 55.0.12(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + specifier: ~55.0.13 + version: 55.0.13(expo@55.0.15)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + expo-localization: + specifier: ~55.0.13 + version: 55.0.13(expo@55.0.15)(react@19.2.5) expo-location: specifier: ~55.1.8 - version: 55.1.8(expo@55.0.14)(typescript@5.9.3) + version: 55.1.8(expo@55.0.15)(typescript@5.9.3) + expo-navigation-bar: + specifier: ~55.0.12 + version: 55.0.12(expo@55.0.15)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) expo-notifications: - specifier: ~55.0.18 - version: 55.0.18(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + specifier: ~55.0.19 + version: 55.0.19(expo@55.0.15)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) expo-router: specifier: ~55.0.12 - version: 55.0.12(c811543d83d1946bea5c9894f6a9bea5) + version: 55.0.12(2abaf9bed2da34a074803b38a8556f5d) expo-secure-store: specifier: ~55.0.13 - version: 55.0.13(expo@55.0.14) + version: 55.0.13(expo@55.0.15) + expo-splash-screen: + specifier: ~55.0.18 + version: 55.0.18(expo@55.0.15)(typescript@5.9.3) expo-sqlite: specifier: ~55.0.15 - version: 55.0.15(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + version: 55.0.15(expo@55.0.15)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) expo-status-bar: specifier: ~55.0.5 version: 55.0.5(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + expo-system-ui: + specifier: ^55.0.15 + version: 55.0.15(expo@55.0.15)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5)) expo-web-browser: specifier: ~55.0.14 - version: 55.0.14(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5)) + version: 55.0.14(expo@55.0.15)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5)) react: specifier: 'catalog:' version: 19.2.5 @@ -396,7 +420,7 @@ importers: version: 19.2.14 jest-expo: specifier: ^55.0.15 - version: 55.0.15(@babel/core@7.29.0)(expo@55.0.14)(jest@29.7.0(@types/node@25.5.2)(ts-node@10.9.2(@types/node@25.5.2)(typescript@5.9.3)))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + version: 55.0.15(@babel/core@7.29.0)(expo@55.0.15)(jest@29.7.0(@types/node@25.5.2)(ts-node@10.9.2(@types/node@25.5.2)(typescript@5.9.3)))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) react-test-renderer: specifier: ^19.2.5 version: 19.2.5(react@19.2.5) @@ -462,7 +486,7 @@ importers: version: 6.0.2 drizzle-orm: specifier: 'catalog:' - version: 0.45.2(@opentelemetry/api@1.9.1)(@types/pg@8.15.6)(expo-sqlite@55.0.15(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(pg@8.20.0)(postgres@3.4.9) + version: 0.45.2(@opentelemetry/api@1.9.1)(@types/pg@8.15.6)(expo-sqlite@55.0.15(expo@55.0.15)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(pg@8.20.0)(postgres@3.4.9) isbot: specifier: ^5.1.37 version: 5.1.37 @@ -544,7 +568,7 @@ importers: dependencies: drizzle-orm: specifier: 'catalog:' - version: 0.45.2(@opentelemetry/api@1.9.1)(@types/pg@8.15.6)(expo-sqlite@55.0.15(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(pg@8.20.0)(postgres@3.4.9) + version: 0.45.2(@opentelemetry/api@1.9.1)(@types/pg@8.15.6)(expo-sqlite@55.0.15(expo@55.0.15)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(pg@8.20.0)(postgres@3.4.9) postgres: specifier: 'catalog:' version: 3.4.9 @@ -1711,8 +1735,8 @@ packages: '@expo-google-fonts/material-symbols@0.4.30': resolution: {integrity: sha512-ZCfA0jcVG/dHJGbweOmIRz6vQ53fR8reuvGSd+GcWzOwMm2Y4tkMIAXhrekltiG8sx4KM9bm4LE18RN8wTxmHg==} - '@expo/cli@55.0.23': - resolution: {integrity: sha512-OTGFvb70OGOTa3KZm8f23cPw4X16qavPBNotsumWwdUvLPfKHEQIvbCNWCMs1eAVW/Act/8psnO7cscXnf6Iug==} + '@expo/cli@55.0.24': + resolution: {integrity: sha512-Z6Xh0WNTg1LvoZQ77zO3snF2cFiv1xf0VguDlwTL1Ql87oMOp30f7mjl9jeaSHqoWkgiAbmxgCKKIGjVX/keiA==} hasBin: true peerDependencies: expo: '*' @@ -1736,6 +1760,9 @@ packages: '@expo/config@55.0.14': resolution: {integrity: sha512-CCIe6Suuy0DjC58PI6jBpK8Y3pW0BimXGP8tZrVKPqS5ECqVTei0Xp78nbC/fbO+79r6ak5Su6Os71U459j4dw==} + '@expo/config@55.0.15': + resolution: {integrity: sha512-lHc0ELIQ8126jYOMZpLv3WIuvordW98jFg5aT/J1/12n2ycuXu01XLZkJsdw0avO34cusUYb1It+MvY8JiMduA==} + '@expo/devcert@1.2.1': resolution: {integrity: sha512-qC4eaxmKMTmJC2ahwyui6ud8f3W60Ss7pMkpBq40Hu3zyiAaugPXnZ24145U7K36qO9UHdZUVxsCvIpz2RYYCA==} @@ -1771,8 +1798,8 @@ packages: '@expo/json-file@10.0.13': resolution: {integrity: sha512-pX/XjQn7tgNw6zuuV2ikmegmwe/S7uiwhrs2wXrANMkq7ozrA+JcZwgW9Q/8WZgciBzfAhNp5hnackHcrmapQA==} - '@expo/local-build-cache-provider@55.0.10': - resolution: {integrity: sha512-T7ekqxsjY6EL65Sldbo+RVehPQBC59R4J57OdgxHfQTpqe8DspfsmL2CEmJO0SaxItp/Kts9ga7R5ujUWE5EQw==} + '@expo/local-build-cache-provider@55.0.11': + resolution: {integrity: sha512-rJ4RTCrkeKaXaido/bVyhl90ZRtVTOEbj59F1PWVjIEIVgjdlfc1J3VD9v7hEsbf/+8Tbr/PgvWhT6Visi5sLQ==} '@expo/log-box@55.0.10': resolution: {integrity: sha512-7jdikExgIrCIF5e3P1qMwcUZ2tcxrNdVqE9Y8kNMUHqZ+ipMlin+SiZwJKHM1+am4CYGjhdyrzbnIpvEcLDYcg==} @@ -1782,8 +1809,8 @@ packages: react: '*' react-native: '*' - '@expo/metro-config@55.0.15': - resolution: {integrity: sha512-MO0skYiGFOtmN4p+cds+tqWsuhGtApUpdBLVXdAw1U3cPW5qQ1IbHqgN+muEvSG+3gtC9CcoEEcSDd1mRCpXNQ==} + '@expo/metro-config@55.0.16': + resolution: {integrity: sha512-JaWDw0dmYZ5pOqA+3/Efvl8JzCVgWQVPogHFjTRC5azUgAsFV+T7moOaZTSgg4d+5TjFZjZbMZg4SUomE7LiGg==} peerDependencies: expo: '*' peerDependenciesMeta: @@ -1814,8 +1841,8 @@ packages: '@expo/plist@0.5.2': resolution: {integrity: sha512-o4xdVdBpe4aTl3sPMZ2u3fJH4iG1I768EIRk1xRZP+GaFI93MaR3JvoFibYqxeTmLQ1p1kNEVqylfUjezxx45g==} - '@expo/prebuild-config@55.0.14': - resolution: {integrity: sha512-88Ou8HF8sWcXD9wduQZ2XBwNMzD8t2x3FtlM0F++rhl9a+aNk2SAj8yhwuGsoEJpbxWG7qq35Yof1r7uU4Z16w==} + '@expo/prebuild-config@55.0.15': + resolution: {integrity: sha512-UcCzVhVBE42UbY5U3t/q1Rk2fSFW/B50LJpB6oFpXhImJfvLKu7ayOFU9XcHd38K89i4GqSia/xXuxQvu4RUBg==} peerDependencies: expo: '*' @@ -4717,15 +4744,15 @@ packages: peerDependencies: expo: '*' - expo-asset@55.0.14: - resolution: {integrity: sha512-8jeWHW39/UOQytGoXXFIrpE+DhK72RhMu09iuTxYuGluqGzGgs+DgcaP9jTvCPwkAXxSfWZdsTttuKXE5nDUCQ==} + expo-asset@55.0.15: + resolution: {integrity: sha512-d3FIpHJ6ZngYXxRItYWBGT5H8Wkk7/l4fMe8Mmd2xDyKrO0/CM7c8r/J5M71D+BJr5P3My8wertGYZXHSiZYxQ==} peerDependencies: expo: '*' react: '*' react-native: '*' - expo-constants@55.0.13: - resolution: {integrity: sha512-imSsHm94KWsJbBLvjsUNgubcPQ3H6dXaAm0IZj2Y6+XEdJmjWo2JreriYmeSu/azmpiYUd3Y7K+/Hq9WXQ2Elg==} + expo-constants@55.0.14: + resolution: {integrity: sha512-l23QVQCYBPKT5zbxxZdJeuhiunadvWdjcQ9+GC8h+02jCoLmWRk20064nCINnQTP3Hf+uLPteUiwYrJd0e446w==} peerDependencies: expo: '*' react-native: '*' @@ -4755,6 +4782,11 @@ packages: peerDependencies: expo: '*' + expo-device@55.0.15: + resolution: {integrity: sha512-vXy4U/IeYI+zHGG45Ap6J7EuyQmkstyo8I+/5YGr5q2zmqLBo6SWE62wii8i9hLHheHn6AtF9UPrSWAREJrE8A==} + peerDependencies: + expo: '*' + expo-file-system@55.0.16: resolution: {integrity: sha512-EetQ/zVFK07Vmz4Yke0fvoES4xVwScTdd0PMoLekuMX7puE4op75pNnEdh1M0AeWzkqLrBoZIaU2ynSrKN5VZg==} peerDependencies: @@ -4795,12 +4827,18 @@ packages: expo: '*' react: '*' - expo-linking@55.0.12: - resolution: {integrity: sha512-JiaIlFHC4iQ57NmsXYdn0HW0iAIEbKZXfGmpnFcY/bztl8I8RjnCV8zYbDMMO1x87mEYy7PmvEv2mmaX8WrQTw==} + expo-linking@55.0.13: + resolution: {integrity: sha512-xbOqNWQCC5RGtXSW83ZCKOjRivyxO2zBouRYy/hgbsyrHUJhztMAjlq8RKYDUL8D6QVsH9Q81SNoq4Zhcn+4HQ==} peerDependencies: react: '*' react-native: '*' + expo-localization@55.0.13: + resolution: {integrity: sha512-fXiEUUihIrXmAEzoneaTOFcQ7TKmr25RR/ymrB/MvYTVnmevFA1zY2KI0VSiXY+NKKjZ8mG65YSn1wh4gEYKxA==} + peerDependencies: + expo: '*' + react: '*' + expo-location@55.1.8: resolution: {integrity: sha512-mEExFf84nmWLwi14GFfUsFLrCm10gbcqFn9EPXpuruQ28YMtJWgCD+jJtESYPQkYF44N21fVok3T28fLuCqydA==} peerDependencies: @@ -4825,8 +4863,15 @@ packages: react-native-worklets: optional: true - expo-notifications@55.0.18: - resolution: {integrity: sha512-NxA9zdADnsQ5g66cznpu3m+bFMyoi7XKN+GkKZCRQ0RJAi4NXwB+1mljzdCAt5TGlcnAwwVBw+3zC1B9qORfcQ==} + expo-navigation-bar@55.0.12: + resolution: {integrity: sha512-G7olnyAqGd7I3hLFAgP4WdcZFMD9pV6UY79P7EHyRdMuRZrYJfDdwcelyYB2+tekOdQEktZ3WlLVK+uS7f7TYw==} + peerDependencies: + expo: '*' + react: '*' + react-native: '*' + + expo-notifications@55.0.19: + resolution: {integrity: sha512-t1DPN9xwSh5kN5T8k0lER/NbcuhMIxj/ukfDWzFOJb2WdfB+VBWaiBUj4K26agsX7tQFMz2wsCXpkYXLdfzSdw==} peerDependencies: expo: '*' react: '*' @@ -4876,6 +4921,11 @@ packages: resolution: {integrity: sha512-Cc1btFyPsD9P4DT2xd1pG/uR96TLVMx0W+dPm9Gjk1uDV9xuzvMcUsY7nf9bt4U5pGyWWkCXmPJcKwWfdl51Pw==} engines: {node: '>=20.16.0'} + expo-splash-screen@55.0.18: + resolution: {integrity: sha512-5+sA2L2e0v7GVWl2+j24lSNnC39HtycCCtJXHiC2N+voWLtZp0qMLAKZY/1vhkzjYzDzfkUcZiRzkdhwT9x+2Q==} + peerDependencies: + expo: '*' + expo-sqlite@55.0.15: resolution: {integrity: sha512-vxE5fs6l953QSIyievQ8TuSstj62eC7zUREjNzbUOwRWaHGGnhnlPJM1HLoTIv+oIt3+b1m7k2fmcDGkpK5t3w==} peerDependencies: @@ -4897,6 +4947,16 @@ packages: react: '*' react-native: '*' + expo-system-ui@55.0.15: + resolution: {integrity: sha512-hnpYpXgm1sXDb46yb7RB+Iq9z44wtDuFOYC8m2pfBNj3Dnv5xnh3CL2N4CpAbLZPwMSBrNk9Opkb9VFwn1FM6A==} + peerDependencies: + expo: '*' + react-native: '*' + react-native-web: '*' + peerDependenciesMeta: + react-native-web: + optional: true + expo-updates-interface@55.1.5: resolution: {integrity: sha512-YOk9vhplWi0djoeqxMlEQgcDFeOGhnj4dWU0v1QvF5RqpqwLGdx780E0k3zL85xw6LXljVN78d6g8z51qIZu5g==} peerDependencies: @@ -4908,8 +4968,8 @@ packages: expo: '*' react-native: '*' - expo@55.0.14: - resolution: {integrity: sha512-MqFdpyE3z5MZqb6Q9v6RqXzbRDbd0RMlGdVLSA/ObX6vgHhzCDIjeb+Uwao9P7R0uebsC4b126jBWxuhMmJHZQ==} + expo@55.0.15: + resolution: {integrity: sha512-sHIvqG477UU1jZHhaexXbUgsU7y+xnYZqDW1HrUkEBYiuEb5lobvWLmwea76EBVkityQx46UDtepFtarpUJQqQ==} hasBin: true peerDependencies: '@expo/dom-webview': '*' @@ -6655,6 +6715,9 @@ packages: engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true + rtl-detect@1.1.2: + resolution: {integrity: sha512-PGMBq03+TTG/p/cRB7HCLKJ1MgDIi07+QU1faSjiYRfmY5UsAttV9Hs08jDAHVwcOwmVLcSJkpwyfXszVjWfIQ==} + safe-buffer@5.1.2: resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} @@ -7103,6 +7166,10 @@ packages: engines: {node: '>=14.17'} hasBin: true + ua-parser-js@0.7.41: + resolution: {integrity: sha512-O3oYyCMPYgNNHuO7Jjk3uacJWZF8loBgwrfd/5LE/HyZ3lUIOdniQ7DNXJcIgZbwioZxk0fLfI4EVnetdiX5jg==} + hasBin: true + uhyphen@0.2.0: resolution: {integrity: sha512-qz3o9CHXmJJPGBdqzab7qAYuW8kQGKNEuoHFYrBwV6hWIMcpAmxDLXojcHfFr9US1Pe6zUswEIJIbLI610fuqA==} @@ -8554,24 +8621,24 @@ snapshots: '@expo-google-fonts/material-symbols@0.4.30': {} - '@expo/cli@55.0.23(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-constants@55.0.13)(expo-font@55.0.6)(expo-router@55.0.12)(expo@55.0.14)(react-dom@19.2.5(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3)': + '@expo/cli@55.0.24(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-constants@55.0.14)(expo-font@55.0.6)(expo-router@55.0.12)(expo@55.0.15)(react-dom@19.2.5(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3)': dependencies: '@expo/code-signing-certificates': 0.0.6 - '@expo/config': 55.0.14(typescript@5.9.3) + '@expo/config': 55.0.15(typescript@5.9.3) '@expo/config-plugins': 55.0.8 '@expo/devcert': 1.2.1 '@expo/env': 2.1.1 '@expo/image-utils': 0.8.13(typescript@5.9.3) '@expo/json-file': 10.0.13 - '@expo/log-box': 55.0.10(@expo/dom-webview@55.0.5)(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + '@expo/log-box': 55.0.10(@expo/dom-webview@55.0.5)(expo@55.0.15)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) '@expo/metro': 55.0.0 - '@expo/metro-config': 55.0.15(expo@55.0.14)(typescript@5.9.3) + '@expo/metro-config': 55.0.16(expo@55.0.15)(typescript@5.9.3) '@expo/osascript': 2.4.2 '@expo/package-manager': 1.10.4 '@expo/plist': 0.5.2 - '@expo/prebuild-config': 55.0.14(expo@55.0.14)(typescript@5.9.3) + '@expo/prebuild-config': 55.0.15(expo@55.0.15)(typescript@5.9.3) '@expo/require-utils': 55.0.4(typescript@5.9.3) - '@expo/router-server': 55.0.14(@expo/metro-runtime@55.0.9)(expo-constants@55.0.13)(expo-font@55.0.6)(expo-router@55.0.12)(expo-server@55.0.7)(expo@55.0.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@expo/router-server': 55.0.14(@expo/metro-runtime@55.0.9)(expo-constants@55.0.14)(expo-font@55.0.6)(expo-router@55.0.12)(expo-server@55.0.7)(expo@55.0.15)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@expo/schema-utils': 55.0.3 '@expo/spawn-async': 1.7.2 '@expo/ws-tunnel': 1.0.6 @@ -8588,7 +8655,7 @@ snapshots: connect: 3.7.0 debug: 4.4.3 dnssd-advertise: 1.1.4 - expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + expo: 55.0.15(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) expo-server: 55.0.7 fetch-nodeshim: 0.4.10 getenv: 2.0.0 @@ -8615,7 +8682,7 @@ snapshots: ws: 8.20.0 zod: 3.25.76 optionalDependencies: - expo-router: 55.0.12(c811543d83d1946bea5c9894f6a9bea5) + expo-router: 55.0.12(2abaf9bed2da34a074803b38a8556f5d) react-native: 0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5) transitivePeerDependencies: - '@expo/dom-webview' @@ -8670,6 +8737,22 @@ snapshots: - supports-color - typescript + '@expo/config@55.0.15(typescript@5.9.3)': + dependencies: + '@expo/config-plugins': 55.0.8 + '@expo/config-types': 55.0.5 + '@expo/json-file': 10.0.13 + '@expo/require-utils': 55.0.4(typescript@5.9.3) + deepmerge: 4.3.1 + getenv: 2.0.0 + glob: 13.0.6 + resolve-workspace-root: 2.0.1 + semver: 7.7.4 + slugify: 1.6.9 + transitivePeerDependencies: + - supports-color + - typescript + '@expo/devcert@1.2.1': dependencies: '@expo/sudo-prompt': 9.3.2 @@ -8684,9 +8767,9 @@ snapshots: react: 19.2.5 react-native: 0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5) - '@expo/dom-webview@55.0.5(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)': + '@expo/dom-webview@55.0.5(expo@55.0.15)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)': dependencies: - expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + expo: 55.0.15(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) react: 19.2.5 react-native: 0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5) @@ -8732,29 +8815,29 @@ snapshots: '@babel/code-frame': 7.29.0 json5: 2.2.3 - '@expo/local-build-cache-provider@55.0.10(typescript@5.9.3)': + '@expo/local-build-cache-provider@55.0.11(typescript@5.9.3)': dependencies: - '@expo/config': 55.0.14(typescript@5.9.3) + '@expo/config': 55.0.15(typescript@5.9.3) chalk: 4.1.2 transitivePeerDependencies: - supports-color - typescript - '@expo/log-box@55.0.10(@expo/dom-webview@55.0.5)(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)': + '@expo/log-box@55.0.10(@expo/dom-webview@55.0.5)(expo@55.0.15)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)': dependencies: - '@expo/dom-webview': 55.0.5(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + '@expo/dom-webview': 55.0.5(expo@55.0.15)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) anser: 1.4.10 - expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + expo: 55.0.15(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) react: 19.2.5 react-native: 0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5) stacktrace-parser: 0.1.11 - '@expo/metro-config@55.0.15(expo@55.0.14)(typescript@5.9.3)': + '@expo/metro-config@55.0.16(expo@55.0.15)(typescript@5.9.3)': dependencies: '@babel/code-frame': 7.29.0 '@babel/core': 7.29.0 '@babel/generator': 7.29.1 - '@expo/config': 55.0.14(typescript@5.9.3) + '@expo/config': 55.0.15(typescript@5.9.3) '@expo/env': 2.1.1 '@expo/json-file': 10.0.13 '@expo/metro': 55.0.0 @@ -8771,18 +8854,18 @@ snapshots: postcss: 8.4.49 resolve-from: 5.0.0 optionalDependencies: - expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + expo: 55.0.15(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) transitivePeerDependencies: - bufferutil - supports-color - typescript - utf-8-validate - '@expo/metro-runtime@55.0.9(@expo/dom-webview@55.0.5)(expo@55.0.14)(react-dom@19.2.5(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)': + '@expo/metro-runtime@55.0.9(@expo/dom-webview@55.0.5)(expo@55.0.15)(react-dom@19.2.5(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)': dependencies: - '@expo/log-box': 55.0.10(@expo/dom-webview@55.0.5)(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + '@expo/log-box': 55.0.10(@expo/dom-webview@55.0.5)(expo@55.0.15)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) anser: 1.4.10 - expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + expo: 55.0.15(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) pretty-format: 29.7.0 react: 19.2.5 react-native: 0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5) @@ -8833,16 +8916,16 @@ snapshots: base64-js: 1.5.1 xmlbuilder: 15.1.1 - '@expo/prebuild-config@55.0.14(expo@55.0.14)(typescript@5.9.3)': + '@expo/prebuild-config@55.0.15(expo@55.0.15)(typescript@5.9.3)': dependencies: - '@expo/config': 55.0.14(typescript@5.9.3) + '@expo/config': 55.0.15(typescript@5.9.3) '@expo/config-plugins': 55.0.8 '@expo/config-types': 55.0.5 '@expo/image-utils': 0.8.13(typescript@5.9.3) '@expo/json-file': 10.0.13 '@react-native/normalize-colors': 0.83.4 debug: 4.4.3 - expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + expo: 55.0.15(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) resolve-from: 5.0.0 semver: 7.7.4 xml2js: 0.6.0 @@ -8860,17 +8943,17 @@ snapshots: transitivePeerDependencies: - supports-color - '@expo/router-server@55.0.14(@expo/metro-runtime@55.0.9)(expo-constants@55.0.13)(expo-font@55.0.6)(expo-router@55.0.12)(expo-server@55.0.7)(expo@55.0.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': + '@expo/router-server@55.0.14(@expo/metro-runtime@55.0.9)(expo-constants@55.0.14)(expo-font@55.0.6)(expo-router@55.0.12)(expo-server@55.0.7)(expo@55.0.15)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: debug: 4.4.3 - expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) - expo-constants: 55.0.13(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(typescript@5.9.3) - expo-font: 55.0.6(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + expo: 55.0.15(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + expo-constants: 55.0.14(expo@55.0.15)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(typescript@5.9.3) + expo-font: 55.0.6(expo@55.0.15)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) expo-server: 55.0.7 react: 19.2.5 optionalDependencies: - '@expo/metro-runtime': 55.0.9(@expo/dom-webview@55.0.5)(expo@55.0.14)(react-dom@19.2.5(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) - expo-router: 55.0.12(c811543d83d1946bea5c9894f6a9bea5) + '@expo/metro-runtime': 55.0.9(@expo/dom-webview@55.0.5)(expo@55.0.15)(react-dom@19.2.5(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + expo-router: 55.0.12(2abaf9bed2da34a074803b38a8556f5d) react-dom: 19.2.5(react@19.2.5) transitivePeerDependencies: - supports-color @@ -8887,7 +8970,7 @@ snapshots: '@expo/vector-icons@15.1.1(expo-font@55.0.6)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)': dependencies: - expo-font: 55.0.6(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + expo-font: 55.0.6(expo@55.0.15)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) react: 19.2.5 react-native: 0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5) @@ -10508,7 +10591,7 @@ snapshots: '@opentelemetry/semantic-conventions': 1.40.0 '@sentry/core': 10.48.0 - '@sentry/react-native@7.11.0(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)': + '@sentry/react-native@7.11.0(expo@55.0.15)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)': dependencies: '@sentry/babel-plugin-component-annotate': 4.8.0 '@sentry/browser': 10.37.0 @@ -10519,7 +10602,7 @@ snapshots: react: 19.2.5 react-native: 0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5) optionalDependencies: - expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + expo: 55.0.15(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) transitivePeerDependencies: - encoding - supports-color @@ -11357,7 +11440,7 @@ snapshots: '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.29.0) '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.29.0) - babel-preset-expo@55.0.17(@babel/core@7.29.0)(@babel/runtime@7.29.2)(expo@55.0.14)(react-refresh@0.14.2): + babel-preset-expo@55.0.17(@babel/core@7.29.0)(@babel/runtime@7.29.2)(expo@55.0.15)(react-refresh@0.14.2): dependencies: '@babel/generator': 7.29.1 '@babel/helper-module-imports': 7.28.6 @@ -11385,7 +11468,7 @@ snapshots: resolve-from: 5.0.0 optionalDependencies: '@babel/runtime': 7.29.2 - expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + expo: 55.0.15(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) transitivePeerDependencies: - '@babel/core' - supports-color @@ -11832,11 +11915,11 @@ snapshots: esbuild: 0.25.12 tsx: 4.21.0 - drizzle-orm@0.45.2(@opentelemetry/api@1.9.1)(@types/pg@8.15.6)(expo-sqlite@55.0.15(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(pg@8.20.0)(postgres@3.4.9): + drizzle-orm@0.45.2(@opentelemetry/api@1.9.1)(@types/pg@8.15.6)(expo-sqlite@55.0.15(expo@55.0.15)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(pg@8.20.0)(postgres@3.4.9): optionalDependencies: '@opentelemetry/api': 1.9.1 '@types/pg': 8.15.6 - expo-sqlite: 55.0.15(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + expo-sqlite: 55.0.15(expo@55.0.15)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) pg: 8.20.0 postgres: 3.4.9 @@ -12111,101 +12194,106 @@ snapshots: jest-message-util: 29.7.0 jest-util: 29.7.0 - expo-application@55.0.14(expo@55.0.14): + expo-application@55.0.14(expo@55.0.15): dependencies: - expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + expo: 55.0.15(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) - expo-asset@55.0.14(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3): + expo-asset@55.0.15(expo@55.0.15)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3): dependencies: '@expo/image-utils': 0.8.13(typescript@5.9.3) - expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) - expo-constants: 55.0.13(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(typescript@5.9.3) + expo: 55.0.15(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + expo-constants: 55.0.14(expo@55.0.15)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(typescript@5.9.3) react: 19.2.5 react-native: 0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5) transitivePeerDependencies: - supports-color - typescript - expo-constants@55.0.13(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(typescript@5.9.3): + expo-constants@55.0.14(expo@55.0.15)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(typescript@5.9.3): dependencies: - '@expo/config': 55.0.14(typescript@5.9.3) + '@expo/config': 55.0.15(typescript@5.9.3) '@expo/env': 2.1.1 - expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + expo: 55.0.15(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) react-native: 0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5) transitivePeerDependencies: - supports-color - typescript - expo-crypto@55.0.14(expo@55.0.14): + expo-crypto@55.0.14(expo@55.0.15): dependencies: - expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + expo: 55.0.15(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) - expo-dev-client@55.0.27(expo@55.0.14)(typescript@5.9.3): + expo-dev-client@55.0.27(expo@55.0.15)(typescript@5.9.3): dependencies: - expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) - expo-dev-launcher: 55.0.28(expo@55.0.14)(typescript@5.9.3) - expo-dev-menu: 55.0.23(expo@55.0.14) - expo-dev-menu-interface: 55.0.2(expo@55.0.14) - expo-manifests: 55.0.15(expo@55.0.14)(typescript@5.9.3) - expo-updates-interface: 55.1.5(expo@55.0.14) + expo: 55.0.15(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + expo-dev-launcher: 55.0.28(expo@55.0.15)(typescript@5.9.3) + expo-dev-menu: 55.0.23(expo@55.0.15) + expo-dev-menu-interface: 55.0.2(expo@55.0.15) + expo-manifests: 55.0.15(expo@55.0.15)(typescript@5.9.3) + expo-updates-interface: 55.1.5(expo@55.0.15) transitivePeerDependencies: - supports-color - typescript - expo-dev-launcher@55.0.28(expo@55.0.14)(typescript@5.9.3): + expo-dev-launcher@55.0.28(expo@55.0.15)(typescript@5.9.3): dependencies: '@expo/schema-utils': 55.0.3 - expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) - expo-dev-menu: 55.0.23(expo@55.0.14) - expo-manifests: 55.0.15(expo@55.0.14)(typescript@5.9.3) + expo: 55.0.15(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + expo-dev-menu: 55.0.23(expo@55.0.15) + expo-manifests: 55.0.15(expo@55.0.15)(typescript@5.9.3) transitivePeerDependencies: - supports-color - typescript - expo-dev-menu-interface@55.0.2(expo@55.0.14): + expo-dev-menu-interface@55.0.2(expo@55.0.15): dependencies: - expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + expo: 55.0.15(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) - expo-dev-menu@55.0.23(expo@55.0.14): + expo-dev-menu@55.0.23(expo@55.0.15): dependencies: - expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) - expo-dev-menu-interface: 55.0.2(expo@55.0.14) + expo: 55.0.15(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + expo-dev-menu-interface: 55.0.2(expo@55.0.15) - expo-file-system@55.0.16(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5)): + expo-device@55.0.15(expo@55.0.15): dependencies: - expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + expo: 55.0.15(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + ua-parser-js: 0.7.41 + + expo-file-system@55.0.16(expo@55.0.15)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5)): + dependencies: + expo: 55.0.15(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) react-native: 0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5) - expo-font@55.0.6(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5): + expo-font@55.0.6(expo@55.0.15)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5): dependencies: - expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + expo: 55.0.15(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) fontfaceobserver: 2.3.0 react: 19.2.5 react-native: 0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5) - expo-glass-effect@55.0.10(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5): + expo-glass-effect@55.0.10(expo@55.0.15)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5): dependencies: - expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + expo: 55.0.15(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) react: 19.2.5 react-native: 0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5) - expo-image@55.0.8(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5): + expo-image@55.0.8(expo@55.0.15)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5): dependencies: - expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + expo: 55.0.15(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) react: 19.2.5 react-native: 0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5) sf-symbols-typescript: 2.2.0 expo-json-utils@55.0.2: {} - expo-keep-awake@55.0.6(expo@55.0.14)(react@19.2.5): + expo-keep-awake@55.0.6(expo@55.0.15)(react@19.2.5): dependencies: - expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + expo: 55.0.15(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) react: 19.2.5 - expo-linking@55.0.12(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3): + expo-linking@55.0.13(expo@55.0.15)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3): dependencies: - expo-constants: 55.0.13(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(typescript@5.9.3) + expo-constants: 55.0.14(expo@55.0.15)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(typescript@5.9.3) invariant: 2.2.4 react: 19.2.5 react-native: 0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5) @@ -12214,18 +12302,24 @@ snapshots: - supports-color - typescript - expo-location@55.1.8(expo@55.0.14)(typescript@5.9.3): + expo-localization@55.0.13(expo@55.0.15)(react@19.2.5): + dependencies: + expo: 55.0.15(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + react: 19.2.5 + rtl-detect: 1.1.2 + + expo-location@55.1.8(expo@55.0.15)(typescript@5.9.3): dependencies: '@expo/image-utils': 0.8.13(typescript@5.9.3) - expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + expo: 55.0.15(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) transitivePeerDependencies: - supports-color - typescript - expo-manifests@55.0.15(expo@55.0.14)(typescript@5.9.3): + expo-manifests@55.0.15(expo@55.0.15)(typescript@5.9.3): dependencies: '@expo/config': 55.0.14(typescript@5.9.3) - expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + expo: 55.0.15(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) expo-json-utils: 55.0.2 transitivePeerDependencies: - supports-color @@ -12249,24 +12343,34 @@ snapshots: optionalDependencies: react-native-worklets: 0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) - expo-notifications@55.0.18(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3): + expo-navigation-bar@55.0.12(expo@55.0.15)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5): + dependencies: + debug: 4.4.3 + expo: 55.0.15(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + react: 19.2.5 + react-native: 0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5) + react-native-is-edge-to-edge: 1.3.1(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + transitivePeerDependencies: + - supports-color + + expo-notifications@55.0.19(expo@55.0.15)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3): dependencies: '@expo/image-utils': 0.8.13(typescript@5.9.3) abort-controller: 3.0.0 badgin: 1.2.3 - expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) - expo-application: 55.0.14(expo@55.0.14) - expo-constants: 55.0.13(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(typescript@5.9.3) + expo: 55.0.15(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + expo-application: 55.0.14(expo@55.0.15) + expo-constants: 55.0.14(expo@55.0.15)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(typescript@5.9.3) react: 19.2.5 react-native: 0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5) transitivePeerDependencies: - supports-color - typescript - expo-router@55.0.12(c811543d83d1946bea5c9894f6a9bea5): + expo-router@55.0.12(2abaf9bed2da34a074803b38a8556f5d): dependencies: - '@expo/log-box': 55.0.10(@expo/dom-webview@55.0.5)(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) - '@expo/metro-runtime': 55.0.9(@expo/dom-webview@55.0.5)(expo@55.0.14)(react-dom@19.2.5(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + '@expo/log-box': 55.0.10(@expo/dom-webview@55.0.5)(expo@55.0.15)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + '@expo/metro-runtime': 55.0.9(@expo/dom-webview@55.0.5)(expo@55.0.15)(react-dom@19.2.5(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) '@expo/schema-utils': 55.0.3 '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.5) '@radix-ui/react-tabs': 1.1.13(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) @@ -12276,13 +12380,13 @@ snapshots: client-only: 0.0.1 debug: 4.4.3 escape-string-regexp: 4.0.0 - expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) - expo-constants: 55.0.13(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(typescript@5.9.3) - expo-glass-effect: 55.0.10(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) - expo-image: 55.0.8(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) - expo-linking: 55.0.12(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + expo: 55.0.15(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + expo-constants: 55.0.14(expo@55.0.15)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(typescript@5.9.3) + expo-glass-effect: 55.0.10(expo@55.0.15)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + expo-image: 55.0.8(expo@55.0.15)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + expo-linking: 55.0.13(expo@55.0.15)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) expo-server: 55.0.7 - expo-symbols: 55.0.7(expo-font@55.0.6)(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + expo-symbols: 55.0.7(expo-font@55.0.6)(expo@55.0.15)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) fast-deep-equal: 3.1.3 invariant: 2.2.4 nanoid: 3.3.11 @@ -12311,16 +12415,24 @@ snapshots: - expo-font - supports-color - expo-secure-store@55.0.13(expo@55.0.14): + expo-secure-store@55.0.13(expo@55.0.15): dependencies: - expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + expo: 55.0.15(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) expo-server@55.0.7: {} - expo-sqlite@55.0.15(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5): + expo-splash-screen@55.0.18(expo@55.0.15)(typescript@5.9.3): + dependencies: + '@expo/prebuild-config': 55.0.15(expo@55.0.15)(typescript@5.9.3) + expo: 55.0.15(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + transitivePeerDependencies: + - supports-color + - typescript + + expo-sqlite@55.0.15(expo@55.0.15)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5): dependencies: await-lock: 2.2.2 - expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + expo: 55.0.15(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) react: 19.2.5 react-native: 0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5) @@ -12330,44 +12442,53 @@ snapshots: react-native: 0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5) react-native-is-edge-to-edge: 1.3.1(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) - expo-symbols@55.0.7(expo-font@55.0.6)(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5): + expo-symbols@55.0.7(expo-font@55.0.6)(expo@55.0.15)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5): dependencies: '@expo-google-fonts/material-symbols': 0.4.30 - expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) - expo-font: 55.0.6(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + expo: 55.0.15(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + expo-font: 55.0.6(expo@55.0.15)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) react: 19.2.5 react-native: 0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5) sf-symbols-typescript: 2.2.0 - expo-updates-interface@55.1.5(expo@55.0.14): + expo-system-ui@55.0.15(expo@55.0.15)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5)): dependencies: - expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + '@react-native/normalize-colors': 0.83.4 + debug: 4.4.3 + expo: 55.0.15(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + react-native: 0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5) + transitivePeerDependencies: + - supports-color - expo-web-browser@55.0.14(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5)): + expo-updates-interface@55.1.5(expo@55.0.15): dependencies: - expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + expo: 55.0.15(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + + expo-web-browser@55.0.14(expo@55.0.15)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5)): + dependencies: + expo: 55.0.15(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) react-native: 0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5) - expo@55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3): + expo@55.0.15(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3): dependencies: '@babel/runtime': 7.29.2 - '@expo/cli': 55.0.23(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-constants@55.0.13)(expo-font@55.0.6)(expo-router@55.0.12)(expo@55.0.14)(react-dom@19.2.5(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) - '@expo/config': 55.0.14(typescript@5.9.3) + '@expo/cli': 55.0.24(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-constants@55.0.14)(expo-font@55.0.6)(expo-router@55.0.12)(expo@55.0.15)(react-dom@19.2.5(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + '@expo/config': 55.0.15(typescript@5.9.3) '@expo/config-plugins': 55.0.8 '@expo/devtools': 55.0.2(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) '@expo/fingerprint': 0.16.6 - '@expo/local-build-cache-provider': 55.0.10(typescript@5.9.3) - '@expo/log-box': 55.0.10(@expo/dom-webview@55.0.5)(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + '@expo/local-build-cache-provider': 55.0.11(typescript@5.9.3) + '@expo/log-box': 55.0.10(@expo/dom-webview@55.0.5)(expo@55.0.15)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) '@expo/metro': 55.0.0 - '@expo/metro-config': 55.0.15(expo@55.0.14)(typescript@5.9.3) + '@expo/metro-config': 55.0.16(expo@55.0.15)(typescript@5.9.3) '@expo/vector-icons': 15.1.1(expo-font@55.0.6)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) '@ungap/structured-clone': 1.3.0 - babel-preset-expo: 55.0.17(@babel/core@7.29.0)(@babel/runtime@7.29.2)(expo@55.0.14)(react-refresh@0.14.2) - expo-asset: 55.0.14(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) - expo-constants: 55.0.13(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(typescript@5.9.3) - expo-file-system: 55.0.16(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5)) - expo-font: 55.0.6(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) - expo-keep-awake: 55.0.6(expo@55.0.14)(react@19.2.5) + babel-preset-expo: 55.0.17(@babel/core@7.29.0)(@babel/runtime@7.29.2)(expo@55.0.15)(react-refresh@0.14.2) + expo-asset: 55.0.15(expo@55.0.15)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + expo-constants: 55.0.14(expo@55.0.15)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(typescript@5.9.3) + expo-file-system: 55.0.16(expo@55.0.15)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5)) + expo-font: 55.0.6(expo@55.0.15)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + expo-keep-awake: 55.0.6(expo@55.0.15)(react@19.2.5) expo-modules-autolinking: 55.0.17(typescript@5.9.3) expo-modules-core: 55.0.22(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) pretty-format: 29.7.0 @@ -12376,8 +12497,8 @@ snapshots: react-refresh: 0.14.2 whatwg-url-minimum: 0.1.1 optionalDependencies: - '@expo/dom-webview': 55.0.5(expo@55.0.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) - '@expo/metro-runtime': 55.0.9(@expo/dom-webview@55.0.5)(expo@55.0.14)(react-dom@19.2.5(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + '@expo/dom-webview': 55.0.5(expo@55.0.15)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + '@expo/metro-runtime': 55.0.9(@expo/dom-webview@55.0.5)(expo@55.0.15)(react-dom@19.2.5(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) transitivePeerDependencies: - '@babel/core' - bufferutil @@ -12974,14 +13095,14 @@ snapshots: jest-mock: 29.7.0 jest-util: 29.7.0 - jest-expo@55.0.15(@babel/core@7.29.0)(expo@55.0.14)(jest@29.7.0(@types/node@25.5.2)(ts-node@10.9.2(@types/node@25.5.2)(typescript@5.9.3)))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3): + jest-expo@55.0.15(@babel/core@7.29.0)(expo@55.0.15)(jest@29.7.0(@types/node@25.5.2)(ts-node@10.9.2(@types/node@25.5.2)(typescript@5.9.3)))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3): dependencies: '@expo/config': 55.0.14(typescript@5.9.3) '@expo/json-file': 10.0.13 '@jest/create-cache-key-function': 29.7.0 '@jest/globals': 29.7.0 babel-jest: 29.7.0(@babel/core@7.29.0) - expo: 55.0.14(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + expo: 55.0.15(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) jest-environment-jsdom: 29.7.0 jest-snapshot: 29.7.0 jest-watch-select-projects: 2.0.0 @@ -14625,6 +14746,8 @@ snapshots: '@rollup/rollup-win32-x64-msvc': 4.60.0 fsevents: 2.3.3 + rtl-detect@1.1.2: {} + safe-buffer@5.1.2: {} safe-buffer@5.2.1: {} @@ -15045,6 +15168,8 @@ snapshots: typescript@5.9.3: {} + ua-parser-js@0.7.41: {} + uhyphen@0.2.0: {} undici-types@6.21.0: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 68fbbc1..8f925c9 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -22,3 +22,5 @@ catalog: "@sentry/react": ^10.48.0 postgres: ^3.4.9 "@types/node": ^22.0.0 + +nodeLinker: hoisted From 6c55de9d6519cc5216d9f628c81baea6fb31b665 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Wed, 15 Apr 2026 01:22:50 +0200 Subject: [PATCH 012/494] Fix Android emulator dev server: use 10.0.2.2 instead of localhost MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Android emulator has its own network stack — localhost refers to the emulator, not the host. Use 10.0.2.2 (host loopback alias) on Android. Co-Authored-By: Claude Opus 4.6 (1M context) --- apps/mobile/app/login.tsx | 6 ++++-- apps/mobile/lib/server-config.ts | 4 +++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/apps/mobile/app/login.tsx b/apps/mobile/app/login.tsx index 0c1df4c..947a171 100644 --- a/apps/mobile/app/login.tsx +++ b/apps/mobile/app/login.tsx @@ -1,5 +1,5 @@ import { useState } from "react"; -import { View, Text, TextInput, TouchableOpacity, StyleSheet, ActivityIndicator } from "react-native"; +import { View, Text, TextInput, TouchableOpacity, StyleSheet, ActivityIndicator, Platform } from "react-native"; import { router } from "expo-router"; import { setServerUrl, @@ -9,9 +9,11 @@ import { } from "../lib/server-config"; import { login } from "../lib/auth"; +const DEV_HOST = Platform.OS === "android" ? "10.0.2.2" : "localhost"; + export default function LoginScreen() { const [serverUrl, setServerUrlState] = useState( - __DEV__ ? "http://localhost:3000" : "https://trails.cool", + __DEV__ ? `http://${DEV_HOST}:3000` : "https://trails.cool", ); const [showCustomServer, setShowCustomServer] = useState(false); const [loading, setLoading] = useState(false); diff --git a/apps/mobile/lib/server-config.ts b/apps/mobile/lib/server-config.ts index a25c3d0..e7dc78b 100644 --- a/apps/mobile/lib/server-config.ts +++ b/apps/mobile/lib/server-config.ts @@ -1,8 +1,10 @@ +import { Platform } from "react-native"; import * as SecureStore from "expo-secure-store"; import { API_VERSION } from "@trails-cool/api"; const STORE_KEY_SERVER_URL = "server_url"; -const DEFAULT_SERVER_URL = __DEV__ ? "http://localhost:3000" : "https://trails.cool"; +const DEV_HOST = Platform.OS === "android" ? "10.0.2.2" : "localhost"; +const DEFAULT_SERVER_URL = __DEV__ ? `http://${DEV_HOST}:3000` : "https://trails.cool"; export interface DiscoveryResponse { apiVersion: string; From 310f20e0a3f2182339e9394355343fa6d43ffbb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Wed, 15 Apr 2026 01:31:45 +0200 Subject: [PATCH 013/494] Allow cleartext HTTP on Android for dev server Android 9+ blocks cleartext HTTP by default. Enable usesCleartextTraffic so the emulator can reach the Journal dev server at http://10.0.2.2:3000. Co-Authored-By: Claude Opus 4.6 (1M context) --- apps/journal/vite.config.ts | 1 + package.json | 10 +- pnpm-lock.yaml | 1811 +++++++++++++++++++---------------- pnpm-workspace.yaml | 1 - 4 files changed, 979 insertions(+), 844 deletions(-) diff --git a/apps/journal/vite.config.ts b/apps/journal/vite.config.ts index 77ce3ab..711c6df 100644 --- a/apps/journal/vite.config.ts +++ b/apps/journal/vite.config.ts @@ -28,5 +28,6 @@ export default defineConfig({ }, server: { port: 3000, + host: true, }, }); diff --git a/package.json b/package.json index 85de51a..f6a6b6e 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,9 @@ "picomatch@>=4.0.0 <4.0.4": "4.0.4", "brace-expansion@>=4.0.0 <5.0.5": "5.0.5", "path-to-regexp@<0.1.13": "0.1.13", - "lodash@<4.18.1": "4.18.1" + "lodash@<4.18.1": "4.18.1", + "react": "catalog:", + "react-dom": "catalog:" }, "onlyBuiltDependencies": [ "@sentry/cli", @@ -75,5 +77,11 @@ "typescript-eslint": "^8.58.1", "vite": "catalog:", "vitest": "^4.1.4" + }, + "version": "1.0.0", + "dependencies": { + "expo": "~55.0.15", + "react": "19.2.0", + "react-native": "0.83.4" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ed42428..d2bf550 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,13 +8,13 @@ catalogs: default: '@react-router/dev': specifier: ^7.14.0 - version: 7.14.0 + version: 7.14.1 '@react-router/node': specifier: ^7.14.0 - version: 7.14.0 + version: 7.14.1 '@react-router/serve': specifier: ^7.14.0 - version: 7.14.0 + version: 7.14.1 '@sentry/node': specifier: ^10.48.0 version: 10.48.0 @@ -45,15 +45,9 @@ catalogs: postgres: specifier: ^3.4.9 version: 3.4.9 - react: - specifier: ^19.2.5 - version: 19.2.5 - react-dom: - specifier: ^19.2.5 - version: 19.2.5 react-router: specifier: ^7.14.0 - version: 7.14.0 + version: 7.14.1 tailwindcss: specifier: ^4.2.2 version: 4.2.2 @@ -69,10 +63,22 @@ overrides: brace-expansion@>=4.0.0 <5.0.5: 5.0.5 path-to-regexp@<0.1.13: 0.1.13 lodash@<4.18.1: 4.18.1 + react: ^19.2.5 + react-dom: ^19.2.5 importers: .: + dependencies: + expo: + specifier: ~55.0.15 + version: 55.0.15(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + react: + specifier: ^19.2.5 + version: 19.2.5 + react-native: + specifier: 0.83.4 + version: 0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5) devDependencies: '@eslint/js': specifier: ^10.0.1 @@ -85,19 +91,19 @@ importers: version: 1.59.1 '@react-router/dev': specifier: 'catalog:' - version: 7.14.0(@react-router/serve@7.14.0(react-router@7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3))(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)(react-router@7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) + version: 7.14.1(@react-router/serve@7.14.1(react-router@7.14.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3))(@types/node@25.6.0)(jiti@2.6.1)(lightningcss@1.32.0)(react-router@7.14.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) '@react-router/node': specifier: 'catalog:' - version: 7.14.0(react-router@7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3) + version: 7.14.1(react-router@7.14.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3) '@react-router/serve': specifier: 'catalog:' - version: 7.14.0(react-router@7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3) + version: 7.14.1(react-router@7.14.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3) '@sentry/vite-plugin': specifier: ^5.2.0 - version: 5.2.0(rollup@4.60.0) + version: 5.2.0(rollup@4.60.1) '@tailwindcss/vite': specifier: 'catalog:' - version: 4.2.2(vite@8.0.8(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.2.2(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) '@testing-library/jest-dom': specifier: ^6.9.1 version: 6.9.1 @@ -158,21 +164,18 @@ importers: prettier: specifier: ^3.8.2 version: 3.8.2 - react: - specifier: 'catalog:' - version: 19.2.5 react-dom: - specifier: 'catalog:' + specifier: ^19.2.5 version: 19.2.5(react@19.2.5) react-i18next: specifier: ^17.0.2 - version: 17.0.2(i18next@26.0.4(typescript@5.9.3))(react-dom@19.2.5(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + version: 17.0.3(i18next@26.0.4(typescript@5.9.3))(react-dom@19.2.5(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) react-leaflet: specifier: ^5.0.0 version: 5.0.0(leaflet@1.9.4)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) react-router: specifier: 'catalog:' - version: 7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + version: 7.14.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5) tailwindcss: specifier: 'catalog:' version: 4.2.2 @@ -181,22 +184,22 @@ importers: version: 2.9.6 typescript-eslint: specifier: ^8.58.1 - version: 8.58.1(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3) + version: 8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3) vite: specifier: 'catalog:' - version: 8.0.8(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) + version: 8.0.8(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) vitest: specifier: ^4.1.4 - version: 4.1.4(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(jsdom@29.0.2)(vite@8.0.8(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.4(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(jsdom@29.0.2)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) apps/journal: dependencies: '@react-router/node': specifier: 'catalog:' - version: 7.14.0(react-router@7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3) + version: 7.14.1(react-router@7.14.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3) '@react-router/serve': specifier: 'catalog:' - version: 7.14.0(react-router@7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3) + version: 7.14.1(react-router@7.14.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3) '@sentry/node': specifier: 'catalog:' version: 10.48.0 @@ -238,7 +241,7 @@ importers: version: 0.45.2(@opentelemetry/api@1.9.1)(@types/pg@8.15.6)(expo-sqlite@55.0.15(expo@55.0.15)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(pg@8.20.0)(postgres@3.4.9) isbot: specifier: ^5.1.37 - version: 5.1.37 + version: 5.1.38 jose: specifier: ^6.2.2 version: 6.2.2 @@ -252,24 +255,24 @@ importers: specifier: ^15.1.3 version: 15.1.3 react: - specifier: 'catalog:' + specifier: ^19.2.5 version: 19.2.5 react-dom: - specifier: 'catalog:' + specifier: ^19.2.5 version: 19.2.5(react@19.2.5) react-router: specifier: 'catalog:' - version: 7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + version: 7.14.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5) devDependencies: '@react-router/dev': specifier: 'catalog:' - version: 7.14.0(@react-router/serve@7.14.0(react-router@7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3))(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)(react-router@7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) + version: 7.14.1(@react-router/serve@7.14.1(react-router@7.14.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3))(@types/node@25.6.0)(jiti@2.6.1)(lightningcss@1.32.0)(react-router@7.14.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) '@simplewebauthn/types': specifier: ^12.0.0 version: 12.0.0 '@tailwindcss/vite': specifier: 'catalog:' - version: 4.2.2(vite@8.0.8(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.2.2(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) '@types/nodemailer': specifier: ^8.0.0 version: 8.0.0 @@ -281,7 +284,7 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-basic-ssl': specifier: ^2.3.0 - version: 2.3.0(vite@8.0.8(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 2.3.0(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) pino-pretty: specifier: ^13.1.3 version: 13.1.3 @@ -293,7 +296,7 @@ importers: version: 5.9.3 vite: specifier: 'catalog:' - version: 8.0.8(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) + version: 8.0.8(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) apps/mobile: dependencies: @@ -365,7 +368,7 @@ importers: version: 55.0.19(expo@55.0.15)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) expo-router: specifier: ~55.0.12 - version: 55.0.12(2abaf9bed2da34a074803b38a8556f5d) + version: 55.0.12(967bbc80afd40466d8ec2b5429609e86) expo-secure-store: specifier: ~55.0.13 version: 55.0.13(expo@55.0.15) @@ -385,7 +388,7 @@ importers: specifier: ~55.0.14 version: 55.0.14(expo@55.0.15)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5)) react: - specifier: 'catalog:' + specifier: ^19.2.5 version: 19.2.5 react-native: specifier: 0.83.4 @@ -411,7 +414,7 @@ importers: devDependencies: '@testing-library/react-native': specifier: ^13.3.3 - version: 13.3.3(jest@29.7.0(@types/node@25.5.2)(ts-node@10.9.2(@types/node@25.5.2)(typescript@5.9.3)))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react-test-renderer@19.2.5(react@19.2.5))(react@19.2.5) + version: 13.3.3(jest@29.7.0(@types/node@25.6.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react-test-renderer@19.2.5(react@19.2.5))(react@19.2.5) '@types/jest': specifier: ^29.5.14 version: 29.5.14 @@ -420,7 +423,7 @@ importers: version: 19.2.14 jest-expo: specifier: ^55.0.15 - version: 55.0.15(@babel/core@7.29.0)(expo@55.0.15)(jest@29.7.0(@types/node@25.5.2)(ts-node@10.9.2(@types/node@25.5.2)(typescript@5.9.3)))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + version: 55.0.16(@babel/core@7.29.0)(expo@55.0.15)(jest@29.7.0(@types/node@25.6.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) react-test-renderer: specifier: ^19.2.5 version: 19.2.5(react@19.2.5) @@ -447,10 +450,10 @@ importers: version: 2.19.3(leaflet@1.9.4) '@react-router/node': specifier: 'catalog:' - version: 7.14.0(react-router@7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3) + version: 7.14.1(react-router@7.14.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3) '@react-router/serve': specifier: 'catalog:' - version: 7.14.0(react-router@7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3) + version: 7.14.1(react-router@7.14.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3) '@sentry/node': specifier: 'catalog:' version: 10.48.0 @@ -489,7 +492,7 @@ importers: version: 0.45.2(@opentelemetry/api@1.9.1)(@types/pg@8.15.6)(expo-sqlite@55.0.15(expo@55.0.15)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(pg@8.20.0)(postgres@3.4.9) isbot: specifier: ^5.1.37 - version: 5.1.37 + version: 5.1.38 lib0: specifier: ^0.2.117 version: 0.2.117 @@ -500,14 +503,14 @@ importers: specifier: ^15.1.3 version: 15.1.3 react: - specifier: 'catalog:' + specifier: ^19.2.5 version: 19.2.5 react-dom: - specifier: 'catalog:' + specifier: ^19.2.5 version: 19.2.5(react@19.2.5) react-router: specifier: 'catalog:' - version: 7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + version: 7.14.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5) ws: specifier: ^8.20.0 version: 8.20.0 @@ -526,10 +529,10 @@ importers: devDependencies: '@react-router/dev': specifier: 'catalog:' - version: 7.14.0(@react-router/serve@7.14.0(react-router@7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3))(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)(react-router@7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) + version: 7.14.1(@react-router/serve@7.14.1(react-router@7.14.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3))(@types/node@25.6.0)(jiti@2.6.1)(lightningcss@1.32.0)(react-router@7.14.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) '@tailwindcss/vite': specifier: 'catalog:' - version: 4.2.2(vite@8.0.8(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.2.2(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) '@types/leaflet.markercluster': specifier: ^1.5.6 version: 1.5.6 @@ -556,7 +559,7 @@ importers: version: 5.9.3 vite: specifier: 'catalog:' - version: 8.0.8(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) + version: 8.0.8(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) packages/api: dependencies: @@ -596,11 +599,11 @@ importers: specifier: '>=26' version: 26.0.4(typescript@5.9.3) react: - specifier: '>=18' + specifier: ^19.2.5 version: 19.2.5 react-i18next: specifier: '>=17' - version: 17.0.2(i18next@26.0.4(typescript@5.9.3))(react-dom@19.2.5(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + version: 17.0.3(i18next@26.0.4(typescript@5.9.3))(react-dom@19.2.5(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) packages/jobs: dependencies: @@ -621,10 +624,10 @@ importers: specifier: '>=1.9' version: 1.9.4 react: - specifier: '>=18' + specifier: ^19.2.5 version: 19.2.5 react-dom: - specifier: '>=18' + specifier: ^19.2.5 version: 19.2.5(react@19.2.5) react-leaflet: specifier: '>=5' @@ -641,8 +644,8 @@ packages: '@adobe/css-tools@4.4.4': resolution: {integrity: sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg==} - '@asamuzakjp/css-color@5.1.9': - resolution: {integrity: sha512-zd9c/Wdso6v1U7v6w3i/hbAr4K7NaSHImdpvmLt+Y9ea5BhilnIGNkfhOJ7FEIuPipAnE9tZeDOll05WDT0kgg==} + '@asamuzakjp/css-color@5.1.10': + resolution: {integrity: sha512-02OhhkKtgNRuicQ/nF3TRnGsxL9wp0r3Y7VlKWyOHHGmGyvXv03y+PnymU8FKFJMTjIr1Bk8U2g1HWSLrpAHww==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} '@asamuzakjp/dom-selector@7.0.9': @@ -1176,23 +1179,19 @@ packages: '@codemirror/view@6.41.0': resolution: {integrity: sha512-6H/qadXsVuDY219Yljhohglve8xf4B8xJkVOEWfA5uiYKiTFppjqsvsfR5iPA0RbvRBoOyTZpbLIxe9+0UR8xA==} - '@cspotcode/source-map-support@0.8.1': - resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} - engines: {node: '>=12'} - '@csstools/color-helpers@6.0.2': resolution: {integrity: sha512-LMGQLS9EuADloEFkcTBR3BwV/CGHV7zyDxVRtVDTwdI2Ca4it0CCVTT9wCkxSgokjE5Ho41hEPgb8OEUwoXr6Q==} engines: {node: '>=20.19.0'} - '@csstools/css-calc@3.1.1': - resolution: {integrity: sha512-HJ26Z/vmsZQqs/o3a6bgKslXGFAungXGbinULZO3eMsOyNJHeBBZfup5FiZInOghgoM4Hwnmw+OgbJCNg1wwUQ==} + '@csstools/css-calc@3.2.0': + resolution: {integrity: sha512-bR9e6o2BDB12jzN/gIbjHa5wLJ4UjD1CB9pM7ehlc0ddk6EBz+yYS1EV2MF55/HUxrHcB/hehAyt5vhsA3hx7w==} engines: {node: '>=20.19.0'} peerDependencies: '@csstools/css-parser-algorithms': ^4.0.0 '@csstools/css-tokenizer': ^4.0.0 - '@csstools/css-color-parser@4.0.2': - resolution: {integrity: sha512-0GEfbBLmTFf0dJlpsNU7zwxRIH0/BGEMuXLTCvFYxuL1tNhqzTbtnFICyJLTNK4a+RechKP75e7w42ClXSnJQw==} + '@csstools/css-color-parser@4.1.0': + resolution: {integrity: sha512-U0KhLYmy2GVj6q4T3WaAe6NPuFYCPQoE3b0dRGxejWDgcPp8TP7S5rVdM5ZrFaqu4N67X8YaPBw14dQSYx3IyQ==} engines: {node: '>=20.19.0'} peerDependencies: '@csstools/css-parser-algorithms': ^4.0.0 @@ -1204,8 +1203,8 @@ packages: peerDependencies: '@csstools/css-tokenizer': ^4.0.0 - '@csstools/css-syntax-patches-for-csstree@1.1.1': - resolution: {integrity: sha512-BvqN0AMWNAnLk9G8jnUT77D+mUbY/H2b3uDTvg2isJkHaOufUE2R3AOwxWo7VBQKT1lOdwdvorddo2B/lk64+w==} + '@csstools/css-syntax-patches-for-csstree@1.1.3': + resolution: {integrity: sha512-SH60bMfrRCJF3morcdk57WklujF4Jr/EsQUzqkarfHXEFcAR1gg7fS/chAE922Sehgzc1/+Tz5H3Ypa1HiEKrg==} peerDependencies: css-tree: ^3.2.1 peerDependenciesMeta: @@ -1246,8 +1245,8 @@ packages: cpu: [ppc64] os: [aix] - '@esbuild/aix-ppc64@0.27.4': - resolution: {integrity: sha512-cQPwL2mp2nSmHHJlCyoXgHGhbEPMrEEU5xhkcy3Hs/O7nGZqEpZ2sUtLaL9MORLtDfRvVl2/3PAuEkYZH0Ty8Q==} + '@esbuild/aix-ppc64@0.27.7': + resolution: {integrity: sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] @@ -1264,8 +1263,8 @@ packages: cpu: [arm64] os: [android] - '@esbuild/android-arm64@0.27.4': - resolution: {integrity: sha512-gdLscB7v75wRfu7QSm/zg6Rx29VLdy9eTr2t44sfTW7CxwAtQghZ4ZnqHk3/ogz7xao0QAgrkradbBzcqFPasw==} + '@esbuild/android-arm64@0.27.7': + resolution: {integrity: sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==} engines: {node: '>=18'} cpu: [arm64] os: [android] @@ -1282,8 +1281,8 @@ packages: cpu: [arm] os: [android] - '@esbuild/android-arm@0.27.4': - resolution: {integrity: sha512-X9bUgvxiC8CHAGKYufLIHGXPJWnr0OCdR0anD2e21vdvgCI8lIfqFbnoeOz7lBjdrAGUhqLZLcQo6MLhTO2DKQ==} + '@esbuild/android-arm@0.27.7': + resolution: {integrity: sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==} engines: {node: '>=18'} cpu: [arm] os: [android] @@ -1300,8 +1299,8 @@ packages: cpu: [x64] os: [android] - '@esbuild/android-x64@0.27.4': - resolution: {integrity: sha512-PzPFnBNVF292sfpfhiyiXCGSn9HZg5BcAz+ivBuSsl6Rk4ga1oEXAamhOXRFyMcjwr2DVtm40G65N3GLeH1Lvw==} + '@esbuild/android-x64@0.27.7': + resolution: {integrity: sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==} engines: {node: '>=18'} cpu: [x64] os: [android] @@ -1318,8 +1317,8 @@ packages: cpu: [arm64] os: [darwin] - '@esbuild/darwin-arm64@0.27.4': - resolution: {integrity: sha512-b7xaGIwdJlht8ZFCvMkpDN6uiSmnxxK56N2GDTMYPr2/gzvfdQN8rTfBsvVKmIVY/X7EM+/hJKEIbbHs9oA4tQ==} + '@esbuild/darwin-arm64@0.27.7': + resolution: {integrity: sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] @@ -1336,8 +1335,8 @@ packages: cpu: [x64] os: [darwin] - '@esbuild/darwin-x64@0.27.4': - resolution: {integrity: sha512-sR+OiKLwd15nmCdqpXMnuJ9W2kpy0KigzqScqHI3Hqwr7IXxBp3Yva+yJwoqh7rE8V77tdoheRYataNKL4QrPw==} + '@esbuild/darwin-x64@0.27.7': + resolution: {integrity: sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==} engines: {node: '>=18'} cpu: [x64] os: [darwin] @@ -1354,8 +1353,8 @@ packages: cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-arm64@0.27.4': - resolution: {integrity: sha512-jnfpKe+p79tCnm4GVav68A7tUFeKQwQyLgESwEAUzyxk/TJr4QdGog9sqWNcUbr/bZt/O/HXouspuQDd9JxFSw==} + '@esbuild/freebsd-arm64@0.27.7': + resolution: {integrity: sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] @@ -1372,8 +1371,8 @@ packages: cpu: [x64] os: [freebsd] - '@esbuild/freebsd-x64@0.27.4': - resolution: {integrity: sha512-2kb4ceA/CpfUrIcTUl1wrP/9ad9Atrp5J94Lq69w7UwOMolPIGrfLSvAKJp0RTvkPPyn6CIWrNy13kyLikZRZQ==} + '@esbuild/freebsd-x64@0.27.7': + resolution: {integrity: sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] @@ -1390,8 +1389,8 @@ packages: cpu: [arm64] os: [linux] - '@esbuild/linux-arm64@0.27.4': - resolution: {integrity: sha512-7nQOttdzVGth1iz57kxg9uCz57dxQLHWxopL6mYuYthohPKEK0vU0C3O21CcBK6KDlkYVcnDXY099HcCDXd9dA==} + '@esbuild/linux-arm64@0.27.7': + resolution: {integrity: sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==} engines: {node: '>=18'} cpu: [arm64] os: [linux] @@ -1408,8 +1407,8 @@ packages: cpu: [arm] os: [linux] - '@esbuild/linux-arm@0.27.4': - resolution: {integrity: sha512-aBYgcIxX/wd5n2ys0yESGeYMGF+pv6g0DhZr3G1ZG4jMfruU9Tl1i2Z+Wnj9/KjGz1lTLCcorqE2viePZqj4Eg==} + '@esbuild/linux-arm@0.27.7': + resolution: {integrity: sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==} engines: {node: '>=18'} cpu: [arm] os: [linux] @@ -1426,8 +1425,8 @@ packages: cpu: [ia32] os: [linux] - '@esbuild/linux-ia32@0.27.4': - resolution: {integrity: sha512-oPtixtAIzgvzYcKBQM/qZ3R+9TEUd1aNJQu0HhGyqtx6oS7qTpvjheIWBbes4+qu1bNlo2V4cbkISr8q6gRBFA==} + '@esbuild/linux-ia32@0.27.7': + resolution: {integrity: sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==} engines: {node: '>=18'} cpu: [ia32] os: [linux] @@ -1444,8 +1443,8 @@ packages: cpu: [loong64] os: [linux] - '@esbuild/linux-loong64@0.27.4': - resolution: {integrity: sha512-8mL/vh8qeCoRcFH2nM8wm5uJP+ZcVYGGayMavi8GmRJjuI3g1v6Z7Ni0JJKAJW+m0EtUuARb6Lmp4hMjzCBWzA==} + '@esbuild/linux-loong64@0.27.7': + resolution: {integrity: sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==} engines: {node: '>=18'} cpu: [loong64] os: [linux] @@ -1462,8 +1461,8 @@ packages: cpu: [mips64el] os: [linux] - '@esbuild/linux-mips64el@0.27.4': - resolution: {integrity: sha512-1RdrWFFiiLIW7LQq9Q2NES+HiD4NyT8Itj9AUeCl0IVCA459WnPhREKgwrpaIfTOe+/2rdntisegiPWn/r/aAw==} + '@esbuild/linux-mips64el@0.27.7': + resolution: {integrity: sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] @@ -1480,8 +1479,8 @@ packages: cpu: [ppc64] os: [linux] - '@esbuild/linux-ppc64@0.27.4': - resolution: {integrity: sha512-tLCwNG47l3sd9lpfyx9LAGEGItCUeRCWeAx6x2Jmbav65nAwoPXfewtAdtbtit/pJFLUWOhpv0FpS6GQAmPrHA==} + '@esbuild/linux-ppc64@0.27.7': + resolution: {integrity: sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] @@ -1498,8 +1497,8 @@ packages: cpu: [riscv64] os: [linux] - '@esbuild/linux-riscv64@0.27.4': - resolution: {integrity: sha512-BnASypppbUWyqjd1KIpU4AUBiIhVr6YlHx/cnPgqEkNoVOhHg+YiSVxM1RLfiy4t9cAulbRGTNCKOcqHrEQLIw==} + '@esbuild/linux-riscv64@0.27.7': + resolution: {integrity: sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] @@ -1516,8 +1515,8 @@ packages: cpu: [s390x] os: [linux] - '@esbuild/linux-s390x@0.27.4': - resolution: {integrity: sha512-+eUqgb/Z7vxVLezG8bVB9SfBie89gMueS+I0xYh2tJdw3vqA/0ImZJ2ROeWwVJN59ihBeZ7Tu92dF/5dy5FttA==} + '@esbuild/linux-s390x@0.27.7': + resolution: {integrity: sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==} engines: {node: '>=18'} cpu: [s390x] os: [linux] @@ -1534,8 +1533,8 @@ packages: cpu: [x64] os: [linux] - '@esbuild/linux-x64@0.27.4': - resolution: {integrity: sha512-S5qOXrKV8BQEzJPVxAwnryi2+Iq5pB40gTEIT69BQONqR7JH1EPIcQ/Uiv9mCnn05jff9umq/5nqzxlqTOg9NA==} + '@esbuild/linux-x64@0.27.7': + resolution: {integrity: sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==} engines: {node: '>=18'} cpu: [x64] os: [linux] @@ -1546,8 +1545,8 @@ packages: cpu: [arm64] os: [netbsd] - '@esbuild/netbsd-arm64@0.27.4': - resolution: {integrity: sha512-xHT8X4sb0GS8qTqiwzHqpY00C95DPAq7nAwX35Ie/s+LO9830hrMd3oX0ZMKLvy7vsonee73x0lmcdOVXFzd6Q==} + '@esbuild/netbsd-arm64@0.27.7': + resolution: {integrity: sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] @@ -1564,8 +1563,8 @@ packages: cpu: [x64] os: [netbsd] - '@esbuild/netbsd-x64@0.27.4': - resolution: {integrity: sha512-RugOvOdXfdyi5Tyv40kgQnI0byv66BFgAqjdgtAKqHoZTbTF2QqfQrFwa7cHEORJf6X2ht+l9ABLMP0dnKYsgg==} + '@esbuild/netbsd-x64@0.27.7': + resolution: {integrity: sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] @@ -1576,8 +1575,8 @@ packages: cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-arm64@0.27.4': - resolution: {integrity: sha512-2MyL3IAaTX+1/qP0O1SwskwcwCoOI4kV2IBX1xYnDDqthmq5ArrW94qSIKCAuRraMgPOmG0RDTA74mzYNQA9ow==} + '@esbuild/openbsd-arm64@0.27.7': + resolution: {integrity: sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] @@ -1594,8 +1593,8 @@ packages: cpu: [x64] os: [openbsd] - '@esbuild/openbsd-x64@0.27.4': - resolution: {integrity: sha512-u8fg/jQ5aQDfsnIV6+KwLOf1CmJnfu1ShpwqdwC0uA7ZPwFws55Ngc12vBdeUdnuWoQYx/SOQLGDcdlfXhYmXQ==} + '@esbuild/openbsd-x64@0.27.7': + resolution: {integrity: sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] @@ -1606,8 +1605,8 @@ packages: cpu: [arm64] os: [openharmony] - '@esbuild/openharmony-arm64@0.27.4': - resolution: {integrity: sha512-JkTZrl6VbyO8lDQO3yv26nNr2RM2yZzNrNHEsj9bm6dOwwu9OYN28CjzZkH57bh4w0I2F7IodpQvUAEd1mbWXg==} + '@esbuild/openharmony-arm64@0.27.7': + resolution: {integrity: sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==} engines: {node: '>=18'} cpu: [arm64] os: [openharmony] @@ -1624,8 +1623,8 @@ packages: cpu: [x64] os: [sunos] - '@esbuild/sunos-x64@0.27.4': - resolution: {integrity: sha512-/gOzgaewZJfeJTlsWhvUEmUG4tWEY2Spp5M20INYRg2ZKl9QPO3QEEgPeRtLjEWSW8FilRNacPOg8R1uaYkA6g==} + '@esbuild/sunos-x64@0.27.7': + resolution: {integrity: sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==} engines: {node: '>=18'} cpu: [x64] os: [sunos] @@ -1642,8 +1641,8 @@ packages: cpu: [arm64] os: [win32] - '@esbuild/win32-arm64@0.27.4': - resolution: {integrity: sha512-Z9SExBg2y32smoDQdf1HRwHRt6vAHLXcxD2uGgO/v2jK7Y718Ix4ndsbNMU/+1Qiem9OiOdaqitioZwxivhXYg==} + '@esbuild/win32-arm64@0.27.7': + resolution: {integrity: sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==} engines: {node: '>=18'} cpu: [arm64] os: [win32] @@ -1660,8 +1659,8 @@ packages: cpu: [ia32] os: [win32] - '@esbuild/win32-ia32@0.27.4': - resolution: {integrity: sha512-DAyGLS0Jz5G5iixEbMHi5KdiApqHBWMGzTtMiJ72ZOLhbu/bzxgAe8Ue8CTS3n3HbIUHQz/L51yMdGMeoxXNJw==} + '@esbuild/win32-ia32@0.27.7': + resolution: {integrity: sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==} engines: {node: '>=18'} cpu: [ia32] os: [win32] @@ -1678,8 +1677,8 @@ packages: cpu: [x64] os: [win32] - '@esbuild/win32-x64@0.27.4': - resolution: {integrity: sha512-+knoa0BDoeXgkNvvV1vvbZX4+hizelrkwmGJBdT17t8FNPwG2lKemmuMZlmaNQ3ws3DKKCxpb4zRZEIp3UxFCg==} + '@esbuild/win32-x64@0.27.7': + resolution: {integrity: sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==} engines: {node: '>=18'} cpu: [x64] os: [win32] @@ -1694,16 +1693,16 @@ packages: resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - '@eslint/config-array@0.23.4': - resolution: {integrity: sha512-lf19F24LSMfF8weXvW5QEtnLqW70u7kgit5e9PSx0MsHAFclGd1T9ynvWEMDT1w5J4Qt54tomGeAhdoAku1Xow==} + '@eslint/config-array@0.23.5': + resolution: {integrity: sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} - '@eslint/config-helpers@0.5.4': - resolution: {integrity: sha512-jJhqiY3wPMlWWO3370M86CPJ7pt8GmEwSLglMfQhjXal07RCvhmU0as4IuUEW5SJeunfItiEetHmSxCCe9lDBg==} + '@eslint/config-helpers@0.5.5': + resolution: {integrity: sha512-eIJYKTCECbP/nsKaaruF6LW967mtbQbsw4JTtSVkUQc9MneSkbrgPJAbKl9nWr0ZeowV8BfsarBmPpBzGelA2w==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} - '@eslint/core@1.2.0': - resolution: {integrity: sha512-8FTGbNzTvmSlc4cZBaShkC6YvFMG0riksYWRFKXztqVdXaQbcZLXlFbSpC05s70sGEsXAw0qwhx69JiW7hQS7A==} + '@eslint/core@1.2.1': + resolution: {integrity: sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} '@eslint/js@10.0.1': @@ -1715,12 +1714,12 @@ packages: eslint: optional: true - '@eslint/object-schema@3.0.4': - resolution: {integrity: sha512-55lO/7+Yp0ISKRP0PsPtNTeNGapXaO085aELZmWCVc5SH3jfrqpuU6YgOdIxMS99ZHkQN1cXKE+cdIqwww9ptw==} + '@eslint/object-schema@3.0.5': + resolution: {integrity: sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} - '@eslint/plugin-kit@0.7.0': - resolution: {integrity: sha512-ejvBr8MQCbVsWNZnCwDXjUKq40MDmHalq7cJ6e9s/qzTUFIIo/afzt1Vui9T97FM/V/pN4YsFVoed5NIa96RDg==} + '@eslint/plugin-kit@0.7.1': + resolution: {integrity: sha512-rZAP3aVgB9ds9KOeUSL+zZ21hPmo8dh6fnIFwRQj5EAZl9gzR7wxYbYXYysAM8CTqGmUGyp2S4kUdV17MnGuWQ==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} '@exodus/bytes@1.15.0': @@ -1732,8 +1731,8 @@ packages: '@noble/hashes': optional: true - '@expo-google-fonts/material-symbols@0.4.30': - resolution: {integrity: sha512-ZCfA0jcVG/dHJGbweOmIRz6vQ53fR8reuvGSd+GcWzOwMm2Y4tkMIAXhrekltiG8sx4KM9bm4LE18RN8wTxmHg==} + '@expo-google-fonts/material-symbols@0.4.31': + resolution: {integrity: sha512-IKuqICW5oWpBSsr7zvteSKuPNLkpKVmKaZC6AvFMeMfpAHW606wNI9iAdu1ENMpnYw+RHrhQlQC5OxOl9VNikQ==} '@expo/cli@55.0.24': resolution: {integrity: sha512-Z6Xh0WNTg1LvoZQ77zO3snF2cFiv1xf0VguDlwTL1Ql87oMOp30f7mjl9jeaSHqoWkgiAbmxgCKKIGjVX/keiA==} @@ -1757,9 +1756,6 @@ packages: '@expo/config-types@55.0.5': resolution: {integrity: sha512-sCmSUZG4mZ/ySXvfyyBdhjivz8Q539X1NondwDdYG7s3SBsk+wsgPJzYsqgAG/P9+l0xWjUD2F+kQ1cAJ6NNLg==} - '@expo/config@55.0.14': - resolution: {integrity: sha512-CCIe6Suuy0DjC58PI6jBpK8Y3pW0BimXGP8tZrVKPqS5ECqVTei0Xp78nbC/fbO+79r6ak5Su6Os71U459j4dw==} - '@expo/config@55.0.15': resolution: {integrity: sha512-lHc0ELIQ8126jYOMZpLv3WIuvordW98jFg5aT/J1/12n2ycuXu01XLZkJsdw0avO34cusUYb1It+MvY8JiMduA==} @@ -1769,7 +1765,7 @@ packages: '@expo/devtools@55.0.2': resolution: {integrity: sha512-4VsFn9MUriocyuhyA+ycJP3TJhUsOFHDc270l9h3LhNpXMf6wvIdGcA0QzXkZtORXmlDybWXRP2KT1k36HcQkA==} peerDependencies: - react: '*' + react: ^19.2.5 react-native: '*' peerDependenciesMeta: react: @@ -1781,7 +1777,7 @@ packages: resolution: {integrity: sha512-lt3uxYOCk3wmWvtOOvsC35CKGbDAOx5C2EaY8SH1JVSfBzqmF8Cs0Xp1MPxncDPMyxpMiWx5SvvV/iLF1rJU4A==} peerDependencies: expo: '*' - react: '*' + react: ^19.2.5 react-native: '*' '@expo/env@2.1.1': @@ -1806,7 +1802,7 @@ packages: peerDependencies: '@expo/dom-webview': ^55.0.5 expo: '*' - react: '*' + react: ^19.2.5 react-native: '*' '@expo/metro-config@55.0.16': @@ -1821,8 +1817,8 @@ packages: resolution: {integrity: sha512-H37b2Mc/8GiQbwtUFzUTxA3KsAMZu00SRg/RhbHa9xVE7J0n5ZX4NHy0LJEFAbkzTb1TUy1hLpo3oEKnG+rLyg==} peerDependencies: expo: '*' - react: '*' - react-dom: '*' + react: ^19.2.5 + react-dom: ^19.2.5 react-native: '*' peerDependenciesMeta: react-dom: @@ -1863,8 +1859,8 @@ packages: expo-font: ^55.0.6 expo-router: '*' expo-server: ^55.0.7 - react: '*' - react-dom: '*' + react: ^19.2.5 + react-dom: ^19.2.5 react-server-dom-webpack: ~19.0.1 || ~19.1.2 || ~19.2.1 peerDependenciesMeta: '@expo/metro-runtime': @@ -1893,7 +1889,7 @@ packages: resolution: {integrity: sha512-Iu2VkcoI5vygbtYngm7jb4ifxElNVXQYdDrYkT7UCEIiKLeWnQY0wf2ZhHZ+Wro6Sc5TaumpKUOqDRpLi5rkvw==} peerDependencies: expo-font: '>=14.0.4' - react: '*' + react: ^19.2.5 react-native: '*' '@expo/ws-tunnel@1.0.6': @@ -1919,7 +1915,7 @@ packages: peerDependencies: '@types/react': '*' '@types/react-native': '*' - react: '*' + react: ^19.2.5 react-native: '*' react-native-gesture-handler: '>=2.16.1' react-native-reanimated: '>=3.16.0 || >=4.0.0-' @@ -1932,7 +1928,7 @@ packages: '@gorhom/portal@1.0.14': resolution: {integrity: sha512-MXyL4xvCjmgaORr/rtryDNFy3kU4qUbKlwtQqqsygd0xX3mhKjOLn6mQK8wfu0RkoE0pBE0nAasRoHua+/QZ7A==} peerDependencies: - react: '*' + react: ^19.2.5 react-native: '*' '@hexagon/base64@1.1.28': @@ -1962,8 +1958,8 @@ packages: resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} engines: {node: '>=8'} - '@istanbuljs/schema@0.1.3': - resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} + '@istanbuljs/schema@0.1.6': + resolution: {integrity: sha512-+Sg6GCR/wy1oSmQDFq4LQDAhm3ETKnorxN+y5nbLULOR3P0c14f2Wurzj3/xqPXtasLFfHd5iRFQ7AJt4KH2cw==} engines: {node: '>=8'} '@jest/console@29.7.0': @@ -2067,9 +2063,6 @@ packages: '@jridgewell/trace-mapping@0.3.31': resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} - '@jridgewell/trace-mapping@0.3.9': - resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} - '@levischuck/tiny-cbor@0.2.11': resolution: {integrity: sha512-llBRm4dT4Z89aRsm6u2oEZ8tfwL/2l6BwpZ7JcyieouniDECM5AqNgr/y08zalEIvW3RSK4upYyybDcmjXqAow==} @@ -2088,7 +2081,7 @@ packages: '@expo/config-plugins': '>=7' '@types/geojson': ^7946.0.0 '@types/react': '>=16.6.1' - react: '>=16.6.1' + react: ^19.2.5 react-native: '>=0.59.9' peerDependenciesMeta: '@expo/config-plugins': @@ -2369,8 +2362,8 @@ packages: peerDependencies: '@types/react': '*' '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react: ^19.2.5 + react-dom: ^19.2.5 peerDependenciesMeta: '@types/react': optional: true @@ -2381,7 +2374,7 @@ packages: resolution: {integrity: sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==} peerDependencies: '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react: ^19.2.5 peerDependenciesMeta: '@types/react': optional: true @@ -2390,7 +2383,7 @@ packages: resolution: {integrity: sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==} peerDependencies: '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react: ^19.2.5 peerDependenciesMeta: '@types/react': optional: true @@ -2400,8 +2393,8 @@ packages: peerDependencies: '@types/react': '*' '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react: ^19.2.5 + react-dom: ^19.2.5 peerDependenciesMeta: '@types/react': optional: true @@ -2412,7 +2405,7 @@ packages: resolution: {integrity: sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==} peerDependencies: '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react: ^19.2.5 peerDependenciesMeta: '@types/react': optional: true @@ -2422,8 +2415,8 @@ packages: peerDependencies: '@types/react': '*' '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react: ^19.2.5 + react-dom: ^19.2.5 peerDependenciesMeta: '@types/react': optional: true @@ -2434,7 +2427,7 @@ packages: resolution: {integrity: sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==} peerDependencies: '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react: ^19.2.5 peerDependenciesMeta: '@types/react': optional: true @@ -2444,8 +2437,8 @@ packages: peerDependencies: '@types/react': '*' '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react: ^19.2.5 + react-dom: ^19.2.5 peerDependenciesMeta: '@types/react': optional: true @@ -2456,7 +2449,7 @@ packages: resolution: {integrity: sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==} peerDependencies: '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react: ^19.2.5 peerDependenciesMeta: '@types/react': optional: true @@ -2466,8 +2459,8 @@ packages: peerDependencies: '@types/react': '*' '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react: ^19.2.5 + react-dom: ^19.2.5 peerDependenciesMeta: '@types/react': optional: true @@ -2479,8 +2472,8 @@ packages: peerDependencies: '@types/react': '*' '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react: ^19.2.5 + react-dom: ^19.2.5 peerDependenciesMeta: '@types/react': optional: true @@ -2492,8 +2485,8 @@ packages: peerDependencies: '@types/react': '*' '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react: ^19.2.5 + react-dom: ^19.2.5 peerDependenciesMeta: '@types/react': optional: true @@ -2505,8 +2498,8 @@ packages: peerDependencies: '@types/react': '*' '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react: ^19.2.5 + react-dom: ^19.2.5 peerDependenciesMeta: '@types/react': optional: true @@ -2517,7 +2510,16 @@ packages: resolution: {integrity: sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==} peerDependencies: '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react: ^19.2.5 + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-slot@1.2.4': + resolution: {integrity: sha512-Jl+bCv8HxKnlTLVrcDE8zTMJ09R9/ukw4qBs/oZClOfoQk/cOTbDn+NceXfV7j09YPVQUryJPHurafcSg6EVKA==} + peerDependencies: + '@types/react': '*' + react: ^19.2.5 peerDependenciesMeta: '@types/react': optional: true @@ -2527,8 +2529,8 @@ packages: peerDependencies: '@types/react': '*' '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react: ^19.2.5 + react-dom: ^19.2.5 peerDependenciesMeta: '@types/react': optional: true @@ -2539,7 +2541,7 @@ packages: resolution: {integrity: sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==} peerDependencies: '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react: ^19.2.5 peerDependenciesMeta: '@types/react': optional: true @@ -2548,7 +2550,7 @@ packages: resolution: {integrity: sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==} peerDependencies: '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react: ^19.2.5 peerDependenciesMeta: '@types/react': optional: true @@ -2557,7 +2559,7 @@ packages: resolution: {integrity: sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==} peerDependencies: '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react: ^19.2.5 peerDependenciesMeta: '@types/react': optional: true @@ -2566,7 +2568,7 @@ packages: resolution: {integrity: sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==} peerDependencies: '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react: ^19.2.5 peerDependenciesMeta: '@types/react': optional: true @@ -2575,7 +2577,7 @@ packages: resolution: {integrity: sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==} peerDependencies: '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react: ^19.2.5 peerDependenciesMeta: '@types/react': optional: true @@ -2584,8 +2586,8 @@ packages: resolution: {integrity: sha512-3EWmekh4Nz+pGcr+xjf0KNyYfC3U2JjnkWsh0zcqaexYqmmB5ZhH37kz41JXGmKzpaMZCnPofBBm64i+YrEvGQ==} peerDependencies: leaflet: ^1.9.0 - react: ^19.0.0 - react-dom: ^19.0.0 + react: ^19.2.5 + react-dom: ^19.2.5 '@react-native/assets-registry@0.83.4': resolution: {integrity: sha512-aqKtpbJDSQeSX/Dwv0yMe1/Rd2QfXi12lnyZDXNn/OEKz59u6+LuPBVgO/9CRyclHmdlvwg8c7PJ9eX2ZMnjWg==} @@ -2677,7 +2679,7 @@ packages: engines: {node: '>= 20.19.4'} peerDependencies: '@types/react': ^19.2.0 - react: '*' + react: ^19.2.5 react-native: '*' peerDependenciesMeta: '@types/react': @@ -2687,7 +2689,7 @@ packages: resolution: {integrity: sha512-Ou28A1aZLj5wiFQ3F93aIsrI4NCwn3IJzkkjNo9KLFXsc0Yks+UqrVaFlffHFLsrbajuGRG/OQpnMA1ljayY5Q==} peerDependencies: '@react-navigation/native': ^7.2.2 - react: '>= 18.2.0' + react: ^19.2.5 react-native: '*' react-native-safe-area-context: '>= 4.0.0' react-native-screens: '>= 4.0.0' @@ -2695,25 +2697,25 @@ packages: '@react-navigation/core@7.17.2': resolution: {integrity: sha512-Rt2OZwcgOmjv401uLGAKaRM6xo0fiBce/A7LfRHI1oe5FV+KooWcgAoZ2XOtgKj6UzVMuQWt3b2e6rxo/mDJRA==} peerDependencies: - react: '>= 18.2.0' + react: ^19.2.5 '@react-navigation/elements@2.9.14': resolution: {integrity: sha512-lKqzu+su2pI/YIZmR7L7xdOs4UL+rVXKJAMpRMBrwInEy96SjIFst6QDGpE89Dunnu3VjVpjWfByo9f2GWBHDQ==} peerDependencies: '@react-native-masked-view/masked-view': '>= 0.2.0' '@react-navigation/native': ^7.2.2 - react: '>= 18.2.0' + react: ^19.2.5 react-native: '*' react-native-safe-area-context: '>= 4.0.0' peerDependenciesMeta: '@react-native-masked-view/masked-view': optional: true - '@react-navigation/native-stack@7.14.10': - resolution: {integrity: sha512-mCbYbYhi7Em2R2nEgwYGdLU38smy+KK+HMMVcwuzllWsF3Qb+jOUEYbB6Or7LvE7SS77BZ6sHdx4HptCEv50hQ==} + '@react-navigation/native-stack@7.14.11': + resolution: {integrity: sha512-1ufBtJ7KbVFlQhXsYSYHqjgkmP30AzJSgW48YjWMQZ3NZGAyYe34w9Wd4KpdebQCfDClPe9maU+8crA/awa6lQ==} peerDependencies: '@react-navigation/native': ^7.2.2 - react: '>= 18.2.0' + react: ^19.2.5 react-native: '*' react-native-safe-area-context: '>= 4.0.0' react-native-screens: '>= 4.0.0' @@ -2721,22 +2723,22 @@ packages: '@react-navigation/native@7.2.2': resolution: {integrity: sha512-kem1Ko2BcbAjmbQIv66dNmr6EtfDut3QU0qjsVhMnLLhktwyXb6FzZYp8gTrUb6AvkAbaJoi+BF5Pl55pAUa5w==} peerDependencies: - react: '>= 18.2.0' + react: ^19.2.5 react-native: '*' '@react-navigation/routers@7.5.3': resolution: {integrity: sha512-1tJHg4KKRJuQ1/EvJxatrMef3NZXEPzwUIUZ3n1yJ2t7Q97siwRtbynRpQG9/69ebbtiZ8W3ScOZF/OmhvM4Rg==} - '@react-router/dev@7.14.0': - resolution: {integrity: sha512-/1ElF4lDTEIZ/rbEdlj6MmRY9ERRDyaTswWes+3pbqEKF2r/ixSzACueHWIfV9ULg/x5/weCvSexDD9f16ObwA==} + '@react-router/dev@7.14.1': + resolution: {integrity: sha512-ZBEwods1TxqPVY2SrXDuDCfoaE5VoTMBYrfa/+3MesprY3foSo1jhin9mh4FwmXPXhhmDYKXi2z5UR+oMj8Qjg==} engines: {node: '>=20.0.0'} hasBin: true peerDependencies: - '@react-router/serve': ^7.14.0 + '@react-router/serve': ^7.14.1 '@vitejs/plugin-rsc': ~0.5.21 - react-router: ^7.14.0 + react-router: ^7.14.1 react-server-dom-webpack: ^19.2.3 - typescript: ^5.1.0 + typescript: ^5.1.0 || ^6.0.0 vite: ^5.1.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 wrangler: ^3.28.2 || ^4.0.0 peerDependenciesMeta: @@ -2751,33 +2753,33 @@ packages: wrangler: optional: true - '@react-router/express@7.14.0': - resolution: {integrity: sha512-isrPotskov4KJ/v0GvTACaXWua/3iPs71717iZZfxix77MqVo1uW7jtuXc8ChJRRWSHZOv2NFvIOYCUFXzmNJA==} + '@react-router/express@7.14.1': + resolution: {integrity: sha512-XX/R+/JIIbwTfaXHz1WAJbiPfkd56y7PN9Czg7h6Tvos9TZlmMXmRhxWKRdzfsa8Lp8sq42JjKOBCEEPyH4V1Q==} engines: {node: '>=20.0.0'} peerDependencies: express: ^4.17.1 || ^5 - react-router: 7.14.0 - typescript: ^5.1.0 + react-router: 7.14.1 + typescript: ^5.1.0 || ^6.0.0 peerDependenciesMeta: typescript: optional: true - '@react-router/node@7.14.0': - resolution: {integrity: sha512-ZxJJLE4PX29+cHLacH3pmCHMCJQz/1dpEgFQtm8Pst2IP5GI6897rShYylLZbJ7jRBJSkskHn+opSEh+o6mmOA==} + '@react-router/node@7.14.1': + resolution: {integrity: sha512-SthTjCwW7otzEAcZwF0RAPMRrDT47B4qHDxZM45rM5K1Gp86ANK/xlXF+DgpLq9qKZf9FbKzxS9hT7FqDeBAOg==} engines: {node: '>=20.0.0'} peerDependencies: - react-router: 7.14.0 - typescript: ^5.1.0 + react-router: 7.14.1 + typescript: ^5.1.0 || ^6.0.0 peerDependenciesMeta: typescript: optional: true - '@react-router/serve@7.14.0': - resolution: {integrity: sha512-setPBP5+ci0vwx+ufGZl0inOwsCoGU1ssOJcW4fHo+Pb6GbbMTrbCOVO6yQkDsTrQju+iStp3d7FTxLHphLhcA==} + '@react-router/serve@7.14.1': + resolution: {integrity: sha512-3oSNEQqU4ekIQTMqc7c9MJMHzSUAl4knG5mF9+1HaLqvUaYAfZPidqd4JWQKeYwe6Tw6fa79lcvUXqfCSXiEUg==} engines: {node: '>=20.0.0'} hasBin: true peerDependencies: - react-router: 7.14.0 + react-router: 7.14.1 '@remix-run/node-fetch-server@0.13.0': resolution: {integrity: sha512-1EsNo0ZpgXu/90AWoRZf/oE3RVTUS80tiTUpt+hv5pjtAkw7icN4WskDwz/KdAw5ARbJLMhZBrO1NqThmy/McA==} @@ -2880,141 +2882,141 @@ packages: '@rolldown/pluginutils@1.0.0-rc.15': resolution: {integrity: sha512-UromN0peaE53IaBRe9W7CjrZgXl90fqGpK+mIZbA3qSTeYqg3pqpROBdIPvOG3F5ereDHNwoHBI2e50n1BDr1g==} - '@rollup/rollup-android-arm-eabi@4.60.0': - resolution: {integrity: sha512-WOhNW9K8bR3kf4zLxbfg6Pxu2ybOUbB2AjMDHSQx86LIF4rH4Ft7vmMwNt0loO0eonglSNy4cpD3MKXXKQu0/A==} + '@rollup/rollup-android-arm-eabi@4.60.1': + resolution: {integrity: sha512-d6FinEBLdIiK+1uACUttJKfgZREXrF0Qc2SmLII7W2AD8FfiZ9Wjd+rD/iRuf5s5dWrr1GgwXCvPqOuDquOowA==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.60.0': - resolution: {integrity: sha512-u6JHLll5QKRvjciE78bQXDmqRqNs5M/3GVqZeMwvmjaNODJih/WIrJlFVEihvV0MiYFmd+ZyPr9wxOVbPAG2Iw==} + '@rollup/rollup-android-arm64@4.60.1': + resolution: {integrity: sha512-YjG/EwIDvvYI1YvYbHvDz/BYHtkY4ygUIXHnTdLhG+hKIQFBiosfWiACWortsKPKU/+dUwQQCKQM3qrDe8c9BA==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.60.0': - resolution: {integrity: sha512-qEF7CsKKzSRc20Ciu2Zw1wRrBz4g56F7r/vRwY430UPp/nt1x21Q/fpJ9N5l47WWvJlkNCPJz3QRVw008fi7yA==} + '@rollup/rollup-darwin-arm64@4.60.1': + resolution: {integrity: sha512-mjCpF7GmkRtSJwon+Rq1N8+pI+8l7w5g9Z3vWj4T7abguC4Czwi3Yu/pFaLvA3TTeMVjnu3ctigusqWUfjZzvw==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.60.0': - resolution: {integrity: sha512-WADYozJ4QCnXCH4wPB+3FuGmDPoFseVCUrANmA5LWwGmC6FL14BWC7pcq+FstOZv3baGX65tZ378uT6WG8ynTw==} + '@rollup/rollup-darwin-x64@4.60.1': + resolution: {integrity: sha512-haZ7hJ1JT4e9hqkoT9R/19XW2QKqjfJVv+i5AGg57S+nLk9lQnJ1F/eZloRO3o9Scy9CM3wQ9l+dkXtcBgN5Ew==} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.60.0': - resolution: {integrity: sha512-6b8wGHJlDrGeSE3aH5mGNHBjA0TTkxdoNHik5EkvPHCt351XnigA4pS7Wsj/Eo9Y8RBU6f35cjN9SYmCFBtzxw==} + '@rollup/rollup-freebsd-arm64@4.60.1': + resolution: {integrity: sha512-czw90wpQq3ZsAVBlinZjAYTKduOjTywlG7fEeWKUA7oCmpA8xdTkxZZlwNJKWqILlq0wehoZcJYfBvOyhPTQ6w==} cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.60.0': - resolution: {integrity: sha512-h25Ga0t4jaylMB8M/JKAyrvvfxGRjnPQIR8lnCayyzEjEOx2EJIlIiMbhpWxDRKGKF8jbNH01NnN663dH638mA==} + '@rollup/rollup-freebsd-x64@4.60.1': + resolution: {integrity: sha512-KVB2rqsxTHuBtfOeySEyzEOB7ltlB/ux38iu2rBQzkjbwRVlkhAGIEDiiYnO2kFOkJp+Z7pUXKyrRRFuFUKt+g==} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.60.0': - resolution: {integrity: sha512-RzeBwv0B3qtVBWtcuABtSuCzToo2IEAIQrcyB/b2zMvBWVbjo8bZDjACUpnaafaxhTw2W+imQbP2BD1usasK4g==} + '@rollup/rollup-linux-arm-gnueabihf@4.60.1': + resolution: {integrity: sha512-L+34Qqil+v5uC0zEubW7uByo78WOCIrBvci69E7sFASRl0X7b/MB6Cqd1lky/CtcSVTydWa2WZwFuWexjS5o6g==} cpu: [arm] os: [linux] libc: [glibc] - '@rollup/rollup-linux-arm-musleabihf@4.60.0': - resolution: {integrity: sha512-Sf7zusNI2CIU1HLzuu9Tc5YGAHEZs5Lu7N1ssJG4Tkw6e0MEsN7NdjUDDfGNHy2IU+ENyWT+L2obgWiguWibWQ==} + '@rollup/rollup-linux-arm-musleabihf@4.60.1': + resolution: {integrity: sha512-n83O8rt4v34hgFzlkb1ycniJh7IR5RCIqt6mz1VRJD6pmhRi0CXdmfnLu9dIUS6buzh60IvACM842Ffb3xd6Gg==} cpu: [arm] os: [linux] libc: [musl] - '@rollup/rollup-linux-arm64-gnu@4.60.0': - resolution: {integrity: sha512-DX2x7CMcrJzsE91q7/O02IJQ5/aLkVtYFryqCjduJhUfGKG6yJV8hxaw8pZa93lLEpPTP/ohdN4wFz7yp/ry9A==} + '@rollup/rollup-linux-arm64-gnu@4.60.1': + resolution: {integrity: sha512-Nql7sTeAzhTAja3QXeAI48+/+GjBJ+QmAH13snn0AJSNL50JsDqotyudHyMbO2RbJkskbMbFJfIJKWA6R1LCJQ==} cpu: [arm64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-arm64-musl@4.60.0': - resolution: {integrity: sha512-09EL+yFVbJZlhcQfShpswwRZ0Rg+z/CsSELFCnPt3iK+iqwGsI4zht3secj5vLEs957QvFFXnzAT0FFPIxSrkQ==} + '@rollup/rollup-linux-arm64-musl@4.60.1': + resolution: {integrity: sha512-+pUymDhd0ys9GcKZPPWlFiZ67sTWV5UU6zOJat02M1+PiuSGDziyRuI/pPue3hoUwm2uGfxdL+trT6Z9rxnlMA==} cpu: [arm64] os: [linux] libc: [musl] - '@rollup/rollup-linux-loong64-gnu@4.60.0': - resolution: {integrity: sha512-i9IcCMPr3EXm8EQg5jnja0Zyc1iFxJjZWlb4wr7U2Wx/GrddOuEafxRdMPRYVaXjgbhvqalp6np07hN1w9kAKw==} + '@rollup/rollup-linux-loong64-gnu@4.60.1': + resolution: {integrity: sha512-VSvgvQeIcsEvY4bKDHEDWcpW4Yw7BtlKG1GUT4FzBUlEKQK0rWHYBqQt6Fm2taXS+1bXvJT6kICu5ZwqKCnvlQ==} cpu: [loong64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-loong64-musl@4.60.0': - resolution: {integrity: sha512-DGzdJK9kyJ+B78MCkWeGnpXJ91tK/iKA6HwHxF4TAlPIY7GXEvMe8hBFRgdrR9Ly4qebR/7gfUs9y2IoaVEyog==} + '@rollup/rollup-linux-loong64-musl@4.60.1': + resolution: {integrity: sha512-4LqhUomJqwe641gsPp6xLfhqWMbQV04KtPp7/dIp0nzPxAkNY1AbwL5W0MQpcalLYk07vaW9Kp1PBhdpZYYcEw==} cpu: [loong64] os: [linux] libc: [musl] - '@rollup/rollup-linux-ppc64-gnu@4.60.0': - resolution: {integrity: sha512-RwpnLsqC8qbS8z1H1AxBA1H6qknR4YpPR9w2XX0vo2Sz10miu57PkNcnHVaZkbqyw/kUWfKMI73jhmfi9BRMUQ==} + '@rollup/rollup-linux-ppc64-gnu@4.60.1': + resolution: {integrity: sha512-tLQQ9aPvkBxOc/EUT6j3pyeMD6Hb8QF2BTBnCQWP/uu1lhc9AIrIjKnLYMEroIz/JvtGYgI9dF3AxHZNaEH0rw==} cpu: [ppc64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-ppc64-musl@4.60.0': - resolution: {integrity: sha512-Z8pPf54Ly3aqtdWC3G4rFigZgNvd+qJlOE52fmko3KST9SoGfAdSRCwyoyG05q1HrrAblLbk1/PSIV+80/pxLg==} + '@rollup/rollup-linux-ppc64-musl@4.60.1': + resolution: {integrity: sha512-RMxFhJwc9fSXP6PqmAz4cbv3kAyvD1etJFjTx4ONqFP9DkTkXsAMU4v3Vyc5BgzC+anz7nS/9tp4obsKfqkDHg==} cpu: [ppc64] os: [linux] libc: [musl] - '@rollup/rollup-linux-riscv64-gnu@4.60.0': - resolution: {integrity: sha512-3a3qQustp3COCGvnP4SvrMHnPQ9d1vzCakQVRTliaz8cIp/wULGjiGpbcqrkv0WrHTEp8bQD/B3HBjzujVWLOA==} + '@rollup/rollup-linux-riscv64-gnu@4.60.1': + resolution: {integrity: sha512-QKgFl+Yc1eEk6MmOBfRHYF6lTxiiiV3/z/BRrbSiW2I7AFTXoBFvdMEyglohPj//2mZS4hDOqeB0H1ACh3sBbg==} cpu: [riscv64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-riscv64-musl@4.60.0': - resolution: {integrity: sha512-pjZDsVH/1VsghMJ2/kAaxt6dL0psT6ZexQVrijczOf+PeP2BUqTHYejk3l6TlPRydggINOeNRhvpLa0AYpCWSQ==} + '@rollup/rollup-linux-riscv64-musl@4.60.1': + resolution: {integrity: sha512-RAjXjP/8c6ZtzatZcA1RaQr6O1TRhzC+adn8YZDnChliZHviqIjmvFwHcxi4JKPSDAt6Uhf/7vqcBzQJy0PDJg==} cpu: [riscv64] os: [linux] libc: [musl] - '@rollup/rollup-linux-s390x-gnu@4.60.0': - resolution: {integrity: sha512-3ObQs0BhvPgiUVZrN7gqCSvmFuMWvWvsjG5ayJ3Lraqv+2KhOsp+pUbigqbeWqueGIsnn+09HBw27rJ+gYK4VQ==} + '@rollup/rollup-linux-s390x-gnu@4.60.1': + resolution: {integrity: sha512-wcuocpaOlaL1COBYiA89O6yfjlp3RwKDeTIA0hM7OpmhR1Bjo9j31G1uQVpDlTvwxGn2nQs65fBFL5UFd76FcQ==} cpu: [s390x] os: [linux] libc: [glibc] - '@rollup/rollup-linux-x64-gnu@4.60.0': - resolution: {integrity: sha512-EtylprDtQPdS5rXvAayrNDYoJhIz1/vzN2fEubo3yLE7tfAw+948dO0g4M0vkTVFhKojnF+n6C8bDNe+gDRdTg==} + '@rollup/rollup-linux-x64-gnu@4.60.1': + resolution: {integrity: sha512-77PpsFQUCOiZR9+LQEFg9GClyfkNXj1MP6wRnzYs0EeWbPcHs02AXu4xuUbM1zhwn3wqaizle3AEYg5aeoohhg==} cpu: [x64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-x64-musl@4.60.0': - resolution: {integrity: sha512-k09oiRCi/bHU9UVFqD17r3eJR9bn03TyKraCrlz5ULFJGdJGi7VOmm9jl44vOJvRJ6P7WuBi/s2A97LxxHGIdw==} + '@rollup/rollup-linux-x64-musl@4.60.1': + resolution: {integrity: sha512-5cIATbk5vynAjqqmyBjlciMJl1+R/CwX9oLk/EyiFXDWd95KpHdrOJT//rnUl4cUcskrd0jCCw3wpZnhIHdD9w==} cpu: [x64] os: [linux] libc: [musl] - '@rollup/rollup-openbsd-x64@4.60.0': - resolution: {integrity: sha512-1o/0/pIhozoSaDJoDcec+IVLbnRtQmHwPV730+AOD29lHEEo4F5BEUB24H0OBdhbBBDwIOSuf7vgg0Ywxdfiiw==} + '@rollup/rollup-openbsd-x64@4.60.1': + resolution: {integrity: sha512-cl0w09WsCi17mcmWqqglez9Gk8isgeWvoUZ3WiJFYSR3zjBQc2J5/ihSjpl+VLjPqjQ/1hJRcqBfLjssREQILw==} cpu: [x64] os: [openbsd] - '@rollup/rollup-openharmony-arm64@4.60.0': - resolution: {integrity: sha512-pESDkos/PDzYwtyzB5p/UoNU/8fJo68vcXM9ZW2V0kjYayj1KaaUfi1NmTUTUpMn4UhU4gTuK8gIaFO4UGuMbA==} + '@rollup/rollup-openharmony-arm64@4.60.1': + resolution: {integrity: sha512-4Cv23ZrONRbNtbZa37mLSueXUCtN7MXccChtKpUnQNgF010rjrjfHx3QxkS2PI7LqGT5xXyYs1a7LbzAwT0iCA==} cpu: [arm64] os: [openharmony] - '@rollup/rollup-win32-arm64-msvc@4.60.0': - resolution: {integrity: sha512-hj1wFStD7B1YBeYmvY+lWXZ7ey73YGPcViMShYikqKT1GtstIKQAtfUI6yrzPjAy/O7pO0VLXGmUVWXQMaYgTQ==} + '@rollup/rollup-win32-arm64-msvc@4.60.1': + resolution: {integrity: sha512-i1okWYkA4FJICtr7KpYzFpRTHgy5jdDbZiWfvny21iIKky5YExiDXP+zbXzm3dUcFpkEeYNHgQ5fuG236JPq0g==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.60.0': - resolution: {integrity: sha512-SyaIPFoxmUPlNDq5EHkTbiKzmSEmq/gOYFI/3HHJ8iS/v1mbugVa7dXUzcJGQfoytp9DJFLhHH4U3/eTy2Bq4w==} + '@rollup/rollup-win32-ia32-msvc@4.60.1': + resolution: {integrity: sha512-u09m3CuwLzShA0EYKMNiFgcjjzwqtUMLmuCJLeZWjjOYA3IT2Di09KaxGBTP9xVztWyIWjVdsB2E9goMjZvTQg==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-gnu@4.60.0': - resolution: {integrity: sha512-RdcryEfzZr+lAr5kRm2ucN9aVlCCa2QNq4hXelZxb8GG0NJSazq44Z3PCCc8wISRuCVnGs0lQJVX5Vp6fKA+IA==} + '@rollup/rollup-win32-x64-gnu@4.60.1': + resolution: {integrity: sha512-k+600V9Zl1CM7eZxJgMyTUzmrmhB/0XZnF4pRypKAlAgxmedUA+1v9R+XOFv56W4SlHEzfeMtzujLJD22Uz5zg==} cpu: [x64] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.60.0': - resolution: {integrity: sha512-PrsWNQ8BuE00O3Xsx3ALh2Df8fAj9+cvvX9AIA6o4KpATR98c9mud4XtDWVvsEuyia5U4tVSTKygawyJkjm60w==} + '@rollup/rollup-win32-x64-msvc@4.60.1': + resolution: {integrity: sha512-lWMnixq/QzxyhTV6NjQJ4SFo1J6PvOX8vUx5Wb4bBPsEb+8xZ89Bz6kOXpfXj9ak9AHTQVQzlgzBEc1SyM27xQ==} cpu: [x64] os: [win32] @@ -3283,7 +3285,7 @@ packages: hasBin: true peerDependencies: expo: '>=49.0.0' - react: '>=17.0.0' + react: ^19.2.5 react-native: '>=0.65.0' peerDependenciesMeta: expo: @@ -3293,13 +3295,13 @@ packages: resolution: {integrity: sha512-XLnXJOHgsCeVAVBbO+9AuGlZWnCxLQHLOmKxpIr8wjE3g7dHibtug6cv8JLx78O4dd7aoCqv2TTyyKY9FLJ2EQ==} engines: {node: '>=18'} peerDependencies: - react: ^16.14.0 || 17.x || 18.x || 19.x + react: ^19.2.5 '@sentry/react@10.48.0': resolution: {integrity: sha512-uc93vKjmu6gNns+JAX4qquuxWpAMit0uGPA1TYlMjct9NG1uX3TkDPJAr9Pgd1lOXx8mKqCmj5fK33QeExMpPw==} engines: {node: '>=18'} peerDependencies: - react: ^16.14.0 || 17.x || 18.x || 19.x + react: ^19.2.5 '@sentry/rollup-plugin@5.2.0': resolution: {integrity: sha512-a8LfpvcYMFtFSroro5MpCcOoS528LeLfUHzxWURnpofOnY+Aso9Si4y4dFlna+RKqxCXjmFbn6CLnfI+YrHysQ==} @@ -3451,7 +3453,7 @@ packages: engines: {node: '>=18'} peerDependencies: jest: '>=29.0.0' - react: '>=18.2.0' + react: ^19.2.5 react-native: '>=0.71' react-test-renderer: '>=18.2.0' peerDependenciesMeta: @@ -3465,8 +3467,8 @@ packages: '@testing-library/dom': ^10.0.0 '@types/react': ^18.0.0 || ^19.0.0 '@types/react-dom': ^18.0.0 || ^19.0.0 - react: ^18.0.0 || ^19.0.0 - react-dom: ^18.0.0 || ^19.0.0 + react: ^19.2.5 + react-dom: ^19.2.5 peerDependenciesMeta: '@types/react': optional: true @@ -3477,18 +3479,6 @@ packages: resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==} engines: {node: '>= 10'} - '@tsconfig/node10@1.0.12': - resolution: {integrity: sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==} - - '@tsconfig/node12@1.0.11': - resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==} - - '@tsconfig/node14@1.0.3': - resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==} - - '@tsconfig/node16@1.0.4': - resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} - '@turbo/darwin-64@2.9.6': resolution: {integrity: sha512-X/56SnVXIQZBLKwniGTwEQTGmtE5brSACnKMBWpY3YafuxVYefrC2acamfjgxP7BG5w3I+6jf0UrLoSzgPcSJg==} cpu: [x64] @@ -3639,8 +3629,8 @@ packages: '@types/node@22.19.17': resolution: {integrity: sha512-wGdMcf+vPYM6jikpS/qhg6WiqSV/OhG+jeeHT/KlVqxYfD40iYJf9/AE1uQxVWFvU7MipKRkRv8NSHiCGgPr8Q==} - '@types/node@25.5.2': - resolution: {integrity: sha512-tO4ZIRKNC+MDWV4qKVZe3Ql/woTnmHDr5JD8UI5hn2pwBrHEwOEMZK7WlNb5RKB6EoJ02gwmQS9OrjuFnZYdpg==} + '@types/node@25.6.0': + resolution: {integrity: sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==} '@types/nodemailer@8.0.0': resolution: {integrity: sha512-fyf8jWULsCo0d0BuoQ75i6IeoHs47qcqxWc7yUdUcV0pOZGjUTTOvwdG1PRXUDqN/8A64yQdQdnA2pZgcdi+cA==} @@ -3680,63 +3670,63 @@ packages: '@types/yargs@17.0.35': resolution: {integrity: sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==} - '@typescript-eslint/eslint-plugin@8.58.1': - resolution: {integrity: sha512-eSkwoemjo76bdXl2MYqtxg51HNwUSkWfODUOQ3PaTLZGh9uIWWFZIjyjaJnex7wXDu+TRx+ATsnSxdN9YWfRTQ==} + '@typescript-eslint/eslint-plugin@8.58.2': + resolution: {integrity: sha512-aC2qc5thQahutKjP+cl8cgN9DWe3ZUqVko30CMSZHnFEHyhOYoZSzkGtAI2mcwZ38xeImDucI4dnqsHiOYuuCw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^8.58.1 + '@typescript-eslint/parser': ^8.58.2 eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/parser@8.58.1': - resolution: {integrity: sha512-gGkiNMPqerb2cJSVcruigx9eHBlLG14fSdPdqMoOcBfh+vvn4iCq2C8MzUB89PrxOXk0y3GZ1yIWb9aOzL93bw==} + '@typescript-eslint/parser@8.58.2': + resolution: {integrity: sha512-/Zb/xaIDfxeJnvishjGdcR4jmr7S+bda8PKNhRGdljDM+elXhlvN0FyPSsMnLmJUrVG9aPO6dof80wjMawsASg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/project-service@8.58.1': - resolution: {integrity: sha512-gfQ8fk6cxhtptek+/8ZIqw8YrRW5048Gug8Ts5IYcMLCw18iUgrZAEY/D7s4hkI0FxEfGakKuPK/XUMPzPxi5g==} + '@typescript-eslint/project-service@8.58.2': + resolution: {integrity: sha512-Cq6UfpZZk15+r87BkIh5rDpi38W4b+Sjnb8wQCPPDDweS/LRCFjCyViEbzHk5Ck3f2QDfgmlxqSa7S7clDtlfg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/scope-manager@8.58.1': - resolution: {integrity: sha512-TPYUEqJK6avLcEjumWsIuTpuYODTTDAtoMdt8ZZa93uWMTX13Nb8L5leSje1NluammvU+oI3QRr5lLXPgihX3w==} + '@typescript-eslint/scope-manager@8.58.2': + resolution: {integrity: sha512-SgmyvDPexWETQek+qzZnrG6844IaO02UVyOLhI4wpo82dpZJY9+6YZCKAMFzXb7qhx37mFK1QcPQ18tud+vo6Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/tsconfig-utils@8.58.1': - resolution: {integrity: sha512-JAr2hOIct2Q+qk3G+8YFfqkqi7sC86uNryT+2i5HzMa2MPjw4qNFvtjnw1IiA1rP7QhNKVe21mSSLaSjwA1Olw==} + '@typescript-eslint/tsconfig-utils@8.58.2': + resolution: {integrity: sha512-3SR+RukipDvkkKp/d0jP0dyzuls3DbGmwDpVEc5wqk5f38KFThakqAAO0XMirWAE+kT00oTauTbzMFGPoAzB0A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/type-utils@8.58.1': - resolution: {integrity: sha512-HUFxvTJVroT+0rXVJC7eD5zol6ID+Sn5npVPWoFuHGg9Ncq5Q4EYstqR+UOqaNRFXi5TYkpXXkLhoCHe3G0+7w==} + '@typescript-eslint/type-utils@8.58.2': + resolution: {integrity: sha512-Z7EloNR/B389FvabdGeTo2XMs4W9TjtPiO9DAsmT0yom0bwlPyRjkJ1uCdW1DvrrrYP50AJZ9Xc3sByZA9+dcg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/types@8.58.1': - resolution: {integrity: sha512-io/dV5Aw5ezwzfPBBWLoT+5QfVtP8O7q4Kftjn5azJ88bYyp/ZMCsyW1lpKK46EXJcaYMZ1JtYj+s/7TdzmQMw==} + '@typescript-eslint/types@8.58.2': + resolution: {integrity: sha512-9TukXyATBQf/Jq9AMQXfvurk+G5R2MwfqQGDR2GzGz28HvY/lXNKGhkY+6IOubwcquikWk5cjlgPvD2uAA7htQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@8.58.1': - resolution: {integrity: sha512-w4w7WR7GHOjqqPnvAYbazq+Y5oS68b9CzasGtnd6jIeOIeKUzYzupGTB2T4LTPSv4d+WPeccbxuneTFHYgAAWg==} + '@typescript-eslint/typescript-estree@8.58.2': + resolution: {integrity: sha512-ELGuoofuhhoCvNbQjFFiobFcGgcDCEm0ThWdmO4Z0UzLqPXS3KFvnEZ+SHewwOYHjM09tkzOWXNTv9u6Gqtyuw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/utils@8.58.1': - resolution: {integrity: sha512-Ln8R0tmWC7pTtLOzgJzYTXSCjJ9rDNHAqTaVONF4FEi2qwce8mD9iSOxOpLFFvWp/wBFlew0mjM1L1ihYWfBdQ==} + '@typescript-eslint/utils@8.58.2': + resolution: {integrity: sha512-QZfjHNEzPY8+l0+fIXMvuQ2sJlplB4zgDZvA+NmvZsZv3EQwOcc1DuIU1VJUTWZ/RKouBMhDyNaBMx4sWvrzRA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/visitor-keys@8.58.1': - resolution: {integrity: sha512-y+vH7QE8ycjoa0bWciFg7OpFcipUuem1ujhrdLtq1gByKwfbC7bPeKsiny9e0urg93DqwGcHey+bGRKCnF1nZQ==} + '@typescript-eslint/visitor-keys@8.58.2': + resolution: {integrity: sha512-f1WO2Lx8a9t8DARmcWAUPJbu0G20bJlj8L4z72K00TMeJAoyLr/tHhI/pzYBLrR4dXWkcxO1cWYZEOX8DKHTqA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@ungap/structured-clone@1.3.0': @@ -3869,9 +3859,6 @@ packages: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} - arg@4.1.3: - resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} - arg@5.0.2: resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} @@ -4005,8 +3992,8 @@ packages: base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - baseline-browser-mapping@2.10.12: - resolution: {integrity: sha512-qyq26DxfY4awP2gIRXhhLWfwzwI+N5Nxk6iQi8EFizIaWIjqicQTE4sLnZZVdeKPRcVNoJOkkpfzoIYuvCKaIQ==} + baseline-browser-mapping@2.10.19: + resolution: {integrity: sha512-qCkNLi2sfBOn8XhZQ0FXsT1Ki/Yo5P90hrkRamVFRS7/KV9hpfA4HkoWNU152+8w0zPjnxo5psx5NL3PSGgv5g==} engines: {node: '>=6.0.0'} hasBin: true @@ -4060,8 +4047,8 @@ packages: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} - browserslist@4.28.1: - resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==} + browserslist@4.28.2: + resolution: {integrity: sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true @@ -4102,8 +4089,8 @@ packages: resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} engines: {node: '>=10'} - caniuse-lite@1.0.30001781: - resolution: {integrity: sha512-RdwNCyMsNBftLjW6w01z8bKEvT6e/5tpPVEgtn22TiLGlstHOVecsX2KHFkD5e/vRnIE4EGzpuIODb3mtswtkw==} + caniuse-lite@1.0.30001788: + resolution: {integrity: sha512-6q8HFp+lOQtcf7wBK+uEenxymVWkGKkjFpCvw5W25cmMwEDU45p1xQFBQv8JDlMMry7eNxyBaR+qxgmTUZkIRQ==} chai@6.2.2: resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} @@ -4269,9 +4256,6 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true - create-require@1.1.1: - resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} - crelt@1.0.6: resolution: {integrity: sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==} @@ -4410,10 +4394,6 @@ packages: resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - diff@4.0.4: - resolution: {integrity: sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==} - engines: {node: '>=0.3.1'} - dnssd-advertise@1.1.4: resolution: {integrity: sha512-AmGyK9WpNf06WeP5TjHZq/wNzP76OuEeaiTlKr9E/EEelYLczywUKoqRz+DPRq/ErssjT4lU+/W7wzJW+7K/ZA==} @@ -4551,8 +4531,8 @@ packages: ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} - electron-to-chromium@1.5.328: - resolution: {integrity: sha512-QNQ5l45DzYytThO21403XN3FvK0hOkWDG8viNf6jqS42msJ8I4tGDSpBCgvDRRPnkffafiwAym2X2eHeGD2V0w==} + electron-to-chromium@1.5.336: + resolution: {integrity: sha512-AbH9q9J455r/nLmdNZes0G0ZKcRX73FicwowalLs6ijwOmCJSRRrLX63lcAlzy9ux3dWK1w1+1nsBJEWN11hcQ==} emittery@0.13.1: resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==} @@ -4626,8 +4606,8 @@ packages: engines: {node: '>=18'} hasBin: true - esbuild@0.27.4: - resolution: {integrity: sha512-Rq4vbHnYkK5fws5NF7MYTU68FPRE1ajX7heQ/8QXXWqNgqqJ/GkmmyxIzUnf2Sr/bakf8l54716CcMGHYhMrrQ==} + esbuild@0.27.7: + resolution: {integrity: sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==} engines: {node: '>=18'} hasBin: true @@ -4748,7 +4728,7 @@ packages: resolution: {integrity: sha512-d3FIpHJ6ZngYXxRItYWBGT5H8Wkk7/l4fMe8Mmd2xDyKrO0/CM7c8r/J5M71D+BJr5P3My8wertGYZXHSiZYxQ==} peerDependencies: expo: '*' - react: '*' + react: ^19.2.5 react-native: '*' expo-constants@55.0.14: @@ -4797,21 +4777,21 @@ packages: resolution: {integrity: sha512-x9czUA3UQWjIwa0ZUEs/eWJNqB4mAue/m4ltESlNPLZhHL0nWWqIfsyHmklTLFH7mVfcHSJvew6k+pR2FE1zVw==} peerDependencies: expo: '*' - react: '*' + react: ^19.2.5 react-native: '*' expo-glass-effect@55.0.10: resolution: {integrity: sha512-5kL/jATvgJWdrqPdxixrECJqD2l8cfQ4ALr1DK7qi9XkyI97ejXvUjB2VsfEePNy3Fg+/VwzA3n3L7Nv3tAPkw==} peerDependencies: expo: '*' - react: '*' + react: ^19.2.5 react-native: '*' expo-image@55.0.8: resolution: {integrity: sha512-fNdvdYVcGn3g1x6o5AXHKzk4xX8U6rg2W9vFdE1pQO80kWCNReh003ypqSrGy4dD+zA8FtZjrNF3oMDGnPpIGQ==} peerDependencies: expo: '*' - react: '*' + react: ^19.2.5 react-native: '*' react-native-web: '*' peerDependenciesMeta: @@ -4825,19 +4805,19 @@ packages: resolution: {integrity: sha512-acJjeHqkNxMVckEcJhGQeIksqqsarscSHJtT559bNgyiM4r14dViQ66su7bb6qDVeBt0K7z3glXI1dHVck1Zgg==} peerDependencies: expo: '*' - react: '*' + react: ^19.2.5 expo-linking@55.0.13: resolution: {integrity: sha512-xbOqNWQCC5RGtXSW83ZCKOjRivyxO2zBouRYy/hgbsyrHUJhztMAjlq8RKYDUL8D6QVsH9Q81SNoq4Zhcn+4HQ==} peerDependencies: - react: '*' + react: ^19.2.5 react-native: '*' expo-localization@55.0.13: resolution: {integrity: sha512-fXiEUUihIrXmAEzoneaTOFcQ7TKmr25RR/ymrB/MvYTVnmevFA1zY2KI0VSiXY+NKKjZ8mG65YSn1wh4gEYKxA==} peerDependencies: expo: '*' - react: '*' + react: ^19.2.5 expo-location@55.1.8: resolution: {integrity: sha512-mEExFf84nmWLwi14GFfUsFLrCm10gbcqFn9EPXpuruQ28YMtJWgCD+jJtESYPQkYF44N21fVok3T28fLuCqydA==} @@ -4856,7 +4836,7 @@ packages: expo-modules-core@55.0.22: resolution: {integrity: sha512-NC5GyvCHvnOvi5MtgLv68oUSrRP/0UORGzU/MX+7BIA8ctgBPxKSjPXPSfhwk3gMzj7eHBhYwlu0HJsIEnVd9A==} peerDependencies: - react: '*' + react: ^19.2.5 react-native: '*' react-native-worklets: ^0.7.4 || ^0.8.0 peerDependenciesMeta: @@ -4867,14 +4847,14 @@ packages: resolution: {integrity: sha512-G7olnyAqGd7I3hLFAgP4WdcZFMD9pV6UY79P7EHyRdMuRZrYJfDdwcelyYB2+tekOdQEktZ3WlLVK+uS7f7TYw==} peerDependencies: expo: '*' - react: '*' + react: ^19.2.5 react-native: '*' expo-notifications@55.0.19: resolution: {integrity: sha512-t1DPN9xwSh5kN5T8k0lER/NbcuhMIxj/ukfDWzFOJb2WdfB+VBWaiBUj4K26agsX7tQFMz2wsCXpkYXLdfzSdw==} peerDependencies: expo: '*' - react: '*' + react: ^19.2.5 react-native: '*' expo-router@55.0.12: @@ -4887,8 +4867,8 @@ packages: expo: '*' expo-constants: ^55.0.13 expo-linking: ^55.0.12 - react: '*' - react-dom: '*' + react: ^19.2.5 + react-dom: ^19.2.5 react-native: '*' react-native-gesture-handler: '*' react-native-reanimated: '*' @@ -4930,13 +4910,13 @@ packages: resolution: {integrity: sha512-vxE5fs6l953QSIyievQ8TuSstj62eC7zUREjNzbUOwRWaHGGnhnlPJM1HLoTIv+oIt3+b1m7k2fmcDGkpK5t3w==} peerDependencies: expo: '*' - react: '*' + react: ^19.2.5 react-native: '*' expo-status-bar@55.0.5: resolution: {integrity: sha512-qb0c3rJO2b7CC0gUVGi1JYp92oLenWdYGyk8l4YQs6U+uaXUTPv6aaFa3KkT2HON10re3AxxPNJci8rsz6kPxg==} peerDependencies: - react: '*' + react: ^19.2.5 react-native: '*' expo-symbols@55.0.7: @@ -4944,7 +4924,7 @@ packages: peerDependencies: expo: '*' expo-font: '*' - react: '*' + react: ^19.2.5 react-native: '*' expo-system-ui@55.0.15: @@ -4974,7 +4954,7 @@ packages: peerDependencies: '@expo/dom-webview': '*' '@expo/metro-runtime': '*' - react: '*' + react: ^19.2.5 react-native: '*' react-native-webview: '*' peerDependenciesMeta: @@ -4995,8 +4975,8 @@ packages: exsolve@1.0.8: resolution: {integrity: sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==} - fast-copy@4.0.2: - resolution: {integrity: sha512-ybA6PDXIXOXivLJK/z9e+Otk7ve13I4ckBvGO5I2RRmBU1gMHLVDJYEuJYhGwez7YNlYji2M2DvVU+a9mSFDlw==} + fast-copy@4.0.3: + resolution: {integrity: sha512-58apWr0GUiDFM8+3afrO6eYwJBn9ZAhDOzG3L+/9llab/haCARS2UIfffmOurYLwbgDRs8n0rfr6qAAPEAuAQw==} fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} @@ -5137,8 +5117,8 @@ packages: resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} engines: {node: '>=10'} - get-tsconfig@4.13.7: - resolution: {integrity: sha512-7tN6rFgBlMgpBML5j8typ92BKFi2sFQvIdpAqLA2beia5avZDrMs0FLZiM5etShWq5irVyGcGMEA1jcDaK7A/Q==} + get-tsconfig@4.13.8: + resolution: {integrity: sha512-J87BxkLXykmisLQ+KA4x2+O6rVf+PJrtFUO8lGyiRg4lyxJLJ8/v0sRAKdVZQOy6tR6lMRAF1NqzCf9BQijm0w==} getenv@2.0.0: resolution: {integrity: sha512-VilgtJj/ALgGY77fiLam5iD336eSWi96Q15JSAG1zi8NRBysm3LXKdGnHb4m5cuyxvOLQQKWpBZAT6ni4FI2iQ==} @@ -5298,8 +5278,8 @@ packages: import-in-the-middle@2.0.6: resolution: {integrity: sha512-3vZV3jX0XRFW3EJDTwzWoZa+RH1b8eTTx6YOCjglrLyPuepwoBti1k3L2dKwdCUrnVEfc5CuRuGstaC/uQJJaw==} - import-in-the-middle@3.0.0: - resolution: {integrity: sha512-OnGy+eYT7wVejH2XWgLRgbmzujhhVIATQH0ztIeRilwHBjTeG3pD+XnH3PKX0r9gJ0BuJmJ68q/oh9qgXnNDQg==} + import-in-the-middle@3.0.1: + resolution: {integrity: sha512-pYkiyXVL2Mf3pozdlDGV6NAObxQx13Ae8knZk1UJRJ6uRW/ZRmTGHlQYtrsSl7ubuE5F8CD1z+s1n4RHNuTtuA==} engines: {node: '>=18'} import-local@3.2.0: @@ -5375,8 +5355,8 @@ packages: resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} engines: {node: '>=8'} - isbot@5.1.37: - resolution: {integrity: sha512-5bcicX81xf6NlTEV8rWdg7Pk01LFizDetuYGHx6d/f6y3lR2/oo8IfxjzJqn1UdDEyCcwT9e7NRloj8DwCYujQ==} + isbot@5.1.38: + resolution: {integrity: sha512-Cus2702JamTNMEY4zTP+TShgq/3qzjvGcBC4XMOV45BLaxD4iUFENkqu7ZhFeSzwNsCSZLjnGlihDQznnpnEEA==} engines: {node: '>=18'} isexe@2.0.0: @@ -5468,8 +5448,8 @@ packages: resolution: {integrity: sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - jest-expo@55.0.15: - resolution: {integrity: sha512-WJHKiEftvn14a+UbiWTFYBuuvaDEYbhGYWa0ycfLlweZrLbb3gWIwa2MqmLDlroA4/8YxRaLIDMkRDMnjplPlQ==} + jest-expo@55.0.16: + resolution: {integrity: sha512-bOvrTNyDaiaoTz9GhvnXib9v9rjX9PTJFvvoqRMRKEg4MoHghG82E7YF+pH71EWSXTaibQ07F46GS+fcUxTWEg==} hasBin: true peerDependencies: expo: '*' @@ -5797,8 +5777,8 @@ packages: lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} - lru-cache@11.2.7: - resolution: {integrity: sha512-aY/R+aEsRelme17KGQa/1ZSIpLpNYYrhcrepKTZgE+W3WM16YMCaPwOHLHsmopZHELU0Ojin1lPVxKR0MihncA==} + lru-cache@11.3.5: + resolution: {integrity: sha512-NxVFwLAnrd9i7KUBxC4DrUhmgjzOs+1Qm50D3oF1/oL+r1NpZ4gA7xvG0/zJ8evR7zIKn4vLf7qTNduWFtCrRw==} engines: {node: 20 || >=22} lru-cache@5.1.1: @@ -5819,9 +5799,6 @@ packages: resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} engines: {node: '>=10'} - make-error@1.3.6: - resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} - makeerror@1.0.12: resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} @@ -5856,6 +5833,10 @@ packages: resolution: {integrity: sha512-d9FfmgUEVejTiSb7bkQeLRGl6aeno2UpuPm3bo3rCYwxewj03ymvOn8s8vnS4fBqAPQ+cE9iQM40wh7nGXR+eA==} engines: {node: '>=20.19.4'} + metro-babel-transformer@0.83.6: + resolution: {integrity: sha512-1AnuazBpzY3meRMr04WUw14kRBkV0W3Ez+AA75FAeNpRyWNN5S3M3PHLUbZw7IXq7ZeOzceyRsHStaFrnWd+8w==} + engines: {node: '>=20.19.4'} + metro-babel-transformer@0.84.3: resolution: {integrity: sha512-svAA+yMLpeMiGcz/jKJs4oHpIGEx4nBqNEJ5AGj4CYIg1efvK+A0TjR6tgIuc6tKO5e8JmN/1lglpN2+f3/z/w==} engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} @@ -5864,6 +5845,10 @@ packages: resolution: {integrity: sha512-Ycl8PBajB7bhbAI7Rt0xEyiF8oJ0RWX8EKkolV1KfCUlC++V/GStMSGpPLwnnBZXZWkCC5edBPzv1Hz1Yi0Euw==} engines: {node: '>=20.19.4'} + metro-cache-key@0.83.6: + resolution: {integrity: sha512-5gdK4PVpgNOHi7xCGrgesNP1AuOA2TiPqpcirGXZi4RLLzX1VMowpkgTVtBfpQQCqWoosQF9yrSo9/KDQg1eBg==} + engines: {node: '>=20.19.4'} + metro-cache-key@0.84.3: resolution: {integrity: sha512-TnSL1Fdvrw+2glTdBSRmA5TL8l/i16ECjsrUdf3E5HncA+sNx8KcwDG8r+3ct1UhfYcusJypzZqTN55FZZcwGg==} engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} @@ -5872,6 +5857,10 @@ packages: resolution: {integrity: sha512-oH+s4U+IfZyg8J42bne2Skc90rcuESIYf86dYittcdWQtPfcaFXWpByPyTuWk3rR1Zz3Eh5HOrcVImfEhhJLng==} engines: {node: '>=20.19.4'} + metro-cache@0.83.6: + resolution: {integrity: sha512-DpvZE32feNkqfZkI4Fic7YI/Kw8QP9wdl1rC4YKPrA77wQbI9vXbxjmfkCT/EGwBTFOPKqvIXo+H3BNe93YyiQ==} + engines: {node: '>=20.19.4'} + metro-cache@0.84.3: resolution: {integrity: sha512-0QElxwLaHqLZf+Xqio8QrjVbuXP/8sJfQBGSPiITlKDVXrVLefuzYVSH9Sj+QL6lrPj2gYZd/iwQh1yZuVKnLA==} engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} @@ -5880,6 +5869,10 @@ packages: resolution: {integrity: sha512-JQ/PAASXH7yczgV6OCUSRhZYME+NU8NYjI2RcaG5ga4QfQ3T/XdiLzpSb3awWZYlDCcQb36l4Vl7i0Zw7/Tf9w==} engines: {node: '>=20.19.4'} + metro-config@0.83.6: + resolution: {integrity: sha512-G5622400uNtnAMlppEA5zkFAZltEf7DSGhOu09BkisCxOlVMWfdosD/oPyh4f2YVQsc1MBYyp4w6OzbExTYarg==} + engines: {node: '>=20.19.4'} + metro-config@0.84.3: resolution: {integrity: sha512-JmCzZWOETR+O22q8oPBWyQppx3roU9EbkbGzD8Gf1jukQ4b5T1fTzqqHruu6K4sTiNq5zVQySmKF6bp4kVARew==} engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} @@ -5888,6 +5881,10 @@ packages: resolution: {integrity: sha512-YcVcLCrf0ed4mdLa82Qob0VxYqfhmlRxUS8+TO4gosZo/gLwSvtdeOjc/Vt0pe/lvMNrBap9LlmvZM8FIsMgJQ==} engines: {node: '>=20.19.4'} + metro-core@0.83.6: + resolution: {integrity: sha512-l+yQ2fuIgR//wszUlMrrAa9+Z+kbKazd0QOh0VQY7jC4ghb7yZBBSla/UMYRBZZ6fPg9IM+wD3+h+37a5f9etw==} + engines: {node: '>=20.19.4'} + metro-core@0.84.3: resolution: {integrity: sha512-cc0pvAa80ai1nDmqqz0P59a+0ZqCZ/YHU/3jEekZL6spFnYDfX8iDLdn9FR6kX+67rmzKxHNrbrSRFLX2AYocw==} engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} @@ -5896,6 +5893,10 @@ packages: resolution: {integrity: sha512-ZEt8s3a1cnYbn40nyCD+CsZdYSlwtFh2kFym4lo+uvfM+UMMH+r/BsrC6rbNClSrt+B7rU9T+Te/sh/NL8ZZKQ==} engines: {node: '>=20.19.4'} + metro-file-map@0.83.6: + resolution: {integrity: sha512-Jg3oN604C7GWbQwFAUXt8KsbMXeKfsxbZ5HFy4XFM3ggTS+ja9QgUmq9B613kgXv3G4M6rwiI6cvh9TRly4x3w==} + engines: {node: '>=20.19.4'} + metro-file-map@0.84.3: resolution: {integrity: sha512-1cL4m4Jv1yRUt9RJExZQLfccscdlMNOcRG6LHLtmJhf3BG9j3MujPVc7CIpKYdFl+KUl+sdjge6oO3+meKCHQA==} engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} @@ -5904,6 +5905,10 @@ packages: resolution: {integrity: sha512-Toe4Md1wS1PBqbvB0cFxBzKEVyyuYTUb0sgifAZh/mSvLH84qA1NAWik9sISWatzvfWf3rOGoUoO5E3f193a3Q==} engines: {node: '>=20.19.4'} + metro-minify-terser@0.83.6: + resolution: {integrity: sha512-Vx3/Ne9Q+EIEDLfKzZUOtn/rxSNa/QjlYxc42nvK4Mg8mB6XUgd3LXX5ZZVq7lzQgehgEqLrbgShJPGfeF8PnQ==} + engines: {node: '>=20.19.4'} + metro-minify-terser@0.84.3: resolution: {integrity: sha512-3ofrG2OQyJbO9RNhCfOcl8QU7EE2WrSsnN5dFkuZaJO5+4Imujr9bUXmspeNlXRsOVk0F/rVRbEFH98lFSCkBQ==} engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} @@ -5912,6 +5917,10 @@ packages: resolution: {integrity: sha512-7p3GtzVUpbAweJeCcUJihJeOQl1bDuimO5ueo1K0BUpUtR41q5EilbQ3klt16UTPPMpA+tISWBtsrqU556mY1A==} engines: {node: '>=20.19.4'} + metro-resolver@0.83.6: + resolution: {integrity: sha512-lAwR/FsT1uJ5iCt4AIsN3boKfJ88aN8bjvDT5FwBS0tKeKw4/sbdSTWlFxc7W/MUTN5RekJ3nQkJRIWsvs28tA==} + engines: {node: '>=20.19.4'} + metro-resolver@0.84.3: resolution: {integrity: sha512-pjEzGDtoM8DTHAIPK/9u9ZxszEiuRohYUVImWvgbnB91V4gqYJpQcoEYUugf2NIm1lrX5HNu0OvNqWmPBnGYjA==} engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} @@ -5920,6 +5929,10 @@ packages: resolution: {integrity: sha512-f+b3ue9AWTVlZe2Xrki6TAoFtKIqw30jwfk7GQ1rDUBQaE0ZQ+NkiMEtb9uwH7uAjJ87U7Tdx1Jg1OJqUfEVlA==} engines: {node: '>=20.19.4'} + metro-runtime@0.83.6: + resolution: {integrity: sha512-WQPua1G2VgYbwRn6vSKxOhTX7CFbSf/JdUu6Nd8bZnPXckOf7HQ2y51NXNQHoEsiuawathrkzL8pBhv+zgZFmg==} + engines: {node: '>=20.19.4'} + metro-runtime@0.84.3: resolution: {integrity: sha512-o7HLRfMyVk9N2dUZ9VjQfB6xxUItL9Pi9WcqxURE7MEKOH6wbGt9/E92YdYLluTOtkzYAEVfdC6h6lcxqA+hMQ==} engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} @@ -5928,6 +5941,10 @@ packages: resolution: {integrity: sha512-VT9bb2KO2/4tWY9Z2yeZqTUao7CicKAOps9LUg2aQzsz+04QyuXL3qgf1cLUVRjA/D6G5u1RJAlN1w9VNHtODQ==} engines: {node: '>=20.19.4'} + metro-source-map@0.83.6: + resolution: {integrity: sha512-AqJbOMMpeyyM4iNI91pchqDIszzNuuHApEhg6OABqZ+9mjLEqzcIEQ/fboZ7x74fNU5DBd2K36FdUQYPqlGClA==} + engines: {node: '>=20.19.4'} + metro-source-map@0.84.3: resolution: {integrity: sha512-jS48CeSzw78M8y6VE0f9uy3lVmfbOS677j2VCxnlmlYmnahcXuC6IhoN9K6LynNvos9517yUadcfgioju38xYQ==} engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} @@ -5937,6 +5954,11 @@ packages: engines: {node: '>=20.19.4'} hasBin: true + metro-symbolicate@0.83.6: + resolution: {integrity: sha512-4nvkmv9T7ozhprlPwk/+xm0SVPsxly5kYyMHdNaOlFemFz4df9BanvD46Ac6OISu/4Idinzfk2KVb++6OfzPAQ==} + engines: {node: '>=20.19.4'} + hasBin: true + metro-symbolicate@0.84.3: resolution: {integrity: sha512-J9Tpo8NCycYrozRvBIUyOwGAu4xkawOsAppmTscFiaegK0WvuDGwIM53GbzVSnytCHjVAF0io5GQxpkrKTuc7g==} engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} @@ -5946,6 +5968,10 @@ packages: resolution: {integrity: sha512-KxYKzZL+lt3Os5H2nx7YkbkWVduLZL5kPrE/Yq+Prm/DE1VLhpfnO6HtPs8vimYFKOa58ncl60GpoX0h7Wm0Vw==} engines: {node: '>=20.19.4'} + metro-transform-plugins@0.83.6: + resolution: {integrity: sha512-V+zoY2Ul0v0BW6IokJkTud3raXmDdbdwkUQ/5eiSoy0jKuKMhrDjdH+H5buCS5iiJdNbykOn69Eip+Sqymkodg==} + engines: {node: '>=20.19.4'} + metro-transform-plugins@0.84.3: resolution: {integrity: sha512-8S3baq2XhBaafHEH5Q8sJW6tmzsEJk80qKc3RU/nZV1MsnYq94RdjTUR6AyKjQd6Rfsk1BtBxhtiNnk7mgslCg==} engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} @@ -5954,6 +5980,10 @@ packages: resolution: {integrity: sha512-8N4pjkNXc6ytlP9oAM6MwqkvUepNSW39LKYl9NjUMpRDazBQ7oBpQDc8Sz4aI8jnH6AGhF7s1m/ayxkN1t04yA==} engines: {node: '>=20.19.4'} + metro-transform-worker@0.83.6: + resolution: {integrity: sha512-G5kDJ/P0ZTIf57t3iyAd5qIXbj2Wb1j7WtIDh82uTFQHe2Mq2SO9aXG9j1wI+kxZlIe58Z22XEXIKMl89z0ibQ==} + engines: {node: '>=20.19.4'} + metro-transform-worker@0.84.3: resolution: {integrity: sha512-Wjba7PyYktNRsHbPmkx2J2UX32rAzcDXjCu49zPHeF/viJlYJhwRaNePQcHaCRqQ+kmgQT4ThprsnJfDj71ZMA==} engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} @@ -5963,6 +5993,11 @@ packages: engines: {node: '>=20.19.4'} hasBin: true + metro@0.83.6: + resolution: {integrity: sha512-pbdndsAZ2F/ceopDdhVbttpa/hfLzXPJ/husc+QvQ33R0D9UXJKzTn5+OzOXx4bpQNtAKF2bY88cCI3Zl44xDQ==} + engines: {node: '>=20.19.4'} + hasBin: true + metro@0.84.3: resolution: {integrity: sha512-1h3lbVrE6hGf1e/764HfhPGg/bGrWMJDDh7G2rc4gFYZboVuI40BlG/y+UhtbhQDNlO/csMvrcnK0YrTlHUVew==} engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} @@ -6005,8 +6040,8 @@ packages: resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} engines: {node: '>=4'} - minimatch@10.2.4: - resolution: {integrity: sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==} + minimatch@10.2.5: + resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==} engines: {node: 18 || 20 || >=22} minimatch@3.1.5: @@ -6076,8 +6111,8 @@ packages: node-int64@0.4.0: resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} - node-releases@2.0.36: - resolution: {integrity: sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==} + node-releases@2.0.37: + resolution: {integrity: sha512-1h5gKZCF+pO/o3Iqt5Jp7wc9rH3eJJ0+nh/CIoiRwjRxde/hAHyLPXYN4V3CqKAbiZPSeJFSWHmJsbkicta0Eg==} nodemailer@8.0.5: resolution: {integrity: sha512-0PF8Yb1yZuQfQbq+5/pZJrtF6WQcjTd5/S4JOHs9PGFxuTqoB/icwuB44pOdURHJbRKX1PPoJZtY7R4VUoCC8w==} @@ -6108,6 +6143,10 @@ packages: resolution: {integrity: sha512-vNKPYC8L5ycVANANpF/S+WZHpfnRWKx/F3AYP4QMn6ZJTh+l2HOrId0clNkEmua58NB9vmI9Qh7YOoV/4folYg==} engines: {node: '>=20.19.4'} + ob1@0.83.6: + resolution: {integrity: sha512-m/xZYkwcjo6UqLMrUICEB3iHk7Bjt3RSR7KXMi6Y1MO/kGkPhoRmfUDF6KAan3rLAZ7ABRqnQyKUTwaqZgUV4w==} + engines: {node: '>=20.19.4'} + ob1@0.84.3: resolution: {integrity: sha512-J7554Ef8bzmKaDY365Afq6PF+qtdnY/d5PKUQFrsKlZHV/N3OGZewVrvDrQDyX5V5NJjTpcAKtlrFZcDr+HvpQ==} engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} @@ -6334,8 +6373,8 @@ packages: resolution: {integrity: sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==} engines: {node: ^10 || ^12 || >=14} - postcss@8.5.8: - resolution: {integrity: sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==} + postcss@8.5.9: + resolution: {integrity: sha512-7a70Nsot+EMX9fFU3064K/kdHWZqGVY+BADLyXc8Dfv+mTLLVl6JzJpPaCZ2kQL9gIJvKXSLMHhqdRRjwQeFtw==} engines: {node: ^10 || ^12 || >=14} postgres-array@2.0.0: @@ -6474,13 +6513,13 @@ packages: resolution: {integrity: sha512-r4F0Sec0BLxWicc7HEyo2x3/2icUTrRmDjaaRyzzn+7aDyFZliszMDOgLVwSnQnYENOlL1o569Ze2HZefk8clA==} engines: {node: '>=10'} peerDependencies: - react: '>=17.0.0' + react: ^19.2.5 - react-i18next@17.0.2: - resolution: {integrity: sha512-shBftH2vaTWK2Bsp7FiL+cevx3xFJlvFxmsDFQSrJc+6twHkP0tv/bGa01VVWzpreUVVwU+3Hev5iFqRg65RwA==} + react-i18next@17.0.3: + resolution: {integrity: sha512-x4xjvUNZ56T+zfXWNedNnCET9Xq1IBYWX7IsWo5cCQ/RT+Rm7GWqt0h9PShFi4IhyMnsdiu1C6Jc4DE+/S3PFQ==} peerDependencies: i18next: '>= 26.0.1' - react: '>= 16.8.0' + react: ^19.2.5 react-dom: '*' react-native: '*' typescript: ^5 || ^6 @@ -6508,38 +6547,38 @@ packages: resolution: {integrity: sha512-CWbTpr5vcHw5bt9i4zSlPEVQdTVcML390TjeDG0cK59z1ylexpqC6M1PJFjV8jD7CF+ACBFsLIDs6DRMoLEofw==} peerDependencies: leaflet: ^1.9.0 - react: ^19.0.0 - react-dom: ^19.0.0 + react: ^19.2.5 + react-dom: ^19.2.5 react-native-gesture-handler@2.31.1: resolution: {integrity: sha512-wQDlECdEzHhYKTnQXFnSqWUtJ5TS3MGQi7EWvQczTnEVKfk6XVSBecnpWAoI/CqlYQ7IWMJEyutY6BxwEBoxeg==} peerDependencies: - react: '*' + react: ^19.2.5 react-native: '*' react-native-is-edge-to-edge@1.3.1: resolution: {integrity: sha512-NIXU/iT5+ORyCc7p0z2nnlkouYKX425vuU1OEm6bMMtWWR9yvb+Xg5AZmImTKoF9abxCPqrKC3rOZsKzUYgYZA==} peerDependencies: - react: '*' + react: ^19.2.5 react-native: '*' react-native-reanimated@4.3.0: resolution: {integrity: sha512-HOTTPdKtddXTOsmQxDASXEwLS3lqEHrKERD3XOgzSqWJ7L3x81Pnx7mTcKx1FKdkgomMug/XSmm1C6Z7GIowxA==} peerDependencies: - react: '*' + react: ^19.2.5 react-native: 0.81 - 0.85 react-native-worklets: 0.8.x react-native-safe-area-context@5.6.2: resolution: {integrity: sha512-4XGqMNj5qjUTYywJqpdWZ9IG8jgkS3h06sfVjfw5yZQZfWnRFXczi0GnYyFyCc2EBps/qFmoCH8fez//WumdVg==} peerDependencies: - react: '*' + react: ^19.2.5 react-native: '*' react-native-screens@4.23.0: resolution: {integrity: sha512-XhO3aK0UeLpBn4kLecd+J+EDeRRJlI/Ro9Fze06vo1q163VeYtzfU9QS09/VyDFMWR1qxDC1iazCArTPSFFiPw==} peerDependencies: - react: '*' + react: ^19.2.5 react-native: '*' react-native-worklets@0.8.1: @@ -6547,7 +6586,7 @@ packages: peerDependencies: '@babel/core': '*' '@react-native/metro-config': '*' - react: '*' + react: ^19.2.5 react-native: 0.81 - 0.85 react-native@0.83.4: @@ -6556,7 +6595,7 @@ packages: hasBin: true peerDependencies: '@types/react': ^19.1.1 - react: ^19.2.0 + react: ^19.2.5 peerDependenciesMeta: '@types/react': optional: true @@ -6570,7 +6609,7 @@ packages: engines: {node: '>=10'} peerDependencies: '@types/react': '*' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react: ^19.2.5 peerDependenciesMeta: '@types/react': optional: true @@ -6580,17 +6619,17 @@ packages: engines: {node: '>=10'} peerDependencies: '@types/react': '*' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + react: ^19.2.5 peerDependenciesMeta: '@types/react': optional: true - react-router@7.14.0: - resolution: {integrity: sha512-m/xR9N4LQLmAS0ZhkY2nkPA1N7gQ5TUVa5n8TgANuDTARbn1gt+zLPXEm7W0XDTbrQ2AJSJKhoa6yx1D8BcpxQ==} + react-router@7.14.1: + resolution: {integrity: sha512-5BCvFskyAAVumqhEKh/iPhLOIkfxcEUz8WqFIARCkMg8hZZzDYX9CtwxXA0e+qT8zAxmMC0x3Ckb9iMONwc5jg==} engines: {node: '>=20.0.0'} peerDependencies: - react: '>=18' - react-dom: '>=18' + react: ^19.2.5 + react-dom: ^19.2.5 peerDependenciesMeta: react-dom: optional: true @@ -6600,7 +6639,7 @@ packages: engines: {node: '>=10'} peerDependencies: '@types/react': '*' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + react: ^19.2.5 peerDependenciesMeta: '@types/react': optional: true @@ -6608,7 +6647,7 @@ packages: react-test-renderer@19.2.0: resolution: {integrity: sha512-zLCFMHFE9vy/w3AxO0zNxy6aAupnCuLSVOJYDe/Tp+ayGI1f2PLQsFVPANSD42gdSbmYx5oN+1VWDhcXtq7hAQ==} peerDependencies: - react: ^19.2.0 + react: ^19.2.5 react-test-renderer@19.2.5: resolution: {integrity: sha512-kwViRpdISMTpcpy5B6TSewfJzRjnajihRaj57ZmOWKD+SPN6k9LUM13O0pfOuW8ir6B6OOiAXwCRqOoVxRNykA==} @@ -6710,8 +6749,8 @@ packages: engines: {node: ^20.19.0 || >=22.12.0} hasBin: true - rollup@4.60.0: - resolution: {integrity: sha512-yqjxruMGBQJ2gG4HtjZtAfXArHomazDHoFwFFmZZl0r7Pdo7qCIXKqKHZc8yeoMgzJJ+pO6pEEHa+V7uzWlrAQ==} + rollup@4.60.1: + resolution: {integrity: sha512-VmtB2rFU/GroZ4oL8+ZqXgSA38O6GR8KSIvWmEFv63pQ0G6KaBH9s07PO8XTXP4vI+3UJUEypOfjkGfmSBBR0w==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -6803,8 +6842,8 @@ packages: resolution: {integrity: sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==} engines: {node: '>= 0.4'} - side-channel-list@1.0.0: - resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} + side-channel-list@1.0.1: + resolution: {integrity: sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==} engines: {node: '>= 0.4'} side-channel-map@1.0.1: @@ -7006,8 +7045,8 @@ packages: tailwindcss@4.2.2: resolution: {integrity: sha512-KWBIxs1Xb6NoLdMVqhbhgwZf2PGBpPEiwOqgI4pFIYbNTfBXiKYyWoTsXgBQ9WFg/OlhnvHaY+AEpW7wSmFo2Q==} - tapable@2.3.0: - resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} + tapable@2.3.2: + resolution: {integrity: sha512-1MOpMXuhGzGL5TTCZFItxCc0AARf1EZFQkGqMm7ERKj8+Hgr5oLvJOVFcC+lRmR8hCe2S3jC4T5D7Vg/d7/fhA==} engines: {node: '>=6'} tdigest@0.1.2: @@ -7036,12 +7075,12 @@ packages: tinybench@2.9.0: resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} - tinyexec@1.0.4: - resolution: {integrity: sha512-u9r3uZC0bdpGOXtlxUIdwf9pkmvhqJdrVCH9fapQtgy/OeTTMZ1nqH7agtvEfmGui6e1XxjcdrlxvxJvc3sMqw==} + tinyexec@1.1.1: + resolution: {integrity: sha512-VKS/ZaQhhkKFMANmAOhhXVoIfBXblQxGX1myCQ2faQrfmobMftXeJPcZGp0gS07ocvGJWDLZGyOZDadDBqYIJg==} engines: {node: '>=18'} - tinyglobby@0.2.15: - resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} + tinyglobby@0.2.16: + resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==} engines: {node: '>=12.0.0'} tinyqueue@2.0.3: @@ -7051,11 +7090,11 @@ packages: resolution: {integrity: sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==} engines: {node: '>=14.0.0'} - tldts-core@7.0.27: - resolution: {integrity: sha512-YQ7uPjgWUibIK6DW5lrKujGwUKhLevU4hcGbP5O6TcIUb+oTjJYJVWPS4nZsIHrEEEG6myk/oqAJUEQmpZrHsg==} + tldts-core@7.0.28: + resolution: {integrity: sha512-7W5Efjhsc3chVdFhqtaU0KtK32J37Zcr9RKtID54nG+tIpcY79CQK/veYPODxtD/LJ4Lue66jvrQzIX2Z2/pUQ==} - tldts@7.0.27: - resolution: {integrity: sha512-I4FZcVFcqCRuT0ph6dCDpPuO4Xgzvh+spkcTr1gK7peIvxWauoloVO0vuy1FQnijT63ss6AsHB6+OIM4aXHbPg==} + tldts@7.0.28: + resolution: {integrity: sha512-+Zg3vWhRUv8B1maGSTFdev9mjoo8Etn2Ayfs4cnjlD3CsGkxXX4QyW3j2WJ0wdjYcYmy7Lx2RDsZMhgCWafKIw==} hasBin: true tmpl@1.0.5: @@ -7097,20 +7136,6 @@ packages: peerDependencies: typescript: '>=4.8.4' - ts-node@10.9.2: - resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} - hasBin: true - peerDependencies: - '@swc/core': '>=1.2.50' - '@swc/wasm': '>=1.2.50' - '@types/node': '*' - typescript: '>=2.7' - peerDependenciesMeta: - '@swc/core': - optional: true - '@swc/wasm': - optional: true - tslib@1.14.1: resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} @@ -7154,8 +7179,8 @@ packages: resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} engines: {node: '>= 0.6'} - typescript-eslint@8.58.1: - resolution: {integrity: sha512-gf6/oHChByg9HJvhMO1iBexJh12AqqTfnuxscMDOVqfJW3htsdRJI/GfPpHTTcyeB8cSTUY2JcZmVgoyPqcrDg==} + typescript-eslint@8.58.2: + resolution: {integrity: sha512-V8iSng9mRbdZjl54VJ9NKr6ZB+dW0J3TzRXRGcSbLIej9jV86ZRtlYeTKDR/QLxXykocJ5icNzbsl2+5TzIvcQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 @@ -7176,15 +7201,15 @@ packages: undici-types@6.21.0: resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} - undici-types@7.18.2: - resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} + undici-types@7.19.2: + resolution: {integrity: sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==} - undici@6.24.1: - resolution: {integrity: sha512-sC+b0tB1whOCzbtlx20fx3WgCXwkW627p4EA9uM+/tNNPkSS+eSEld6pAs9nDv7WbY1UUljBMYPtu9BCOrCWKA==} + undici@6.25.0: + resolution: {integrity: sha512-ZgpWDC5gmNiuY9CnLVXEH8rl50xhRCuLNA97fAUnKi8RRuV4E6KG31pDTsLVUKnohJE0I3XDrTeEydAXRw47xg==} engines: {node: '>=18.17'} - undici@7.24.5: - resolution: {integrity: sha512-3IWdCpjgxp15CbJnsi/Y9TCDE7HWVN19j1hmzVhoAkY/+CJx449tVxT5wZc1Gwg8J+P0LWvzlBzxYRnHJ+1i7Q==} + undici@7.25.0: + resolution: {integrity: sha512-xXnp4kTyor2Zq+J1FfPI6Eq3ew5h6Vl0F/8d9XU5zZQf1tX9s2Su1/3PiMmUANFULpmksxkClamIZcaUqryHsQ==} engines: {node: '>=20.18.1'} unicode-canonical-property-names-ecmascript@2.0.1: @@ -7228,7 +7253,7 @@ packages: engines: {node: '>=10'} peerDependencies: '@types/react': '*' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + react: ^19.2.5 peerDependenciesMeta: '@types/react': optional: true @@ -7236,19 +7261,19 @@ packages: use-latest-callback@0.2.6: resolution: {integrity: sha512-FvRG9i1HSo0wagmX63Vrm8SnlUU3LMM3WyZkQ76RnslpBrX694AdG4A0zQBx2B3ZifFA0yv/BaEHGBnEax5rZg==} peerDependencies: - react: '>=16.8' + react: ^19.2.5 use-latest-callback@0.3.3: resolution: {integrity: sha512-G9A/EL7okx4wzBfATt8bdGg0v1K0Gp0IClTzljffM63gtPisgDKCaLCLUb4g2M4CoXDg5yyHjOU+g3SUPbXwrA==} peerDependencies: - react: '>=16.8' + react: ^19.2.5 use-sidecar@1.1.3: resolution: {integrity: sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==} engines: {node: '>=10'} peerDependencies: '@types/react': '*' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + react: ^19.2.5 peerDependenciesMeta: '@types/react': optional: true @@ -7256,7 +7281,7 @@ packages: use-sync-external-store@1.6.0: resolution: {integrity: sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==} peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react: ^19.2.5 utils-merge@1.0.1: resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} @@ -7266,9 +7291,6 @@ packages: resolution: {integrity: sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg==} hasBin: true - v8-compile-cache-lib@3.0.1: - resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} - v8-to-istanbul@9.3.0: resolution: {integrity: sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==} engines: {node: '>=10.12.0'} @@ -7292,27 +7314,27 @@ packages: vaul@1.1.2: resolution: {integrity: sha512-ZFkClGpWyI2WUQjdLJ/BaGuV6AVQiJ3uELGk3OYtP+B6yCO7Cmn9vPFXVJkRaGkOJu3m8bQMgtyzNHixULceQA==} peerDependencies: - react: ^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc + react: ^19.2.5 + react-dom: ^19.2.5 vite-node@3.2.4: resolution: {integrity: sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} hasBin: true - vite@6.4.2: - resolution: {integrity: sha512-2N/55r4JDJ4gdrCvGgINMy+HH3iRpNIz8K6SFwVsA+JbQScLiC+clmAxBgwiSPgcG9U15QmvqCGWzMbqda5zGQ==} - engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + vite@7.3.2: + resolution: {integrity: sha512-Bby3NOsna2jsjfLVOHKes8sGwgl4TT0E6vvpYgnAYDIF/tie7MRaFthmKuHx1NSXjiTueXH3do80FMQgvEktRg==} + engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: - '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 + '@types/node': ^20.19.0 || >=22.12.0 jiti: '>=1.21.0' - less: '*' + less: ^4.0.0 lightningcss: ^1.21.0 - sass: '*' - sass-embedded: '*' - stylus: '*' - sugarss: '*' + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 terser: ^5.16.0 tsx: ^4.8.1 yaml: ^2.4.2 @@ -7618,10 +7640,6 @@ packages: resolution: {integrity: sha512-vv/9h42eCMC81ZHDFswuu/MKzkl/vyq1BhaNGfHyOonwlG4CJbQF4oiBBJPvfdeCt/PlVDWh7Nov9D34YY09uQ==} engines: {node: '>=16.0.0', npm: '>=8.0.0'} - yn@3.1.1: - resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} - engines: {node: '>=6'} - yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} @@ -7633,10 +7651,10 @@ snapshots: '@adobe/css-tools@4.4.4': {} - '@asamuzakjp/css-color@5.1.9': + '@asamuzakjp/css-color@5.1.10': dependencies: - '@csstools/css-calc': 3.1.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) - '@csstools/css-color-parser': 4.0.2(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-calc': 3.2.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-color-parser': 4.1.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) '@csstools/css-tokenizer': 4.0.0 @@ -7683,7 +7701,7 @@ snapshots: '@babel/types': 7.29.0 '@jridgewell/gen-mapping': 0.3.13 '@jridgewell/trace-mapping': 0.3.31 - jsesc: 3.1.0 + jsesc: 3.0.2 '@babel/helper-annotate-as-pure@7.27.3': dependencies: @@ -7693,7 +7711,7 @@ snapshots: dependencies: '@babel/compat-data': 7.29.0 '@babel/helper-validator-option': 7.27.1 - browserslist: 4.28.1 + browserslist: 4.28.2 lru-cache: 5.1.1 semver: 6.3.1 @@ -8300,22 +8318,17 @@ snapshots: style-mod: 4.1.3 w3c-keyname: 2.2.8 - '@cspotcode/source-map-support@0.8.1': - dependencies: - '@jridgewell/trace-mapping': 0.3.9 - optional: true - '@csstools/color-helpers@6.0.2': {} - '@csstools/css-calc@3.1.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': + '@csstools/css-calc@3.2.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': dependencies: '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) '@csstools/css-tokenizer': 4.0.0 - '@csstools/css-color-parser@4.0.2(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': + '@csstools/css-color-parser@4.1.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': dependencies: '@csstools/color-helpers': 6.0.2 - '@csstools/css-calc': 3.1.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-calc': 3.2.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) '@csstools/css-tokenizer': 4.0.0 @@ -8323,7 +8336,7 @@ snapshots: dependencies: '@csstools/css-tokenizer': 4.0.0 - '@csstools/css-syntax-patches-for-csstree@1.1.1(css-tree@3.2.1)': + '@csstools/css-syntax-patches-for-csstree@1.1.3(css-tree@3.2.1)': optionalDependencies: css-tree: 3.2.1 @@ -8359,12 +8372,12 @@ snapshots: '@esbuild-kit/esm-loader@2.6.5': dependencies: '@esbuild-kit/core-utils': 3.3.2 - get-tsconfig: 4.13.7 + get-tsconfig: 4.13.8 '@esbuild/aix-ppc64@0.25.12': optional: true - '@esbuild/aix-ppc64@0.27.4': + '@esbuild/aix-ppc64@0.27.7': optional: true '@esbuild/android-arm64@0.18.20': @@ -8373,7 +8386,7 @@ snapshots: '@esbuild/android-arm64@0.25.12': optional: true - '@esbuild/android-arm64@0.27.4': + '@esbuild/android-arm64@0.27.7': optional: true '@esbuild/android-arm@0.18.20': @@ -8382,7 +8395,7 @@ snapshots: '@esbuild/android-arm@0.25.12': optional: true - '@esbuild/android-arm@0.27.4': + '@esbuild/android-arm@0.27.7': optional: true '@esbuild/android-x64@0.18.20': @@ -8391,7 +8404,7 @@ snapshots: '@esbuild/android-x64@0.25.12': optional: true - '@esbuild/android-x64@0.27.4': + '@esbuild/android-x64@0.27.7': optional: true '@esbuild/darwin-arm64@0.18.20': @@ -8400,7 +8413,7 @@ snapshots: '@esbuild/darwin-arm64@0.25.12': optional: true - '@esbuild/darwin-arm64@0.27.4': + '@esbuild/darwin-arm64@0.27.7': optional: true '@esbuild/darwin-x64@0.18.20': @@ -8409,7 +8422,7 @@ snapshots: '@esbuild/darwin-x64@0.25.12': optional: true - '@esbuild/darwin-x64@0.27.4': + '@esbuild/darwin-x64@0.27.7': optional: true '@esbuild/freebsd-arm64@0.18.20': @@ -8418,7 +8431,7 @@ snapshots: '@esbuild/freebsd-arm64@0.25.12': optional: true - '@esbuild/freebsd-arm64@0.27.4': + '@esbuild/freebsd-arm64@0.27.7': optional: true '@esbuild/freebsd-x64@0.18.20': @@ -8427,7 +8440,7 @@ snapshots: '@esbuild/freebsd-x64@0.25.12': optional: true - '@esbuild/freebsd-x64@0.27.4': + '@esbuild/freebsd-x64@0.27.7': optional: true '@esbuild/linux-arm64@0.18.20': @@ -8436,7 +8449,7 @@ snapshots: '@esbuild/linux-arm64@0.25.12': optional: true - '@esbuild/linux-arm64@0.27.4': + '@esbuild/linux-arm64@0.27.7': optional: true '@esbuild/linux-arm@0.18.20': @@ -8445,7 +8458,7 @@ snapshots: '@esbuild/linux-arm@0.25.12': optional: true - '@esbuild/linux-arm@0.27.4': + '@esbuild/linux-arm@0.27.7': optional: true '@esbuild/linux-ia32@0.18.20': @@ -8454,7 +8467,7 @@ snapshots: '@esbuild/linux-ia32@0.25.12': optional: true - '@esbuild/linux-ia32@0.27.4': + '@esbuild/linux-ia32@0.27.7': optional: true '@esbuild/linux-loong64@0.18.20': @@ -8463,7 +8476,7 @@ snapshots: '@esbuild/linux-loong64@0.25.12': optional: true - '@esbuild/linux-loong64@0.27.4': + '@esbuild/linux-loong64@0.27.7': optional: true '@esbuild/linux-mips64el@0.18.20': @@ -8472,7 +8485,7 @@ snapshots: '@esbuild/linux-mips64el@0.25.12': optional: true - '@esbuild/linux-mips64el@0.27.4': + '@esbuild/linux-mips64el@0.27.7': optional: true '@esbuild/linux-ppc64@0.18.20': @@ -8481,7 +8494,7 @@ snapshots: '@esbuild/linux-ppc64@0.25.12': optional: true - '@esbuild/linux-ppc64@0.27.4': + '@esbuild/linux-ppc64@0.27.7': optional: true '@esbuild/linux-riscv64@0.18.20': @@ -8490,7 +8503,7 @@ snapshots: '@esbuild/linux-riscv64@0.25.12': optional: true - '@esbuild/linux-riscv64@0.27.4': + '@esbuild/linux-riscv64@0.27.7': optional: true '@esbuild/linux-s390x@0.18.20': @@ -8499,7 +8512,7 @@ snapshots: '@esbuild/linux-s390x@0.25.12': optional: true - '@esbuild/linux-s390x@0.27.4': + '@esbuild/linux-s390x@0.27.7': optional: true '@esbuild/linux-x64@0.18.20': @@ -8508,13 +8521,13 @@ snapshots: '@esbuild/linux-x64@0.25.12': optional: true - '@esbuild/linux-x64@0.27.4': + '@esbuild/linux-x64@0.27.7': optional: true '@esbuild/netbsd-arm64@0.25.12': optional: true - '@esbuild/netbsd-arm64@0.27.4': + '@esbuild/netbsd-arm64@0.27.7': optional: true '@esbuild/netbsd-x64@0.18.20': @@ -8523,13 +8536,13 @@ snapshots: '@esbuild/netbsd-x64@0.25.12': optional: true - '@esbuild/netbsd-x64@0.27.4': + '@esbuild/netbsd-x64@0.27.7': optional: true '@esbuild/openbsd-arm64@0.25.12': optional: true - '@esbuild/openbsd-arm64@0.27.4': + '@esbuild/openbsd-arm64@0.27.7': optional: true '@esbuild/openbsd-x64@0.18.20': @@ -8538,13 +8551,13 @@ snapshots: '@esbuild/openbsd-x64@0.25.12': optional: true - '@esbuild/openbsd-x64@0.27.4': + '@esbuild/openbsd-x64@0.27.7': optional: true '@esbuild/openharmony-arm64@0.25.12': optional: true - '@esbuild/openharmony-arm64@0.27.4': + '@esbuild/openharmony-arm64@0.27.7': optional: true '@esbuild/sunos-x64@0.18.20': @@ -8553,7 +8566,7 @@ snapshots: '@esbuild/sunos-x64@0.25.12': optional: true - '@esbuild/sunos-x64@0.27.4': + '@esbuild/sunos-x64@0.27.7': optional: true '@esbuild/win32-arm64@0.18.20': @@ -8562,7 +8575,7 @@ snapshots: '@esbuild/win32-arm64@0.25.12': optional: true - '@esbuild/win32-arm64@0.27.4': + '@esbuild/win32-arm64@0.27.7': optional: true '@esbuild/win32-ia32@0.18.20': @@ -8571,7 +8584,7 @@ snapshots: '@esbuild/win32-ia32@0.25.12': optional: true - '@esbuild/win32-ia32@0.27.4': + '@esbuild/win32-ia32@0.27.7': optional: true '@esbuild/win32-x64@0.18.20': @@ -8580,7 +8593,7 @@ snapshots: '@esbuild/win32-x64@0.25.12': optional: true - '@esbuild/win32-x64@0.27.4': + '@esbuild/win32-x64@0.27.7': optional: true '@eslint-community/eslint-utils@4.9.1(eslint@10.2.0(jiti@2.6.1))': @@ -8590,19 +8603,19 @@ snapshots: '@eslint-community/regexpp@4.12.2': {} - '@eslint/config-array@0.23.4': + '@eslint/config-array@0.23.5': dependencies: - '@eslint/object-schema': 3.0.4 + '@eslint/object-schema': 3.0.5 debug: 4.4.3 - minimatch: 10.2.4 + minimatch: 10.2.5 transitivePeerDependencies: - supports-color - '@eslint/config-helpers@0.5.4': + '@eslint/config-helpers@0.5.5': dependencies: - '@eslint/core': 1.2.0 + '@eslint/core': 1.2.1 - '@eslint/core@1.2.0': + '@eslint/core@1.2.1': dependencies: '@types/json-schema': 7.0.15 @@ -8610,16 +8623,16 @@ snapshots: optionalDependencies: eslint: 10.2.0(jiti@2.6.1) - '@eslint/object-schema@3.0.4': {} + '@eslint/object-schema@3.0.5': {} - '@eslint/plugin-kit@0.7.0': + '@eslint/plugin-kit@0.7.1': dependencies: - '@eslint/core': 1.2.0 + '@eslint/core': 1.2.1 levn: 0.4.1 '@exodus/bytes@1.15.0': {} - '@expo-google-fonts/material-symbols@0.4.30': {} + '@expo-google-fonts/material-symbols@0.4.31': {} '@expo/cli@55.0.24(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-constants@55.0.14)(expo-font@55.0.6)(expo-router@55.0.12)(expo@55.0.15)(react-dom@19.2.5(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3)': dependencies: @@ -8682,7 +8695,7 @@ snapshots: ws: 8.20.0 zod: 3.25.76 optionalDependencies: - expo-router: 55.0.12(2abaf9bed2da34a074803b38a8556f5d) + expo-router: 55.0.12(967bbc80afd40466d8ec2b5429609e86) react-native: 0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5) transitivePeerDependencies: - '@expo/dom-webview' @@ -8721,22 +8734,6 @@ snapshots: '@expo/config-types@55.0.5': {} - '@expo/config@55.0.14(typescript@5.9.3)': - dependencies: - '@expo/config-plugins': 55.0.8 - '@expo/config-types': 55.0.5 - '@expo/json-file': 10.0.13 - '@expo/require-utils': 55.0.4(typescript@5.9.3) - deepmerge: 4.3.1 - getenv: 2.0.0 - glob: 13.0.6 - resolve-workspace-root: 2.0.1 - semver: 7.7.4 - slugify: 1.6.9 - transitivePeerDependencies: - - supports-color - - typescript - '@expo/config@55.0.15(typescript@5.9.3)': dependencies: '@expo/config-plugins': 55.0.8 @@ -8791,7 +8788,7 @@ snapshots: getenv: 2.0.0 glob: 13.0.6 ignore: 5.3.2 - minimatch: 10.2.4 + minimatch: 10.2.5 resolve-from: 5.0.0 semver: 7.7.4 transitivePeerDependencies: @@ -8842,7 +8839,7 @@ snapshots: '@expo/json-file': 10.0.13 '@expo/metro': 55.0.0 '@expo/spawn-async': 1.7.2 - browserslist: 4.28.1 + browserslist: 4.28.2 chalk: 4.1.2 debug: 4.4.3 getenv: 2.0.0 @@ -8953,7 +8950,7 @@ snapshots: react: 19.2.5 optionalDependencies: '@expo/metro-runtime': 55.0.9(@expo/dom-webview@55.0.5)(expo@55.0.15)(react-dom@19.2.5(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) - expo-router: 55.0.12(2abaf9bed2da34a074803b38a8556f5d) + expo-router: 55.0.12(967bbc80afd40466d8ec2b5429609e86) react-dom: 19.2.5(react@19.2.5) transitivePeerDependencies: - supports-color @@ -8988,7 +8985,7 @@ snapshots: '@opentelemetry/core': 2.6.1(@opentelemetry/api@1.9.1) '@opentelemetry/instrumentation': 0.212.0(@opentelemetry/api@1.9.1) '@opentelemetry/semantic-conventions': 1.40.0 - minimatch: 10.2.4 + minimatch: 10.2.5 transitivePeerDependencies: - supports-color @@ -9042,32 +9039,32 @@ snapshots: js-yaml: 3.14.2 resolve-from: 5.0.0 - '@istanbuljs/schema@0.1.3': {} + '@istanbuljs/schema@0.1.6': {} '@jest/console@29.7.0': dependencies: '@jest/types': 29.6.3 - '@types/node': 25.5.2 + '@types/node': 25.6.0 chalk: 4.1.2 jest-message-util: 29.7.0 jest-util: 29.7.0 slash: 3.0.0 - '@jest/core@29.7.0(ts-node@10.9.2(@types/node@25.5.2)(typescript@5.9.3))': + '@jest/core@29.7.0': dependencies: '@jest/console': 29.7.0 '@jest/reporters': 29.7.0 '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 25.5.2 + '@types/node': 25.6.0 ansi-escapes: 4.3.2 chalk: 4.1.2 ci-info: 3.9.0 exit: 0.1.2 graceful-fs: 4.2.11 jest-changed-files: 29.7.0 - jest-config: 29.7.0(@types/node@25.5.2)(ts-node@10.9.2(@types/node@25.5.2)(typescript@5.9.3)) + jest-config: 29.7.0(@types/node@25.6.0) jest-haste-map: 29.7.0 jest-message-util: 29.7.0 jest-regex-util: 29.6.3 @@ -9098,7 +9095,7 @@ snapshots: dependencies: '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 25.5.2 + '@types/node': 25.6.0 jest-mock: 29.7.0 '@jest/expect-utils@29.7.0': @@ -9116,7 +9113,7 @@ snapshots: dependencies: '@jest/types': 29.6.3 '@sinonjs/fake-timers': 10.3.0 - '@types/node': 25.5.2 + '@types/node': 25.6.0 jest-message-util: 29.7.0 jest-mock: 29.7.0 jest-util: 29.7.0 @@ -9140,7 +9137,7 @@ snapshots: '@jest/transform': 29.7.0 '@jest/types': 29.6.3 '@jridgewell/trace-mapping': 0.3.31 - '@types/node': 25.5.2 + '@types/node': 25.6.0 chalk: 4.1.2 collect-v8-coverage: 1.0.3 exit: 0.1.2 @@ -9214,7 +9211,7 @@ snapshots: '@jest/schemas': 29.6.3 '@types/istanbul-lib-coverage': 2.0.6 '@types/istanbul-reports': 3.0.4 - '@types/node': 25.5.2 + '@types/node': 25.6.0 '@types/yargs': 17.0.35 chalk: 4.1.2 @@ -9242,12 +9239,6 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 - '@jridgewell/trace-mapping@0.3.9': - dependencies: - '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.5 - optional: true - '@levischuck/tiny-cbor@0.2.11': {} '@lezer/common@1.5.2': {} @@ -9512,7 +9503,7 @@ snapshots: dependencies: '@opentelemetry/api': 1.9.1 '@opentelemetry/api-logs': 0.214.0 - import-in-the-middle: 3.0.0 + import-in-the-middle: 3.0.1 require-in-the-middle: 8.0.1 transitivePeerDependencies: - supports-color @@ -9794,6 +9785,13 @@ snapshots: optionalDependencies: '@types/react': 19.2.14 + '@radix-ui/react-slot@1.2.4(@types/react@19.2.14)(react@19.2.5)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.5) + react: 19.2.5 + optionalDependencies: + '@types/react': 19.2.14 + '@radix-ui/react-tabs@1.1.13(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@radix-ui/primitive': 1.1.3 @@ -9973,7 +9971,7 @@ snapshots: hermes-parser: 0.33.3 invariant: 2.2.4 nullthrows: 1.1.1 - tinyglobby: 0.2.15 + tinyglobby: 0.2.16 yargs: 17.7.2 '@react-native/community-cli-plugin@0.83.4(@react-native/metro-config@0.85.1(@babel/core@7.29.0))': @@ -9981,9 +9979,9 @@ snapshots: '@react-native/dev-middleware': 0.83.4 debug: 4.4.3 invariant: 2.2.4 - metro: 0.83.5 - metro-config: 0.83.5 - metro-core: 0.83.5 + metro: 0.83.6 + metro-config: 0.83.6 + metro-core: 0.83.6 semver: 7.7.4 optionalDependencies: '@react-native/metro-config': 0.85.1(@babel/core@7.29.0) @@ -10091,7 +10089,7 @@ snapshots: use-latest-callback: 0.2.6(react@19.2.5) use-sync-external-store: 1.6.0(react@19.2.5) - '@react-navigation/native-stack@7.14.10(@react-navigation/native@7.2.2(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native-safe-area-context@5.6.2(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native-screens@4.23.0(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)': + '@react-navigation/native-stack@7.14.11(@react-navigation/native@7.2.2(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native-safe-area-context@5.6.2(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native-screens@4.23.0(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)': dependencies: '@react-navigation/elements': 2.9.14(@react-navigation/native@7.2.2(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native-safe-area-context@5.6.2(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) '@react-navigation/native': 7.2.2(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) @@ -10119,7 +10117,7 @@ snapshots: dependencies: nanoid: 3.3.11 - '@react-router/dev@7.14.0(@react-router/serve@7.14.0(react-router@7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3))(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)(react-router@7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3)': + '@react-router/dev@7.14.1(@react-router/serve@7.14.1(react-router@7.14.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3))(@types/node@25.6.0)(jiti@2.6.1)(lightningcss@1.32.0)(react-router@7.14.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3)': dependencies: '@babel/core': 7.29.0 '@babel/generator': 7.29.1 @@ -10128,7 +10126,7 @@ snapshots: '@babel/preset-typescript': 7.28.5(@babel/core@7.29.0) '@babel/traverse': 7.29.0 '@babel/types': 7.29.0 - '@react-router/node': 7.14.0(react-router@7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3) + '@react-router/node': 7.14.1(react-router@7.14.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3) '@remix-run/node-fetch-server': 0.13.0 arg: 5.0.2 babel-dead-code-elimination: 1.0.12 @@ -10136,7 +10134,7 @@ snapshots: dedent: 1.7.2 es-module-lexer: 1.7.0 exit-hook: 2.2.1 - isbot: 5.1.37 + isbot: 5.1.38 jsesc: 3.0.2 lodash: 4.18.1 p-map: 7.0.4 @@ -10145,14 +10143,14 @@ snapshots: pkg-types: 2.3.0 prettier: 3.8.2 react-refresh: 0.14.2 - react-router: 7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + react-router: 7.14.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5) semver: 7.7.4 - tinyglobby: 0.2.15 + tinyglobby: 0.2.16 valibot: 1.3.1(typescript@5.9.3) - vite: 8.0.8(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) - vite-node: 3.2.4(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) + vite: 8.0.8(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) + vite-node: 3.2.4(@types/node@25.6.0)(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) optionalDependencies: - '@react-router/serve': 7.14.0(react-router@7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3) + '@react-router/serve': 7.14.1(react-router@7.14.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - '@types/node' @@ -10169,31 +10167,31 @@ snapshots: - tsx - yaml - '@react-router/express@7.14.0(express@4.22.1)(react-router@7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3)': + '@react-router/express@7.14.1(express@4.22.1)(react-router@7.14.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3)': dependencies: - '@react-router/node': 7.14.0(react-router@7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3) + '@react-router/node': 7.14.1(react-router@7.14.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3) express: 4.22.1 - react-router: 7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + react-router: 7.14.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5) optionalDependencies: typescript: 5.9.3 - '@react-router/node@7.14.0(react-router@7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3)': + '@react-router/node@7.14.1(react-router@7.14.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3)': dependencies: '@mjackson/node-fetch-server': 0.2.0 - react-router: 7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + react-router: 7.14.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5) optionalDependencies: typescript: 5.9.3 - '@react-router/serve@7.14.0(react-router@7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3)': + '@react-router/serve@7.14.1(react-router@7.14.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3)': dependencies: '@mjackson/node-fetch-server': 0.2.0 - '@react-router/express': 7.14.0(express@4.22.1)(react-router@7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3) - '@react-router/node': 7.14.0(react-router@7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3) + '@react-router/express': 7.14.1(express@4.22.1)(react-router@7.14.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3) + '@react-router/node': 7.14.1(react-router@7.14.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3) compression: 1.8.1 express: 4.22.1 get-port: 5.1.1 morgan: 1.10.1 - react-router: 7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + react-router: 7.14.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5) source-map-support: 0.5.21 transitivePeerDependencies: - supports-color @@ -10252,79 +10250,79 @@ snapshots: '@rolldown/pluginutils@1.0.0-rc.15': {} - '@rollup/rollup-android-arm-eabi@4.60.0': + '@rollup/rollup-android-arm-eabi@4.60.1': optional: true - '@rollup/rollup-android-arm64@4.60.0': + '@rollup/rollup-android-arm64@4.60.1': optional: true - '@rollup/rollup-darwin-arm64@4.60.0': + '@rollup/rollup-darwin-arm64@4.60.1': optional: true - '@rollup/rollup-darwin-x64@4.60.0': + '@rollup/rollup-darwin-x64@4.60.1': optional: true - '@rollup/rollup-freebsd-arm64@4.60.0': + '@rollup/rollup-freebsd-arm64@4.60.1': optional: true - '@rollup/rollup-freebsd-x64@4.60.0': + '@rollup/rollup-freebsd-x64@4.60.1': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.60.0': + '@rollup/rollup-linux-arm-gnueabihf@4.60.1': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.60.0': + '@rollup/rollup-linux-arm-musleabihf@4.60.1': optional: true - '@rollup/rollup-linux-arm64-gnu@4.60.0': + '@rollup/rollup-linux-arm64-gnu@4.60.1': optional: true - '@rollup/rollup-linux-arm64-musl@4.60.0': + '@rollup/rollup-linux-arm64-musl@4.60.1': optional: true - '@rollup/rollup-linux-loong64-gnu@4.60.0': + '@rollup/rollup-linux-loong64-gnu@4.60.1': optional: true - '@rollup/rollup-linux-loong64-musl@4.60.0': + '@rollup/rollup-linux-loong64-musl@4.60.1': optional: true - '@rollup/rollup-linux-ppc64-gnu@4.60.0': + '@rollup/rollup-linux-ppc64-gnu@4.60.1': optional: true - '@rollup/rollup-linux-ppc64-musl@4.60.0': + '@rollup/rollup-linux-ppc64-musl@4.60.1': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.60.0': + '@rollup/rollup-linux-riscv64-gnu@4.60.1': optional: true - '@rollup/rollup-linux-riscv64-musl@4.60.0': + '@rollup/rollup-linux-riscv64-musl@4.60.1': optional: true - '@rollup/rollup-linux-s390x-gnu@4.60.0': + '@rollup/rollup-linux-s390x-gnu@4.60.1': optional: true - '@rollup/rollup-linux-x64-gnu@4.60.0': + '@rollup/rollup-linux-x64-gnu@4.60.1': optional: true - '@rollup/rollup-linux-x64-musl@4.60.0': + '@rollup/rollup-linux-x64-musl@4.60.1': optional: true - '@rollup/rollup-openbsd-x64@4.60.0': + '@rollup/rollup-openbsd-x64@4.60.1': optional: true - '@rollup/rollup-openharmony-arm64@4.60.0': + '@rollup/rollup-openharmony-arm64@4.60.1': optional: true - '@rollup/rollup-win32-arm64-msvc@4.60.0': + '@rollup/rollup-win32-arm64-msvc@4.60.1': optional: true - '@rollup/rollup-win32-ia32-msvc@4.60.0': + '@rollup/rollup-win32-ia32-msvc@4.60.1': optional: true - '@rollup/rollup-win32-x64-gnu@4.60.0': + '@rollup/rollup-win32-x64-gnu@4.60.1': optional: true - '@rollup/rollup-win32-x64-msvc@4.60.0': + '@rollup/rollup-win32-x64-msvc@4.60.1': optional: true '@sentry-internal/browser-utils@10.37.0': @@ -10512,7 +10510,7 @@ snapshots: dependencies: progress: 2.0.3 proxy-from-env: 1.1.0 - undici: 6.24.1 + undici: 6.25.0 which: 2.0.2 optionalDependencies: '@sentry/cli-darwin': 3.3.5 @@ -10532,7 +10530,7 @@ snapshots: dependencies: '@sentry/core': 10.48.0 '@sentry/opentelemetry': 10.48.0(@opentelemetry/api@1.9.1)(@opentelemetry/context-async-hooks@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/core@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/semantic-conventions@1.40.0) - import-in-the-middle: 3.0.0 + import-in-the-middle: 3.0.1 optionalDependencies: '@opentelemetry/api': 1.9.1 '@opentelemetry/context-async-hooks': 2.6.1(@opentelemetry/api@1.9.1) @@ -10577,7 +10575,7 @@ snapshots: '@sentry/core': 10.48.0 '@sentry/node-core': 10.48.0(@opentelemetry/api@1.9.1)(@opentelemetry/context-async-hooks@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/core@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/instrumentation@0.214.0(@opentelemetry/api@1.9.1))(@opentelemetry/resources@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/semantic-conventions@1.40.0) '@sentry/opentelemetry': 10.48.0(@opentelemetry/api@1.9.1)(@opentelemetry/context-async-hooks@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/core@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/semantic-conventions@1.40.0) - import-in-the-middle: 3.0.0 + import-in-the-middle: 3.0.1 transitivePeerDependencies: - '@opentelemetry/exporter-trace-otlp-http' - supports-color @@ -10619,12 +10617,12 @@ snapshots: '@sentry/core': 10.48.0 react: 19.2.5 - '@sentry/rollup-plugin@5.2.0(rollup@4.60.0)': + '@sentry/rollup-plugin@5.2.0(rollup@4.60.1)': dependencies: '@sentry/bundler-plugin-core': 5.2.0 magic-string: 0.30.21 optionalDependencies: - rollup: 4.60.0 + rollup: 4.60.1 transitivePeerDependencies: - encoding - supports-color @@ -10633,10 +10631,10 @@ snapshots: dependencies: '@sentry/core': 10.37.0 - '@sentry/vite-plugin@5.2.0(rollup@4.60.0)': + '@sentry/vite-plugin@5.2.0(rollup@4.60.1)': dependencies: '@sentry/bundler-plugin-core': 5.2.0 - '@sentry/rollup-plugin': 5.2.0(rollup@4.60.0) + '@sentry/rollup-plugin': 5.2.0(rollup@4.60.1) transitivePeerDependencies: - encoding - rollup @@ -10732,12 +10730,12 @@ snapshots: '@tailwindcss/oxide-win32-arm64-msvc': 4.2.2 '@tailwindcss/oxide-win32-x64-msvc': 4.2.2 - '@tailwindcss/vite@4.2.2(vite@8.0.8(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))': + '@tailwindcss/vite@4.2.2(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))': dependencies: '@tailwindcss/node': 4.2.2 '@tailwindcss/oxide': 4.2.2 tailwindcss: 4.2.2 - vite: 8.0.8(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) + vite: 8.0.8(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) '@testing-library/dom@10.4.1': dependencies: @@ -10759,7 +10757,7 @@ snapshots: picocolors: 1.1.1 redent: 3.0.0 - '@testing-library/react-native@13.3.3(jest@29.7.0(@types/node@25.5.2)(ts-node@10.9.2(@types/node@25.5.2)(typescript@5.9.3)))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react-test-renderer@19.2.5(react@19.2.5))(react@19.2.5)': + '@testing-library/react-native@13.3.3(jest@29.7.0(@types/node@25.6.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react-test-renderer@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: jest-matcher-utils: 30.3.0 picocolors: 1.1.1 @@ -10769,7 +10767,7 @@ snapshots: react-test-renderer: 19.2.5(react@19.2.5) redent: 3.0.0 optionalDependencies: - jest: 29.7.0(@types/node@25.5.2)(ts-node@10.9.2(@types/node@25.5.2)(typescript@5.9.3)) + jest: 29.7.0(@types/node@25.6.0) '@testing-library/react@16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: @@ -10783,18 +10781,6 @@ snapshots: '@tootallnate/once@2.0.0': {} - '@tsconfig/node10@1.0.12': - optional: true - - '@tsconfig/node12@1.0.11': - optional: true - - '@tsconfig/node14@1.0.3': - optional: true - - '@tsconfig/node16@1.0.4': - optional: true - '@turbo/darwin-64@2.9.6': optional: true @@ -10973,7 +10959,7 @@ snapshots: '@types/connect@3.4.38': dependencies: - '@types/node': 25.5.2 + '@types/node': 25.6.0 '@types/deep-eql@4.0.2': {} @@ -10985,7 +10971,7 @@ snapshots: '@types/graceful-fs@4.1.9': dependencies: - '@types/node': 25.5.2 + '@types/node': 25.6.0 '@types/hammerjs@2.0.46': {} @@ -11006,7 +10992,7 @@ snapshots: '@types/jsdom@20.0.1': dependencies: - '@types/node': 25.5.2 + '@types/node': 25.6.0 '@types/tough-cookie': 4.0.5 parse5: 7.3.0 @@ -11022,19 +11008,19 @@ snapshots: '@types/mysql@2.15.27': dependencies: - '@types/node': 25.5.2 + '@types/node': 25.6.0 '@types/node@22.19.17': dependencies: undici-types: 6.21.0 - '@types/node@25.5.2': + '@types/node@25.6.0': dependencies: - undici-types: 7.18.2 + undici-types: 7.19.2 '@types/nodemailer@8.0.0': dependencies: - '@types/node': 25.5.2 + '@types/node': 25.6.0 '@types/pg-pool@2.0.7': dependencies: @@ -11042,7 +11028,7 @@ snapshots: '@types/pg@8.15.6': dependencies: - '@types/node': 25.5.2 + '@types/node': 25.6.0 pg-protocol: 1.13.0 pg-types: 2.2.0 @@ -11062,13 +11048,13 @@ snapshots: '@types/tedious@4.0.14': dependencies: - '@types/node': 25.5.2 + '@types/node': 25.6.0 '@types/tough-cookie@4.0.5': {} '@types/ws@8.18.1': dependencies: - '@types/node': 25.5.2 + '@types/node': 25.6.0 '@types/yargs-parser@21.0.3': {} @@ -11076,14 +11062,14 @@ snapshots: dependencies: '@types/yargs-parser': 21.0.3 - '@typescript-eslint/eslint-plugin@8.58.1(@typescript-eslint/parser@8.58.1(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3))(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/eslint-plugin@8.58.2(@typescript-eslint/parser@8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3))(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.58.1(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.58.1 - '@typescript-eslint/type-utils': 8.58.1(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/utils': 8.58.1(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.58.1 + '@typescript-eslint/parser': 8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.58.2 + '@typescript-eslint/type-utils': 8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/utils': 8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.58.2 eslint: 10.2.0(jiti@2.6.1) ignore: 7.0.5 natural-compare: 1.4.0 @@ -11092,41 +11078,41 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.58.1(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/parser@8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3)': dependencies: - '@typescript-eslint/scope-manager': 8.58.1 - '@typescript-eslint/types': 8.58.1 - '@typescript-eslint/typescript-estree': 8.58.1(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.58.1 + '@typescript-eslint/scope-manager': 8.58.2 + '@typescript-eslint/types': 8.58.2 + '@typescript-eslint/typescript-estree': 8.58.2(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.58.2 debug: 4.4.3 eslint: 10.2.0(jiti@2.6.1) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.58.1(typescript@5.9.3)': + '@typescript-eslint/project-service@8.58.2(typescript@5.9.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.58.1(typescript@5.9.3) - '@typescript-eslint/types': 8.58.1 + '@typescript-eslint/tsconfig-utils': 8.58.2(typescript@5.9.3) + '@typescript-eslint/types': 8.58.2 debug: 4.4.3 typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@8.58.1': + '@typescript-eslint/scope-manager@8.58.2': dependencies: - '@typescript-eslint/types': 8.58.1 - '@typescript-eslint/visitor-keys': 8.58.1 + '@typescript-eslint/types': 8.58.2 + '@typescript-eslint/visitor-keys': 8.58.2 - '@typescript-eslint/tsconfig-utils@8.58.1(typescript@5.9.3)': + '@typescript-eslint/tsconfig-utils@8.58.2(typescript@5.9.3)': dependencies: typescript: 5.9.3 - '@typescript-eslint/type-utils@8.58.1(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/type-utils@8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3)': dependencies: - '@typescript-eslint/types': 8.58.1 - '@typescript-eslint/typescript-estree': 8.58.1(typescript@5.9.3) - '@typescript-eslint/utils': 8.58.1(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/types': 8.58.2 + '@typescript-eslint/typescript-estree': 8.58.2(typescript@5.9.3) + '@typescript-eslint/utils': 8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3) debug: 4.4.3 eslint: 10.2.0(jiti@2.6.1) ts-api-utils: 2.5.0(typescript@5.9.3) @@ -11134,44 +11120,44 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/types@8.58.1': {} + '@typescript-eslint/types@8.58.2': {} - '@typescript-eslint/typescript-estree@8.58.1(typescript@5.9.3)': + '@typescript-eslint/typescript-estree@8.58.2(typescript@5.9.3)': dependencies: - '@typescript-eslint/project-service': 8.58.1(typescript@5.9.3) - '@typescript-eslint/tsconfig-utils': 8.58.1(typescript@5.9.3) - '@typescript-eslint/types': 8.58.1 - '@typescript-eslint/visitor-keys': 8.58.1 + '@typescript-eslint/project-service': 8.58.2(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.58.2(typescript@5.9.3) + '@typescript-eslint/types': 8.58.2 + '@typescript-eslint/visitor-keys': 8.58.2 debug: 4.4.3 - minimatch: 10.2.4 + minimatch: 10.2.5 semver: 7.7.4 - tinyglobby: 0.2.15 + tinyglobby: 0.2.16 ts-api-utils: 2.5.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.58.1(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/utils@8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3)': dependencies: '@eslint-community/eslint-utils': 4.9.1(eslint@10.2.0(jiti@2.6.1)) - '@typescript-eslint/scope-manager': 8.58.1 - '@typescript-eslint/types': 8.58.1 - '@typescript-eslint/typescript-estree': 8.58.1(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.58.2 + '@typescript-eslint/types': 8.58.2 + '@typescript-eslint/typescript-estree': 8.58.2(typescript@5.9.3) eslint: 10.2.0(jiti@2.6.1) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@8.58.1': + '@typescript-eslint/visitor-keys@8.58.2': dependencies: - '@typescript-eslint/types': 8.58.1 + '@typescript-eslint/types': 8.58.2 eslint-visitor-keys: 5.0.1 '@ungap/structured-clone@1.3.0': {} - '@vitejs/plugin-basic-ssl@2.3.0(vite@8.0.8(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))': + '@vitejs/plugin-basic-ssl@2.3.0(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))': dependencies: - vite: 8.0.8(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) + vite: 8.0.8(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) '@vitest/expect@4.1.4': dependencies: @@ -11182,13 +11168,13 @@ snapshots: chai: 6.2.2 tinyrainbow: 3.1.0 - '@vitest/mocker@4.1.4(vite@8.0.8(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))': + '@vitest/mocker@4.1.4(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))': dependencies: '@vitest/spy': 4.1.4 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 8.0.8(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) + vite: 8.0.8(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) '@vitest/pretty-format@4.1.4': dependencies: @@ -11295,9 +11281,6 @@ snapshots: normalize-path: 3.0.0 picomatch: 2.3.2 - arg@4.1.3: - optional: true - arg@5.0.2: {} argparse@1.0.10: @@ -11360,7 +11343,7 @@ snapshots: dependencies: '@babel/helper-plugin-utils': 7.28.6 '@istanbuljs/load-nyc-config': 1.1.0 - '@istanbuljs/schema': 0.1.3 + '@istanbuljs/schema': 0.1.6 istanbul-lib-instrument: 5.2.1 test-exclude: 6.0.0 transitivePeerDependencies: @@ -11487,7 +11470,7 @@ snapshots: base64-js@1.5.1: {} - baseline-browser-mapping@2.10.12: {} + baseline-browser-mapping@2.10.19: {} basic-auth@2.0.1: dependencies: @@ -11551,13 +11534,13 @@ snapshots: dependencies: fill-range: 7.1.1 - browserslist@4.28.1: + browserslist@4.28.2: dependencies: - baseline-browser-mapping: 2.10.12 - caniuse-lite: 1.0.30001781 - electron-to-chromium: 1.5.328 - node-releases: 2.0.36 - update-browserslist-db: 1.2.3(browserslist@4.28.1) + baseline-browser-mapping: 2.10.19 + caniuse-lite: 1.0.30001788 + electron-to-chromium: 1.5.336 + node-releases: 2.0.37 + update-browserslist-db: 1.2.3(browserslist@4.28.2) bser@2.1.1: dependencies: @@ -11590,7 +11573,7 @@ snapshots: camelcase@6.3.0: {} - caniuse-lite@1.0.30001781: {} + caniuse-lite@1.0.30001788: {} chai@6.2.2: {} @@ -11620,7 +11603,7 @@ snapshots: chrome-launcher@0.15.2: dependencies: - '@types/node': 25.5.2 + '@types/node': 25.6.0 escape-string-regexp: 4.0.0 is-wsl: 2.2.0 lighthouse-logger: 1.4.2 @@ -11629,7 +11612,7 @@ snapshots: chromium-edge-launcher@0.2.0: dependencies: - '@types/node': 25.5.2 + '@types/node': 25.6.0 escape-string-regexp: 4.0.0 is-wsl: 2.2.0 lighthouse-logger: 1.4.2 @@ -11755,15 +11738,15 @@ snapshots: core-js-compat@3.49.0: dependencies: - browserslist: 4.28.1 + browserslist: 4.28.2 - create-jest@29.7.0(@types/node@25.5.2)(ts-node@10.9.2(@types/node@25.5.2)(typescript@5.9.3)): + create-jest@29.7.0(@types/node@25.6.0): dependencies: '@jest/types': 29.6.3 chalk: 4.1.2 exit: 0.1.2 graceful-fs: 4.2.11 - jest-config: 29.7.0(@types/node@25.5.2)(ts-node@10.9.2(@types/node@25.5.2)(typescript@5.9.3)) + jest-config: 29.7.0(@types/node@25.6.0) jest-util: 29.7.0 prompts: 2.4.2 transitivePeerDependencies: @@ -11772,9 +11755,6 @@ snapshots: - supports-color - ts-node - create-require@1.1.1: - optional: true - crelt@1.0.6: {} cron-parser@4.9.0: @@ -11875,9 +11855,6 @@ snapshots: diff-sequences@29.6.3: {} - diff@4.0.4: - optional: true - dnssd-advertise@1.1.4: {} dom-accessibility-api@0.5.16: {} @@ -11935,7 +11912,7 @@ snapshots: ee-first@1.1.1: {} - electron-to-chromium@1.5.328: {} + electron-to-chromium@1.5.336: {} emittery@0.13.1: {} @@ -11952,7 +11929,7 @@ snapshots: enhanced-resolve@5.20.1: dependencies: graceful-fs: 4.2.11 - tapable: 2.3.0 + tapable: 2.3.2 entities@4.5.0: {} @@ -12041,34 +12018,34 @@ snapshots: '@esbuild/win32-ia32': 0.25.12 '@esbuild/win32-x64': 0.25.12 - esbuild@0.27.4: + esbuild@0.27.7: optionalDependencies: - '@esbuild/aix-ppc64': 0.27.4 - '@esbuild/android-arm': 0.27.4 - '@esbuild/android-arm64': 0.27.4 - '@esbuild/android-x64': 0.27.4 - '@esbuild/darwin-arm64': 0.27.4 - '@esbuild/darwin-x64': 0.27.4 - '@esbuild/freebsd-arm64': 0.27.4 - '@esbuild/freebsd-x64': 0.27.4 - '@esbuild/linux-arm': 0.27.4 - '@esbuild/linux-arm64': 0.27.4 - '@esbuild/linux-ia32': 0.27.4 - '@esbuild/linux-loong64': 0.27.4 - '@esbuild/linux-mips64el': 0.27.4 - '@esbuild/linux-ppc64': 0.27.4 - '@esbuild/linux-riscv64': 0.27.4 - '@esbuild/linux-s390x': 0.27.4 - '@esbuild/linux-x64': 0.27.4 - '@esbuild/netbsd-arm64': 0.27.4 - '@esbuild/netbsd-x64': 0.27.4 - '@esbuild/openbsd-arm64': 0.27.4 - '@esbuild/openbsd-x64': 0.27.4 - '@esbuild/openharmony-arm64': 0.27.4 - '@esbuild/sunos-x64': 0.27.4 - '@esbuild/win32-arm64': 0.27.4 - '@esbuild/win32-ia32': 0.27.4 - '@esbuild/win32-x64': 0.27.4 + '@esbuild/aix-ppc64': 0.27.7 + '@esbuild/android-arm': 0.27.7 + '@esbuild/android-arm64': 0.27.7 + '@esbuild/android-x64': 0.27.7 + '@esbuild/darwin-arm64': 0.27.7 + '@esbuild/darwin-x64': 0.27.7 + '@esbuild/freebsd-arm64': 0.27.7 + '@esbuild/freebsd-x64': 0.27.7 + '@esbuild/linux-arm': 0.27.7 + '@esbuild/linux-arm64': 0.27.7 + '@esbuild/linux-ia32': 0.27.7 + '@esbuild/linux-loong64': 0.27.7 + '@esbuild/linux-mips64el': 0.27.7 + '@esbuild/linux-ppc64': 0.27.7 + '@esbuild/linux-riscv64': 0.27.7 + '@esbuild/linux-s390x': 0.27.7 + '@esbuild/linux-x64': 0.27.7 + '@esbuild/netbsd-arm64': 0.27.7 + '@esbuild/netbsd-x64': 0.27.7 + '@esbuild/openbsd-arm64': 0.27.7 + '@esbuild/openbsd-x64': 0.27.7 + '@esbuild/openharmony-arm64': 0.27.7 + '@esbuild/sunos-x64': 0.27.7 + '@esbuild/win32-arm64': 0.27.7 + '@esbuild/win32-ia32': 0.27.7 + '@esbuild/win32-x64': 0.27.7 escalade@3.2.0: {} @@ -12107,10 +12084,10 @@ snapshots: dependencies: '@eslint-community/eslint-utils': 4.9.1(eslint@10.2.0(jiti@2.6.1)) '@eslint-community/regexpp': 4.12.2 - '@eslint/config-array': 0.23.4 - '@eslint/config-helpers': 0.5.4 - '@eslint/core': 1.2.0 - '@eslint/plugin-kit': 0.7.0 + '@eslint/config-array': 0.23.5 + '@eslint/config-helpers': 0.5.5 + '@eslint/core': 1.2.1 + '@eslint/plugin-kit': 0.7.1 '@humanfs/node': 0.16.7 '@humanwhocodes/module-importer': 1.0.1 '@humanwhocodes/retry': 0.4.3 @@ -12132,7 +12109,7 @@ snapshots: imurmurhash: 0.1.4 is-glob: 4.0.3 json-stable-stringify-without-jsonify: 1.0.1 - minimatch: 10.2.4 + minimatch: 10.2.5 natural-compare: 1.4.0 optionator: 0.9.4 optionalDependencies: @@ -12318,7 +12295,7 @@ snapshots: expo-manifests@55.0.15(expo@55.0.15)(typescript@5.9.3): dependencies: - '@expo/config': 55.0.14(typescript@5.9.3) + '@expo/config': 55.0.15(typescript@5.9.3) expo: 55.0.15(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) expo-json-utils: 55.0.2 transitivePeerDependencies: @@ -12367,16 +12344,16 @@ snapshots: - supports-color - typescript - expo-router@55.0.12(2abaf9bed2da34a074803b38a8556f5d): + expo-router@55.0.12(967bbc80afd40466d8ec2b5429609e86): dependencies: '@expo/log-box': 55.0.10(@expo/dom-webview@55.0.5)(expo@55.0.15)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) '@expo/metro-runtime': 55.0.9(@expo/dom-webview@55.0.5)(expo@55.0.15)(react-dom@19.2.5(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) '@expo/schema-utils': 55.0.3 - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.5) + '@radix-ui/react-slot': 1.2.4(@types/react@19.2.14)(react@19.2.5) '@radix-ui/react-tabs': 1.1.13(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@react-navigation/bottom-tabs': 7.15.9(@react-navigation/native@7.2.2(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native-safe-area-context@5.6.2(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native-screens@4.23.0(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) '@react-navigation/native': 7.2.2(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) - '@react-navigation/native-stack': 7.14.10(@react-navigation/native@7.2.2(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native-safe-area-context@5.6.2(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native-screens@4.23.0(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + '@react-navigation/native-stack': 7.14.11(@react-navigation/native@7.2.2(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native-safe-area-context@5.6.2(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native-screens@4.23.0(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) client-only: 0.0.1 debug: 4.4.3 escape-string-regexp: 4.0.0 @@ -12404,7 +12381,7 @@ snapshots: use-latest-callback: 0.2.6(react@19.2.5) vaul: 1.1.2(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) optionalDependencies: - '@testing-library/react-native': 13.3.3(jest@29.7.0(@types/node@25.5.2)(ts-node@10.9.2(@types/node@25.5.2)(typescript@5.9.3)))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react-test-renderer@19.2.5(react@19.2.5))(react@19.2.5) + '@testing-library/react-native': 13.3.3(jest@29.7.0(@types/node@25.6.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react-test-renderer@19.2.5(react@19.2.5))(react@19.2.5) react-dom: 19.2.5(react@19.2.5) react-native-gesture-handler: 2.31.1(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) react-native-reanimated: 4.3.0(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) @@ -12444,7 +12421,7 @@ snapshots: expo-symbols@55.0.7(expo-font@55.0.6)(expo@55.0.15)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5): dependencies: - '@expo-google-fonts/material-symbols': 0.4.30 + '@expo-google-fonts/material-symbols': 0.4.31 expo: 55.0.15(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.9)(expo-router@55.0.12)(react-dom@19.2.5(react@19.2.5))(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3) expo-font: 55.0.6(expo@55.0.15)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) react: 19.2.5 @@ -12551,7 +12528,7 @@ snapshots: exsolve@1.0.8: {} - fast-copy@4.0.2: {} + fast-copy@4.0.3: {} fast-deep-equal@3.1.3: {} @@ -12686,7 +12663,7 @@ snapshots: get-stream@6.0.1: {} - get-tsconfig@4.13.7: + get-tsconfig@4.13.8: dependencies: resolve-pkg-maps: 1.0.0 @@ -12698,7 +12675,7 @@ snapshots: glob@13.0.6: dependencies: - minimatch: 10.2.4 + minimatch: 10.2.5 minipass: 7.1.3 path-scurry: 2.0.2 @@ -12857,7 +12834,7 @@ snapshots: cjs-module-lexer: 2.2.0 module-details-from-path: 1.0.4 - import-in-the-middle@3.0.0: + import-in-the-middle@3.0.1: dependencies: acorn: 8.16.0 acorn-import-attributes: 1.9.5(acorn@8.16.0) @@ -12916,7 +12893,7 @@ snapshots: dependencies: is-docker: 2.2.1 - isbot@5.1.37: {} + isbot@5.1.38: {} isexe@2.0.0: {} @@ -12928,7 +12905,7 @@ snapshots: dependencies: '@babel/core': 7.29.0 '@babel/parser': 7.29.2 - '@istanbuljs/schema': 0.1.3 + '@istanbuljs/schema': 0.1.6 istanbul-lib-coverage: 3.2.2 semver: 6.3.1 transitivePeerDependencies: @@ -12938,7 +12915,7 @@ snapshots: dependencies: '@babel/core': 7.29.0 '@babel/parser': 7.29.2 - '@istanbuljs/schema': 0.1.3 + '@istanbuljs/schema': 0.1.6 istanbul-lib-coverage: 3.2.2 semver: 7.7.4 transitivePeerDependencies: @@ -12975,7 +12952,7 @@ snapshots: '@jest/expect': 29.7.0 '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 25.5.2 + '@types/node': 25.6.0 chalk: 4.1.2 co: 4.6.0 dedent: 1.7.2 @@ -12995,16 +12972,16 @@ snapshots: - babel-plugin-macros - supports-color - jest-cli@29.7.0(@types/node@25.5.2)(ts-node@10.9.2(@types/node@25.5.2)(typescript@5.9.3)): + jest-cli@29.7.0(@types/node@25.6.0): dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@25.5.2)(typescript@5.9.3)) + '@jest/core': 29.7.0 '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 chalk: 4.1.2 - create-jest: 29.7.0(@types/node@25.5.2)(ts-node@10.9.2(@types/node@25.5.2)(typescript@5.9.3)) + create-jest: 29.7.0(@types/node@25.6.0) exit: 0.1.2 import-local: 3.2.0 - jest-config: 29.7.0(@types/node@25.5.2)(ts-node@10.9.2(@types/node@25.5.2)(typescript@5.9.3)) + jest-config: 29.7.0(@types/node@25.6.0) jest-util: 29.7.0 jest-validate: 29.7.0 yargs: 17.7.2 @@ -13014,7 +12991,7 @@ snapshots: - supports-color - ts-node - jest-config@29.7.0(@types/node@25.5.2)(ts-node@10.9.2(@types/node@25.5.2)(typescript@5.9.3)): + jest-config@29.7.0(@types/node@25.6.0): dependencies: '@babel/core': 7.29.0 '@jest/test-sequencer': 29.7.0 @@ -13039,8 +13016,7 @@ snapshots: slash: 3.0.0 strip-json-comments: 3.1.1 optionalDependencies: - '@types/node': 25.5.2 - ts-node: 10.9.2(@types/node@25.5.2)(typescript@5.9.3) + '@types/node': 25.6.0 transitivePeerDependencies: - babel-plugin-macros - supports-color @@ -13077,7 +13053,7 @@ snapshots: '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 '@types/jsdom': 20.0.1 - '@types/node': 25.5.2 + '@types/node': 25.6.0 jest-mock: 29.7.0 jest-util: 29.7.0 jsdom: 20.0.3 @@ -13091,13 +13067,13 @@ snapshots: '@jest/environment': 29.7.0 '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 25.5.2 + '@types/node': 25.6.0 jest-mock: 29.7.0 jest-util: 29.7.0 - jest-expo@55.0.15(@babel/core@7.29.0)(expo@55.0.15)(jest@29.7.0(@types/node@25.5.2)(ts-node@10.9.2(@types/node@25.5.2)(typescript@5.9.3)))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3): + jest-expo@55.0.16(@babel/core@7.29.0)(expo@55.0.15)(jest@29.7.0(@types/node@25.6.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3): dependencies: - '@expo/config': 55.0.14(typescript@5.9.3) + '@expo/config': 55.0.15(typescript@5.9.3) '@expo/json-file': 10.0.13 '@jest/create-cache-key-function': 29.7.0 '@jest/globals': 29.7.0 @@ -13106,7 +13082,7 @@ snapshots: jest-environment-jsdom: 29.7.0 jest-snapshot: 29.7.0 jest-watch-select-projects: 2.0.0 - jest-watch-typeahead: 2.2.1(jest@29.7.0(@types/node@25.5.2)(ts-node@10.9.2(@types/node@25.5.2)(typescript@5.9.3))) + jest-watch-typeahead: 2.2.1(jest@29.7.0(@types/node@25.6.0)) json5: 2.2.3 lodash: 4.18.1 react-native: 0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5) @@ -13129,7 +13105,7 @@ snapshots: dependencies: '@jest/types': 29.6.3 '@types/graceful-fs': 4.1.9 - '@types/node': 25.5.2 + '@types/node': 25.6.0 anymatch: 3.1.3 fb-watchman: 2.0.2 graceful-fs: 4.2.11 @@ -13175,7 +13151,7 @@ snapshots: jest-mock@29.7.0: dependencies: '@jest/types': 29.6.3 - '@types/node': 25.5.2 + '@types/node': 25.6.0 jest-util: 29.7.0 jest-pnp-resolver@1.2.3(jest-resolve@29.7.0): @@ -13210,7 +13186,7 @@ snapshots: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 25.5.2 + '@types/node': 25.6.0 chalk: 4.1.2 emittery: 0.13.1 graceful-fs: 4.2.11 @@ -13238,7 +13214,7 @@ snapshots: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 25.5.2 + '@types/node': 25.6.0 chalk: 4.1.2 cjs-module-lexer: 1.4.3 collect-v8-coverage: 1.0.3 @@ -13284,7 +13260,7 @@ snapshots: jest-util@29.7.0: dependencies: '@jest/types': 29.6.3 - '@types/node': 25.5.2 + '@types/node': 25.6.0 chalk: 4.1.2 ci-info: 3.9.0 graceful-fs: 4.2.11 @@ -13305,11 +13281,11 @@ snapshots: chalk: 3.0.0 prompts: 2.4.2 - jest-watch-typeahead@2.2.1(jest@29.7.0(@types/node@25.5.2)(ts-node@10.9.2(@types/node@25.5.2)(typescript@5.9.3))): + jest-watch-typeahead@2.2.1(jest@29.7.0(@types/node@25.6.0)): dependencies: ansi-escapes: 6.2.1 chalk: 4.1.2 - jest: 29.7.0(@types/node@25.5.2)(ts-node@10.9.2(@types/node@25.5.2)(typescript@5.9.3)) + jest: 29.7.0(@types/node@25.6.0) jest-regex-util: 29.6.3 jest-watcher: 29.7.0 slash: 5.1.0 @@ -13320,7 +13296,7 @@ snapshots: dependencies: '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 25.5.2 + '@types/node': 25.6.0 ansi-escapes: 4.3.2 chalk: 4.1.2 emittery: 0.13.1 @@ -13329,17 +13305,17 @@ snapshots: jest-worker@29.7.0: dependencies: - '@types/node': 25.5.2 + '@types/node': 25.6.0 jest-util: 29.7.0 merge-stream: 2.0.0 supports-color: 8.1.1 - jest@29.7.0(@types/node@25.5.2)(ts-node@10.9.2(@types/node@25.5.2)(typescript@5.9.3)): + jest@29.7.0(@types/node@25.6.0): dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@25.5.2)(typescript@5.9.3)) + '@jest/core': 29.7.0 '@jest/types': 29.6.3 import-local: 3.2.0 - jest-cli: 29.7.0(@types/node@25.5.2)(ts-node@10.9.2(@types/node@25.5.2)(typescript@5.9.3)) + jest-cli: 29.7.0(@types/node@25.6.0) transitivePeerDependencies: - '@types/node' - babel-plugin-macros @@ -13402,22 +13378,22 @@ snapshots: jsdom@29.0.2: dependencies: - '@asamuzakjp/css-color': 5.1.9 + '@asamuzakjp/css-color': 5.1.10 '@asamuzakjp/dom-selector': 7.0.9 '@bramus/specificity': 2.4.2 - '@csstools/css-syntax-patches-for-csstree': 1.1.1(css-tree@3.2.1) + '@csstools/css-syntax-patches-for-csstree': 1.1.3(css-tree@3.2.1) '@exodus/bytes': 1.15.0 css-tree: 3.2.1 data-urls: 7.0.0 decimal.js: 10.6.0 html-encoding-sniffer: 6.0.0 is-potential-custom-element-name: 1.0.1 - lru-cache: 11.2.7 + lru-cache: 11.3.5 parse5: 8.0.0 saxes: 6.0.0 symbol-tree: 3.2.4 tough-cookie: 6.0.1 - undici: 7.24.5 + undici: 7.25.0 w3c-xmlserializer: 5.0.0 webidl-conversions: 8.0.1 whatwg-mimetype: 5.0.0 @@ -13555,7 +13531,7 @@ snapshots: lru-cache@10.4.3: {} - lru-cache@11.2.7: {} + lru-cache@11.3.5: {} lru-cache@5.1.1: dependencies: @@ -13573,9 +13549,6 @@ snapshots: dependencies: semver: 7.7.4 - make-error@1.3.6: - optional: true - makeerror@1.0.12: dependencies: tmpl: 1.0.5 @@ -13605,6 +13578,16 @@ snapshots: transitivePeerDependencies: - supports-color + metro-babel-transformer@0.83.6: + dependencies: + '@babel/core': 7.29.0 + flow-enums-runtime: 0.0.6 + hermes-parser: 0.35.0 + metro-cache-key: 0.83.6 + nullthrows: 1.1.1 + transitivePeerDependencies: + - supports-color + metro-babel-transformer@0.84.3: dependencies: '@babel/core': 7.29.0 @@ -13619,6 +13602,10 @@ snapshots: dependencies: flow-enums-runtime: 0.0.6 + metro-cache-key@0.83.6: + dependencies: + flow-enums-runtime: 0.0.6 + metro-cache-key@0.84.3: dependencies: flow-enums-runtime: 0.0.6 @@ -13632,6 +13619,15 @@ snapshots: transitivePeerDependencies: - supports-color + metro-cache@0.83.6: + dependencies: + exponential-backoff: 3.1.3 + flow-enums-runtime: 0.0.6 + https-proxy-agent: 7.0.6 + metro-core: 0.83.6 + transitivePeerDependencies: + - supports-color + metro-cache@0.84.3: dependencies: exponential-backoff: 3.1.3 @@ -13656,6 +13652,21 @@ snapshots: - supports-color - utf-8-validate + metro-config@0.83.6: + dependencies: + connect: 3.7.0 + flow-enums-runtime: 0.0.6 + jest-validate: 29.7.0 + metro: 0.83.6 + metro-cache: 0.83.6 + metro-core: 0.83.6 + metro-runtime: 0.83.6 + yaml: 2.8.3 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + metro-config@0.84.3: dependencies: connect: 3.7.0 @@ -13677,6 +13688,12 @@ snapshots: lodash.throttle: 4.1.1 metro-resolver: 0.83.5 + metro-core@0.83.6: + dependencies: + flow-enums-runtime: 0.0.6 + lodash.throttle: 4.1.1 + metro-resolver: 0.83.6 + metro-core@0.84.3: dependencies: flow-enums-runtime: 0.0.6 @@ -13697,6 +13714,20 @@ snapshots: transitivePeerDependencies: - supports-color + metro-file-map@0.83.6: + dependencies: + debug: 4.4.3 + fb-watchman: 2.0.2 + flow-enums-runtime: 0.0.6 + graceful-fs: 4.2.11 + invariant: 2.2.4 + jest-worker: 29.7.0 + micromatch: 4.0.8 + nullthrows: 1.1.1 + walker: 1.0.8 + transitivePeerDependencies: + - supports-color + metro-file-map@0.84.3: dependencies: debug: 4.4.3 @@ -13716,6 +13747,11 @@ snapshots: flow-enums-runtime: 0.0.6 terser: 5.46.1 + metro-minify-terser@0.83.6: + dependencies: + flow-enums-runtime: 0.0.6 + terser: 5.46.1 + metro-minify-terser@0.84.3: dependencies: flow-enums-runtime: 0.0.6 @@ -13725,6 +13761,10 @@ snapshots: dependencies: flow-enums-runtime: 0.0.6 + metro-resolver@0.83.6: + dependencies: + flow-enums-runtime: 0.0.6 + metro-resolver@0.84.3: dependencies: flow-enums-runtime: 0.0.6 @@ -13734,6 +13774,11 @@ snapshots: '@babel/runtime': 7.29.2 flow-enums-runtime: 0.0.6 + metro-runtime@0.83.6: + dependencies: + '@babel/runtime': 7.29.2 + flow-enums-runtime: 0.0.6 + metro-runtime@0.84.3: dependencies: '@babel/runtime': 7.29.2 @@ -13753,6 +13798,20 @@ snapshots: transitivePeerDependencies: - supports-color + metro-source-map@0.83.6: + dependencies: + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + flow-enums-runtime: 0.0.6 + invariant: 2.2.4 + metro-symbolicate: 0.83.6 + nullthrows: 1.1.1 + ob1: 0.83.6 + source-map: 0.5.7 + vlq: 1.0.1 + transitivePeerDependencies: + - supports-color + metro-source-map@0.84.3: dependencies: '@babel/traverse': 7.29.0 @@ -13778,6 +13837,17 @@ snapshots: transitivePeerDependencies: - supports-color + metro-symbolicate@0.83.6: + dependencies: + flow-enums-runtime: 0.0.6 + invariant: 2.2.4 + metro-source-map: 0.83.6 + nullthrows: 1.1.1 + source-map: 0.5.7 + vlq: 1.0.1 + transitivePeerDependencies: + - supports-color + metro-symbolicate@0.84.3: dependencies: flow-enums-runtime: 0.0.6 @@ -13800,6 +13870,17 @@ snapshots: transitivePeerDependencies: - supports-color + metro-transform-plugins@0.83.6: + dependencies: + '@babel/core': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/template': 7.28.6 + '@babel/traverse': 7.29.0 + flow-enums-runtime: 0.0.6 + nullthrows: 1.1.1 + transitivePeerDependencies: + - supports-color + metro-transform-plugins@0.84.3: dependencies: '@babel/core': 7.29.0 @@ -13831,6 +13912,26 @@ snapshots: - supports-color - utf-8-validate + metro-transform-worker@0.83.6: + dependencies: + '@babel/core': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/parser': 7.29.2 + '@babel/types': 7.29.0 + flow-enums-runtime: 0.0.6 + metro: 0.83.6 + metro-babel-transformer: 0.83.6 + metro-cache: 0.83.6 + metro-cache-key: 0.83.6 + metro-minify-terser: 0.83.6 + metro-source-map: 0.83.6 + metro-transform-plugins: 0.83.6 + nullthrows: 1.1.1 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + metro-transform-worker@0.84.3: dependencies: '@babel/core': 7.29.0 @@ -13898,6 +13999,53 @@ snapshots: - supports-color - utf-8-validate + metro@0.83.6: + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/core': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/parser': 7.29.2 + '@babel/template': 7.28.6 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + accepts: 2.0.0 + chalk: 4.1.2 + ci-info: 2.0.0 + connect: 3.7.0 + debug: 4.4.3 + error-stack-parser: 2.1.4 + flow-enums-runtime: 0.0.6 + graceful-fs: 4.2.11 + hermes-parser: 0.35.0 + image-size: 1.2.1 + invariant: 2.2.4 + jest-worker: 29.7.0 + jsc-safe-url: 0.2.4 + lodash.throttle: 4.1.1 + metro-babel-transformer: 0.83.6 + metro-cache: 0.83.6 + metro-cache-key: 0.83.6 + metro-config: 0.83.6 + metro-core: 0.83.6 + metro-file-map: 0.83.6 + metro-resolver: 0.83.6 + metro-runtime: 0.83.6 + metro-source-map: 0.83.6 + metro-symbolicate: 0.83.6 + metro-transform-plugins: 0.83.6 + metro-transform-worker: 0.83.6 + mime-types: 3.0.2 + nullthrows: 1.1.1 + serialize-error: 2.1.0 + source-map: 0.5.7 + throat: 5.0.0 + ws: 7.5.10 + yargs: 17.7.2 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + metro@0.84.3: dependencies: '@babel/code-frame': 7.29.0 @@ -13970,7 +14118,7 @@ snapshots: min-indent@1.0.1: {} - minimatch@10.2.4: + minimatch@10.2.5: dependencies: brace-expansion: 5.0.5 @@ -14020,7 +14168,7 @@ snapshots: node-int64@0.4.0: {} - node-releases@2.0.36: {} + node-releases@2.0.37: {} nodemailer@8.0.5: {} @@ -14049,6 +14197,10 @@ snapshots: dependencies: flow-enums-runtime: 0.0.6 + ob1@0.83.6: + dependencies: + flow-enums-runtime: 0.0.6 + ob1@0.84.3: dependencies: flow-enums-runtime: 0.0.6 @@ -14161,7 +14313,7 @@ snapshots: path-scurry@2.0.2: dependencies: - lru-cache: 11.2.7 + lru-cache: 11.3.5 minipass: 7.1.3 path-to-regexp@0.1.13: {} @@ -14227,7 +14379,7 @@ snapshots: dependencies: colorette: 2.0.20 dateformat: 4.6.3 - fast-copy: 4.0.2 + fast-copy: 4.0.3 fast-safe-stringify: 2.1.1 help-me: 5.0.0 joycon: 3.1.1 @@ -14298,7 +14450,7 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 - postcss@8.5.8: + postcss@8.5.9: dependencies: nanoid: 3.3.11 picocolors: 1.1.1 @@ -14437,7 +14589,7 @@ snapshots: dependencies: react: 19.2.5 - react-i18next@17.0.2(i18next@26.0.4(typescript@5.9.3))(react-dom@19.2.5(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3): + react-i18next@17.0.3(i18next@26.0.4(typescript@5.9.3))(react-dom@19.2.5(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)(typescript@5.9.3): dependencies: '@babel/runtime': 7.29.2 html-parse-stringify: 3.0.1 @@ -14541,8 +14693,8 @@ snapshots: invariant: 2.2.4 jest-environment-node: 29.7.0 memoize-one: 5.2.1 - metro-runtime: 0.83.5 - metro-source-map: 0.83.5 + metro-runtime: 0.83.6 + metro-source-map: 0.83.6 nullthrows: 1.1.1 pretty-format: 29.7.0 promise: 8.3.0 @@ -14587,7 +14739,7 @@ snapshots: optionalDependencies: '@types/react': 19.2.14 - react-router@7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5): + react-router@7.14.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5): dependencies: cookie: 1.1.1 react: 19.2.5 @@ -14715,35 +14867,35 @@ snapshots: '@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.15 '@rolldown/binding-win32-x64-msvc': 1.0.0-rc.15 - rollup@4.60.0: + rollup@4.60.1: dependencies: '@types/estree': 1.0.8 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.60.0 - '@rollup/rollup-android-arm64': 4.60.0 - '@rollup/rollup-darwin-arm64': 4.60.0 - '@rollup/rollup-darwin-x64': 4.60.0 - '@rollup/rollup-freebsd-arm64': 4.60.0 - '@rollup/rollup-freebsd-x64': 4.60.0 - '@rollup/rollup-linux-arm-gnueabihf': 4.60.0 - '@rollup/rollup-linux-arm-musleabihf': 4.60.0 - '@rollup/rollup-linux-arm64-gnu': 4.60.0 - '@rollup/rollup-linux-arm64-musl': 4.60.0 - '@rollup/rollup-linux-loong64-gnu': 4.60.0 - '@rollup/rollup-linux-loong64-musl': 4.60.0 - '@rollup/rollup-linux-ppc64-gnu': 4.60.0 - '@rollup/rollup-linux-ppc64-musl': 4.60.0 - '@rollup/rollup-linux-riscv64-gnu': 4.60.0 - '@rollup/rollup-linux-riscv64-musl': 4.60.0 - '@rollup/rollup-linux-s390x-gnu': 4.60.0 - '@rollup/rollup-linux-x64-gnu': 4.60.0 - '@rollup/rollup-linux-x64-musl': 4.60.0 - '@rollup/rollup-openbsd-x64': 4.60.0 - '@rollup/rollup-openharmony-arm64': 4.60.0 - '@rollup/rollup-win32-arm64-msvc': 4.60.0 - '@rollup/rollup-win32-ia32-msvc': 4.60.0 - '@rollup/rollup-win32-x64-gnu': 4.60.0 - '@rollup/rollup-win32-x64-msvc': 4.60.0 + '@rollup/rollup-android-arm-eabi': 4.60.1 + '@rollup/rollup-android-arm64': 4.60.1 + '@rollup/rollup-darwin-arm64': 4.60.1 + '@rollup/rollup-darwin-x64': 4.60.1 + '@rollup/rollup-freebsd-arm64': 4.60.1 + '@rollup/rollup-freebsd-x64': 4.60.1 + '@rollup/rollup-linux-arm-gnueabihf': 4.60.1 + '@rollup/rollup-linux-arm-musleabihf': 4.60.1 + '@rollup/rollup-linux-arm64-gnu': 4.60.1 + '@rollup/rollup-linux-arm64-musl': 4.60.1 + '@rollup/rollup-linux-loong64-gnu': 4.60.1 + '@rollup/rollup-linux-loong64-musl': 4.60.1 + '@rollup/rollup-linux-ppc64-gnu': 4.60.1 + '@rollup/rollup-linux-ppc64-musl': 4.60.1 + '@rollup/rollup-linux-riscv64-gnu': 4.60.1 + '@rollup/rollup-linux-riscv64-musl': 4.60.1 + '@rollup/rollup-linux-s390x-gnu': 4.60.1 + '@rollup/rollup-linux-x64-gnu': 4.60.1 + '@rollup/rollup-linux-x64-musl': 4.60.1 + '@rollup/rollup-openbsd-x64': 4.60.1 + '@rollup/rollup-openharmony-arm64': 4.60.1 + '@rollup/rollup-win32-arm64-msvc': 4.60.1 + '@rollup/rollup-win32-ia32-msvc': 4.60.1 + '@rollup/rollup-win32-x64-gnu': 4.60.1 + '@rollup/rollup-win32-x64-msvc': 4.60.1 fsevents: 2.3.3 rtl-detect@1.1.2: {} @@ -14823,7 +14975,7 @@ snapshots: shell-quote@1.8.3: {} - side-channel-list@1.0.0: + side-channel-list@1.0.1: dependencies: es-errors: 1.3.0 object-inspect: 1.13.4 @@ -14847,7 +14999,7 @@ snapshots: dependencies: es-errors: 1.3.0 object-inspect: 1.13.4 - side-channel-list: 1.0.0 + side-channel-list: 1.0.1 side-channel-map: 1.0.1 side-channel-weakmap: 1.0.2 @@ -15011,7 +15163,7 @@ snapshots: tailwindcss@4.2.2: {} - tapable@2.3.0: {} + tapable@2.3.2: {} tdigest@0.1.2: dependencies: @@ -15031,7 +15183,7 @@ snapshots: test-exclude@6.0.0: dependencies: - '@istanbuljs/schema': 0.1.3 + '@istanbuljs/schema': 0.1.6 glob: 7.2.3 minimatch: 3.1.5 @@ -15043,9 +15195,9 @@ snapshots: tinybench@2.9.0: {} - tinyexec@1.0.4: {} + tinyexec@1.1.1: {} - tinyglobby@0.2.15: + tinyglobby@0.2.16: dependencies: fdir: 6.5.0(picomatch@4.0.4) picomatch: 4.0.4 @@ -15054,11 +15206,11 @@ snapshots: tinyrainbow@3.1.0: {} - tldts-core@7.0.27: {} + tldts-core@7.0.28: {} - tldts@7.0.27: + tldts@7.0.28: dependencies: - tldts-core: 7.0.27 + tldts-core: 7.0.28 tmpl@1.0.5: {} @@ -15079,7 +15231,7 @@ snapshots: tough-cookie@6.0.1: dependencies: - tldts: 7.0.27 + tldts: 7.0.28 tr46@0.0.3: {} @@ -15095,33 +15247,14 @@ snapshots: dependencies: typescript: 5.9.3 - ts-node@10.9.2(@types/node@25.5.2)(typescript@5.9.3): - dependencies: - '@cspotcode/source-map-support': 0.8.1 - '@tsconfig/node10': 1.0.12 - '@tsconfig/node12': 1.0.11 - '@tsconfig/node14': 1.0.3 - '@tsconfig/node16': 1.0.4 - '@types/node': 25.5.2 - acorn: 8.16.0 - acorn-walk: 8.3.5 - arg: 4.1.3 - create-require: 1.1.1 - diff: 4.0.4 - make-error: 1.3.6 - typescript: 5.9.3 - v8-compile-cache-lib: 3.0.1 - yn: 3.1.1 - optional: true - tslib@1.14.1: {} tslib@2.8.1: {} tsx@4.21.0: dependencies: - esbuild: 0.27.4 - get-tsconfig: 4.13.7 + esbuild: 0.27.7 + get-tsconfig: 4.13.8 optionalDependencies: fsevents: 2.3.3 @@ -15155,12 +15288,12 @@ snapshots: media-typer: 0.3.0 mime-types: 2.1.35 - typescript-eslint@8.58.1(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3): + typescript-eslint@8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.58.1(@typescript-eslint/parser@8.58.1(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3))(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/parser': 8.58.1(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/typescript-estree': 8.58.1(typescript@5.9.3) - '@typescript-eslint/utils': 8.58.1(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/eslint-plugin': 8.58.2(@typescript-eslint/parser@8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3))(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/parser': 8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/typescript-estree': 8.58.2(typescript@5.9.3) + '@typescript-eslint/utils': 8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3) eslint: 10.2.0(jiti@2.6.1) typescript: 5.9.3 transitivePeerDependencies: @@ -15174,11 +15307,11 @@ snapshots: undici-types@6.21.0: {} - undici-types@7.18.2: {} + undici-types@7.19.2: {} - undici@6.24.1: {} + undici@6.25.0: {} - undici@7.24.5: {} + undici@7.25.0: {} unicode-canonical-property-names-ecmascript@2.0.1: {} @@ -15195,9 +15328,9 @@ snapshots: unpipe@1.0.0: {} - update-browserslist-db@1.2.3(browserslist@4.28.1): + update-browserslist-db@1.2.3(browserslist@4.28.2): dependencies: - browserslist: 4.28.1 + browserslist: 4.28.2 escalade: 3.2.0 picocolors: 1.1.1 @@ -15241,9 +15374,6 @@ snapshots: uuid@7.0.3: {} - v8-compile-cache-lib@3.0.1: - optional: true - v8-to-istanbul@9.3.0: dependencies: '@jridgewell/trace-mapping': 0.3.31 @@ -15267,13 +15397,13 @@ snapshots: - '@types/react' - '@types/react-dom' - vite-node@3.2.4(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3): + vite-node@3.2.4(@types/node@25.6.0)(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3): dependencies: cac: 6.7.14 debug: 4.4.3 es-module-lexer: 1.7.0 pathe: 2.0.3 - vite: 6.4.2(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) + vite: 7.3.2(@types/node@25.6.0)(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) transitivePeerDependencies: - '@types/node' - jiti @@ -15288,16 +15418,16 @@ snapshots: - tsx - yaml - vite@6.4.2(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3): + vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3): dependencies: - esbuild: 0.25.12 + esbuild: 0.27.7 fdir: 6.5.0(picomatch@4.0.4) picomatch: 4.0.4 - postcss: 8.5.8 - rollup: 4.60.0 - tinyglobby: 0.2.15 + postcss: 8.5.9 + rollup: 4.60.1 + tinyglobby: 0.2.16 optionalDependencies: - '@types/node': 25.5.2 + '@types/node': 25.6.0 fsevents: 2.3.3 jiti: 2.6.1 lightningcss: 1.32.0 @@ -15305,26 +15435,26 @@ snapshots: tsx: 4.21.0 yaml: 2.8.3 - vite@8.0.8(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3): + vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3): dependencies: lightningcss: 1.32.0 picomatch: 4.0.4 - postcss: 8.5.8 + postcss: 8.5.9 rolldown: 1.0.0-rc.15 - tinyglobby: 0.2.15 + tinyglobby: 0.2.16 optionalDependencies: - '@types/node': 25.5.2 - esbuild: 0.27.4 + '@types/node': 25.6.0 + esbuild: 0.27.7 fsevents: 2.3.3 jiti: 2.6.1 terser: 5.46.1 tsx: 4.21.0 yaml: 2.8.3 - vitest@4.1.4(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(jsdom@29.0.2)(vite@8.0.8(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): + vitest@4.1.4(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(jsdom@29.0.2)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): dependencies: '@vitest/expect': 4.1.4 - '@vitest/mocker': 4.1.4(vite@8.0.8(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) + '@vitest/mocker': 4.1.4(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) '@vitest/pretty-format': 4.1.4 '@vitest/runner': 4.1.4 '@vitest/snapshot': 4.1.4 @@ -15338,14 +15468,14 @@ snapshots: picomatch: 4.0.4 std-env: 4.0.0 tinybench: 2.9.0 - tinyexec: 1.0.4 - tinyglobby: 0.2.15 + tinyexec: 1.1.1 + tinyglobby: 0.2.16 tinyrainbow: 3.1.0 - vite: 8.0.8(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) + vite: 8.0.8(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) why-is-node-running: 2.3.0 optionalDependencies: '@opentelemetry/api': 1.9.1 - '@types/node': 25.5.2 + '@types/node': 25.6.0 jsdom: 29.0.2 transitivePeerDependencies: - msw @@ -15421,7 +15551,7 @@ snapshots: wkx@0.5.0: dependencies: - '@types/node': 25.5.2 + '@types/node': 25.6.0 word-wrap@1.2.5: {} @@ -15504,9 +15634,6 @@ snapshots: dependencies: lib0: 0.2.117 - yn@3.1.1: - optional: true - yocto-queue@0.1.0: {} zod@3.25.76: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 8f925c9..3a860bb 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -23,4 +23,3 @@ catalog: postgres: ^3.4.9 "@types/node": ^22.0.0 -nodeLinker: hoisted From b7fe68359c38b002f85a34192caf6589453c795f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Wed, 15 Apr 2026 02:27:59 +0200 Subject: [PATCH 014/494] Fix flaky overnight E2E test: increase timeouts The "Waypoints (3)" assertion timed out at 5s in CI. The waypoints load from URL params but the sidebar needs BRouter mock response + Yjs sync before updating. Increase to 15s to match other assertions. Co-Authored-By: Claude Opus 4.6 (1M context) --- e2e/planner.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/e2e/planner.test.ts b/e2e/planner.test.ts index eb9608c..05db769 100644 --- a/e2e/planner.test.ts +++ b/e2e/planner.test.ts @@ -259,10 +259,10 @@ test.describe("Planner", () => { await expect(page.locator(".leaflet-container")).toBeVisible({ timeout: 10000 }); await expect(page.getByText("Connected")).toBeVisible({ timeout: 15000 }); - await expect(page.getByText("Waypoints (3)")).toBeVisible({ timeout: 5000 }); + await expect(page.getByText("Waypoints (3)")).toBeVisible({ timeout: 15000 }); const sidebar = page.locator("aside"); - await expect(sidebar.getByText(/\d+\.\d+ km/).first()).toBeVisible({ timeout: 10000 }); + await expect(sidebar.getByText(/\d+\.\d+ km/).first()).toBeVisible({ timeout: 15000 }); // Hover waypoint 2 to reveal controls, click the overnight toggle (moon icon) const waypointRows = sidebar.locator("li").filter({ has: page.locator("span.rounded-full") }); From 5c4c0ae49ddd5d76486359add7b10ec214683e86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Wed, 15 Apr 2026 07:12:13 +0200 Subject: [PATCH 015/494] Fix route compute 401: use authenticated API client The route editor called fetch() directly for /api/v1/routes/compute without the bearer token. Now uses the API client which injects auth headers and handles 401 auto-refresh. Co-Authored-By: Claude Opus 4.6 (1M context) --- apps/mobile/lib/api-client.ts | 7 +++++++ apps/mobile/lib/editor/use-route-editor.ts | 23 +++++----------------- 2 files changed, 12 insertions(+), 18 deletions(-) diff --git a/apps/mobile/lib/api-client.ts b/apps/mobile/lib/api-client.ts index f9d1732..f5da29a 100644 --- a/apps/mobile/lib/api-client.ts +++ b/apps/mobile/lib/api-client.ts @@ -113,6 +113,13 @@ export function updateRoute(id: string, data: { name?: string; description?: str }); } +export function computeRoute(waypoints: Array<{ lat: number; lon: number }>, profile = "fastbike") { + return request("/routes/compute", { + method: "POST", + body: JSON.stringify({ waypoints, profile }), + }); +} + // --- Activities --- export async function listActivities(cursor?: string, limit = 20) { diff --git a/apps/mobile/lib/editor/use-route-editor.ts b/apps/mobile/lib/editor/use-route-editor.ts index 08dad73..f6b19a4 100644 --- a/apps/mobile/lib/editor/use-route-editor.ts +++ b/apps/mobile/lib/editor/use-route-editor.ts @@ -1,8 +1,7 @@ import { useState, useCallback, useRef } from "react"; import type { Waypoint } from "@trails-cool/types"; import type { RouteDetail } from "../api-client"; -import { updateRoute } from "../api-client"; -import { getServerUrl } from "../server-config"; +import { updateRoute, computeRoute as apiComputeRoute } from "../api-client"; import { generateGpx } from "@trails-cool/gpx"; export interface RouteSegment { @@ -44,22 +43,10 @@ export function useRouteEditor(route: RouteDetail) { setState((s) => ({ ...s, computing: true, error: null })); try { - const serverUrl = await getServerUrl(); - const resp = await fetch(`${serverUrl}/api/v1/routes/compute`, { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ - waypoints: waypoints.map((w) => ({ lat: w.lat, lon: w.lon })), - profile: route.routingProfile ?? "fastbike", - }), - }); - - if (!resp.ok) { - setState((s) => ({ ...s, computing: false, error: "Route computation failed" })); - return; - } - - const geojson = await resp.json(); + const geojson = await apiComputeRoute( + waypoints.map((w) => ({ lat: w.lat, lon: w.lon })), + route.routingProfile ?? "fastbike", + ); const coords = extractCoordsFromGeojson(geojson); setState((s) => ({ ...s, From 58bff065ffb9a4be47b7aab0e7cf406503878c87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Wed, 15 Apr 2026 07:28:25 +0200 Subject: [PATCH 016/494] Gracefully handle missing MapLibre native module Use try/catch require() for MapLibre so the app works without it (shows fallback UI). Needed when running on builds that don't include MapLibre native module (old EAS builds, Expo Go). Co-Authored-By: Claude Opus 4.6 (1M context) --- apps/mobile/lib/editor/RouteMap.tsx | 64 ++++++++++++++++++++++++----- 1 file changed, 53 insertions(+), 11 deletions(-) diff --git a/apps/mobile/lib/editor/RouteMap.tsx b/apps/mobile/lib/editor/RouteMap.tsx index 57171e1..c41eeb0 100644 --- a/apps/mobile/lib/editor/RouteMap.tsx +++ b/apps/mobile/lib/editor/RouteMap.tsx @@ -1,9 +1,18 @@ import { useRef, useCallback } from "react"; import { StyleSheet, View, Text } from "react-native"; -import MapLibreGL from "@maplibre/maplibre-react-native"; import type { Waypoint } from "@trails-cool/types"; import type { RouteSegment } from "./use-route-editor"; +import type MapLibreRN from "@maplibre/maplibre-react-native"; + +let MapLibreGL: typeof MapLibreRN | null = null; +try { + // eslint-disable-next-line @typescript-eslint/no-require-imports + MapLibreGL = require("@maplibre/maplibre-react-native").default; +} catch { + // Native module not available — will show fallback UI +} + const OSM_STYLE = { version: 8 as const, sources: { @@ -40,7 +49,32 @@ export function RouteMap({ onWaypointDragEnd: _onWaypointDragEnd, onWaypointPress, }: RouteMapProps) { - const cameraRef = useRef(null); + if (!MapLibreGL) { + return ( + + Map + Requires a dev build with MapLibre + + ); + } + + return ; +} + +function RouteMapInner({ + waypoints, + segments, + computing, + onLongPress, + onWaypointDragEnd: _onWaypointDragEnd, + onWaypointPress, +}: RouteMapProps) { + const ML = MapLibreGL!; + const cameraRef = useRef(null); const handleLongPress = useCallback( // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -71,7 +105,7 @@ export function RouteMap({ return ( - {bounds && ( - - + - + {/* Waypoint markers */} {waypoints.map((wp, i) => ( - @@ -126,9 +160,9 @@ export function RouteMap({ isDayBreak={wp.isDayBreak} onPress={() => onWaypointPress(i)} /> - + ))} - + {computing && ( @@ -186,6 +220,14 @@ function computeBounds( } const styles = StyleSheet.create({ + fallback: { + flex: 1, + backgroundColor: "#f3f4f6", + justifyContent: "center", + alignItems: "center", + }, + fallbackText: { fontSize: 16, color: "#9ca3af", fontWeight: "600" }, + fallbackHint: { fontSize: 12, color: "#9ca3af", marginTop: 4 }, container: { flex: 1 }, map: { flex: 1 }, computingBanner: { From 2a94af565511e41cd331ce6f0d1502608f63a3d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Wed, 15 Apr 2026 07:39:04 +0200 Subject: [PATCH 017/494] Add Metro config for monorepo module resolution MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Metro couldn't resolve hoisted packages (@maplibre, @gorhom, etc.) because it only looked in apps/mobile/node_modules. Configure watchFolders and nodeModulesPaths to include the monorepo root. Also revert MapLibre fallback — direct import is correct, the issue was Metro resolution, not a missing native module. Co-Authored-By: Claude Opus 4.6 (1M context) --- apps/mobile/lib/editor/RouteMap.tsx | 11 +---------- apps/mobile/metro.config.js | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 10 deletions(-) create mode 100644 apps/mobile/metro.config.js diff --git a/apps/mobile/lib/editor/RouteMap.tsx b/apps/mobile/lib/editor/RouteMap.tsx index c41eeb0..409580f 100644 --- a/apps/mobile/lib/editor/RouteMap.tsx +++ b/apps/mobile/lib/editor/RouteMap.tsx @@ -1,18 +1,9 @@ import { useRef, useCallback } from "react"; import { StyleSheet, View, Text } from "react-native"; +import MapLibreGL from "@maplibre/maplibre-react-native"; import type { Waypoint } from "@trails-cool/types"; import type { RouteSegment } from "./use-route-editor"; -import type MapLibreRN from "@maplibre/maplibre-react-native"; - -let MapLibreGL: typeof MapLibreRN | null = null; -try { - // eslint-disable-next-line @typescript-eslint/no-require-imports - MapLibreGL = require("@maplibre/maplibre-react-native").default; -} catch { - // Native module not available — will show fallback UI -} - const OSM_STYLE = { version: 8 as const, sources: { diff --git a/apps/mobile/metro.config.js b/apps/mobile/metro.config.js new file mode 100644 index 0000000..fb69142 --- /dev/null +++ b/apps/mobile/metro.config.js @@ -0,0 +1,18 @@ +const { getDefaultConfig } = require("expo/metro-config"); +const path = require("path"); + +const projectRoot = __dirname; +const monorepoRoot = path.resolve(projectRoot, "../.."); + +const config = getDefaultConfig(projectRoot); + +// Watch all files in the monorepo +config.watchFolders = [monorepoRoot]; + +// Resolve modules from both the project and monorepo root +config.resolver.nodeModulesPaths = [ + path.resolve(projectRoot, "node_modules"), + path.resolve(monorepoRoot, "node_modules"), +]; + +module.exports = config; From 3bcb1fce7c2748c2175be7026ae4dc6ad98bd17c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Wed, 15 Apr 2026 20:56:42 +0200 Subject: [PATCH 018/494] Add 6-digit login code for mobile authentication Magic links open in the device browser, not the OAuth in-app browser, so the session doesn't carry over. A login code lets mobile users type a 6-digit code from their email into the login page instead. - Generate 6-digit numeric code alongside magic link token - Store code in magic_tokens table - Add verify-code step to login API endpoint - Show code input UI after magic link is sent - Include code in email template - i18n keys for code UI (en + de) Co-Authored-By: Claude Opus 4.6 (1M context) --- apps/journal/app/lib/auth.server.ts | 41 ++++++++++++++- apps/journal/app/lib/email.server.ts | 18 +++++-- apps/journal/app/routes/api.auth.login.ts | 23 ++++++--- apps/journal/app/routes/auth.login.tsx | 63 ++++++++++++++++++++--- packages/db/src/schema/journal.ts | 1 + packages/i18n/src/locales/de.ts | 2 + packages/i18n/src/locales/en.ts | 2 + 7 files changed, 130 insertions(+), 20 deletions(-) diff --git a/apps/journal/app/lib/auth.server.ts b/apps/journal/app/lib/auth.server.ts index e510bdc..d44e4cd 100644 --- a/apps/journal/app/lib/auth.server.ts +++ b/apps/journal/app/lib/auth.server.ts @@ -229,7 +229,13 @@ export async function finishAuthentication( // --- Magic Links --- -export async function createMagicToken(email: string): Promise { +function generateLoginCode(): string { + // 6-digit numeric code, zero-padded + const num = randomBytes(3).readUIntBE(0, 3) % 1_000_000; + return String(num).padStart(6, "0"); +} + +export async function createMagicToken(email: string): Promise<{ token: string; code: string }> { const db = getDb(); // Check user exists @@ -237,16 +243,47 @@ export async function createMagicToken(email: string): Promise { if (!user) throw new Error("No account found for this email"); const token = randomBytes(32).toString("base64url"); + const code = generateLoginCode(); const expiresAt = new Date(Date.now() + 15 * 60 * 1000); // 15 minutes await db.insert(magicTokens).values({ id: randomUUID(), email, token, + code, expiresAt, }); - return token; + return { token, code }; +} + +export async function verifyLoginCode(email: string, code: string): Promise { + const db = getDb(); + + const [record] = await db + .select() + .from(magicTokens) + .where( + and( + eq(magicTokens.email, email), + eq(magicTokens.code, code), + eq(magicTokens.purpose, "login"), + gt(magicTokens.expiresAt, new Date()), + isNull(magicTokens.usedAt), + ), + ); + + if (!record) throw new Error("Invalid or expired code"); + + await db + .update(magicTokens) + .set({ usedAt: new Date() }) + .where(eq(magicTokens.id, record.id)); + + const [user] = await db.select().from(users).where(eq(users.email, record.email)); + if (!user) throw new Error("User not found"); + + return user.id; } export async function initiateEmailChange(userId: string, newEmail: string): Promise { diff --git a/apps/journal/app/lib/email.server.ts b/apps/journal/app/lib/email.server.ts index 50b2209..3b5a856 100644 --- a/apps/journal/app/lib/email.server.ts +++ b/apps/journal/app/lib/email.server.ts @@ -30,23 +30,33 @@ export async function sendEmail( // --- Templates --- -export function magicLinkTemplate(link: string): { html: string; text: string } { +export function magicLinkTemplate(link: string, code?: string): { html: string; text: string } { + const codeSection = code + ? `

Or enter this code on the login page:

+
+ ${code} +
` + : ""; + const html = `

Sign in to trails.cool

Click the button below to sign in to your account. This link expires in 15 minutes.

Sign In + ${codeSection}

If the button doesn't work, copy and paste this link:
${link}


If you didn't request this link, you can safely ignore this email.

`.trim(); + const codeText = code ? `\nOr enter this code: ${code}\n` : ""; + const text = [ "Sign in to trails.cool", "", `Click here to sign in: ${link}`, - "", + codeText, "This link expires in 15 minutes.", "", "If you didn't request this link, you can safely ignore this email.", @@ -89,8 +99,8 @@ export function welcomeTemplate(username: string): { html: string; text: string // --- Convenience wrappers --- -export async function sendMagicLink(email: string, link: string): Promise { - const { html, text } = magicLinkTemplate(link); +export async function sendMagicLink(email: string, link: string, code?: string): Promise { + const { html, text } = magicLinkTemplate(link, code); await sendEmail(email, "Sign in to trails.cool", html, text); } diff --git a/apps/journal/app/routes/api.auth.login.ts b/apps/journal/app/routes/api.auth.login.ts index e4f766e..7fa122e 100644 --- a/apps/journal/app/routes/api.auth.login.ts +++ b/apps/journal/app/routes/api.auth.login.ts @@ -1,11 +1,11 @@ import { data } from "react-router"; import type { Route } from "./+types/api.auth.login"; -import { startAuthentication, finishAuthentication, createMagicToken, createSession } from "~/lib/auth.server"; +import { startAuthentication, finishAuthentication, createMagicToken, verifyLoginCode, createSession } from "~/lib/auth.server"; import { sendMagicLink } from "~/lib/email.server"; export async function action({ request }: Route.ActionArgs) { const body = await request.json(); - const { step, response, challenge, email } = body; + const { step, response, challenge, email, code } = body; try { if (step === "start-passkey") { @@ -20,19 +20,28 @@ export async function action({ request }: Route.ActionArgs) { } if (step === "magic-link") { - const token = await createMagicToken(email); + const { token, code: loginCode } = await createMagicToken(email); const origin = process.env.ORIGIN ?? "http://localhost:3000"; const link = `${origin}/auth/verify?token=${token}`; - // In dev, return the link directly so the client can auto-redirect + // In dev, return the link and code directly if (process.env.NODE_ENV !== "production") { - console.log(`[Magic Link] ${email}: ${link}`); - return data({ step: "magic-link-sent", devLink: link }); + console.log(`[Magic Link] ${email}: ${link} (code: ${loginCode})`); + return data({ step: "magic-link-sent", devLink: link, code: loginCode }); } - await sendMagicLink(email, link); + await sendMagicLink(email, link, loginCode); return data({ step: "magic-link-sent" }); } + if (step === "verify-code") { + if (!email || !code) { + return data({ error: "Email and code are required" }, { status: 400 }); + } + const userId = await verifyLoginCode(email, code); + const cookie = await createSession(userId, request); + return data({ step: "done" }, { headers: { "Set-Cookie": cookie } }); + } + return data({ error: "Invalid step" }, { status: 400 }); } catch (e) { return data({ error: (e as Error).message }, { status: 400 }); diff --git a/apps/journal/app/routes/auth.login.tsx b/apps/journal/app/routes/auth.login.tsx index 3a6bd18..1201c4b 100644 --- a/apps/journal/app/routes/auth.login.tsx +++ b/apps/journal/app/routes/auth.login.tsx @@ -17,6 +17,7 @@ export default function LoginPage() { }); }, []); const [email, setEmail] = useState(""); + const [loginCode, setLoginCode] = useState(""); const [error, setError] = useState(null); const [loading, setLoading] = useState(false); const [magicLinkSent, setMagicLinkSent] = useState(false); @@ -70,6 +71,31 @@ export default function LoginPage() { } }; + const handleCodeVerify = async (e: React.FormEvent) => { + e.preventDefault(); + setError(null); + setLoading(true); + + try { + const resp = await fetch("/api/auth/login", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ step: "verify-code", email, code: loginCode }), + }); + const result = await resp.json(); + + if (result.error) { + setError(result.error); + } else if (result.step === "done") { + window.location.href = returnTo ?? "/"; + } + } catch (err) { + setError((err as Error).message); + } finally { + setLoading(false); + } + }; + const handleMagicLink = async (e: React.FormEvent) => { e.preventDefault(); setError(null); @@ -168,13 +194,36 @@ export default function LoginPage() { )} {magicLinkSent && ( -
-

- {t("auth.checkEmail")} {email}. -

-

- {t("auth.linkExpires")} -

+
+
+

+ {t("auth.checkEmail")} {email}. +

+

+ {t("auth.linkExpires")} +

+
+ +
+

{t("auth.codeHelp")}

+ setLoginCode(e.target.value.replace(/\D/g, "").slice(0, 6))} + className="block w-full rounded-md border border-gray-300 px-3 py-3 text-center text-2xl font-mono tracking-[0.3em] shadow-sm focus:border-blue-500 focus:outline-none focus:ring-1 focus:ring-blue-500" + /> + +
)} diff --git a/packages/db/src/schema/journal.ts b/packages/db/src/schema/journal.ts index 19de61c..90d79a6 100644 --- a/packages/db/src/schema/journal.ts +++ b/packages/db/src/schema/journal.ts @@ -49,6 +49,7 @@ export const magicTokens = journalSchema.table("magic_tokens", { id: text("id").primaryKey(), email: text("email").notNull(), token: text("token").notNull().unique(), + code: text("code"), purpose: text("purpose").notNull().default("login"), expiresAt: timestamp("expires_at", { withTimezone: true }).notNull(), usedAt: timestamp("used_at", { withTimezone: true }), diff --git a/packages/i18n/src/locales/de.ts b/packages/i18n/src/locales/de.ts index 3978862..dd6fabe 100644 --- a/packages/i18n/src/locales/de.ts +++ b/packages/i18n/src/locales/de.ts @@ -265,6 +265,8 @@ export default { backToPasskey: "Zurück zur Passkey-Anmeldung", checkEmail: "Prüfe deine E-Mails! Wir haben einen Anmeldelink gesendet an", linkExpires: "Der Link ist 15 Minuten gültig.", + codeHelp: "Oder gib den 6-stelligen Code aus der E-Mail ein:", + verifyCode: "Code bestätigen", noAccount: "Noch kein Konto?", registerDescription: "Registriere dich mit einem Passkey — kein Passwort nötig.", registerWithPasskey: "Mit Passkey registrieren", diff --git a/packages/i18n/src/locales/en.ts b/packages/i18n/src/locales/en.ts index a067869..b2dbf9c 100644 --- a/packages/i18n/src/locales/en.ts +++ b/packages/i18n/src/locales/en.ts @@ -265,6 +265,8 @@ export default { backToPasskey: "Back to passkey login", checkEmail: "Check your email! We sent a login link to", linkExpires: "The link expires in 15 minutes.", + codeHelp: "Or enter the 6-digit code from the email:", + verifyCode: "Verify Code", noAccount: "Don't have an account?", registerDescription: "Register with a passkey — no password needed.", registerWithPasskey: "Register with Passkey", From 680815e1f63bbe072e69c4fcfa29f1353451e23f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Fri, 17 Apr 2026 22:12:23 +0200 Subject: [PATCH 019/494] Add OpenSpec proposal for legal disclaimers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Proposal, design, specs, and tasks for German legal compliance (Impressum, Datenschutzerklärung, ToS) and alpha-stage disclaimers at signup. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../changes/legal-disclaimers/.openspec.yaml | 2 + openspec/changes/legal-disclaimers/design.md | 52 +++++++++++++ .../changes/legal-disclaimers/proposal.md | 36 +++++++++ .../specs/journal-auth/spec.md | 17 +++++ .../specs/legal-disclaimers/spec.md | 73 +++++++++++++++++++ openspec/changes/legal-disclaimers/tasks.md | 46 ++++++++++++ 6 files changed, 226 insertions(+) create mode 100644 openspec/changes/legal-disclaimers/.openspec.yaml create mode 100644 openspec/changes/legal-disclaimers/design.md create mode 100644 openspec/changes/legal-disclaimers/proposal.md create mode 100644 openspec/changes/legal-disclaimers/specs/journal-auth/spec.md create mode 100644 openspec/changes/legal-disclaimers/specs/legal-disclaimers/spec.md create mode 100644 openspec/changes/legal-disclaimers/tasks.md diff --git a/openspec/changes/legal-disclaimers/.openspec.yaml b/openspec/changes/legal-disclaimers/.openspec.yaml new file mode 100644 index 0000000..863bff1 --- /dev/null +++ b/openspec/changes/legal-disclaimers/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-driven +created: 2026-04-17 diff --git a/openspec/changes/legal-disclaimers/design.md b/openspec/changes/legal-disclaimers/design.md new file mode 100644 index 0000000..b829d8e --- /dev/null +++ b/openspec/changes/legal-disclaimers/design.md @@ -0,0 +1,52 @@ +## Context + +The operator is based in Germany. German law requires an Impressum for any online service (TMG §5 / MStV §18) and a GDPR-compliant privacy policy (DSGVO Art. 13/14). Missing Impressum is routinely exploited by Abmahnanwälte — fines and legal costs can reach several thousand euros. The current privacy page is written as a human-readable manifest, not a formal Datenschutzerklärung. + +The service is also in early alpha. The operator may reset the database, change core behavior, or break APIs at any time. Users signing up now have no way to know this. + +## Goals / Non-Goals + +**Goals:** +- Meet the minimum legal requirements to operate from Germany (Impressum, Datenschutzerklärung, ToS) +- Set clear user expectations about the alpha state — database resets, breaking changes +- Require explicit acknowledgement at signup so there is a record of informed consent +- Keep the existing privacy manifest style (readable, honest) while adding the formal GDPR sections + +**Non-Goals:** +- Professional legal review — the operator should still have a German IT lawyer review the final text before publishing +- Cookie banner / consent management — trails.cool uses only essential cookies (no tracking, no analytics), so no banner is required under §25 TDDDG +- Age verification or KYC +- ToS-level commitments that would constitute a contract of service (we explicitly disclaim warranties) + +## Decisions + +### 1. Routes under `/legal/` +**Choice**: `/legal/imprint`, `/legal/privacy`, `/legal/terms` — move the existing `/privacy` route to `/legal/privacy` with a redirect. +**Rationale**: Grouped namespace makes the legal pages easy to find and link from the footer. Redirect preserves existing privacy links. +**Alternative considered**: Keep `/privacy` at the top level — less organized as more legal pages are added. + +### 2. Impressum as a plain page with placeholders +**Choice**: The Impressum page is server-rendered from a small config object (operator name, address, email, responsible person). Not i18n'd — Impressum is normally in the language of the operator's country (German), but we'll include an English section below. +**Rationale**: The operator's legal details rarely change. Keeping them in a config file (TypeScript) rather than the database avoids needing a CMS for a static page. +**Alternative considered**: Database-backed operator config — overkill for data that changes once a year at most. + +### 3. Signup acknowledgement via checkbox + timestamp +**Choice**: Add a required checkbox on the registration form. On successful registration, store `terms_accepted_at` on the user row. If the Terms are later updated in a material way, we can compare the accepted timestamp and prompt re-acknowledgement. +**Rationale**: A timestamped record of acknowledgement is sufficient for the experimental-status disclaimer. Re-acknowledgement is only needed for material changes. +**Alternative considered**: Store the full ToS version hash — more precise but overkill while the operator can reset everyone's data anyway. + +### 4. Alpha banner +**Choice**: A thin banner at the top of the Journal layout, showing "trails.cool is in early development — your data may be reset. See Terms." The banner is dismissible for the browser session (sessionStorage, not cookie). Not shown on the Planner because Planner sessions are already anonymous and ephemeral. +**Rationale**: Persistent, visible signal that users can dismiss. Session-scoped dismissal means returning users still see it occasionally. +**Alternative considered**: One-time dismissal stored in the DB — adds server state for a trivial UX feature. + +### 5. Keep Datenschutzerklärung readable +**Choice**: The existing privacy manifest structure (Planner, Journal, Sentry, Email, Third Parties, Security) stays. We add new sections at the top for the GDPR-required info: data controller contact, legal basis for processing each category, data subject rights (Art. 15–22 DSGVO), and right to complain to the Berlin Beauftragte für Datenschutz. +**Rationale**: Keeping the plain-language summary is valuable. The formal sections are additive. + +## Risks / Trade-offs + +- **Text is not legally reviewed**: The drafted text is a starting point — the operator should have a German IT lawyer review before publishing. → Mitigation: Note this explicitly in the tasks; don't treat the first version as final. +- **Impressum requires real address**: The operator's private address is publicly exposed unless they rent a business address or use a service. → Mitigation: Call this out in the tasks so the operator decides before deploying. +- **Re-acknowledgement flow not built now**: If the Terms change materially, users should re-acknowledge. The initial version doesn't include this. → Mitigation: The `terms_accepted_at` timestamp is captured so the flow can be added later. +- **Banner fatigue**: A persistent banner can be annoying. → Mitigation: Session-scoped dismissal keeps it low-friction. diff --git a/openspec/changes/legal-disclaimers/proposal.md b/openspec/changes/legal-disclaimers/proposal.md new file mode 100644 index 0000000..bd473f2 --- /dev/null +++ b/openspec/changes/legal-disclaimers/proposal.md @@ -0,0 +1,36 @@ +## Why + +trails.cool is operated from Germany, which means German law (TMG, TDDDG, MStV, and GDPR via DSGVO) applies. There is currently no Impressum, no Terms of Service, and the privacy manifest isn't a full GDPR-compliant Datenschutzerklärung — this exposes the operator to legal risk (Abmahnungen are common for missing Impressum in Germany). + +Separately, the service is in active early development. Users signing up today may find their accounts wiped if the operator decides to reset the database, or they may encounter breaking changes to the UI, URLs, or federation behavior. Current users have no signal that this is experimental, which sets wrong expectations and creates another liability surface. + +## What Changes + +- Add an **Impressum** page at `/legal/imprint` with operator name, address, email, and responsible person per §5 TMG / §18 MStV +- Expand the existing privacy manifest into a full **Datenschutzerklärung** at `/legal/privacy` — keep the human-readable summary but add the GDPR-required sections (legal basis, data subject rights, controller contact, right to complain) +- Add a **Terms of Service** page at `/legal/terms` with: + - Alpha / experimental status disclaimer (service is untested, under active development) + - No warranty / no SLA / limitation of liability (within German consumer-protection limits) + - Explicit statement that the database may be wiped without notice + - User responsibility to export their own data (linking to existing export) + - Acceptable use (no illegal content, no abuse) +- Require **acknowledgement at signup**: a checkbox on the registration form confirming the user has read the Terms and understands the alpha status. Form cannot submit without it. +- Add a persistent **alpha banner** on the Journal (thin, dismissible for the session) linking to the Terms with the line "trails.cool is in early development — data may be reset" +- Add **footer links** to Impressum / Privacy / Terms on both apps (Journal and Planner) + +## Capabilities + +### New Capabilities +- `legal-disclaimers`: Impressum page, Terms of Service with alpha disclaimer, full Datenschutzerklärung, signup acknowledgement flow, alpha banner, and footer links + +### Modified Capabilities +- `journal-auth`: Registration SHALL require explicit acknowledgement of the Terms of Service before account creation + +## Impact + +- **Legal risk reduction**: Closes the Impressum gap that triggers Abmahnungen in Germany +- **User expectations**: Clear alpha signal reduces complaints if the DB is reset +- **Code**: New routes in the Journal (`/legal/imprint`, `/legal/terms`, expanded `/legal/privacy`), footer component updates, registration form change +- **i18n**: All legal copy needs EN + DE translations (DE is the authoritative version for German consumers) +- **Database**: Add `terms_accepted_at` timestamp to the `users` table to record acknowledgement +- **Operator info**: The operator's real name and address will be in the Impressum — this is a legal requirement and cannot be omitted diff --git a/openspec/changes/legal-disclaimers/specs/journal-auth/spec.md b/openspec/changes/legal-disclaimers/specs/journal-auth/spec.md new file mode 100644 index 0000000..eec943c --- /dev/null +++ b/openspec/changes/legal-disclaimers/specs/journal-auth/spec.md @@ -0,0 +1,17 @@ +## ADDED Requirements + +### Requirement: Terms acknowledgement at signup +The registration form SHALL require explicit acknowledgement of the Terms of Service before an account can be created. + +#### Scenario: Checkbox required +- **WHEN** a user views the registration form +- **THEN** they see a required checkbox labeled "I have read and agree to the Terms of Service, including that trails.cool is in alpha and my data may be reset" +- **AND** the checkbox label links to the Terms page + +#### Scenario: Cannot submit without acknowledgement +- **WHEN** a user attempts to register without checking the acknowledgement box +- **THEN** the form blocks submission and shows a validation message + +#### Scenario: Acknowledgement recorded +- **WHEN** a user successfully registers +- **THEN** the current timestamp is stored in `users.terms_accepted_at` diff --git a/openspec/changes/legal-disclaimers/specs/legal-disclaimers/spec.md b/openspec/changes/legal-disclaimers/specs/legal-disclaimers/spec.md new file mode 100644 index 0000000..246a563 --- /dev/null +++ b/openspec/changes/legal-disclaimers/specs/legal-disclaimers/spec.md @@ -0,0 +1,73 @@ +## ADDED Requirements + +### Requirement: Impressum page +The Journal SHALL serve an Impressum page at `/legal/imprint` containing the operator's legal information per §5 TMG and §18 MStV. + +#### Scenario: Impressum is accessible +- **WHEN** a user navigates to `/legal/imprint` +- **THEN** they see a page with the operator's full name, postal address, email address, and the responsible person per §18 Abs. 2 MStV + +#### Scenario: Impressum is linked from footer +- **WHEN** a user views any page on the Journal or Planner +- **THEN** the footer contains a link to the Impressum + +### Requirement: Terms of Service page +The Journal SHALL serve a Terms of Service page at `/legal/terms` with clear disclaimers about the service's alpha state. + +#### Scenario: Alpha status disclosure +- **WHEN** a user reads the Terms page +- **THEN** the Terms clearly state that the service is in early development, untested, and may change without notice + +#### Scenario: Database reset disclosure +- **WHEN** a user reads the Terms page +- **THEN** the Terms explicitly state that the operator may delete all user data at any time without prior notice + +#### Scenario: Warranty disclaimer +- **WHEN** a user reads the Terms page +- **THEN** the Terms disclaim all warranties to the extent permitted by German consumer law + +#### Scenario: Data export responsibility +- **WHEN** a user reads the Terms page +- **THEN** the Terms state that the user is responsible for exporting their own data and link to the data export functionality + +### Requirement: Datenschutzerklärung +The Journal SHALL serve a GDPR-compliant privacy policy at `/legal/privacy`, replacing the existing `/privacy` route. + +#### Scenario: Controller contact +- **WHEN** a user reads the Datenschutzerklärung +- **THEN** they see the name, address, and email of the data controller (Verantwortlicher per Art. 4 Nr. 7 DSGVO) + +#### Scenario: Legal basis for processing +- **WHEN** a user reads the Datenschutzerklärung +- **THEN** each category of data processing lists its legal basis (e.g., Art. 6 Abs. 1 lit. b for contract, lit. f for legitimate interest) + +#### Scenario: Data subject rights +- **WHEN** a user reads the Datenschutzerklärung +- **THEN** they see their rights under GDPR: access (Art. 15), rectification (Art. 16), erasure (Art. 17), data portability (Art. 20), objection (Art. 21), and right to lodge a complaint with a supervisory authority + +#### Scenario: Redirect from old privacy URL +- **WHEN** a user navigates to `/privacy` +- **THEN** they are redirected to `/legal/privacy` with a 301 status + +### Requirement: Alpha banner +The Journal SHALL display a persistent banner notifying users that the service is in alpha, dismissible for the browser session. + +#### Scenario: Banner visible on first visit +- **WHEN** a user visits any Journal page for the first time in a session +- **THEN** a banner is shown with text stating trails.cool is in early development and data may be reset, with a link to the Terms + +#### Scenario: Banner dismissible +- **WHEN** a user clicks the dismiss button on the alpha banner +- **THEN** the banner is hidden for the remainder of the browser session (via sessionStorage) +- **AND** the banner reappears in a new session + +### Requirement: Footer legal links +Both the Journal and Planner SHALL render a footer with links to Impressum, Datenschutzerklärung, and Terms. + +#### Scenario: Footer on Journal +- **WHEN** a user views any Journal page +- **THEN** the footer contains links labeled "Impressum", "Privacy", and "Terms" pointing to the respective legal pages + +#### Scenario: Footer on Planner +- **WHEN** a user views any Planner page +- **THEN** the footer contains the same three legal links, pointing to the Journal instance (since the Planner is stateless and legal pages live on the Journal) diff --git a/openspec/changes/legal-disclaimers/tasks.md b/openspec/changes/legal-disclaimers/tasks.md new file mode 100644 index 0000000..a2007bb --- /dev/null +++ b/openspec/changes/legal-disclaimers/tasks.md @@ -0,0 +1,46 @@ +## 1. Operator Information + +- [ ] 1.1 Decide what operator address to use on the Impressum (private address vs. business address service vs. lawyer's address) — legal requirement, must be reachable +- [ ] 1.2 Create `apps/journal/app/lib/operator.ts` exporting the operator details (name, address, email, responsible person) + +## 2. Legal Pages + +- [ ] 2.1 Create `apps/journal/app/routes/legal.imprint.tsx` rendering the Impressum from the operator config +- [ ] 2.2 Create `apps/journal/app/routes/legal.terms.tsx` with Terms of Service covering alpha status, warranty disclaimer, DB reset disclosure, and data export responsibility +- [ ] 2.3 Move existing `apps/journal/app/routes/privacy.tsx` to `apps/journal/app/routes/legal.privacy.tsx` and expand with GDPR-required sections (controller, legal basis, data subject rights, complaint right) +- [ ] 2.4 Add a redirect from `/privacy` to `/legal/privacy` with 301 status +- [ ] 2.5 Register the new routes in `apps/journal/app/routes.ts` + +## 3. i18n + +- [ ] 3.1 Add German translations for all legal page copy (Impressum, Terms, Datenschutzerklärung) — DE is the authoritative version for German consumers +- [ ] 3.2 Add English translations for the same pages +- [ ] 3.3 Add translation keys for the alpha banner and signup acknowledgement checkbox + +## 4. Signup Acknowledgement + +- [ ] 4.1 Add `terms_accepted_at` column (timestamp, nullable initially for existing users) to the `users` table in `packages/db/src/schema/journal.ts` +- [ ] 4.2 Run `pnpm db:push` to apply the schema +- [ ] 4.3 Add a required checkbox to `apps/journal/app/routes/auth.register.tsx` linking to the Terms +- [ ] 4.4 Client-side: block form submission if checkbox is unchecked; show validation message +- [ ] 4.5 Server-side: reject registration requests in `api.auth.register.ts` that don't include `termsAccepted: true` +- [ ] 4.6 On successful registration, set `users.terms_accepted_at = NOW()` + +## 5. Alpha Banner + +- [ ] 5.1 Create `apps/journal/app/components/AlphaBanner.tsx` — thin banner with message and dismiss button, reads `sessionStorage.alphaBannerDismissed` +- [ ] 5.2 Render `` in the Journal root layout +- [ ] 5.3 Add corresponding i18n strings + +## 6. Footer Links + +- [ ] 6.1 Create `apps/journal/app/components/Footer.tsx` with links to Impressum, Privacy, Terms +- [ ] 6.2 Add the footer to the Journal root layout +- [ ] 6.3 Add a footer to the Planner layout linking to the Journal's legal pages (absolute URLs, since Planner is stateless) + +## 7. Review & Publish + +- [ ] 7.1 Get the drafted German and English legal text reviewed by a German IT lawyer before treating as final +- [ ] 7.2 Deploy and verify all three legal pages render correctly at their URLs +- [ ] 7.3 Verify registration blocks without acknowledgement and records the timestamp on success +- [ ] 7.4 Verify the alpha banner appears and dismisses correctly From 258e1bb5e5b4e6284eb2bbcbe1d156f38d1e81df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Fri, 17 Apr 2026 22:26:38 +0200 Subject: [PATCH 020/494] Fix CI on main: RouteMap typecheck + metro.config lint - RouteMap.tsx referenced undefined MapLibreRN namespace, causing typecheck to fail on main and in every downstream PR - metro.config.js is CommonJS, exclude from ESLint flat config Changes that were pushed directly to main earlier bypassed CI and broke both typecheck and lint. Co-Authored-By: Claude Opus 4.6 (1M context) --- apps/mobile/lib/editor/RouteMap.tsx | 2 +- eslint.config.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/mobile/lib/editor/RouteMap.tsx b/apps/mobile/lib/editor/RouteMap.tsx index 409580f..49c177d 100644 --- a/apps/mobile/lib/editor/RouteMap.tsx +++ b/apps/mobile/lib/editor/RouteMap.tsx @@ -65,7 +65,7 @@ function RouteMapInner({ onWaypointPress, }: RouteMapProps) { const ML = MapLibreGL!; - const cameraRef = useRef(null); + const cameraRef = useRef(null); const handleLongPress = useCallback( // eslint-disable-next-line @typescript-eslint/no-explicit-any diff --git a/eslint.config.js b/eslint.config.js index bed5d97..2df196e 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -3,7 +3,7 @@ import tseslint from "typescript-eslint"; import prettier from "eslint-config-prettier"; export default tseslint.config( - { ignores: ["**/build/", "**/dist/", "**/.react-router/", "**/.expo/", "**/node_modules/"] }, + { ignores: ["**/build/", "**/dist/", "**/.react-router/", "**/.expo/", "**/node_modules/", "**/metro.config.js"] }, js.configs.recommended, ...tseslint.configs.recommended, { From cc0f44258ab86d24ab9d62b5e9778ecab1d66d3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Sat, 18 Apr 2026 00:08:48 +0200 Subject: [PATCH 021/494] Add legal pages, ToS acceptance, and alpha banner MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Journal: Impressum (§5 TMG), Terms of Service, GDPR privacy page - Registration flow: required ToS checkbox, termsAcceptedAt persisted - Alpha banner on Journal (always visible); alpha badge on Planner hero - Footer with legal links + GitHub on both apps - Reduce PII: sendDefaultPii=false, Sentry init only after login (Journal) - Drop Sentry from Planner (no login, no consent possible) - Drop localStorage caching from i18n client detection - Sync SSR i18n resources each request so locale edits HMR without restart Co-Authored-By: Claude Opus 4.7 (1M context) --- apps/journal/app/components/AlphaBanner.tsx | 10 + apps/journal/app/components/Footer.tsx | 33 +++ apps/journal/app/entry.client.tsx | 22 -- apps/journal/app/entry.server.tsx | 1 + apps/journal/app/lib/auth.server.ts | 3 +- apps/journal/app/lib/operator.ts | 20 ++ apps/journal/app/lib/sentry.client.ts | 30 +++ apps/journal/app/root.tsx | 8 +- apps/journal/app/routes.ts | 3 + apps/journal/app/routes/api.auth.register.ts | 8 +- apps/journal/app/routes/auth.login.tsx | 2 +- apps/journal/app/routes/auth.register.tsx | 47 +++- apps/journal/app/routes/legal.imprint.tsx | 94 ++++++++ apps/journal/app/routes/legal.privacy.tsx | 238 +++++++++++++++++++ apps/journal/app/routes/legal.terms.tsx | 187 +++++++++++++++ apps/journal/app/routes/privacy.tsx | 129 +--------- apps/mobile/lib/sentry.ts | 1 + apps/planner/app/entry.client.tsx | 22 -- apps/planner/app/routes/home.tsx | 16 +- openspec/changes/legal-disclaimers/tasks.md | 44 ++-- packages/db/src/schema/journal.ts | 1 + packages/i18n/src/index.ts | 20 +- packages/i18n/src/locales/de.ts | 20 ++ packages/i18n/src/locales/en.ts | 20 ++ 24 files changed, 773 insertions(+), 206 deletions(-) create mode 100644 apps/journal/app/components/AlphaBanner.tsx create mode 100644 apps/journal/app/components/Footer.tsx create mode 100644 apps/journal/app/lib/operator.ts create mode 100644 apps/journal/app/lib/sentry.client.ts create mode 100644 apps/journal/app/routes/legal.imprint.tsx create mode 100644 apps/journal/app/routes/legal.privacy.tsx create mode 100644 apps/journal/app/routes/legal.terms.tsx diff --git a/apps/journal/app/components/AlphaBanner.tsx b/apps/journal/app/components/AlphaBanner.tsx new file mode 100644 index 0000000..16ca223 --- /dev/null +++ b/apps/journal/app/components/AlphaBanner.tsx @@ -0,0 +1,10 @@ +import { useTranslation } from "react-i18next"; + +export function AlphaBanner() { + const { t } = useTranslation("journal"); + return ( +
+

{t("alpha.message")}

+
+ ); +} diff --git a/apps/journal/app/components/Footer.tsx b/apps/journal/app/components/Footer.tsx new file mode 100644 index 0000000..1542c1c --- /dev/null +++ b/apps/journal/app/components/Footer.tsx @@ -0,0 +1,33 @@ +import { useTranslation } from "react-i18next"; + +export function Footer() { + const { t } = useTranslation("journal"); + return ( + + ); +} diff --git a/apps/journal/app/entry.client.tsx b/apps/journal/app/entry.client.tsx index 8e3f019..d5b4d57 100644 --- a/apps/journal/app/entry.client.tsx +++ b/apps/journal/app/entry.client.tsx @@ -1,30 +1,8 @@ -import * as Sentry from "@sentry/react"; -import { useEffect } from "react"; import { startTransition, StrictMode } from "react"; import { hydrateRoot } from "react-dom/client"; import { HydratedRouter } from "react-router/dom"; -import { useLocation, useNavigationType, createRoutesFromChildren, matchRoutes } from "react-router"; import { initI18nClient } from "@trails-cool/i18n"; -const sentryEnvironment = import.meta.env.VITE_SENTRY_ENVIRONMENT ?? - (import.meta.env.PROD ? "production" : "development"); - -Sentry.init({ - dsn: "https://a32ffcc575d34be072e91b20f247eeee@o4509530546634752.ingest.de.sentry.io/4509530555547728", - integrations: [ - Sentry.reactRouterV7BrowserTracingIntegration({ - useEffect, - useLocation, - useNavigationType, - createRoutesFromChildren, - matchRoutes, - }), - ], - environment: sentryEnvironment, - tracesSampleRate: sentryEnvironment === "ci" ? 0 : 1.0, - enabled: import.meta.env.PROD && sentryEnvironment !== "ci", -}); - initI18nClient(); startTransition(() => { diff --git a/apps/journal/app/entry.server.tsx b/apps/journal/app/entry.server.tsx index 0bdfe8f..ff195e8 100644 --- a/apps/journal/app/entry.server.tsx +++ b/apps/journal/app/entry.server.tsx @@ -16,6 +16,7 @@ Sentry.init({ environment: sentryEnvironment, tracesSampleRate: 1.0, enabled: process.env.NODE_ENV === "production" && !process.env.CI, + sendDefaultPii: false, beforeSend(event) { // Drop 404s — they're expected (scanners, typos), not bugs const serialized = event.extra?.__serialized__ as Record | undefined; diff --git a/apps/journal/app/lib/auth.server.ts b/apps/journal/app/lib/auth.server.ts index d44e4cd..204aa64 100644 --- a/apps/journal/app/lib/auth.server.ts +++ b/apps/journal/app/lib/auth.server.ts @@ -76,6 +76,7 @@ export async function finishRegistration( email, username, domain, + termsAcceptedAt: new Date(), }); await db.insert(credentials).values({ @@ -158,7 +159,7 @@ export async function registerWithMagicLink(email: string, username: string): Pr const userId = randomUUID(); const domain = process.env.DOMAIN ?? "localhost"; - await db.insert(users).values({ id: userId, email, username, domain }); + await db.insert(users).values({ id: userId, email, username, domain, termsAcceptedAt: new Date() }); // Create magic token for verification const token = randomBytes(32).toString("base64url"); diff --git a/apps/journal/app/lib/operator.ts b/apps/journal/app/lib/operator.ts new file mode 100644 index 0000000..4ea49af --- /dev/null +++ b/apps/journal/app/lib/operator.ts @@ -0,0 +1,20 @@ +/** + * Operator details for the Impressum (§5 TMG / §18 MStV). + * + * Required by German law. Address must be a reachable physical address. + * Email must be a direct contact (no forms-only policy). + */ +export const operator = { + name: "Ullrich Schäfer", + address: { + street: "Mehringdamm 87", + postalCode: "10965", + city: "Berlin", + country: "Germany", + }, + email: "legal@trails.cool", + // Responsible for content per §18 Abs. 2 MStV + responsiblePerson: "Ullrich Schäfer", +} as const; + +export type Operator = typeof operator; diff --git a/apps/journal/app/lib/sentry.client.ts b/apps/journal/app/lib/sentry.client.ts new file mode 100644 index 0000000..d2e6dac --- /dev/null +++ b/apps/journal/app/lib/sentry.client.ts @@ -0,0 +1,30 @@ +import * as Sentry from "@sentry/react"; +import { useEffect } from "react"; +import { useLocation, useNavigationType, createRoutesFromChildren, matchRoutes } from "react-router"; + +let initialized = false; + +export function initSentryClient() { + if (initialized) return; + initialized = true; + + const sentryEnvironment = import.meta.env.VITE_SENTRY_ENVIRONMENT ?? + (import.meta.env.PROD ? "production" : "development"); + + Sentry.init({ + dsn: "https://a32ffcc575d34be072e91b20f247eeee@o4509530546634752.ingest.de.sentry.io/4509530555547728", + integrations: [ + Sentry.reactRouterV7BrowserTracingIntegration({ + useEffect, + useLocation, + useNavigationType, + createRoutesFromChildren, + matchRoutes, + }), + ], + environment: sentryEnvironment, + tracesSampleRate: sentryEnvironment === "ci" ? 0 : 1.0, + enabled: import.meta.env.PROD && sentryEnvironment !== "ci", + sendDefaultPii: false, + }); +} diff --git a/apps/journal/app/root.tsx b/apps/journal/app/root.tsx index be4a5f4..d8967b0 100644 --- a/apps/journal/app/root.tsx +++ b/apps/journal/app/root.tsx @@ -7,6 +7,9 @@ import { useTranslation } from "react-i18next"; import { detectLocale } from "@trails-cool/i18n"; import { getSessionUser } from "~/lib/auth.server"; import { LocaleProvider } from "~/components/LocaleContext"; +import { AlphaBanner } from "~/components/AlphaBanner"; +import { Footer } from "~/components/Footer"; +import { initSentryClient } from "~/lib/sentry.client"; import stylesheet from "@trails-cool/ui/styles.css?url"; export const links: LinksFunction = () => [{ rel: "stylesheet", href: stylesheet }]; @@ -116,7 +119,8 @@ export default function App({ loaderData }: Route.ComponentProps) { const locale = loaderData?.locale ?? "en"; useEffect(() => { if (user) { - Sentry.setUser({ id: user.id, username: user.username }); + initSentryClient(); + Sentry.setUser({ id: user.id }); } else { Sentry.setUser(null); } @@ -124,8 +128,10 @@ export default function App({ loaderData }: Route.ComponentProps) { return ( + +
); } diff --git a/apps/journal/app/routes.ts b/apps/journal/app/routes.ts index 537369b..8e4558b 100644 --- a/apps/journal/app/routes.ts +++ b/apps/journal/app/routes.ts @@ -33,6 +33,9 @@ export default [ route("api/sync/disconnect/:provider", "routes/api.sync.disconnect.$provider.ts"), route("api/sync/webhook/:provider", "routes/api.sync.webhook.$provider.ts"), route("privacy", "routes/privacy.tsx"), + route("legal/imprint", "routes/legal.imprint.tsx"), + route("legal/terms", "routes/legal.terms.tsx"), + route("legal/privacy", "routes/legal.privacy.tsx"), // REST API v1 route("api/v1/routes", "routes/api.v1.routes._index.ts"), route("api/v1/routes/compute", "routes/api.v1.routes.compute.ts"), diff --git a/apps/journal/app/routes/api.auth.register.ts b/apps/journal/app/routes/api.auth.register.ts index debd278..eac3e68 100644 --- a/apps/journal/app/routes/api.auth.register.ts +++ b/apps/journal/app/routes/api.auth.register.ts @@ -6,9 +6,15 @@ import { logger } from "~/lib/logger.server"; export async function action({ request }: Route.ActionArgs) { const body = await request.json(); - const { step, email, username, response, challenge, userId } = body; + const { step, email, username, response, challenge, userId, termsAccepted } = body; const origin = process.env.ORIGIN ?? `http://localhost:3000`; + // Registration steps require terms acceptance + const requiresTerms = step === "start" || step === "finish" || step === "register-magic-link"; + if (requiresTerms && !termsAccepted) { + return data({ error: "Terms of Service must be accepted" }, { status: 400 }); + } + try { if (step === "start") { const result = await startRegistration(email, username); diff --git a/apps/journal/app/routes/auth.login.tsx b/apps/journal/app/routes/auth.login.tsx index 1201c4b..7db270a 100644 --- a/apps/journal/app/routes/auth.login.tsx +++ b/apps/journal/app/routes/auth.login.tsx @@ -62,7 +62,7 @@ export default function LoginPage() { } catch (err) { const message = (err as Error).message; if (message.includes("timed out") || message.includes("not allowed")) { - setError("No passkey found for this site. Register a new account or use a magic link instead."); + setError(t("auth.passkeyNotFound")); } else { setError(message); } diff --git a/apps/journal/app/routes/auth.register.tsx b/apps/journal/app/routes/auth.register.tsx index 90ea6b1..dec2692 100644 --- a/apps/journal/app/routes/auth.register.tsx +++ b/apps/journal/app/routes/auth.register.tsx @@ -5,12 +5,15 @@ export default function RegisterPage() { const { t } = useTranslation("journal"); const [email, setEmail] = useState(""); const [username, setUsername] = useState(""); + const [termsAccepted, setTermsAccepted] = useState(false); const [error, setError] = useState(null); const [loading, setLoading] = useState(false); const [supportsPasskey, setSupportsPasskey] = useState(null); const [magicLinkSent, setMagicLinkSent] = useState(false); + const [hostname, setHostname] = useState("…"); useEffect(() => { + setHostname(window.location.hostname); import("@simplewebauthn/browser").then(({ browserSupportsWebAuthn }) => { setSupportsPasskey(browserSupportsWebAuthn()); }); @@ -18,6 +21,10 @@ export default function RegisterPage() { const handleRegisterPasskey = async (e: React.FormEvent) => { e.preventDefault(); + if (!termsAccepted) { + setError(t("auth.termsRequired")); + return; + } setError(null); setLoading(true); @@ -25,7 +32,7 @@ export default function RegisterPage() { const startResp = await fetch("/api/auth/register", { method: "POST", headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ step: "start", email, username }), + body: JSON.stringify({ step: "start", email, username, termsAccepted }), }); const startData = await startResp.json(); @@ -45,6 +52,7 @@ export default function RegisterPage() { step: "finish", email, username, + termsAccepted, response: webAuthnResp, challenge: startData.options.challenge, userId: startData.userId, @@ -66,6 +74,10 @@ export default function RegisterPage() { const handleRegisterMagicLink = async (e: React.FormEvent) => { e.preventDefault(); + if (!termsAccepted) { + setError(t("auth.termsRequired")); + return; + } setError(null); setLoading(true); @@ -73,7 +85,7 @@ export default function RegisterPage() { const resp = await fetch("/api/auth/register", { method: "POST", headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ step: "register-magic-link", email, username }), + body: JSON.stringify({ step: "register-magic-link", email, username, termsAccepted }), }); const result = await resp.json(); @@ -143,10 +155,33 @@ export default function RegisterPage() { placeholder="alice" />

- Your handle will be @{username || "..."}@{typeof window !== "undefined" ? window.location.hostname : "trails.cool"} + {t("auth.handleWillBe", { + handle: `@${username || "…"}@${hostname}`, + })}

+ + {error && (

{error}

)} @@ -154,7 +189,7 @@ export default function RegisterPage() { {supportsPasskey ? ( + + +
+ +
+ + ); +} diff --git a/openspec/specs/journal-auth/spec.md b/openspec/specs/journal-auth/spec.md index 2949f10..2806cdc 100644 --- a/openspec/specs/journal-auth/spec.md +++ b/openspec/specs/journal-auth/spec.md @@ -32,3 +32,26 @@ The registration form SHALL require explicit acknowledgement of the Terms of Ser #### Scenario: Missing version rejected - **WHEN** a registration request arrives without a non-empty `termsVersion` field - **THEN** the server responds with HTTP 400 and does not create a user + +### Requirement: Re-accept updated Terms on next visit +Logged-in users whose stored `terms_version` does not match the currently-published version SHALL be prompted to accept the current Terms before accessing any non-allow-listed page. + +#### Scenario: Stale version redirects to accept-terms page +- **WHEN** a logged-in user whose `users.terms_version` is NULL or differs from the current `TERMS_VERSION` requests any page outside the allow-list (`/auth/accept-terms`, `/auth/logout`, `/legal/*`) +- **THEN** the server redirects them to `/auth/accept-terms?returnTo=` + +#### Scenario: Allow-list keeps Terms and logout reachable +- **WHEN** the same user requests `/legal/terms`, `/legal/privacy`, `/legal/imprint`, `/auth/accept-terms`, or `/auth/logout` +- **THEN** the request is served normally without being redirected + +#### Scenario: Successful re-acceptance updates both fields +- **WHEN** a user submits the acceptance form with the required checkbox ticked +- **THEN** the server updates `users.terms_version` to the current version and `users.terms_accepted_at` to the current timestamp, then redirects to the `returnTo` path (or `/`) + +#### Scenario: Re-acceptance rejects missing consent +- **WHEN** the form is submitted without the checkbox ticked +- **THEN** the server responds with HTTP 400 and does not update the user row + +#### Scenario: returnTo is restricted to same-origin paths +- **WHEN** a `returnTo` value is not a same-origin absolute path (missing leading `/`, or starting with `//`) +- **THEN** the server redirects to `/` instead, preventing open-redirect abuse diff --git a/packages/i18n/src/locales/de.ts b/packages/i18n/src/locales/de.ts index f17e32b..b4cb12c 100644 --- a/packages/i18n/src/locales/de.ts +++ b/packages/i18n/src/locales/de.ts @@ -288,6 +288,13 @@ export default { alreadyHaveAccount: "Bereits ein Konto?", handleWillBe: "Dein Handle wird {{handle}} sein", passkeyNotFound: "Für diese Seite wurde kein Passkey gefunden. Registriere ein neues Konto oder nutze stattdessen einen Magic Link.", + reaccept: { + heading: "Aktualisierte Nutzungsbedingungen", + bodyUpdated: "Die Nutzungsbedingungen wurden aktualisiert (von Version {{from}} auf {{to}}). Bitte lies und akzeptiere sie, um trails.cool weiter zu nutzen.", + bodyNew: "Ab sofort erfassen wir, welche Version der Nutzungsbedingungen du akzeptiert hast. Bitte lies die aktuelle Version ({{version}}) und akzeptiere sie, um trails.cool weiter zu nutzen.", + submit: "Akzeptieren und fortfahren", + logoutInstead: "Stattdessen abmelden", + }, registerDescription: "Registriere dich mit einem Passkey — kein Passwort nötig.", registerWithPasskey: "Mit Passkey registrieren", creatingPasskey: "Erstelle Passkey...", diff --git a/packages/i18n/src/locales/en.ts b/packages/i18n/src/locales/en.ts index a4c9a15..f41764d 100644 --- a/packages/i18n/src/locales/en.ts +++ b/packages/i18n/src/locales/en.ts @@ -288,6 +288,13 @@ export default { alreadyHaveAccount: "Already have an account?", handleWillBe: "Your handle will be {{handle}}", passkeyNotFound: "No passkey found for this site. Register a new account or use a magic link instead.", + reaccept: { + heading: "Updated Terms of Service", + bodyUpdated: "The Terms of Service have been updated (from version {{from}} to {{to}}). Please review and accept to continue using trails.cool.", + bodyNew: "We now record which version of the Terms of Service you've accepted. Please review the current version ({{version}}) and accept to continue using trails.cool.", + submit: "Accept and continue", + logoutInstead: "Log out instead", + }, registerDescription: "Register with a passkey — no password needed.", registerWithPasskey: "Register with Passkey", creatingPasskey: "Creating passkey...", From 5b40bd9b0059790945fa1e17187a2a8f3346d0a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Sun, 19 Apr 2026 08:13:24 +0200 Subject: [PATCH 043/494] Show empty-state CTA on Route detail page when no waypoints MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Observed: both non-maintainer users (pistazie, nelli) created a route, never planned in it, and stopped. The Route detail page rendered as a dead end — name, a row of buttons, then blank. Changes: - Detect "empty" as no geometry AND no distance (the state every new route has before any planning happens). - When empty, hide the top-row button cluster (Edit in Planner / Edit / Export GPX) and render a centered dashed-border card in its place. - Card shows: large headline, short body (owner-specific vs viewer-only copy), primary "Open in Planner" button (same action as the existing top-row button, just visually prominent), and a secondary "or upload a GPX file" link to the edit page. - Bilingual copy added under routes.empty.*. No non-empty route loses any UI — those paths stay identical. Co-Authored-By: Claude Opus 4.7 (1M context) --- apps/journal/app/routes/routes.$id.tsx | 36 +++++++++++++++++++++++++- packages/i18n/src/locales/de.ts | 7 +++++ packages/i18n/src/locales/en.ts | 7 +++++ 3 files changed, 49 insertions(+), 1 deletion(-) diff --git a/apps/journal/app/routes/routes.$id.tsx b/apps/journal/app/routes/routes.$id.tsx index 5623e31..821bc1b 100644 --- a/apps/journal/app/routes/routes.$id.tsx +++ b/apps/journal/app/routes/routes.$id.tsx @@ -99,6 +99,11 @@ export default function RouteDetailPage({ loaderData }: Route.ComponentProps) { const [editLoading, setEditLoading] = useState(false); const [highlightedDay, setHighlightedDay] = useState(null); + // A route is "empty" when it has no geometry and no computed distance — + // i.e. nobody has planned any waypoints yet. Surfaced as a dedicated + // empty-state below so the page isn't a dead end. + const isEmpty = !route.geojson && route.distance == null; + const handleEditInPlanner = useCallback(async () => { setEditLoading(true); try { @@ -121,7 +126,7 @@ export default function RouteDetailPage({ loaderData }: Route.ComponentProps) {

{route.description}

)} - {isOwner && ( + {isOwner && !isEmpty && (
+ + {t("routes.empty.uploadGpx")} + +
+ )} + + )} + {versions.length > 0 && (

Version History

diff --git a/packages/i18n/src/locales/de.ts b/packages/i18n/src/locales/de.ts index b4cb12c..87af7f4 100644 --- a/packages/i18n/src/locales/de.ts +++ b/packages/i18n/src/locales/de.ts @@ -179,6 +179,13 @@ export default { noRoutesYet: "Noch keine Routen. Erstelle deine erste Route!", noMapPreview: "Keine Kartenvorschau", saveChanges: "Änderungen speichern", + empty: { + heading: "Diese Route ist leer", + bodyOwner: "Du hast noch keine Wegpunkte geplant. Öffne sie im Planer, um eine Strecke zu skizzieren, oder lade eine GPX-Datei hoch.", + bodyViewer: "Diese Route enthält noch keine Wegpunkte.", + openInPlanner: "Im Planer öffnen", + uploadGpx: "oder eine GPX-Datei hochladen", + }, }, activities: { title: "Aktivitäten", diff --git a/packages/i18n/src/locales/en.ts b/packages/i18n/src/locales/en.ts index f41764d..1560842 100644 --- a/packages/i18n/src/locales/en.ts +++ b/packages/i18n/src/locales/en.ts @@ -179,6 +179,13 @@ export default { noRoutesYet: "No routes yet. Create your first route!", noMapPreview: "No map preview", saveChanges: "Save Changes", + empty: { + heading: "This route is empty", + bodyOwner: "You haven't planned any waypoints yet. Open it in the Planner to sketch a path, or upload a GPX file.", + bodyViewer: "This route doesn't have any waypoints yet.", + openInPlanner: "Open in Planner", + uploadGpx: "or upload a GPX file", + }, }, activities: { title: "Activities", From 621d91e14f0f5b41943c71c516de384d3d668265 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Sun, 19 Apr 2026 08:23:44 +0200 Subject: [PATCH 044/494] Park mobile-activity-recording + mobile-nearby-sync under docs/ideas Both are blocked on the mobile-app foundation and on a user base that actually records activities or needs offline peer sync. With 3 users and 0 activities on prod today, these are engineering for a hypothetical population. Move the artifact sets out of openspec/changes/ (so openspec list stays clean) and under docs/ideas/ where self-host-overpass already lives. Each gets a short README documenting: - current parked status - revive triggers (when should we look at this again?) - key constraints not to rediscover (background-GPS privacy review; BLE dev-build requirement; QR-only subset as a cheaper path) Reviving is `git mv docs/ideas/ openspec/changes/` and running /opsx:apply, same pattern as self-host-overpass. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../mobile-activity-recording/.openspec.yaml | 0 .../ideas/mobile-activity-recording/README.md | 39 +++++++++++++++++ .../mobile-activity-recording/proposal.md | 0 .../specs/mobile-activity-recording/spec.md | 0 .../ideas}/mobile-nearby-sync/.openspec.yaml | 0 docs/ideas/mobile-nearby-sync/README.md | 43 +++++++++++++++++++ .../ideas}/mobile-nearby-sync/proposal.md | 0 .../specs/mobile-nearby-sync/spec.md | 0 8 files changed, 82 insertions(+) rename {openspec/changes => docs/ideas}/mobile-activity-recording/.openspec.yaml (100%) create mode 100644 docs/ideas/mobile-activity-recording/README.md rename {openspec/changes => docs/ideas}/mobile-activity-recording/proposal.md (100%) rename {openspec/changes => docs/ideas}/mobile-activity-recording/specs/mobile-activity-recording/spec.md (100%) rename {openspec/changes => docs/ideas}/mobile-nearby-sync/.openspec.yaml (100%) create mode 100644 docs/ideas/mobile-nearby-sync/README.md rename {openspec/changes => docs/ideas}/mobile-nearby-sync/proposal.md (100%) rename {openspec/changes => docs/ideas}/mobile-nearby-sync/specs/mobile-nearby-sync/spec.md (100%) diff --git a/openspec/changes/mobile-activity-recording/.openspec.yaml b/docs/ideas/mobile-activity-recording/.openspec.yaml similarity index 100% rename from openspec/changes/mobile-activity-recording/.openspec.yaml rename to docs/ideas/mobile-activity-recording/.openspec.yaml diff --git a/docs/ideas/mobile-activity-recording/README.md b/docs/ideas/mobile-activity-recording/README.md new file mode 100644 index 0000000..ccc2075 --- /dev/null +++ b/docs/ideas/mobile-activity-recording/README.md @@ -0,0 +1,39 @@ +# mobile-activity-recording (parked) + +OpenSpec change for recording GPS activities on-device in the mobile app +(ride/hike tracking, live stats, save as Journal activity, HealthKit / +Health Connect export). Moved here from `openspec/changes/` so it does not +clutter the active change list; revive by moving the directory back under +`openspec/changes/` when ready to implement. + +## Status + +**Parked.** Blocked on `mobile-app` (the foundation change) landing first, +and on there being enough Journal users actually logging activities to +justify the native-recording complexity. At the current user count (3) and +activity count (0), shipping this would be writing code for nobody. + +## When to revive + +Revisit once **any** of these is true: + +- The mobile app is live and users are asking to record from the phone + instead of importing from Wahoo/Garmin/Komoot later +- The web Journal has a meaningful stream of imported activities, so the + feature lands into an existing behaviour rather than inventing one +- A specific user request justifies the iOS/Android background-location + privacy review (App Store's bar for background GPS is high) + +## Key constraints to remember + +- **Background GPS requires explicit user consent + justification** on iOS + and Android. App Store privacy review will scrutinise this. +- **Dependencies**: `expo-location` for the track, plus `expo-health` (or + equivalent) for HealthKit / Health Connect integration. +- **Battery**: continuous GPS at high accuracy is a power-hungry path; + recording UI needs clear on/off state and resumption. + +## What's in the folder + +- `proposal.md` — why / what / impact +- `specs/` — delta specs (would land against a new `mobile-activity-recording` capability) diff --git a/openspec/changes/mobile-activity-recording/proposal.md b/docs/ideas/mobile-activity-recording/proposal.md similarity index 100% rename from openspec/changes/mobile-activity-recording/proposal.md rename to docs/ideas/mobile-activity-recording/proposal.md diff --git a/openspec/changes/mobile-activity-recording/specs/mobile-activity-recording/spec.md b/docs/ideas/mobile-activity-recording/specs/mobile-activity-recording/spec.md similarity index 100% rename from openspec/changes/mobile-activity-recording/specs/mobile-activity-recording/spec.md rename to docs/ideas/mobile-activity-recording/specs/mobile-activity-recording/spec.md diff --git a/openspec/changes/mobile-nearby-sync/.openspec.yaml b/docs/ideas/mobile-nearby-sync/.openspec.yaml similarity index 100% rename from openspec/changes/mobile-nearby-sync/.openspec.yaml rename to docs/ideas/mobile-nearby-sync/.openspec.yaml diff --git a/docs/ideas/mobile-nearby-sync/README.md b/docs/ideas/mobile-nearby-sync/README.md new file mode 100644 index 0000000..ee23976 --- /dev/null +++ b/docs/ideas/mobile-nearby-sync/README.md @@ -0,0 +1,43 @@ +# mobile-nearby-sync (parked) + +OpenSpec change for sharing routes between nearby devices without internet +(BLE-based peer sync + QR-code waypoint fallback) in the mobile app. +Moved here from `openspec/changes/` so it does not clutter the active +change list; revive by moving the directory back under +`openspec/changes/` when ready to implement. + +## Status + +**Parked.** Blocked on `mobile-app` landing first, and on there being +enough users actually hiking/bikepacking together to justify the BLE +complexity. At the current user count (3) this is engineering for a +hypothetical group trip. + +## When to revive + +Revisit once **any** of these is true: + +- The mobile app is live and users start reporting "we were in a dead zone + and couldn't update the route" +- A group / tour organiser asks specifically for peer-to-peer route sync +- QR-code waypoint sharing alone (the simpler half of this spec) would + cover the need — worth shipping that first as a narrower change + +## Key constraints to remember + +- **Requires an Expo dev build** — `react-native-ble-plx` isn't available + in Expo Go. +- **iOS + Android BLE APIs differ significantly**; expect platform-specific + bugs. Background BLE advertising has battery and OS-lifecycle caveats + (iOS suspends advertising when backgrounded after a grace period). +- **Permissions sprawl**: iOS `NSBluetoothAlwaysUsageDescription`, Android + `BLUETOOTH_SCAN` + `BLUETOOTH_CONNECT` + `BLUETOOTH_ADVERTISE`, plus + location on older Android. +- **QR waypoint sharing is an order of magnitude simpler** than BLE and + covers a big chunk of the use case — consider extracting that as a + separate, earlier change if the need becomes real. + +## What's in the folder + +- `proposal.md` — why / what / non-goals / impact / future ideas (TXQR) +- `specs/` — delta specs (would land against a new `mobile-nearby-sync` capability) diff --git a/openspec/changes/mobile-nearby-sync/proposal.md b/docs/ideas/mobile-nearby-sync/proposal.md similarity index 100% rename from openspec/changes/mobile-nearby-sync/proposal.md rename to docs/ideas/mobile-nearby-sync/proposal.md diff --git a/openspec/changes/mobile-nearby-sync/specs/mobile-nearby-sync/spec.md b/docs/ideas/mobile-nearby-sync/specs/mobile-nearby-sync/spec.md similarity index 100% rename from openspec/changes/mobile-nearby-sync/specs/mobile-nearby-sync/spec.md rename to docs/ideas/mobile-nearby-sync/specs/mobile-nearby-sync/spec.md From dcbd703f4767230e840672be09acb30ee352a9ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Sun, 19 Apr 2026 08:49:59 +0200 Subject: [PATCH 045/494] Propose social MVP: public-content-visibility + demo-activity-bot MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two stacked OpenSpec change proposals for a demoable social layer, with scope deliberately minimal ("enough to send a URL and have it open to real-looking content without signup"): 1. public-content-visibility - Adds visibility enum {private, unlisted, public} on routes + activities, defaulting to private for every existing row. - Detail pages (/routes/:id, /activities/:id) become accessible to logged-out visitors when content is public or unlisted; private → 404 (not 403) to avoid existence leaks. - Broadens /users/:username into a public profile listing only public routes + activities; 404s when there's no public content to prevent account enumeration. - Open Graph / Twitter Card meta on public detail + profile pages. - Visibility selector in the owner's edit flow. - Out of scope: follow/follower, cross-user feed, reactions, federation. 2. demo-activity-bot (depends on #1) - A single bot user, Bruno the trail dog, seeded on worker startup when DEMO_BOT_ENABLED=true. Reserved username, sentinel email, no credentials. - pg-boss recurring job fires every 90 min, decides-to-walk with p=0.12 during 07:00-21:00 local, yielding ~2-3 walks/day at organic times. - Each walk: random start + end within inner-Berlin bbox, trekking only (dogs don't ride bikes), 2-12 km crow. BRouter plans the route; the route GPX is also attached as the activity's trace. - Everything inserted with visibility=public, synthetic=true. - Daily prune deletes synthetic rows > DEMO_BOT_RETENTION_DAYS old (default 14). Hard cap of 40 items/14d protects against runaway growth. - Small "🐕 demo account" badge on /users/bruno for honesty. Both changes are artifacts only — no code lands with this PR. Apply in order after merge: public-content-visibility first, then demo-activity-bot. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../changes/demo-activity-bot/.openspec.yaml | 2 + openspec/changes/demo-activity-bot/design.md | 154 ++++++++++++++++++ .../changes/demo-activity-bot/proposal.md | 35 ++++ .../specs/activity-feed/spec.md | 16 ++ .../specs/demo-activity-bot/spec.md | 77 +++++++++ .../specs/route-management/spec.md | 16 ++ openspec/changes/demo-activity-bot/tasks.md | 72 ++++++++ .../public-content-visibility/.openspec.yaml | 2 + .../public-content-visibility/design.md | 111 +++++++++++++ .../public-content-visibility/proposal.md | 37 +++++ .../specs/activity-feed/spec.md | 48 ++++++ .../specs/public-profiles/spec.md | 22 +++ .../specs/route-management/spec.md | 52 ++++++ .../public-content-visibility/tasks.md | 62 +++++++ 14 files changed, 706 insertions(+) create mode 100644 openspec/changes/demo-activity-bot/.openspec.yaml create mode 100644 openspec/changes/demo-activity-bot/design.md create mode 100644 openspec/changes/demo-activity-bot/proposal.md create mode 100644 openspec/changes/demo-activity-bot/specs/activity-feed/spec.md create mode 100644 openspec/changes/demo-activity-bot/specs/demo-activity-bot/spec.md create mode 100644 openspec/changes/demo-activity-bot/specs/route-management/spec.md create mode 100644 openspec/changes/demo-activity-bot/tasks.md create mode 100644 openspec/changes/public-content-visibility/.openspec.yaml create mode 100644 openspec/changes/public-content-visibility/design.md create mode 100644 openspec/changes/public-content-visibility/proposal.md create mode 100644 openspec/changes/public-content-visibility/specs/activity-feed/spec.md create mode 100644 openspec/changes/public-content-visibility/specs/public-profiles/spec.md create mode 100644 openspec/changes/public-content-visibility/specs/route-management/spec.md create mode 100644 openspec/changes/public-content-visibility/tasks.md diff --git a/openspec/changes/demo-activity-bot/.openspec.yaml b/openspec/changes/demo-activity-bot/.openspec.yaml new file mode 100644 index 0000000..c8af3f5 --- /dev/null +++ b/openspec/changes/demo-activity-bot/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-driven +created: 2026-04-19 diff --git a/openspec/changes/demo-activity-bot/design.md b/openspec/changes/demo-activity-bot/design.md new file mode 100644 index 0000000..2925617 --- /dev/null +++ b/openspec/changes/demo-activity-bot/design.md @@ -0,0 +1,154 @@ +## Context + +The Journal runs on a single Hetzner Cloud container with Postgres + PostGIS, BRouter as a sibling compose service, and pg-boss already configured as the background-job queue (`apps/journal/server.ts` boots a worker on startup). `public-content-visibility` introduces a `visibility` column on routes + activities; once that lands, a piece of content marked `public` is viewable by logged-out visitors at its permanent URL and on the owner's `/users/:username` profile. + +This change layers a synthetic-content generator on top. The motivation is narrow — a non-empty feed for prospective users we're demoing to. The design matches that: **cheap, single-region, single-user, single-purpose**. Nothing here should generalise to "simulate a real community"; the bot is allowed to look slightly repetitive because it exists to fill an empty demo, not to fake scale. + +Adjacent context: +- BRouter runs internally and already rate-limits per-session at the Planner, but here we're inside the Journal server, so the bot controls its own cadence rather than sharing a limiter with user-driven routing. Load is low — at most a handful of routes per day. +- pg-boss supports cron-style recurring schedules and singleton jobs (no concurrent duplicates), which are exactly what we need. + +## Goals / Non-Goals + +**Goals:** +- A logged-out visitor landing on `trails.cool/users/demo` sees a recent-looking public profile with several routes and activities. +- The content is generated entirely on-host, with no third-party data calls. +- Synthetic content is trivially separable from real content (single boolean flag). +- The bot can be disabled without a deploy (env flag) and its output wiped with a single DELETE. +- Cadence is boring. One content item every few hours is enough — we are not trying to pretend a Strava-scale community. + +**Non-Goals:** +- Realistic social signals (likes, comments, follower counts). +- Multiple bot personas or multi-region coverage. +- Route topology tricks beyond "point-to-point via BRouter" (no multi-day, no loops, no no-go areas). +- Photos or media on activities. +- Running the bot in local dev / CI / staging — disabled by default everywhere except prod. + +## Decisions + +### Single bot user: Bruno the trail dog + +**Decision:** One account with: + +- Username: `bruno` (reserved; a later real registration with that username is blocked) +- Display name: `Bruno` +- Bio: short, whimsical, something like *"Professional park inspector. Currently accepting tennis balls."* +- Sentinel email: `bruno@` — unroutable, so magic-link login cannot succeed +- No passkey credentials +- `terms_accepted_at` / `terms_version` populated to the current values at bootstrap + +The persona is a park-walking dog whose "human" logs the walks. This choice: + +- Makes the bot legibly fictional at a glance — a dog account with emoji-laced names reads as *charming*, not as a real-user-you're-being-tricked-into-believing-in. +- Narrows the generator's parameter space (trekking profile only, short distances, urban parks) so output is consistent and failure-prone edge cases get pruned. +- Keeps the copy bank small and writable in one sitting. + +**Alternatives considered:** +- **"Finn" — realistic commuter-cyclist.** Fills the feed convincingly, but deception risk if a visitor later realises. Rejected. +- **"trails.cool test pilot" — explicitly diagnostic.** Honest but dead boring; kills the "lively feed" goal the bot exists for. Rejected. +- **Multi-persona community simulation.** Out of scope for v1. + +### Bruno's generation parameters + +**Decision:** The persona constrains the generator more tightly than the generic v1 draft: + +- **Profile pool**: `["trekking"]` only (dogs don't ride bikes). +- **Distance band**: 2–12 km crow distance between start and end — a realistic walk, not a hike. +- **Region**: Berlin inner (bbox roughly `13.25,52.45,13.55,52.60`), biased toward parks/green areas: Grunewald, Tiergarten, Tempelhofer Feld, Volkspark Friedrichshain, Treptower Park, Müggelsee shoreline. The bbox itself is permissive; the copy just reads as park-flavoured. +- **Started-at window**: 07:00–20:00 local, with a slight bias toward morning/evening ("walkies" times). +- **Copy templates**: a mix of serious-sounding audit language ("Grunewald north-loop patrol") and comic ("Bruno found three sticks today 🐕"). Bilingual EN + DE. + +**Why narrower:** the persona is a feature, not a limitation. Not every dog-walk needs to be in a park, but pretending Bruno walked 40 km across Brandenburg would break the illusion the whole persona exists to prop up. + +### Route generation: BRouter point-to-point in a seed region + +**Decision:** A configured seed region is a bounding box. For the Bruno persona: + +- Region: Berlin inner (`13.25,52.45,13.55,52.60`) — narrower than "Berlin + Brandenburg"; a dog-walk spanning Brandenburg breaks the illusion. +- Profile: `trekking` only (see the Bruno persona decision above). +- Start point: random within the box. +- End point: 2–12 km crow distance from start. +- Query BRouter with those two waypoints and `trekking`; reject and retry if BRouter returns no route or the computed distance is outside a sanity band (say, 1.5–18 km real distance). +- Persist the returned GPX as the route's source of truth and let existing enrichment compute the rest (PostGIS geom, distance, elevation). + +The bbox stays env-configurable; changing `DEMO_BOT_REGION` relocates Bruno without a code change. + +**Alternatives considered:** +- **Pre-recorded GPX files in a corpus.** Chosen by user to be (b) — synthesised via BRouter — in the conversation that led here. Keeps variety cheap and relocatable (change the bbox, new city). +- **Komoot import** — reject, external dependency. +- **Multi-waypoint (3+ stops)** — slight realism gain, much higher generation failure rate (more chances for BRouter to return no-route). Skip. + +### Activity generation follows the route + +**Decision:** When a route is generated, immediately derive an activity from it: + +- `route_id` links to the new route +- `name` and `description` drawn from a small templated set (e.g., "Weekend ride through the Havelland", "Evening loop around Müggelsee") +- `started_at` = today between 06:00 and 20:00 local (random), `duration` = distance ÷ an average speed per profile ± jitter +- `distance`, `elevation_gain`, `elevation_loss` = the route's computed values +- `gpx` = the route's GPX verbatim (the activity "happened" along the planned route) +- `visibility = 'public'`, `synthetic = true` + +**Why bundled:** keeping route + activity generation in one transaction means the feed item is coherent the moment it appears. Separating them just to pretend the user planned then rode feels like theatre — we're not hiding the bot, we're just filling the surface. + +### Cadence and guards + +**Decision:** A dog walks twice a day, sometimes three times, never six. The schedule should look like Bruno's day, not like a cron job. + +- A recurring pg-boss job `demo-bot:generate` fires **every 90 minutes** as a singleton. +- Most ticks decide to *not* walk: the handler rolls a per-tick probability and skips if it doesn't hit. The probability is **0.12 per tick during 07:00–21:00 local, 0 otherwise** — which yields roughly 2–3 walks per day across the day, biased to waking hours. +- This both looks human (walks aren't on a fixed cron) and makes the generation load tiny: one BRouter call per walk, so ~2–3 per day. +- The job skips itself entirely when `process.env.DEMO_BOT_ENABLED !== "true"`. Dev / CI / tests: no-op. +- Hard cap: if there are already ≥ 40 synthetic items in the last 14 days (≈ 3/day × 14 rounded up), skip for that tick. Stops runaway growth if the retention job fails. +- BRouter call per generation: 1. Bot traffic is rounding-error compared to real user traffic. + +**Alternatives considered:** +- **Fixed cron every 4 hours** — boring, too regular, a demo visitor with sharp eyes notices. +- **Poisson process with mean 3/day** — more faithful but more code. The 90-minute-tick-with-probability scheme is close enough. +- **Walk at specific realistic times** (morning, lunch, evening) — adds temporal pattern. Probably worth revisiting once we see the feed in practice, but not worth coding up front. + +### Retention + +**Decision:** A second recurring job `demo-bot:prune` runs daily and deletes synthetic routes + activities whose `created_at` is older than `DEMO_BOT_RETENTION_DAYS` (default 14). Route-version rows cascade-delete via existing FK. + +**Why daily, not weekly:** smaller blast radius if the prune gets something wrong, and it keeps the feed visibly "recent" rather than stable. + +### Flagging synthetic content at the DB level + +**Decision:** Add `synthetic boolean NOT NULL DEFAULT false` to `journal.routes` and `journal.activities`. Set `true` only when the bot inserts. + +**Why:** makes the "delete all bot content" operation a one-liner and lets future listing code exclude synthetic if we decide to, without introspecting content shape or owner. `owner_id = demo_user_id` would almost work as a proxy, but the dedicated flag decouples identity from status — if we later delete and re-seed the demo user we don't lose the signal. + +### Env surface + +**Decision:** +- `DEMO_BOT_ENABLED`: `"true"` turns the generator + prune on; anything else is off. Absent means off. +- `DEMO_BOT_RETENTION_DAYS`: integer, defaults to 14. +- `DEMO_BOT_REGION`: JSON `{ "bbox": [w,s,e,n] }`, defaults to inner Berlin (`13.25,52.45,13.55,52.60`) to suit Bruno's park-walker persona. +- No secrets. The whole feature is public-facing by design. + +## Risks / Trade-offs + +- **BRouter outages halt the feed** → acceptable; the job logs and skips. The feed will stop refreshing but existing items remain visible. +- **Uncanny repetition** (same start neighbourhoods, template names) → mitigated by varying the start point randomly and the templated copy, but still acceptable for a demo. A reviewer will obviously figure out it's synthetic if they look — we're not hiding it. +- **Mistaking bot content for real content during analytics** → mitigated by the `synthetic` flag; analytics queries filter `WHERE synthetic = false` when they want real usage. +- **Runaway insert if retention breaks** → mitigated by the hard cap (50 items in last 14 days) inside the generator. +- **GDPR / privacy concerns** → none new: the bot has no real PII, its content is first-party, and `demo@trails.cool` is a reserved sentinel address. +- **Someone logs in as `demo`** → the user has no credentials (no passkey, no magic-token). Email sentinel means a magic-link request can't succeed either (no inbox). Safe. +- **Accidentally enabled in dev** → mitigated by the explicit env opt-in; default-off in every environment but prod. + +## Migration Plan + +1. Merge schema + code; `drizzle-kit push --force` adds `synthetic` columns. +2. Set `DEMO_BOT_ENABLED=true` on the prod Journal container; leave every other environment off. +3. On next worker restart, the bootstrap step inserts the `demo` user. +4. First generation run produces one route + activity. Verify at `/users/demo`. +5. After a few ticks, verify the feed looks plausible and the prune doesn't fire unexpectedly (it won't, nothing is 14 days old). + +**Rollback:** `DEMO_BOT_ENABLED=false` and redeploy. To wipe all generated content: `DELETE FROM journal.activities WHERE synthetic = true; DELETE FROM journal.routes WHERE synthetic = true;`. The `demo` user row can stay — it's cheap and keeps the URL stable if we re-enable later. + +## Open Questions + +- **Do we want the profile to also get a "synthetic content" badge** so honest readers (and us, on demos) can tell at a glance? A tiny "demo account" pill on `/users/demo` is cheap. Decide during implementation. +- **Should the bot post a few backfilled items on first enablement** so the feed isn't just one item for the first four hours? Probably yes — a small one-time bootstrap that generates 3–5 items immediately if the synthetic-item count is 0. Proposing it as a task. +- **Should BRouter calls be recorded as `brouter_request_duration_seconds` the same as user requests**? Probably — same histogram is fine; synthetic traffic is a small addition and it keeps ops alerts meaningful. diff --git a/openspec/changes/demo-activity-bot/proposal.md b/openspec/changes/demo-activity-bot/proposal.md new file mode 100644 index 0000000..bf6814d --- /dev/null +++ b/openspec/changes/demo-activity-bot/proposal.md @@ -0,0 +1,35 @@ +## Why + +To demo trails.cool to prospective users and contributors we need live-looking content on the public surface introduced by `public-content-visibility`. Today a demo link opens to an empty profile. Even after visibility ships, the Journal has 3 users and 0 activities — the feed shows "nothing happened today," which is the worst possible first impression. + +A synthetic "demo" user that autonomously produces plausible activities closes that gap. It also keeps pressure on the content-creation code paths: if the bot is wedged, the import / routing / geometry pipelines are probably broken for real users too. + +This change is the direct follow-up to `public-content-visibility` and is only useful once that lands. + +## What Changes + +- A dedicated bot user account (username e.g. `demo`) is bootstrapped on first run with a stable ID, a public display name, and `visibility` defaults that mark its content public. +- A recurring pg-boss job (the existing background-jobs infrastructure on the Journal host) runs every few hours, chooses a random start + end point within a configured seed region, asks BRouter for a route, persists the route + a derived activity attributed to the demo user with `visibility = 'public'`. +- Synthetic rows are explicitly flagged at the database level (`synthetic boolean NOT NULL DEFAULT false`) so a single DELETE can clean them up and listings can optionally exclude them later. +- A retention job trims synthetic activities older than a configurable window (default 14 days) so the feed looks fresh, not a swamp of old rides. +- Everything is gated behind a `DEMO_BOT_ENABLED` env flag. Local dev, CI, and tests default to disabled. The flag is set on prod only. +- Route profiles vary: trekking and fastbike, with plausible distance ranges for each. Start times of day look reasonable. Names and descriptions draw from a small templated copy set (in both EN and DE). + +## Capabilities + +### New Capabilities +- `demo-activity-bot`: A bot user, a scheduler that seeds plausible public routes + activities using BRouter and a seed region, and a retention job to keep the feed bounded. + +### Modified Capabilities +- `route-management`: adds a `synthetic` flag alongside the `visibility` work from `public-content-visibility`, so listings and exports can distinguish bot content if they ever need to. +- `activity-feed`: same `synthetic` flag for symmetry. + +## Impact + +- **Code**: new `apps/journal/app/jobs/demo-bot.ts` for the job handlers, small helpers for picking seed coordinates and templating names, a one-time bootstrap that inserts the demo user if missing. +- **Data**: a schema change (the `synthetic` column on two tables) plus ongoing inserts into those same tables. Bounded by the retention job. +- **Infrastructure**: no new services — pg-boss is already in the stack. `DEMO_BOT_ENABLED` is a new env var on the prod Journal container. +- **External calls**: BRouter calls from the bot; throttled at the scheduler level so the bot never competes with real user traffic. No external API beyond BRouter. +- **Privacy**: the bot user has no real email, no PII, and its content is clearly author-attributed to `demo`. The legal / privacy pages do not need to change — this is first-party content the operator controls. +- **Non-goals (explicit)**: realistic social signals (no likes/comments on demo content), multi-user bot personas (one user for v1), cross-region variety (one seed region), multi-day tours, photos or media attachments. +- **Rollback**: flip `DEMO_BOT_ENABLED=false` — the job stops. A single `DELETE FROM ... WHERE synthetic = true` removes all bot content without touching real data. diff --git a/openspec/changes/demo-activity-bot/specs/activity-feed/spec.md b/openspec/changes/demo-activity-bot/specs/activity-feed/spec.md new file mode 100644 index 0000000..a2ec420 --- /dev/null +++ b/openspec/changes/demo-activity-bot/specs/activity-feed/spec.md @@ -0,0 +1,16 @@ +## ADDED Requirements + +### Requirement: Synthetic activity flag +The Journal SHALL persist a `synthetic` boolean on every activity so automated / demo content can be distinguished from user-created content. + +#### Scenario: User-created activities default to non-synthetic +- **WHEN** an activity is created through any user-facing flow (GPX upload, sync import, Planner handoff) +- **THEN** the activity row is persisted with `synthetic = false` + +#### Scenario: Bot inserts flag their rows as synthetic +- **WHEN** the demo-activity-bot inserts an activity +- **THEN** the row is persisted with `synthetic = true` + +#### Scenario: Synthetic flag is not user-editable +- **WHEN** an activity owner edits the activity via any user-facing action +- **THEN** the stored `synthetic` value is not changed by the edit diff --git a/openspec/changes/demo-activity-bot/specs/demo-activity-bot/spec.md b/openspec/changes/demo-activity-bot/specs/demo-activity-bot/spec.md new file mode 100644 index 0000000..169c7ca --- /dev/null +++ b/openspec/changes/demo-activity-bot/specs/demo-activity-bot/spec.md @@ -0,0 +1,77 @@ +## ADDED Requirements + +### Requirement: Demo user bootstrap +The Journal SHALL ensure a dedicated bot user exists when the demo bot starts, creating it on first run if missing. + +#### Scenario: Bot user created on first run +- **WHEN** the Journal worker starts with `DEMO_BOT_ENABLED=true` and no `users` row matches the reserved demo username +- **THEN** a new `users` row is inserted with the reserved username, a public-facing display name, a sentinel email (`demo@`), no passkey credentials, and `terms_accepted_at` + `terms_version` populated at the current version +- **AND** subsequent worker startups are idempotent — no second row is inserted + +#### Scenario: Demo user has no usable credentials +- **WHEN** any request attempts to authenticate as the demo user via passkey or magic-link +- **THEN** authentication fails because no passkey is registered and no mailbox receives magic-link mails + +### Requirement: Synthetic content generation job +The Journal SHALL run a recurring background job that generates one public route and one linked public activity for the demo user per run, subject to an env flag and a rate cap. + +#### Scenario: Disabled in non-production environments +- **WHEN** the `DEMO_BOT_ENABLED` env var is absent or any value other than `"true"` +- **THEN** the job body is a no-op: no BRouter calls, no inserts, no errors + +#### Scenario: Enabled generation flow (decide-to-walk fires) +- **WHEN** `DEMO_BOT_ENABLED=true`, the local hour is within 07:00–21:00, the per-tick Bernoulli roll fires, and the hard cap has not been reached +- **THEN** the job picks a random start and end point within the configured seed region, calls BRouter with the `trekking` profile, persists the returned GPX as a new route with `visibility='public'` and `synthetic=true`, and inserts a linked activity with the same GPX, `visibility='public'`, `synthetic=true`, a plausible `started_at` and `duration`, and a templated Bruno-voiced name/description +- **AND** the route and activity are attributed to the demo user + +#### Scenario: Decide-to-walk does not fire +- **WHEN** the local hour is outside 07:00–21:00, or the Bernoulli roll does not fire +- **THEN** the job returns without inserting anything — Bruno just isn't walking right now + +#### Scenario: BRouter failure is tolerated +- **WHEN** the BRouter call returns no route, a rate-limit, or an error +- **THEN** the job logs the failure, inserts nothing, and exits without throwing — the next scheduled tick retries + +#### Scenario: Hard cap prevents runaway growth +- **WHEN** there are already 40 or more synthetic items created in the last 14 days +- **THEN** the job skips generation for that tick + +#### Scenario: Singleton scheduling prevents overlap +- **WHEN** a tick fires while the previous run is still executing +- **THEN** the new tick is skipped (pg-boss singleton semantics) so the job cannot overlap itself + +### Requirement: Synthetic content retention +The Journal SHALL run a recurring job that deletes synthetic routes and activities older than a configurable window. + +#### Scenario: Prune removes old synthetic content +- **WHEN** the prune job runs with `DEMO_BOT_RETENTION_DAYS=14` +- **THEN** every row in `journal.routes` and `journal.activities` with `synthetic=true` and `created_at < now() - 14 days` is deleted +- **AND** route-version rows cascade-delete via existing foreign keys +- **AND** rows with `synthetic=false` are never touched + +#### Scenario: Prune is a no-op when nothing is old +- **WHEN** the prune job runs and no synthetic rows exceed the retention window +- **THEN** no DELETE statements execute and the job returns normally + +#### Scenario: Disabled in non-production environments +- **WHEN** `DEMO_BOT_ENABLED` is not `"true"` +- **THEN** the prune job body is a no-op + +### Requirement: Initial backfill +On first enablement (when no synthetic content exists yet) the Journal SHALL populate the demo profile with a small batch of items so the first visitor does not see a single-item feed. + +#### Scenario: First enablement backfills several items +- **WHEN** the bot is enabled for the first time and the count of synthetic routes is 0 +- **THEN** the generation job produces 3–5 items in sequence during its first run +- **AND** subsequent runs produce one item at a time as normal + +### Requirement: Seed region is configurable +The Journal SHALL read the seed region (bounding box) from an env var so the deployment can change it without a code change. + +#### Scenario: Env-configured region +- **WHEN** `DEMO_BOT_REGION` is set to a JSON object containing a `bbox` array of four numbers `[west, south, east, north]` +- **THEN** all generated start and end points fall within that box + +#### Scenario: Sensible default +- **WHEN** `DEMO_BOT_REGION` is unset +- **THEN** the job uses a documented default region (inner Berlin) so that out-of-the-box runs still produce plausible Bruno-style walks diff --git a/openspec/changes/demo-activity-bot/specs/route-management/spec.md b/openspec/changes/demo-activity-bot/specs/route-management/spec.md new file mode 100644 index 0000000..a61f717 --- /dev/null +++ b/openspec/changes/demo-activity-bot/specs/route-management/spec.md @@ -0,0 +1,16 @@ +## ADDED Requirements + +### Requirement: Synthetic route flag +The Journal SHALL persist a `synthetic` boolean on every route so automated / demo content can be distinguished from user-created content. + +#### Scenario: User-created routes default to non-synthetic +- **WHEN** a route is created through any user-facing flow (New Route, GPX import, Planner handoff) +- **THEN** the route row is persisted with `synthetic = false` + +#### Scenario: Bot inserts flag their rows as synthetic +- **WHEN** the demo-activity-bot inserts a route +- **THEN** the row is persisted with `synthetic = true` + +#### Scenario: Synthetic flag is not user-editable +- **WHEN** a route owner edits a route via any user-facing action +- **THEN** the stored `synthetic` value is not changed by the edit diff --git a/openspec/changes/demo-activity-bot/tasks.md b/openspec/changes/demo-activity-bot/tasks.md new file mode 100644 index 0000000..f8170a8 --- /dev/null +++ b/openspec/changes/demo-activity-bot/tasks.md @@ -0,0 +1,72 @@ +## 1. Schema + +- [ ] 1.1 Add `synthetic boolean NOT NULL DEFAULT false` to `journal.routes` in `packages/db/src/schema/journal.ts` +- [ ] 1.2 Add the same column to `journal.activities` +- [ ] 1.3 Verify existing CRUD helpers (`createRoute`, `updateRoute`, `createActivity`, `listRoutes`, `listActivities`) compile and ignore the new column for default callers + +## 2. Bruno bootstrap + +- [ ] 2.1 Reserved username: `bruno`. Sentinel email: `bruno@`. Display name: `Bruno`. Bio: a short whimsical line (finalise exact wording during apply — e.g. "Professional park inspector. Currently accepting tennis balls."). +- [ ] 2.2 Add an `ensureDemoUser()` helper in `apps/journal/app/lib/demo-bot.server.ts` that inserts the `bruno` row only if missing (idempotent via `ON CONFLICT DO NOTHING` on `username`), with `terms_accepted_at` and `terms_version` populated. +- [ ] 2.3 Call `ensureDemoUser()` from the worker startup sequence when `DEMO_BOT_ENABLED === "true"`. +- [ ] 2.4 Confirm Bruno has no credentials row; the passkey and magic-link login paths both fail for his email (no mailbox exists for `bruno@`). + +## 3. Region + generation helpers + +- [ ] 3.1 Add `loadRegion()` that reads `DEMO_BOT_REGION` JSON (with `bbox: [w,s,e,n]`) and falls back to the inner-Berlin default `[13.25, 52.45, 13.55, 52.60]` +- [ ] 3.2 Add `pickEndpoints(bbox)` — random start + end, 2–12 km crow distance apart (dog-walk scale) +- [ ] 3.3 Profile is fixed to `trekking` (Bruno doesn't ride bikes); no `pickProfile()` needed for v1 +- [ ] 3.4 Add `templateName(startedAt)` + `templateDescription()` — EN + DE Bruno-voiced copy, mixing serious-audit flavour ("Grunewald north-loop patrol") and comic ("Bruno found three sticks today 🐕"); 10–15 entries in each pool, picked deterministically from the day + started-at to avoid same-day repeats + +## 4. BRouter client for the bot + +- [ ] 4.1 Reuse the existing `computeRoute` helper where possible; otherwise add a minimal `brouter-client.server.ts` that POSTs to `process.env.BROUTER_URL` and returns parsed GPX + stats +- [ ] 4.2 On no-route / 5xx / timeout, return a typed "no route" error — the job handles it, does not throw out of the worker + +## 5. Generation job + +- [ ] 5.1 Register a pg-boss recurring job `demo-bot:generate` to fire every 90 minutes, singleton mode +- [ ] 5.2 Handler: skip immediately if `DEMO_BOT_ENABLED !== "true"` +- [ ] 5.3 Decide-to-walk gate: compute local hour; if outside 07:00–21:00 → skip. Otherwise roll a Bernoulli with p=0.12 and skip if it doesn't fire. Expected output: ~2–3 walks/day +- [ ] 5.4 Hard cap: `SELECT count(*) FROM routes WHERE synthetic AND created_at > now() - interval '14 days'`; skip if >= 40 +- [ ] 5.5 Pick region + endpoints (profile is fixed to `trekking`); call BRouter; on failure log and return +- [ ] 5.6 Insert route with `visibility='public'`, `synthetic=true`, owner = Bruno; insert linked activity with derived `started_at` = now, `duration` = distance ÷ ~4.5 km/h ± jitter, stats, and the same GPX + +## 6. Initial backfill + +- [ ] 6.1 At the top of the generation handler, check if `count(synthetic routes) == 0`; if so, loop up to 5 times running the full generation body sequentially (each call independent — if one fails, keep going) +- [ ] 6.2 After the backfill path, fall through to the normal single-item generation + +## 7. Retention job + +- [ ] 7.1 Register a pg-boss recurring job `demo-bot:prune` with a cron like `15 3 * * *` (daily at 03:15 UTC), singleton +- [ ] 7.2 Handler: skip if `DEMO_BOT_ENABLED !== "true"` +- [ ] 7.3 Read `DEMO_BOT_RETENTION_DAYS` with default 14 +- [ ] 7.4 `DELETE FROM journal.activities WHERE synthetic AND created_at < now() - interval ?`; same for routes +- [ ] 7.5 Log the count removed for observability + +## 8. Ops + env surface + +- [ ] 8.1 Document `DEMO_BOT_ENABLED`, `DEMO_BOT_RETENTION_DAYS`, `DEMO_BOT_REGION` in `infrastructure/secrets.app.env`'s commented template (do not enable in any environment file except prod) +- [ ] 8.2 Set `DEMO_BOT_ENABLED=true` only in prod +- [ ] 8.3 Expose counts via a Prometheus gauge (e.g. `demo_bot_synthetic_routes_total`, `demo_bot_synthetic_activities_total`) and reuse the existing `brouter_request_duration_seconds` histogram for the bot's BRouter calls — no new metric plumbing needed + +## 9. UX tweaks + +- [ ] 9.1 "🐕 demo account" badge on `/users/bruno` so honest readers can tell at a glance; gate on `user.username === 'bruno'` +- [ ] 9.2 i18n: `demo.badge` key in EN + DE (e.g. "Demo account" / "Demo-Konto") + +## 10. Tests + +- [ ] 10.1 Unit: `ensureDemoUser` is idempotent; second call is a no-op and does not duplicate +- [ ] 10.2 Unit: `pickEndpoints` stays within bbox; distance bands match profile +- [ ] 10.3 Unit: `templateName` / `templateDescription` return non-empty strings in both locales +- [ ] 10.4 Integration (tests DB): the generation handler inserts one route + one activity with `synthetic=true, visibility='public'` when enabled, and inserts nothing when disabled +- [ ] 10.5 Integration: the prune handler deletes only `synthetic=true` rows past the window; real rows are untouched + +## 11. Rollout + +- [ ] 11.1 Merge schema + code; deploy — the bot stays disabled everywhere because no env flag is set +- [ ] 11.2 Flip `DEMO_BOT_ENABLED=true` on prod via the SOPS env file + redeploy +- [ ] 11.3 On next worker start: verify `ensureDemoUser` created the `demo` user, the backfill produced 3–5 items, and `/users/demo` renders them publicly +- [ ] 11.4 After 24 h: verify cadence looks right and the prune job ran without deleting anything yet diff --git a/openspec/changes/public-content-visibility/.openspec.yaml b/openspec/changes/public-content-visibility/.openspec.yaml new file mode 100644 index 0000000..c8af3f5 --- /dev/null +++ b/openspec/changes/public-content-visibility/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-driven +created: 2026-04-19 diff --git a/openspec/changes/public-content-visibility/design.md b/openspec/changes/public-content-visibility/design.md new file mode 100644 index 0000000..390df32 --- /dev/null +++ b/openspec/changes/public-content-visibility/design.md @@ -0,0 +1,111 @@ +## Context + +The Journal uses a straightforward "logged-in or you're not seeing anything" access model today. Routes and activities are owned by a single user via `owner_id` foreign keys, and every detail-page loader calls `getSessionUser(request)` then either serves the page or (implicitly) returns the "route not found" error. There is no notion of cross-user visibility. + +The Planner is separately anonymous, so that's not a concern here — this change is Journal-only. + +Two near-term pressures shape the design: + +- **The demo plan** (send a URL to a prospective user or contributor and have them see real content without signing up). Anything that requires a friction step on arrival defeats the demo. +- **Upcoming `demo-activity-bot`** that generates synthetic activities. That content has to be publicly viewable or the bot is pointless. + +What this design deliberately *does not* touch: +- Followers / subscriptions / per-user feeds +- Reactions / comments / any write surface for non-owners +- ActivityPub / Fedify / federation +- Per-segment privacy on a single route + +Those are all future chapters. Keeping the first step narrow means less to get wrong and less to re-design later. + +## Goals / Non-Goals + +**Goals:** +- A route or activity owner can mark a piece of content as public. +- Logged-out visitors can open that content at its permanent URL. +- A logged-out visitor can find the rest of that user's public content via `/users/:username`. +- Sharing a public URL on Slack / Twitter / Bluesky / email produces a decent preview. +- Default stays private — nothing already in the database becomes visible just because this change ships. + +**Non-Goals:** +- Discovery (there is no "browse public routes" page on the instance yet). +- Indexing control beyond the default (no per-route `robots` override). +- Changing the Planner's anonymous model. +- Any write access for non-owners on public content. + +## Decisions + +### Visibility model: three values, not two + +**Decision:** `visibility` enum `'private' | 'unlisted' | 'public'`. Stored as a text column for simplicity; can be migrated to a native enum later if worth it. + +- `private` (default) — only the owner can fetch the detail page; listings never show it. +- `unlisted` — anyone with the URL can view; excluded from the owner's public profile and any future discovery pages. +- `public` — anyone can view; appears on the owner's public profile. + +**Alternatives:** +- **Just `private | public`** — simpler, but kills the useful "I want to share with someone without putting it on my profile" case. Every other sharing-oriented service has an unlisted tier; it's cheap to add now and irritating to retrofit later. +- **Sharing via time-limited tokens** (Google-Docs-style) — more powerful but out of scope for the demo goal. Parked. + +### Default is `private` for all existing rows + +**Decision:** The new column ships with `DEFAULT 'private'` and every existing row — two real routes and zero activities — remains private. Users opt in to publication by explicitly changing the value. + +**Why:** This change cannot silently un-privatise data anyone uploaded under the old rules. That principle outweighs the demo inconvenience (we'll mark the demo user's seeded content public at insert time). + +### Access check lives in route loaders + +**Decision:** Each detail-page loader (`routes.$id.tsx`, `activities.$id.tsx`) resolves the content row, compares `visibility` + `owner_id` against the session user: + +- `visibility === 'public'` → serve. +- `visibility === 'unlisted'` AND the request is a direct detail page URL → serve. +- otherwise → serve only if the requester is the owner, else 404 (not 403 — leaking existence is a privacy bug). + +A small helper `canView(content, user)` in `~/lib/auth.server` centralises the rule so list endpoints use the same logic. + +**Alternatives:** +- **Route-level middleware** (before loaders) — cleaner in theory but React Router 7 loaders are the right place for content-specific auth, and centralising via a helper avoids coupling the router tree to visibility semantics. + +### Public profile page reuses the existing `/users/:username` route + +**Decision:** That route exists today but is auth-gated (and renders the current user's own routes/activities). Broaden it: + +- Publicly accessible. +- Shows public routes + public activities of the requested username, most recent first. +- 404 if the user has no public content at all. This hides the existence of private-only accounts; an attacker can't enumerate accounts by username. +- A "This is your profile" control strip visible only to the logged-in owner, with a quick link to settings. + +### Open Graph / Twitter Card meta tags + +**Decision:** Each public route / activity detail page emits OG tags via React Router's `meta` export: + +- `og:title` — route or activity name + "· trails.cool" +- `og:description` — user description (truncated) or a sensible default +- `og:type` — `"article"` +- `og:site_name` — `"trails.cool"` +- `twitter:card` — `"summary"` (summary, not summary_large_image; we don't have social cards yet) + +A future `social-preview-images` follow-up can add rendered static map PNGs. Explicitly out of scope here. + +### `robots` control + +**Decision:** Public route / activity pages emit no `robots` meta (defaults to indexable). The legal pages keep their existing `noindex`. No sitemap is generated; discovery via search is passive. + +## Risks / Trade-offs + +- **Username enumeration via profile 404** → Mitigation: 404 both for "no such user" and "user exists but has no public content", so the two are indistinguishable. Timing-side-channel on the DB lookup is not defended against in v1; acceptable at this scale. +- **Future listing pages will want more data** → The `canView` helper already supports it. Adding an `index` boolean or "discoverable" flag is additive. +- **`unlisted` is only private-ish** → If the URL leaks it's effectively public. That's the Internet; same as every other unlisted-sharing feature. Documented in the settings UI copy. +- **Content previously private becomes linkable** → Once a user makes a route public and shares it, they can't fully retract — archives exist. Same as any web publish. No new warning for v1; the visibility selector itself is unambiguous. +- **Spec drift risk** → `route-management` and `activity-feed` both gain modified requirements; keep the delta specs tight so the archive survives review. + +## Migration Plan + +1. Merge schema change; `drizzle-kit push --force` on deploy adds the column with default `'private'`. +2. Logged-out access to public pages is a new code path — nothing existing regresses since all rows remain `'private'` until a user changes them. +3. `demo-activity-bot` is the first caller that will create rows with `visibility: 'public'` at insert time. +4. Rollback: `UPDATE routes SET visibility = 'private'; UPDATE activities SET visibility = 'private';` restores the prior behaviour without any code change; the public code path becomes dead but harmless. + +## Open Questions + +- Should the settings page add a default-visibility preference per user (e.g. "make new routes public by default")? Probably nice but not in this spec; revisit after observing real usage. +- Do we want to emit `` on unlisted pages to discourage indexing of the URL if it leaks? Low-cost, worth considering during implementation. diff --git a/openspec/changes/public-content-visibility/proposal.md b/openspec/changes/public-content-visibility/proposal.md new file mode 100644 index 0000000..b2996e9 --- /dev/null +++ b/openspec/changes/public-content-visibility/proposal.md @@ -0,0 +1,37 @@ +## Why + +trails.cool currently has no way to show its content to anyone who isn't logged in. Route and activity detail pages require auth, there is no public-facing profile page, and shared URLs have no Open Graph metadata — so a link pasted in Slack or on a social platform looks like a blank trails.cool card. + +Two immediate reasons to fix this: + +1. **Demos + acquisition.** The next phase of the project is onboarding more users and contributors. The pitch lands better when you can send a URL that opens directly to "look at this route / this weekend's ride" without making the visitor register first. +2. **Prerequisite for any `demo-activity-bot` work.** A synthetic-activity generator is pointless if the generated content isn't publicly viewable. This change unblocks that follow-up. + +This is also the smallest possible step into the "social" direction the Journal was always described as heading for. It does not introduce follow/follower, cross-user feeds, reactions, or ActivityPub — those remain future work. + +## What Changes + +- New `visibility` column on routes and activities with values `private` (default for existing rows), `unlisted` (reachable only by direct URL, excluded from listings), `public` (visible everywhere). +- Logged-out visitors can view **public** route and activity detail pages. Private / nonexistent routes return 404, just like logged-in requests to other users' private content. Unlisted renders for anyone with the URL but does not appear in listings. +- New public profile page at `/users/:username` that lists that user's **public** routes and activities. Returns 404 if the user has no public content (keeps the existence of private-only accounts itself private). +- Route detail page gains a visibility selector for owners (the existing edit page is the natural home). +- Open Graph / Twitter Card meta tags on public route and activity detail pages so shared URLs preview nicely (title, description, a small route preview image for future, the instance name as site). +- **BREAKING for spec-readers only**: several existing requirements in `route-management` and `activity-feed` are modified to reflect the new "auth-or-public" access rule. The default in migration is `private`, so **behaviour for existing users does not change** — their routes stay inaccessible to logged-out visitors until they explicitly make one public. + +## Capabilities + +### New Capabilities +- `public-profiles`: Public-facing user pages at `/users/:username` listing a user's public routes and activities, with nothing shown for users who have no public content. + +### Modified Capabilities +- `route-management`: adds visibility field + modified access rules so public routes are viewable without auth; owners can change visibility. +- `activity-feed`: adds visibility field; public activities render to logged-out visitors. + +## Impact + +- **Code**: schema (`visibility` column on `routes` + `activities`), loader auth changes on `routes.$id.tsx` / `activities.$id.tsx`, new route `users.$username.tsx` (already exists but is auth-gated today), a visibility selector somewhere in the route edit flow, a `meta` export on public detail pages for OG tags. +- **Data**: default `visibility = private` for all existing rows — three users, zero activities, two empty routes — so migration is effectively a no-op for behaviour. No backfill needed. +- **Privacy**: this change explicitly reduces the default privacy posture *only if a user opts in by marking content public*. A short sentence in `/legal/privacy` notes public content is world-visible. No new third-party surface. +- **Search engines**: public pages are not actively promoted (no sitemap). `robots: noindex` stays on legal pages and settings; `routes` and `activities` public pages get a permissive default (search-indexable) so demo URLs work well. +- **Non-goals (explicit)**: follow/follower, a cross-user feed, reactions/comments, federation, route privacy per-section. Keeping scope tight. +- **Rollback**: flipping the default back to `private` everywhere is a single UPDATE. Pages gating on visibility degrade to "auth-only" if we remove the public path. diff --git a/openspec/changes/public-content-visibility/specs/activity-feed/spec.md b/openspec/changes/public-content-visibility/specs/activity-feed/spec.md new file mode 100644 index 0000000..b0cffab --- /dev/null +++ b/openspec/changes/public-content-visibility/specs/activity-feed/spec.md @@ -0,0 +1,48 @@ +## MODIFIED Requirements + +### Requirement: Activity detail page +The Journal SHALL display an activity detail page with map, stats, and description. Access depends on the activity's `visibility`: `public` activities are viewable by anyone including unauthenticated visitors, `unlisted` activities are viewable by anyone who has the URL, and `private` activities are viewable only by the owner. + +#### Scenario: Owner views own activity +- **WHEN** a logged-in user navigates to an activity they own at any visibility +- **THEN** they see the activity name, description, a map with the GPS trace, distance, duration, and elevation stats + +#### Scenario: Anyone views a public activity +- **WHEN** any visitor (including unauthenticated) navigates to a `public` activity's URL +- **THEN** they see the full activity detail page as above + +#### Scenario: Anyone with the URL views an unlisted activity +- **WHEN** any visitor navigates directly to an `unlisted` activity's URL +- **THEN** they see the full activity detail page as above + +#### Scenario: Non-owner is blocked from a private activity +- **WHEN** a visitor who is not the owner requests a `private` activity URL +- **THEN** the server responds with HTTP 404 (not 403), so the existence of the private activity is not leaked + +#### Scenario: Public and unlisted activity pages emit social-share metadata +- **WHEN** a visitor loads a `public` or `unlisted` activity detail page +- **THEN** the response emits Open Graph and Twitter Card meta tags (`og:title`, `og:description`, `og:type="article"`, `og:site_name`, `twitter:card="summary"`) + +## ADDED Requirements + +### Requirement: Activity visibility +The Journal SHALL persist a `visibility` value on every activity and SHALL allow the owner to change it. + +#### Scenario: New activities default to private +- **WHEN** an activity is created without an explicit visibility +- **THEN** the activity row is persisted with `visibility = 'private'` + +#### Scenario: Owner changes an activity's visibility +- **WHEN** an activity owner selects a different visibility (`private`, `unlisted`, `public`) and saves +- **THEN** the stored visibility is updated and subsequent access checks use the new value immediately + +### Requirement: Activity listings respect visibility +The Journal's own-activities feed SHALL show the owner everything regardless of visibility, while any cross-user listing SHALL only include activities with `visibility = 'public'`. + +#### Scenario: Own activity feed is unchanged +- **WHEN** a logged-in user views their own activity feed +- **THEN** the feed includes all of their own activities regardless of visibility + +#### Scenario: Public profile lists only public activities +- **WHEN** a visitor loads `/users/:username` +- **THEN** the rendered list of activities includes only the user's `public` activities; `unlisted` and `private` activities are omitted diff --git a/openspec/changes/public-content-visibility/specs/public-profiles/spec.md b/openspec/changes/public-content-visibility/specs/public-profiles/spec.md new file mode 100644 index 0000000..e2f4cd0 --- /dev/null +++ b/openspec/changes/public-content-visibility/specs/public-profiles/spec.md @@ -0,0 +1,22 @@ +## ADDED Requirements + +### Requirement: Public profile page +The Journal SHALL serve a public profile page at `/users/:username` that lists the user's public routes and activities in reverse chronological order, viewable without authentication. + +#### Scenario: Logged-out visitor views a profile with public content +- **WHEN** an unauthenticated visitor navigates to `/users/:username` for a user with at least one `public` route or activity +- **THEN** the page renders that user's display name (falling back to username), the `@username@domain` handle, and a reverse-chronological list of their `public` routes and `public` activities +- **AND** items marked `unlisted` or `private` do NOT appear in the list + +#### Scenario: Profile 404 when there is no public content +- **WHEN** a visitor navigates to `/users/:username` for a user whose content is all `private` or `unlisted`, or for a username that does not exist +- **THEN** the server responds with HTTP 404 +- **AND** the response does NOT distinguish the two cases, so existence of a private-only account is not leaked + +#### Scenario: Owner sees their own profile +- **WHEN** a user navigates to their own `/users/:username` while logged in +- **THEN** the page renders exactly the same as for a logged-out visitor, plus a small owner-only control strip linking to settings + +#### Scenario: Profile page emits social-share metadata +- **WHEN** any visitor loads a populated `/users/:username` +- **THEN** the page emits Open Graph tags (`og:title`, `og:site_name`, `og:type="profile"`) so links shared on social platforms render a meaningful preview diff --git a/openspec/changes/public-content-visibility/specs/route-management/spec.md b/openspec/changes/public-content-visibility/specs/route-management/spec.md new file mode 100644 index 0000000..fe804d0 --- /dev/null +++ b/openspec/changes/public-content-visibility/specs/route-management/spec.md @@ -0,0 +1,52 @@ +## MODIFIED Requirements + +### Requirement: View route +The Journal SHALL display route details including map, metadata, and elevation stats. Access depends on the route's `visibility`: `public` routes are viewable by anyone including unauthenticated visitors, `unlisted` routes are viewable by anyone who has the URL, and `private` routes are viewable only by the owner. + +#### Scenario: Owner views own route +- **WHEN** a logged-in user navigates to a route they own at any visibility +- **THEN** they see the route name, description, a map with the route polyline, distance, and elevation gain/loss + +#### Scenario: Anyone views a public route +- **WHEN** any visitor (including unauthenticated) navigates to a `public` route's URL +- **THEN** they see the full route detail page as above + +#### Scenario: Anyone with the URL views an unlisted route +- **WHEN** any visitor navigates directly to an `unlisted` route's URL +- **THEN** they see the full route detail page as above + +#### Scenario: Non-owner is blocked from a private route +- **WHEN** a visitor who is not the owner requests a `private` route URL +- **THEN** the server responds with HTTP 404 (not 403), so the existence of the private route is not leaked + +#### Scenario: Public and unlisted route pages emit social-share metadata +- **WHEN** a visitor loads a `public` or `unlisted` route detail page +- **THEN** the response emits Open Graph and Twitter Card meta tags (`og:title`, `og:description`, `og:type="article"`, `og:site_name`, `twitter:card="summary"`) + +## ADDED Requirements + +### Requirement: Route visibility +The Journal SHALL persist a `visibility` value on every route and SHALL allow the owner to change it. + +#### Scenario: New routes default to private +- **WHEN** a route is created without an explicit visibility +- **THEN** the route row is persisted with `visibility = 'private'` + +#### Scenario: Owner changes a route's visibility +- **WHEN** a route owner selects a different visibility (`private`, `unlisted`, `public`) in the edit flow and saves +- **THEN** the stored visibility is updated and subsequent access checks use the new value immediately + +#### Scenario: Non-owner cannot change visibility +- **WHEN** a request to update visibility arrives from a user who is not the route owner +- **THEN** the server rejects it with HTTP 403 or 404 (matching the current update-route behaviour), and the stored value is unchanged + +### Requirement: Route listings respect visibility +Any listing that exposes routes beyond the owner's own dashboard SHALL only include routes with `visibility = 'public'`. + +#### Scenario: Public profile lists only public routes +- **WHEN** a visitor loads `/users/:username` +- **THEN** the rendered list of routes includes only the user's `public` routes; `unlisted` and `private` routes are omitted + +#### Scenario: Owner's own routes list is unchanged +- **WHEN** a logged-in user views their own routes list at `/routes` +- **THEN** the list includes all of their own routes regardless of visibility diff --git a/openspec/changes/public-content-visibility/tasks.md b/openspec/changes/public-content-visibility/tasks.md new file mode 100644 index 0000000..4196ff5 --- /dev/null +++ b/openspec/changes/public-content-visibility/tasks.md @@ -0,0 +1,62 @@ +## 1. Schema + +- [ ] 1.1 Add `visibility text NOT NULL DEFAULT 'private'` to `journal.routes` in `packages/db/src/schema/journal.ts` +- [ ] 1.2 Add the same column to `journal.activities` in the same file +- [ ] 1.3 Export a shared type `type Visibility = 'private' | 'unlisted' | 'public'` from `packages/db/src/schema/journal.ts` (or a small adjacent module) and reuse at the app layer + +## 2. Server-side access helper + +- [ ] 2.1 Add `canView(content, user)` in `apps/journal/app/lib/auth.server.ts` that returns `true` for `public`, `true` for `unlisted` (the direct-URL case — callers pass `true` when routed to a detail page, `false` when generating listings), and ownership-checked otherwise +- [ ] 2.2 Unit test the three matrix cells + +## 3. Route detail access + +- [ ] 3.1 Update `apps/journal/app/routes/routes.$id.tsx` loader: fetch route, then apply `canView`; return 404 when not allowed +- [ ] 3.2 Expose `visibility` on the loader's returned shape so the component can render the current-visibility badge to the owner +- [ ] 3.3 Emit Open Graph / Twitter Card `meta` for `public` and `unlisted` routes (title, description, `og:type="article"`, `og:site_name="trails.cool"`, `twitter:card="summary"`) + +## 4. Activity detail access + +- [ ] 4.1 Mirror 3.1 in `apps/journal/app/routes/activities.$id.tsx` +- [ ] 4.2 Mirror 3.3 for activities + +## 5. Visibility selector in the edit flow + +- [ ] 5.1 Add a visibility ` on routes/:id/edit with owner-only access. - Activity detail page gets a small visibility form + set-visibility action intent (no separate activity-edit page needed). - EN + DE i18n under routes.visibility.* and activities.visibility.*. Listings: - Listing helpers listPublicRoutesForOwner / listPublicActivitiesForOwner for cross-user queries. Existing owner-scoped listRoutes/listActivities stay — owners see their own content regardless of visibility. Public profile: - /users/:username is now truly public. Renders the user's public routes + activities, 404s when no public content exists AND viewer isn't the owner (prevents account enumeration). - Owner sees a short "this is your profile" note linking to settings. - Open Graph meta (og:type=profile) for shareable preview. Privacy manifest: - Added a bullet noting public content is world-visible on profile and indexable by search engines. - Bumped PRIVACY_LAST_UPDATED to 2026-04-20 + rendered legal-archive snapshot. Tests: - 13 unit tests for canView covering the full matrix. - 6 E2E tests in e2e/public-content.test.ts covering: - Private route → 404 for logged-out visitor - Public route → reachable + OG tags present (og:title, og:type, og:site_name) - Owner still sees own private content - Profile 404 when no public content - Profile renders when at least one public route exists - Unlisted route reachable via direct URL but hidden from profile - Test file runs serially (describe.configure mode=serial) to avoid WebAuthn virtual-authenticator races under Playwright's default parallel workers. - New public-content Playwright project added to config. Rollout safety: every existing row in prod keeps visibility='private' by default — nothing becomes visible to outsiders until an owner explicitly opts in. Co-Authored-By: Claude Opus 4.7 (1M context) --- apps/journal/app/lib/activities.server.ts | 34 ++ apps/journal/app/lib/auth.server.ts | 40 ++ apps/journal/app/lib/canView.test.ts | 64 +++ apps/journal/app/lib/legal.ts | 2 +- apps/journal/app/lib/routes.server.ts | 20 + apps/journal/app/routes/activities.$id.tsx | 76 +++- apps/journal/app/routes/legal.privacy.tsx | 8 + apps/journal/app/routes/routes.$id.edit.tsx | 39 +- apps/journal/app/routes/routes.$id.tsx | 34 +- apps/journal/app/routes/users.$username.tsx | 140 ++++++- docs/legal-archive/privacy-2026-04-20.md | 377 ++++++++++++++++++ e2e/public-content.test.ts | 179 +++++++++ .../public-content-visibility/tasks.md | 66 +-- packages/db/src/schema/journal.ts | 11 + packages/i18n/src/locales/de.ts | 21 + packages/i18n/src/locales/en.ts | 21 + playwright.config.ts | 8 + 17 files changed, 1079 insertions(+), 61 deletions(-) create mode 100644 apps/journal/app/lib/canView.test.ts create mode 100644 docs/legal-archive/privacy-2026-04-20.md create mode 100644 e2e/public-content.test.ts diff --git a/apps/journal/app/lib/activities.server.ts b/apps/journal/app/lib/activities.server.ts index a4ec344..f2ea007 100644 --- a/apps/journal/app/lib/activities.server.ts +++ b/apps/journal/app/lib/activities.server.ts @@ -2,6 +2,7 @@ import { randomUUID } from "node:crypto"; import { eq, desc, and, sql } from "drizzle-orm"; import { getDb } from "./db.ts"; import { activities, routes, syncImports } from "@trails-cool/db/schema/journal"; +import type { Visibility } from "@trails-cool/db/schema/journal"; import { parseGpxAsync } from "@trails-cool/gpx"; import { setGeomFromGpx } from "./routes.server.ts"; @@ -13,6 +14,21 @@ export interface ActivityInput { distance?: number | null; duration?: number | null; startedAt?: Date | null; + visibility?: Visibility; +} + +export async function updateActivityVisibility( + id: string, + ownerId: string, + visibility: Visibility, +): Promise { + const db = getDb(); + const result = await db + .update(activities) + .set({ visibility }) + .where(and(eq(activities.id, id), eq(activities.ownerId, ownerId))) + .returning({ id: activities.id }); + return result.length > 0; } export async function createActivity(ownerId: string, input: ActivityInput) { @@ -100,6 +116,24 @@ export async function listActivities(ownerId: string) { return rows.map((r) => ({ ...r, geojson: geojsonMap.get(r.id) ?? null })); } +/** + * List the *public* activities of a given owner. Used for cross-user + * listings (the public profile page); never includes `unlisted` or + * `private` content. + */ +export async function listPublicActivitiesForOwner(ownerId: string) { + const db = getDb(); + const rows = await db + .select() + .from(activities) + .where(and(eq(activities.ownerId, ownerId), eq(activities.visibility, "public"))) + .orderBy(desc(activities.createdAt)); + + const ids = rows.map((r) => r.id); + const geojsonMap = ids.length > 0 ? await getSimplifiedActivityGeojsonBatch(ids) : new Map(); + return rows.map((r) => ({ ...r, geojson: geojsonMap.get(r.id) ?? null })); +} + export async function linkActivityToRoute(activityId: string, routeId: string, _ownerId: string) { const db = getDb(); await db diff --git a/apps/journal/app/lib/auth.server.ts b/apps/journal/app/lib/auth.server.ts index 0aa8861..cc006bc 100644 --- a/apps/journal/app/lib/auth.server.ts +++ b/apps/journal/app/lib/auth.server.ts @@ -13,6 +13,7 @@ import type { } from "@simplewebauthn/types"; import { getDb } from "./db.ts"; import { users, credentials, magicTokens } from "@trails-cool/db/schema/journal"; +import type { Visibility } from "@trails-cool/db/schema/journal"; const RP_NAME = "trails.cool"; const RP_ID = process.env.DOMAIN ?? "localhost"; @@ -410,6 +411,45 @@ export const sessionStorage = createCookieSessionStorage({ }, }); +/** + * A row that carries the minimum a visibility check needs. + */ +export interface Viewable { + ownerId: string; + visibility: Visibility; +} + +/** + * The caller's identity. `null` represents a logged-out visitor. + */ +export interface Viewer { + id: string; +} + +/** + * Decide whether a viewer may see a piece of content. + * + * - `public` content is viewable by anyone. + * - `unlisted` content is viewable only on direct-link access — listings + * should omit it. Callers rendering a detail page pass `asDirectLink: + * true`; listings default to `false`. + * - `private` content is viewable only by the owner. + * + * Centralised here so detail loaders and listing queries use the same + * rule. Intentionally does not throw; callers handle the `false` case + * (usually by returning HTTP 404 rather than 403 to avoid leaking + * existence). + */ +export function canView( + content: Viewable, + viewer: Viewer | null, + { asDirectLink = false }: { asDirectLink?: boolean } = {}, +): boolean { + if (content.visibility === "public") return true; + if (content.visibility === "unlisted" && asDirectLink) return true; + return viewer?.id === content.ownerId; +} + /** * Record the user's acceptance of the current Terms version. Updates both * `terms_accepted_at` (NOW) and `terms_version`. Used when an existing user diff --git a/apps/journal/app/lib/canView.test.ts b/apps/journal/app/lib/canView.test.ts new file mode 100644 index 0000000..ec7e259 --- /dev/null +++ b/apps/journal/app/lib/canView.test.ts @@ -0,0 +1,64 @@ +import { describe, it, expect } from "vitest"; +import { canView, type Viewable, type Viewer } from "./auth.server.ts"; + +const owner: Viewer = { id: "owner-id" }; +const other: Viewer = { id: "other-id" }; + +function row(visibility: "private" | "unlisted" | "public"): Viewable { + return { ownerId: owner.id, visibility }; +} + +describe("canView", () => { + describe("public content", () => { + it("is viewable by the owner", () => { + expect(canView(row("public"), owner)).toBe(true); + }); + it("is viewable by another logged-in user", () => { + expect(canView(row("public"), other)).toBe(true); + }); + it("is viewable by a logged-out visitor", () => { + expect(canView(row("public"), null)).toBe(true); + }); + it("ignores asDirectLink (always viewable)", () => { + expect(canView(row("public"), null, { asDirectLink: false })).toBe(true); + expect(canView(row("public"), null, { asDirectLink: true })).toBe(true); + }); + }); + + describe("unlisted content", () => { + it("is viewable by the owner", () => { + expect(canView(row("unlisted"), owner)).toBe(true); + }); + it("is viewable by another user on a direct link", () => { + expect(canView(row("unlisted"), other, { asDirectLink: true })).toBe(true); + }); + it("is viewable by a logged-out visitor on a direct link", () => { + expect(canView(row("unlisted"), null, { asDirectLink: true })).toBe(true); + }); + it("is NOT visible in a listing to another user", () => { + expect(canView(row("unlisted"), other, { asDirectLink: false })).toBe(false); + }); + it("is NOT visible in a listing to a logged-out visitor", () => { + expect(canView(row("unlisted"), null, { asDirectLink: false })).toBe(false); + }); + it("defaults to the listing rule when asDirectLink is omitted", () => { + expect(canView(row("unlisted"), other)).toBe(false); + expect(canView(row("unlisted"), null)).toBe(false); + }); + }); + + describe("private content", () => { + it("is viewable by the owner", () => { + expect(canView(row("private"), owner)).toBe(true); + expect(canView(row("private"), owner, { asDirectLink: true })).toBe(true); + }); + it("is NOT viewable by another user", () => { + expect(canView(row("private"), other)).toBe(false); + expect(canView(row("private"), other, { asDirectLink: true })).toBe(false); + }); + it("is NOT viewable by a logged-out visitor", () => { + expect(canView(row("private"), null)).toBe(false); + expect(canView(row("private"), null, { asDirectLink: true })).toBe(false); + }); + }); +}); diff --git a/apps/journal/app/lib/legal.ts b/apps/journal/app/lib/legal.ts index a312bc7..9105096 100644 --- a/apps/journal/app/lib/legal.ts +++ b/apps/journal/app/lib/legal.ts @@ -16,4 +16,4 @@ export const TERMS_VERSION = "2026-04-19"; * require re-acceptance (the policy is informational, not contract), so this * is display-only — not persisted. */ -export const PRIVACY_LAST_UPDATED = "2026-04-19"; +export const PRIVACY_LAST_UPDATED = "2026-04-20"; diff --git a/apps/journal/app/lib/routes.server.ts b/apps/journal/app/lib/routes.server.ts index 2a77a14..1d6f13c 100644 --- a/apps/journal/app/lib/routes.server.ts +++ b/apps/journal/app/lib/routes.server.ts @@ -2,6 +2,7 @@ import { randomUUID } from "node:crypto"; import { eq, desc, and } from "drizzle-orm"; import { getDb } from "./db.ts"; import { routes, routeVersions } from "@trails-cool/db/schema/journal"; +import type { Visibility } from "@trails-cool/db/schema/journal"; import { parseGpxAsync } from "@trails-cool/gpx"; import { sql } from "drizzle-orm"; @@ -10,6 +11,7 @@ export interface RouteInput { description?: string; gpx?: string; routingProfile?: string; + visibility?: Visibility; } export async function createRoute(ownerId: string, input: RouteInput) { @@ -96,6 +98,23 @@ export async function listRoutes(ownerId: string) { return rows.map((r) => ({ ...r, geojson: geojsonMap.get(r.id) ?? null })); } +/** + * List the *public* routes of a given owner. Used for cross-user listings + * (the public profile page); never includes `unlisted` or `private` content. + */ +export async function listPublicRoutesForOwner(ownerId: string) { + const db = getDb(); + const rows = await db + .select() + .from(routes) + .where(and(eq(routes.ownerId, ownerId), eq(routes.visibility, "public"))) + .orderBy(desc(routes.updatedAt)); + + const ids = rows.map((r) => r.id); + const geojsonMap = ids.length > 0 ? await getSimplifiedGeojsonBatch(ids) : new Map(); + return rows.map((r) => ({ ...r, geojson: geojsonMap.get(r.id) ?? null })); +} + export async function updateRoute( id: string, ownerId: string, @@ -106,6 +125,7 @@ export async function updateRoute( const updateData: Record = { updatedAt: new Date() }; if (input.name !== undefined) updateData.name = input.name; if (input.description !== undefined) updateData.description = input.description; + if (input.visibility !== undefined) updateData.visibility = input.visibility; if (input.gpx) { updateData.gpx = input.gpx; diff --git a/apps/journal/app/routes/activities.$id.tsx b/apps/journal/app/routes/activities.$id.tsx index 1b80106..3c840ae 100644 --- a/apps/journal/app/routes/activities.$id.tsx +++ b/apps/journal/app/routes/activities.$id.tsx @@ -1,12 +1,15 @@ import { data, redirect } from "react-router"; import { useTranslation } from "react-i18next"; import type { Route } from "./+types/activities.$id"; -import { getSessionUser } from "~/lib/auth.server"; -import { getActivity, deleteActivity, linkActivityToRoute, createRouteFromActivity } from "~/lib/activities.server"; +import { canView, getSessionUser } from "~/lib/auth.server"; +import { getActivity, deleteActivity, linkActivityToRoute, createRouteFromActivity, updateActivityVisibility } from "~/lib/activities.server"; import { deleteImportByActivity } from "~/lib/sync/imports.server"; import { listRoutes } from "~/lib/routes.server"; import { ClientDate } from "~/components/ClientDate"; import { ClientMap } from "~/components/ClientMap"; +import type { Visibility } from "@trails-cool/db/schema/journal"; + +const VISIBILITY_VALUES = new Set(["private", "unlisted", "public"]); export async function loader({ params, request }: Route.LoaderArgs) { const activity = await getActivity(params.id); @@ -15,6 +18,12 @@ export async function loader({ params, request }: Route.LoaderArgs) { const user = await getSessionUser(request); const isOwner = user?.id === activity.ownerId; + // Visibility gate — public always, unlisted on direct link, private owner-only. + // 404 (not 403) to avoid leaking existence. + if (!canView(activity, user, { asDirectLink: true })) { + throw data({ error: "Activity not found" }, { status: 404 }); + } + const userRoutes = isOwner && user ? await listRoutes(user.id) : []; return data({ @@ -30,6 +39,7 @@ export async function loader({ params, request }: Route.LoaderArgs) { hasGpx: !!activity.gpx, geojson: activity.geojson ?? null, startedAt: activity.startedAt?.toISOString() ?? null, + visibility: activity.visibility, createdAt: activity.createdAt.toISOString(), importSource: activity.importSource, }, @@ -66,12 +76,41 @@ export async function action({ params, request }: Route.ActionArgs) { return data({ error: "Activity not found" }, { status: 404 }); } + if (intent === "set-visibility") { + const raw = formData.get("visibility") as string | null; + if (!raw || !VISIBILITY_VALUES.has(raw as Visibility)) { + return data({ error: "Invalid visibility" }, { status: 400 }); + } + const ok = await updateActivityVisibility(params.id, user.id, raw as Visibility); + if (!ok) return data({ error: "Activity not found" }, { status: 404 }); + return redirect(`/activities/${params.id}`); + } + return data({ error: "Unknown action" }, { status: 400 }); } export function meta({ data: loaderData }: Route.MetaArgs) { - const name = (loaderData as { activity: { name: string } })?.activity?.name ?? "Activity"; - return [{ title: `${name} — trails.cool` }]; + const activity = (loaderData as { activity?: { name: string; description: string | null; visibility: string } })?.activity; + const name = activity?.name ?? "Activity"; + const title = `${name} — trails.cool`; + const tags: Array> = [{ title }]; + + if (activity && (activity.visibility === "public" || activity.visibility === "unlisted")) { + const description = (activity.description && activity.description.length > 0) + ? activity.description.slice(0, 280) + : `An activity on trails.cool`; + tags.push( + { property: "og:title", content: title }, + { property: "og:description", content: description }, + { property: "og:type", content: "article" }, + { property: "og:site_name", content: "trails.cool" }, + { name: "twitter:card", content: "summary" }, + { name: "twitter:title", content: title }, + { name: "twitter:description", content: description }, + ); + } + + return tags; } export default function ActivityDetailPage({ loaderData }: Route.ComponentProps) { @@ -177,6 +216,35 @@ export default function ActivityDetailPage({ loaderData }: Route.ComponentProps)
)} + {isOwner && ( +
+
+ +
+ + +
+ +
+
+ )} + {isOwner && (
{ if (!confirm(t("activities.deleteConfirm"))) e.preventDefault(); }}> diff --git a/apps/journal/app/routes/legal.privacy.tsx b/apps/journal/app/routes/legal.privacy.tsx index 90a601c..bdc805d 100644 --- a/apps/journal/app/routes/legal.privacy.tsx +++ b/apps/journal/app/routes/legal.privacy.tsx @@ -375,6 +375,14 @@ export default function PrivacyPage() {
  • Routes: GPX, geometry, title, description
  • Activities: title, description, date, linked route
  • GPX / JSON export available per object and overall
  • +
  • + Routes and activities each carry a visibility setting + (private / unlisted / public) + that defaults to private. Content you explicitly mark + public is visible to anyone on the internet, + including on your public profile at /users/<you> + and on search engines that index those pages. +
  • diff --git a/apps/journal/app/routes/routes.$id.edit.tsx b/apps/journal/app/routes/routes.$id.edit.tsx index 9dce0ca..e1fe2e9 100644 --- a/apps/journal/app/routes/routes.$id.edit.tsx +++ b/apps/journal/app/routes/routes.$id.edit.tsx @@ -1,7 +1,11 @@ import { data, redirect } from "react-router"; +import { useTranslation } from "react-i18next"; import type { Route } from "./+types/routes.$id.edit"; import { getSessionUser } from "~/lib/auth.server"; import { getRoute, updateRoute } from "~/lib/routes.server"; +import type { Visibility } from "@trails-cool/db/schema/journal"; + +const VISIBILITY_VALUES = new Set(["private", "unlisted", "public"]); export async function loader({ params, request }: Route.LoaderArgs) { const user = await getSessionUser(request); @@ -12,7 +16,12 @@ export async function loader({ params, request }: Route.LoaderArgs) { if (route.ownerId !== user.id) throw data({ error: "Not authorized" }, { status: 403 }); return data({ - route: { id: route.id, name: route.name, description: route.description }, + route: { + id: route.id, + name: route.name, + description: route.description, + visibility: route.visibility, + }, }); } @@ -24,13 +33,17 @@ export async function action({ params, request }: Route.ActionArgs) { const name = formData.get("name") as string; const description = formData.get("description") as string; const gpxFile = formData.get("gpx") as File | null; + const visibilityRaw = formData.get("visibility") as string | null; - const input: { name?: string; description?: string; gpx?: string } = {}; + const input: { name?: string; description?: string; gpx?: string; visibility?: Visibility } = {}; if (name) input.name = name; if (description !== null) input.description = description; if (gpxFile && gpxFile.size > 0) { input.gpx = await gpxFile.text(); } + if (visibilityRaw && VISIBILITY_VALUES.has(visibilityRaw as Visibility)) { + input.visibility = visibilityRaw as Visibility; + } await updateRoute(params.id, user.id, input); return redirect(`/routes/${params.id}`); @@ -42,6 +55,7 @@ export function meta(_args: Route.MetaArgs) { export default function EditRoutePage({ loaderData }: Route.ComponentProps) { const { route } = loaderData; + const { t } = useTranslation("journal"); return (
    @@ -75,6 +89,27 @@ export default function EditRoutePage({ loaderData }: Route.ComponentProps) { />
    +
    + + +

    + {route.visibility === "private" && t("routes.visibility.privateHelp")} + {route.visibility === "unlisted" && t("routes.visibility.unlistedHelp")} + {route.visibility === "public" && t("routes.visibility.publicHelp")} +

    +
    +