From 7e22f1260b04375aecf66dc67624a1a6c2c1494a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Fri, 8 May 2026 02:18:06 +0200 Subject: [PATCH 001/319] Add unify-auth-completion architecture artifacts Extract the post-verify orchestration shared across passkey register-finish, passkey login-finish, magic-link verify-code, and magic-link click-through into a single completeAuth function. Two ADRs record the decision: - ADR-0004: centralize web auth completion (record terms + create session + redirect) in apps/journal/app/lib/auth/completion.ts. - ADR-0005: explicitly no AuthMethod polymorphism. Passkey + magic- link is the entire identity surface; OAuth2/PKCE is session transport, not a peer method. Recorded as a negative decision so future architecture passes don't re-suggest extracting the interface. CONTEXT.md gains an Authentication section covering completeAuth, the two methods, the OAuth2-as-transport distinction, and where the Terms gate enforcement lives (root loader for web, requireApiUser for API per the just-merged mobile-terms-gate). OpenSpec change unify-auth-completion captures the proposal, design (5 decisions including the negative-scope choices), spec delta on authentication-methods, and 14 tasks. Implementation follows on this branch. Co-Authored-By: Claude Opus 4.7 (1M context) --- CONTEXT.md | 54 +++++++++ docs/adr/0004-centralize-auth-completion.md | 26 +++++ docs/adr/0005-no-authmethod-polymorphism.md | 40 +++++++ .../unify-auth-completion/.openspec.yaml | 2 + .../changes/unify-auth-completion/design.md | 103 ++++++++++++++++++ .../changes/unify-auth-completion/proposal.md | 32 ++++++ .../specs/authentication-methods/spec.md | 33 ++++++ .../changes/unify-auth-completion/tasks.md | 30 +++++ 8 files changed, 320 insertions(+) create mode 100644 docs/adr/0004-centralize-auth-completion.md create mode 100644 docs/adr/0005-no-authmethod-polymorphism.md create mode 100644 openspec/changes/unify-auth-completion/.openspec.yaml create mode 100644 openspec/changes/unify-auth-completion/design.md create mode 100644 openspec/changes/unify-auth-completion/proposal.md create mode 100644 openspec/changes/unify-auth-completion/specs/authentication-methods/spec.md create mode 100644 openspec/changes/unify-auth-completion/tasks.md diff --git a/CONTEXT.md b/CONTEXT.md index e41990c..007ea13 100644 --- a/CONTEXT.md +++ b/CONTEXT.md @@ -124,3 +124,57 @@ webhooks to the right user via `provider_user_id`. Unknown `(user_id, provider, workout_id)`. - `sync_pushes` — push state per `(user_id, route_id, provider)` → `remote_id`, `last_pushed_version`. + +--- + +## Authentication + +User identity in the Journal. Two **authentication methods** are supported +and are intentionally the entire surface (see ADR-0005): **passkey** +(WebAuthn) as the preferred method and **magic-link + 6-digit code** +(email) as a fallback for users without passkey support or for cross-device +sign-in. There is no plan for social sign-in (Google/Apple/etc.) — passkeys +already deliver the one-tap UX, and adding centralized identity providers +would conflict with the privacy-first ethos and ActivityPub federation. + +OAuth2/PKCE (the `mobile-app` flow) is **not** a third authentication +method. It is a **session transport** for native clients: users still +authenticate via passkey or magic-link in a WebView, then the mobile app +exchanges the resulting authorization code for long-lived bearer tokens. +The peer of OAuth2 transport is the cookie session, not passkey or +magic-link. + +### completeAuth +The single chokepoint for the post-verify orchestration of every web +auth flow. Lives at `apps/journal/app/lib/auth/completion.ts` (see +ADR-0004). Called by every route handler that has just verified a +user's identity (passkey login finish, magic-link code verify, magic +link consumer). Does three things in order: + +1. If `isNewRegistration`, records the accepted Terms version + (`recordTermsAcceptance`). +2. Creates the session cookie via `createSession`. +3. Returns `redirect(returnTo ?? "/")` with the session `Set-Cookie` + header attached. + +Identity-method-specific work (WebAuthn ceremony verification, magic +token consumption) stays in the per-method functions and runs *before* +`completeAuth`. The chokepoint deliberately knows nothing about how +identity was proved. + +### Terms gate +Cross-cutting middleware enforcing that `users.terms_version` matches +the current `TERMS_VERSION` constant before any non-allow-listed +authenticated request succeeds. Two enforcement points: + +- **Web (cookie sessions)**: the root loader redirects stale-terms users + to `/auth/accept-terms`. Allow-list: `/auth/accept-terms`, + `/auth/logout`, `/legal/*`. `/oauth/authorize` is *not* on the + allow-list, so OAuth code issuance is gated by this same redirect + before mobile sees an authorization code. +- **API (bearer tokens)**: `requireApiUser` returns + `403 { code: "TERMS_OUTDATED", currentTermsVersion }` for stale-terms + bearer-token traffic. (Added in `mobile-terms-gate`, 2026-05-08.) + +`completeAuth` only **records** terms on registration; it does not +enforce them. Enforcement remains middleware's job. diff --git a/docs/adr/0004-centralize-auth-completion.md b/docs/adr/0004-centralize-auth-completion.md new file mode 100644 index 0000000..533e53e --- /dev/null +++ b/docs/adr/0004-centralize-auth-completion.md @@ -0,0 +1,26 @@ +# Centralize web auth completion in `completeAuth` + +Every successful web authentication today (passkey login, passkey +register, magic-link code verify, magic-link click-through verify) +inlines the same three-step orchestration in its route handler: +record the accepted Terms version on registration, mint the session +cookie, and redirect to `returnTo` (or `/`). With four call sites +re-implementing the same sequence, a bug in any of them — a missed +terms write, a wrong cookie option, an open-redirect-prone returnTo +— must be fixed in four places, and a future fifth flow (e.g. an +admin-impersonation login, a one-time recovery flow) re-derives the +same boilerplate. + +We extract the orchestration into a single function +`completeAuth({ userId, isNewRegistration, termsVersion?, request, +returnTo? })` at `apps/journal/app/lib/auth/completion.ts`. Per-method +identity verification (WebAuthn ceremony, magic-token consumption) +stays in its own function and runs *before* `completeAuth` — +the chokepoint deliberately knows nothing about how identity was +proved. Terms enforcement (the gate) remains middleware (root loader +for web, `requireApiUser` for API); `completeAuth` only *records* +terms on registration. The OAuth-code-issuance flow at +`/oauth/authorize` is **not** routed through `completeAuth` — it +operates on an already-authenticated user and shares only the +trailing redirect, not the full sequence (see ADR-0005 for the +broader scope decision). diff --git a/docs/adr/0005-no-authmethod-polymorphism.md b/docs/adr/0005-no-authmethod-polymorphism.md new file mode 100644 index 0000000..cbab089 --- /dev/null +++ b/docs/adr/0005-no-authmethod-polymorphism.md @@ -0,0 +1,40 @@ +# No `AuthMethod` polymorphism — passkey + magic-link is the entire surface + +A natural temptation when reshaping auth is to extract an +`AuthMethod` interface (analogous to the connected-services +`Importer` / `RoutePusher` / `WebhookReceiver` capability seams) so +passkey and magic-link become two adapters of a common shape, with +future Google/Apple/SAML/etc. as additional adapters. We are +explicitly **not** doing that, and recording the negative decision +here so future architecture passes don't re-suggest it. + +Two reasons. First, the *number of adapters is fixed*: passkey is +trails.cool's preferred identity method and magic-link is its +fallback for browsers without WebAuthn support and cross-device sign- +in. There are no plans for additional methods. Social sign-in (Google, +Apple) would conflict with the privacy-first ethos in `CLAUDE.md` +(third-party identity providers see every login), would fight the +ActivityPub federation model (centralized OIDC vs. +`user@domain` identity), and would add account-linking edge cases +without a UX win — passkeys already deliver the one-tap convenience +that justifies social sign-in elsewhere. With two adapters and no +forecast third, an `AuthMethod` interface is theoretical +polymorphism with no future second customer; the deletion test fails. + +Second, the *interface shape would be shallow*. WebAuthn is a +multi-step ceremony (start → finish, with challenge persistence +between calls); magic-link is a request-then-verify flow with a +15-minute token in the database. Forcing both into a unified +`startAuth(input) → finishAuth(response)` interface produces an +adapter where each implementation barely shares a type signature — +the two flows have genuinely different shapes, and the seam would +fill with optional methods and discriminated unions. The real +repetition lives in the *post-verify orchestration* (record terms, +mint session, redirect), which ADR-0004 addresses with a single +`completeAuth` function — no polymorphism required. + +OAuth2/PKCE in the `mobile-app` change is sometimes mistaken for a +third auth method. It isn't: mobile users still authenticate via +passkey or magic-link in a WebView, and OAuth2 only exchanges the +resulting code for long-lived bearer tokens. OAuth2 is **session +transport** (peer of: HTTP-only cookie), not identity proof. diff --git a/openspec/changes/unify-auth-completion/.openspec.yaml b/openspec/changes/unify-auth-completion/.openspec.yaml new file mode 100644 index 0000000..054b8c0 --- /dev/null +++ b/openspec/changes/unify-auth-completion/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-driven +created: 2026-05-08 diff --git a/openspec/changes/unify-auth-completion/design.md b/openspec/changes/unify-auth-completion/design.md new file mode 100644 index 0000000..a55e0ce --- /dev/null +++ b/openspec/changes/unify-auth-completion/design.md @@ -0,0 +1,103 @@ +## Context + +`apps/journal/app/lib/auth.server.ts` is 489 lines covering passkey ceremonies, magic-link token lifecycle, session cookie storage, terms recording, and email-change tokens. Four route handlers (`api.auth.register.ts`, `api.auth.login.ts` × 2 branches, `auth.verify.tsx`) each repeat the same trailing sequence after their per-method identity verification: + +```ts +if (isNewRegistration) await recordTermsAcceptance(userId, termsVersion); +const headers = await createSession(userId, request); +return redirect(safeReturnTo(returnTo) ?? "/", { headers }); +``` + +The repetition is the *entire* asymmetry between methods at the post-verify layer. WebAuthn vs. magic-link diverge before this point (challenge persistence, token consumption, etc.) but converge here — every flow does the same thing. + +ADRs already recorded: +- ADR-0004: centralize this orchestration in a single `completeAuth` function. +- ADR-0005: do **not** extract an `AuthMethod` interface; passkey + magic-link is the entire surface and OAuth2 is transport, not a peer. + +## Goals / Non-Goals + +**Goals:** +- One function (`completeAuth`) is the only place where a successful web auth records terms + creates session + redirects. Bug fixes apply once. +- File reorganization: `apps/journal/app/lib/auth/` directory containing `completion.ts` and `session.ts`. The existing `auth.server.ts` shrinks but stays for the per-method functions (passkey ceremony, magic-token lifecycle). +- `returnTo` sanitization centralized inside `completeAuth` so no caller can ship an open-redirect. +- Refactor is behaviour-preserving: existing e2e auth tests pass without modification. + +**Non-Goals:** +- No `AuthMethod` interface (per ADR-0005). +- The OAuth-code issuance flow at `/oauth/authorize` is NOT migrated. It operates on already-authenticated users; only the trailing redirect overlaps, not enough leverage to fold in. +- The add-passkey post-login ceremony does NOT need `completeAuth` (no session creation — user is already logged in). +- The magic-link request-token step does NOT need `completeAuth` (only emits a token; verification happens later). +- Session transport (cookie vs. bearer) — orthogonal; not touched. +- Connected-devices UX — separate spec. +- Any change to the Terms gate enforcement points (root loader for web, `requireApiUser` for API). + +## Decisions + +### Decision 1: Single function, no mode flag +`completeAuth` covers exactly the four web post-verify call sites listed in the proposal. There is no `redirectMode: 'cookie' | 'oauth-code'` flag because OAuth-code issuance is genuinely a different flow (already-authenticated user, no session creation, only a code + redirect). Folding both into one function would force a discriminated union and obscure that they don't share much. The OAuth-code path stays in `oauth.authorize.tsx` unchanged. + +### Decision 2: Function signature +```ts +async function completeAuth(input: { + userId: string; + isNewRegistration: boolean; + termsVersion?: string; // required if isNewRegistration; ignored otherwise + request: Request; + returnTo?: string | null; +}): Promise +``` + +Returns a `Response` (a `redirect` from React Router with the session `Set-Cookie` attached). Callers do `return await completeAuth(...)` from their action / loader. No headers-vs-redirect split: the chokepoint owns both halves. + +`termsVersion` is optional at the type level but required-when-`isNewRegistration` at runtime. Asserting it inside the function (throw on `isNewRegistration && !termsVersion`) keeps the call sites tidy. Alternative: a discriminated union forcing the compiler to require `termsVersion` when `isNewRegistration: true`. Lean toward the runtime assertion — three call sites, two of which set `isNewRegistration: false` — the type ergonomics aren't worth the union complexity. + +### Decision 3: File layout +New directory `apps/journal/app/lib/auth/` containing: +- `completion.ts` — `completeAuth` + `safeReturnTo` helper (open-redirect rejection). +- `session.ts` — `sessionStorage`, `createSession`, `getSessionUser`, `destroySession`. Moved from `auth.server.ts`. + +`auth.server.ts` keeps the per-method functions (passkey ceremony, magic-token lifecycle, terms recording, email-change). It re-exports the moved session helpers from their new home so existing imports keep working without a touch: +```ts +// auth.server.ts +export { sessionStorage, createSession, getSessionUser, destroySession } from "./auth/session.ts"; +``` + +That keeps the migration small. A future change can rip the re-exports and update callers across the app — out of scope here. + +### Decision 4: `returnTo` sanitization centralizes inside `completeAuth` +Today, several callers do their own `returnTo` checks of varying rigor (some check `startsWith("/") && !startsWith("//")`, others don't). Move the check into `safeReturnTo` inside `completion.ts`; every caller passes `returnTo` raw and gets the safe version applied uniformly. Reject anything that isn't a same-origin path → fall back to `/`. + +### Decision 5: Tests +Unit tests for `completeAuth` in `completion.test.ts`: +- new-registration writes `users.terms_version` + `users.terms_accepted_at` (mock the DB or use an in-memory test DB — match existing test patterns). +- non-registration skips the terms write. +- response includes a `Set-Cookie` header from `sessionStorage.commitSession`. +- `returnTo` of `/foo` redirects to `/foo`; `returnTo` of `//evil.com/x` redirects to `/`; `returnTo` of `https://evil.com` redirects to `/`; missing `returnTo` redirects to `/`. + +Existing `e2e/auth.test.ts` (passkey register + login + logout) MUST pass without modification — that's the behaviour-preservation proof. + +## Risks / Trade-offs + +- **[Risk]** Re-exporting from `auth.server.ts` to maintain backwards compatibility means there are temporarily two paths to the same symbols. → **Mitigation:** comment marks the re-exports as transitional. A follow-up PR (small) can update import paths app-wide and remove the re-exports. + +- **[Risk]** The runtime assertion (`isNewRegistration && !termsVersion → throw`) is a programmer error, not a user-visible failure. If a future caller forgets to pass `termsVersion`, tests should catch it; if they don't, registration breaks loudly. → **Accepted:** the type-level alternative (discriminated union) costs more than it pays back at three internal call sites. + +- **[Trade-off]** Centralizing `returnTo` sanitization changes behaviour at any call sites that *don't* currently sanitize. The change is strictly safer (rejecting more inputs as `/`) but worth confirming there are no integration tests that pass a deliberately-unsafe `returnTo` and expect it to work. + +## Migration Plan + +Single PR ("spec apply") containing: + +1. Create `apps/journal/app/lib/auth/session.ts` with the moved helpers. +2. Add re-exports in `auth.server.ts`. +3. Create `apps/journal/app/lib/auth/completion.ts` with `completeAuth` + `safeReturnTo`. +4. Write `completion.test.ts` (unit tests). +5. Migrate the 4 callers to `completeAuth`. +6. Verify `pnpm typecheck && pnpm lint && pnpm test && pnpm test:e2e` green. + +**Rollback**: revert the PR. No DB or schema changes; the file moves are pure code-organization, the call-site changes are mechanical. + +## Open Questions + +- **Q1**: Does `sessionStorage` get its `secret` from `process.env.SESSION_SECRET` directly, or from a config helper? Move-as-is and revisit only if it complicates the `session.ts` file. → Decide during implementation. +- **Q2**: Should the `auth.server.ts` re-exports be marked `@deprecated` JSDoc-style so editors warn on use? Light touch — yes, with a comment pointing at `./auth/session.ts`. Decide during implementation. diff --git a/openspec/changes/unify-auth-completion/proposal.md b/openspec/changes/unify-auth-completion/proposal.md new file mode 100644 index 0000000..1c557cb --- /dev/null +++ b/openspec/changes/unify-auth-completion/proposal.md @@ -0,0 +1,32 @@ +## Why + +Every successful web authentication today inlines the same three-step orchestration in its route handler: record the accepted Terms version on registration (`recordTermsAcceptance`), mint the session cookie (`createSession`), and `redirect(returnTo ?? "/", { headers })`. Four call sites — passkey register-finish, passkey login-finish, magic-link verify-code, and the magic-link click-through consumer — re-implement the same sequence. A bug in any one of them must be fixed in four places, and a future fifth flow (admin impersonation, recovery, etc.) re-derives the same boilerplate. + +This change extracts the orchestration into a single function `completeAuth` and folds in the small file-organization win that comes with it (a new `apps/journal/app/lib/auth/` directory). It does **not** introduce an `AuthMethod` interface — see ADR-0005 for why polymorphism here is theoretical with no future adapter. + +## What Changes + +- **New module** `apps/journal/app/lib/auth/completion.ts` exporting `completeAuth({ userId, isNewRegistration, termsVersion?, request, returnTo? }) → Promise`. Records terms on registration (only), creates the session, returns a `redirect(...)` Response with the `Set-Cookie` header attached. +- **New module** `apps/journal/app/lib/auth/session.ts` carrying the cookie session storage (`sessionStorage`, `createSession`, `getSessionUser`, `destroySession`) extracted from `auth.server.ts`. The existing path keeps re-exports for backwards compatibility — caller migration is a follow-up if anything. +- **Caller migration**: 4 route handlers (`api.auth.register.ts` passkey-finish branch, `api.auth.login.ts` passkey-finish-passkey branch, `api.auth.login.ts` magic-link verify-code branch, `auth.verify.tsx` magic-link click-through) replace their inlined orchestration with a single `completeAuth(...)` call. +- **`returnTo` sanitization** centralizes inside `completeAuth` (was already same-origin checked in callers; now there's one place). +- **Tests**: new `completion.test.ts` covering register-records-terms, non-register-skips-terms, returnTo default, header attachment, returnTo open-redirect rejection. Existing `e2e/auth.test.ts` continues to pass without modification — that's the proof the refactor is behaviour-preserving. +- **Negative scope (recorded in ADR-0005)**: no `AuthMethod` interface, no adapter pattern. Passkey + magic-link is the entire identity surface; OAuth2/PKCE is session transport, not a third method. + +## Capabilities + +### New Capabilities + +(none — this change reshapes existing capabilities, no new user-visible behaviour.) + +### Modified Capabilities + +- `authentication-methods`: requirement-level addition codifying that every post-verify web flow goes through the single completion chokepoint that records terms (on register), creates the session, and redirects. User-visible behaviour unchanged. + +## Impact + +- **Code**: 1 new directory (`apps/journal/app/lib/auth/`), 2 new files (`completion.ts`, `session.ts`), `auth.server.ts` slims down by ~80 lines (the moved session helpers), 4 route handlers shrink. No DB changes. No schema changes. +- **Tests**: 1 new unit test file (`completion.test.ts`). Existing e2e auth test should pass unmodified. +- **Specs**: 1 spec gets a small ADDED requirement (`authentication-methods/spec.md`). +- **Decision references**: `docs/adr/0004-centralize-auth-completion.md`, `docs/adr/0005-no-authmethod-polymorphism.md`, `CONTEXT.md` (Authentication section). +- **Out of scope** (separate concerns): the OAuth-code issuance flow at `/oauth/authorize` (operates on already-authenticated users; only shares the trailing redirect), the magic-link request-token step (emits a token, no session created), the add-passkey post-login ceremony (no session creation). Connected-devices UX is its own spec/change. Session-transport changes (cookie ↔ bearer) are orthogonal and not touched here. diff --git a/openspec/changes/unify-auth-completion/specs/authentication-methods/spec.md b/openspec/changes/unify-auth-completion/specs/authentication-methods/spec.md new file mode 100644 index 0000000..d7035c9 --- /dev/null +++ b/openspec/changes/unify-auth-completion/specs/authentication-methods/spec.md @@ -0,0 +1,33 @@ +## ADDED Requirements + +### Requirement: Single web auth completion chokepoint +Every successful web authentication flow — passkey register-finish, passkey login-finish, magic-link 6-digit-code verify, magic-link click-through verify — SHALL complete by calling a single `completeAuth` function at `apps/journal/app/lib/auth/completion.ts`. The function SHALL be the sole place where a successful web authentication records the accepted Terms version (only on registration), mints the cookie session, and constructs the redirect to `returnTo` (or `/` when absent or rejected). + +Per-method identity verification (WebAuthn ceremony, magic-token consumption, 6-digit-code consumption) SHALL run in its own function and produce a `userId` *before* `completeAuth` is invoked. `completeAuth` SHALL NOT know how identity was proved. + +The Terms gate (root-loader redirect for cookie sessions; `requireApiUser` 403 for bearer-token API requests) SHALL remain the enforcement point for stale `terms_version`. `completeAuth` only **records** terms on new registrations; it does not enforce them. + +OAuth-code issuance at `/oauth/authorize` SHALL NOT be routed through `completeAuth` — that flow operates on an already-authenticated user and shares only the trailing redirect, not the full sequence. + +#### Scenario: Passkey register-finish completes through the chokepoint +- **WHEN** a visitor submits a successful WebAuthn `step: "finish"` registration response +- **THEN** the route handler verifies the credential, creates the user row, and calls `completeAuth({ userId, isNewRegistration: true, termsVersion, request, returnTo })` +- **AND** `completeAuth` writes `users.terms_version` and `users.terms_accepted_at`, mints the session cookie, and returns a `Response` redirecting to `returnTo` (or `/`) + +#### Scenario: Passkey login-finish completes through the chokepoint +- **WHEN** a visitor submits a successful WebAuthn `step: "finish-passkey"` login response +- **THEN** the route handler verifies the credential and calls `completeAuth({ userId, isNewRegistration: false, request, returnTo })` +- **AND** `completeAuth` skips the terms write (only registrations record terms), mints the session cookie, and returns a `Response` redirecting to `returnTo` (or `/`) + +#### Scenario: Magic-link 6-digit-code verify completes through the chokepoint +- **WHEN** a visitor submits a valid 6-digit code via `step: "verify-code"` +- **THEN** the route handler consumes the magic token (marks `used_at`) and calls `completeAuth({ userId, isNewRegistration: false, request, returnTo })` + +#### Scenario: Magic-link click-through verify completes through the chokepoint +- **WHEN** a visitor opens `/auth/verify?token=` with a valid, unused, unexpired token +- **THEN** the route handler consumes the magic token and calls `completeAuth({ userId, isNewRegistration: false, request, returnTo })` + +#### Scenario: returnTo is sanitized inside completeAuth +- **WHEN** `completeAuth` is called with a `returnTo` value that is not a same-origin absolute path (e.g. starts with `//`, an absolute URL, or is malformed) +- **THEN** the redirect target falls back to `/` rather than honoring the unsafe value +- **AND** every caller benefits from the same check rather than reimplementing it diff --git a/openspec/changes/unify-auth-completion/tasks.md b/openspec/changes/unify-auth-completion/tasks.md new file mode 100644 index 0000000..ca50181 --- /dev/null +++ b/openspec/changes/unify-auth-completion/tasks.md @@ -0,0 +1,30 @@ +## 1. New auth module structure + +- [ ] 1.1 Create `apps/journal/app/lib/auth/` directory. +- [ ] 1.2 Create `apps/journal/app/lib/auth/session.ts` and move `sessionStorage`, `createSession`, `getSessionUser`, `destroySession` from `auth.server.ts` (preserve behaviour, including `process.env.SESSION_SECRET` source). +- [ ] 1.3 In `auth.server.ts`, re-export the moved helpers from `./auth/session.ts` so existing imports keep working unchanged. Add a JSDoc `@deprecated`-style comment pointing at the new path. + +## 2. completeAuth chokepoint + +- [ ] 2.1 Write `apps/journal/app/lib/auth/completion.test.ts` (TDD red): scenarios for new-registration writes terms, non-registration skips terms, returnTo defaults to `/`, returnTo `//evil.com` rejected, returnTo `https://evil.com` rejected, response includes Set-Cookie. +- [ ] 2.2 Create `apps/journal/app/lib/auth/completion.ts` exporting `completeAuth({ userId, isNewRegistration, termsVersion?, request, returnTo? }) → Promise` and a private `safeReturnTo(value)` helper. Implementation: assert `termsVersion` when `isNewRegistration`; if `isNewRegistration`, `recordTermsAcceptance(userId, termsVersion)`; `createSession(userId, request)`; `redirect(safeReturnTo(returnTo) ?? "/", { headers })`. +- [ ] 2.3 Run completion tests green. + +## 3. Caller migration + +- [ ] 3.1 `apps/journal/app/routes/api.auth.register.ts` passkey-finish branch — replace inlined session+redirect with `return completeAuth({ userId, isNewRegistration: true, termsVersion, request, returnTo })`. Drop now-unused imports. +- [ ] 3.2 `apps/journal/app/routes/api.auth.login.ts` passkey `step: "finish-passkey"` branch — replace with `return completeAuth({ userId, isNewRegistration: false, request, returnTo })`. +- [ ] 3.3 `apps/journal/app/routes/api.auth.login.ts` magic-link `step: "verify-code"` branch — replace with `return completeAuth(...)`. +- [ ] 3.4 `apps/journal/app/routes/auth.verify.tsx` magic-link click-through consumer — replace with `return completeAuth(...)`. +- [ ] 3.5 Confirm no other callers of `createSession` remain inside auth route handlers (they should all flow through `completeAuth`). `getSessionUser` and `destroySession` continue to be called directly from non-completion sites — that's expected. + +## 4. Verification + +- [ ] 4.1 `pnpm typecheck && pnpm lint && pnpm test` green. +- [ ] 4.2 `pnpm test:e2e` (auth flows) green without modification — proves behaviour-preserving refactor. +- [ ] 4.3 Manual sanity: register with passkey locally, login with passkey, log out, re-login via magic-link 6-digit code, click-through magic link from `auth.verify.tsx`. Confirm session cookie set + correct redirect each time. + +## 5. Documentation + follow-up + +- [ ] 5.1 At archive time, apply the spec delta in `specs/authentication-methods/` to `openspec/specs/`. +- [ ] 5.2 (Optional follow-up — not part of this change) update import paths app-wide from `auth.server.ts` to `./auth/session.ts` and drop the re-exports. Track separately. From d64c47614d82b5211a6f8a93ad20873c540f3784 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Fri, 8 May 2026 02:38:15 +0200 Subject: [PATCH 002/319] Implement completeAuth chokepoint + caller migration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implements all of unify-auth-completion (12/14 tasks done; manual smoke + archive-time spec sync remain). Design refinement during implementation: completeAuth supports two response shapes via a `mode` parameter: - mode: 'redirect' (loaders / direct browser navigation; auth.verify.tsx) - mode: 'json' (action handlers called by imperative fetch from client forms; api.auth.login, api.auth.register) Both modes share createSession + safeReturnTo + Set-Cookie. JSON mode carries `{ ok: true, step: "done", redirectTo }` (the `step` field preserves the existing client-form check). Why two modes: passkey ceremonies are inherently imperative (start → browser WebAuthn API → finish), so action handlers can't move to
/useFetcher. Picking option (B) from the design grill — the chokepoint owns destination selection while clients navigate — required this dual shape. The 3 hardcoded client-side targets (returnTo ?? "/", "/", "/?add-passkey=1") collapse into 1 server-side sanitization pass (safeReturnTo) inside completeAuth. New module: - apps/journal/app/lib/auth/session.ts: cookie session storage (sessionStorage, createSession, getSessionUser, destroySession) moved from auth.server.ts. Legacy import path kept via re-exports with @deprecated JSDoc. - apps/journal/app/lib/auth/completion.ts: completeAuth + safeReturnTo. - apps/journal/app/lib/auth/completion.test.ts: 10 contract tests covering both modes, returnTo sanitization (path-relative, protocol- relative, absolute-URL, malformed), Set-Cookie attachment, redirect status, JSON shape. Caller migration: - api.auth.register.ts passkey-finish → completeAuth(json) - api.auth.login.ts finish-passkey → completeAuth(json) - api.auth.login.ts verify-code → completeAuth(json) - auth.verify.tsx magic-link consumer → completeAuth(redirect) Client form updates: - auth.login.tsx: pass returnTo in fetch body, read result.redirectTo on done. - auth.register.tsx: pass returnTo: "/?add-passkey=1" for the magic- link verify-code path (preserves the post-register passkey prompt via the chokepoint's safeReturnTo, instead of hardcoding it client-side). Verified: - pnpm typecheck && pnpm lint: green across all 15 workspaces. - pnpm --filter @trails-cool/journal test: 126 passed. - pnpm test:e2e auth: 4/4 passed without modification — confirms the refactor is behaviour-preserving for the user-facing flows that matter most (passkey register + login). Spec delta in openspec/changes/unify-auth-completion/specs/ applies at /opsx:archive time. Co-Authored-By: Claude Opus 4.7 (1M context) --- apps/journal/app/lib/auth.server.ts | 47 ++------ apps/journal/app/lib/auth/completion.test.ts | 112 ++++++++++++++++++ apps/journal/app/lib/auth/completion.ts | 76 ++++++++++++ apps/journal/app/lib/auth/session.ts | 46 +++++++ apps/journal/app/routes/api.auth.login.ts | 11 +- apps/journal/app/routes/api.auth.register.ts | 8 +- apps/journal/app/routes/auth.login.tsx | 8 +- apps/journal/app/routes/auth.register.tsx | 14 ++- apps/journal/app/routes/auth.verify.tsx | 14 ++- .../changes/unify-auth-completion/design.md | 6 +- .../specs/authentication-methods/spec.md | 16 +-- .../changes/unify-auth-completion/tasks.md | 26 ++-- 12 files changed, 304 insertions(+), 80 deletions(-) create mode 100644 apps/journal/app/lib/auth/completion.test.ts create mode 100644 apps/journal/app/lib/auth/completion.ts create mode 100644 apps/journal/app/lib/auth/session.ts diff --git a/apps/journal/app/lib/auth.server.ts b/apps/journal/app/lib/auth.server.ts index 2fbcbf5..b25615d 100644 --- a/apps/journal/app/lib/auth.server.ts +++ b/apps/journal/app/lib/auth.server.ts @@ -397,22 +397,19 @@ export async function verifyEmailChange(token: string, userId: string): Promise< } // --- Sessions --- +// +// Cookie session storage moved to `./auth/session.ts` so the post-verify +// chokepoint (`./auth/completion.ts`, see ADR-0004) can compose it. The +// re-exports below preserve the legacy `~/lib/auth.server` import path — +// new code should import from `~/lib/auth/session` directly. -import { createCookieSessionStorage } from "react-router"; - -const sessionSecret = process.env.SESSION_SECRET ?? "dev-secret-change-in-production"; - -export const sessionStorage = createCookieSessionStorage({ - cookie: { - name: "__session", - httpOnly: true, - secure: process.env.NODE_ENV === "production", - sameSite: "lax", - path: "/", - maxAge: 60 * 60 * 24 * 30, // 30 days - secrets: [sessionSecret], - }, -}); +/** @deprecated Import from `~/lib/auth/session` instead. */ +export { + sessionStorage, + createSession, + getSessionUser, + destroySession, +} from "./auth/session.ts"; /** * A row that carries the minimum a visibility check needs. @@ -466,23 +463,3 @@ export async function recordTermsAcceptance(userId: string, termsVersion: string .where(eq(users.id, userId)); } -export async function createSession(userId: string, request: Request) { - const session = await sessionStorage.getSession(request.headers.get("Cookie")); - session.set("userId", userId); - return sessionStorage.commitSession(session); -} - -export async function getSessionUser(request: Request) { - const db = getDb(); - const session = await sessionStorage.getSession(request.headers.get("Cookie")); - const userId = session.get("userId"); - if (!userId) return null; - - const [user] = await db.select().from(users).where(eq(users.id, userId)); - return user ?? null; -} - -export async function destroySession(request: Request) { - const session = await sessionStorage.getSession(request.headers.get("Cookie")); - return sessionStorage.destroySession(session); -} diff --git a/apps/journal/app/lib/auth/completion.test.ts b/apps/journal/app/lib/auth/completion.test.ts new file mode 100644 index 0000000..4da2a58 --- /dev/null +++ b/apps/journal/app/lib/auth/completion.test.ts @@ -0,0 +1,112 @@ +// Contract tests for the completeAuth chokepoint. See ADR-0004 + +// docs/adr/0005-no-authmethod-polymorphism.md for why this exists. + +import { describe, it, expect } from "vitest"; +import { completeAuth } from "./completion.ts"; + +function reqWith(headers: Record = {}) { + return new Request("https://localhost/whatever", { headers }); +} + +describe("completeAuth (mode=redirect)", () => { + it("redirects to returnTo when it's a same-origin path", async () => { + const res = await completeAuth({ + userId: "u1", + request: reqWith(), + returnTo: "/profile", + }); + expect(res.status).toBe(302); + expect(res.headers.get("Location")).toBe("/profile"); + }); + + it("redirects to / when returnTo is missing", async () => { + const res = await completeAuth({ userId: "u1", request: reqWith() }); + expect(res.headers.get("Location")).toBe("/"); + }); + + it("redirects to / when returnTo is null", async () => { + const res = await completeAuth({ + userId: "u1", + request: reqWith(), + returnTo: null, + }); + expect(res.headers.get("Location")).toBe("/"); + }); + + it("rejects protocol-relative returnTo (//evil.com/x) → /", async () => { + const res = await completeAuth({ + userId: "u1", + request: reqWith(), + returnTo: "//evil.com/x", + }); + expect(res.headers.get("Location")).toBe("/"); + }); + + it("rejects absolute-URL returnTo (https://evil.com) → /", async () => { + const res = await completeAuth({ + userId: "u1", + request: reqWith(), + returnTo: "https://evil.com", + }); + expect(res.headers.get("Location")).toBe("/"); + }); + + it("rejects returnTo that doesn't start with / → /", async () => { + const res = await completeAuth({ + userId: "u1", + request: reqWith(), + returnTo: "javascript:alert(1)", + }); + expect(res.headers.get("Location")).toBe("/"); + }); + + it("attaches a __session Set-Cookie carrying the userId", async () => { + const res = await completeAuth({ + userId: "u1", + request: reqWith(), + returnTo: "/", + }); + const setCookie = res.headers.get("Set-Cookie"); + expect(setCookie).not.toBeNull(); + expect(setCookie!).toMatch(/^__session=/); + // HttpOnly is required for a session cookie. + expect(setCookie!.toLowerCase()).toContain("httponly"); + }); +}); + +describe("completeAuth (mode=json)", () => { + it("returns 200 JSON with sanitized redirectTo and Set-Cookie", async () => { + const res = await completeAuth({ + userId: "u1", + request: reqWith(), + returnTo: "/profile", + mode: "json", + }); + expect(res.status).toBe(200); + expect(res.headers.get("Content-Type")).toContain("application/json"); + expect(res.headers.get("Set-Cookie")).toMatch(/^__session=/); + const body = (await res.json()) as { ok: boolean; step: string; redirectTo: string }; + expect(body).toEqual({ ok: true, step: "done", redirectTo: "/profile" }); + }); + + it("falls back to / when returnTo is unsafe (json mode)", async () => { + const res = await completeAuth({ + userId: "u1", + request: reqWith(), + returnTo: "https://evil.com", + mode: "json", + }); + const body = (await res.json()) as { ok: boolean; redirectTo: string }; + expect(body.redirectTo).toBe("/"); + }); + + it("redirectTo defaults to / when no returnTo (json mode)", async () => { + const res = await completeAuth({ + userId: "u1", + request: reqWith(), + mode: "json", + }); + const body = (await res.json()) as { ok: boolean; redirectTo: string }; + expect(body.redirectTo).toBe("/"); + }); +}); diff --git a/apps/journal/app/lib/auth/completion.ts b/apps/journal/app/lib/auth/completion.ts new file mode 100644 index 0000000..cc56200 --- /dev/null +++ b/apps/journal/app/lib/auth/completion.ts @@ -0,0 +1,76 @@ +// completeAuth — the single chokepoint that every successful web auth +// flow uses to mint the cookie session and produce the response. See +// ADR-0004 + CONTEXT.md (Authentication section). +// +// Two response shapes, picked via `mode`: +// - 'redirect' (loader callers / direct browser navigation): +// 302 redirect to the sanitized target, Set-Cookie attached. +// - 'json' (action callers from imperative fetch in client forms): +// 200 JSON { ok: true, redirectTo } with Set-Cookie. Client reads +// redirectTo and does window.location = redirectTo. +// +// Both modes share identity-agnostic behaviour: createSession + same- +// origin sanitization + Set-Cookie. Per ADR-0005, this function knows +// nothing about how identity was proved (passkey, magic-link, etc.) — +// the caller does its own per-method verification first. +// +// Terms recording is NOT here: both registration paths (finishRegistration +// for passkey, registerWithMagicLink for magic-link) record terms at +// user-creation time, before any path can reach completeAuth. + +import { redirect } from "react-router"; +import { createSession } from "./session.ts"; + +export type CompleteAuthMode = "redirect" | "json"; + +export interface CompleteAuthInput { + userId: string; + request: Request; + /** + * Optional caller-supplied redirect target. Validated as a same-origin + * path; anything else falls back to "/". Pass through whatever you + * received from the client — sanitization is centralized here. + */ + returnTo?: string | null; + /** + * Response shape: + * - 'redirect' (default): 302 redirect Response; right for loaders + * (direct browser navigation, e.g. auth.verify.tsx loader). + * - 'json': 200 JSON `{ ok: true, redirectTo }`; right for action + * handlers called by imperative fetch from client form code + * (e.g. api.auth.register, api.auth.login). Client navigates + * using `data.redirectTo`. + */ + mode?: CompleteAuthMode; +} + +/** + * Same-origin path check. Accepts only paths that start with a single + * "/" — rejects: + * - Empty / null / undefined + * - Protocol-relative ("//evil.com/x") + * - Absolute URLs ("https://evil.com") + * - Anything not starting with "/" + */ +function safeReturnTo(value: string | null | undefined): string | null { + if (typeof value !== "string" || value.length === 0) return null; + if (!value.startsWith("/")) return null; + if (value.startsWith("//")) return null; + return value; +} + +export async function completeAuth(input: CompleteAuthInput): Promise { + const cookie = await createSession(input.userId, input.request); + const target = safeReturnTo(input.returnTo) ?? "/"; + const headers = { "Set-Cookie": cookie }; + if (input.mode === "json") { + // `step: "done"` retained for compatibility with existing client + // form checks (auth.register.tsx, auth.login.tsx). New code should + // read `redirectTo` and navigate there. + return Response.json( + { ok: true, step: "done", redirectTo: target }, + { headers }, + ); + } + return redirect(target, { headers }); +} diff --git a/apps/journal/app/lib/auth/session.ts b/apps/journal/app/lib/auth/session.ts new file mode 100644 index 0000000..c2d20b3 --- /dev/null +++ b/apps/journal/app/lib/auth/session.ts @@ -0,0 +1,46 @@ +// Cookie session storage. Lives here (separate from auth.server.ts) so +// the post-verify chokepoint (./completion.ts) can compose it without +// dragging the entire auth surface in. +// +// The legacy import path `~/lib/auth.server` continues to re-export +// these symbols for backwards compat — see auth.server.ts. + +import { createCookieSessionStorage } from "react-router"; +import { eq } from "drizzle-orm"; +import { users } from "@trails-cool/db/schema/journal"; +import { getDb } from "../db.ts"; + +const sessionSecret = process.env.SESSION_SECRET ?? "dev-secret-change-in-production"; + +export const sessionStorage = createCookieSessionStorage({ + cookie: { + name: "__session", + httpOnly: true, + secure: process.env.NODE_ENV === "production", + sameSite: "lax", + path: "/", + maxAge: 60 * 60 * 24 * 30, // 30 days + secrets: [sessionSecret], + }, +}); + +export async function createSession(userId: string, request: Request) { + const session = await sessionStorage.getSession(request.headers.get("Cookie")); + session.set("userId", userId); + return sessionStorage.commitSession(session); +} + +export async function getSessionUser(request: Request) { + const db = getDb(); + const session = await sessionStorage.getSession(request.headers.get("Cookie")); + const userId = session.get("userId"); + if (!userId) return null; + + const [user] = await db.select().from(users).where(eq(users.id, userId)); + return user ?? null; +} + +export async function destroySession(request: Request) { + const session = await sessionStorage.getSession(request.headers.get("Cookie")); + return sessionStorage.destroySession(session); +} diff --git a/apps/journal/app/routes/api.auth.login.ts b/apps/journal/app/routes/api.auth.login.ts index 7fa122e..184f685 100644 --- a/apps/journal/app/routes/api.auth.login.ts +++ b/apps/journal/app/routes/api.auth.login.ts @@ -1,11 +1,12 @@ import { data } from "react-router"; import type { Route } from "./+types/api.auth.login"; -import { startAuthentication, finishAuthentication, createMagicToken, verifyLoginCode, createSession } from "~/lib/auth.server"; +import { startAuthentication, finishAuthentication, createMagicToken, verifyLoginCode } from "~/lib/auth.server"; +import { completeAuth } from "~/lib/auth/completion"; import { sendMagicLink } from "~/lib/email.server"; export async function action({ request }: Route.ActionArgs) { const body = await request.json(); - const { step, response, challenge, email, code } = body; + const { step, response, challenge, email, code, returnTo } = body; try { if (step === "start-passkey") { @@ -15,8 +16,7 @@ export async function action({ request }: Route.ActionArgs) { if (step === "finish-passkey") { const userId = await finishAuthentication(response, challenge); - const cookie = await createSession(userId, request); - return data({ step: "done" }, { headers: { "Set-Cookie": cookie } }); + return completeAuth({ userId, request, returnTo, mode: "json" }); } if (step === "magic-link") { @@ -38,8 +38,7 @@ export async function action({ request }: Route.ActionArgs) { 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 completeAuth({ userId, request, returnTo, mode: "json" }); } return data({ error: "Invalid step" }, { status: 400 }); diff --git a/apps/journal/app/routes/api.auth.register.ts b/apps/journal/app/routes/api.auth.register.ts index a78d005..b9a8e31 100644 --- a/apps/journal/app/routes/api.auth.register.ts +++ b/apps/journal/app/routes/api.auth.register.ts @@ -1,12 +1,13 @@ import { data } from "react-router"; import type { Route } from "./+types/api.auth.register"; -import { startRegistration, finishRegistration, createSession, addPasskeyStart, addPasskeyFinish, registerWithMagicLink } from "~/lib/auth.server"; +import { startRegistration, finishRegistration, addPasskeyStart, addPasskeyFinish, registerWithMagicLink } from "~/lib/auth.server"; +import { completeAuth } from "~/lib/auth/completion"; import { sendWelcome, sendMagicLink } from "~/lib/email.server"; 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, termsAccepted, termsVersion } = body; + const { step, email, username, response, challenge, userId, termsAccepted, termsVersion, returnTo } = body; const origin = process.env.ORIGIN ?? `http://localhost:3000`; // Registration steps require terms acceptance + the version the client @@ -27,11 +28,10 @@ export async function action({ request }: Route.ActionArgs) { if (step === "finish") { const newUserId = await finishRegistration(userId, email, username, response, challenge, termsVersion); - const cookie = await createSession(newUserId, request); sendWelcome(email, username).catch((err) => logger.error({ err }, "Failed to send welcome email"), ); - return data({ step: "done" }, { headers: { "Set-Cookie": cookie } }); + return completeAuth({ userId: newUserId, request, returnTo, mode: "json" }); } if (step === "register-magic-link") { diff --git a/apps/journal/app/routes/auth.login.tsx b/apps/journal/app/routes/auth.login.tsx index 7db270a..5b39c8a 100644 --- a/apps/journal/app/routes/auth.login.tsx +++ b/apps/journal/app/routes/auth.login.tsx @@ -50,6 +50,7 @@ export default function LoginPage() { step: "finish-passkey", response: webAuthnResp, challenge: startData.options.challenge, + returnTo, }), }); @@ -57,7 +58,8 @@ export default function LoginPage() { if (finishData.error) { setError(finishData.error); } else if (finishData.step === "done") { - window.location.href = returnTo ?? "/"; + // Server-sanitized destination (see completeAuth in auth/completion.ts). + window.location.href = finishData.redirectTo ?? "/"; } } catch (err) { const message = (err as Error).message; @@ -80,14 +82,14 @@ export default function LoginPage() { const resp = await fetch("/api/auth/login", { method: "POST", headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ step: "verify-code", email, code: loginCode }), + body: JSON.stringify({ step: "verify-code", email, code: loginCode, returnTo }), }); const result = await resp.json(); if (result.error) { setError(result.error); } else if (result.step === "done") { - window.location.href = returnTo ?? "/"; + window.location.href = result.redirectTo ?? "/"; } } catch (err) { setError((err as Error).message); diff --git a/apps/journal/app/routes/auth.register.tsx b/apps/journal/app/routes/auth.register.tsx index 2a5ae74..81dc6e9 100644 --- a/apps/journal/app/routes/auth.register.tsx +++ b/apps/journal/app/routes/auth.register.tsx @@ -75,7 +75,7 @@ export default function RegisterPage() { if (finishData.error) { setError(finishData.error); } else if (finishData.step === "done") { - window.location.href = "/"; + window.location.href = finishData.redirectTo ?? "/"; } } catch (err) { setError((err as Error).message); @@ -134,13 +134,21 @@ export default function RegisterPage() { const resp = await fetch("/api/auth/login", { method: "POST", headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ step: "verify-code", email, code: verifyCode }), + body: JSON.stringify({ + step: "verify-code", + email, + code: verifyCode, + // Just-registered user: prompt to set up a passkey so next time + // they can use it directly. completeAuth's safeReturnTo accepts + // this as a same-origin path. + returnTo: "/?add-passkey=1", + }), }); const result = await resp.json(); if (result.error) { setError(result.error); } else if (result.step === "done") { - window.location.href = "/?add-passkey=1"; + window.location.href = result.redirectTo ?? "/?add-passkey=1"; } } catch (err) { setError((err as Error).message); diff --git a/apps/journal/app/routes/auth.verify.tsx b/apps/journal/app/routes/auth.verify.tsx index dec9eae..d6c2965 100644 --- a/apps/journal/app/routes/auth.verify.tsx +++ b/apps/journal/app/routes/auth.verify.tsx @@ -1,6 +1,7 @@ import { redirect, data } from "react-router"; import type { Route } from "./+types/auth.verify"; -import { verifyMagicToken, verifyEmailChange, createSession, getSessionUser } from "~/lib/auth.server"; +import { verifyMagicToken, verifyEmailChange, getSessionUser } from "~/lib/auth.server"; +import { completeAuth } from "~/lib/auth/completion"; export async function loader({ request }: Route.LoaderArgs) { const url = new URL(request.url); @@ -20,10 +21,13 @@ export async function loader({ request }: Route.LoaderArgs) { } const userId = await verifyMagicToken(token); - const cookie = await createSession(userId, request); - const returnTo = url.searchParams.get("returnTo"); - const destination = returnTo?.startsWith("/") ? returnTo : "/?add-passkey=1"; - return redirect(destination, { headers: { "Set-Cookie": cookie } }); + // Default destination after magic-link sign-in is "/?add-passkey=1" + // (prompt to set up a passkey now that they're in). If the link + // carried a returnTo, completeAuth's safeReturnTo will honor any + // same-origin path and otherwise fall back to "/" — handle the + // add-passkey default before delegating. + const returnTo = url.searchParams.get("returnTo") ?? "/?add-passkey=1"; + return completeAuth({ userId, request, returnTo, mode: "redirect" }); } catch (e) { return data({ error: (e as Error).message }, { status: 400 }); } diff --git a/openspec/changes/unify-auth-completion/design.md b/openspec/changes/unify-auth-completion/design.md index a55e0ce..df67e25 100644 --- a/openspec/changes/unify-auth-completion/design.md +++ b/openspec/changes/unify-auth-completion/design.md @@ -40,8 +40,6 @@ ADRs already recorded: ```ts async function completeAuth(input: { userId: string; - isNewRegistration: boolean; - termsVersion?: string; // required if isNewRegistration; ignored otherwise request: Request; returnTo?: string | null; }): Promise @@ -49,7 +47,9 @@ async function completeAuth(input: { Returns a `Response` (a `redirect` from React Router with the session `Set-Cookie` attached). Callers do `return await completeAuth(...)` from their action / loader. No headers-vs-redirect split: the chokepoint owns both halves. -`termsVersion` is optional at the type level but required-when-`isNewRegistration` at runtime. Asserting it inside the function (throw on `isNewRegistration && !termsVersion`) keeps the call sites tidy. Alternative: a discriminated union forcing the compiler to require `termsVersion` when `isNewRegistration: true`. Lean toward the runtime assertion — three call sites, two of which set `isNewRegistration: false` — the type ergonomics aren't worth the union complexity. +**Terms recording is NOT in `completeAuth`.** Both registration paths already write `terms_version` + `terms_accepted_at` at user creation: `finishRegistration` writes them when the user row is inserted (passkey path); `registerWithMagicLink` writes them when the user row is inserted (magic-link path). Magic-link registration *must* write terms at user creation, before verification, because the user row exists between register and verify — if terms weren't already written, the Terms gate would bounce the user on first authenticated visit. + +So `completeAuth` is purely **session + redirect**. No `isNewRegistration` flag, no `termsVersion` parameter. The earlier framing of an `isNewRegistration` discriminator was a mis-read — there is no code path that needs to record terms at completion time. ### Decision 3: File layout New directory `apps/journal/app/lib/auth/` containing: diff --git a/openspec/changes/unify-auth-completion/specs/authentication-methods/spec.md b/openspec/changes/unify-auth-completion/specs/authentication-methods/spec.md index d7035c9..a248324 100644 --- a/openspec/changes/unify-auth-completion/specs/authentication-methods/spec.md +++ b/openspec/changes/unify-auth-completion/specs/authentication-methods/spec.md @@ -1,31 +1,31 @@ ## ADDED Requirements ### Requirement: Single web auth completion chokepoint -Every successful web authentication flow — passkey register-finish, passkey login-finish, magic-link 6-digit-code verify, magic-link click-through verify — SHALL complete by calling a single `completeAuth` function at `apps/journal/app/lib/auth/completion.ts`. The function SHALL be the sole place where a successful web authentication records the accepted Terms version (only on registration), mints the cookie session, and constructs the redirect to `returnTo` (or `/` when absent or rejected). +Every successful web authentication flow — passkey register-finish, passkey login-finish, magic-link 6-digit-code verify, magic-link click-through verify — SHALL complete by calling a single `completeAuth` function at `apps/journal/app/lib/auth/completion.ts`. The function SHALL be the sole place where a successful web authentication mints the cookie session and constructs the redirect to `returnTo` (or `/` when absent or rejected). Per-method identity verification (WebAuthn ceremony, magic-token consumption, 6-digit-code consumption) SHALL run in its own function and produce a `userId` *before* `completeAuth` is invoked. `completeAuth` SHALL NOT know how identity was proved. -The Terms gate (root-loader redirect for cookie sessions; `requireApiUser` 403 for bearer-token API requests) SHALL remain the enforcement point for stale `terms_version`. `completeAuth` only **records** terms on new registrations; it does not enforce them. +Terms recording happens at user creation time inside the per-method registration functions (`finishRegistration` for passkey, `registerWithMagicLink` for magic-link), not inside `completeAuth`. The Terms gate (root-loader redirect for cookie sessions; `requireApiUser` 403 for bearer-token API requests) SHALL remain the enforcement point for stale `terms_version`. OAuth-code issuance at `/oauth/authorize` SHALL NOT be routed through `completeAuth` — that flow operates on an already-authenticated user and shares only the trailing redirect, not the full sequence. #### Scenario: Passkey register-finish completes through the chokepoint - **WHEN** a visitor submits a successful WebAuthn `step: "finish"` registration response -- **THEN** the route handler verifies the credential, creates the user row, and calls `completeAuth({ userId, isNewRegistration: true, termsVersion, request, returnTo })` -- **AND** `completeAuth` writes `users.terms_version` and `users.terms_accepted_at`, mints the session cookie, and returns a `Response` redirecting to `returnTo` (or `/`) +- **THEN** the route handler verifies the credential and creates the user row (with terms recorded) inside `finishRegistration`, then calls `completeAuth({ userId, request, returnTo })` +- **AND** `completeAuth` mints the session cookie and returns a `Response` redirecting to `returnTo` (or `/`) #### Scenario: Passkey login-finish completes through the chokepoint - **WHEN** a visitor submits a successful WebAuthn `step: "finish-passkey"` login response -- **THEN** the route handler verifies the credential and calls `completeAuth({ userId, isNewRegistration: false, request, returnTo })` -- **AND** `completeAuth` skips the terms write (only registrations record terms), mints the session cookie, and returns a `Response` redirecting to `returnTo` (or `/`) +- **THEN** the route handler verifies the credential and calls `completeAuth({ userId, request, returnTo })` +- **AND** `completeAuth` mints the session cookie and returns a `Response` redirecting to `returnTo` (or `/`) #### Scenario: Magic-link 6-digit-code verify completes through the chokepoint - **WHEN** a visitor submits a valid 6-digit code via `step: "verify-code"` -- **THEN** the route handler consumes the magic token (marks `used_at`) and calls `completeAuth({ userId, isNewRegistration: false, request, returnTo })` +- **THEN** the route handler consumes the magic token (marks `used_at`) and calls `completeAuth({ userId, request, returnTo })` #### Scenario: Magic-link click-through verify completes through the chokepoint - **WHEN** a visitor opens `/auth/verify?token=` with a valid, unused, unexpired token -- **THEN** the route handler consumes the magic token and calls `completeAuth({ userId, isNewRegistration: false, request, returnTo })` +- **THEN** the route handler consumes the magic token and calls `completeAuth({ userId, request, returnTo })` #### Scenario: returnTo is sanitized inside completeAuth - **WHEN** `completeAuth` is called with a `returnTo` value that is not a same-origin absolute path (e.g. starts with `//`, an absolute URL, or is malformed) diff --git a/openspec/changes/unify-auth-completion/tasks.md b/openspec/changes/unify-auth-completion/tasks.md index ca50181..aa94674 100644 --- a/openspec/changes/unify-auth-completion/tasks.md +++ b/openspec/changes/unify-auth-completion/tasks.md @@ -1,27 +1,27 @@ ## 1. New auth module structure -- [ ] 1.1 Create `apps/journal/app/lib/auth/` directory. -- [ ] 1.2 Create `apps/journal/app/lib/auth/session.ts` and move `sessionStorage`, `createSession`, `getSessionUser`, `destroySession` from `auth.server.ts` (preserve behaviour, including `process.env.SESSION_SECRET` source). -- [ ] 1.3 In `auth.server.ts`, re-export the moved helpers from `./auth/session.ts` so existing imports keep working unchanged. Add a JSDoc `@deprecated`-style comment pointing at the new path. +- [x] 1.1 Create `apps/journal/app/lib/auth/` directory. +- [x] 1.2 Create `apps/journal/app/lib/auth/session.ts` and move `sessionStorage`, `createSession`, `getSessionUser`, `destroySession` from `auth.server.ts` (preserve behaviour, including `process.env.SESSION_SECRET` source). +- [x] 1.3 In `auth.server.ts`, re-export the moved helpers from `./auth/session.ts` so existing imports keep working unchanged. Add a JSDoc `@deprecated`-style comment pointing at the new path. ## 2. completeAuth chokepoint -- [ ] 2.1 Write `apps/journal/app/lib/auth/completion.test.ts` (TDD red): scenarios for new-registration writes terms, non-registration skips terms, returnTo defaults to `/`, returnTo `//evil.com` rejected, returnTo `https://evil.com` rejected, response includes Set-Cookie. -- [ ] 2.2 Create `apps/journal/app/lib/auth/completion.ts` exporting `completeAuth({ userId, isNewRegistration, termsVersion?, request, returnTo? }) → Promise` and a private `safeReturnTo(value)` helper. Implementation: assert `termsVersion` when `isNewRegistration`; if `isNewRegistration`, `recordTermsAcceptance(userId, termsVersion)`; `createSession(userId, request)`; `redirect(safeReturnTo(returnTo) ?? "/", { headers })`. -- [ ] 2.3 Run completion tests green. +- [x] 2.1 Write `apps/journal/app/lib/auth/completion.test.ts` (TDD red): scenarios for returnTo defaults to `/`, returnTo `//evil.com` rejected, returnTo `https://evil.com` rejected, response is a 302/303 redirect, response includes Set-Cookie naming `__session`. +- [x] 2.2 Create `apps/journal/app/lib/auth/completion.ts` exporting `completeAuth({ userId, request, returnTo? }) → Promise` and a private `safeReturnTo(value)` helper. Implementation: `createSession(userId, request)`; `redirect(safeReturnTo(returnTo) ?? "/", { headers: { "Set-Cookie": cookie } })`. Terms recording is **not** here — both registration paths already record terms at user creation, so the chokepoint is purely session + redirect. +- [x] 2.3 Run completion tests green. ## 3. Caller migration -- [ ] 3.1 `apps/journal/app/routes/api.auth.register.ts` passkey-finish branch — replace inlined session+redirect with `return completeAuth({ userId, isNewRegistration: true, termsVersion, request, returnTo })`. Drop now-unused imports. -- [ ] 3.2 `apps/journal/app/routes/api.auth.login.ts` passkey `step: "finish-passkey"` branch — replace with `return completeAuth({ userId, isNewRegistration: false, request, returnTo })`. -- [ ] 3.3 `apps/journal/app/routes/api.auth.login.ts` magic-link `step: "verify-code"` branch — replace with `return completeAuth(...)`. -- [ ] 3.4 `apps/journal/app/routes/auth.verify.tsx` magic-link click-through consumer — replace with `return completeAuth(...)`. -- [ ] 3.5 Confirm no other callers of `createSession` remain inside auth route handlers (they should all flow through `completeAuth`). `getSessionUser` and `destroySession` continue to be called directly from non-completion sites — that's expected. +- [x] 3.1 `apps/journal/app/routes/api.auth.register.ts` passkey-finish branch — replace inlined session+redirect with `return completeAuth({ userId, request, returnTo })`. Drop now-unused imports. +- [x] 3.2 `apps/journal/app/routes/api.auth.login.ts` passkey `step: "finish-passkey"` branch — replace with `return completeAuth({ userId, request, returnTo })`. +- [x] 3.3 `apps/journal/app/routes/api.auth.login.ts` magic-link `step: "verify-code"` branch — replace with `return completeAuth(...)`. +- [x] 3.4 `apps/journal/app/routes/auth.verify.tsx` magic-link click-through consumer — replace with `return completeAuth(...)`. +- [x] 3.5 Confirm no other callers of `createSession` remain inside auth route handlers (they should all flow through `completeAuth`). `getSessionUser` and `destroySession` continue to be called directly from non-completion sites — that's expected. ## 4. Verification -- [ ] 4.1 `pnpm typecheck && pnpm lint && pnpm test` green. -- [ ] 4.2 `pnpm test:e2e` (auth flows) green without modification — proves behaviour-preserving refactor. +- [x] 4.1 `pnpm typecheck && pnpm lint && pnpm test` green. +- [x] 4.2 `pnpm test:e2e` (auth flows) green without modification — proves behaviour-preserving refactor. - [ ] 4.3 Manual sanity: register with passkey locally, login with passkey, log out, re-login via magic-link 6-digit code, click-through magic link from `auth.verify.tsx`. Confirm session cookie set + correct redirect each time. ## 5. Documentation + follow-up From fc2f938cf5b5bff832e874c8f1fa23e538148da2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Fri, 8 May 2026 02:55:19 +0200 Subject: [PATCH 003/319] Mark task 4.3 (manual smoke) complete MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All four flows verified locally over plain HTTP: passkey register, passkey login, logout, magic-link 6-digit verify-code, magic-link click-through. Session cookie set + correct redirect every time. 13/14 tasks done. Only 5.1 (spec delta sync at /opsx:archive time) and 5.2 (optional follow-up to drop the auth.server.ts re-exports) remain — neither blocks merge. Co-Authored-By: Claude Opus 4.7 (1M context) --- openspec/changes/unify-auth-completion/tasks.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openspec/changes/unify-auth-completion/tasks.md b/openspec/changes/unify-auth-completion/tasks.md index aa94674..7281465 100644 --- a/openspec/changes/unify-auth-completion/tasks.md +++ b/openspec/changes/unify-auth-completion/tasks.md @@ -22,7 +22,7 @@ - [x] 4.1 `pnpm typecheck && pnpm lint && pnpm test` green. - [x] 4.2 `pnpm test:e2e` (auth flows) green without modification — proves behaviour-preserving refactor. -- [ ] 4.3 Manual sanity: register with passkey locally, login with passkey, log out, re-login via magic-link 6-digit code, click-through magic link from `auth.verify.tsx`. Confirm session cookie set + correct redirect each time. +- [x] 4.3 Manual sanity: register with passkey locally, login with passkey, log out, re-login via magic-link 6-digit code, click-through magic link from `auth.verify.tsx`. Confirm session cookie set + correct redirect each time. Verified 2026-05-08 over plain HTTP (HTTPS dev hits a pre-existing HTTP/2 + missing-Host issue with React Router 7.14's CSRF check — separate follow-up). ## 5. Documentation + follow-up From b9aac2859a642811b3ccfd1711173634dc14455b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Fri, 8 May 2026 03:01:30 +0200 Subject: [PATCH 004/319] Drop auth.server.ts re-exports + rename to .server.ts convention (task 5.2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two cleanups in one pass: 1. Update import paths app-wide from `~/lib/auth.server` to `~/lib/auth/session.server` for the four session helpers (sessionStorage, createSession, getSessionUser, destroySession). ~40 files: 33 simple path swaps where the file imported only session symbols, 5 splits where it also imported per-method auth functions (auth.verify.tsx, api.settings.email.ts, activities.\$id.tsx, routes.\$id.tsx, auth.accept-terms.tsx) — those keep one import from auth.server (for verifyMagicToken, canView, recordTermsAcceptance, etc.) and gain a second import from auth/session.server. Two more files used relative paths and were missed by the first grep pass (lib/oauth.server.ts and routes/oauth.authorize.tsx) — migrated too. The @deprecated re-exports block in auth.server.ts is gone. 2. Rename the new auth files to follow the project's `.server.ts` convention so Vite/React Router treat them as server-only (they read process.env.SESSION_SECRET, hit the DB, etc. — must NOT enter the client bundle): - auth/session.ts → auth/session.server.ts - auth/completion.ts → auth/completion.server.ts - auth/completion.test.ts → auth/completion.server.test.ts Done with `git mv` so blame is preserved. Verified: typecheck + lint green; 126 unit tests pass. Co-Authored-By: Claude Opus 4.7 (1M context) --- apps/journal/app/lib/auth.server.ts | 18 ++++-------------- ...etion.test.ts => completion.server.test.ts} | 2 +- .../{completion.ts => completion.server.ts} | 2 +- .../lib/auth/{session.ts => session.server.ts} | 0 apps/journal/app/lib/oauth.server.ts | 2 +- apps/journal/app/root.tsx | 2 +- apps/journal/app/routes/activities.$id.tsx | 3 ++- apps/journal/app/routes/activities._index.tsx | 2 +- apps/journal/app/routes/activities.new.tsx | 2 +- apps/journal/app/routes/api.auth.login.ts | 2 +- apps/journal/app/routes/api.auth.register.ts | 2 +- apps/journal/app/routes/api.events.ts | 2 +- .../app/routes/api.follows.$id.approve.ts | 2 +- .../app/routes/api.follows.$id.reject.ts | 2 +- .../app/routes/api.notifications.$id.read.ts | 2 +- .../app/routes/api.notifications.read-all.ts | 2 +- .../routes/api.routes.$id.edit-in-planner.ts | 2 +- .../app/routes/api.settings.delete-account.ts | 2 +- apps/journal/app/routes/api.settings.email.ts | 3 ++- .../app/routes/api.settings.passkey.delete.ts | 2 +- .../journal/app/routes/api.settings.profile.ts | 2 +- .../app/routes/api.sync.callback.$provider.ts | 2 +- .../app/routes/api.sync.connect.$provider.ts | 2 +- .../routes/api.sync.disconnect.$provider.ts | 2 +- .../routes/api.sync.push.$provider.$routeId.ts | 2 +- .../app/routes/api.users.$username.follow.ts | 2 +- .../app/routes/api.users.$username.unfollow.ts | 2 +- apps/journal/app/routes/auth.accept-terms.tsx | 3 ++- apps/journal/app/routes/auth.logout.tsx | 2 +- apps/journal/app/routes/auth.verify.tsx | 5 +++-- apps/journal/app/routes/explore.tsx | 2 +- apps/journal/app/routes/feed.tsx | 2 +- apps/journal/app/routes/home.tsx | 2 +- apps/journal/app/routes/notifications.tsx | 2 +- apps/journal/app/routes/oauth.authorize.tsx | 2 +- apps/journal/app/routes/routes.$id.edit.tsx | 2 +- apps/journal/app/routes/routes.$id.tsx | 3 ++- apps/journal/app/routes/routes._index.tsx | 2 +- apps/journal/app/routes/routes.new.tsx | 2 +- apps/journal/app/routes/settings.account.tsx | 2 +- .../app/routes/settings.connections.tsx | 2 +- apps/journal/app/routes/settings.profile.tsx | 2 +- apps/journal/app/routes/settings.security.tsx | 2 +- apps/journal/app/routes/settings.tsx | 2 +- .../app/routes/sync.import.$provider.tsx | 2 +- .../app/routes/users.$username.followers.tsx | 2 +- .../app/routes/users.$username.following.tsx | 2 +- apps/journal/app/routes/users.$username.tsx | 2 +- .../changes/unify-auth-completion/tasks.md | 2 +- 49 files changed, 57 insertions(+), 62 deletions(-) rename apps/journal/app/lib/auth/{completion.test.ts => completion.server.test.ts} (98%) rename apps/journal/app/lib/auth/{completion.ts => completion.server.ts} (98%) rename apps/journal/app/lib/auth/{session.ts => session.server.ts} (100%) diff --git a/apps/journal/app/lib/auth.server.ts b/apps/journal/app/lib/auth.server.ts index b25615d..6df9c3f 100644 --- a/apps/journal/app/lib/auth.server.ts +++ b/apps/journal/app/lib/auth.server.ts @@ -396,20 +396,10 @@ export async function verifyEmailChange(token: string, userId: string): Promise< return newEmail; } -// --- Sessions --- -// -// Cookie session storage moved to `./auth/session.ts` so the post-verify -// chokepoint (`./auth/completion.ts`, see ADR-0004) can compose it. The -// re-exports below preserve the legacy `~/lib/auth.server` import path — -// new code should import from `~/lib/auth/session` directly. - -/** @deprecated Import from `~/lib/auth/session` instead. */ -export { - sessionStorage, - createSession, - getSessionUser, - destroySession, -} from "./auth/session.ts"; +// Cookie session storage lives at `./auth/session.ts` (see ADR-0004 + the +// `auth/completion.ts` chokepoint). Import session helpers directly from +// there; this file owns only per-method identity verification (passkey +// ceremony + magic-token lifecycle) and Terms recording. /** * A row that carries the minimum a visibility check needs. diff --git a/apps/journal/app/lib/auth/completion.test.ts b/apps/journal/app/lib/auth/completion.server.test.ts similarity index 98% rename from apps/journal/app/lib/auth/completion.test.ts rename to apps/journal/app/lib/auth/completion.server.test.ts index 4da2a58..f5400b9 100644 --- a/apps/journal/app/lib/auth/completion.test.ts +++ b/apps/journal/app/lib/auth/completion.server.test.ts @@ -2,7 +2,7 @@ // docs/adr/0005-no-authmethod-polymorphism.md for why this exists. import { describe, it, expect } from "vitest"; -import { completeAuth } from "./completion.ts"; +import { completeAuth } from "./completion.server.ts"; function reqWith(headers: Record = {}) { return new Request("https://localhost/whatever", { headers }); diff --git a/apps/journal/app/lib/auth/completion.ts b/apps/journal/app/lib/auth/completion.server.ts similarity index 98% rename from apps/journal/app/lib/auth/completion.ts rename to apps/journal/app/lib/auth/completion.server.ts index cc56200..cbf7dcf 100644 --- a/apps/journal/app/lib/auth/completion.ts +++ b/apps/journal/app/lib/auth/completion.server.ts @@ -19,7 +19,7 @@ // user-creation time, before any path can reach completeAuth. import { redirect } from "react-router"; -import { createSession } from "./session.ts"; +import { createSession } from "./session.server.ts"; export type CompleteAuthMode = "redirect" | "json"; diff --git a/apps/journal/app/lib/auth/session.ts b/apps/journal/app/lib/auth/session.server.ts similarity index 100% rename from apps/journal/app/lib/auth/session.ts rename to apps/journal/app/lib/auth/session.server.ts diff --git a/apps/journal/app/lib/oauth.server.ts b/apps/journal/app/lib/oauth.server.ts index a4c8c30..d1cd525 100644 --- a/apps/journal/app/lib/oauth.server.ts +++ b/apps/journal/app/lib/oauth.server.ts @@ -7,7 +7,7 @@ import { oauthCodes, oauthTokens, } from "@trails-cool/db/schema/journal"; -import { getSessionUser } from "./auth.server.ts"; +import { getSessionUser } from "./auth/session.server.ts"; const CODE_EXPIRY_MS = 10 * 60 * 1000; // 10 minutes const ACCESS_TOKEN_EXPIRY_MS = 60 * 60 * 1000; // 1 hour diff --git a/apps/journal/app/root.tsx b/apps/journal/app/root.tsx index 1a475db..65ff76a 100644 --- a/apps/journal/app/root.tsx +++ b/apps/journal/app/root.tsx @@ -5,7 +5,7 @@ import type { Route } from "./+types/root"; import * as Sentry from "@sentry/react"; import { useTranslation } from "react-i18next"; import { detectLocale } from "@trails-cool/i18n"; -import { getSessionUser } from "~/lib/auth.server"; +import { getSessionUser } from "~/lib/auth/session.server"; import { LocaleProvider } from "~/components/LocaleContext"; import { AlphaBanner } from "~/components/AlphaBanner"; import { useUnreadNotifications } from "~/hooks/useUnreadNotifications"; diff --git a/apps/journal/app/routes/activities.$id.tsx b/apps/journal/app/routes/activities.$id.tsx index 3c840ae..7b4da0d 100644 --- a/apps/journal/app/routes/activities.$id.tsx +++ b/apps/journal/app/routes/activities.$id.tsx @@ -1,7 +1,8 @@ import { data, redirect } from "react-router"; import { useTranslation } from "react-i18next"; import type { Route } from "./+types/activities.$id"; -import { canView, getSessionUser } from "~/lib/auth.server"; +import { canView } from "~/lib/auth.server"; +import { getSessionUser } from "~/lib/auth/session.server"; import { getActivity, deleteActivity, linkActivityToRoute, createRouteFromActivity, updateActivityVisibility } from "~/lib/activities.server"; import { deleteImportByActivity } from "~/lib/sync/imports.server"; import { listRoutes } from "~/lib/routes.server"; diff --git a/apps/journal/app/routes/activities._index.tsx b/apps/journal/app/routes/activities._index.tsx index 4380be9..78e3526 100644 --- a/apps/journal/app/routes/activities._index.tsx +++ b/apps/journal/app/routes/activities._index.tsx @@ -1,7 +1,7 @@ import { data, redirect } from "react-router"; import { useTranslation } from "react-i18next"; import type { Route } from "./+types/activities._index"; -import { getSessionUser } from "~/lib/auth.server"; +import { getSessionUser } from "~/lib/auth/session.server"; import { listActivities } from "~/lib/activities.server"; import { ClientDate } from "~/components/ClientDate"; import { ClientMap } from "~/components/ClientMap"; diff --git a/apps/journal/app/routes/activities.new.tsx b/apps/journal/app/routes/activities.new.tsx index 4200010..5de4291 100644 --- a/apps/journal/app/routes/activities.new.tsx +++ b/apps/journal/app/routes/activities.new.tsx @@ -1,6 +1,6 @@ import { data, redirect } from "react-router"; import type { Route } from "./+types/activities.new"; -import { getSessionUser } from "~/lib/auth.server"; +import { getSessionUser } from "~/lib/auth/session.server"; import { createActivity } from "~/lib/activities.server"; import { listRoutes } from "~/lib/routes.server"; diff --git a/apps/journal/app/routes/api.auth.login.ts b/apps/journal/app/routes/api.auth.login.ts index 184f685..1ac014e 100644 --- a/apps/journal/app/routes/api.auth.login.ts +++ b/apps/journal/app/routes/api.auth.login.ts @@ -1,7 +1,7 @@ import { data } from "react-router"; import type { Route } from "./+types/api.auth.login"; import { startAuthentication, finishAuthentication, createMagicToken, verifyLoginCode } from "~/lib/auth.server"; -import { completeAuth } from "~/lib/auth/completion"; +import { completeAuth } from "~/lib/auth/completion.server"; import { sendMagicLink } from "~/lib/email.server"; export async function action({ request }: Route.ActionArgs) { diff --git a/apps/journal/app/routes/api.auth.register.ts b/apps/journal/app/routes/api.auth.register.ts index b9a8e31..a6421a1 100644 --- a/apps/journal/app/routes/api.auth.register.ts +++ b/apps/journal/app/routes/api.auth.register.ts @@ -1,7 +1,7 @@ import { data } from "react-router"; import type { Route } from "./+types/api.auth.register"; import { startRegistration, finishRegistration, addPasskeyStart, addPasskeyFinish, registerWithMagicLink } from "~/lib/auth.server"; -import { completeAuth } from "~/lib/auth/completion"; +import { completeAuth } from "~/lib/auth/completion.server"; import { sendWelcome, sendMagicLink } from "~/lib/email.server"; import { logger } from "~/lib/logger.server"; diff --git a/apps/journal/app/routes/api.events.ts b/apps/journal/app/routes/api.events.ts index 5c0bbce..3b89d98 100644 --- a/apps/journal/app/routes/api.events.ts +++ b/apps/journal/app/routes/api.events.ts @@ -1,5 +1,5 @@ import type { Route } from "./+types/api.events"; -import { getSessionUser } from "~/lib/auth.server"; +import { getSessionUser } from "~/lib/auth/session.server"; import { register } from "~/lib/events.server"; import { countUnread } from "~/lib/notifications.server"; diff --git a/apps/journal/app/routes/api.follows.$id.approve.ts b/apps/journal/app/routes/api.follows.$id.approve.ts index fc7db5b..cfa90ae 100644 --- a/apps/journal/app/routes/api.follows.$id.approve.ts +++ b/apps/journal/app/routes/api.follows.$id.approve.ts @@ -1,6 +1,6 @@ import { data } from "react-router"; import type { Route } from "./+types/api.follows.$id.approve"; -import { getSessionUser } from "~/lib/auth.server"; +import { getSessionUser } from "~/lib/auth/session.server"; import { approveFollowRequest } from "~/lib/follow.server"; export async function action({ request, params }: Route.ActionArgs) { diff --git a/apps/journal/app/routes/api.follows.$id.reject.ts b/apps/journal/app/routes/api.follows.$id.reject.ts index b7d20fa..6fb03e1 100644 --- a/apps/journal/app/routes/api.follows.$id.reject.ts +++ b/apps/journal/app/routes/api.follows.$id.reject.ts @@ -1,6 +1,6 @@ import { data } from "react-router"; import type { Route } from "./+types/api.follows.$id.reject"; -import { getSessionUser } from "~/lib/auth.server"; +import { getSessionUser } from "~/lib/auth/session.server"; import { rejectFollowRequest } from "~/lib/follow.server"; export async function action({ request, params }: Route.ActionArgs) { diff --git a/apps/journal/app/routes/api.notifications.$id.read.ts b/apps/journal/app/routes/api.notifications.$id.read.ts index 0e39f26..c90653c 100644 --- a/apps/journal/app/routes/api.notifications.$id.read.ts +++ b/apps/journal/app/routes/api.notifications.$id.read.ts @@ -1,6 +1,6 @@ import { data } from "react-router"; import type { Route } from "./+types/api.notifications.$id.read"; -import { getSessionUser } from "~/lib/auth.server"; +import { getSessionUser } from "~/lib/auth/session.server"; import { markRead } from "~/lib/notifications.server"; export async function action({ request, params }: Route.ActionArgs) { diff --git a/apps/journal/app/routes/api.notifications.read-all.ts b/apps/journal/app/routes/api.notifications.read-all.ts index 38b4875..150f95a 100644 --- a/apps/journal/app/routes/api.notifications.read-all.ts +++ b/apps/journal/app/routes/api.notifications.read-all.ts @@ -1,6 +1,6 @@ import { data } from "react-router"; import type { Route } from "./+types/api.notifications.read-all"; -import { getSessionUser } from "~/lib/auth.server"; +import { getSessionUser } from "~/lib/auth/session.server"; import { markAllRead } from "~/lib/notifications.server"; export async function action({ request }: Route.ActionArgs) { diff --git a/apps/journal/app/routes/api.routes.$id.edit-in-planner.ts b/apps/journal/app/routes/api.routes.$id.edit-in-planner.ts index 3fa5b1d..6f4e502 100644 --- a/apps/journal/app/routes/api.routes.$id.edit-in-planner.ts +++ b/apps/journal/app/routes/api.routes.$id.edit-in-planner.ts @@ -1,6 +1,6 @@ import { data } from "react-router"; import type { Route } from "./+types/api.routes.$id.edit-in-planner"; -import { getSessionUser } from "~/lib/auth.server"; +import { getSessionUser } from "~/lib/auth/session.server"; import { getRouteWithVersions } from "~/lib/routes.server"; import { createRouteToken } from "~/lib/jwt.server"; diff --git a/apps/journal/app/routes/api.settings.delete-account.ts b/apps/journal/app/routes/api.settings.delete-account.ts index c569de7..88e3168 100644 --- a/apps/journal/app/routes/api.settings.delete-account.ts +++ b/apps/journal/app/routes/api.settings.delete-account.ts @@ -1,7 +1,7 @@ import { redirect } from "react-router"; import { eq } from "drizzle-orm"; import type { Route } from "./+types/api.settings.delete-account"; -import { getSessionUser, destroySession } from "~/lib/auth.server"; +import { getSessionUser, destroySession } from "~/lib/auth/session.server"; import { getDb } from "~/lib/db"; import { users } from "@trails-cool/db/schema/journal"; diff --git a/apps/journal/app/routes/api.settings.email.ts b/apps/journal/app/routes/api.settings.email.ts index 8f0505f..75ee66f 100644 --- a/apps/journal/app/routes/api.settings.email.ts +++ b/apps/journal/app/routes/api.settings.email.ts @@ -1,6 +1,7 @@ import { data, redirect } from "react-router"; import type { Route } from "./+types/api.settings.email"; -import { getSessionUser, initiateEmailChange } from "~/lib/auth.server"; +import { initiateEmailChange } from "~/lib/auth.server"; +import { getSessionUser } from "~/lib/auth/session.server"; import { sendMagicLink } from "~/lib/email.server"; export async function action({ request }: Route.ActionArgs) { diff --git a/apps/journal/app/routes/api.settings.passkey.delete.ts b/apps/journal/app/routes/api.settings.passkey.delete.ts index 1aa1dda..e96dade 100644 --- a/apps/journal/app/routes/api.settings.passkey.delete.ts +++ b/apps/journal/app/routes/api.settings.passkey.delete.ts @@ -1,7 +1,7 @@ import { data, redirect } from "react-router"; import { eq, and } from "drizzle-orm"; import type { Route } from "./+types/api.settings.passkey.delete"; -import { getSessionUser } from "~/lib/auth.server"; +import { getSessionUser } from "~/lib/auth/session.server"; import { getDb } from "~/lib/db"; import { credentials } from "@trails-cool/db/schema/journal"; diff --git a/apps/journal/app/routes/api.settings.profile.ts b/apps/journal/app/routes/api.settings.profile.ts index 79abf04..adfd301 100644 --- a/apps/journal/app/routes/api.settings.profile.ts +++ b/apps/journal/app/routes/api.settings.profile.ts @@ -1,7 +1,7 @@ import { data, redirect } from "react-router"; import { eq } from "drizzle-orm"; import type { Route } from "./+types/api.settings.profile"; -import { getSessionUser } from "~/lib/auth.server"; +import { getSessionUser } from "~/lib/auth/session.server"; import { getDb } from "~/lib/db"; import { users } from "@trails-cool/db/schema/journal"; diff --git a/apps/journal/app/routes/api.sync.callback.$provider.ts b/apps/journal/app/routes/api.sync.callback.$provider.ts index df8980c..1741070 100644 --- a/apps/journal/app/routes/api.sync.callback.$provider.ts +++ b/apps/journal/app/routes/api.sync.callback.$provider.ts @@ -1,6 +1,6 @@ import { redirect, data } from "react-router"; import type { Route } from "./+types/api.sync.callback.$provider"; -import { getSessionUser } from "~/lib/auth.server"; +import { getSessionUser } from "~/lib/auth/session.server"; import { getManifest, link } from "~/lib/connected-services"; import { decodeOAuthState, diff --git a/apps/journal/app/routes/api.sync.connect.$provider.ts b/apps/journal/app/routes/api.sync.connect.$provider.ts index 3239c9f..4ead0e4 100644 --- a/apps/journal/app/routes/api.sync.connect.$provider.ts +++ b/apps/journal/app/routes/api.sync.connect.$provider.ts @@ -1,6 +1,6 @@ import { redirect, data } from "react-router"; import type { Route } from "./+types/api.sync.connect.$provider"; -import { getSessionUser } from "~/lib/auth.server"; +import { getSessionUser } from "~/lib/auth/session.server"; import { getManifest } from "~/lib/connected-services"; import { encodeOAuthState } from "~/lib/connected-services/oauth-state.server"; diff --git a/apps/journal/app/routes/api.sync.disconnect.$provider.ts b/apps/journal/app/routes/api.sync.disconnect.$provider.ts index 5c23cb5..03bcf90 100644 --- a/apps/journal/app/routes/api.sync.disconnect.$provider.ts +++ b/apps/journal/app/routes/api.sync.disconnect.$provider.ts @@ -1,6 +1,6 @@ import { redirect, data } from "react-router"; import type { Route } from "./+types/api.sync.disconnect.$provider"; -import { getSessionUser } from "~/lib/auth.server"; +import { getSessionUser } from "~/lib/auth/session.server"; import { getManifest, unlinkByUserProvider } from "~/lib/connected-services"; export async function action({ params, request }: Route.ActionArgs) { diff --git a/apps/journal/app/routes/api.sync.push.$provider.$routeId.ts b/apps/journal/app/routes/api.sync.push.$provider.$routeId.ts index 548c4a0..ac15efe 100644 --- a/apps/journal/app/routes/api.sync.push.$provider.$routeId.ts +++ b/apps/journal/app/routes/api.sync.push.$provider.$routeId.ts @@ -1,6 +1,6 @@ import { redirect, data } from "react-router"; import type { Route } from "./+types/api.sync.push.$provider.$routeId"; -import { getSessionUser } from "~/lib/auth.server"; +import { getSessionUser } from "~/lib/auth/session.server"; import { getManifest } from "~/lib/connected-services"; import { pushRouteToProvider } from "~/lib/connected-services/push-action.server"; import { encodeOAuthState } from "~/lib/connected-services/oauth-state.server"; diff --git a/apps/journal/app/routes/api.users.$username.follow.ts b/apps/journal/app/routes/api.users.$username.follow.ts index 83bff8f..c515874 100644 --- a/apps/journal/app/routes/api.users.$username.follow.ts +++ b/apps/journal/app/routes/api.users.$username.follow.ts @@ -1,6 +1,6 @@ import { data } from "react-router"; import type { Route } from "./+types/api.users.$username.follow"; -import { getSessionUser } from "~/lib/auth.server"; +import { getSessionUser } from "~/lib/auth/session.server"; import { followUser, FollowError } from "~/lib/follow.server"; export async function action({ request, params }: Route.ActionArgs) { diff --git a/apps/journal/app/routes/api.users.$username.unfollow.ts b/apps/journal/app/routes/api.users.$username.unfollow.ts index 485dc0f..036d342 100644 --- a/apps/journal/app/routes/api.users.$username.unfollow.ts +++ b/apps/journal/app/routes/api.users.$username.unfollow.ts @@ -1,6 +1,6 @@ import { data } from "react-router"; import type { Route } from "./+types/api.users.$username.unfollow"; -import { getSessionUser } from "~/lib/auth.server"; +import { getSessionUser } from "~/lib/auth/session.server"; import { unfollowUser, FollowError } from "~/lib/follow.server"; export async function action({ request, params }: Route.ActionArgs) { diff --git a/apps/journal/app/routes/auth.accept-terms.tsx b/apps/journal/app/routes/auth.accept-terms.tsx index 111b186..81da750 100644 --- a/apps/journal/app/routes/auth.accept-terms.tsx +++ b/apps/journal/app/routes/auth.accept-terms.tsx @@ -2,7 +2,8 @@ import { useState } from "react"; import { Form, data, redirect, useLoaderData, useSearchParams } from "react-router"; import { useTranslation } from "react-i18next"; import type { Route } from "./+types/auth.accept-terms"; -import { getSessionUser, recordTermsAcceptance } from "~/lib/auth.server"; +import { recordTermsAcceptance } from "~/lib/auth.server"; +import { getSessionUser } from "~/lib/auth/session.server"; import { TERMS_VERSION } from "~/lib/legal"; export function meta() { diff --git a/apps/journal/app/routes/auth.logout.tsx b/apps/journal/app/routes/auth.logout.tsx index 44e9cf2..37f9c03 100644 --- a/apps/journal/app/routes/auth.logout.tsx +++ b/apps/journal/app/routes/auth.logout.tsx @@ -1,6 +1,6 @@ import { redirect } from "react-router"; import type { Route } from "./+types/auth.logout"; -import { destroySession } from "~/lib/auth.server"; +import { destroySession } from "~/lib/auth/session.server"; export async function action({ request }: Route.ActionArgs) { const cookie = await destroySession(request); diff --git a/apps/journal/app/routes/auth.verify.tsx b/apps/journal/app/routes/auth.verify.tsx index d6c2965..12fc00b 100644 --- a/apps/journal/app/routes/auth.verify.tsx +++ b/apps/journal/app/routes/auth.verify.tsx @@ -1,7 +1,8 @@ import { redirect, data } from "react-router"; import type { Route } from "./+types/auth.verify"; -import { verifyMagicToken, verifyEmailChange, getSessionUser } from "~/lib/auth.server"; -import { completeAuth } from "~/lib/auth/completion"; +import { verifyMagicToken, verifyEmailChange } from "~/lib/auth.server"; +import { getSessionUser } from "~/lib/auth/session.server"; +import { completeAuth } from "~/lib/auth/completion.server"; export async function loader({ request }: Route.LoaderArgs) { const url = new URL(request.url); diff --git a/apps/journal/app/routes/explore.tsx b/apps/journal/app/routes/explore.tsx index 1479acb..6386a80 100644 --- a/apps/journal/app/routes/explore.tsx +++ b/apps/journal/app/routes/explore.tsx @@ -2,7 +2,7 @@ import { data } from "react-router"; import { Link } from "react-router"; import { useTranslation } from "react-i18next"; import type { Route } from "./+types/explore"; -import { getSessionUser } from "~/lib/auth.server"; +import { getSessionUser } from "~/lib/auth/session.server"; import { EXPLORE_DEFAULT_PAGE_SIZE, countFollowersBatch, diff --git a/apps/journal/app/routes/feed.tsx b/apps/journal/app/routes/feed.tsx index 755ac3b..4590144 100644 --- a/apps/journal/app/routes/feed.tsx +++ b/apps/journal/app/routes/feed.tsx @@ -2,7 +2,7 @@ import { data, redirect } from "react-router"; import { Link } from "react-router"; import { useTranslation } from "react-i18next"; import type { Route } from "./+types/feed"; -import { getSessionUser } from "~/lib/auth.server"; +import { getSessionUser } from "~/lib/auth/session.server"; import { listSocialFeed, listRecentPublicActivities } from "~/lib/activities.server"; import { ClientDate } from "~/components/ClientDate"; import { ClientMap } from "~/components/ClientMap"; diff --git a/apps/journal/app/routes/home.tsx b/apps/journal/app/routes/home.tsx index 071f681..981c2ac 100644 --- a/apps/journal/app/routes/home.tsx +++ b/apps/journal/app/routes/home.tsx @@ -3,7 +3,7 @@ import { data } from "react-router"; import { useTranslation } from "react-i18next"; import { eq, count } from "drizzle-orm"; import type { Route } from "./+types/home"; -import { getSessionUser } from "~/lib/auth.server"; +import { getSessionUser } from "~/lib/auth/session.server"; import { getDb } from "~/lib/db"; import { credentials } from "@trails-cool/db/schema/journal"; import { listActivities, listRecentPublicActivities } from "~/lib/activities.server"; diff --git a/apps/journal/app/routes/notifications.tsx b/apps/journal/app/routes/notifications.tsx index 5306d16..dda955a 100644 --- a/apps/journal/app/routes/notifications.tsx +++ b/apps/journal/app/routes/notifications.tsx @@ -4,7 +4,7 @@ import { useTranslation } from "react-i18next"; import { inArray, eq, and } from "drizzle-orm"; import type { Route } from "./+types/notifications"; import { getDb } from "~/lib/db"; -import { getSessionUser } from "~/lib/auth.server"; +import { getSessionUser } from "~/lib/auth/session.server"; import { listForUser } from "~/lib/notifications.server"; import { linkFor } from "~/lib/notifications/link-for"; import { readPayload } from "~/lib/notifications/payload"; diff --git a/apps/journal/app/routes/oauth.authorize.tsx b/apps/journal/app/routes/oauth.authorize.tsx index 91342d9..fa918f0 100644 --- a/apps/journal/app/routes/oauth.authorize.tsx +++ b/apps/journal/app/routes/oauth.authorize.tsx @@ -1,6 +1,6 @@ import type { Route } from "./+types/oauth.authorize"; import { redirect } from "react-router"; -import { getSessionUser } from "../lib/auth.server.ts"; +import { getSessionUser } from "../lib/auth/session.server.ts"; import { getOAuthClient, validateRedirectUri, diff --git a/apps/journal/app/routes/routes.$id.edit.tsx b/apps/journal/app/routes/routes.$id.edit.tsx index e1fe2e9..59497fb 100644 --- a/apps/journal/app/routes/routes.$id.edit.tsx +++ b/apps/journal/app/routes/routes.$id.edit.tsx @@ -1,7 +1,7 @@ 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 { getSessionUser } from "~/lib/auth/session.server"; import { getRoute, updateRoute } from "~/lib/routes.server"; import type { Visibility } from "@trails-cool/db/schema/journal"; diff --git a/apps/journal/app/routes/routes.$id.tsx b/apps/journal/app/routes/routes.$id.tsx index 3313a1b..a85c066 100644 --- a/apps/journal/app/routes/routes.$id.tsx +++ b/apps/journal/app/routes/routes.$id.tsx @@ -3,7 +3,8 @@ import { data, redirect } from "react-router"; import { useTranslation } from "react-i18next"; import type { Route } from "./+types/routes.$id"; import { and, eq } from "drizzle-orm"; -import { canView, getSessionUser } from "~/lib/auth.server"; +import { canView } from "~/lib/auth.server"; +import { getSessionUser } from "~/lib/auth/session.server"; import { getRoute, getRouteWithVersions, deleteRoute, updateRoute } from "~/lib/routes.server"; import { getDb } from "~/lib/db"; import { syncPushes } from "@trails-cool/db/schema/journal"; diff --git a/apps/journal/app/routes/routes._index.tsx b/apps/journal/app/routes/routes._index.tsx index 85511a6..a4fed7a 100644 --- a/apps/journal/app/routes/routes._index.tsx +++ b/apps/journal/app/routes/routes._index.tsx @@ -1,7 +1,7 @@ import { data, redirect } from "react-router"; import { useTranslation } from "react-i18next"; import type { Route } from "./+types/routes._index"; -import { getSessionUser } from "~/lib/auth.server"; +import { getSessionUser } from "~/lib/auth/session.server"; import { listRoutes } from "~/lib/routes.server"; import { ClientDate } from "~/components/ClientDate"; import { ClientMap } from "~/components/ClientMap"; diff --git a/apps/journal/app/routes/routes.new.tsx b/apps/journal/app/routes/routes.new.tsx index 7a939bd..caf02b2 100644 --- a/apps/journal/app/routes/routes.new.tsx +++ b/apps/journal/app/routes/routes.new.tsx @@ -1,7 +1,7 @@ import { data, redirect } from "react-router"; import type { Route } from "./+types/routes.new"; -import { getSessionUser } from "~/lib/auth.server"; +import { getSessionUser } from "~/lib/auth/session.server"; import { createRoute } from "~/lib/routes.server"; export async function loader({ request }: Route.LoaderArgs) { diff --git a/apps/journal/app/routes/settings.account.tsx b/apps/journal/app/routes/settings.account.tsx index 17aa3ca..0dc41c1 100644 --- a/apps/journal/app/routes/settings.account.tsx +++ b/apps/journal/app/routes/settings.account.tsx @@ -2,7 +2,7 @@ import { useState, useEffect } from "react"; import { data, redirect, useFetcher } from "react-router"; import { useTranslation } from "react-i18next"; import type { Route } from "./+types/settings.account"; -import { getSessionUser } from "~/lib/auth.server"; +import { getSessionUser } from "~/lib/auth/session.server"; export function meta() { return [{ title: "Account — Settings — trails.cool" }]; diff --git a/apps/journal/app/routes/settings.connections.tsx b/apps/journal/app/routes/settings.connections.tsx index 583d45b..b0d905e 100644 --- a/apps/journal/app/routes/settings.connections.tsx +++ b/apps/journal/app/routes/settings.connections.tsx @@ -2,7 +2,7 @@ import { data, redirect, useSearchParams } from "react-router"; import { useTranslation } from "react-i18next"; import { eq } from "drizzle-orm"; import type { Route } from "./+types/settings.connections"; -import { getSessionUser } from "~/lib/auth.server"; +import { getSessionUser } from "~/lib/auth/session.server"; import { getDb } from "~/lib/db"; import { connectedServices } from "@trails-cool/db/schema/journal"; import { getAllManifests } from "~/lib/connected-services"; diff --git a/apps/journal/app/routes/settings.profile.tsx b/apps/journal/app/routes/settings.profile.tsx index 2c9956b..8f8ad5c 100644 --- a/apps/journal/app/routes/settings.profile.tsx +++ b/apps/journal/app/routes/settings.profile.tsx @@ -2,7 +2,7 @@ import { useState, useEffect } from "react"; import { data, redirect, useFetcher } from "react-router"; import { useTranslation } from "react-i18next"; import type { Route } from "./+types/settings.profile"; -import { getSessionUser } from "~/lib/auth.server"; +import { getSessionUser } from "~/lib/auth/session.server"; export function meta() { return [{ title: "Profile — Settings — trails.cool" }]; diff --git a/apps/journal/app/routes/settings.security.tsx b/apps/journal/app/routes/settings.security.tsx index d499120..0062ca4 100644 --- a/apps/journal/app/routes/settings.security.tsx +++ b/apps/journal/app/routes/settings.security.tsx @@ -3,7 +3,7 @@ import { data, redirect, useFetcher } from "react-router"; import { useTranslation } from "react-i18next"; import { eq } from "drizzle-orm"; import type { Route } from "./+types/settings.security"; -import { getSessionUser } from "~/lib/auth.server"; +import { getSessionUser } from "~/lib/auth/session.server"; import { getDb } from "~/lib/db"; import { credentials } from "@trails-cool/db/schema/journal"; import { ClientDate } from "~/components/ClientDate"; diff --git a/apps/journal/app/routes/settings.tsx b/apps/journal/app/routes/settings.tsx index 1df5d11..a85c0e4 100644 --- a/apps/journal/app/routes/settings.tsx +++ b/apps/journal/app/routes/settings.tsx @@ -2,7 +2,7 @@ import { Outlet, redirect } from "react-router"; import { Link, useLocation } from "react-router"; import { useTranslation } from "react-i18next"; import type { Route } from "./+types/settings"; -import { getSessionUser } from "~/lib/auth.server"; +import { getSessionUser } from "~/lib/auth/session.server"; export function meta() { return [{ title: "Settings — trails.cool" }]; diff --git a/apps/journal/app/routes/sync.import.$provider.tsx b/apps/journal/app/routes/sync.import.$provider.tsx index c401ac0..e90b811 100644 --- a/apps/journal/app/routes/sync.import.$provider.tsx +++ b/apps/journal/app/routes/sync.import.$provider.tsx @@ -2,7 +2,7 @@ import { useCallback, useEffect, useRef, useState } from "react"; import { data, redirect, useFetcher } from "react-router"; import { useTranslation } from "react-i18next"; import type { Route } from "./+types/sync.import.$provider"; -import { getSessionUser } from "~/lib/auth.server"; +import { getSessionUser } from "~/lib/auth/session.server"; import { getManifest, getService, diff --git a/apps/journal/app/routes/users.$username.followers.tsx b/apps/journal/app/routes/users.$username.followers.tsx index df2ab30..9b22fcd 100644 --- a/apps/journal/app/routes/users.$username.followers.tsx +++ b/apps/journal/app/routes/users.$username.followers.tsx @@ -4,7 +4,7 @@ import type { Route } from "./+types/users.$username.followers"; import { getDb } from "~/lib/db"; import { users } from "@trails-cool/db/schema/journal"; import { listFollowers, countFollowers, getFollowState } from "~/lib/follow.server"; -import { getSessionUser } from "~/lib/auth.server"; +import { getSessionUser } from "~/lib/auth/session.server"; import { CollectionPage } from "~/components/CollectionPage"; export async function loader({ params, request }: Route.LoaderArgs) { diff --git a/apps/journal/app/routes/users.$username.following.tsx b/apps/journal/app/routes/users.$username.following.tsx index 680083b..1c8237f 100644 --- a/apps/journal/app/routes/users.$username.following.tsx +++ b/apps/journal/app/routes/users.$username.following.tsx @@ -4,7 +4,7 @@ import type { Route } from "./+types/users.$username.following"; import { getDb } from "~/lib/db"; import { users } from "@trails-cool/db/schema/journal"; import { listFollowing, countFollowing, getFollowState } from "~/lib/follow.server"; -import { getSessionUser } from "~/lib/auth.server"; +import { getSessionUser } from "~/lib/auth/session.server"; import { CollectionPage } from "~/components/CollectionPage"; export async function loader({ params, request }: Route.LoaderArgs) { diff --git a/apps/journal/app/routes/users.$username.tsx b/apps/journal/app/routes/users.$username.tsx index 5163971..83b566c 100644 --- a/apps/journal/app/routes/users.$username.tsx +++ b/apps/journal/app/routes/users.$username.tsx @@ -4,7 +4,7 @@ import { useTranslation } from "react-i18next"; import { getDb } from "~/lib/db"; import { users } from "@trails-cool/db/schema/journal"; import { eq } from "drizzle-orm"; -import { getSessionUser } from "~/lib/auth.server"; +import { getSessionUser } from "~/lib/auth/session.server"; import { listPublicRoutesForOwner } from "~/lib/routes.server"; import { listPublicActivitiesForOwner } from "~/lib/activities.server"; import { loadPersona } from "~/lib/demo-bot.server"; diff --git a/openspec/changes/unify-auth-completion/tasks.md b/openspec/changes/unify-auth-completion/tasks.md index 7281465..0bdceff 100644 --- a/openspec/changes/unify-auth-completion/tasks.md +++ b/openspec/changes/unify-auth-completion/tasks.md @@ -27,4 +27,4 @@ ## 5. Documentation + follow-up - [ ] 5.1 At archive time, apply the spec delta in `specs/authentication-methods/` to `openspec/specs/`. -- [ ] 5.2 (Optional follow-up — not part of this change) update import paths app-wide from `auth.server.ts` to `./auth/session.ts` and drop the re-exports. Track separately. +- [x] 5.2 Update import paths app-wide from `auth.server.ts` to `./auth/session.ts` and drop the re-exports. (Folded into this PR after the smoke test confirmed everything works.) From e268aeec10acb2fb6343edd7042701aab9b6634f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Fri, 8 May 2026 03:02:51 +0200 Subject: [PATCH 005/319] Archive unify-auth-completion + sync spec delta (task 5.1) Applies the ADDED requirement from openspec/changes/unify-auth-completion/specs/authentication-methods/ into openspec/specs/authentication-methods/spec.md: - Single web auth completion chokepoint (completeAuth at apps/journal/app/lib/auth/completion.server.ts) with five scenarios covering passkey register/login finish, magic-link verify-code, magic-link click-through, and returnTo sanitization. Path in the synced requirement is .server.ts (the post-rename name), not the .ts the delta originally captured. Change moved to openspec/changes/archive/2026-05-08-unify-auth-completion/. 15/15 tasks complete. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../.openspec.yaml | 0 .../design.md | 0 .../proposal.md | 0 .../specs/authentication-methods/spec.md | 0 .../tasks.md | 2 +- openspec/specs/authentication-methods/spec.md | 32 +++++++++++++++++++ 6 files changed, 33 insertions(+), 1 deletion(-) rename openspec/changes/{unify-auth-completion => archive/2026-05-08-unify-auth-completion}/.openspec.yaml (100%) rename openspec/changes/{unify-auth-completion => archive/2026-05-08-unify-auth-completion}/design.md (100%) rename openspec/changes/{unify-auth-completion => archive/2026-05-08-unify-auth-completion}/proposal.md (100%) rename openspec/changes/{unify-auth-completion => archive/2026-05-08-unify-auth-completion}/specs/authentication-methods/spec.md (100%) rename openspec/changes/{unify-auth-completion => archive/2026-05-08-unify-auth-completion}/tasks.md (97%) diff --git a/openspec/changes/unify-auth-completion/.openspec.yaml b/openspec/changes/archive/2026-05-08-unify-auth-completion/.openspec.yaml similarity index 100% rename from openspec/changes/unify-auth-completion/.openspec.yaml rename to openspec/changes/archive/2026-05-08-unify-auth-completion/.openspec.yaml diff --git a/openspec/changes/unify-auth-completion/design.md b/openspec/changes/archive/2026-05-08-unify-auth-completion/design.md similarity index 100% rename from openspec/changes/unify-auth-completion/design.md rename to openspec/changes/archive/2026-05-08-unify-auth-completion/design.md diff --git a/openspec/changes/unify-auth-completion/proposal.md b/openspec/changes/archive/2026-05-08-unify-auth-completion/proposal.md similarity index 100% rename from openspec/changes/unify-auth-completion/proposal.md rename to openspec/changes/archive/2026-05-08-unify-auth-completion/proposal.md diff --git a/openspec/changes/unify-auth-completion/specs/authentication-methods/spec.md b/openspec/changes/archive/2026-05-08-unify-auth-completion/specs/authentication-methods/spec.md similarity index 100% rename from openspec/changes/unify-auth-completion/specs/authentication-methods/spec.md rename to openspec/changes/archive/2026-05-08-unify-auth-completion/specs/authentication-methods/spec.md diff --git a/openspec/changes/unify-auth-completion/tasks.md b/openspec/changes/archive/2026-05-08-unify-auth-completion/tasks.md similarity index 97% rename from openspec/changes/unify-auth-completion/tasks.md rename to openspec/changes/archive/2026-05-08-unify-auth-completion/tasks.md index 0bdceff..e2dfba7 100644 --- a/openspec/changes/unify-auth-completion/tasks.md +++ b/openspec/changes/archive/2026-05-08-unify-auth-completion/tasks.md @@ -26,5 +26,5 @@ ## 5. Documentation + follow-up -- [ ] 5.1 At archive time, apply the spec delta in `specs/authentication-methods/` to `openspec/specs/`. +- [x] 5.1 At archive time, apply the spec delta in `specs/authentication-methods/` to `openspec/specs/`. - [x] 5.2 Update import paths app-wide from `auth.server.ts` to `./auth/session.ts` and drop the re-exports. (Folded into this PR after the smoke test confirmed everything works.) diff --git a/openspec/specs/authentication-methods/spec.md b/openspec/specs/authentication-methods/spec.md index 64e8995..9fb5c5b 100644 --- a/openspec/specs/authentication-methods/spec.md +++ b/openspec/specs/authentication-methods/spec.md @@ -93,3 +93,35 @@ A signed-in user SHALL be able to remove a passkey from their account via the Se #### Scenario: Last-passkey safety net (verified email is the fallback) - **WHEN** a user attempts to delete their only remaining passkey - **THEN** the action proceeds because magic-link login by email is always available — passkey deletion does not lock the user out + +### Requirement: Single web auth completion chokepoint +Every successful web authentication flow — passkey register-finish, passkey login-finish, magic-link 6-digit-code verify, magic-link click-through verify — SHALL complete by calling a single `completeAuth` function at `apps/journal/app/lib/auth/completion.server.ts`. The function SHALL be the sole place where a successful web authentication mints the cookie session and constructs the redirect to `returnTo` (or `/` when absent or rejected). + +Per-method identity verification (WebAuthn ceremony, magic-token consumption, 6-digit-code consumption) SHALL run in its own function and produce a `userId` *before* `completeAuth` is invoked. `completeAuth` SHALL NOT know how identity was proved. + +Terms recording happens at user creation time inside the per-method registration functions (`finishRegistration` for passkey, `registerWithMagicLink` for magic-link), not inside `completeAuth`. The Terms gate (root-loader redirect for cookie sessions; `requireApiUser` 403 for bearer-token API requests) SHALL remain the enforcement point for stale `terms_version`. + +OAuth-code issuance at `/oauth/authorize` SHALL NOT be routed through `completeAuth` — that flow operates on an already-authenticated user and shares only the trailing redirect, not the full sequence. + +#### Scenario: Passkey register-finish completes through the chokepoint +- **WHEN** a visitor submits a successful WebAuthn `step: "finish"` registration response +- **THEN** the route handler verifies the credential and creates the user row (with terms recorded) inside `finishRegistration`, then calls `completeAuth({ userId, request, returnTo })` +- **AND** `completeAuth` mints the session cookie and returns a `Response` redirecting to `returnTo` (or `/`) + +#### Scenario: Passkey login-finish completes through the chokepoint +- **WHEN** a visitor submits a successful WebAuthn `step: "finish-passkey"` login response +- **THEN** the route handler verifies the credential and calls `completeAuth({ userId, request, returnTo })` +- **AND** `completeAuth` mints the session cookie and returns a `Response` redirecting to `returnTo` (or `/`) + +#### Scenario: Magic-link 6-digit-code verify completes through the chokepoint +- **WHEN** a visitor submits a valid 6-digit code via `step: "verify-code"` +- **THEN** the route handler consumes the magic token (marks `used_at`) and calls `completeAuth({ userId, request, returnTo })` + +#### Scenario: Magic-link click-through verify completes through the chokepoint +- **WHEN** a visitor opens `/auth/verify?token=` with a valid, unused, unexpired token +- **THEN** the route handler consumes the magic token and calls `completeAuth({ userId, request, returnTo })` + +#### Scenario: returnTo is sanitized inside completeAuth +- **WHEN** `completeAuth` is called with a `returnTo` value that is not a same-origin absolute path (e.g. starts with `//`, an absolute URL, or is malformed) +- **THEN** the redirect target falls back to `/` rather than honoring the unsafe value +- **AND** every caller benefits from the same check rather than reimplementing it From 9cc08a725a578b1f0f6bd929c08dd05a39984509 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 10 May 2026 08:42:40 +0000 Subject: [PATCH 006/319] Bump the production group with 41 updates Bumps the production group with 41 updates: | Package | From | To | | --- | --- | --- | | [expo](https://github.com/expo/expo/tree/HEAD/packages/expo) | `55.0.19` | `55.0.23` | | [react](https://github.com/facebook/react/tree/HEAD/packages/react) | `19.2.5` | `19.2.0` | | [@expo/fingerprint](https://github.com/expo/expo/tree/HEAD/packages/@expo/fingerprint) | `0.16.6` | `0.16.7` | | [i18next](https://github.com/i18next/i18next) | `26.0.8` | `26.0.10` | | [react-i18next](https://github.com/i18next/react-i18next) | `17.0.6` | `17.0.7` | | [turbo](https://github.com/vercel/turborepo) | `2.9.8` | `2.9.12` | | [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint) | `8.59.1` | `8.59.2` | | [isbot](https://github.com/omrilotan/isbot) | `5.1.39` | `5.1.40` | | [zod](https://github.com/colinhacks/zod) | `4.4.2` | `4.4.3` | | [@expo/metro-runtime](https://github.com/expo/expo) | `55.0.10` | `55.0.11` | | [@gorhom/bottom-sheet](https://github.com/gorhom/react-native-bottom-sheet) | `5.2.13` | `5.2.14` | | [@maplibre/maplibre-react-native](https://github.com/maplibre/maplibre-react-native) | `11.0.2` | `11.1.1` | | [@sentry/react-native](https://github.com/getsentry/sentry-react-native) | `8.10.0` | `8.11.0` | | [expo-constants](https://github.com/expo/expo/tree/HEAD/packages/expo-constants) | `55.0.15` | `55.0.16` | | [expo-dev-client](https://github.com/expo/expo/tree/HEAD/packages/expo-dev-client) | `55.0.30` | `55.0.32` | | [expo-dev-menu](https://github.com/expo/expo/tree/HEAD/packages/expo-dev-menu) | `55.0.26` | `55.0.27` | | [expo-device](https://github.com/expo/expo/tree/HEAD/packages/expo-device) | `55.0.15` | `55.0.16` | | [expo-file-system](https://github.com/expo/expo/tree/HEAD/packages/expo-file-system) | `55.0.17` | `55.0.19` | | [expo-linking](https://github.com/expo/expo/tree/HEAD/packages/expo-linking) | `55.0.14` | `55.0.15` | | [expo-location](https://github.com/expo/expo/tree/HEAD/packages/expo-location) | `55.1.8` | `55.1.9` | | [expo-router](https://github.com/expo/expo/tree/HEAD/packages/expo-router) | `55.0.13` | `55.0.14` | | [expo-splash-screen](https://github.com/expo/expo/tree/HEAD/packages/expo-splash-screen) | `55.0.19` | `55.0.20` | | [expo-status-bar](https://github.com/expo/expo/tree/HEAD/packages/expo-status-bar) | `55.0.5` | `55.0.6` | | [expo-system-ui](https://github.com/expo/expo/tree/HEAD/packages/expo-system-ui) | `55.0.16` | `55.0.17` | | [expo-web-browser](https://github.com/expo/expo/tree/HEAD/packages/expo-web-browser) | `55.0.14` | `55.0.15` | | [react-native-gesture-handler](https://github.com/software-mansion/react-native-gesture-handler) | `2.31.1` | `2.31.2` | | [react-native-reanimated](https://github.com/software-mansion/react-native-reanimated/tree/HEAD/packages/react-native-reanimated) | `4.3.0` | `4.3.1` | | [jest-expo](https://github.com/expo/expo/tree/HEAD/packages/jest-expo) | `55.0.16` | `55.0.17` | | [react-test-renderer](https://github.com/facebook/react/tree/HEAD/packages/react-test-renderer) | `19.2.5` | `19.2.6` | | [@codemirror/view](https://github.com/codemirror/view) | `6.41.1` | `6.42.1` | | [@react-router/dev](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dev) | `7.14.2` | `7.15.0` | | [@react-router/node](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-node) | `7.14.2` | `7.15.0` | | [@react-router/serve](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-serve) | `7.14.2` | `7.15.0` | | [@sentry/node](https://github.com/getsentry/sentry-javascript) | `10.51.0` | `10.52.0` | | [@sentry/react](https://github.com/getsentry/sentry-javascript) | `10.51.0` | `10.52.0` | | [@tailwindcss/vite](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/@tailwindcss-vite) | `4.2.4` | `4.3.0` | | [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) | `22.19.17` | `22.19.18` | | [react-dom](https://github.com/facebook/react/tree/HEAD/packages/react-dom) | `19.2.5` | `19.2.6` | | [react-router](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router) | `7.14.2` | `7.15.0` | | [tailwindcss](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss) | `4.2.4` | `4.3.0` | | [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) | `7.3.2` | `7.3.3` | Updates `expo` from 55.0.19 to 55.0.23 - [Changelog](https://github.com/expo/expo/blob/main/packages/expo/CHANGELOG.md) - [Commits](https://github.com/expo/expo/commits/HEAD/packages/expo) Updates `react` from 19.2.5 to 19.2.0 - [Release notes](https://github.com/facebook/react/releases) - [Changelog](https://github.com/facebook/react/blob/main/CHANGELOG.md) - [Commits](https://github.com/facebook/react/commits/v19.2.0/packages/react) Updates `@expo/fingerprint` from 0.16.6 to 0.16.7 - [Changelog](https://github.com/expo/expo/blob/main/packages/@expo/fingerprint/CHANGELOG.md) - [Commits](https://github.com/expo/expo/commits/HEAD/packages/@expo/fingerprint) Updates `i18next` from 26.0.8 to 26.0.10 - [Release notes](https://github.com/i18next/i18next/releases) - [Changelog](https://github.com/i18next/i18next/blob/master/CHANGELOG.md) - [Commits](https://github.com/i18next/i18next/compare/v26.0.8...v26.0.10) Updates `react-i18next` from 17.0.6 to 17.0.7 - [Changelog](https://github.com/i18next/react-i18next/blob/master/CHANGELOG.md) - [Commits](https://github.com/i18next/react-i18next/compare/v17.0.6...v17.0.7) Updates `turbo` from 2.9.8 to 2.9.12 - [Release notes](https://github.com/vercel/turborepo/releases) - [Changelog](https://github.com/vercel/turborepo/blob/main/RELEASE.md) - [Commits](https://github.com/vercel/turborepo/compare/v2.9.8...v2.9.12) Updates `typescript-eslint` from 8.59.1 to 8.59.2 - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.59.2/packages/typescript-eslint) Updates `isbot` from 5.1.39 to 5.1.40 - [Changelog](https://github.com/omrilotan/isbot/blob/main/CHANGELOG.md) - [Commits](https://github.com/omrilotan/isbot/compare/v5.1.39...v5.1.40) Updates `zod` from 4.4.2 to 4.4.3 - [Release notes](https://github.com/colinhacks/zod/releases) - [Commits](https://github.com/colinhacks/zod/compare/v4.4.2...v4.4.3) Updates `@expo/metro-runtime` from 55.0.10 to 55.0.11 - [Changelog](https://github.com/expo/expo/blob/main/CHANGELOG.md) - [Commits](https://github.com/expo/expo/commits) Updates `@gorhom/bottom-sheet` from 5.2.13 to 5.2.14 - [Release notes](https://github.com/gorhom/react-native-bottom-sheet/releases) - [Changelog](https://github.com/gorhom/react-native-bottom-sheet/blob/master/CHANGELOG.md) - [Commits](https://github.com/gorhom/react-native-bottom-sheet/compare/v5.2.13...v5.2.14) Updates `@maplibre/maplibre-react-native` from 11.0.2 to 11.1.1 - [Release notes](https://github.com/maplibre/maplibre-react-native/releases) - [Changelog](https://github.com/maplibre/maplibre-react-native/blob/main/CHANGELOG.md) - [Commits](https://github.com/maplibre/maplibre-react-native/compare/v11.0.2...v11.1.1) Updates `@sentry/react-native` from 8.10.0 to 8.11.0 - [Release notes](https://github.com/getsentry/sentry-react-native/releases) - [Changelog](https://github.com/getsentry/sentry-react-native/blob/main/CHANGELOG.md) - [Commits](https://github.com/getsentry/sentry-react-native/compare/8.10.0...8.11.0) Updates `expo-constants` from 55.0.15 to 55.0.16 - [Changelog](https://github.com/expo/expo/blob/main/packages/expo-constants/CHANGELOG.md) - [Commits](https://github.com/expo/expo/commits/HEAD/packages/expo-constants) Updates `expo-dev-client` from 55.0.30 to 55.0.32 - [Changelog](https://github.com/expo/expo/blob/main/packages/expo-dev-client/CHANGELOG.md) - [Commits](https://github.com/expo/expo/commits/HEAD/packages/expo-dev-client) Updates `expo-dev-menu` from 55.0.26 to 55.0.27 - [Changelog](https://github.com/expo/expo/blob/main/packages/expo-dev-menu/CHANGELOG.md) - [Commits](https://github.com/expo/expo/commits/HEAD/packages/expo-dev-menu) Updates `expo-device` from 55.0.15 to 55.0.16 - [Changelog](https://github.com/expo/expo/blob/main/packages/expo-device/CHANGELOG.md) - [Commits](https://github.com/expo/expo/commits/HEAD/packages/expo-device) Updates `expo-file-system` from 55.0.17 to 55.0.19 - [Changelog](https://github.com/expo/expo/blob/main/packages/expo-file-system/CHANGELOG.md) - [Commits](https://github.com/expo/expo/commits/HEAD/packages/expo-file-system) Updates `expo-linking` from 55.0.14 to 55.0.15 - [Changelog](https://github.com/expo/expo/blob/main/packages/expo-linking/CHANGELOG.md) - [Commits](https://github.com/expo/expo/commits/HEAD/packages/expo-linking) Updates `expo-location` from 55.1.8 to 55.1.9 - [Changelog](https://github.com/expo/expo/blob/main/packages/expo-location/CHANGELOG.md) - [Commits](https://github.com/expo/expo/commits/HEAD/packages/expo-location) Updates `expo-router` from 55.0.13 to 55.0.14 - [Changelog](https://github.com/expo/expo/blob/main/packages/expo-router/CHANGELOG.md) - [Commits](https://github.com/expo/expo/commits/HEAD/packages/expo-router) Updates `expo-splash-screen` from 55.0.19 to 55.0.20 - [Changelog](https://github.com/expo/expo/blob/main/packages/expo-splash-screen/CHANGELOG.md) - [Commits](https://github.com/expo/expo/commits/HEAD/packages/expo-splash-screen) Updates `expo-status-bar` from 55.0.5 to 55.0.6 - [Changelog](https://github.com/expo/expo/blob/main/packages/expo-status-bar/CHANGELOG.md) - [Commits](https://github.com/expo/expo/commits/HEAD/packages/expo-status-bar) Updates `expo-system-ui` from 55.0.16 to 55.0.17 - [Changelog](https://github.com/expo/expo/blob/main/packages/expo-system-ui/CHANGELOG.md) - [Commits](https://github.com/expo/expo/commits/HEAD/packages/expo-system-ui) Updates `expo-web-browser` from 55.0.14 to 55.0.15 - [Changelog](https://github.com/expo/expo/blob/main/packages/expo-web-browser/CHANGELOG.md) - [Commits](https://github.com/expo/expo/commits/HEAD/packages/expo-web-browser) Updates `react-native-gesture-handler` from 2.31.1 to 2.31.2 - [Release notes](https://github.com/software-mansion/react-native-gesture-handler/releases) - [Commits](https://github.com/software-mansion/react-native-gesture-handler/compare/v2.31.1...v2.31.2) Updates `react-native-reanimated` from 4.3.0 to 4.3.1 - [Release notes](https://github.com/software-mansion/react-native-reanimated/releases) - [Changelog](https://github.com/software-mansion/react-native-reanimated/blob/main/packages/react-native-reanimated/RELEASE.md) - [Commits](https://github.com/software-mansion/react-native-reanimated/commits/4.3.1/packages/react-native-reanimated) Updates `jest-expo` from 55.0.16 to 55.0.17 - [Changelog](https://github.com/expo/expo/blob/main/packages/jest-expo/CHANGELOG.md) - [Commits](https://github.com/expo/expo/commits/HEAD/packages/jest-expo) Updates `react-test-renderer` from 19.2.5 to 19.2.6 - [Release notes](https://github.com/facebook/react/releases) - [Changelog](https://github.com/facebook/react/blob/main/CHANGELOG.md) - [Commits](https://github.com/facebook/react/commits/v19.2.6/packages/react-test-renderer) Updates `@codemirror/view` from 6.41.1 to 6.42.1 - [Changelog](https://github.com/codemirror/view/blob/main/CHANGELOG.md) - [Commits](https://github.com/codemirror/view/commits) Updates `@react-router/dev` from 7.14.2 to 7.15.0 - [Release notes](https://github.com/remix-run/react-router/releases) - [Changelog](https://github.com/remix-run/react-router/blob/main/packages/react-router-dev/CHANGELOG.md) - [Commits](https://github.com/remix-run/react-router/commits/@react-router/dev@7.15.0/packages/react-router-dev) Updates `@react-router/node` from 7.14.2 to 7.15.0 - [Release notes](https://github.com/remix-run/react-router/releases) - [Changelog](https://github.com/remix-run/react-router/blob/main/packages/react-router-node/CHANGELOG.md) - [Commits](https://github.com/remix-run/react-router/commits/@react-router/node@7.15.0/packages/react-router-node) Updates `@react-router/serve` from 7.14.2 to 7.15.0 - [Release notes](https://github.com/remix-run/react-router/releases) - [Changelog](https://github.com/remix-run/react-router/blob/main/packages/react-router-serve/CHANGELOG.md) - [Commits](https://github.com/remix-run/react-router/commits/@react-router/serve@7.15.0/packages/react-router-serve) Updates `@sentry/node` from 10.51.0 to 10.52.0 - [Release notes](https://github.com/getsentry/sentry-javascript/releases) - [Changelog](https://github.com/getsentry/sentry-javascript/blob/develop/CHANGELOG.md) - [Commits](https://github.com/getsentry/sentry-javascript/compare/10.51.0...10.52.0) Updates `@sentry/react` from 10.51.0 to 10.52.0 - [Release notes](https://github.com/getsentry/sentry-javascript/releases) - [Changelog](https://github.com/getsentry/sentry-javascript/blob/develop/CHANGELOG.md) - [Commits](https://github.com/getsentry/sentry-javascript/compare/10.51.0...10.52.0) Updates `@tailwindcss/vite` from 4.2.4 to 4.3.0 - [Release notes](https://github.com/tailwindlabs/tailwindcss/releases) - [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md) - [Commits](https://github.com/tailwindlabs/tailwindcss/commits/v4.3.0/packages/@tailwindcss-vite) Updates `@types/node` from 22.19.17 to 22.19.18 - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node) Updates `react-dom` from 19.2.5 to 19.2.6 - [Release notes](https://github.com/facebook/react/releases) - [Changelog](https://github.com/facebook/react/blob/main/CHANGELOG.md) - [Commits](https://github.com/facebook/react/commits/v19.2.6/packages/react-dom) Updates `react-router` from 7.14.2 to 7.15.0 - [Release notes](https://github.com/remix-run/react-router/releases) - [Changelog](https://github.com/remix-run/react-router/blob/main/packages/react-router/CHANGELOG.md) - [Commits](https://github.com/remix-run/react-router/commits/react-router@7.15.0/packages/react-router) Updates `tailwindcss` from 4.2.4 to 4.3.0 - [Release notes](https://github.com/tailwindlabs/tailwindcss/releases) - [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md) - [Commits](https://github.com/tailwindlabs/tailwindcss/commits/v4.3.0/packages/tailwindcss) Updates `vite` from 7.3.2 to 7.3.3 - [Release notes](https://github.com/vitejs/vite/releases) - [Changelog](https://github.com/vitejs/vite/blob/v7.3.3/packages/vite/CHANGELOG.md) - [Commits](https://github.com/vitejs/vite/commits/v7.3.3/packages/vite) --- updated-dependencies: - dependency-name: expo dependency-version: 55.0.23 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production - dependency-name: react dependency-version: 19.2.0 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production - dependency-name: "@expo/fingerprint" dependency-version: 0.16.7 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: production - dependency-name: i18next dependency-version: 26.0.10 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: production - dependency-name: react-i18next dependency-version: 17.0.7 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: production - dependency-name: turbo dependency-version: 2.9.12 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: production - dependency-name: typescript-eslint dependency-version: 8.59.2 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: production - dependency-name: isbot dependency-version: 5.1.40 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production - dependency-name: zod dependency-version: 4.4.3 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production - dependency-name: "@expo/metro-runtime" dependency-version: 55.0.11 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production - dependency-name: "@gorhom/bottom-sheet" dependency-version: 5.2.14 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production - dependency-name: "@maplibre/maplibre-react-native" dependency-version: 11.1.1 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: production - dependency-name: "@sentry/react-native" dependency-version: 8.11.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: production - dependency-name: expo-constants dependency-version: 55.0.16 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production - dependency-name: expo-dev-client dependency-version: 55.0.32 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production - dependency-name: expo-dev-menu dependency-version: 55.0.27 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production - dependency-name: expo-device dependency-version: 55.0.16 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production - dependency-name: expo-file-system dependency-version: 55.0.19 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production - dependency-name: expo-linking dependency-version: 55.0.15 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production - dependency-name: expo-location dependency-version: 55.1.9 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production - dependency-name: expo-router dependency-version: 55.0.14 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production - dependency-name: expo-splash-screen dependency-version: 55.0.20 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production - dependency-name: expo-status-bar dependency-version: 55.0.6 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production - dependency-name: expo-system-ui dependency-version: 55.0.17 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production - dependency-name: expo-web-browser dependency-version: 55.0.15 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production - dependency-name: react-native-gesture-handler dependency-version: 2.31.2 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production - dependency-name: react-native-reanimated dependency-version: 4.3.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production - dependency-name: jest-expo dependency-version: 55.0.17 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: production - dependency-name: react-test-renderer dependency-version: 19.2.6 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: production - dependency-name: "@codemirror/view" dependency-version: 6.42.1 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: production - dependency-name: "@react-router/dev" dependency-version: 7.15.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: production - dependency-name: "@react-router/node" dependency-version: 7.15.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: production - dependency-name: "@react-router/serve" dependency-version: 7.15.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: production - dependency-name: "@sentry/node" dependency-version: 10.52.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: production - dependency-name: "@sentry/react" dependency-version: 10.52.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: production - dependency-name: "@tailwindcss/vite" dependency-version: 4.3.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: production - dependency-name: "@types/node" dependency-version: 22.19.18 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production - dependency-name: react-dom dependency-version: 19.2.6 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production - dependency-name: react-router dependency-version: 7.15.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: production - dependency-name: tailwindcss dependency-version: 4.3.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: production - dependency-name: vite dependency-version: 7.3.3 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production ... Signed-off-by: dependabot[bot] --- apps/journal/package.json | 4 +- apps/mobile/package.json | 44 +- apps/planner/package.json | 4 +- package.json | 12 +- packages/api/package.json | 2 +- pnpm-lock.yaml | 3332 ++++++++++++++++++++++++------------- pnpm-workspace.yaml | 20 +- 7 files changed, 2229 insertions(+), 1189 deletions(-) diff --git a/apps/journal/package.json b/apps/journal/package.json index 26e2b77..5a7bf58 100644 --- a/apps/journal/package.json +++ b/apps/journal/package.json @@ -29,7 +29,7 @@ "@trails-cool/types": "workspace:*", "@trails-cool/ui": "workspace:*", "drizzle-orm": "catalog:", - "isbot": "^5.1.39", + "isbot": "^5.1.40", "jose": "^6.2.3", "nodemailer": "^8.0.7", "pino": "^10.3.1", @@ -37,7 +37,7 @@ "react": "catalog:", "react-dom": "catalog:", "react-router": "catalog:", - "zod": "^4.4.2" + "zod": "^4.4.3" }, "devDependencies": { "@react-router/dev": "catalog:", diff --git a/apps/mobile/package.json b/apps/mobile/package.json index e5ef23d..6e18270 100644 --- a/apps/mobile/package.json +++ b/apps/mobile/package.json @@ -29,51 +29,51 @@ ] }, "dependencies": { - "@expo/metro-runtime": "^55.0.10", - "@gorhom/bottom-sheet": "^5.2.13", - "@maplibre/maplibre-react-native": "^11.0.2", + "@expo/metro-runtime": "^55.0.11", + "@gorhom/bottom-sheet": "^5.2.14", + "@maplibre/maplibre-react-native": "^11.1.1", "@sentry/cli": "^3.4.1", - "@sentry/react-native": "~8.10.0", + "@sentry/react-native": "~8.11.0", "@trails-cool/api": "workspace:*", "@trails-cool/gpx": "workspace:*", "@trails-cool/i18n": "workspace:*", "@trails-cool/map-core": "workspace:*", "@trails-cool/sentry-config": "workspace:*", "@trails-cool/types": "workspace:*", - "expo": "~55.0.19", - "expo-constants": "~55.0.15", + "expo": "~55.0.23", + "expo-constants": "~55.0.16", "expo-crypto": "~55.0.14", - "expo-dev-client": "~55.0.30", - "expo-dev-menu": "^55.0.26", - "expo-device": "~55.0.15", - "expo-file-system": "~55.0.17", - "expo-linking": "~55.0.14", + "expo-dev-client": "~55.0.32", + "expo-dev-menu": "^55.0.27", + "expo-device": "~55.0.16", + "expo-file-system": "~55.0.19", + "expo-linking": "~55.0.15", "expo-localization": "~55.0.13", - "expo-location": "~55.1.8", + "expo-location": "~55.1.9", "expo-navigation-bar": "~55.0.12", "expo-notifications": "~55.0.22", - "expo-router": "~55.0.13", + "expo-router": "~55.0.14", "expo-secure-store": "~55.0.13", - "expo-splash-screen": "~55.0.19", + "expo-splash-screen": "~55.0.20", "expo-sqlite": "~55.0.15", - "expo-status-bar": "~55.0.5", - "expo-system-ui": "^55.0.16", - "expo-web-browser": "~55.0.14", + "expo-status-bar": "~55.0.6", + "expo-system-ui": "^55.0.17", + "expo-web-browser": "~55.0.15", "react": "catalog:", "react-native": "0.83.4", - "react-native-gesture-handler": "^2.31.1", - "react-native-reanimated": "^4.3.0", + "react-native-gesture-handler": "^2.31.2", + "react-native-reanimated": "^4.3.1", "react-native-safe-area-context": "~5.7.0", "react-native-screens": "~4.24.0", "use-latest-callback": "^0.3.3", - "zod": "^4.4.2" + "zod": "^4.4.3" }, "devDependencies": { "@testing-library/react-native": "^13.3.3", "@types/jest": "^29.5.14", "@types/react": "~19.2.14", - "jest-expo": "^55.0.15", - "react-test-renderer": "^19.2.5", + "jest-expo": "^55.0.17", + "react-test-renderer": "^19.2.6", "typescript": "~5.9.2" } } diff --git a/apps/planner/package.json b/apps/planner/package.json index 73f407a..e889d3b 100644 --- a/apps/planner/package.json +++ b/apps/planner/package.json @@ -15,7 +15,7 @@ "@codemirror/commands": "^6.10.3", "@codemirror/language": "^6.12.3", "@codemirror/state": "^6.6.0", - "@codemirror/view": "^6.41.1", + "@codemirror/view": "^6.42.1", "@geoman-io/leaflet-geoman-free": "^2.19.3", "@react-router/node": "catalog:", "@react-router/serve": "catalog:", @@ -32,7 +32,7 @@ "@trails-cool/ui": "workspace:*", "codemirror": "^6.0.2", "drizzle-orm": "catalog:", - "isbot": "^5.1.39", + "isbot": "^5.1.40", "lib0": "^0.2.117", "pino": "^10.3.1", "prom-client": "^15.1.3", diff --git a/package.json b/package.json index f9d7da5..fc4a937 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ }, "devDependencies": { "@eslint/js": "^10.0.1", - "@expo/fingerprint": "^0.16.6", + "@expo/fingerprint": "^0.16.7", "@fission-ai/openspec": "^1.3.1", "@playwright/test": "^1.59.1", "@react-router/dev": "catalog:", @@ -62,7 +62,7 @@ "eslint": "^10.3.0", "eslint-config-prettier": "^10.1.8", "fit-file-parser": "^2.3.3", - "i18next": "^26.0.8", + "i18next": "^26.0.10", "i18next-browser-languagedetector": "^8.2.1", "jsdom": "^29.1.1", "leaflet": "^1.9.4", @@ -72,19 +72,19 @@ "prettier": "^3.8.3", "react": "catalog:", "react-dom": "catalog:", - "react-i18next": "^17.0.6", + "react-i18next": "^17.0.7", "react-leaflet": "^5.0.0", "react-router": "catalog:", "tailwindcss": "catalog:", - "turbo": "^2.9.8", + "turbo": "^2.9.12", "typescript": "catalog:", - "typescript-eslint": "^8.59.1", + "typescript-eslint": "^8.59.2", "vite": "catalog:", "vitest": "^4.1.5" }, "version": "1.0.0", "dependencies": { - "expo": "~55.0.19", + "expo": "~55.0.23", "react": "19.2.0", "react-native": "0.83.4" } diff --git a/packages/api/package.json b/packages/api/package.json index 5952f0b..92c5392 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -10,6 +10,6 @@ "typecheck": "tsc" }, "dependencies": { - "zod": "^4.4.2" + "zod": "^4.4.3" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 629469c..7bd5340 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -7,26 +7,26 @@ settings: catalogs: default: '@react-router/dev': - specifier: ^7.14.2 - version: 7.14.2 + specifier: ^7.15.0 + version: 7.15.0 '@react-router/node': - specifier: ^7.14.2 - version: 7.14.2 + specifier: ^7.15.0 + version: 7.15.0 '@react-router/serve': - specifier: ^7.14.2 - version: 7.14.2 + specifier: ^7.15.0 + version: 7.15.0 '@sentry/node': - specifier: ^10.51.0 - version: 10.51.0 + specifier: ^10.52.0 + version: 10.52.0 '@sentry/react': - specifier: ^10.51.0 - version: 10.51.0 + specifier: ^10.52.0 + version: 10.52.0 '@tailwindcss/vite': - specifier: ^4.2.4 - version: 4.2.4 + specifier: ^4.3.0 + version: 4.3.0 '@types/node': - specifier: ^22.0.0 - version: 22.19.17 + specifier: ^22.19.18 + version: 22.19.18 '@types/react': specifier: ^19.2.14 version: 19.2.14 @@ -46,11 +46,11 @@ catalogs: specifier: ^3.4.9 version: 3.4.9 react-router: - specifier: ^7.14.2 - version: 7.14.2 + specifier: ^7.15.0 + version: 7.15.0 tailwindcss: - specifier: ^4.2.4 - version: 4.2.4 + specifier: ^4.3.0 + version: 4.3.0 typescript: specifier: ^5.8.3 version: 5.9.3 @@ -64,15 +64,15 @@ overrides: 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 + react-dom: ^19.2.6 importers: .: dependencies: expo: - specifier: ~55.0.19 - version: 55.0.19(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.13)(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.23 + version: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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 @@ -82,37 +82,37 @@ importers: devDependencies: '@eslint/js': specifier: ^10.0.1 - version: 10.0.1(eslint@10.3.0(jiti@2.6.1)) + version: 10.0.1(eslint@10.3.0(jiti@2.7.0)) '@expo/fingerprint': - specifier: ^0.16.6 - version: 0.16.6 + specifier: ^0.16.7 + version: 0.16.7 '@fission-ai/openspec': specifier: ^1.3.1 - version: 1.3.1(@types/node@25.6.0) + version: 1.3.1(@types/node@25.6.2) '@playwright/test': specifier: ^1.59.1 version: 1.59.1 '@react-router/dev': specifier: 'catalog:' - version: 7.14.2(@react-router/serve@7.14.2(react-router@7.14.2(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.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.4))(yaml@2.8.4) + version: 7.15.0(@react-router/serve@7.15.0(react-router@7.15.0(react-dom@19.2.6(react@19.2.5))(react@19.2.5))(typescript@5.9.3))(@types/node@25.6.2)(jiti@2.7.0)(lightningcss@1.32.0)(react-router@7.15.0(react-dom@19.2.6(react@19.2.5))(react@19.2.5))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4))(yaml@2.8.4) '@react-router/node': specifier: 'catalog:' - version: 7.14.2(react-router@7.14.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3) + version: 7.15.0(react-router@7.15.0(react-dom@19.2.6(react@19.2.5))(react@19.2.5))(typescript@5.9.3) '@react-router/serve': specifier: 'catalog:' - version: 7.14.2(react-router@7.14.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3) + version: 7.15.0(react-router@7.15.0(react-dom@19.2.6(react@19.2.5))(react@19.2.5))(typescript@5.9.3) '@sentry/vite-plugin': specifier: ^5.2.1 - version: 5.2.1(rollup@4.60.2) + version: 5.2.1(rollup@4.60.3) '@tailwindcss/vite': specifier: 'catalog:' - version: 4.2.4(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.4)) + version: 4.3.0(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4)) '@testing-library/jest-dom': specifier: ^6.9.1 version: 6.9.1 '@testing-library/react': specifier: ^16.3.2 - version: 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) + version: 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.6(react@19.2.5))(react@19.2.5) '@types/geojson': specifier: ^7946.0.16 version: 7946.0.16 @@ -130,22 +130,22 @@ 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.19)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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 eslint: specifier: ^10.3.0 - version: 10.3.0(jiti@2.6.1) + version: 10.3.0(jiti@2.7.0) eslint-config-prettier: specifier: ^10.1.8 - version: 10.1.8(eslint@10.3.0(jiti@2.6.1)) + version: 10.1.8(eslint@10.3.0(jiti@2.7.0)) fit-file-parser: specifier: ^2.3.3 version: 2.3.3 i18next: - specifier: ^26.0.8 - version: 26.0.8(typescript@5.9.3) + specifier: ^26.0.10 + version: 26.0.10(typescript@5.9.3) i18next-browser-languagedetector: specifier: ^8.2.1 version: 8.2.1 @@ -168,50 +168,50 @@ importers: specifier: ^3.8.3 version: 3.8.3 react-dom: - specifier: ^19.2.5 - version: 19.2.5(react@19.2.5) + specifier: ^19.2.6 + version: 19.2.6(react@19.2.5) react-i18next: - specifier: ^17.0.6 - version: 17.0.6(i18next@26.0.8(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) + specifier: ^17.0.7 + version: 17.0.7(i18next@26.0.10(typescript@5.9.3))(react-dom@19.2.6(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) + version: 5.0.0(leaflet@1.9.4)(react-dom@19.2.6(react@19.2.5))(react@19.2.5) react-router: specifier: 'catalog:' - version: 7.14.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + version: 7.15.0(react-dom@19.2.6(react@19.2.5))(react@19.2.5) tailwindcss: - specifier: 'catalog:' - version: 4.2.4 + specifier: 4.3.0 + version: 4.3.0 turbo: - specifier: ^2.9.8 - version: 2.9.8 + specifier: ^2.9.12 + version: 2.9.12 typescript: specifier: 'catalog:' version: 5.9.3 typescript-eslint: - specifier: ^8.59.1 - version: 8.59.1(eslint@10.3.0(jiti@2.6.1))(typescript@5.9.3) + specifier: ^8.59.2 + version: 8.59.2(eslint@10.3.0(jiti@2.7.0))(typescript@5.9.3) vite: specifier: 'catalog:' - version: 8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.4) + version: 8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4) vitest: specifier: ^4.1.5 - version: 4.1.5(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(jsdom@29.1.1)(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.4)) + version: 4.1.5(@opentelemetry/api@1.9.1)(@types/node@25.6.2)(jsdom@29.1.1)(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4)) apps/journal: dependencies: '@react-router/node': specifier: 'catalog:' - version: 7.14.2(react-router@7.14.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3) + version: 7.15.0(react-router@7.15.0(react-dom@19.2.6(react@19.2.5))(react@19.2.5))(typescript@5.9.3) '@react-router/serve': specifier: 'catalog:' - version: 7.14.2(react-router@7.14.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3) + version: 7.15.0(react-router@7.15.0(react-dom@19.2.6(react@19.2.5))(react@19.2.5))(typescript@5.9.3) '@sentry/node': specifier: 'catalog:' - version: 10.51.0 + version: 10.52.0 '@sentry/react': specifier: 'catalog:' - version: 10.51.0(react@19.2.5) + version: 10.52.0(react@19.2.5) '@simplewebauthn/browser': specifier: ^13.3.0 version: 13.3.0 @@ -250,10 +250,10 @@ 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.19)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.39 - version: 5.1.39 + specifier: ^5.1.40 + version: 5.1.40 jose: specifier: ^6.2.3 version: 6.2.3 @@ -270,24 +270,24 @@ importers: specifier: ^19.2.5 version: 19.2.5 react-dom: - specifier: ^19.2.5 - version: 19.2.5(react@19.2.5) + specifier: ^19.2.6 + version: 19.2.6(react@19.2.5) react-router: specifier: 'catalog:' - version: 7.14.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + version: 7.15.0(react-dom@19.2.6(react@19.2.5))(react@19.2.5) zod: - specifier: ^4.4.2 - version: 4.4.2 + specifier: ^4.4.3 + version: 4.4.3 devDependencies: '@react-router/dev': specifier: 'catalog:' - version: 7.14.2(@react-router/serve@7.14.2(react-router@7.14.2(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.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.4))(yaml@2.8.4) + version: 7.15.0(@react-router/serve@7.15.0(react-router@7.15.0(react-dom@19.2.6(react@19.2.5))(react@19.2.5))(typescript@5.9.3))(@types/node@25.6.2)(jiti@2.7.0)(lightningcss@1.32.0)(react-router@7.15.0(react-dom@19.2.6(react@19.2.5))(react@19.2.5))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4))(yaml@2.8.4) '@simplewebauthn/types': specifier: ^12.0.0 version: 12.0.0 '@tailwindcss/vite': specifier: 'catalog:' - version: 4.2.4(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.4)) + version: 4.3.0(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4)) '@types/nodemailer': specifier: ^8.0.0 version: 8.0.0 @@ -299,37 +299,37 @@ 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.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.4)) + version: 2.3.0(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4)) pino-pretty: specifier: ^13.1.3 version: 13.1.3 tailwindcss: specifier: 'catalog:' - version: 4.2.4 + version: 4.3.0 typescript: specifier: 'catalog:' version: 5.9.3 vite: specifier: 'catalog:' - version: 8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.4) + version: 8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4) apps/mobile: dependencies: '@expo/metro-runtime': - specifier: ^55.0.10 - version: 55.0.10(@expo/dom-webview@55.0.5)(expo@55.0.19)(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) + specifier: ^55.0.11 + version: 55.0.11(@expo/dom-webview@55.0.5)(expo@55.0.23)(react-dom@19.2.6(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.13 - version: 5.2.13(@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) + specifier: ^5.2.14 + version: 5.2.14(@types/react@19.2.14)(react-native-gesture-handler@2.31.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-reanimated@4.3.1(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: ^11.0.2 - version: 11.0.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) + specifier: ^11.1.1 + version: 11.1.1(@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.4.1 version: 3.4.1 '@sentry/react-native': - specifier: ~8.10.0 - version: 8.10.0(@expo/env@2.1.1)(dotenv@16.6.1)(expo@55.0.19)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + specifier: ~8.11.0 + version: 8.11.0(@expo/env@2.1.2)(dotenv@16.6.1)(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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 @@ -349,62 +349,62 @@ importers: specifier: workspace:* version: link:../../packages/types expo: - specifier: ~55.0.19 - version: 55.0.19(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.13)(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.23 + version: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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.15 - version: 55.0.15(expo@55.0.19)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5)) + specifier: ~55.0.16 + version: 55.0.16(expo@55.0.23)(react-native@0.83.4(@babel/core@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-crypto: specifier: ~55.0.14 - version: 55.0.14(expo@55.0.19) + version: 55.0.14(expo@55.0.23) expo-dev-client: - specifier: ~55.0.30 - version: 55.0.30(expo@55.0.19) + specifier: ~55.0.32 + version: 55.0.32(expo@55.0.23) expo-dev-menu: - specifier: ^55.0.26 - version: 55.0.26(expo@55.0.19) + specifier: ^55.0.27 + version: 55.0.27(expo@55.0.23) expo-device: - specifier: ~55.0.15 - version: 55.0.15(expo@55.0.19) + specifier: ~55.0.16 + version: 55.0.16(expo@55.0.23) expo-file-system: - specifier: ~55.0.17 - version: 55.0.17(expo@55.0.19)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5)) + specifier: ~55.0.19 + version: 55.0.19(expo@55.0.23)(react-native@0.83.4(@babel/core@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.14 - version: 55.0.14(expo@55.0.19)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + specifier: ~55.0.15 + version: 55.0.15(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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-localization: specifier: ~55.0.13 - version: 55.0.13(expo@55.0.19)(react@19.2.5) + version: 55.0.13(expo@55.0.23)(react@19.2.5) expo-location: - specifier: ~55.1.8 - version: 55.1.8(expo@55.0.19)(typescript@5.9.3) + specifier: ~55.1.9 + version: 55.1.9(expo@55.0.23)(typescript@5.9.3) expo-navigation-bar: specifier: ~55.0.12 - version: 55.0.12(expo@55.0.19)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.12(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.22 - version: 55.0.22(expo@55.0.19)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.22(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.13 - version: 55.0.13(b9c3b63b8b06344e8f195cf40e503a18) + specifier: ~55.0.14 + version: 55.0.14(ab64f1877338f7f43eb15d5c78597024) expo-secure-store: specifier: ~55.0.13 - version: 55.0.13(expo@55.0.19) + version: 55.0.13(expo@55.0.23) expo-splash-screen: - specifier: ~55.0.19 - version: 55.0.19(expo@55.0.19)(typescript@5.9.3) + specifier: ~55.0.20 + version: 55.0.20(expo@55.0.23)(typescript@5.9.3) expo-sqlite: specifier: ~55.0.15 - version: 55.0.15(expo@55.0.19)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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) + specifier: ~55.0.6 + version: 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) expo-system-ui: - specifier: ^55.0.16 - version: 55.0.16(expo@55.0.19)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5)) + specifier: ^55.0.17 + version: 55.0.17(expo@55.0.23)(react-native@0.83.4(@babel/core@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.19)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5)) + specifier: ~55.0.15 + version: 55.0.15(expo@55.0.23)(react-native@0.83.4(@babel/core@7.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: ^19.2.5 version: 19.2.5 @@ -412,11 +412,11 @@ importers: 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) 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) + specifier: ^2.31.2 + version: 2.31.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-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) + specifier: ^4.3.1 + version: 4.3.1(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.7.0 version: 5.7.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) @@ -427,12 +427,12 @@ importers: specifier: ^0.3.3 version: 0.3.3(react@19.2.5) zod: - specifier: ^4.4.2 - version: 4.4.2 + specifier: ^4.4.3 + version: 4.4.3 devDependencies: '@testing-library/react-native': specifier: ^13.3.3 - 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) + version: 13.3.3(jest@29.7.0(@types/node@25.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-test-renderer@19.2.6(react@19.2.5))(react@19.2.5) '@types/jest': specifier: ^29.5.14 version: 29.5.14 @@ -440,11 +440,11 @@ importers: specifier: ~19.2.14 version: 19.2.14 jest-expo: - specifier: ^55.0.15 - version: 55.0.16(@babel/core@7.29.0)(expo@55.0.19)(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) + specifier: ^55.0.17 + version: 55.0.17(@babel/core@7.29.0)(expo@55.0.23)(jest@29.7.0(@types/node@25.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)(typescript@5.9.3) react-test-renderer: - specifier: ^19.2.5 - version: 19.2.5(react@19.2.5) + specifier: ^19.2.6 + version: 19.2.6(react@19.2.5) typescript: specifier: ~5.9.2 version: 5.9.3 @@ -461,23 +461,23 @@ importers: specifier: ^6.6.0 version: 6.6.0 '@codemirror/view': - specifier: ^6.41.1 - version: 6.41.1 + specifier: ^6.42.1 + version: 6.42.1 '@geoman-io/leaflet-geoman-free': specifier: ^2.19.3 version: 2.19.3(leaflet@1.9.4) '@react-router/node': specifier: 'catalog:' - version: 7.14.2(react-router@7.14.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3) + version: 7.15.0(react-router@7.15.0(react-dom@19.2.6(react@19.2.5))(react@19.2.5))(typescript@5.9.3) '@react-router/serve': specifier: 'catalog:' - version: 7.14.2(react-router@7.14.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3) + version: 7.15.0(react-router@7.15.0(react-dom@19.2.6(react@19.2.5))(react@19.2.5))(typescript@5.9.3) '@sentry/node': specifier: 'catalog:' - version: 10.51.0 + version: 10.52.0 '@sentry/react': specifier: 'catalog:' - version: 10.51.0(react@19.2.5) + version: 10.52.0(react@19.2.5) '@trails-cool/db': specifier: workspace:* version: link:../../packages/db @@ -510,10 +510,10 @@ 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.19)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.39 - version: 5.1.39 + specifier: ^5.1.40 + version: 5.1.40 lib0: specifier: ^0.2.117 version: 0.2.117 @@ -527,17 +527,17 @@ importers: specifier: ^19.2.5 version: 19.2.5 react-dom: - specifier: ^19.2.5 - version: 19.2.5(react@19.2.5) + specifier: ^19.2.6 + version: 19.2.6(react@19.2.5) react-router: specifier: 'catalog:' - version: 7.14.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + version: 7.15.0(react-dom@19.2.6(react@19.2.5))(react@19.2.5) ws: specifier: ^8.20.0 version: 8.20.0 y-codemirror.next: specifier: ^0.3.5 - version: 0.3.5(@codemirror/state@6.6.0)(@codemirror/view@6.41.1)(yjs@13.6.30) + version: 0.3.5(@codemirror/state@6.6.0)(@codemirror/view@6.42.1)(yjs@13.6.30) y-protocols: specifier: ^1.0.7 version: 1.0.7(yjs@13.6.30) @@ -550,10 +550,10 @@ importers: devDependencies: '@react-router/dev': specifier: 'catalog:' - version: 7.14.2(@react-router/serve@7.14.2(react-router@7.14.2(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.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.4))(yaml@2.8.4) + version: 7.15.0(@react-router/serve@7.15.0(react-router@7.15.0(react-dom@19.2.6(react@19.2.5))(react@19.2.5))(typescript@5.9.3))(@types/node@25.6.2)(jiti@2.7.0)(lightningcss@1.32.0)(react-router@7.15.0(react-dom@19.2.6(react@19.2.5))(react@19.2.5))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4))(yaml@2.8.4) '@tailwindcss/vite': specifier: 'catalog:' - version: 4.2.4(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.4)) + version: 4.3.0(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4)) '@types/leaflet.markercluster': specifier: ^1.5.6 version: 1.5.6 @@ -574,32 +574,32 @@ importers: version: 13.1.3 tailwindcss: specifier: 'catalog:' - version: 4.2.4 + version: 4.3.0 typescript: specifier: 'catalog:' version: 5.9.3 vite: specifier: 'catalog:' - version: 8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.4) + version: 8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4) packages/api: dependencies: zod: - specifier: ^4.4.2 - version: 4.4.2 + specifier: ^4.4.3 + version: 4.4.3 packages/db: 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.19)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(pg@8.20.0)(postgres@3.4.9) postgres: specifier: 'catalog:' version: 3.4.9 devDependencies: '@types/node': specifier: 'catalog:' - version: 22.19.17 + version: 22.19.18 packages/fit: dependencies: @@ -612,7 +612,7 @@ importers: devDependencies: '@types/node': specifier: 'catalog:' - version: 22.19.17 + version: 22.19.18 fit-file-parser: specifier: ^2.3.3 version: 2.3.3 @@ -628,7 +628,7 @@ importers: devDependencies: '@types/node': specifier: 'catalog:' - version: 22.19.17 + version: 22.19.18 packages/i18n: dependencies: @@ -640,7 +640,7 @@ importers: version: 19.2.5 react-i18next: specifier: '>=17' - version: 17.0.6(i18next@26.0.8(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.6(i18next@26.0.8(typescript@5.9.3))(react-dom@19.2.6(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: @@ -650,7 +650,7 @@ importers: devDependencies: '@types/node': specifier: 'catalog:' - version: 22.19.17 + version: 22.19.18 packages/map: dependencies: @@ -664,11 +664,11 @@ importers: specifier: ^19.2.5 version: 19.2.5 react-dom: - specifier: ^19.2.5 - version: 19.2.5(react@19.2.5) + specifier: ^19.2.6 + version: 19.2.6(react@19.2.5) react-leaflet: specifier: '>=5' - version: 5.0.0(leaflet@1.9.4)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + version: 5.0.0(leaflet@1.9.4)(react-dom@19.2.6(react@19.2.5))(react@19.2.5) packages/map-core: {} @@ -676,7 +676,7 @@ importers: devDependencies: '@types/node': specifier: 'catalog:' - version: 22.19.17 + version: 22.19.18 packages/types: {} @@ -686,7 +686,7 @@ importers: devDependencies: '@types/node': specifier: 'catalog:' - version: 22.19.17 + version: 22.19.18 packages: @@ -1229,8 +1229,8 @@ packages: '@codemirror/state@6.6.0': resolution: {integrity: sha512-4nbvra5R5EtiCzr9BTHiTLc+MLXK2QGiAVYMyi8PkQd3SR+6ixar/Q/01Fa21TBIDOZXgeWV4WppsQolSreAPQ==} - '@codemirror/view@6.41.1': - resolution: {integrity: sha512-ToDnWKbBnke+ZLrP6vgTTDScGi5H37YYuZGniQaBzxMVdtCxMrslsmtnOvbPZk4RX9bvkQqnWR/WS/35tJA0qg==} + '@codemirror/view@6.42.1': + resolution: {integrity: sha512-ToN3oFc0nsxNUYVF5P0ztLgbC4UPPjPtA9aKYhkOKQaZASpOUo6ISXyQLP66ctVwlDc+j6Jv0uK5IFALkiXztg==} '@csstools/color-helpers@6.0.2': resolution: {integrity: sha512-LMGQLS9EuADloEFkcTBR3BwV/CGHV7zyDxVRtVDTwdI2Ca4it0CCVTT9wCkxSgokjE5Ho41hEPgb8OEUwoXr6Q==} @@ -1784,11 +1784,11 @@ packages: '@noble/hashes': optional: true - '@expo-google-fonts/material-symbols@0.4.33': - resolution: {integrity: sha512-GQFy5tx7LBiRJttLYhz+KPmoVCQSVXiJPXVgMt/d8BWYbnJmw0nFixZtOaZQJE9F/L6vni3totwPNmbrdMi3ow==} + '@expo-google-fonts/material-symbols@0.4.36': + resolution: {integrity: sha512-hFIN8h99qUid9OppB9Sj18sUQib2O0I9c0soBmgb932Kz+20pAaGe/PRH6NdAqm8/DdOs+Hwx8A4Fqn9ZNadhg==} - '@expo/cli@55.0.27': - resolution: {integrity: sha512-FF/qWyHikqvVd5GBDiLII2PRgToNGz5MjxHw76a7aufbe5kCRpAqAy7HRoio1PlF5g9UIYnFjs333a3fWTlgMw==} + '@expo/cli@55.0.29': + resolution: {integrity: sha512-r2dXQ82e/3nwxS7faLRL6HBD8UWDo/IyptQ0Vg6Z5Bgyp2Kd24h8xPn3RHfY3LLJ3wfEXglf4E79/Dqkm1Z6WA==} hasBin: true peerDependencies: expo: '*' @@ -1809,14 +1809,14 @@ packages: '@expo/config-types@55.0.5': resolution: {integrity: sha512-sCmSUZG4mZ/ySXvfyyBdhjivz8Q539X1NondwDdYG7s3SBsk+wsgPJzYsqgAG/P9+l0xWjUD2F+kQ1cAJ6NNLg==} - '@expo/config@55.0.15': - resolution: {integrity: sha512-lHc0ELIQ8126jYOMZpLv3WIuvordW98jFg5aT/J1/12n2ycuXu01XLZkJsdw0avO34cusUYb1It+MvY8JiMduA==} + '@expo/config@55.0.16': + resolution: {integrity: sha512-H5dpQv5TfyZDNheZAWO3SmP10diGWZwN5QOUsArkDJih0QKNtahQBOmrV2xbhgln/nrUGoy41U/ZIY/MEx63Ug==} '@expo/devcert@1.2.1': resolution: {integrity: sha512-qC4eaxmKMTmJC2ahwyui6ud8f3W60Ss7pMkpBq40Hu3zyiAaugPXnZ24145U7K36qO9UHdZUVxsCvIpz2RYYCA==} - '@expo/devtools@55.0.2': - resolution: {integrity: sha512-4VsFn9MUriocyuhyA+ycJP3TJhUsOFHDc270l9h3LhNpXMf6wvIdGcA0QzXkZtORXmlDybWXRP2KT1k36HcQkA==} + '@expo/devtools@55.0.3': + resolution: {integrity: sha512-KoIDgo0NoXeWLsIcOdZqtAG/1LlsM+JL0DA3bo0vCYaOYTBLXi/ZvRBqa20Ub8D2vKLNa+FgRQW0gRg04Ps1Pg==} peerDependencies: react: ^19.2.5 react-native: '*' @@ -1833,45 +1833,48 @@ packages: react: ^19.2.5 react-native: '*' - '@expo/env@2.1.1': - resolution: {integrity: sha512-rVvHC4I6xlPcg+mAO09ydUi2Wjv1ZytpLmHOSzvXzBAz9mMrJggqCe4s4dubjJvi/Ino/xQCLhbaLCnTtLpikg==} + '@expo/env@2.1.2': + resolution: {integrity: sha512-RJtGFfj/ygO/6zcVbV3cckHf4THcEkv5IZft1GjCB3dfT6axvzvIwXE9EiQqQYmGHcQ+ZrvC8xZcIhiHba0pYg==} engines: {node: '>=20.12.0'} - '@expo/fingerprint@0.16.6': - resolution: {integrity: sha512-nRITNbnu3RKSHPvKVehrSU4KG2VY9V8nvULOHBw98ukHCAU4bGrU5APvcblOkX3JAap+xEHsg/mZvqlvkLInmQ==} + '@expo/fingerprint@0.16.7': + resolution: {integrity: sha512-BH8sicYOqZ1iBMwCVEGIz6uTTfylosjc49FoMmCYIzKOiYdiVehsfoYBwyfxwWIiya1VMhm1gv0cgOP8fxHpDw==} hasBin: true '@expo/image-utils@0.8.13': resolution: {integrity: sha512-1I//yBQeTY6p0u1ihqGNDAr35EbSG8uFEupFrIF0jd++h9EWH33521yZJU1yE+mwGlzCb61g3ehu78siMhXBlA==} - '@expo/json-file@10.0.13': - resolution: {integrity: sha512-pX/XjQn7tgNw6zuuV2ikmegmwe/S7uiwhrs2wXrANMkq7ozrA+JcZwgW9Q/8WZgciBzfAhNp5hnackHcrmapQA==} + '@expo/image-utils@0.8.14': + resolution: {integrity: sha512-5Sn+jG4Cw+shC2wDMXoqSAJnvERbiwzHn05FpWtD5IBflfTIs5gUmjzwiGVyjOdlMSQhgRrw/AymPbmO9h9mpQ==} - '@expo/local-build-cache-provider@55.0.11': - resolution: {integrity: sha512-rJ4RTCrkeKaXaido/bVyhl90ZRtVTOEbj59F1PWVjIEIVgjdlfc1J3VD9v7hEsbf/+8Tbr/PgvWhT6Visi5sLQ==} + '@expo/json-file@10.0.14': + resolution: {integrity: sha512-yWwBFywFv+SxkJp/pIzzA416JVYflNUh7pqQzgaA6nXDqRyK7KfrqVzk8PdUfDnqbBcaZZxpzNssfQZzp5KHrA==} - '@expo/log-box@55.0.11': - resolution: {integrity: sha512-JQHFLWkskIbJi6cxYMjErx8lQqfFJilDQLKmdTO3m3YkdmN9GE/CrzjOfVlCG0DGEGZJ90br0pGKvGPdXNsHKw==} + '@expo/local-build-cache-provider@55.0.12': + resolution: {integrity: sha512-Wqhe7ajt6lyIEQvqDC1zm0MQ1RqQLlM9awCepY9pz+tm9rvhuxGPZTSddWeD8k4kolinBlDbLDFnNi06XgaDWQ==} + + '@expo/log-box@55.0.12': + resolution: {integrity: sha512-f9ARS8J60cq3LLNdIqmUjYwyerBzVS5Ecp7KjIf3GOIPjW0571rkcwLz4/U18l/1DeSkSzIkYsNl2TC9oTdWaQ==} peerDependencies: - '@expo/dom-webview': ^55.0.5 + '@expo/dom-webview': ^55.0.6 expo: '*' react: ^19.2.5 react-native: '*' - '@expo/metro-config@55.0.18': - resolution: {integrity: sha512-XT7YHdQsUjdun0n4cyE5iXIyncDERIG4WesMBRUClr1RAurPwyg95BrbOBpq3E3uvwSBrAGfhu1w8VADqP4ZTQ==} + '@expo/metro-config@55.0.20': + resolution: {integrity: sha512-dUv0simEyPbN2wbOjI+BdEZyXdghgCZD0+3rrA1WxXZN1lRofUx6g2+Nik2Qg61v/BXFrCTh8reYEzQPzHOhdQ==} peerDependencies: expo: '*' peerDependenciesMeta: expo: optional: true - '@expo/metro-runtime@55.0.10': - resolution: {integrity: sha512-7v+ldTvMWRa1ml83Jel9W2f8qT/NZZWrlHaEjf29nb72JTEO50+Xac9PWLo+X3LCDAAuyYuBGKYXOJwfqxV0fQ==} + '@expo/metro-runtime@55.0.11': + resolution: {integrity: sha512-4KKi/jGrIEXi2YGu0hYTVr0CEeRJy5SXbCrz9+KDZkuD3ROwKNpM1DBawni5rhPVovFnR323HBck9GaxhnfrRw==} peerDependencies: expo: '*' react: ^19.2.5 - react-dom: ^19.2.5 + react-dom: ^19.2.6 react-native: '*' peerDependenciesMeta: react-dom: @@ -1880,40 +1883,40 @@ packages: '@expo/metro@55.1.1': resolution: {integrity: sha512-/wfXo5hTuAVpVLG/4hzlmD9NBGJkzkmBEMm/4VICajYRbj7y8OmqqPWbbymzHiBiHB6tI9BnsyXpQM6zVZEECg==} - '@expo/osascript@2.4.2': - resolution: {integrity: sha512-/XP7PSYF2hzOZzqfjgkoWtllyeTN8dW3aM4P6YgKcmmPikKL5FdoyQhti4eh6RK5a5VrUXJTOlTNIpIHsfB5Iw==} + '@expo/osascript@2.4.3': + resolution: {integrity: sha512-wbuj3EebM7W9hN/Wp4xTzKd6rQ2zKJzAxkFxkOOwyysLp0HOAgQ4/5RINyoS241pZUX2rUHq7mAJ7pcCQ8U0Ow==} engines: {node: '>=12'} - '@expo/package-manager@1.10.4': - resolution: {integrity: sha512-y9Mr4Kmpk4abAVZrNNPCdzOZr8nLLyi18p1SXr0RCVA8IfzqZX/eY4H+50a0HTmXqIsPZrQdcdb4I3ekMS9GvQ==} + '@expo/package-manager@1.10.5': + resolution: {integrity: sha512-nCP9Mebfl3jvOr0/P6VAuyah6PAtun+aihIL2zAtuE8uSe94JWkVZ7051i0MUVO+y3gFpBqnr8IIH5ch+VJjHA==} - '@expo/plist@0.5.2': - resolution: {integrity: sha512-o4xdVdBpe4aTl3sPMZ2u3fJH4iG1I768EIRk1xRZP+GaFI93MaR3JvoFibYqxeTmLQ1p1kNEVqylfUjezxx45g==} + '@expo/plist@0.5.3': + resolution: {integrity: sha512-jz5oPcPDd3fygwVxwSwmO6wodTwm0Qa14NUyPy0ka7H8sFmCtNZUI2+DzVe/EXjOhq1FbEjrwl89gdlWYOnVjQ==} - '@expo/prebuild-config@55.0.16': - resolution: {integrity: sha512-o4EAVgDGk1lISirtMD8hciO2vyMp7cWlPdfTtjjd5AXSfODVYDIDhygXrfvVQHmJXAztVqPUTKJT+BYOsVkYGQ==} + '@expo/prebuild-config@55.0.17': + resolution: {integrity: sha512-Mcs+dg4Ripu0yCtzf66KZr18PehI1O8HxzJw+G5SUF8VWX+ic99aci1PltvmydWepLwTQL6ykmpXicAUA31IqA==} peerDependencies: expo: '*' - '@expo/require-utils@55.0.4': - resolution: {integrity: sha512-JAANvXqV7MOysWeVWgaiDzikoyDjJWOV/ulOW60Zb3kXJfrx2oZOtGtDXDFKD1mXuahQgoM5QOjuZhF7gFRNjA==} + '@expo/require-utils@55.0.5': + resolution: {integrity: sha512-U4K/CQ2VpXuwfNGsN+daKmYOt15hCP8v/pXaYH6eut7kdYZo6SfJ1yr67BIcJ+1Gzzs+QzTxswAZChKpXmceyw==} peerDependencies: typescript: ^5.0.0 || ^5.0.0-0 peerDependenciesMeta: typescript: optional: true - '@expo/router-server@55.0.15': - resolution: {integrity: sha512-6LksYO4Pg13qroL138KfUebt/x/EO07zVhdyT/nTgcxnpn6CS4ecTl3DciSKhxbaH+0BVLdANkxYeGdp43TMwQ==} + '@expo/router-server@55.0.16': + resolution: {integrity: sha512-LvAdrm039nQBG+95+ff5Rc4CsBuoc/giDhjQrgxB9lKJqC/ZTq1xbwfEZFNq6yokX6fOCs/vlxdhmSkOjMIrvg==} peerDependencies: - '@expo/metro-runtime': ^55.0.10 + '@expo/metro-runtime': ^55.0.11 expo: '*' - expo-constants: ^55.0.15 - expo-font: ^55.0.6 + expo-constants: ^55.0.16 + expo-font: ^55.0.7 expo-router: '*' - expo-server: ^55.0.8 + expo-server: ^55.0.9 react: ^19.2.5 - react-dom: ^19.2.5 + react-dom: ^19.2.6 react-server-dom-webpack: ~19.0.1 || ~19.1.2 || ~19.2.1 peerDependenciesMeta: '@expo/metro-runtime': @@ -1925,8 +1928,8 @@ packages: react-server-dom-webpack: optional: true - '@expo/schema-utils@55.0.3': - resolution: {integrity: sha512-l9KHVjTo6MvoeyvwNr6AjckGJm8NIcqZ3QSAh51cWozXW9v2AUjyCyqYtFtyntLWRZ0x/ByYJishpQo4ZQq45Q==} + '@expo/schema-utils@55.0.4': + resolution: {integrity: sha512-65IdeeE8dAZR3n3J5Eq7LYiQ8BFGeEYCWPBCzycvafL7PkskbCyIclTQarRwf/HXFoRvezKCjaLwy/8v9Prk6g==} '@expo/sdk-runtime-versions@1.0.0': resolution: {integrity: sha512-Doz2bfiPndXYFPMRwPyGa1k5QaKDVpY806UJj570epIiMzWaYyCtobasyfC++qfIXVb5Ocy7r3tP9d62hAQ7IQ==} @@ -1948,8 +1951,8 @@ packages: '@expo/ws-tunnel@1.0.6': resolution: {integrity: sha512-nDRbLmSrJar7abvUjp3smDwH8HcbZcoOEa5jVPUv9/9CajgmWw20JNRwTuBRzWIWIkEJDkz20GoNA+tSwUqk0Q==} - '@expo/xcpretty@4.4.3': - resolution: {integrity: sha512-wC562eD3gS6vO2tWHToFhlFnmHKfKHgF1oyvojeSkLK/ZYop1bMU+7cOMiF9Sq70CzcsLy/EMRy/uRc76QmNRw==} + '@expo/xcpretty@4.4.4': + resolution: {integrity: sha512-4aQzz9vgxcNXFfo/iyNgDDYfsU5XGKKxWxZopw0cVotHiW+U8IJbIxMaxsINs6bHhtkG3StKNPcOrn3eBuxKPw==} hasBin: true '@fastify/otel@0.18.0': @@ -1971,8 +1974,8 @@ packages: peerDependencies: leaflet: ^1.2.0 - '@gorhom/bottom-sheet@5.2.13': - resolution: {integrity: sha512-cMxyd9kIowMME9kw2wwXAuWrXUQnPkJQz7rDbOSBBomZ+PpV/C/tlO1UozBrAe2zs3tp9th3JMW21FI/y0VeuQ==} + '@gorhom/bottom-sheet@5.2.14': + resolution: {integrity: sha512-uLQFlDjp9z+jrOFcMSEldPqL5JdaXL3vXOh+juhwoNvXgTsEorJLjHTugXu+YccAG/0KJnShzKCrb71MHBsvJg==} peerDependencies: '@types/react': '*' '@types/react-native': '*' @@ -2285,8 +2288,8 @@ packages: resolution: {integrity: sha512-zxa92qF96ZNojLxeAjnaRpjVCy+swoUNJvDhtpC90k7u5F0TMr4GmvNqMKvYrMoPB8d7gRSXbMG1hBbmgESIsw==} hasBin: true - '@maplibre/maplibre-react-native@11.0.2': - resolution: {integrity: sha512-aL+eD0OD2wBqBVS8G/oyykzGbH2npYOkx9HokayvXjYlj0rIz4uvMreQganPcdO3dkmtY9bVx35BnV+WQ8f/5A==} + '@maplibre/maplibre-react-native@11.1.1': + resolution: {integrity: sha512-yKeEyXupYYRO0s5PE1pSIvGQ3YEyoJGpvwMkZraZ3hFKR8ZeGgvTO3xm45KsSFKKYuBgOYH7Kg7mYXfQlmgEjw==} peerDependencies: '@expo/config-plugins': '>=54.0.0' '@types/geojson': ^7946.0.0 @@ -2395,12 +2398,6 @@ packages: peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation-ioredis@0.62.0': - resolution: {integrity: sha512-ZYt//zcPve8qklaZX+5Z4MkU7UpEkFRrxsf2cnaKYBitqDnsCN69CPAuuMOX6NYdW2rG9sFy7V/QWtBlP5XiNQ==} - engines: {node: ^18.19.0 || >=20.6.0} - peerDependencies: - '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation-kafkajs@0.23.0': resolution: {integrity: sha512-4K+nVo+zI+aDz0Z85SObwbdixIbzS9moIuKJaYsdlzcHYnKOPtB7ya8r8Ezivy/GVIBHiKJVq4tv+BEkgOMLaQ==} engines: {node: ^18.19.0 || >=20.6.0} @@ -2455,12 +2452,6 @@ packages: peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation-redis@0.62.0': - resolution: {integrity: sha512-y3pPpot7WzR/8JtHcYlTYsyY8g+pbFhAqbwAuG5bLPnR6v6pt1rQc0DpH0OlGP/9CZbWBP+Zhwp9yFoygf/ZXQ==} - engines: {node: ^18.19.0 || >=20.6.0} - peerDependencies: - '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation-tedious@0.33.0': resolution: {integrity: sha512-Q6WQwAD01MMTub31GlejoiFACYNw26J426wyjvU7by7fDIr2nZXNW4vhTGs7i7F0TnXBO3xN688g1tdUgYwJ5w==} engines: {node: ^18.19.0 || >=20.6.0} @@ -2485,10 +2476,6 @@ packages: peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/redis-common@0.38.2': - resolution: {integrity: sha512-1BCcU93iwSRZvDAgwUxC/DV4T/406SkMfxGqu5ojc3AvNI+I9GhV7v0J1HljsczuuhcnFLYqD5VmwVXfCGHzxA==} - engines: {node: ^18.19.0 || >=20.6.0} - '@opentelemetry/resources@2.6.1': resolution: {integrity: sha512-lID/vxSuKWXM55XhAKNoYXu9Cutoq5hFdkbTdI/zDKQktXzcWBVhNsOkiZFTMU9UtEWuGRNe0HUgmsFldIdxVA==} engines: {node: ^18.19.0 || >=20.6.0} @@ -2579,7 +2566,7 @@ packages: '@types/react': '*' '@types/react-dom': '*' react: ^19.2.5 - react-dom: ^19.2.5 + react-dom: ^19.2.6 peerDependenciesMeta: '@types/react': optional: true @@ -2610,7 +2597,7 @@ packages: '@types/react': '*' '@types/react-dom': '*' react: ^19.2.5 - react-dom: ^19.2.5 + react-dom: ^19.2.6 peerDependenciesMeta: '@types/react': optional: true @@ -2632,7 +2619,7 @@ packages: '@types/react': '*' '@types/react-dom': '*' react: ^19.2.5 - react-dom: ^19.2.5 + react-dom: ^19.2.6 peerDependenciesMeta: '@types/react': optional: true @@ -2654,7 +2641,7 @@ packages: '@types/react': '*' '@types/react-dom': '*' react: ^19.2.5 - react-dom: ^19.2.5 + react-dom: ^19.2.6 peerDependenciesMeta: '@types/react': optional: true @@ -2676,7 +2663,7 @@ packages: '@types/react': '*' '@types/react-dom': '*' react: ^19.2.5 - react-dom: ^19.2.5 + react-dom: ^19.2.6 peerDependenciesMeta: '@types/react': optional: true @@ -2689,7 +2676,7 @@ packages: '@types/react': '*' '@types/react-dom': '*' react: ^19.2.5 - react-dom: ^19.2.5 + react-dom: ^19.2.6 peerDependenciesMeta: '@types/react': optional: true @@ -2702,7 +2689,7 @@ packages: '@types/react': '*' '@types/react-dom': '*' react: ^19.2.5 - react-dom: ^19.2.5 + react-dom: ^19.2.6 peerDependenciesMeta: '@types/react': optional: true @@ -2715,7 +2702,7 @@ packages: '@types/react': '*' '@types/react-dom': '*' react: ^19.2.5 - react-dom: ^19.2.5 + react-dom: ^19.2.6 peerDependenciesMeta: '@types/react': optional: true @@ -2746,7 +2733,7 @@ packages: '@types/react': '*' '@types/react-dom': '*' react: ^19.2.5 - react-dom: ^19.2.5 + react-dom: ^19.2.6 peerDependenciesMeta: '@types/react': optional: true @@ -2803,7 +2790,7 @@ packages: peerDependencies: leaflet: ^1.9.0 react: ^19.2.5 - react-dom: ^19.2.5 + react-dom: ^19.2.6 '@react-native/assets-registry@0.83.4': resolution: {integrity: sha512-aqKtpbJDSQeSX/Dwv0yMe1/Rd2QfXi12lnyZDXNn/OEKz59u6+LuPBVgO/9CRyclHmdlvwg8c7PJ9eX2ZMnjWg==} @@ -2922,25 +2909,25 @@ packages: '@types/react': optional: true - '@react-navigation/bottom-tabs@7.15.10': - resolution: {integrity: sha512-Ao/yYlrpr0cwYYGxt9FDMQk+tTSHNm4WTaszyhroINLdoEMuKH19k1tGFdYbRBKHJx1UIH8kD+EZTYW1w6LL3Q==} + '@react-navigation/bottom-tabs@7.15.13': + resolution: {integrity: sha512-UZ3WteUDhe8xDWTbT3uon8CtkjiiOy3xIgYx8AI0ZmulvDzpKh+n0CW5X1z2BNCFxCJj563M+L7FH0Pf6Ov7mA==} peerDependencies: - '@react-navigation/native': ^7.2.2 + '@react-navigation/native': ^7.2.4 react: ^19.2.5 react-native: '*' react-native-safe-area-context: '>= 4.0.0' react-native-screens: '>= 4.0.0' - '@react-navigation/core@7.17.2': - resolution: {integrity: sha512-Rt2OZwcgOmjv401uLGAKaRM6xo0fiBce/A7LfRHI1oe5FV+KooWcgAoZ2XOtgKj6UzVMuQWt3b2e6rxo/mDJRA==} + '@react-navigation/core@7.17.4': + resolution: {integrity: sha512-Rv9E2oNNQEkPGpmu9q+vJwGJRSQR6LBg5L+Yo1QHjtwGbHUbjkIKOdYymDZoZYgNzX2OD4rAIlfuzbDKa3cCeA==} peerDependencies: react: ^19.2.5 - '@react-navigation/elements@2.9.15': - resolution: {integrity: sha512-cyz/pPiyyC6gaTVLsGFc1g0MYgrmuCFqklAWGXMWPscr5YU3ui94vPI4vnZwcsEy0T758TQWLzmS5XudZeRKcA==} + '@react-navigation/elements@2.9.17': + resolution: {integrity: sha512-Prax9RDS6l32npcl4PzvL88VoXe9HdtcIUP2+rim3DLVSZceD6oreA+cmPBUjeLFjsnxKlU3pTRby3RpYJ5/xw==} peerDependencies: '@react-native-masked-view/masked-view': '>= 0.2.0' - '@react-navigation/native': ^7.2.2 + '@react-navigation/native': ^7.2.4 react: ^19.2.5 react-native: '*' react-native-safe-area-context: '>= 4.0.0' @@ -2948,32 +2935,32 @@ packages: '@react-native-masked-view/masked-view': optional: true - '@react-navigation/native-stack@7.14.12': - resolution: {integrity: sha512-dUfpkrVeVKKV8iqXsmoUp3Rv0iH3YaB3eZwScru/FlcqAp/r3/qA6zEXkGX9hZK+/ziWAPFrf1frBSNbgOYSFQ==} + '@react-navigation/native-stack@7.14.14': + resolution: {integrity: sha512-KCKwnooV05vPw7PGqMoNmCJXARjsp51DRw/3Bw9tjOLGBkmLaUbOJJuM7IQXcI+1EWE4GjBYrfIPtiARGNUg1g==} peerDependencies: - '@react-navigation/native': ^7.2.2 + '@react-navigation/native': ^7.2.4 react: ^19.2.5 react-native: '*' react-native-safe-area-context: '>= 4.0.0' react-native-screens: '>= 4.0.0' - '@react-navigation/native@7.2.2': - resolution: {integrity: sha512-kem1Ko2BcbAjmbQIv66dNmr6EtfDut3QU0qjsVhMnLLhktwyXb6FzZYp8gTrUb6AvkAbaJoi+BF5Pl55pAUa5w==} + '@react-navigation/native@7.2.4': + resolution: {integrity: sha512-eWC2D3JjhYLId2fVTZhhCiUpWIaPhO9XyEb7Wq8ElmOHyIODlbOzgZ0rKia02OIsDKr9BzZl2sK1dL70yMxDaw==} peerDependencies: react: ^19.2.5 react-native: '*' - '@react-navigation/routers@7.5.3': - resolution: {integrity: sha512-1tJHg4KKRJuQ1/EvJxatrMef3NZXEPzwUIUZ3n1yJ2t7Q97siwRtbynRpQG9/69ebbtiZ8W3ScOZF/OmhvM4Rg==} + '@react-navigation/routers@7.5.5': + resolution: {integrity: sha512-9/hhMte12Kgu+pMnLfA4EWJ0OQmIEAMVMX06FPH2yGkEQSQ3JhhCN/GkcRikzQhtEi97VYYQA15umptBUShcOQ==} - '@react-router/dev@7.14.2': - resolution: {integrity: sha512-lU88Ls4iC78RdPOKkER54+hlsHzzS8WSZrf2/cGQumbIN2A5WvO0LDyv72cdJmLWujgZ9rpNoGzmqWINssShGQ==} + '@react-router/dev@7.15.0': + resolution: {integrity: sha512-ZwUQu4KNZrViFqdeFWqh00Bk/QbLNvoWRDfjsqOp3oyuG3jSRLYnqRD3VAMK/FYMpL+s37ByT7XqqLXaF7Nw1g==} engines: {node: '>=20.0.0'} hasBin: true peerDependencies: - '@react-router/serve': ^7.14.2 + '@react-router/serve': ^7.15.0 '@vitejs/plugin-rsc': ~0.5.21 - react-router: ^7.14.2 + react-router: ^7.15.0 react-server-dom-webpack: ^19.2.3 typescript: ^5.1.0 || ^6.0.0 vite: ^5.1.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 @@ -2990,36 +2977,36 @@ packages: wrangler: optional: true - '@react-router/express@7.14.2': - resolution: {integrity: sha512-IYs61kHfMWsJk/ju4Ts4hw7wblZecfXuIvqQPKEaz+gwpkJMSWDzhPpgmC16EnmBQkXPqMVpsjvNxA/d9p9ehg==} + '@react-router/express@7.15.0': + resolution: {integrity: sha512-WldQrI5FxbsTLztOqx0+c7248m8IDUchCUUX177I+qz9OMuLR9ueIqz53zBKCVQ+Zf7k6FyatwpoLmr/Wovalg==} engines: {node: '>=20.0.0'} peerDependencies: express: ^4.17.1 || ^5 - react-router: 7.14.2 + react-router: 7.15.0 typescript: ^5.1.0 || ^6.0.0 peerDependenciesMeta: typescript: optional: true - '@react-router/node@7.14.2': - resolution: {integrity: sha512-8zxVfgKOXjk0k8YxSBDTFyNAuVdr+og1wFbQpmJJOxo7ObxfI81EbHenyyxGvFiw77rNFLS9Dqgnv5xZgHZfCw==} + '@react-router/node@7.15.0': + resolution: {integrity: sha512-SgvWaWF1n3u+bpXXZUW9BSd2p/NwkIYLz4SSeDYqoX5RkYX5rcI4cHHuNJXszPu+Dm9QIri4J9g/4EV3KfgiXQ==} engines: {node: '>=20.0.0'} peerDependencies: - react-router: 7.14.2 + react-router: 7.15.0 typescript: ^5.1.0 || ^6.0.0 peerDependenciesMeta: typescript: optional: true - '@react-router/serve@7.14.2': - resolution: {integrity: sha512-Rh/Mrd9+Jkf+IOd7beEccCfTDavOQRpkk0TLwLFK60dv0yUIyOTIaKxC7W6I0WMrgAjhUL09JxfMsoz2vtYhTg==} + '@react-router/serve@7.15.0': + resolution: {integrity: sha512-0XtYmwc11vWdYn2zeEXx9E3u0I6TH3bm4uDaMdsyI09S6hl6uc98vBkTSXg7Znm3qR82R/jjtn3LvV2QEZ193w==} engines: {node: '>=20.0.0'} hasBin: true peerDependencies: - react-router: 7.14.2 + react-router: 7.15.0 - '@remix-run/node-fetch-server@0.13.0': - resolution: {integrity: sha512-1EsNo0ZpgXu/90AWoRZf/oE3RVTUS80tiTUpt+hv5pjtAkw7icN4WskDwz/KdAw5ARbJLMhZBrO1NqThmy/McA==} + '@remix-run/node-fetch-server@0.13.1': + resolution: {integrity: sha512-dOL+A/C84EA47gO/ps52KGrVSiYy96512rwtbXmJfWKYFm1FbrbjA3jao1hcIfao+jwVNEaZ1kTMwFjiino+HQ==} '@rolldown/binding-android-arm64@1.0.0-rc.17': resolution: {integrity: sha512-s70pVGhw4zqGeFnXWvAzJDlvxhlRollagdCCKRgOsgUOH3N1l0LIxf83AtGzmb5SiVM4Hjl5HyarMRfdfj3DaQ==} @@ -3119,141 +3106,141 @@ packages: '@rolldown/pluginutils@1.0.0-rc.17': resolution: {integrity: sha512-n8iosDOt6Ig1UhJ2AYqoIhHWh/isz0xpicHTzpKBeotdVsTEcxsSA/i3EVM7gQAj0rU27OLAxCjzlj15IWY7bg==} - '@rollup/rollup-android-arm-eabi@4.60.2': - resolution: {integrity: sha512-dnlp69efPPg6Uaw2dVqzWRfAWRnYVb1XJ8CyyhIbZeaq4CA5/mLeZ1IEt9QqQxmbdvagjLIm2ZL8BxXv5lH4Yw==} + '@rollup/rollup-android-arm-eabi@4.60.3': + resolution: {integrity: sha512-x35CNW/ANXG3hE/EZpRU8MXX1JDN86hBb2wMGAtltkz7pc6cxgjpy1OMMfDosOQ+2hWqIkag/fGok1Yady9nGw==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.60.2': - resolution: {integrity: sha512-OqZTwDRDchGRHHm/hwLOL7uVPB9aUvI0am/eQuWMNyFHf5PSEQmyEeYYheA0EPPKUO/l0uigCp+iaTjoLjVoHg==} + '@rollup/rollup-android-arm64@4.60.3': + resolution: {integrity: sha512-xw3xtkDApIOGayehp2+Rz4zimfkaX65r4t47iy+ymQB2G4iJCBBfj0ogVg5jpvjpn8UWn/+q9tprxleYeNp3Hw==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.60.2': - resolution: {integrity: sha512-UwRE7CGpvSVEQS8gUMBe1uADWjNnVgP3Iusyda1nSRwNDCsRjnGc7w6El6WLQsXmZTbLZx9cecegumcitNfpmA==} + '@rollup/rollup-darwin-arm64@4.60.3': + resolution: {integrity: sha512-vo6Y5Qfpx7/5EaamIwi0WqW2+zfiusVihKatLvtN1VFVy3D13uERk/6gZLU1UiHRL6fDXqj/ELIeVRGnvcTE1g==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.60.2': - resolution: {integrity: sha512-gjEtURKLCC5VXm1I+2i1u9OhxFsKAQJKTVB8WvDAHF+oZlq0GTVFOlTlO1q3AlCTE/DF32c16ESvfgqR7343/g==} + '@rollup/rollup-darwin-x64@4.60.3': + resolution: {integrity: sha512-D+0QGcZhBzTN82weOnsSlY7V7+RMmPuF1CkbxyMAGE8+ZHeUjyb76ZiWmBlCu//AQQONvxcqRbwZTajZKqjuOw==} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.60.2': - resolution: {integrity: sha512-Bcl6CYDeAgE70cqZaMojOi/eK63h5Me97ZqAQoh77VPjMysA/4ORQBRGo3rRy45x4MzVlU9uZxs8Uwy7ZaKnBw==} + '@rollup/rollup-freebsd-arm64@4.60.3': + resolution: {integrity: sha512-6HnvHCT7fDyj6R0Ph7A6x8dQS/S38MClRWeDLqc0MdfWkxjiu1HSDYrdPhqSILzjTIC/pnXbbJbo+ft+gy/9hQ==} cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.60.2': - resolution: {integrity: sha512-LU+TPda3mAE2QB0/Hp5VyeKJivpC6+tlOXd1VMoXV/YFMvk/MNk5iXeBfB4MQGRWyOYVJ01625vjkr0Az98OJQ==} + '@rollup/rollup-freebsd-x64@4.60.3': + resolution: {integrity: sha512-KHLgC3WKlUYW3ShFKnnosZDOJ0xjg9zp7au3sIm2bs/tGBeC2ipmvRh/N7JKi0t9Ue20C0dpEshi8WUubg+cnA==} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.60.2': - resolution: {integrity: sha512-2QxQrM+KQ7DAW4o22j+XZ6RKdxjLD7BOWTP0Bv0tmjdyhXSsr2Ul1oJDQqh9Zf5qOwTuTc7Ek83mOFaKnodPjg==} + '@rollup/rollup-linux-arm-gnueabihf@4.60.3': + resolution: {integrity: sha512-DV6fJoxEYWJOvaZIsok7KrYl0tPvga5OZ2yvKHNNYyk/2roMLqQAbGhr78EQ5YhHpnhLKJD3S1WFusAkmUuV5g==} cpu: [arm] os: [linux] libc: [glibc] - '@rollup/rollup-linux-arm-musleabihf@4.60.2': - resolution: {integrity: sha512-TbziEu2DVsTEOPif2mKWkMeDMLoYjx95oESa9fkQQK7r/Orta0gnkcDpzwufEcAO2BLBsD7mZkXGFqEdMRRwfw==} + '@rollup/rollup-linux-arm-musleabihf@4.60.3': + resolution: {integrity: sha512-mQKoJAzvuOs6F+TZybQO4GOTSMUu7v0WdxEk24krQ/uUxXoPTtHjuaUuPmFhtBcM4K0ons8nrE3JyhTuCFtT/w==} cpu: [arm] os: [linux] libc: [musl] - '@rollup/rollup-linux-arm64-gnu@4.60.2': - resolution: {integrity: sha512-bO/rVDiDUuM2YfuCUwZ1t1cP+/yqjqz+Xf2VtkdppefuOFS2OSeAfgafaHNkFn0t02hEyXngZkxtGqXcXwO8Rg==} + '@rollup/rollup-linux-arm64-gnu@4.60.3': + resolution: {integrity: sha512-Whjj2qoiJ6+OOJMGptTYazaJvjOJm+iKHpXQM1P3LzGjt7Ff++Tp7nH4N8J/BUA7R9IHfDyx4DJIflifwnbmIA==} cpu: [arm64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-arm64-musl@4.60.2': - resolution: {integrity: sha512-hr26p7e93Rl0Za+JwW7EAnwAvKkehh12BU1Llm9Ykiibg4uIr2rbpxG9WCf56GuvidlTG9KiiQT/TXT1yAWxTA==} + '@rollup/rollup-linux-arm64-musl@4.60.3': + resolution: {integrity: sha512-4YTNHKqGng5+yiZt3mg77nmyuCfmNfX4fPmyUapBcIk+BdwSwmCWGXOUxhXbBEkFHtoN5boLj/5NON+u5QC9tg==} cpu: [arm64] os: [linux] libc: [musl] - '@rollup/rollup-linux-loong64-gnu@4.60.2': - resolution: {integrity: sha512-pOjB/uSIyDt+ow3k/RcLvUAOGpysT2phDn7TTUB3n75SlIgZzM6NKAqlErPhoFU+npgY3/n+2HYIQVbF70P9/A==} + '@rollup/rollup-linux-loong64-gnu@4.60.3': + resolution: {integrity: sha512-SU3kNlhkpI4UqlUc2VXPGK9o886ZsSeGfMAX2ba2b8DKmMXq4AL7KUrkSWVbb7koVqx41Yczx6dx5PNargIrEA==} cpu: [loong64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-loong64-musl@4.60.2': - resolution: {integrity: sha512-2/w+q8jszv9Ww1c+6uJT3OwqhdmGP2/4T17cu8WuwyUuuaCDDJ2ojdyYwZzCxx0GcsZBhzi3HmH+J5pZNXnd+Q==} + '@rollup/rollup-linux-loong64-musl@4.60.3': + resolution: {integrity: sha512-6lDLl5h4TXpB1mTf2rQWnAk/LcXrx9vBfu/DT5TIPhvMhRWaZ5MxkIc8u4lJAmBo6klTe1ywXIUHFjylW505sg==} cpu: [loong64] os: [linux] libc: [musl] - '@rollup/rollup-linux-ppc64-gnu@4.60.2': - resolution: {integrity: sha512-11+aL5vKheYgczxtPVVRhdptAM2H7fcDR5Gw4/bTcteuZBlH4oP9f5s9zYO9aGZvoGeBpqXI/9TZZihZ609wKw==} + '@rollup/rollup-linux-ppc64-gnu@4.60.3': + resolution: {integrity: sha512-BMo8bOw8evlup/8G+cj5xWtPyp93xPdyoSN16Zy90Q2QZ0ZYRhCt6ZJSwbrRzG9HApFabjwj2p25TUPDWrhzqQ==} cpu: [ppc64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-ppc64-musl@4.60.2': - resolution: {integrity: sha512-i16fokAGK46IVZuV8LIIwMdtqhin9hfYkCh8pf8iC3QU3LpwL+1FSFGej+O7l3E/AoknL6Dclh2oTdnRMpTzFQ==} + '@rollup/rollup-linux-ppc64-musl@4.60.3': + resolution: {integrity: sha512-E0L8X1dZN1/Rph+5VPF6Xj2G7JJvMACVXtamTJIDrVI44Y3K+G8gQaMEAavbqCGTa16InptiVrX6eM6pmJ+7qA==} cpu: [ppc64] os: [linux] libc: [musl] - '@rollup/rollup-linux-riscv64-gnu@4.60.2': - resolution: {integrity: sha512-49FkKS6RGQoriDSK/6E2GkAsAuU5kETFCh7pG4yD/ylj9rKhTmO3elsnmBvRD4PgJPds5W2PkhC82aVwmUcJ7A==} + '@rollup/rollup-linux-riscv64-gnu@4.60.3': + resolution: {integrity: sha512-oZJ/WHaVfHUiRAtmTAeo3DcevNsVvH8mbvodjZy7D5QKvCefO371SiKRpxoDcCxB3PTRTLayWBkvmDQKTcX/sw==} cpu: [riscv64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-riscv64-musl@4.60.2': - resolution: {integrity: sha512-mjYNkHPfGpUR00DuM1ZZIgs64Hpf4bWcz9Z41+4Q+pgDx73UwWdAYyf6EG/lRFldmdHHzgrYyge5akFUW0D3mQ==} + '@rollup/rollup-linux-riscv64-musl@4.60.3': + resolution: {integrity: sha512-Dhbyh7j9FybM3YaTgaHmVALwA8AkUwTPccyCQ79TG9AJUsMQqgN1DDEZNr4+QUfwiWvLDumW5vdwzoeUF+TNxQ==} cpu: [riscv64] os: [linux] libc: [musl] - '@rollup/rollup-linux-s390x-gnu@4.60.2': - resolution: {integrity: sha512-ALyvJz965BQk8E9Al/JDKKDLH2kfKFLTGMlgkAbbYtZuJt9LU8DW3ZoDMCtQpXAltZxwBHevXz5u+gf0yA0YoA==} + '@rollup/rollup-linux-s390x-gnu@4.60.3': + resolution: {integrity: sha512-cJd1X5XhHHlltkaypz1UcWLA8AcoIi1aWhsvaWDskD1oz2eKCypnqvTQ8ykMNI0RSmm7NkTdSqSSD7zM0xa6Ig==} cpu: [s390x] os: [linux] libc: [glibc] - '@rollup/rollup-linux-x64-gnu@4.60.2': - resolution: {integrity: sha512-UQjrkIdWrKI626Du8lCQ6MJp/6V1LAo2bOK9OTu4mSn8GGXIkPXk/Vsp4bLHCd9Z9Iz2OTEaokUE90VweJgIYQ==} + '@rollup/rollup-linux-x64-gnu@4.60.3': + resolution: {integrity: sha512-DAZDBHQfG2oQuhY7mc6I3/qB4LU2fQCjRvxbDwd/Jdvb9fypP4IJ4qmtu6lNjes6B531AI8cg1aKC2di97bUxA==} cpu: [x64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-x64-musl@4.60.2': - resolution: {integrity: sha512-bTsRGj6VlSdn/XD4CGyzMnzaBs9bsRxy79eTqTCBsA8TMIEky7qg48aPkvJvFe1HyzQ5oMZdg7AnVlWQSKLTnw==} + '@rollup/rollup-linux-x64-musl@4.60.3': + resolution: {integrity: sha512-cRxsE8c13mZOh3vP+wLDxpQBRrOHDIGOWyDL93Sy0Ga8y515fBcC2pjUfFwUe5T7tqvTvWbCpg1URM/AXdWIXA==} cpu: [x64] os: [linux] libc: [musl] - '@rollup/rollup-openbsd-x64@4.60.2': - resolution: {integrity: sha512-6d4Z3534xitaA1FcMWP7mQPq5zGwBmGbhphh2DwaA1aNIXUu3KTOfwrWpbwI4/Gr0uANo7NTtaykFyO2hPuFLg==} + '@rollup/rollup-openbsd-x64@4.60.3': + resolution: {integrity: sha512-QaWcIgRxqEdQdhJqW4DJctsH6HCmo5vHxY0krHSX4jMtOqfzC+dqDGuHM87bu4H8JBeibWx7jFz+h6/4C8wA5Q==} cpu: [x64] os: [openbsd] - '@rollup/rollup-openharmony-arm64@4.60.2': - resolution: {integrity: sha512-NetAg5iO2uN7eB8zE5qrZ3CSil+7IJt4WDFLcC75Ymywq1VZVD6qJ6EvNLjZ3rEm6gB7XW5JdT60c6MN35Z85Q==} + '@rollup/rollup-openharmony-arm64@4.60.3': + resolution: {integrity: sha512-AaXwSvUi3QIPtroAUw1t5yHGIyqKEXwH54WUocFolZhpGDruJcs8c+xPNDRn4XiQsS7MEwnYsHW2l0MBLDMkWg==} cpu: [arm64] os: [openharmony] - '@rollup/rollup-win32-arm64-msvc@4.60.2': - resolution: {integrity: sha512-NCYhOotpgWZ5kdxCZsv6Iudx0wX8980Q/oW4pNFNihpBKsDbEA1zpkfxJGC0yugsUuyDZ7gL37dbzwhR0VI7pQ==} + '@rollup/rollup-win32-arm64-msvc@4.60.3': + resolution: {integrity: sha512-65LAKM/bAWDqKNEelHlcHvm2V+Vfb8C6INFxQXRHCvaVN1rJfwr4NvdP4FyzUaLqWfaCGaadf6UbTm8xJeYfEg==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.60.2': - resolution: {integrity: sha512-RXsaOqXxfoUBQoOgvmmijVxJnW2IGB0eoMO7F8FAjaj0UTywUO/luSqimWBJn04WNgUkeNhh7fs7pESXajWmkg==} + '@rollup/rollup-win32-ia32-msvc@4.60.3': + resolution: {integrity: sha512-EEM2gyhBF5MFnI6vMKdX1LAosE627RGBzIoGMdLloPZkXrUN0Ckqgr2Qi8+J3zip/8NVVro3/FjB+tjhZUgUHA==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-gnu@4.60.2': - resolution: {integrity: sha512-qdAzEULD+/hzObedtmV6iBpdL5TIbKVztGiK7O3/KYSf+HIzU257+MX1EXJcyIiDbMAqmbwaufcYPvyRryeZtA==} + '@rollup/rollup-win32-x64-gnu@4.60.3': + resolution: {integrity: sha512-E5Eb5H/DpxaoXH++Qkv28RcUJboMopmdDUALBczvHMf7hNIxaDZqwY5lK12UK1BHacSmvupoEWGu+n993Z0y1A==} cpu: [x64] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.60.2': - resolution: {integrity: sha512-Nd/SgG27WoA9e+/TdK74KnHz852TLa94ovOYySo/yMPuTmpckK/jIF2jSwS3g7ELSKXK13/cVdmg1Z/DaCWKxA==} + '@rollup/rollup-win32-x64-msvc@4.60.3': + resolution: {integrity: sha512-hPt/bgL5cE+Qp+/TPHBqptcAgPzgj46mPcg/16zNUmbQk0j+mOEQV/+Lqu8QRtDV3Ek95Q6FeFITpuhl6OTsAA==} cpu: [x64] os: [win32] @@ -3261,18 +3248,34 @@ packages: resolution: {integrity: sha512-lNKBS4P7RUvf1niojXQWe9bU3gnBUCbST4Dj0pSiyat1N96cXVyHkeE+uGxowD0RrVWhs+kGHiVX3FcmRWF6sA==} engines: {node: '>=18'} + '@sentry-internal/browser-utils@10.52.0': + resolution: {integrity: sha512-x/yEPZdpH6NGQeoeQnV9tj8reAH8twNttiltGZl2o8Rk7sQeUfe7E8yuYP2XbJ2RqyZK5qRS3COrNyMPzf6KFA==} + engines: {node: '>=18'} + '@sentry-internal/feedback@10.51.0': resolution: {integrity: sha512-bCM95bcpphx28e6aU0bwRLxOgwosYsdNzezM1sM0pVOkb0TB3hDFRamramVDK+/Hp1o8qmRxS4c5w/A7YBZGkA==} engines: {node: '>=18'} + '@sentry-internal/feedback@10.52.0': + resolution: {integrity: sha512-5kAn1W8ZvCuHtEHXpq6iRkUMdNCilwww+YxaN2yofVrCivAbB3Ha5JJUMqmWOPW0pC27zGYmoJMIDvG+PczUxA==} + engines: {node: '>=18'} + '@sentry-internal/replay-canvas@10.51.0': resolution: {integrity: sha512-8PW1Pp+Yl3lPwYqhBCr5SgkuhDanu9ZLzUqD2bPKL/ElqbM2eDVIWxq4z4ZzePrmZa6IcCjTv6sVQJ7Z4dLyLA==} engines: {node: '>=18'} + '@sentry-internal/replay-canvas@10.52.0': + resolution: {integrity: sha512-BI5ie4dxPuUJ344CXVSnAxY1xZCbghglPSCIlTOYODpR9so9yo5IZh+Mwspt0oWsUMaxWJiQSNYlbPWi7WDavg==} + engines: {node: '>=18'} + '@sentry-internal/replay@10.51.0': resolution: {integrity: sha512-jCpI5HXSwK6ZT2HX70+mDRciAocHzSiDk4DTgvzV69Wvd+Ei5WLgE+d39eaEPsm8lUC0Ydntb5sJIB6uG9D4bw==} engines: {node: '>=18'} + '@sentry-internal/replay@10.52.0': + resolution: {integrity: sha512-diywyuc/H7VTUR+W5ryVmLF+0X4UP1OskMqb6V8RSAvJHcj2JmIm7uP+Fc6ACTno+b6AUShwT/L4xVXzO6X9Cw==} + engines: {node: '>=18'} + '@sentry/babel-plugin-component-annotate@5.2.1': resolution: {integrity: sha512-QQ9AL5EXIbSK26ObLVtiU6l3tCUdpGSJ/6VwDkPhC3qvtoksSlcoU9Yzm7XC0NBcvu1N2abL5R7gckKGZ4JewQ==} engines: {node: '>= 18'} @@ -3281,6 +3284,10 @@ packages: resolution: {integrity: sha512-Zdc0sKfenxUtW/OGhtJ7xHFN44bXR7YqxJ1zBDzlZfW0nTbeTTUZBq9z5NUw6qdS0Vs/i3V4qzAKTbRKWfqSEA==} engines: {node: '>=18'} + '@sentry/browser@10.52.0': + resolution: {integrity: sha512-ijL9jN86oXwXQWbwhPlEb70ODJSEmjxQEQdnZkC4gDWbjswcwvRsVJPYk+1xl2ir2iZixRIHipVxDcLwian35g==} + engines: {node: '>=18'} + '@sentry/bundler-plugin-core@5.2.1': resolution: {integrity: sha512-uXb+TOZKXxm2STsP3iR70Jh/yYHwlHOvql7w/bUVYgDyiB/1Mv0D6oNGS0kelsgBsBwCq3ngyJYlyNy3oM1pPw==} engines: {node: '>= 18'} @@ -3393,8 +3400,12 @@ packages: resolution: {integrity: sha512-Y45V/YXvVLEXmOdkbD1oG1gkRWFi9guCEGg3PlIlIpRjAbZUrvLGgjRJIc1E7XpSzmOnWbs5BbUxMv4PDaPj2w==} engines: {node: '>=18'} - '@sentry/expo-upload-sourcemaps@8.10.0': - resolution: {integrity: sha512-9nca3zuzeohl77Hspkox0CcpCQz11gvplgJMktD0fVLrHKBLW9/KTtAOBSez7FfXe2e8FbF7cd5/Cb5EHyJjpw==} + '@sentry/core@10.52.0': + resolution: {integrity: sha512-VA/kAqLhkMnRWY2RXdBLyTemR9D4m7MVRy/gyapoq9yvllVPx9WXbvKgnMP2LQp7mFgT/oLFvw58aQKaYTGn3A==} + engines: {node: '>=18'} + + '@sentry/expo-upload-sourcemaps@8.11.0': + resolution: {integrity: sha512-KECCEY//0aGCGNYswLxJfZN1pCb11GvUz5CGLTKg9sXNfo26RGtZwxEWXnbiM1yHhZhpMoCQjPY9nDmKlvZHnQ==} engines: {node: '>=18'} hasBin: true peerDependencies: @@ -3406,8 +3417,8 @@ packages: dotenv: optional: true - '@sentry/node-core@10.51.0': - resolution: {integrity: sha512-VP9DMEzBEuauABrfDHYz/pRYa74M09uRJLz0ls3yel3sKhYHMyCB29ZxbKcciUhD4d33dwgi8DbaPZV2H/wnfQ==} + '@sentry/node-core@10.52.0': + resolution: {integrity: sha512-IG7MBtLRPQ2LuU+kbD14AFZroZgAeUmJQTP1FI/F8n56O31+p+9R703LuBTpvZr6sm+eRYDMWcGYYkfLHRVjwg==} engines: {node: '>=18'} peerDependencies: '@opentelemetry/api': ^1.9.0 @@ -3430,12 +3441,12 @@ packages: '@opentelemetry/semantic-conventions': optional: true - '@sentry/node@10.51.0': - resolution: {integrity: sha512-2yZLRZwS1dKG8/4eOTpGSo/gO/EgmT9aPj6lAzUkRa7bZCTTdW4BraaHU0leX5T94909Qfhbr3W5AVTfDOCKiQ==} + '@sentry/node@10.52.0': + resolution: {integrity: sha512-9+p3KJUk3rHO1HOEZuSknP2RgKCJZONDm4HWgkVDtVBtocb66KLtVlMjc59d2/bWP7tM3wc877tpG30quFfU9g==} engines: {node: '>=18'} - '@sentry/opentelemetry@10.51.0': - resolution: {integrity: sha512-Qc7AlCE4uhB+SvHLqah4RgR1WdY7wmmr/hx9g/prDP9R1ocshmUEMrZK9qjuwaklW7/fmkFCXI8ETxo5L1bHIA==} + '@sentry/opentelemetry@10.52.0': + resolution: {integrity: sha512-Sc7StsvC0bwhMcgDfTRWUIexO5cNzzKUurvUwtpgQUnxO7AzexU3lkY3yHYDsCbWYAEQMXAgQYQtbcqoh+Ie7g==} engines: {node: '>=18'} peerDependencies: '@opentelemetry/api': ^1.9.0 @@ -3443,8 +3454,8 @@ packages: '@opentelemetry/sdk-trace-base': ^1.30.1 || ^2.1.0 '@opentelemetry/semantic-conventions': ^1.39.0 - '@sentry/react-native@8.10.0': - resolution: {integrity: sha512-Pfr7h1unqMsE87UMwaUIZ26VjX7SSsitBLpK4gHeIwYmuXn+qfdYUmme6RnoLlL5IPzu8pCLoRNCvdAJy6eTgw==} + '@sentry/react-native@8.11.0': + resolution: {integrity: sha512-cLksJuM5lR447kifAsVgNrY3s6cG2mWEP1ZMPuYKJ0NCtRvpeA09/QmwN9YXbViSftHxyDf+hDvE6bI444chdg==} hasBin: true peerDependencies: expo: '>=49.0.0' @@ -3460,6 +3471,12 @@ packages: peerDependencies: react: ^19.2.5 + '@sentry/react@10.52.0': + resolution: {integrity: sha512-2m72QCsja2cJJHD0ALxRnVt0qMEC2FV4LSi6AAiEdEG4lTb6mgcxavx5pJrW90jE+6dMGPbUz4q8c9vi4jh1qQ==} + engines: {node: '>=18'} + peerDependencies: + react: ^19.2.5 + '@sentry/rollup-plugin@5.2.1': resolution: {integrity: sha512-LKJyL4fzcHnHExipVN0/QinhBNoGZt+UXg8xJaqc6MwOolOhxHW0ii2hu1OZsiOhX0+r9MK7T+a7Sx0F0bzdMQ==} engines: {node: '>= 18'} @@ -3503,69 +3520,69 @@ packages: '@standard-schema/spec@1.1.0': resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} - '@tailwindcss/node@4.2.4': - resolution: {integrity: sha512-Ai7+yQPxz3ddrDQzFfBKdHEVBg0w3Zl83jnjuwxnZOsnH9pGn93QHQtpU0p/8rYWxvbFZHneni6p1BSLK4DkGA==} + '@tailwindcss/node@4.3.0': + resolution: {integrity: sha512-aFb4gUhFOgdh9AXo4IzBEOzBkkAxm9VigwDJnMIYv3lcfXCJVesNfbEaBl4BNgVRyid92AmdviqwBUBRKSeY3g==} - '@tailwindcss/oxide-android-arm64@4.2.4': - resolution: {integrity: sha512-e7MOr1SAn9U8KlZzPi1ZXGZHeC5anY36qjNwmZv9pOJ8E4Q6jmD1vyEHkQFmNOIN7twGPEMXRHmitN4zCMN03g==} + '@tailwindcss/oxide-android-arm64@4.3.0': + resolution: {integrity: sha512-TJPiq67tKlLuObP6RkwvVGDoxCMBVtDgKkLfa/uyj7/FyxvQwHS+UOnVrXXgbEsfUaMgiVvC4KbJnRr26ho4Ng==} engines: {node: '>= 20'} cpu: [arm64] os: [android] - '@tailwindcss/oxide-darwin-arm64@4.2.4': - resolution: {integrity: sha512-tSC/Kbqpz/5/o/C2sG7QvOxAKqyd10bq+ypZNf+9Fi2TvbVbv1zNpcEptcsU7DPROaSbVgUXmrzKhurFvo5eDg==} + '@tailwindcss/oxide-darwin-arm64@4.3.0': + resolution: {integrity: sha512-oMN/WZRb+SO37BmUElEgeEWuU8E/HXRkiODxJxLe1UTHVXLrdVSgfaJV7pSlhRGMSOiXLuxTIjfsF3wYvz8cgQ==} engines: {node: '>= 20'} cpu: [arm64] os: [darwin] - '@tailwindcss/oxide-darwin-x64@4.2.4': - resolution: {integrity: sha512-yPyUXn3yO/ufR6+Kzv0t4fCg2qNr90jxXc5QqBpjlPNd0NqyDXcmQb/6weunH/MEDXW5dhyEi+agTDiqa3WsGg==} + '@tailwindcss/oxide-darwin-x64@4.3.0': + resolution: {integrity: sha512-N6CUmu4a6bKVADfw77p+iw6Yd9Q3OBhe0veaDX+QazfuVYlQsHfDgxBrsjQ/IW+zywL8mTrNd0SdJT/zgtvMdA==} engines: {node: '>= 20'} cpu: [x64] os: [darwin] - '@tailwindcss/oxide-freebsd-x64@4.2.4': - resolution: {integrity: sha512-BoMIB4vMQtZsXdGLVc2z+P9DbETkiopogfWZKbWwM8b/1Vinbs4YcUwo+kM/KeLkX3Ygrf4/PsRndKaYhS8Eiw==} + '@tailwindcss/oxide-freebsd-x64@4.3.0': + resolution: {integrity: sha512-zDL5hBkQdH5C6MpqbK3gQAgP80tsMwSI26vjOzjJtNCMUo0lFgOItzHKBIupOZNQxt3ouPH7RPhvNhiTfCe5CQ==} engines: {node: '>= 20'} cpu: [x64] os: [freebsd] - '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.4': - resolution: {integrity: sha512-7pIHBLTHYRAlS7V22JNuTh33yLH4VElwKtB3bwchK/UaKUPpQ0lPQiOWcbm4V3WP2I6fNIJ23vABIvoy2izdwA==} + '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.0': + resolution: {integrity: sha512-R06HdNi7A7OEoMsf6d4tjZ71RCWnZQPHj2mnotSFURjNLdBC+cIgXQ7l81CqeoiQftjf6OOblxXMInMgN2VzMA==} engines: {node: '>= 20'} cpu: [arm] os: [linux] - '@tailwindcss/oxide-linux-arm64-gnu@4.2.4': - resolution: {integrity: sha512-+E4wxJ0ZGOzSH325reXTWB48l42i93kQqMvDyz5gqfRzRZ7faNhnmvlV4EPGJU3QJM/3Ab5jhJ5pCRUsKn6OQw==} + '@tailwindcss/oxide-linux-arm64-gnu@4.3.0': + resolution: {integrity: sha512-qTJHELX8jetjhRQHCLilkVLmybpzNQAtaI/gaoVoidn/ufbNDbAo8KlK2J+yPoc8wQxvDxCmh/5lr8nC1+lTbg==} engines: {node: '>= 20'} cpu: [arm64] os: [linux] libc: [glibc] - '@tailwindcss/oxide-linux-arm64-musl@4.2.4': - resolution: {integrity: sha512-bBADEGAbo4ASnppIziaQJelekCxdMaxisrk+fB7Thit72IBnALp9K6ffA2G4ruj90G9XRS2VQ6q2bCKbfFV82g==} + '@tailwindcss/oxide-linux-arm64-musl@4.3.0': + resolution: {integrity: sha512-Z6sukiQsngnWO+l39X4pPbiWT81IC+PLKF+PHxIlyZbGNb9MODfYlXEVlFvej5BOZInWX01kVyzeLvHsXhfczQ==} engines: {node: '>= 20'} cpu: [arm64] os: [linux] libc: [musl] - '@tailwindcss/oxide-linux-x64-gnu@4.2.4': - resolution: {integrity: sha512-7Mx25E4WTfnht0TVRTyC00j3i0M+EeFe7wguMDTlX4mRxafznw0CA8WJkFjWYH5BlgELd1kSjuU2JiPnNZbJDA==} + '@tailwindcss/oxide-linux-x64-gnu@4.3.0': + resolution: {integrity: sha512-DRNdQRpSGzRGfARVuVkxvM8Q12nh19l4BF/G7zGA1oe+9wcC6saFBHTISrpIcKzhiXtSrlSrluCfvMuledoCTQ==} engines: {node: '>= 20'} cpu: [x64] os: [linux] libc: [glibc] - '@tailwindcss/oxide-linux-x64-musl@4.2.4': - resolution: {integrity: sha512-2wwJRF7nyhOR0hhHoChc04xngV3iS+akccHTGtz965FwF0up4b2lOdo6kI1EbDaEXKgvcrFBYcYQQ/rrnWFVfA==} + '@tailwindcss/oxide-linux-x64-musl@4.3.0': + resolution: {integrity: sha512-Z0IADbDo8bh6I7h2IQMx601AdXBLfFpEdUotft86evd/8ZPflZe9COPO8Q1vw+pfLWIUo9zN/JGZvwuAJqduqg==} engines: {node: '>= 20'} cpu: [x64] os: [linux] libc: [musl] - '@tailwindcss/oxide-wasm32-wasi@4.2.4': - resolution: {integrity: sha512-FQsqApeor8Fo6gUEklzmaa9994orJZZDBAlQpK2Mq+DslRKFJeD6AjHpBQ0kZFQohVr8o85PPh8eOy86VlSCmw==} + '@tailwindcss/oxide-wasm32-wasi@4.3.0': + resolution: {integrity: sha512-HNZGOUxEmElksYR7S6sC5jTeNGpobAsy9u7Gu0AskJ8/20FR9GqebUyB+HBcU/ax6BHuiuJi+Oda4B+YX6H1yA==} engines: {node: '>=14.0.0'} cpu: [wasm32] bundledDependencies: @@ -3576,24 +3593,24 @@ packages: - '@emnapi/wasi-threads' - tslib - '@tailwindcss/oxide-win32-arm64-msvc@4.2.4': - resolution: {integrity: sha512-L9BXqxC4ToVgwMFqj3pmZRqyHEztulpUJzCxUtLjobMCzTPsGt1Fa9enKbOpY2iIyVtaHNeNvAK8ERP/64sqGQ==} + '@tailwindcss/oxide-win32-arm64-msvc@4.3.0': + resolution: {integrity: sha512-Pe+RPVTi1T+qymuuRpcdvwSVZjnll/f7n8gBxMMh3xLTctMDKqpdfGimbMyioqtLhUYZxdJ9wGNhV7MKHvgZsQ==} engines: {node: '>= 20'} cpu: [arm64] os: [win32] - '@tailwindcss/oxide-win32-x64-msvc@4.2.4': - resolution: {integrity: sha512-ESlKG0EpVJQwRjXDDa9rLvhEAh0mhP1sF7sap9dNZT0yyl9SAG6T7gdP09EH0vIv0UNTlo6jPWyujD6559fZvw==} + '@tailwindcss/oxide-win32-x64-msvc@4.3.0': + resolution: {integrity: sha512-Mvrf2kXW/yeW/OTezZlCGOirXRcUuLIBx/5Y12BaPM7wJoryG6dfS/NJL8aBPqtTEx/Vm4T4vKzFUcKDT+TKUA==} engines: {node: '>= 20'} cpu: [x64] os: [win32] - '@tailwindcss/oxide@4.2.4': - resolution: {integrity: sha512-9El/iI069DKDSXwTvB9J4BwdO5JhRrOweGaK25taBAvBXyXqJAX+Jqdvs8r8gKpsI/1m0LeJLyQYTf/WLrBT1Q==} + '@tailwindcss/oxide@4.3.0': + resolution: {integrity: sha512-F7HZGBeN9I0/AuuJS5PwcD8xayx5ri5GhjYUDBEVYUkexyA/giwbDNjRVrxSezE3T250OU2K/wp/ltWx3UOefg==} engines: {node: '>= 20'} - '@tailwindcss/vite@4.2.4': - resolution: {integrity: sha512-pCvohwOCspk3ZFn6eJzrrX3g4n2JY73H6MmYC87XfGPyTty4YsCjYTMArRZm/zOI8dIt3+EcrLHAFPe5A4bgtw==} + '@tailwindcss/vite@4.3.0': + resolution: {integrity: sha512-t6J3OrB5Fc0ExuhohouH0fWUGMYL6PTLhW+E7zIk/pdbnJARZDCwjBznFnkh5ynRnIRSI4YjtTH0t6USjJISrw==} peerDependencies: vite: ^5.2.0 || ^6 || ^7 || ^8 @@ -3625,44 +3642,44 @@ packages: '@types/react': ^18.0.0 || ^19.0.0 '@types/react-dom': ^18.0.0 || ^19.0.0 react: ^19.2.5 - react-dom: ^19.2.5 + react-dom: ^19.2.6 peerDependenciesMeta: '@types/react': optional: true '@types/react-dom': optional: true - '@tootallnate/once@2.0.0': - resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==} + '@tootallnate/once@2.0.1': + resolution: {integrity: sha512-HqmEUIGRJ5fSXchkVgR5F7qn48bDBzv0kWj/Kfu5e6uci4UlEeng4331LnBkWffb++Ei3FOVLxo8JJWMFBDMeQ==} engines: {node: '>= 10'} - '@turbo/darwin-64@2.9.8': - resolution: {integrity: sha512-zU1P95ygDpsQ+2QHh7CVTqvYwi9UBlhKWzoIyUnP3vUoge7H9SQEzrd8dj+XcTrslAp9Db3vIBcXtMVoTEYDnA==} + '@turbo/darwin-64@2.9.12': + resolution: {integrity: sha512-eu3eFRmE9NjgZ0wPdRJ44l+LGSeIky+tz5ZQd8zQkw/Yqi+BM7wq+8nbabeoiVUcICi/IZweMOKl/MCmkrd1+g==} cpu: [x64] os: [darwin] - '@turbo/darwin-arm64@2.9.8': - resolution: {integrity: sha512-nKRFI5ZhCGUi4eXNlrojzWcT/CehMj0raot1WE4lw5qf66ZxZHbRbBqcwNEy+ZLY7RkJJRY+TaU89fuj3BcgGg==} + '@turbo/darwin-arm64@2.9.12': + resolution: {integrity: sha512-RUkAE404z/J8NsyrUosMcBaXT6M4bRFxTQrmkDQBLQVXaC8Jl0e9bMvYDSX0GW7Ffm2m3j9y7RXgR1foeUAM9w==} cpu: [arm64] os: [darwin] - '@turbo/linux-64@2.9.8': - resolution: {integrity: sha512-Wf/kQpVDCaWM3P5d6lKvJnqjYn/ofUBGbT4h4vRFrdC4N6B/nsun03S2kQNJJMXpXg39woeS4CI367RMU3/OAg==} + '@turbo/linux-64@2.9.12': + resolution: {integrity: sha512-InIUtH7cw/vqXNX1Gr7QgWfmw3ct08pV5CpfdEOR48z2u2rzdmpIuk00B/Q2xCb0PMWtKgiMQynfuphmEuUyTQ==} cpu: [x64] os: [linux] - '@turbo/linux-arm64@2.9.8': - resolution: {integrity: sha512-v6S3HuKVoa9CEx16IxKj1i/+crxXx22A9O80zW1350zyUlcX0T/zLOxVf1k+ruK/7ssXnDJVg8uSYOxlYRedlA==} + '@turbo/linux-arm64@2.9.12': + resolution: {integrity: sha512-lC6nD//Xh67fmJM0LKaLsg74Wry0aYrgMklpiNgCbUaMdPIOqj0A00iri3NU7Lb7pZHx8ViisgpeDKlpSgFUCA==} cpu: [arm64] os: [linux] - '@turbo/windows-64@2.9.8': - resolution: {integrity: sha512-JaefWOJNBazDylAn3f+lLB34XMNu8nEBbgPRP/Ewysg81cBubGfcyyyzpQOGVuMwfaqdNAE/kitG7w3AbJn9/g==} + '@turbo/windows-64@2.9.12': + resolution: {integrity: sha512-conYri8VUl72JOdYnLDPYwzqbPcY5ECoHmo9FWoKznemhaAIilj4maHqs9Uar0aKfNoZIULniy+6iWaLtLO34A==} cpu: [x64] os: [win32] - '@turbo/windows-arm64@2.9.8': - resolution: {integrity: sha512-Or6ljjB4TiiwCdVKDYWew0SokQ9kep5zruL8P3nbum9WdkH5XA41rQID4Ulc215Z+R3DrB+qXSHPsJjU3/n2ng==} + '@turbo/windows-arm64@2.9.12': + resolution: {integrity: sha512-XoR4bsg62/L/esRVcmoMESEiNZ36+YmyjYGLpoqk8nwMgXzzVjNOgX0lRSz5w/U/ajLGv3nhMsS0Q2QOdvp2AQ==} cpu: [arm64] os: [win32] @@ -3762,6 +3779,9 @@ packages: '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + '@types/estree@1.0.9': + resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} + '@types/geojson@7946.0.16': resolution: {integrity: sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==} @@ -3798,12 +3818,15 @@ packages: '@types/mysql@2.15.27': resolution: {integrity: sha512-YfWiV16IY0OeBfBCk8+hXKmdTKrKlwKN1MNKAPBu5JYxLwBEZl7QzeEpGnlZb3VMGJrrGmB84gXiH+ofs/TezA==} - '@types/node@22.19.17': - resolution: {integrity: sha512-wGdMcf+vPYM6jikpS/qhg6WiqSV/OhG+jeeHT/KlVqxYfD40iYJf9/AE1uQxVWFvU7MipKRkRv8NSHiCGgPr8Q==} + '@types/node@22.19.18': + resolution: {integrity: sha512-9v00a+dn2yWVsYDEunWC4g/TcRKVq3r8N5FuZp7u0SGrPvdN9c2yXI9bBuf5Fl0hNCb+QTIePTn5pJs2pwBOQQ==} '@types/node@25.6.0': resolution: {integrity: sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==} + '@types/node@25.6.2': + resolution: {integrity: sha512-sokuT28dxf9JT5Kady1fsXOvI4HVpjZa95NKT5y9PNTIrs2AsobR4GFAA90ZG8M+nxVRLysCXsVj6eGC7Vbrlw==} + '@types/nodemailer@8.0.0': resolution: {integrity: sha512-fyf8jWULsCo0d0BuoQ75i6IeoHs47qcqxWc7yUdUcV0pOZGjUTTOvwdG1PRXUDqN/8A64yQdQdnA2pZgcdi+cA==} @@ -3842,67 +3865,67 @@ packages: '@types/yargs@17.0.35': resolution: {integrity: sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==} - '@typescript-eslint/eslint-plugin@8.59.1': - resolution: {integrity: sha512-BOziFIfE+6osHO9FoJG4zjoHUcvI7fTNBSpdAwrNH0/TLvzjsk2oo8XSSOT2HhqUyhZPfHv4UOffoJ9oEEQ7Ag==} + '@typescript-eslint/eslint-plugin@8.59.2': + resolution: {integrity: sha512-j/bwmkBvHUtPNxzuWe5z6BEk3q54YRyGlBXkSsmfoih7zNrBvl5A9A98anlp/7JbyZcWIJ8KXo/3Tq/DjFLtuQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^8.59.1 + '@typescript-eslint/parser': ^8.59.2 eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/parser@8.59.1': - resolution: {integrity: sha512-HDQH9O/47Dxi1ceDhBXdaldtf/WV9yRYMjbjCuNk3qnaTD564qwv61Y7+gTxwxRKzSrgO5uhtw584igXVuuZkA==} + '@typescript-eslint/parser@8.59.2': + resolution: {integrity: sha512-plR3pp6D+SSUn1HM7xvSkx12/DhoHInI2YF35KAcVFNZvlC0gtrWqx7Qq1oH2Ssgi0vlFRCTbP+DZc7B9+TtsQ==} 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.59.1': - resolution: {integrity: sha512-+MuHQlHiEr00Of/IQbE/MmEoi44znZHbR/Pz7Opq4HryUOlRi+/44dro9Ycy8Fyo+/024IWtw8m4JUMCGTYxDg==} + '@typescript-eslint/project-service@8.59.2': + resolution: {integrity: sha512-+2hqvEkeyf/0FBor67duF0Ll7Ot8jyKzDQOSrxazF/danillRq2DwR9dLptsXpoZQqxE1UisSmoZewrlPas9Vw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/scope-manager@8.59.1': - resolution: {integrity: sha512-LwuHQI4pDOYVKvmH2dkaJo6YZCSgouVgnS/z7yBPKBMvgtBvyLqiLy9Z6b7+m/TRcX1NFYUqZetI5Y+aT4GEfg==} + '@typescript-eslint/scope-manager@8.59.2': + resolution: {integrity: sha512-JzfyEpEtOU89CcFSwyNS3mu4MLvLSXqnmX05+aKBDM+TdR5jzcGOEBwxwGNxrEQ7p/z6kK2WyioCGBf2zZBnvg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/tsconfig-utils@8.59.1': - resolution: {integrity: sha512-/0nEyPbX7gRsk0Uwfe4ALwwgxuA66d/l2mhRDNlAvaj4U3juhUtJNq0DsY8M2AYwwb9rEq2hrC3IcIcEt++iJA==} + '@typescript-eslint/tsconfig-utils@8.59.2': + resolution: {integrity: sha512-BKK4alN7oi4C/zv4VqHQ+uRU+lTa6JGIZ7s1juw7b3RHo9OfKB+bKX3u0iVZetdsUCBBkSbdWbarJbmN0fTeSw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/type-utils@8.59.1': - resolution: {integrity: sha512-klWPBR2ciQHS3f++ug/mVnWKPjBUo7icEL3FAO1lhAR1Z1i5NQYZ1EannMSRYcq5qCv5wNALlXr6fksRHyYl7w==} + '@typescript-eslint/type-utils@8.59.2': + resolution: {integrity: sha512-nhqaj1nmTdVVl/BP5omXNRGO38jn5iosis2vbdmupF2txCf8ylWT8lx+JlvMYYVqzGVKtjojUFoQ3JRWK+mfzQ==} 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.59.1': - resolution: {integrity: sha512-ZDCjgccSdYPw5Bxh+my4Z0lJU96ZDN7jbBzvmEn0FZx3RtU1C7VWl6NbDx94bwY3V5YsgwRzJPOgeY2Q/nLG8A==} + '@typescript-eslint/types@8.59.2': + resolution: {integrity: sha512-e82GVOE8Ps3E++Egvb6Y3Dw0S10u8NkQ9KXmtRhCWJJ8kDhOJTvtMAWnFL16kB1583goCWXsr0NieKCZMs2/0Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@8.59.1': - resolution: {integrity: sha512-OUd+vJS05sSkOip+BkZ/2NS8RMxrAAJemsC6vU3kmfLyeaJT0TftHkV9mcx2107MmsBVXXexhVu4F0TZXyMl4g==} + '@typescript-eslint/typescript-estree@8.59.2': + resolution: {integrity: sha512-o0XPGNwcWw+FIwStOWn+BwBuEmL6QXP0rsvAFg7ET1dey1Nr6Wb1ac8p5HEsK0ygO/6mUxlk+YWQD9xcb/nnXg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/utils@8.59.1': - resolution: {integrity: sha512-3pIeoXhCeYH9FSCBI8P3iNwJlGuzPlYKkTlen2O9T1DSeeg8UG8jstq6BLk+Mda0qup7mgk4z4XL4OzRaxZ8LA==} + '@typescript-eslint/utils@8.59.2': + resolution: {integrity: sha512-Juw3EinkXqjaffxz6roowvV7GZT/kET5vSKKZT6upl5TXdWkLkYmNPXwDDL2Vkt2DPn0nODIS4egC/0AGxKo/Q==} 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.59.1': - resolution: {integrity: sha512-LdDNl6C5iJExcM0Yh0PwAIBb9PrSiCsWamF/JyEZawm3kFDnRoaq3LGE4bpyRao/fWeGKKyw7icx0YxrLFC5Cg==} + '@typescript-eslint/visitor-keys@8.59.2': + resolution: {integrity: sha512-NwjLUnGy8/Zfx23fl50tRC8rYaYnM52xNRYFAXvmiil9yh1+K6aRVQMnzW6gQB/1DLgWt977lYQn7C+wtgXZiA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@ungap/structured-clone@1.3.0': - resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} + '@ungap/structured-clone@1.3.1': + resolution: {integrity: sha512-mUFwbeTqrVgDQxFveS+df2yfap6iuP20NAKAsBt5jDEoOTDew+zwLAOilHCeQJOVSvmgCX4ogqIrA0mnyr08yQ==} '@vitejs/plugin-basic-ssl@2.3.0': resolution: {integrity: sha512-bdyo8rB3NnQbikdMpHaML9Z1OZPBu6fFOBo+OtxsBlvMJtysWskmBcnbIDhUqgC8tcxNv/a+BcV5U+2nQMm1OQ==} @@ -4134,12 +4157,12 @@ packages: peerDependencies: '@babel/core': ^7.0.0 || ^8.0.0-0 - babel-preset-expo@55.0.19: - resolution: {integrity: sha512-IaxT7xremfrW2HqtG7gWI7TUSJke/V+zDW1whLpmO06ZdKOfB5Qup7oICqBWqfbcBW3h57llWOMAn1cycvbsgQ==} + babel-preset-expo@55.0.21: + resolution: {integrity: sha512-anXoUZBcxydLdVs2L+r3bWKGUvZv2FtgOl8xRJ12i/YfKICBpwTGZWSTiEYTqBByZ6GkA3mE9+3TW97X2ocFTQ==} peerDependencies: '@babel/runtime': ^7.20.0 expo: '*' - expo-widgets: ^55.0.15 + expo-widgets: ^55.0.17 react-refresh: '>=0.14.0 <1.0.0' peerDependenciesMeta: '@babel/runtime': @@ -4168,8 +4191,8 @@ packages: base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - baseline-browser-mapping@2.10.25: - resolution: {integrity: sha512-QO/VHsXCQdnzADMfmkeOPvHdIAkoB7i0/rGjINPJEetLx75hNttVWGQ/jycHUDP9zZ9rupbm60WRxcwViB0MiA==} + baseline-browser-mapping@2.10.29: + resolution: {integrity: sha512-Asa2krT+XTPZINCS+2QcyS8WTkObE77RwkydwF7h6DmnKqbvlalz93m/dnphUyCa6SWSP51VgtEUf2FN+gelFQ==} engines: {node: '>=6.0.0'} hasBin: true @@ -4215,8 +4238,8 @@ packages: brace-expansion@1.1.14: resolution: {integrity: sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==} - brace-expansion@5.0.5: - resolution: {integrity: sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==} + brace-expansion@5.0.6: + resolution: {integrity: sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==} engines: {node: 18 || 20 || >=22} braces@3.0.3: @@ -4265,8 +4288,8 @@ packages: resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} engines: {node: '>=10'} - caniuse-lite@1.0.30001791: - resolution: {integrity: sha512-yk0l/YSrOnFZk3UROpDLQD9+kC1l4meK/wed583AXrzoarMGJcbRi2Q4RaUYbKxYAsZ8sWmaSa/DsLmdBeI1vQ==} + caniuse-lite@1.0.30001792: + resolution: {integrity: sha512-hVLMUZFgR4JJ6ACt1uEESvQN1/dBVqPAKY0hgrV70eN3391K6juAfTjKZLKvOMsx8PxA7gsY1/tLMMTcfFLLpw==} chai@6.2.2: resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} @@ -4722,8 +4745,8 @@ packages: ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} - electron-to-chromium@1.5.349: - resolution: {integrity: sha512-QsWVGyRuY07Aqb234QytTfwd5d9AJlfNIQ5wIOl1L+PZDzI9d9+Fn0FRale/QYlFxt/bUnB0/nLd1jFPGxGK1A==} + electron-to-chromium@1.5.353: + resolution: {integrity: sha512-kOrWphBi8TOZyiJZqsgqIle0lw+tzmnQK83pV9dZUd01Nm2POECSyFQMAuarzZdYqQW7FH9RaYOuaRo3h+bQ3w==} emittery@0.13.1: resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==} @@ -4746,8 +4769,8 @@ packages: end-of-stream@1.4.5: resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} - enhanced-resolve@5.21.0: - resolution: {integrity: sha512-otxSQPw4lkOZWkHpB3zaEQs6gWYEsmX4xQF68ElXC/TWvGxGMSGOvoNbaLXm6/cS/fSfHtsEdw90y20PCd+sCA==} + enhanced-resolve@5.21.2: + resolution: {integrity: sha512-xe9vQb5kReirPUxgQrXA3ihgbCqssmTiM7cOZ+Gzu+VeGWgpV98lLZvp0dl4yriyAePcewxGUs9UpKD8PET9KQ==} engines: {node: '>=10.13.0'} entities@4.5.0: @@ -4922,15 +4945,15 @@ packages: peerDependencies: expo: '*' - expo-asset@55.0.16: - resolution: {integrity: sha512-5IJyfJtYqvKGg04NKGQWiCIoK/fULDL9m15mXPPyfabD1jsToVj2hnWmo1r2SWNNmMwtQxi6jTpcGwVo2nLDxg==} + expo-asset@55.0.17: + resolution: {integrity: sha512-pK9HHJuFqjE8kDUcbMFsZj3Cz8WdXpvZHZmYl7ouFQp59P83BvHln6VnqPDGlO+/4929G0Lm8ZUzbONuNRhi9w==} peerDependencies: expo: '*' react: ^19.2.5 react-native: '*' - expo-constants@55.0.15: - resolution: {integrity: sha512-w394fcZLJjeKN+9ZnJzL/HiarE1nwZFDa+3S9frevh6Ur+MAAs9QDrcXhDrV8T3xqRzzYaqsP6Z8TFZ4efWN1A==} + expo-constants@55.0.16: + resolution: {integrity: sha512-Z15/No94UHoogD+pulxjudGAeOHTEIWZgb/vnX48Wx5D+apWTeCbnKxQZZtGQlosvduYL5kaic2/W8U+NHfBQQ==} peerDependencies: expo: '*' react-native: '*' @@ -4940,13 +4963,13 @@ packages: peerDependencies: expo: '*' - expo-dev-client@55.0.30: - resolution: {integrity: sha512-guDTu5MsI7C5TWi4d6PwG6CsfPeEDVu9V0eljwOLUC96MAwzc0Kw9/IgqGywrom5zBk8JCXv1dAZbUO+Ik83MQ==} + expo-dev-client@55.0.32: + resolution: {integrity: sha512-rfZ0Xpgbw3RPymkivvLSQ2Koqefj+oVOReqNLN3JXDlqdC2jOr3MCqfTaJs5VFNzFKk7pOPyE60jh03UdvsHCQ==} peerDependencies: expo: '*' - expo-dev-launcher@55.0.31: - resolution: {integrity: sha512-jCWpW8+hzyv7xI4fIx+bGg84PQGzohNnBXdyazrU0J0BZCseguNCaxuU9LTcNTP/PGMJxZFEUFmU/Siojtdl/w==} + expo-dev-launcher@55.0.33: + resolution: {integrity: sha512-WZsTtyEVgCBMj3vlgbDSKbYbUbAwijNhJY9jBqqlmbPLHtLE+Wc6nCTafb0dWY6+Si+afF98lvPyz6WSAu59uA==} peerDependencies: expo: '*' @@ -4955,38 +4978,38 @@ packages: peerDependencies: expo: '*' - expo-dev-menu@55.0.26: - resolution: {integrity: sha512-NXZumkYIycz77IY/o7qI9Ow+qb/qkq6aQ4eqO7tUJMCyBNVIfwfrb3Qm9ANhZlDT0yrk8FcH7zYmtoJbfwRr1Q==} + expo-dev-menu@55.0.27: + resolution: {integrity: sha512-Il+kkIXlPDfZ/Z3ZquV1r5niECEByJObUMkB24c0B4N4693f0SDoKyyaRqcGRsRCVXW9r0eAoTeEnXl1revQdA==} peerDependencies: expo: '*' - expo-device@55.0.15: - resolution: {integrity: sha512-vXy4U/IeYI+zHGG45Ap6J7EuyQmkstyo8I+/5YGr5q2zmqLBo6SWE62wii8i9hLHheHn6AtF9UPrSWAREJrE8A==} + expo-device@55.0.16: + resolution: {integrity: sha512-o6eQjO2reoniXpos0FnPcrAVMYUfFPcIUdMRUUpKwQys7cmTJBjJLbOo+SuctVXUrsHUm6zyoKI7nX3C3lpqJw==} peerDependencies: expo: '*' - expo-file-system@55.0.17: - resolution: {integrity: sha512-d27K1cagUOt2BwxwPka9KW8Znu5kN1tnairozCzzCRZviZFtWnBxwFuJ3KU6MAbav/9UhSMkp5Ve/oZ+SR0UgQ==} + expo-file-system@55.0.19: + resolution: {integrity: sha512-c4smCbMqELLI3YQrGpw21MwZIREXM2e53vQD/+KWQcae1q+hgw8J2TroEqcQ/jVOtFpZYVvyVfgu4HDKNEKmNw==} peerDependencies: expo: '*' react-native: '*' - expo-font@55.0.6: - resolution: {integrity: sha512-x9czUA3UQWjIwa0ZUEs/eWJNqB4mAue/m4ltESlNPLZhHL0nWWqIfsyHmklTLFH7mVfcHSJvew6k+pR2FE1zVw==} + expo-font@55.0.7: + resolution: {integrity: sha512-oH39Xb+3i6Y69b7YRP+P+5WLx7621t+ep/RAgLwJJYpTjs7CnSohUG+873rEtqsTAuQGi63ms7x9ZeHj1E9LYw==} peerDependencies: expo: '*' react: ^19.2.5 react-native: '*' - expo-glass-effect@55.0.10: - resolution: {integrity: sha512-5kL/jATvgJWdrqPdxixrECJqD2l8cfQ4ALr1DK7qi9XkyI97ejXvUjB2VsfEePNy3Fg+/VwzA3n3L7Nv3tAPkw==} + expo-glass-effect@55.0.11: + resolution: {integrity: sha512-wqq7GUOqSkfoFJzreZvBG0jzjsq5c582m3glhWSjcmIuByxXXWp6j6GY6hyFuYKzpOXhbuvusVxGCQi0yWnp3g==} peerDependencies: expo: '*' react: ^19.2.5 react-native: '*' - expo-image@55.0.9: - resolution: {integrity: sha512-+NVgWv+tr7a6EpBEaIIVVp+XfruRA2JL5xOxvd6ajvFGdH0rOhagwX1m1piAII6w7sh6uAnBr8X+fDZsav7B2w==} + expo-image@55.0.10: + resolution: {integrity: sha512-We+vq/Z8jy8zmGxcOP8vrhiWkkwyXFdSks8cSlPi0bpu6D0Ei6l9Nj2xHWCD+yoENh92aCEe1+QRujAwXbogGA==} peerDependencies: expo: '*' react: ^19.2.5 @@ -4999,14 +5022,14 @@ packages: expo-json-utils@55.0.2: resolution: {integrity: sha512-QJMOZOPOG7CTnKcrdVaiummn2va1MCO56z++eyWkDv3GBRODldM6MFMDf/jTREWthFc2Nxo6TuyWRrEV9S6n/Q==} - expo-keep-awake@55.0.7: - resolution: {integrity: sha512-QBWOEu8FkPBGYc0h0rsCkSTMJNBEKgzVsmLuQpO7V79V9sPR052k3Iiu/G8Kzmny2enyHYYed8RY+CUsip/SeQ==} + expo-keep-awake@55.0.8: + resolution: {integrity: sha512-PfIpMfM+STOBwkR5XOE+yVtER86c44MD+W8QD8JxuO0sT9pF7Y1SJYakWlpvX8xsGA+bjKLxftm9403s9kQhKA==} peerDependencies: expo: '*' react: ^19.2.5 - expo-linking@55.0.14: - resolution: {integrity: sha512-ZSqOvJyEquf04M5/ZpQo2diK9QRnNrzgqZo7p8gzxaPPHxP6IyUJnmcd12qT+dTxnRTVmUpxFQVHHWbvwPNIwQ==} + expo-linking@55.0.15: + resolution: {integrity: sha512-/RQh2vkNqV8Bim9Owm/evVqn2fqTvCDYHkpYPoSKbLAdydSGdHC2xZNw7Odl4wu1i1/3L4Xz//LKd3NsPWYWBQ==} peerDependencies: react: ^19.2.5 react-native: '*' @@ -5017,8 +5040,8 @@ packages: expo: '*' react: ^19.2.5 - expo-location@55.1.8: - resolution: {integrity: sha512-mEExFf84nmWLwi14GFfUsFLrCm10gbcqFn9EPXpuruQ28YMtJWgCD+jJtESYPQkYF44N21fVok3T28fLuCqydA==} + expo-location@55.1.9: + resolution: {integrity: sha512-PIH9/qeyhtGh190FyIJNZYHXZOoi42SbVHY9IoTMBmqWLHf1BJyGhPpFlaLBSCjxObqfVZmrWsN5dtjueSwYQA==} peerDependencies: expo: '*' @@ -5027,12 +5050,12 @@ packages: peerDependencies: expo: '*' - expo-modules-autolinking@55.0.19: - resolution: {integrity: sha512-rHO1NZC/bxcKTLzkn6WYm9ErzS6qp7Kgb1NM2YxXJAYRWHwW/M7NZXyj6swWiKxyhRpcdoppRpjrz1sBuYGAjg==} + expo-modules-autolinking@55.0.21: + resolution: {integrity: sha512-P9KsJgOwI7JVwxmGfRvcXkXO4LNRvHRdWmb4ukLmX15G/vZ7b6SM17yiYkPceWq1F5KeeZ11KFjEcl0y17xy7w==} hasBin: true - expo-modules-core@55.0.24: - resolution: {integrity: sha512-1FztZjelwf3xQZpD6+LFo6IKjnGF/PMVXYkv9aC3EybMl/ZbXji35cfhy9W5uR/bwQ7L+SVqvd5A00XOoIiO8Q==} + expo-modules-core@55.0.25: + resolution: {integrity: sha512-yXpfg7aHLbuqoXocK34Vua6Aey5SCyqLygAsXAMbul9P8vfBjLpaOPiTJ5cLVF7Drfq8ownqVJO6qpGEtZ6GOw==} peerDependencies: react: ^19.2.5 react-native: '*' @@ -5055,18 +5078,18 @@ packages: react: ^19.2.5 react-native: '*' - expo-router@55.0.13: - resolution: {integrity: sha512-cIBR5RmQtbr+b535mlbMhmm7lweVZXFtjzJOgJTutoxIApRztl816kFRFNesnVyqQ0LZrEU0a6vqa3i0wdlRQw==} + expo-router@55.0.14: + resolution: {integrity: sha512-rOn/wosp2hAPM+O2o41hnarbP5Zqv9UkHWa31KoSoiOme1tpmZd2yc93XtRAtzP0P5E5xzqq7a2rbEAarpP5XA==} peerDependencies: - '@expo/log-box': 55.0.11 - '@expo/metro-runtime': ^55.0.10 + '@expo/log-box': 55.0.12 + '@expo/metro-runtime': ^55.0.11 '@react-navigation/drawer': ^7.9.4 '@testing-library/react-native': '>= 13.2.0' expo: '*' - expo-constants: ^55.0.15 - expo-linking: ^55.0.14 + expo-constants: ^55.0.16 + expo-linking: ^55.0.15 react: ^19.2.5 - react-dom: ^19.2.5 + react-dom: ^19.2.6 react-native: '*' react-native-gesture-handler: '*' react-native-reanimated: '*' @@ -5095,12 +5118,12 @@ packages: peerDependencies: expo: '*' - expo-server@55.0.8: - resolution: {integrity: sha512-AoV5TKuO4biSzrhe/OVLyInfTT0pV9/OOc/g/oVq5vmCjL8SaSYTkES8PLt+67Tm7VqX+Dn0+kSx1nQcjEKaPw==} + expo-server@55.0.9: + resolution: {integrity: sha512-N5Ipn1NwqaJzEm+G97o0Jbe4g/th3R/16N1DabnYryXKCiZwDkK13/w3VfGkQN9LOOaBP+JIRxGf4M8lQKPzyA==} engines: {node: '>=20.16.0'} - expo-splash-screen@55.0.19: - resolution: {integrity: sha512-l8BWI/inLJW46Ojz5NgwvaM8LftrdXeFfZBUXhAoZxg44Qo2xKY76s0S1h3WIxWXT4sRKwK8YQzGr4k+zHubxQ==} + expo-splash-screen@55.0.20: + resolution: {integrity: sha512-WI5T0dutiZhxsqlF+jhEP4JRpQNILLlP8IpmKehsnV53Cncv6AQrKE7y1sOWwDyC2m2GBufZ/Vwam1RMt2EfmA==} peerDependencies: expo: '*' @@ -5111,22 +5134,22 @@ packages: react: ^19.2.5 react-native: '*' - expo-status-bar@55.0.5: - resolution: {integrity: sha512-qb0c3rJO2b7CC0gUVGi1JYp92oLenWdYGyk8l4YQs6U+uaXUTPv6aaFa3KkT2HON10re3AxxPNJci8rsz6kPxg==} + expo-status-bar@55.0.6: + resolution: {integrity: sha512-ijOUptfdiqYt7rObZ6jrPQ8sE5YN/8MxKCIJx0b7TY4nGkSJxhPIxeoW4GXcXCA8mTQ9PiOHH/ThLZgRVZvUlQ==} peerDependencies: react: ^19.2.5 react-native: '*' - expo-symbols@55.0.7: - resolution: {integrity: sha512-y4ALLbncSGQzhFLw1PaIBbO39xzaw3ie249HmK6zK/WLJYfw4Z/9UU4iPKO3KCE4FyCKIzd+yRsvzvlri23YrQ==} + expo-symbols@55.0.8: + resolution: {integrity: sha512-Dg6BTu+fCWukdlh+3XYIr6NbqJWmK4aAQ6i6BInKnWU0ALuzVUJcMDq8Lk9bHok2hOh3OhzJqlCqEoBXPInIVQ==} peerDependencies: expo: '*' expo-font: '*' react: ^19.2.5 react-native: '*' - expo-system-ui@55.0.16: - resolution: {integrity: sha512-LwFBpFzy7L4j0ZqHZaxNU4tewQXkH37N4afXu6ZrkyKsH9q5V3jOT1way/N+Hylgyx5+jGpzvae9OcphS/+iDQ==} + expo-system-ui@55.0.17: + resolution: {integrity: sha512-sCrQbp1VyMe63c7y7/luz88P9Ro3/jeUBXby2uYk0wHtkawUzBK9V69J3HTC4rI5eXiJMJPF2oCKO71c/7wtTg==} peerDependencies: expo: '*' react-native: '*' @@ -5140,14 +5163,14 @@ packages: peerDependencies: expo: '*' - expo-web-browser@55.0.14: - resolution: {integrity: sha512-bTDkBSQBnrlnYcM7Aak72AOvJuvdgA3M8p//Lazrm0Nfa77T9cRXzQ6KhLrB08V39n1+00d1dvuTWznJslkmdg==} + expo-web-browser@55.0.15: + resolution: {integrity: sha512-6hwZQob3EF+RWwZ+IvWLZjj2wI1frqx21+m/uzBqdUEHUhp2cVJi7kmxDolDmrve+ZldryZi1qfN78ALdvjHSA==} peerDependencies: expo: '*' react-native: '*' - expo@55.0.19: - resolution: {integrity: sha512-8nTbChg2vy7aNsX5F7KiSb552YP7dc4eD89+UjCKlFPQg4Dw7RyjYuXgFBU7ADw2JjTHl848jFLyT6nvqNROgg==} + expo@55.0.23: + resolution: {integrity: sha512-b+lKwfzJzFiSm9G0wVGWw3c2YoZyubbl9gHOF1ZFuK8FqtxSge8pDDJMuEFmTi14dbKwh/tirB7MiORq54r7CQ==} hasBin: true peerDependencies: '@expo/dom-webview': '*' @@ -5456,6 +5479,14 @@ packages: i18next-browser-languagedetector@8.2.1: resolution: {integrity: sha512-bZg8+4bdmaOiApD7N7BPT9W8MLZG+nPTOFlLiJiT8uzKXFjhxw4v2ierCXOwB5sFDMtuA5G4kgYZ0AznZxQ/cw==} + i18next@26.0.10: + resolution: {integrity: sha512-k3yGPAlWR2RdMYoVXJoDZDT87qeHIWKH7gVksdZMpRty7QX/D9QZeYGvN08KGbKHke9wn01eYT+EEsrqX/YTlw==} + peerDependencies: + typescript: ^5 || ^6 + peerDependenciesMeta: + typescript: + optional: true + i18next@26.0.8: resolution: {integrity: sha512-BRzLom0mhDhV9v0QhgUUHWQJuwFmnr1194xEcNLYD6ym8y8s542n4jXUvRLnhNTbh9PmpU6kGZamyuGHQMsGjw==} peerDependencies: @@ -5532,8 +5563,8 @@ packages: is-arrayish@0.3.4: resolution: {integrity: sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA==} - is-core-module@2.16.1: - resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} + is-core-module@2.16.2: + resolution: {integrity: sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==} engines: {node: '>= 0.4'} is-docker@2.2.1: @@ -5584,8 +5615,8 @@ packages: resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} engines: {node: '>=8'} - isbot@5.1.39: - resolution: {integrity: sha512-obH0yYahGXdzNxo+djmHhBYThUKDkz565cxkIlt2L9hXfv1NlaLKoDBHo6KxXsYrIXx2RK3x5vY36CfZcobxEw==} + isbot@5.1.40: + resolution: {integrity: sha512-yNeeynhhtIVRBk12tBV4eHNxwB42HzR4Q3Ea7vCOiJhImGaAIdIMrbJtacQlBizGLjUPw+akkFI5Dn9T70XoVQ==} engines: {node: '>=18'} isexe@2.0.0: @@ -5677,8 +5708,8 @@ packages: resolution: {integrity: sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - jest-expo@55.0.16: - resolution: {integrity: sha512-bOvrTNyDaiaoTz9GhvnXib9v9rjX9PTJFvvoqRMRKEg4MoHghG82E7YF+pH71EWSXTaibQ07F46GS+fcUxTWEg==} + jest-expo@55.0.17: + resolution: {integrity: sha512-LEJJyPBYtr7FzL5DUvnPsWF4ial6h23XQ37ikmqu/HFR4KidFkQ03ht2jsUWUSqmN/KdKeWSesEmbe5AUNZn3A==} hasBin: true peerDependencies: expo: '*' @@ -5787,8 +5818,8 @@ packages: jimp-compact@0.16.1: resolution: {integrity: sha512-dZ6Ra7u1G8c4Letq/B5EzAxj4tLFHL+cGtdpR+PVm4yzPDj+lCk+AbivWt1eOM+ikzkowtyV7qSqX6qr3t71Ww==} - jiti@2.6.1: - resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} + jiti@2.7.0: + resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} hasBin: true jose@6.2.3: @@ -6017,6 +6048,10 @@ packages: resolution: {integrity: sha512-NxVFwLAnrd9i7KUBxC4DrUhmgjzOs+1Qm50D3oF1/oL+r1NpZ4gA7xvG0/zJ8evR7zIKn4vLf7qTNduWFtCrRw==} engines: {node: 20 || >=22} + lru-cache@11.3.6: + resolution: {integrity: sha512-Gf/KoL3C/MlI7Bt0PGI9I+TeTC/I6r/csU58N4BSNc4lppLBeKsOdFYkK+dX0ABDUMJNfCHTyPpzwwO21Awd3A==} + engines: {node: 20 || >=22} + lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} @@ -6541,8 +6576,8 @@ packages: resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} engines: {node: '>=8'} - pkg-types@2.3.0: - resolution: {integrity: sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==} + pkg-types@2.3.1: + resolution: {integrity: sha512-y+ichcgc2LrADuhLNAx8DFjVfgz91pRxfZdI3UDhxHvcVEZsenLO+7XaU5vOp0u/7V/wZ+plyuQxtrDlZJ+yeg==} playwright-core@1.59.1: resolution: {integrity: sha512-HBV/RJg81z5BiiZ9yPzIiClYV/QMsDCKUyogwH9p3MCP6IYjUFu/MActgYAvK0oWyV9NlwM3GLBjADyWgydVyg==} @@ -6576,6 +6611,10 @@ packages: resolution: {integrity: sha512-qif0+jGGZoLWdHey3UFHHWP0H7Gbmsk8T5VEqyYFbWqPr1XqvLGBbk/sl8V5exGmcYJklJOhOQq1pV9IcsiFag==} engines: {node: ^10 || ^12 || >=14} + postcss@8.5.14: + resolution: {integrity: sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==} + engines: {node: ^10 || ^12 || >=14} + postgres-array@2.0.0: resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==} engines: {node: '>=4'} @@ -6719,8 +6758,8 @@ packages: react-devtools-core@6.1.5: resolution: {integrity: sha512-ePrwPfxAnB+7hgnEr8vpKxL9cmnp7F322t8oqcPshbIQQhDKgFDW4tjhF2wjVbdXF9O/nyuy3sQWd9JGpiLPvA==} - react-dom@19.2.5: - resolution: {integrity: sha512-J5bAZz+DXMMwW/wV3xzKke59Af6CHY7G4uYLN1OvBcKEsWOs4pQExj86BBKamxl/Ik5bx9whOrvBlSDfWzgSag==} + react-dom@19.2.6: + resolution: {integrity: sha512-0prMI+hvBbPjsWnxDLxlCGyM8PN6UuWjEUCYmZhO67xIV9Xasa/r/vDnq+Xyq4Lo27g8QSbO5YzARu0D1Sps3g==} peerDependencies: react: ^19.2.5 @@ -6749,6 +6788,22 @@ packages: typescript: optional: true + react-i18next@17.0.7: + resolution: {integrity: sha512-rwtPXsb/zwzDafN+gytcjF5YnqGQQIRmCQ6DctBC1VSipRB8GD/MWEVrFP42vjMyuYydxWxM8CZRt+yiNuuoHg==} + peerDependencies: + i18next: '>= 26.0.10' + react: ^19.2.5 + react-dom: '*' + react-native: '*' + typescript: ^5 || ^6 + peerDependenciesMeta: + react-dom: + optional: true + react-native: + optional: true + typescript: + optional: true + react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} @@ -6758,18 +6813,18 @@ packages: react-is@18.3.1: resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} - react-is@19.2.5: - resolution: {integrity: sha512-Dn0t8IQhCmeIT3wu+Apm1/YVsJXsGWi6k4sPdnBIdqMVtHtv0IGi6dcpNpNkNac0zB2uUAqNX3MHzN8c+z2rwQ==} + react-is@19.2.6: + resolution: {integrity: sha512-XjBR15BhXuylgWGuslhDKqlSayuqvqBX91BP8pauG8kd1zY8kotkNWbXksTCNRarse4kuGbe2kIY05ARtwNIvw==} react-leaflet@5.0.0: resolution: {integrity: sha512-CWbTpr5vcHw5bt9i4zSlPEVQdTVcML390TjeDG0cK59z1ylexpqC6M1PJFjV8jD7CF+ACBFsLIDs6DRMoLEofw==} peerDependencies: leaflet: ^1.9.0 react: ^19.2.5 - react-dom: ^19.2.5 + react-dom: ^19.2.6 - react-native-gesture-handler@2.31.1: - resolution: {integrity: sha512-wQDlECdEzHhYKTnQXFnSqWUtJ5TS3MGQi7EWvQczTnEVKfk6XVSBecnpWAoI/CqlYQ7IWMJEyutY6BxwEBoxeg==} + react-native-gesture-handler@2.31.2: + resolution: {integrity: sha512-rw5q74i2AfS7YGYdbxQDhOU7xqgY6WRM1132/CCm3erqjblhECZDZFHIm0tteHoC9ih24wogVBVVzcTBQtZ+5A==} peerDependencies: react: ^19.2.5 react-native: '*' @@ -6780,8 +6835,8 @@ packages: react: ^19.2.5 react-native: '*' - react-native-reanimated@4.3.0: - resolution: {integrity: sha512-HOTTPdKtddXTOsmQxDASXEwLS3lqEHrKERD3XOgzSqWJ7L3x81Pnx7mTcKx1FKdkgomMug/XSmm1C6Z7GIowxA==} + react-native-reanimated@4.3.1: + resolution: {integrity: sha512-KhGsS0YkCA+gusgyzlf9hnqzVPIR398KTpqXyqq/+yYJJPAvyEEPKcxlB0xtOOXSMrR2A9uRKVARVQhZwrOh+Q==} peerDependencies: react: ^19.2.5 react-native: 0.81 - 0.85 @@ -6842,12 +6897,12 @@ packages: '@types/react': optional: true - react-router@7.14.2: - resolution: {integrity: sha512-yCqNne6I8IB6rVCH7XUvlBK7/QKyqypBFGv+8dj4QBFJiiRX+FG7/nkdAvGElyvVZ/HQP5N19wzteuTARXi5Gw==} + react-router@7.15.0: + resolution: {integrity: sha512-HW9vYwuM8f4yx66Izy8xfrzCM+SBJluoZcCbww9A1TySax11S5Vgw6fi3ZjMONw9J4gQwngL7PzkyIpJJpJ7RQ==} engines: {node: '>=20.0.0'} peerDependencies: react: ^19.2.5 - react-dom: ^19.2.5 + react-dom: ^19.2.6 peerDependenciesMeta: react-dom: optional: true @@ -6867,8 +6922,8 @@ packages: peerDependencies: react: ^19.2.5 - react-test-renderer@19.2.5: - resolution: {integrity: sha512-kwViRpdISMTpcpy5B6TSewfJzRjnajihRaj57ZmOWKD+SPN6k9LUM13O0pfOuW8ir6B6OOiAXwCRqOoVxRNykA==} + react-test-renderer@19.2.6: + resolution: {integrity: sha512-GbS6V23YduFTPiWJ5xICbKEjRcqx1Z90js/V5miqhz7qp/d6xSe9Dd6NjSQODFRdzdsqRMPW82E/sFpPRbY5Mw==} peerDependencies: react: ^19.2.5 @@ -6876,6 +6931,10 @@ packages: resolution: {integrity: sha512-llUJLzz1zTUBrskt2pwZgLq59AemifIftw4aB7JxOqf1HY2FDaGDxgwpAPVzHU1kdWabH7FauP4i1oEeer2WCA==} engines: {node: '>=0.10.0'} + react@19.2.6: + resolution: {integrity: sha512-sfWGGfavi0xr8Pg0sVsyHMAOziVYKgPLNrS7ig+ivMNb3wbCBw3KxtflsGBAwD3gYQlE/AEZsTLgToRrSCjb0Q==} + engines: {node: '>=0.10.0'} + readdirp@4.1.2: resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} engines: {node: '>= 14.18.0'} @@ -6975,8 +7034,8 @@ packages: engines: {node: ^20.19.0 || >=22.12.0} hasBin: true - rollup@4.60.2: - resolution: {integrity: sha512-J9qZyW++QK/09NyN/zeO0dG/1GdGfyp9lV8ajHnRVLfo/uFsbji5mHnDgn/qYdUHyCkM2N+8VyspgZclfAh0eQ==} + rollup@4.60.3: + resolution: {integrity: sha512-pAQK9HalE84QSm4Po3EmWIZPd3FnjkShVkiMlz1iligWYkWQ7wHYd1PF/T7QZ5TVSD6uSTon5gBVMSM4JfBV+A==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -7030,6 +7089,11 @@ packages: engines: {node: '>=10'} hasBin: true + semver@7.8.0: + resolution: {integrity: sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==} + engines: {node: '>=10'} + hasBin: true + send@0.19.2: resolution: {integrity: sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==} engines: {node: '>= 0.8.0'} @@ -7290,8 +7354,8 @@ packages: resolution: {integrity: sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==} engines: {node: '>=20'} - tailwindcss@4.2.4: - resolution: {integrity: sha512-HhKppgO81FQof5m6TEnuBWCZGgfRAWbaeOaGT00KOy/Pf/j6oUihdvBpA7ltCeAvZpFhW3j0PTclkxsd4IXYDA==} + tailwindcss@4.3.0: + resolution: {integrity: sha512-y6nxMGB1nMW9R6k96e5gdIFzcfL/gTJRNaqGes1YvkLnPVXzWgbqFF2yLC0T8G774n24cx3Pe8XrKoniCOAH+Q==} tapable@2.3.3: resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==} @@ -7304,8 +7368,8 @@ packages: resolution: {integrity: sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==} engines: {node: '>=8'} - terser@5.46.2: - resolution: {integrity: sha512-uxfo9fPcSgLDYob/w1FuL0c99MWiJDnv+5qXSQc5+Ki5NjVNsYi66INnMFBjf6uFz6OnX12piJQPF4IpjJTNTw==} + terser@5.47.1: + resolution: {integrity: sha512-tPbLXTI6ohPASb/1YViL428oEHu6/qv1OxqYnfaonVCFHqx4+wCd95pHrQWsL5X4pl90CTyW9piSAsS2L0VoMw==} engines: {node: '>=10'} hasBin: true @@ -7402,8 +7466,8 @@ packages: resolution: {integrity: sha512-axr3IdNuVIxnaK5XGEUFTu3YmAQ6lllgrvqfEoR16g/HGnYY/6We4oWENtAnzK6/LpJ2ur9PAb80RBt7/U4ugw==} engines: {node: '>= 6.0.0'} - turbo@2.9.8: - resolution: {integrity: sha512-REEB2rVTVDTf4hav1gJ5dIsGylWZrNonvjXFtk1dCi8gND3PhZtnYkyry1bra/Fo+iP6ctTEZbg6vWfdfHq/1A==} + turbo@2.9.12: + resolution: {integrity: sha512-lCPgus1NuTiBdaITWqzSH/Ff6HVL8HHGBtOXHg1dHRfcshN79XkygSdh0M6g8b0td91ILLG5MTkLOkp5UvyPJw==} hasBin: true type-check@0.4.0: @@ -7430,8 +7494,8 @@ packages: resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} engines: {node: '>= 0.6'} - typescript-eslint@8.59.1: - resolution: {integrity: sha512-xqDcFVBmlrltH64lklOVp1wYxgJr6LVdg3NamBgH2OOQDLFdTKfIZXF5PfghrnXQKXZGTQs8tr1vL7fJvq8CTQ==} + typescript-eslint@8.59.2: + resolution: {integrity: sha512-pJw051uomb3ZeCzGTpRb8RbEqB5Y4WWet8gl/GcTlU35BSx0PVdZ86/bqkQCyKKuraVQEK7r6kBHQXF+fBhkoQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 @@ -7547,8 +7611,8 @@ packages: resolution: {integrity: sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==} engines: {node: '>=10.12.0'} - valibot@1.3.1: - resolution: {integrity: sha512-sfdRir/QFM0JaF22hqTroPc5xy4DimuGQVKFrzF1YfGwaS1nJot3Y8VqMdLO2Lg27fMzat2yD3pY5PbAYO39Gg==} + valibot@1.4.0: + resolution: {integrity: sha512-iC/x7fVcSyOwlm/VSt7RlHnzNGLGvR9GnxdifUeWoCJo0q4ZZvrVkIHC6faTlkxG47I2Y4UrFquPuVHCrOnrLg==} peerDependencies: typescript: '>=5' peerDependenciesMeta: @@ -7567,15 +7631,15 @@ packages: resolution: {integrity: sha512-ZFkClGpWyI2WUQjdLJ/BaGuV6AVQiJ3uELGk3OYtP+B6yCO7Cmn9vPFXVJkRaGkOJu3m8bQMgtyzNHixULceQA==} peerDependencies: react: ^19.2.5 - react-dom: ^19.2.5 + react-dom: ^19.2.6 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@7.3.2: - resolution: {integrity: sha512-Bby3NOsna2jsjfLVOHKes8sGwgl4TT0E6vvpYgnAYDIF/tie7MRaFthmKuHx1NSXjiTueXH3do80FMQgvEktRg==} + vite@7.3.3: + resolution: {integrity: sha512-/4XH147Ui7OGTjg3HbdWe5arnZQSbfuRzdr9Ec7TQi5I7R+ir0Rlc9GIvD4v0XZurELqA035KVXJXpR61xhiTA==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: @@ -7752,8 +7816,8 @@ packages: resolution: {integrity: sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==} engines: {node: '>=20'} - whatwg-url-minimum@0.1.1: - resolution: {integrity: sha512-u2FNVjFVFZhdjb502KzXy1gKn1mEisQRJssmSJT8CPhZdZa0AP6VCbWlXERKyGu0l09t0k50FiDiralpGhBxgA==} + whatwg-url-minimum@0.1.2: + resolution: {integrity: sha512-XPEm0XFQWNVG292lII1PrRRJl3sItrs7CettZ4ncYxuDVpLyy+NwlGyut2hXI0JswcJUxeCH+CyOJK0ZzAXD6A==} whatwg-url@11.0.0: resolution: {integrity: sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==} @@ -7907,8 +7971,8 @@ packages: zod@3.25.76: resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} - zod@4.4.2: - resolution: {integrity: sha512-IynmDyxsEsb9RKzO3J9+4SxXnl2FTFSzNBaKKaMV6tsSk0rw9gYw9gs+JFCq/qk2LCZ78KDwyj+Z289TijSkUw==} + zod@4.4.3: + resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==} snapshots: @@ -8543,20 +8607,20 @@ snapshots: dependencies: '@codemirror/language': 6.12.3 '@codemirror/state': 6.6.0 - '@codemirror/view': 6.41.1 + '@codemirror/view': 6.42.1 '@lezer/common': 1.5.2 '@codemirror/commands@6.10.3': dependencies: '@codemirror/language': 6.12.3 '@codemirror/state': 6.6.0 - '@codemirror/view': 6.41.1 + '@codemirror/view': 6.42.1 '@lezer/common': 1.5.2 '@codemirror/language@6.12.3': dependencies: '@codemirror/state': 6.6.0 - '@codemirror/view': 6.41.1 + '@codemirror/view': 6.42.1 '@lezer/common': 1.5.2 '@lezer/highlight': 1.2.3 '@lezer/lr': 1.4.8 @@ -8565,20 +8629,20 @@ snapshots: '@codemirror/lint@6.9.5': dependencies: '@codemirror/state': 6.6.0 - '@codemirror/view': 6.41.1 + '@codemirror/view': 6.42.1 crelt: 1.0.6 '@codemirror/search@6.6.0': dependencies: '@codemirror/state': 6.6.0 - '@codemirror/view': 6.41.1 + '@codemirror/view': 6.42.1 crelt: 1.0.6 '@codemirror/state@6.6.0': dependencies: '@marijn/find-cluster-break': 1.0.2 - '@codemirror/view@6.41.1': + '@codemirror/view@6.42.1': dependencies: '@codemirror/state': 6.6.0 crelt: 1.0.6 @@ -8863,9 +8927,9 @@ snapshots: '@esbuild/win32-x64@0.27.7': optional: true - '@eslint-community/eslint-utils@4.9.1(eslint@10.3.0(jiti@2.6.1))': + '@eslint-community/eslint-utils@4.9.1(eslint@10.3.0(jiti@2.7.0))': dependencies: - eslint: 10.3.0(jiti@2.6.1) + eslint: 10.3.0(jiti@2.7.0) eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.2': {} @@ -8886,9 +8950,9 @@ snapshots: dependencies: '@types/json-schema': 7.0.15 - '@eslint/js@10.0.1(eslint@10.3.0(jiti@2.6.1))': + '@eslint/js@10.0.1(eslint@10.3.0(jiti@2.7.0))': optionalDependencies: - eslint: 10.3.0(jiti@2.6.1) + eslint: 10.3.0(jiti@2.7.0) '@eslint/object-schema@3.0.5': {} @@ -8899,30 +8963,30 @@ snapshots: '@exodus/bytes@1.15.0': {} - '@expo-google-fonts/material-symbols@0.4.33': {} + '@expo-google-fonts/material-symbols@0.4.36': {} - '@expo/cli@55.0.27(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-constants@55.0.15)(expo-font@55.0.6)(expo-router@55.0.13)(expo@55.0.19)(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.29(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-constants@55.0.16)(expo-font@55.0.7)(expo-router@55.0.14)(expo@55.0.23)(react-dom@19.2.6(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.15(typescript@5.9.3) + '@expo/config': 55.0.16(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.11(@expo/dom-webview@55.0.5)(expo@55.0.19)(react-native@0.83.4(@babel/core@7.29.0)(@react-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/env': 2.1.2 + '@expo/image-utils': 0.8.14(typescript@5.9.3) + '@expo/json-file': 10.0.14 + '@expo/log-box': 55.0.12(@expo/dom-webview@55.0.5)(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.1.1 - '@expo/metro-config': 55.0.18(expo@55.0.19)(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.16(expo@55.0.19)(typescript@5.9.3) - '@expo/require-utils': 55.0.4(typescript@5.9.3) - '@expo/router-server': 55.0.15(@expo/metro-runtime@55.0.10)(expo-constants@55.0.15)(expo-font@55.0.6)(expo-router@55.0.13)(expo-server@55.0.8)(expo@55.0.19)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) - '@expo/schema-utils': 55.0.3 + '@expo/metro-config': 55.0.20(expo@55.0.23)(typescript@5.9.3) + '@expo/osascript': 2.4.3 + '@expo/package-manager': 1.10.5 + '@expo/plist': 0.5.3 + '@expo/prebuild-config': 55.0.17(expo@55.0.23)(typescript@5.9.3) + '@expo/require-utils': 55.0.5(typescript@5.9.3) + '@expo/router-server': 55.0.16(@expo/metro-runtime@55.0.11)(expo-constants@55.0.16)(expo-font@55.0.7)(expo-router@55.0.14)(expo-server@55.0.9)(expo@55.0.23)(react-dom@19.2.6(react@19.2.5))(react@19.2.5) + '@expo/schema-utils': 55.0.4 '@expo/spawn-async': 1.7.2 '@expo/ws-tunnel': 1.0.6 - '@expo/xcpretty': 4.4.3 + '@expo/xcpretty': 4.4.4 '@react-native/dev-middleware': 0.83.6 accepts: 1.3.8 arg: 5.0.2 @@ -8935,8 +8999,8 @@ snapshots: connect: 3.7.0 debug: 4.4.3 dnssd-advertise: 1.1.4 - expo: 55.0.19(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.13)(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.8 + expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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.9 fetch-nodeshim: 0.4.10 getenv: 2.0.0 glob: 13.0.6 @@ -8950,7 +9014,7 @@ snapshots: progress: 2.0.3 prompts: 2.4.2 resolve-from: 5.0.0 - semver: 7.7.4 + semver: 7.8.0 send: 0.19.2 slugify: 1.6.9 source-map-support: 0.5.21 @@ -8962,7 +9026,7 @@ snapshots: ws: 8.20.0 zod: 3.25.76 optionalDependencies: - expo-router: 55.0.13(b9c3b63b8b06344e8f195cf40e503a18) + expo-router: 55.0.14(ab64f1877338f7f43eb15d5c78597024) react-native: 0.83.4(@babel/core@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' @@ -8977,6 +9041,83 @@ snapshots: - typescript - utf-8-validate + '@expo/cli@55.0.29(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-constants@55.0.16)(expo-font@55.0.7)(expo-router@55.0.14)(expo@55.0.23)(react-dom@19.2.6(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3)': + dependencies: + '@expo/code-signing-certificates': 0.0.6 + '@expo/config': 55.0.16(typescript@5.9.3) + '@expo/config-plugins': 55.0.8 + '@expo/devcert': 1.2.1 + '@expo/env': 2.1.2 + '@expo/image-utils': 0.8.14(typescript@5.9.3) + '@expo/json-file': 10.0.14 + '@expo/log-box': 55.0.12(@expo/dom-webview@55.0.5)(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) + '@expo/metro': 55.1.1 + '@expo/metro-config': 55.0.20(expo@55.0.23)(typescript@5.9.3) + '@expo/osascript': 2.4.3 + '@expo/package-manager': 1.10.5 + '@expo/plist': 0.5.3 + '@expo/prebuild-config': 55.0.17(expo@55.0.23)(typescript@5.9.3) + '@expo/require-utils': 55.0.5(typescript@5.9.3) + '@expo/router-server': 55.0.16(@expo/metro-runtime@55.0.11)(expo-constants@55.0.16)(expo-font@55.0.7)(expo-router@55.0.14)(expo-server@55.0.9)(expo@55.0.23)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@expo/schema-utils': 55.0.4 + '@expo/spawn-async': 1.7.2 + '@expo/ws-tunnel': 1.0.6 + '@expo/xcpretty': 4.4.4 + '@react-native/dev-middleware': 0.83.6 + accepts: 1.3.8 + arg: 5.0.2 + better-opn: 3.0.2 + bplist-creator: 0.1.0 + bplist-parser: 0.3.2 + chalk: 4.1.2 + ci-info: 3.9.0 + compression: 1.8.1 + connect: 3.7.0 + debug: 4.4.3 + dnssd-advertise: 1.1.4 + expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) + expo-server: 55.0.9 + fetch-nodeshim: 0.4.10 + getenv: 2.0.0 + glob: 13.0.6 + lan-network: 0.2.1 + multitars: 1.0.0 + node-forge: 1.4.0 + npm-package-arg: 11.0.3 + ora: 3.4.0 + picomatch: 4.0.4 + pretty-format: 29.7.0 + progress: 2.0.3 + prompts: 2.4.2 + resolve-from: 5.0.0 + semver: 7.8.0 + send: 0.19.2 + slugify: 1.6.9 + source-map-support: 0.5.21 + stacktrace-parser: 0.1.11 + structured-headers: 0.4.1 + terminal-link: 2.1.1 + toqr: 0.1.1 + wrap-ansi: 7.0.0 + ws: 8.20.0 + zod: 3.25.76 + optionalDependencies: + expo-router: 55.0.14(8759932d8bf60b7936be47619a69edd6) + react-native: 0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6) + transitivePeerDependencies: + - '@expo/dom-webview' + - '@expo/metro-runtime' + - bufferutil + - expo-constants + - expo-font + - react + - react-dom + - react-server-dom-webpack + - supports-color + - typescript + - utf-8-validate + optional: true + '@expo/code-signing-certificates@0.0.6': dependencies: node-forge: 1.4.0 @@ -8984,15 +9125,15 @@ snapshots: '@expo/config-plugins@55.0.8': dependencies: '@expo/config-types': 55.0.5 - '@expo/json-file': 10.0.13 - '@expo/plist': 0.5.2 + '@expo/json-file': 10.0.14 + '@expo/plist': 0.5.3 '@expo/sdk-runtime-versions': 1.0.0 chalk: 4.1.2 debug: 4.4.3 getenv: 2.0.0 glob: 13.0.6 resolve-from: 5.0.0 - semver: 7.7.4 + semver: 7.8.0 slugify: 1.6.9 xcode: 3.0.1 xml2js: 0.6.0 @@ -9001,17 +9142,17 @@ snapshots: '@expo/config-types@55.0.5': {} - '@expo/config@55.0.15(typescript@5.9.3)': + '@expo/config@55.0.16(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) + '@expo/json-file': 10.0.14 + '@expo/require-utils': 55.0.5(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 + semver: 7.8.0 slugify: 1.6.9 transitivePeerDependencies: - supports-color @@ -9024,20 +9165,35 @@ snapshots: transitivePeerDependencies: - supports-color - '@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/devtools@55.0.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)': dependencies: chalk: 4.1.2 optionalDependencies: 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.19)(react-native@0.83.4(@babel/core@7.29.0)(@react-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/devtools@55.0.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.6))(react@19.2.6)': dependencies: - expo: 55.0.19(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.13)(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) + chalk: 4.1.2 + optionalDependencies: + react: 19.2.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.6) + optional: true + + '@expo/dom-webview@55.0.5(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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/env@2.1.1': + '@expo/dom-webview@55.0.5(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)': + dependencies: + expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) + react: 19.2.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.6) + optional: true + + '@expo/env@2.1.2': dependencies: chalk: 4.1.2 debug: 4.4.3 @@ -9045,9 +9201,9 @@ snapshots: transitivePeerDependencies: - supports-color - '@expo/fingerprint@0.16.6': + '@expo/fingerprint@0.16.7': dependencies: - '@expo/env': 2.1.1 + '@expo/env': 2.1.2 '@expo/spawn-async': 1.7.2 arg: 5.0.2 chalk: 4.1.2 @@ -9057,53 +9213,76 @@ snapshots: ignore: 5.3.2 minimatch: 10.2.5 resolve-from: 5.0.0 - semver: 7.7.4 + semver: 7.8.0 transitivePeerDependencies: - supports-color '@expo/image-utils@0.8.13(typescript@5.9.3)': dependencies: - '@expo/require-utils': 55.0.4(typescript@5.9.3) + '@expo/require-utils': 55.0.5(typescript@5.9.3) '@expo/spawn-async': 1.7.2 chalk: 4.1.2 getenv: 2.0.0 jimp-compact: 0.16.1 parse-png: 2.1.0 - semver: 7.7.4 + semver: 7.8.0 transitivePeerDependencies: - supports-color - typescript - '@expo/json-file@10.0.13': + '@expo/image-utils@0.8.14(typescript@5.9.3)': + dependencies: + '@expo/require-utils': 55.0.5(typescript@5.9.3) + '@expo/spawn-async': 1.7.2 + chalk: 4.1.2 + getenv: 2.0.0 + jimp-compact: 0.16.1 + parse-png: 2.1.0 + semver: 7.8.0 + transitivePeerDependencies: + - supports-color + - typescript + + '@expo/json-file@10.0.14': dependencies: '@babel/code-frame': 7.29.0 json5: 2.2.3 - '@expo/local-build-cache-provider@55.0.11(typescript@5.9.3)': + '@expo/local-build-cache-provider@55.0.12(typescript@5.9.3)': dependencies: - '@expo/config': 55.0.15(typescript@5.9.3) + '@expo/config': 55.0.16(typescript@5.9.3) chalk: 4.1.2 transitivePeerDependencies: - supports-color - typescript - '@expo/log-box@55.0.11(@expo/dom-webview@55.0.5)(expo@55.0.19)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.12(@expo/dom-webview@55.0.5)(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.19)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.19(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.13)(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.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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.18(expo@55.0.19)(typescript@5.9.3)': + '@expo/log-box@55.0.12(@expo/dom-webview@55.0.5)(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)': + dependencies: + '@expo/dom-webview': 55.0.5(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) + anser: 1.4.10 + expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) + react: 19.2.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.6) + stacktrace-parser: 0.1.11 + optional: true + + '@expo/metro-config@55.0.20(expo@55.0.23)(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.15(typescript@5.9.3) - '@expo/env': 2.1.1 - '@expo/json-file': 10.0.13 + '@expo/config': 55.0.16(typescript@5.9.3) + '@expo/env': 2.1.2 + '@expo/json-file': 10.0.14 '@expo/metro': 55.1.1 '@expo/spawn-async': 1.7.2 browserslist: 4.28.2 @@ -9118,28 +9297,44 @@ snapshots: postcss: 8.4.49 resolve-from: 5.0.0 optionalDependencies: - expo: 55.0.19(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.13)(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.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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.10(@expo/dom-webview@55.0.5)(expo@55.0.19)(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.11(@expo/dom-webview@55.0.5)(expo@55.0.23)(react-dom@19.2.6(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.11(@expo/dom-webview@55.0.5)(expo@55.0.19)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.12(@expo/dom-webview@55.0.5)(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.19(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.13)(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.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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) + react-dom: 19.2.6(react@19.2.5) transitivePeerDependencies: - '@expo/dom-webview' + '@expo/metro-runtime@55.0.11(@expo/dom-webview@55.0.5)(expo@55.0.23)(react-dom@19.2.6(react@19.2.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.6))(react@19.2.6)': + dependencies: + '@expo/log-box': 55.0.12(@expo/dom-webview@55.0.5)(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) + anser: 1.4.10 + expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) + pretty-format: 29.7.0 + react: 19.2.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.6) + stacktrace-parser: 0.1.11 + whatwg-fetch: 3.6.20 + optionalDependencies: + react-dom: 19.2.6(react@19.2.6) + transitivePeerDependencies: + - '@expo/dom-webview' + optional: true + '@expo/metro@55.1.1': dependencies: metro: 0.83.7 @@ -9161,43 +9356,43 @@ snapshots: - supports-color - utf-8-validate - '@expo/osascript@2.4.2': + '@expo/osascript@2.4.3': dependencies: '@expo/spawn-async': 1.7.2 - '@expo/package-manager@1.10.4': + '@expo/package-manager@1.10.5': dependencies: - '@expo/json-file': 10.0.13 + '@expo/json-file': 10.0.14 '@expo/spawn-async': 1.7.2 chalk: 4.1.2 npm-package-arg: 11.0.3 ora: 3.4.0 resolve-workspace-root: 2.0.1 - '@expo/plist@0.5.2': + '@expo/plist@0.5.3': dependencies: '@xmldom/xmldom': 0.8.13 base64-js: 1.5.1 xmlbuilder: 15.1.1 - '@expo/prebuild-config@55.0.16(expo@55.0.19)(typescript@5.9.3)': + '@expo/prebuild-config@55.0.17(expo@55.0.23)(typescript@5.9.3)': dependencies: - '@expo/config': 55.0.15(typescript@5.9.3) + '@expo/config': 55.0.16(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 + '@expo/image-utils': 0.8.14(typescript@5.9.3) + '@expo/json-file': 10.0.14 '@react-native/normalize-colors': 0.83.6 debug: 4.4.3 - expo: 55.0.19(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.13)(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.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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 + semver: 7.8.0 xml2js: 0.6.0 transitivePeerDependencies: - supports-color - typescript - '@expo/require-utils@55.0.4(typescript@5.9.3)': + '@expo/require-utils@55.0.5(typescript@5.9.3)': dependencies: '@babel/code-frame': 7.29.0 '@babel/core': 7.29.0 @@ -9207,22 +9402,38 @@ snapshots: transitivePeerDependencies: - supports-color - '@expo/router-server@55.0.15(@expo/metro-runtime@55.0.10)(expo-constants@55.0.15)(expo-font@55.0.6)(expo-router@55.0.13)(expo-server@55.0.8)(expo@55.0.19)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': + '@expo/router-server@55.0.16(@expo/metro-runtime@55.0.11)(expo-constants@55.0.16)(expo-font@55.0.7)(expo-router@55.0.14)(expo-server@55.0.9)(expo@55.0.23)(react-dom@19.2.6(react@19.2.5))(react@19.2.5)': dependencies: debug: 4.4.3 - expo: 55.0.19(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.13)(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.15(expo@55.0.19)(react-native@0.83.4(@babel/core@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.19)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.8 + expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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.16(expo@55.0.23)(react-native@0.83.4(@babel/core@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.7(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.9 react: 19.2.5 optionalDependencies: - '@expo/metro-runtime': 55.0.10(@expo/dom-webview@55.0.5)(expo@55.0.19)(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.13(b9c3b63b8b06344e8f195cf40e503a18) - react-dom: 19.2.5(react@19.2.5) + '@expo/metro-runtime': 55.0.11(@expo/dom-webview@55.0.5)(expo@55.0.23)(react-dom@19.2.6(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.14(ab64f1877338f7f43eb15d5c78597024) + react-dom: 19.2.6(react@19.2.5) transitivePeerDependencies: - supports-color - '@expo/schema-utils@55.0.3': {} + '@expo/router-server@55.0.16(@expo/metro-runtime@55.0.11)(expo-constants@55.0.16)(expo-font@55.0.7)(expo-router@55.0.14)(expo-server@55.0.9)(expo@55.0.23)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + dependencies: + debug: 4.4.3 + expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) + expo-constants: 55.0.16(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6)) + expo-font: 55.0.7(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) + expo-server: 55.0.9 + react: 19.2.6 + optionalDependencies: + '@expo/metro-runtime': 55.0.11(@expo/dom-webview@55.0.5)(expo@55.0.23)(react-dom@19.2.6(react@19.2.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.6))(react@19.2.6) + expo-router: 55.0.14(8759932d8bf60b7936be47619a69edd6) + react-dom: 19.2.6(react@19.2.6) + transitivePeerDependencies: + - supports-color + optional: true + + '@expo/schema-utils@55.0.4': {} '@expo/sdk-runtime-versions@1.0.0': {} @@ -9232,15 +9443,22 @@ 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)(@react-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/vector-icons@15.1.1(expo-font@55.0.7)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.19)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.7(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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) + '@expo/vector-icons@15.1.1(expo-font@55.0.7)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)': + dependencies: + expo-font: 55.0.7(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) + react: 19.2.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.6) + optional: true + '@expo/ws-tunnel@1.0.6': {} - '@expo/xcpretty@4.4.3': + '@expo/xcpretty@4.4.4': dependencies: '@babel/code-frame': 7.29.0 chalk: 4.1.2 @@ -9256,17 +9474,17 @@ snapshots: transitivePeerDependencies: - supports-color - '@fission-ai/openspec@1.3.1(@types/node@25.6.0)': + '@fission-ai/openspec@1.3.1(@types/node@25.6.2)': dependencies: - '@inquirer/core': 10.3.2(@types/node@25.6.0) - '@inquirer/prompts': 7.10.1(@types/node@25.6.0) + '@inquirer/core': 10.3.2(@types/node@25.6.2) + '@inquirer/prompts': 7.10.1(@types/node@25.6.2) chalk: 5.6.2 commander: 14.0.3 fast-glob: 3.3.3 ora: 8.2.0 posthog-node: 5.33.4 yaml: 2.8.4 - zod: 4.4.2 + zod: 4.4.3 transitivePeerDependencies: - '@types/node' - rxjs @@ -9283,14 +9501,14 @@ snapshots: lodash: 4.18.1 polyclip-ts: 0.16.8 - '@gorhom/bottom-sheet@5.2.13(@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)': + '@gorhom/bottom-sheet@5.2.14(@types/react@19.2.14)(react-native-gesture-handler@2.31.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-reanimated@4.3.1(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) + react-native-gesture-handler: 2.31.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-reanimated: 4.3.1(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 @@ -9320,128 +9538,128 @@ snapshots: '@inquirer/ansi@1.0.2': {} - '@inquirer/checkbox@4.3.2(@types/node@25.6.0)': + '@inquirer/checkbox@4.3.2(@types/node@25.6.2)': dependencies: '@inquirer/ansi': 1.0.2 - '@inquirer/core': 10.3.2(@types/node@25.6.0) + '@inquirer/core': 10.3.2(@types/node@25.6.2) '@inquirer/figures': 1.0.15 - '@inquirer/type': 3.0.10(@types/node@25.6.0) + '@inquirer/type': 3.0.10(@types/node@25.6.2) yoctocolors-cjs: 2.1.3 optionalDependencies: - '@types/node': 25.6.0 + '@types/node': 25.6.2 - '@inquirer/confirm@5.1.21(@types/node@25.6.0)': + '@inquirer/confirm@5.1.21(@types/node@25.6.2)': dependencies: - '@inquirer/core': 10.3.2(@types/node@25.6.0) - '@inquirer/type': 3.0.10(@types/node@25.6.0) + '@inquirer/core': 10.3.2(@types/node@25.6.2) + '@inquirer/type': 3.0.10(@types/node@25.6.2) optionalDependencies: - '@types/node': 25.6.0 + '@types/node': 25.6.2 - '@inquirer/core@10.3.2(@types/node@25.6.0)': + '@inquirer/core@10.3.2(@types/node@25.6.2)': dependencies: '@inquirer/ansi': 1.0.2 '@inquirer/figures': 1.0.15 - '@inquirer/type': 3.0.10(@types/node@25.6.0) + '@inquirer/type': 3.0.10(@types/node@25.6.2) cli-width: 4.1.0 mute-stream: 2.0.0 signal-exit: 4.1.0 wrap-ansi: 6.2.0 yoctocolors-cjs: 2.1.3 optionalDependencies: - '@types/node': 25.6.0 + '@types/node': 25.6.2 - '@inquirer/editor@4.2.23(@types/node@25.6.0)': + '@inquirer/editor@4.2.23(@types/node@25.6.2)': dependencies: - '@inquirer/core': 10.3.2(@types/node@25.6.0) - '@inquirer/external-editor': 1.0.3(@types/node@25.6.0) - '@inquirer/type': 3.0.10(@types/node@25.6.0) + '@inquirer/core': 10.3.2(@types/node@25.6.2) + '@inquirer/external-editor': 1.0.3(@types/node@25.6.2) + '@inquirer/type': 3.0.10(@types/node@25.6.2) optionalDependencies: - '@types/node': 25.6.0 + '@types/node': 25.6.2 - '@inquirer/expand@4.0.23(@types/node@25.6.0)': + '@inquirer/expand@4.0.23(@types/node@25.6.2)': dependencies: - '@inquirer/core': 10.3.2(@types/node@25.6.0) - '@inquirer/type': 3.0.10(@types/node@25.6.0) + '@inquirer/core': 10.3.2(@types/node@25.6.2) + '@inquirer/type': 3.0.10(@types/node@25.6.2) yoctocolors-cjs: 2.1.3 optionalDependencies: - '@types/node': 25.6.0 + '@types/node': 25.6.2 - '@inquirer/external-editor@1.0.3(@types/node@25.6.0)': + '@inquirer/external-editor@1.0.3(@types/node@25.6.2)': dependencies: chardet: 2.1.1 iconv-lite: 0.7.2 optionalDependencies: - '@types/node': 25.6.0 + '@types/node': 25.6.2 '@inquirer/figures@1.0.15': {} - '@inquirer/input@4.3.1(@types/node@25.6.0)': + '@inquirer/input@4.3.1(@types/node@25.6.2)': dependencies: - '@inquirer/core': 10.3.2(@types/node@25.6.0) - '@inquirer/type': 3.0.10(@types/node@25.6.0) + '@inquirer/core': 10.3.2(@types/node@25.6.2) + '@inquirer/type': 3.0.10(@types/node@25.6.2) optionalDependencies: - '@types/node': 25.6.0 + '@types/node': 25.6.2 - '@inquirer/number@3.0.23(@types/node@25.6.0)': + '@inquirer/number@3.0.23(@types/node@25.6.2)': dependencies: - '@inquirer/core': 10.3.2(@types/node@25.6.0) - '@inquirer/type': 3.0.10(@types/node@25.6.0) + '@inquirer/core': 10.3.2(@types/node@25.6.2) + '@inquirer/type': 3.0.10(@types/node@25.6.2) optionalDependencies: - '@types/node': 25.6.0 + '@types/node': 25.6.2 - '@inquirer/password@4.0.23(@types/node@25.6.0)': + '@inquirer/password@4.0.23(@types/node@25.6.2)': dependencies: '@inquirer/ansi': 1.0.2 - '@inquirer/core': 10.3.2(@types/node@25.6.0) - '@inquirer/type': 3.0.10(@types/node@25.6.0) + '@inquirer/core': 10.3.2(@types/node@25.6.2) + '@inquirer/type': 3.0.10(@types/node@25.6.2) optionalDependencies: - '@types/node': 25.6.0 + '@types/node': 25.6.2 - '@inquirer/prompts@7.10.1(@types/node@25.6.0)': + '@inquirer/prompts@7.10.1(@types/node@25.6.2)': dependencies: - '@inquirer/checkbox': 4.3.2(@types/node@25.6.0) - '@inquirer/confirm': 5.1.21(@types/node@25.6.0) - '@inquirer/editor': 4.2.23(@types/node@25.6.0) - '@inquirer/expand': 4.0.23(@types/node@25.6.0) - '@inquirer/input': 4.3.1(@types/node@25.6.0) - '@inquirer/number': 3.0.23(@types/node@25.6.0) - '@inquirer/password': 4.0.23(@types/node@25.6.0) - '@inquirer/rawlist': 4.1.11(@types/node@25.6.0) - '@inquirer/search': 3.2.2(@types/node@25.6.0) - '@inquirer/select': 4.4.2(@types/node@25.6.0) + '@inquirer/checkbox': 4.3.2(@types/node@25.6.2) + '@inquirer/confirm': 5.1.21(@types/node@25.6.2) + '@inquirer/editor': 4.2.23(@types/node@25.6.2) + '@inquirer/expand': 4.0.23(@types/node@25.6.2) + '@inquirer/input': 4.3.1(@types/node@25.6.2) + '@inquirer/number': 3.0.23(@types/node@25.6.2) + '@inquirer/password': 4.0.23(@types/node@25.6.2) + '@inquirer/rawlist': 4.1.11(@types/node@25.6.2) + '@inquirer/search': 3.2.2(@types/node@25.6.2) + '@inquirer/select': 4.4.2(@types/node@25.6.2) optionalDependencies: - '@types/node': 25.6.0 + '@types/node': 25.6.2 - '@inquirer/rawlist@4.1.11(@types/node@25.6.0)': + '@inquirer/rawlist@4.1.11(@types/node@25.6.2)': dependencies: - '@inquirer/core': 10.3.2(@types/node@25.6.0) - '@inquirer/type': 3.0.10(@types/node@25.6.0) + '@inquirer/core': 10.3.2(@types/node@25.6.2) + '@inquirer/type': 3.0.10(@types/node@25.6.2) yoctocolors-cjs: 2.1.3 optionalDependencies: - '@types/node': 25.6.0 + '@types/node': 25.6.2 - '@inquirer/search@3.2.2(@types/node@25.6.0)': + '@inquirer/search@3.2.2(@types/node@25.6.2)': dependencies: - '@inquirer/core': 10.3.2(@types/node@25.6.0) + '@inquirer/core': 10.3.2(@types/node@25.6.2) '@inquirer/figures': 1.0.15 - '@inquirer/type': 3.0.10(@types/node@25.6.0) + '@inquirer/type': 3.0.10(@types/node@25.6.2) yoctocolors-cjs: 2.1.3 optionalDependencies: - '@types/node': 25.6.0 + '@types/node': 25.6.2 - '@inquirer/select@4.4.2(@types/node@25.6.0)': + '@inquirer/select@4.4.2(@types/node@25.6.2)': dependencies: '@inquirer/ansi': 1.0.2 - '@inquirer/core': 10.3.2(@types/node@25.6.0) + '@inquirer/core': 10.3.2(@types/node@25.6.2) '@inquirer/figures': 1.0.15 - '@inquirer/type': 3.0.10(@types/node@25.6.0) + '@inquirer/type': 3.0.10(@types/node@25.6.2) yoctocolors-cjs: 2.1.3 optionalDependencies: - '@types/node': 25.6.0 + '@types/node': 25.6.2 - '@inquirer/type@3.0.10(@types/node@25.6.0)': + '@inquirer/type@3.0.10(@types/node@25.6.2)': optionalDependencies: - '@types/node': 25.6.0 + '@types/node': 25.6.2 '@isaacs/ttlcache@1.4.1': {} @@ -9458,7 +9676,7 @@ snapshots: '@jest/console@29.7.0': dependencies: '@jest/types': 29.6.3 - '@types/node': 25.6.0 + '@types/node': 25.6.2 chalk: 4.1.2 jest-message-util: 29.7.0 jest-util: 29.7.0 @@ -9471,14 +9689,14 @@ snapshots: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 25.6.0 + '@types/node': 25.6.2 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.6.0) + jest-config: 29.7.0(@types/node@25.6.2) jest-haste-map: 29.7.0 jest-message-util: 29.7.0 jest-regex-util: 29.6.3 @@ -9509,7 +9727,7 @@ snapshots: dependencies: '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 25.6.0 + '@types/node': 25.6.2 jest-mock: 29.7.0 '@jest/expect-utils@29.7.0': @@ -9527,7 +9745,7 @@ snapshots: dependencies: '@jest/types': 29.6.3 '@sinonjs/fake-timers': 10.3.0 - '@types/node': 25.6.0 + '@types/node': 25.6.2 jest-message-util: 29.7.0 jest-mock: 29.7.0 jest-util: 29.7.0 @@ -9551,7 +9769,7 @@ snapshots: '@jest/transform': 29.7.0 '@jest/types': 29.6.3 '@jridgewell/trace-mapping': 0.3.31 - '@types/node': 25.6.0 + '@types/node': 25.6.2 chalk: 4.1.2 collect-v8-coverage: 1.0.3 exit: 0.1.2 @@ -9625,7 +9843,7 @@ snapshots: '@jest/schemas': 29.6.3 '@types/istanbul-lib-coverage': 2.0.6 '@types/istanbul-reports': 3.0.4 - '@types/node': 25.6.0 + '@types/node': 25.6.2 '@types/yargs': 17.0.35 chalk: 4.1.2 @@ -9679,7 +9897,7 @@ snapshots: rw: 1.3.3 tinyqueue: 3.0.0 - '@maplibre/maplibre-react-native@11.0.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)': + '@maplibre/maplibre-react-native@11.1.1(@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: '@maplibre/maplibre-gl-style-spec': 24.8.1 '@turf/distance': 7.3.5 @@ -9802,15 +10020,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@opentelemetry/instrumentation-ioredis@0.62.0(@opentelemetry/api@1.9.1)': - dependencies: - '@opentelemetry/api': 1.9.1 - '@opentelemetry/instrumentation': 0.214.0(@opentelemetry/api@1.9.1) - '@opentelemetry/redis-common': 0.38.2 - '@opentelemetry/semantic-conventions': 1.40.0 - transitivePeerDependencies: - - supports-color - '@opentelemetry/instrumentation-kafkajs@0.23.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 @@ -9890,15 +10099,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@opentelemetry/instrumentation-redis@0.62.0(@opentelemetry/api@1.9.1)': - dependencies: - '@opentelemetry/api': 1.9.1 - '@opentelemetry/instrumentation': 0.214.0(@opentelemetry/api@1.9.1) - '@opentelemetry/redis-common': 0.38.2 - '@opentelemetry/semantic-conventions': 1.40.0 - transitivePeerDependencies: - - supports-color - '@opentelemetry/instrumentation-tedious@0.33.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 @@ -9935,8 +10135,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@opentelemetry/redis-common@0.38.2': {} - '@opentelemetry/resources@2.6.1(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 @@ -10076,88 +10274,178 @@ snapshots: '@radix-ui/primitive@1.1.3': {} - '@radix-ui/react-collection@1.1.7(@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)': + '@radix-ui/react-collection@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.5))(react@19.2.5)': dependencies: '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.5) '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.5) - '@radix-ui/react-primitive': 2.1.3(@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) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.5))(react@19.2.5) '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.5) react: 19.2.5 - react-dom: 19.2.5(react@19.2.5) + react-dom: 19.2.6(react@19.2.5) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) + '@radix-ui/react-collection@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.6) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.6) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) + optionalDependencies: + '@types/react': 19.2.14 + '@types/react-dom': 19.2.3(@types/react@19.2.14) + optional: true + '@radix-ui/react-compose-refs@1.1.2(@types/react@19.2.14)(react@19.2.5)': dependencies: react: 19.2.5 optionalDependencies: '@types/react': 19.2.14 + '@radix-ui/react-compose-refs@1.1.2(@types/react@19.2.14)(react@19.2.6)': + dependencies: + react: 19.2.6 + optionalDependencies: + '@types/react': 19.2.14 + optional: true + '@radix-ui/react-context@1.1.2(@types/react@19.2.14)(react@19.2.5)': dependencies: react: 19.2.5 optionalDependencies: '@types/react': 19.2.14 - '@radix-ui/react-dialog@1.1.15(@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)': + '@radix-ui/react-context@1.1.2(@types/react@19.2.14)(react@19.2.6)': + dependencies: + react: 19.2.6 + optionalDependencies: + '@types/react': 19.2.14 + optional: true + + '@radix-ui/react-dialog@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.5))(react@19.2.5)': dependencies: '@radix-ui/primitive': 1.1.3 '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.5) '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.5) - '@radix-ui/react-dismissable-layer': 1.1.11(@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) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.5))(react@19.2.5) '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.14)(react@19.2.5) - '@radix-ui/react-focus-scope': 1.1.7(@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) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.5))(react@19.2.5) '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.5) - '@radix-ui/react-portal': 1.1.9(@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) - '@radix-ui/react-presence': 1.1.5(@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) - '@radix-ui/react-primitive': 2.1.3(@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) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.5))(react@19.2.5) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.5))(react@19.2.5) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.5))(react@19.2.5) '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.5) '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.5) aria-hidden: 1.2.6 react: 19.2.5 - react-dom: 19.2.5(react@19.2.5) + react-dom: 19.2.6(react@19.2.5) react-remove-scroll: 2.7.2(@types/react@19.2.14)(react@19.2.5) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) + '@radix-ui/react-dialog@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.6) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.6) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.14)(react@19.2.6) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.6) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.6) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.6) + aria-hidden: 1.2.6 + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) + react-remove-scroll: 2.7.2(@types/react@19.2.14)(react@19.2.6) + optionalDependencies: + '@types/react': 19.2.14 + '@types/react-dom': 19.2.3(@types/react@19.2.14) + optional: true + '@radix-ui/react-direction@1.1.1(@types/react@19.2.14)(react@19.2.5)': dependencies: react: 19.2.5 optionalDependencies: '@types/react': 19.2.14 - '@radix-ui/react-dismissable-layer@1.1.11(@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)': + '@radix-ui/react-direction@1.1.1(@types/react@19.2.14)(react@19.2.6)': + dependencies: + react: 19.2.6 + optionalDependencies: + '@types/react': 19.2.14 + optional: true + + '@radix-ui/react-dismissable-layer@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.5))(react@19.2.5)': dependencies: '@radix-ui/primitive': 1.1.3 '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.5) - '@radix-ui/react-primitive': 2.1.3(@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) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.5))(react@19.2.5) '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.5) '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.2.14)(react@19.2.5) react: 19.2.5 - react-dom: 19.2.5(react@19.2.5) + react-dom: 19.2.6(react@19.2.5) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) + '@radix-ui/react-dismissable-layer@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.6) + '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.2.14)(react@19.2.6) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) + optionalDependencies: + '@types/react': 19.2.14 + '@types/react-dom': 19.2.3(@types/react@19.2.14) + optional: true + '@radix-ui/react-focus-guards@1.1.3(@types/react@19.2.14)(react@19.2.5)': dependencies: react: 19.2.5 optionalDependencies: '@types/react': 19.2.14 - '@radix-ui/react-focus-scope@1.1.7(@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)': + '@radix-ui/react-focus-guards@1.1.3(@types/react@19.2.14)(react@19.2.6)': + dependencies: + react: 19.2.6 + optionalDependencies: + '@types/react': 19.2.14 + optional: true + + '@radix-ui/react-focus-scope@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.5))(react@19.2.5)': dependencies: '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.5) - '@radix-ui/react-primitive': 2.1.3(@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) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.5))(react@19.2.5) '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.5) react: 19.2.5 - react-dom: 19.2.5(react@19.2.5) + react-dom: 19.2.6(react@19.2.5) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) + '@radix-ui/react-focus-scope@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.6) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) + optionalDependencies: + '@types/react': 19.2.14 + '@types/react-dom': 19.2.3(@types/react@19.2.14) + optional: true + '@radix-ui/react-id@1.1.1(@types/react@19.2.14)(react@19.2.5)': dependencies: '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.5) @@ -10165,52 +10453,110 @@ snapshots: optionalDependencies: '@types/react': 19.2.14 - '@radix-ui/react-portal@1.1.9(@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)': + '@radix-ui/react-id@1.1.1(@types/react@19.2.14)(react@19.2.6)': dependencies: - '@radix-ui/react-primitive': 2.1.3(@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) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.6) + react: 19.2.6 + optionalDependencies: + '@types/react': 19.2.14 + optional: true + + '@radix-ui/react-portal@1.1.9(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.5))(react@19.2.5)': + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.5))(react@19.2.5) '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.5) react: 19.2.5 - react-dom: 19.2.5(react@19.2.5) + react-dom: 19.2.6(react@19.2.5) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-presence@1.1.5(@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)': + '@radix-ui/react-portal@1.1.9(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.6) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) + optionalDependencies: + '@types/react': 19.2.14 + '@types/react-dom': 19.2.3(@types/react@19.2.14) + optional: true + + '@radix-ui/react-presence@1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.5))(react@19.2.5)': dependencies: '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.5) '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.5) react: 19.2.5 - react-dom: 19.2.5(react@19.2.5) + react-dom: 19.2.6(react@19.2.5) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-primitive@2.1.3(@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)': + '@radix-ui/react-presence@1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.6) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.6) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) + optionalDependencies: + '@types/react': 19.2.14 + '@types/react-dom': 19.2.3(@types/react@19.2.14) + optional: true + + '@radix-ui/react-primitive@2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.5))(react@19.2.5)': dependencies: '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.5) react: 19.2.5 - react-dom: 19.2.5(react@19.2.5) + react-dom: 19.2.6(react@19.2.5) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-roving-focus@1.1.11(@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)': + '@radix-ui/react-primitive@2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + dependencies: + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.6) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) + optionalDependencies: + '@types/react': 19.2.14 + '@types/react-dom': 19.2.3(@types/react@19.2.14) + optional: true + + '@radix-ui/react-roving-focus@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.5))(react@19.2.5)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@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) + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.5))(react@19.2.5) '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.5) '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.5) '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.5) '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.5) - '@radix-ui/react-primitive': 2.1.3(@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) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.5))(react@19.2.5) '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.5) '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.5) react: 19.2.5 - react-dom: 19.2.5(react@19.2.5) + react-dom: 19.2.6(react@19.2.5) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) + '@radix-ui/react-roving-focus@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.6) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.6) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.6) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.6) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.6) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) + optionalDependencies: + '@types/react': 19.2.14 + '@types/react-dom': 19.2.3(@types/react@19.2.14) + optional: true + '@radix-ui/react-slot@1.2.3(@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) @@ -10218,6 +10564,14 @@ snapshots: optionalDependencies: '@types/react': 19.2.14 + '@radix-ui/react-slot@1.2.3(@types/react@19.2.14)(react@19.2.6)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.6) + react: 19.2.6 + optionalDependencies: + '@types/react': 19.2.14 + optional: true + '@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) @@ -10225,28 +10579,60 @@ snapshots: 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)': + '@radix-ui/react-slot@1.2.4(@types/react@19.2.14)(react@19.2.6)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.6) + react: 19.2.6 + optionalDependencies: + '@types/react': 19.2.14 + optional: true + + '@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.6(react@19.2.5))(react@19.2.5)': dependencies: '@radix-ui/primitive': 1.1.3 '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.5) '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.5) '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.5) - '@radix-ui/react-presence': 1.1.5(@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) - '@radix-ui/react-primitive': 2.1.3(@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) - '@radix-ui/react-roving-focus': 1.1.11(@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) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.5))(react@19.2.5) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.5))(react@19.2.5) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.5))(react@19.2.5) '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.5) react: 19.2.5 - react-dom: 19.2.5(react@19.2.5) + react-dom: 19.2.6(react@19.2.5) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@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.6(react@19.2.6))(react@19.2.6)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.6) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.6) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.6) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.6) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) + optionalDependencies: + '@types/react': 19.2.14 + '@types/react-dom': 19.2.3(@types/react@19.2.14) + optional: true + '@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.2.14)(react@19.2.5)': dependencies: react: 19.2.5 optionalDependencies: '@types/react': 19.2.14 + '@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.2.14)(react@19.2.6)': + dependencies: + react: 19.2.6 + optionalDependencies: + '@types/react': 19.2.14 + optional: true + '@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.2.14)(react@19.2.5)': dependencies: '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.2.14)(react@19.2.5) @@ -10255,6 +10641,15 @@ snapshots: optionalDependencies: '@types/react': 19.2.14 + '@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.2.14)(react@19.2.6)': + dependencies: + '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.2.14)(react@19.2.6) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.6) + react: 19.2.6 + optionalDependencies: + '@types/react': 19.2.14 + optional: true + '@radix-ui/react-use-effect-event@0.0.2(@types/react@19.2.14)(react@19.2.5)': dependencies: '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.5) @@ -10262,6 +10657,14 @@ snapshots: optionalDependencies: '@types/react': 19.2.14 + '@radix-ui/react-use-effect-event@0.0.2(@types/react@19.2.14)(react@19.2.6)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.6) + react: 19.2.6 + optionalDependencies: + '@types/react': 19.2.14 + optional: true + '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@19.2.14)(react@19.2.5)': dependencies: '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.5) @@ -10269,17 +10672,32 @@ snapshots: optionalDependencies: '@types/react': 19.2.14 + '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@19.2.14)(react@19.2.6)': + dependencies: + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.6) + react: 19.2.6 + optionalDependencies: + '@types/react': 19.2.14 + optional: true + '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.2.14)(react@19.2.5)': dependencies: react: 19.2.5 optionalDependencies: '@types/react': 19.2.14 - '@react-leaflet/core@3.0.0(leaflet@1.9.4)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': + '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.2.14)(react@19.2.6)': + dependencies: + react: 19.2.6 + optionalDependencies: + '@types/react': 19.2.14 + optional: true + + '@react-leaflet/core@3.0.0(leaflet@1.9.4)(react-dom@19.2.6(react@19.2.5))(react@19.2.5)': dependencies: leaflet: 1.9.4 react: 19.2.5 - react-dom: 19.2.5(react@19.2.5) + react-dom: 19.2.6(react@19.2.5) '@react-native/assets-registry@0.83.4': {} @@ -10425,7 +10843,7 @@ snapshots: metro: 0.83.7 metro-config: 0.83.7 metro-core: 0.83.7 - semver: 7.7.4 + semver: 7.8.0 optionalDependencies: '@react-native/metro-config': 0.85.1(@babel/core@7.29.0) transitivePeerDependencies: @@ -10525,10 +10943,20 @@ snapshots: optionalDependencies: '@types/react': 19.2.14 - '@react-navigation/bottom-tabs@7.15.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.7.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-screens@4.24.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/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.6))(react@19.2.6)': dependencies: - '@react-navigation/elements': 2.9.15(@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.7.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) + invariant: 2.2.4 + nullthrows: 1.1.1 + react: 19.2.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.6) + optionalDependencies: + '@types/react': 19.2.14 + optional: true + + '@react-navigation/bottom-tabs@7.15.13(@react-navigation/native@7.2.4(react-native@0.83.4(@babel/core@7.29.0)(@react-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.7.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-screens@4.24.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.17(@react-navigation/native@7.2.4(react-native@0.83.4(@babel/core@7.29.0)(@react-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.7.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.4(react-native@0.83.4(@babel/core@7.29.0)(@react-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)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5) @@ -10538,21 +10966,48 @@ snapshots: transitivePeerDependencies: - '@react-native-masked-view/masked-view' - '@react-navigation/core@7.17.2(react@19.2.5)': + '@react-navigation/bottom-tabs@7.15.13(@react-navigation/native@7.2.4(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-safe-area-context@5.7.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.6))(react@19.2.6))(react-native-screens@4.24.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.6))(react@19.2.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.6))(react@19.2.6)': dependencies: - '@react-navigation/routers': 7.5.3 + '@react-navigation/elements': 2.9.17(@react-navigation/native@7.2.4(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-safe-area-context@5.7.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.6))(react@19.2.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.6))(react@19.2.6) + '@react-navigation/native': 7.2.4(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) + color: 4.2.3 + react: 19.2.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.6) + react-native-safe-area-context: 5.7.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.6))(react@19.2.6) + react-native-screens: 4.24.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.6))(react@19.2.6) + sf-symbols-typescript: 2.2.0 + transitivePeerDependencies: + - '@react-native-masked-view/masked-view' + optional: true + + '@react-navigation/core@7.17.4(react@19.2.5)': + dependencies: + '@react-navigation/routers': 7.5.5 escape-string-regexp: 4.0.0 fast-deep-equal: 3.1.3 nanoid: 3.3.12 query-string: 7.1.3 react: 19.2.5 - react-is: 19.2.5 + react-is: 19.2.6 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.15(@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.7.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/core@7.17.4(react@19.2.6)': dependencies: - '@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/routers': 7.5.5 + escape-string-regexp: 4.0.0 + fast-deep-equal: 3.1.3 + nanoid: 3.3.12 + query-string: 7.1.3 + react: 19.2.6 + react-is: 19.2.6 + use-latest-callback: 0.2.6(react@19.2.6) + use-sync-external-store: 1.6.0(react@19.2.6) + optional: true + + '@react-navigation/elements@2.9.17(@react-navigation/native@7.2.4(react-native@0.83.4(@babel/core@7.29.0)(@react-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.7.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/native': 7.2.4(react-native@0.83.4(@babel/core@7.29.0)(@react-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)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5) @@ -10560,10 +11015,21 @@ 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.12(@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.7.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-screens@4.24.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/elements@2.9.17(@react-navigation/native@7.2.4(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-safe-area-context@5.7.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.6))(react@19.2.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.6))(react@19.2.6)': dependencies: - '@react-navigation/elements': 2.9.15(@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.7.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': 7.2.4(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) + color: 4.2.3 + react: 19.2.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.6) + react-native-safe-area-context: 5.7.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.6))(react@19.2.6) + use-latest-callback: 0.2.6(react@19.2.6) + use-sync-external-store: 1.6.0(react@19.2.6) + optional: true + + '@react-navigation/native-stack@7.14.14(@react-navigation/native@7.2.4(react-native@0.83.4(@babel/core@7.29.0)(@react-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.7.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-screens@4.24.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.17(@react-navigation/native@7.2.4(react-native@0.83.4(@babel/core@7.29.0)(@react-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.7.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.4(react-native@0.83.4(@babel/core@7.29.0)(@react-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)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5) @@ -10574,9 +11040,24 @@ snapshots: transitivePeerDependencies: - '@react-native-masked-view/masked-view' - '@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.14(@react-navigation/native@7.2.4(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-safe-area-context@5.7.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.6))(react@19.2.6))(react-native-screens@4.24.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.6))(react@19.2.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.6))(react@19.2.6)': dependencies: - '@react-navigation/core': 7.17.2(react@19.2.5) + '@react-navigation/elements': 2.9.17(@react-navigation/native@7.2.4(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-safe-area-context@5.7.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.6))(react@19.2.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.6))(react@19.2.6) + '@react-navigation/native': 7.2.4(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) + color: 4.2.3 + react: 19.2.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.6) + react-native-safe-area-context: 5.7.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.6))(react@19.2.6) + react-native-screens: 4.24.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.6))(react@19.2.6) + sf-symbols-typescript: 2.2.0 + warn-once: 0.1.1 + transitivePeerDependencies: + - '@react-native-masked-view/masked-view' + optional: true + + '@react-navigation/native@7.2.4(react-native@0.83.4(@babel/core@7.29.0)(@react-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.4(react@19.2.5) escape-string-regexp: 4.0.0 fast-deep-equal: 3.1.3 nanoid: 3.3.12 @@ -10584,11 +11065,22 @@ 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) use-latest-callback: 0.2.6(react@19.2.5) - '@react-navigation/routers@7.5.3': + '@react-navigation/native@7.2.4(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)': + dependencies: + '@react-navigation/core': 7.17.4(react@19.2.6) + escape-string-regexp: 4.0.0 + fast-deep-equal: 3.1.3 + nanoid: 3.3.12 + react: 19.2.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.6) + use-latest-callback: 0.2.6(react@19.2.6) + optional: true + + '@react-navigation/routers@7.5.5': dependencies: nanoid: 3.3.12 - '@react-router/dev@7.14.2(@react-router/serve@7.14.2(react-router@7.14.2(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.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.4))(yaml@2.8.4)': + '@react-router/dev@7.15.0(@react-router/serve@7.15.0(react-router@7.15.0(react-dom@19.2.6(react@19.2.5))(react@19.2.5))(typescript@5.9.3))(@types/node@25.6.2)(jiti@2.7.0)(lightningcss@1.32.0)(react-router@7.15.0(react-dom@19.2.6(react@19.2.5))(react@19.2.5))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4))(yaml@2.8.4)': dependencies: '@babel/core': 7.29.0 '@babel/generator': 7.29.1 @@ -10597,31 +11089,31 @@ 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.2(react-router@7.14.2(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 + '@react-router/node': 7.15.0(react-router@7.15.0(react-dom@19.2.6(react@19.2.5))(react@19.2.5))(typescript@5.9.3) + '@remix-run/node-fetch-server': 0.13.1 arg: 5.0.2 babel-dead-code-elimination: 1.0.12 chokidar: 4.0.3 dedent: 1.7.2 es-module-lexer: 1.7.0 exit-hook: 2.2.1 - isbot: 5.1.39 + isbot: 5.1.40 jsesc: 3.0.2 lodash: 4.18.1 p-map: 7.0.4 pathe: 1.1.2 picocolors: 1.1.1 - pkg-types: 2.3.0 + pkg-types: 2.3.1 prettier: 3.8.3 react-refresh: 0.14.2 - react-router: 7.14.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5) - semver: 7.7.4 + react-router: 7.15.0(react-dom@19.2.6(react@19.2.5))(react@19.2.5) + semver: 7.8.0 tinyglobby: 0.2.16 - valibot: 1.3.1(typescript@5.9.3) - vite: 8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.4) - vite-node: 3.2.4(@types/node@25.6.0)(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.4) + valibot: 1.4.0(typescript@5.9.3) + vite: 8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4) + vite-node: 3.2.4(@types/node@25.6.2)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4) optionalDependencies: - '@react-router/serve': 7.14.2(react-router@7.14.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3) + '@react-router/serve': 7.15.0(react-router@7.15.0(react-dom@19.2.6(react@19.2.5))(react@19.2.5))(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - '@types/node' @@ -10638,37 +11130,37 @@ snapshots: - tsx - yaml - '@react-router/express@7.14.2(express@4.22.1)(react-router@7.14.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3)': + '@react-router/express@7.15.0(express@4.22.1)(react-router@7.15.0(react-dom@19.2.6(react@19.2.5))(react@19.2.5))(typescript@5.9.3)': dependencies: - '@react-router/node': 7.14.2(react-router@7.14.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3) + '@react-router/node': 7.15.0(react-router@7.15.0(react-dom@19.2.6(react@19.2.5))(react@19.2.5))(typescript@5.9.3) express: 4.22.1 - react-router: 7.14.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + react-router: 7.15.0(react-dom@19.2.6(react@19.2.5))(react@19.2.5) optionalDependencies: typescript: 5.9.3 - '@react-router/node@7.14.2(react-router@7.14.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3)': + '@react-router/node@7.15.0(react-router@7.15.0(react-dom@19.2.6(react@19.2.5))(react@19.2.5))(typescript@5.9.3)': dependencies: '@mjackson/node-fetch-server': 0.2.0 - react-router: 7.14.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + react-router: 7.15.0(react-dom@19.2.6(react@19.2.5))(react@19.2.5) optionalDependencies: typescript: 5.9.3 - '@react-router/serve@7.14.2(react-router@7.14.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3)': + '@react-router/serve@7.15.0(react-router@7.15.0(react-dom@19.2.6(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.2(express@4.22.1)(react-router@7.14.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3) - '@react-router/node': 7.14.2(react-router@7.14.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3) + '@react-router/express': 7.15.0(express@4.22.1)(react-router@7.15.0(react-dom@19.2.6(react@19.2.5))(react@19.2.5))(typescript@5.9.3) + '@react-router/node': 7.15.0(react-router@7.15.0(react-dom@19.2.6(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.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + react-router: 7.15.0(react-dom@19.2.6(react@19.2.5))(react@19.2.5) source-map-support: 0.5.21 transitivePeerDependencies: - supports-color - typescript - '@remix-run/node-fetch-server@0.13.0': {} + '@remix-run/node-fetch-server@0.13.1': {} '@rolldown/binding-android-arm64@1.0.0-rc.17': optional: true @@ -10721,99 +11213,117 @@ snapshots: '@rolldown/pluginutils@1.0.0-rc.17': {} - '@rollup/rollup-android-arm-eabi@4.60.2': + '@rollup/rollup-android-arm-eabi@4.60.3': optional: true - '@rollup/rollup-android-arm64@4.60.2': + '@rollup/rollup-android-arm64@4.60.3': optional: true - '@rollup/rollup-darwin-arm64@4.60.2': + '@rollup/rollup-darwin-arm64@4.60.3': optional: true - '@rollup/rollup-darwin-x64@4.60.2': + '@rollup/rollup-darwin-x64@4.60.3': optional: true - '@rollup/rollup-freebsd-arm64@4.60.2': + '@rollup/rollup-freebsd-arm64@4.60.3': optional: true - '@rollup/rollup-freebsd-x64@4.60.2': + '@rollup/rollup-freebsd-x64@4.60.3': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.60.2': + '@rollup/rollup-linux-arm-gnueabihf@4.60.3': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.60.2': + '@rollup/rollup-linux-arm-musleabihf@4.60.3': optional: true - '@rollup/rollup-linux-arm64-gnu@4.60.2': + '@rollup/rollup-linux-arm64-gnu@4.60.3': optional: true - '@rollup/rollup-linux-arm64-musl@4.60.2': + '@rollup/rollup-linux-arm64-musl@4.60.3': optional: true - '@rollup/rollup-linux-loong64-gnu@4.60.2': + '@rollup/rollup-linux-loong64-gnu@4.60.3': optional: true - '@rollup/rollup-linux-loong64-musl@4.60.2': + '@rollup/rollup-linux-loong64-musl@4.60.3': optional: true - '@rollup/rollup-linux-ppc64-gnu@4.60.2': + '@rollup/rollup-linux-ppc64-gnu@4.60.3': optional: true - '@rollup/rollup-linux-ppc64-musl@4.60.2': + '@rollup/rollup-linux-ppc64-musl@4.60.3': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.60.2': + '@rollup/rollup-linux-riscv64-gnu@4.60.3': optional: true - '@rollup/rollup-linux-riscv64-musl@4.60.2': + '@rollup/rollup-linux-riscv64-musl@4.60.3': optional: true - '@rollup/rollup-linux-s390x-gnu@4.60.2': + '@rollup/rollup-linux-s390x-gnu@4.60.3': optional: true - '@rollup/rollup-linux-x64-gnu@4.60.2': + '@rollup/rollup-linux-x64-gnu@4.60.3': optional: true - '@rollup/rollup-linux-x64-musl@4.60.2': + '@rollup/rollup-linux-x64-musl@4.60.3': optional: true - '@rollup/rollup-openbsd-x64@4.60.2': + '@rollup/rollup-openbsd-x64@4.60.3': optional: true - '@rollup/rollup-openharmony-arm64@4.60.2': + '@rollup/rollup-openharmony-arm64@4.60.3': optional: true - '@rollup/rollup-win32-arm64-msvc@4.60.2': + '@rollup/rollup-win32-arm64-msvc@4.60.3': optional: true - '@rollup/rollup-win32-ia32-msvc@4.60.2': + '@rollup/rollup-win32-ia32-msvc@4.60.3': optional: true - '@rollup/rollup-win32-x64-gnu@4.60.2': + '@rollup/rollup-win32-x64-gnu@4.60.3': optional: true - '@rollup/rollup-win32-x64-msvc@4.60.2': + '@rollup/rollup-win32-x64-msvc@4.60.3': optional: true '@sentry-internal/browser-utils@10.51.0': dependencies: '@sentry/core': 10.51.0 + '@sentry-internal/browser-utils@10.52.0': + dependencies: + '@sentry/core': 10.52.0 + '@sentry-internal/feedback@10.51.0': dependencies: '@sentry/core': 10.51.0 + '@sentry-internal/feedback@10.52.0': + dependencies: + '@sentry/core': 10.52.0 + '@sentry-internal/replay-canvas@10.51.0': dependencies: '@sentry-internal/replay': 10.51.0 '@sentry/core': 10.51.0 + '@sentry-internal/replay-canvas@10.52.0': + dependencies: + '@sentry-internal/replay': 10.52.0 + '@sentry/core': 10.52.0 + '@sentry-internal/replay@10.51.0': dependencies: '@sentry-internal/browser-utils': 10.51.0 '@sentry/core': 10.51.0 + '@sentry-internal/replay@10.52.0': + dependencies: + '@sentry-internal/browser-utils': 10.52.0 + '@sentry/core': 10.52.0 + '@sentry/babel-plugin-component-annotate@5.2.1': {} '@sentry/browser@10.51.0': @@ -10824,6 +11334,14 @@ snapshots: '@sentry-internal/replay-canvas': 10.51.0 '@sentry/core': 10.51.0 + '@sentry/browser@10.52.0': + dependencies: + '@sentry-internal/browser-utils': 10.52.0 + '@sentry-internal/feedback': 10.52.0 + '@sentry-internal/replay': 10.52.0 + '@sentry-internal/replay-canvas': 10.52.0 + '@sentry/core': 10.52.0 + '@sentry/bundler-plugin-core@5.2.1': dependencies: '@babel/core': 7.29.0 @@ -10923,17 +11441,19 @@ snapshots: '@sentry/core@10.51.0': {} - '@sentry/expo-upload-sourcemaps@8.10.0(@expo/env@2.1.1)(dotenv@16.6.1)': + '@sentry/core@10.52.0': {} + + '@sentry/expo-upload-sourcemaps@8.11.0(@expo/env@2.1.2)(dotenv@16.6.1)': dependencies: '@sentry/cli': 3.4.1 optionalDependencies: - '@expo/env': 2.1.1 + '@expo/env': 2.1.2 dotenv: 16.6.1 - '@sentry/node-core@10.51.0(@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/sdk-trace-base@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/semantic-conventions@1.40.0)': + '@sentry/node-core@10.52.0(@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/sdk-trace-base@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/semantic-conventions@1.40.0)': dependencies: - '@sentry/core': 10.51.0 - '@sentry/opentelemetry': 10.51.0(@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) + '@sentry/core': 10.52.0 + '@sentry/opentelemetry': 10.52.0(@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.1 optionalDependencies: '@opentelemetry/api': 1.9.1 @@ -10942,7 +11462,7 @@ snapshots: '@opentelemetry/sdk-trace-base': 2.6.1(@opentelemetry/api@1.9.1) '@opentelemetry/semantic-conventions': 1.40.0 - '@sentry/node@10.51.0': + '@sentry/node@10.52.0': dependencies: '@fastify/otel': 0.18.0(@opentelemetry/api@1.9.1) '@opentelemetry/api': 1.9.1 @@ -10956,7 +11476,6 @@ snapshots: '@opentelemetry/instrumentation-graphql': 0.62.0(@opentelemetry/api@1.9.1) '@opentelemetry/instrumentation-hapi': 0.60.0(@opentelemetry/api@1.9.1) '@opentelemetry/instrumentation-http': 0.214.0(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation-ioredis': 0.62.0(@opentelemetry/api@1.9.1) '@opentelemetry/instrumentation-kafkajs': 0.23.0(@opentelemetry/api@1.9.1) '@opentelemetry/instrumentation-knex': 0.58.0(@opentelemetry/api@1.9.1) '@opentelemetry/instrumentation-koa': 0.62.0(@opentelemetry/api@1.9.1) @@ -10966,40 +11485,39 @@ snapshots: '@opentelemetry/instrumentation-mysql': 0.60.0(@opentelemetry/api@1.9.1) '@opentelemetry/instrumentation-mysql2': 0.60.0(@opentelemetry/api@1.9.1) '@opentelemetry/instrumentation-pg': 0.66.0(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation-redis': 0.62.0(@opentelemetry/api@1.9.1) '@opentelemetry/instrumentation-tedious': 0.33.0(@opentelemetry/api@1.9.1) '@opentelemetry/sdk-trace-base': 2.6.1(@opentelemetry/api@1.9.1) '@opentelemetry/semantic-conventions': 1.40.0 '@prisma/instrumentation': 7.6.0(@opentelemetry/api@1.9.1) - '@sentry/core': 10.51.0 - '@sentry/node-core': 10.51.0(@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/sdk-trace-base@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/semantic-conventions@1.40.0) - '@sentry/opentelemetry': 10.51.0(@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) + '@sentry/core': 10.52.0 + '@sentry/node-core': 10.52.0(@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/sdk-trace-base@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/semantic-conventions@1.40.0) + '@sentry/opentelemetry': 10.52.0(@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.1 transitivePeerDependencies: - '@opentelemetry/exporter-trace-otlp-http' - supports-color - '@sentry/opentelemetry@10.51.0(@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)': + '@sentry/opentelemetry@10.52.0(@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)': dependencies: '@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 - '@sentry/core': 10.51.0 + '@sentry/core': 10.52.0 - '@sentry/react-native@8.10.0(@expo/env@2.1.1)(dotenv@16.6.1)(expo@55.0.19)(react-native@0.83.4(@babel/core@7.29.0)(@react-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@8.11.0(@expo/env@2.1.2)(dotenv@16.6.1)(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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': 5.2.1 '@sentry/browser': 10.51.0 '@sentry/cli': 3.4.1 '@sentry/core': 10.51.0 - '@sentry/expo-upload-sourcemaps': 8.10.0(@expo/env@2.1.1)(dotenv@16.6.1) + '@sentry/expo-upload-sourcemaps': 8.11.0(@expo/env@2.1.2)(dotenv@16.6.1) '@sentry/react': 10.51.0(react@19.2.5) '@sentry/types': 10.51.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) optionalDependencies: - expo: 55.0.19(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.13)(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.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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: - '@expo/env' - dotenv @@ -11010,12 +11528,18 @@ snapshots: '@sentry/core': 10.51.0 react: 19.2.5 - '@sentry/rollup-plugin@5.2.1(rollup@4.60.2)': + '@sentry/react@10.52.0(react@19.2.5)': + dependencies: + '@sentry/browser': 10.52.0 + '@sentry/core': 10.52.0 + react: 19.2.5 + + '@sentry/rollup-plugin@5.2.1(rollup@4.60.3)': dependencies: '@sentry/bundler-plugin-core': 5.2.1 magic-string: 0.30.21 optionalDependencies: - rollup: 4.60.2 + rollup: 4.60.3 transitivePeerDependencies: - encoding - supports-color @@ -11024,10 +11548,10 @@ snapshots: dependencies: '@sentry/core': 10.51.0 - '@sentry/vite-plugin@5.2.1(rollup@4.60.2)': + '@sentry/vite-plugin@5.2.1(rollup@4.60.3)': dependencies: '@sentry/bundler-plugin-core': 5.2.1 - '@sentry/rollup-plugin': 5.2.1(rollup@4.60.2) + '@sentry/rollup-plugin': 5.2.1(rollup@4.60.3) transitivePeerDependencies: - encoding - rollup @@ -11062,73 +11586,73 @@ snapshots: '@standard-schema/spec@1.1.0': {} - '@tailwindcss/node@4.2.4': + '@tailwindcss/node@4.3.0': dependencies: '@jridgewell/remapping': 2.3.5 - enhanced-resolve: 5.21.0 - jiti: 2.6.1 + enhanced-resolve: 5.21.2 + jiti: 2.7.0 lightningcss: 1.32.0 magic-string: 0.30.21 source-map-js: 1.2.1 - tailwindcss: 4.2.4 + tailwindcss: 4.3.0 - '@tailwindcss/oxide-android-arm64@4.2.4': + '@tailwindcss/oxide-android-arm64@4.3.0': optional: true - '@tailwindcss/oxide-darwin-arm64@4.2.4': + '@tailwindcss/oxide-darwin-arm64@4.3.0': optional: true - '@tailwindcss/oxide-darwin-x64@4.2.4': + '@tailwindcss/oxide-darwin-x64@4.3.0': optional: true - '@tailwindcss/oxide-freebsd-x64@4.2.4': + '@tailwindcss/oxide-freebsd-x64@4.3.0': optional: true - '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.4': + '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.0': optional: true - '@tailwindcss/oxide-linux-arm64-gnu@4.2.4': + '@tailwindcss/oxide-linux-arm64-gnu@4.3.0': optional: true - '@tailwindcss/oxide-linux-arm64-musl@4.2.4': + '@tailwindcss/oxide-linux-arm64-musl@4.3.0': optional: true - '@tailwindcss/oxide-linux-x64-gnu@4.2.4': + '@tailwindcss/oxide-linux-x64-gnu@4.3.0': optional: true - '@tailwindcss/oxide-linux-x64-musl@4.2.4': + '@tailwindcss/oxide-linux-x64-musl@4.3.0': optional: true - '@tailwindcss/oxide-wasm32-wasi@4.2.4': + '@tailwindcss/oxide-wasm32-wasi@4.3.0': optional: true - '@tailwindcss/oxide-win32-arm64-msvc@4.2.4': + '@tailwindcss/oxide-win32-arm64-msvc@4.3.0': optional: true - '@tailwindcss/oxide-win32-x64-msvc@4.2.4': + '@tailwindcss/oxide-win32-x64-msvc@4.3.0': optional: true - '@tailwindcss/oxide@4.2.4': + '@tailwindcss/oxide@4.3.0': optionalDependencies: - '@tailwindcss/oxide-android-arm64': 4.2.4 - '@tailwindcss/oxide-darwin-arm64': 4.2.4 - '@tailwindcss/oxide-darwin-x64': 4.2.4 - '@tailwindcss/oxide-freebsd-x64': 4.2.4 - '@tailwindcss/oxide-linux-arm-gnueabihf': 4.2.4 - '@tailwindcss/oxide-linux-arm64-gnu': 4.2.4 - '@tailwindcss/oxide-linux-arm64-musl': 4.2.4 - '@tailwindcss/oxide-linux-x64-gnu': 4.2.4 - '@tailwindcss/oxide-linux-x64-musl': 4.2.4 - '@tailwindcss/oxide-wasm32-wasi': 4.2.4 - '@tailwindcss/oxide-win32-arm64-msvc': 4.2.4 - '@tailwindcss/oxide-win32-x64-msvc': 4.2.4 + '@tailwindcss/oxide-android-arm64': 4.3.0 + '@tailwindcss/oxide-darwin-arm64': 4.3.0 + '@tailwindcss/oxide-darwin-x64': 4.3.0 + '@tailwindcss/oxide-freebsd-x64': 4.3.0 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.3.0 + '@tailwindcss/oxide-linux-arm64-gnu': 4.3.0 + '@tailwindcss/oxide-linux-arm64-musl': 4.3.0 + '@tailwindcss/oxide-linux-x64-gnu': 4.3.0 + '@tailwindcss/oxide-linux-x64-musl': 4.3.0 + '@tailwindcss/oxide-wasm32-wasi': 4.3.0 + '@tailwindcss/oxide-win32-arm64-msvc': 4.3.0 + '@tailwindcss/oxide-win32-x64-msvc': 4.3.0 - '@tailwindcss/vite@4.2.4(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.4))': + '@tailwindcss/vite@4.3.0(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4))': dependencies: - '@tailwindcss/node': 4.2.4 - '@tailwindcss/oxide': 4.2.4 - tailwindcss: 4.2.4 - vite: 8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.4) + '@tailwindcss/node': 4.3.0 + '@tailwindcss/oxide': 4.3.0 + tailwindcss: 4.3.0 + vite: 8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4) '@testing-library/dom@10.4.1': dependencies: @@ -11150,46 +11674,59 @@ snapshots: picocolors: 1.1.1 redent: 3.0.0 - '@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)': + '@testing-library/react-native@13.3.3(jest@29.7.0(@types/node@22.19.18))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react-test-renderer@19.2.6(react@19.2.6))(react@19.2.6)': + dependencies: + jest-matcher-utils: 30.3.0 + picocolors: 1.1.1 + pretty-format: 30.3.0 + react: 19.2.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.6) + react-test-renderer: 19.2.6(react@19.2.6) + redent: 3.0.0 + optionalDependencies: + jest: 29.7.0(@types/node@22.19.18) + optional: true + + '@testing-library/react-native@13.3.3(jest@29.7.0(@types/node@25.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-test-renderer@19.2.6(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)(@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-test-renderer: 19.2.6(react@19.2.5) redent: 3.0.0 optionalDependencies: - jest: 29.7.0(@types/node@25.6.0) + jest: 29.7.0(@types/node@25.6.2) - '@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)': + '@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.6(react@19.2.5))(react@19.2.5)': dependencies: '@babel/runtime': 7.29.2 '@testing-library/dom': 10.4.1 react: 19.2.5 - react-dom: 19.2.5(react@19.2.5) + react-dom: 19.2.6(react@19.2.5) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@tootallnate/once@2.0.0': {} + '@tootallnate/once@2.0.1': {} - '@turbo/darwin-64@2.9.8': + '@turbo/darwin-64@2.9.12': optional: true - '@turbo/darwin-arm64@2.9.8': + '@turbo/darwin-arm64@2.9.12': optional: true - '@turbo/linux-64@2.9.8': + '@turbo/linux-64@2.9.12': optional: true - '@turbo/linux-arm64@2.9.8': + '@turbo/linux-arm64@2.9.12': optional: true - '@turbo/windows-64@2.9.8': + '@turbo/windows-64@2.9.12': optional: true - '@turbo/windows-arm64@2.9.8': + '@turbo/windows-arm64@2.9.12': optional: true '@turf/bbox@7.3.4': @@ -11385,7 +11922,7 @@ snapshots: '@types/connect@3.4.38': dependencies: - '@types/node': 25.6.0 + '@types/node': 25.6.2 '@types/deep-eql@4.0.2': {} @@ -11393,11 +11930,13 @@ snapshots: '@types/estree@1.0.8': {} + '@types/estree@1.0.9': {} + '@types/geojson@7946.0.16': {} '@types/graceful-fs@4.1.9': dependencies: - '@types/node': 25.6.0 + '@types/node': 25.6.2 '@types/hammerjs@2.0.46': {} @@ -11418,7 +11957,7 @@ snapshots: '@types/jsdom@20.0.1': dependencies: - '@types/node': 25.6.0 + '@types/node': 25.6.2 '@types/tough-cookie': 4.0.5 parse5: 7.3.0 @@ -11434,9 +11973,9 @@ snapshots: '@types/mysql@2.15.27': dependencies: - '@types/node': 25.6.0 + '@types/node': 25.6.2 - '@types/node@22.19.17': + '@types/node@22.19.18': dependencies: undici-types: 6.21.0 @@ -11444,6 +11983,10 @@ snapshots: dependencies: undici-types: 7.19.2 + '@types/node@25.6.2': + dependencies: + undici-types: 7.19.2 + '@types/nodemailer@8.0.0': dependencies: '@types/node': 25.6.0 @@ -11454,7 +11997,7 @@ snapshots: '@types/pg@8.15.6': dependencies: - '@types/node': 25.6.0 + '@types/node': 25.6.2 pg-protocol: 1.13.0 pg-types: 2.2.0 @@ -11474,7 +12017,7 @@ snapshots: '@types/tedious@4.0.14': dependencies: - '@types/node': 25.6.0 + '@types/node': 25.6.2 '@types/tough-cookie@4.0.5': {} @@ -11488,15 +12031,15 @@ snapshots: dependencies: '@types/yargs-parser': 21.0.3 - '@typescript-eslint/eslint-plugin@8.59.1(@typescript-eslint/parser@8.59.1(eslint@10.3.0(jiti@2.6.1))(typescript@5.9.3))(eslint@10.3.0(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/eslint-plugin@8.59.2(@typescript-eslint/parser@8.59.2(eslint@10.3.0(jiti@2.7.0))(typescript@5.9.3))(eslint@10.3.0(jiti@2.7.0))(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.59.1(eslint@10.3.0(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.59.1 - '@typescript-eslint/type-utils': 8.59.1(eslint@10.3.0(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/utils': 8.59.1(eslint@10.3.0(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.59.1 - eslint: 10.3.0(jiti@2.6.1) + '@typescript-eslint/parser': 8.59.2(eslint@10.3.0(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.59.2 + '@typescript-eslint/type-utils': 8.59.2(eslint@10.3.0(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/utils': 8.59.2(eslint@10.3.0(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.59.2 + eslint: 10.3.0(jiti@2.7.0) ignore: 7.0.5 natural-compare: 1.4.0 ts-api-utils: 2.5.0(typescript@5.9.3) @@ -11504,86 +12047,86 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.59.1(eslint@10.3.0(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/parser@8.59.2(eslint@10.3.0(jiti@2.7.0))(typescript@5.9.3)': dependencies: - '@typescript-eslint/scope-manager': 8.59.1 - '@typescript-eslint/types': 8.59.1 - '@typescript-eslint/typescript-estree': 8.59.1(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.59.1 + '@typescript-eslint/scope-manager': 8.59.2 + '@typescript-eslint/types': 8.59.2 + '@typescript-eslint/typescript-estree': 8.59.2(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.59.2 debug: 4.4.3 - eslint: 10.3.0(jiti@2.6.1) + eslint: 10.3.0(jiti@2.7.0) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.59.1(typescript@5.9.3)': + '@typescript-eslint/project-service@8.59.2(typescript@5.9.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.59.1(typescript@5.9.3) - '@typescript-eslint/types': 8.59.1 + '@typescript-eslint/tsconfig-utils': 8.59.2(typescript@5.9.3) + '@typescript-eslint/types': 8.59.2 debug: 4.4.3 typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@8.59.1': + '@typescript-eslint/scope-manager@8.59.2': dependencies: - '@typescript-eslint/types': 8.59.1 - '@typescript-eslint/visitor-keys': 8.59.1 + '@typescript-eslint/types': 8.59.2 + '@typescript-eslint/visitor-keys': 8.59.2 - '@typescript-eslint/tsconfig-utils@8.59.1(typescript@5.9.3)': + '@typescript-eslint/tsconfig-utils@8.59.2(typescript@5.9.3)': dependencies: typescript: 5.9.3 - '@typescript-eslint/type-utils@8.59.1(eslint@10.3.0(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/type-utils@8.59.2(eslint@10.3.0(jiti@2.7.0))(typescript@5.9.3)': dependencies: - '@typescript-eslint/types': 8.59.1 - '@typescript-eslint/typescript-estree': 8.59.1(typescript@5.9.3) - '@typescript-eslint/utils': 8.59.1(eslint@10.3.0(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/types': 8.59.2 + '@typescript-eslint/typescript-estree': 8.59.2(typescript@5.9.3) + '@typescript-eslint/utils': 8.59.2(eslint@10.3.0(jiti@2.7.0))(typescript@5.9.3) debug: 4.4.3 - eslint: 10.3.0(jiti@2.6.1) + eslint: 10.3.0(jiti@2.7.0) ts-api-utils: 2.5.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/types@8.59.1': {} + '@typescript-eslint/types@8.59.2': {} - '@typescript-eslint/typescript-estree@8.59.1(typescript@5.9.3)': + '@typescript-eslint/typescript-estree@8.59.2(typescript@5.9.3)': dependencies: - '@typescript-eslint/project-service': 8.59.1(typescript@5.9.3) - '@typescript-eslint/tsconfig-utils': 8.59.1(typescript@5.9.3) - '@typescript-eslint/types': 8.59.1 - '@typescript-eslint/visitor-keys': 8.59.1 + '@typescript-eslint/project-service': 8.59.2(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.59.2(typescript@5.9.3) + '@typescript-eslint/types': 8.59.2 + '@typescript-eslint/visitor-keys': 8.59.2 debug: 4.4.3 minimatch: 10.2.5 - semver: 7.7.4 + semver: 7.8.0 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.59.1(eslint@10.3.0(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/utils@8.59.2(eslint@10.3.0(jiti@2.7.0))(typescript@5.9.3)': dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.3.0(jiti@2.6.1)) - '@typescript-eslint/scope-manager': 8.59.1 - '@typescript-eslint/types': 8.59.1 - '@typescript-eslint/typescript-estree': 8.59.1(typescript@5.9.3) - eslint: 10.3.0(jiti@2.6.1) + '@eslint-community/eslint-utils': 4.9.1(eslint@10.3.0(jiti@2.7.0)) + '@typescript-eslint/scope-manager': 8.59.2 + '@typescript-eslint/types': 8.59.2 + '@typescript-eslint/typescript-estree': 8.59.2(typescript@5.9.3) + eslint: 10.3.0(jiti@2.7.0) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@8.59.1': + '@typescript-eslint/visitor-keys@8.59.2': dependencies: - '@typescript-eslint/types': 8.59.1 + '@typescript-eslint/types': 8.59.2 eslint-visitor-keys: 5.0.1 - '@ungap/structured-clone@1.3.0': {} + '@ungap/structured-clone@1.3.1': {} - '@vitejs/plugin-basic-ssl@2.3.0(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.4))': + '@vitejs/plugin-basic-ssl@2.3.0(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4))': dependencies: - vite: 8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.4) + vite: 8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4) '@vitest/expect@4.1.5': dependencies: @@ -11594,13 +12137,13 @@ snapshots: chai: 6.2.2 tinyrainbow: 3.1.0 - '@vitest/mocker@4.1.5(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.4))': + '@vitest/mocker@4.1.5(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4))': dependencies: '@vitest/spy': 4.1.5 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.4) + vite: 8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4) '@vitest/pretty-format@4.1.5': dependencies: @@ -11851,7 +12394,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.19(@babel/core@7.29.0)(@babel/runtime@7.29.2)(expo@55.0.19)(react-refresh@0.14.2): + babel-preset-expo@55.0.21(@babel/core@7.29.0)(@babel/runtime@7.29.2)(expo@55.0.23)(react-refresh@0.14.2): dependencies: '@babel/generator': 7.29.1 '@babel/helper-module-imports': 7.28.6 @@ -11879,7 +12422,7 @@ snapshots: resolve-from: 5.0.0 optionalDependencies: '@babel/runtime': 7.29.2 - expo: 55.0.19(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.13)(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.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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 @@ -11898,7 +12441,7 @@ snapshots: base64-js@1.5.1: {} - baseline-browser-mapping@2.10.25: {} + baseline-browser-mapping@2.10.29: {} basic-auth@2.0.1: dependencies: @@ -11954,7 +12497,7 @@ snapshots: balanced-match: 1.0.2 concat-map: 0.0.1 - brace-expansion@5.0.5: + brace-expansion@5.0.6: dependencies: balanced-match: 4.0.4 @@ -11964,9 +12507,9 @@ snapshots: browserslist@4.28.2: dependencies: - baseline-browser-mapping: 2.10.25 - caniuse-lite: 1.0.30001791 - electron-to-chromium: 1.5.349 + baseline-browser-mapping: 2.10.29 + caniuse-lite: 1.0.30001792 + electron-to-chromium: 1.5.353 node-releases: 2.0.38 update-browserslist-db: 1.2.3(browserslist@4.28.2) @@ -12001,7 +12544,7 @@ snapshots: camelcase@6.3.0: {} - caniuse-lite@1.0.30001791: {} + caniuse-lite@1.0.30001792: {} chai@6.2.2: {} @@ -12035,7 +12578,7 @@ snapshots: chrome-launcher@0.15.2: dependencies: - '@types/node': 25.6.0 + '@types/node': 25.6.2 escape-string-regexp: 4.0.0 is-wsl: 2.2.0 lighthouse-logger: 1.4.2 @@ -12044,7 +12587,7 @@ snapshots: chromium-edge-launcher@0.2.0: dependencies: - '@types/node': 25.6.0 + '@types/node': 25.6.2 escape-string-regexp: 4.0.0 is-wsl: 2.2.0 lighthouse-logger: 1.4.2 @@ -12093,7 +12636,7 @@ snapshots: '@codemirror/lint': 6.9.5 '@codemirror/search': 6.6.0 '@codemirror/state': 6.6.0 - '@codemirror/view': 6.41.1 + '@codemirror/view': 6.42.1 collect-v8-coverage@1.0.3: {} @@ -12180,13 +12723,29 @@ snapshots: dependencies: browserslist: 4.28.2 - create-jest@29.7.0(@types/node@25.6.0): + create-jest@29.7.0(@types/node@22.19.18): 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.6.0) + jest-config: 29.7.0(@types/node@22.19.18) + jest-util: 29.7.0 + prompts: 2.4.2 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + optional: true + + create-jest@29.7.0(@types/node@25.6.2): + 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.6.2) jest-util: 29.7.0 prompts: 2.4.2 transitivePeerDependencies: @@ -12330,11 +12889,19 @@ 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.19)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.19)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(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.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) pg: 8.20.0 postgres: 3.4.9 @@ -12350,7 +12917,7 @@ snapshots: ee-first@1.1.1: {} - electron-to-chromium@1.5.349: {} + electron-to-chromium@1.5.353: {} emittery@0.13.1: {} @@ -12366,7 +12933,7 @@ snapshots: dependencies: once: 1.4.0 - enhanced-resolve@5.21.0: + enhanced-resolve@5.21.2: dependencies: graceful-fs: 4.2.11 tapable: 2.3.3 @@ -12507,9 +13074,9 @@ snapshots: optionalDependencies: source-map: 0.6.1 - eslint-config-prettier@10.1.8(eslint@10.3.0(jiti@2.6.1)): + eslint-config-prettier@10.1.8(eslint@10.3.0(jiti@2.7.0)): dependencies: - eslint: 10.3.0(jiti@2.6.1) + eslint: 10.3.0(jiti@2.7.0) eslint-scope@9.1.2: dependencies: @@ -12522,9 +13089,9 @@ snapshots: eslint-visitor-keys@5.0.1: {} - eslint@10.3.0(jiti@2.6.1): + eslint@10.3.0(jiti@2.7.0): dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.3.0(jiti@2.6.1)) + '@eslint-community/eslint-utils': 4.9.1(eslint@10.3.0(jiti@2.7.0)) '@eslint-community/regexpp': 4.12.2 '@eslint/config-array': 0.23.5 '@eslint/config-helpers': 0.5.5 @@ -12555,7 +13122,7 @@ snapshots: natural-compare: 1.4.0 optionator: 0.9.4 optionalDependencies: - jiti: 2.6.1 + jiti: 2.7.0 transitivePeerDependencies: - supports-color @@ -12579,7 +13146,7 @@ snapshots: estree-walker@3.0.3: dependencies: - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 esutils@2.0.3: {} @@ -12613,98 +13180,154 @@ snapshots: jest-message-util: 29.7.0 jest-util: 29.7.0 - expo-application@55.0.14(expo@55.0.19): + expo-application@55.0.14(expo@55.0.23): dependencies: - expo: 55.0.19(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.13)(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.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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.16(expo@55.0.19)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.17(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.19(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.13)(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.15(expo@55.0.19)(react-native@0.83.4(@babel/core@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-utils': 0.8.14(typescript@5.9.3) + expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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.16(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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) transitivePeerDependencies: - supports-color - typescript - expo-constants@55.0.15(expo@55.0.19)(react-native@0.83.4(@babel/core@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-asset@55.0.17(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)(typescript@5.9.3): dependencies: - '@expo/env': 2.1.1 - expo: 55.0.19(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.13)(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/image-utils': 0.8.14(typescript@5.9.3) + expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) + expo-constants: 55.0.16(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6)) + react: 19.2.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.6) + transitivePeerDependencies: + - supports-color + - typescript + optional: true + + expo-constants@55.0.16(expo@55.0.23)(react-native@0.83.4(@babel/core@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/env': 2.1.2 + expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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-crypto@55.0.14(expo@55.0.19): + expo-constants@55.0.16(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6)): dependencies: - expo: 55.0.19(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.13)(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/env': 2.1.2 + expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(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.6) + transitivePeerDependencies: + - supports-color + optional: true - expo-dev-client@55.0.30(expo@55.0.19): + expo-crypto@55.0.14(expo@55.0.23): dependencies: - expo: 55.0.19(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.13)(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.31(expo@55.0.19) - expo-dev-menu: 55.0.26(expo@55.0.19) - expo-dev-menu-interface: 55.0.2(expo@55.0.19) - expo-manifests: 55.0.16(expo@55.0.19) - expo-updates-interface: 55.1.6(expo@55.0.19) + expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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.31(expo@55.0.19): + expo-dev-client@55.0.32(expo@55.0.23): dependencies: - '@expo/schema-utils': 55.0.3 - expo: 55.0.19(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.13)(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.26(expo@55.0.19) - expo-manifests: 55.0.16(expo@55.0.19) + expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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.33(expo@55.0.23) + expo-dev-menu: 55.0.27(expo@55.0.23) + expo-dev-menu-interface: 55.0.2(expo@55.0.23) + expo-manifests: 55.0.16(expo@55.0.23) + expo-updates-interface: 55.1.6(expo@55.0.23) - expo-dev-menu-interface@55.0.2(expo@55.0.19): + expo-dev-launcher@55.0.33(expo@55.0.23): dependencies: - expo: 55.0.19(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.13)(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/schema-utils': 55.0.4 + expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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.27(expo@55.0.23) + expo-manifests: 55.0.16(expo@55.0.23) - expo-dev-menu@55.0.26(expo@55.0.19): + expo-dev-menu-interface@55.0.2(expo@55.0.23): dependencies: - expo: 55.0.19(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.13)(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.19) + expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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-device@55.0.15(expo@55.0.19): + expo-dev-menu@55.0.27(expo@55.0.23): dependencies: - expo: 55.0.19(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.13)(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.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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.23) + + expo-device@55.0.16(expo@55.0.23): + dependencies: + expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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.17(expo@55.0.19)(react-native@0.83.4(@babel/core@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-file-system@55.0.19(expo@55.0.23)(react-native@0.83.4(@babel/core@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.19(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.13)(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.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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.19)(react-native@0.83.4(@babel/core@7.29.0)(@react-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-file-system@55.0.19(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6)): dependencies: - expo: 55.0.19(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.13)(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.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(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.6) + optional: true + + expo-font@55.0.7(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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.19)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.7(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6): dependencies: - expo: 55.0.19(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.13)(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.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) + fontfaceobserver: 2.3.0 + react: 19.2.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.6) + optional: true + + expo-glass-effect@55.0.11(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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.9(expo@55.0.19)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.11(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6): dependencies: - expo: 55.0.19(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.13)(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.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) + react: 19.2.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.6) + optional: true + + expo-image@55.0.10(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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-image@55.0.10(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6): + dependencies: + expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) + react: 19.2.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.6) + sf-symbols-typescript: 2.2.0 + optional: true + expo-json-utils@55.0.2: {} - expo-keep-awake@55.0.7(expo@55.0.19)(react@19.2.5): + expo-keep-awake@55.0.8(expo@55.0.23)(react@19.2.5): dependencies: - expo: 55.0.19(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.13)(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.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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.14(expo@55.0.19)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.8(expo@55.0.23)(react@19.2.6): dependencies: - expo-constants: 55.0.15(expo@55.0.19)(react-native@0.83.4(@babel/core@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.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) + react: 19.2.6 + optional: true + + expo-linking@55.0.15(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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-constants: 55.0.16(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(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) @@ -12712,28 +13335,39 @@ snapshots: - expo - supports-color - expo-localization@55.0.13(expo@55.0.19)(react@19.2.5): + expo-linking@55.0.15(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6): dependencies: - expo: 55.0.19(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.13)(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.16(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6)) + invariant: 2.2.4 + react: 19.2.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.6) + transitivePeerDependencies: + - expo + - supports-color + optional: true + + expo-localization@55.0.13(expo@55.0.23)(react@19.2.5): + dependencies: + expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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.19)(typescript@5.9.3): + expo-location@55.1.9(expo@55.0.23)(typescript@5.9.3): dependencies: - '@expo/image-utils': 0.8.13(typescript@5.9.3) - expo: 55.0.19(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.13)(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/image-utils': 0.8.14(typescript@5.9.3) + expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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.16(expo@55.0.19): + expo-manifests@55.0.16(expo@55.0.23): dependencies: - expo: 55.0.19(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.13)(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.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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 - expo-modules-autolinking@55.0.19(typescript@5.9.3): + expo-modules-autolinking@55.0.21(typescript@5.9.3): dependencies: - '@expo/require-utils': 55.0.4(typescript@5.9.3) + '@expo/require-utils': 55.0.5(typescript@5.9.3) '@expo/spawn-async': 1.7.2 chalk: 4.1.2 commander: 7.2.0 @@ -12741,7 +13375,7 @@ snapshots: - supports-color - typescript - expo-modules-core@55.0.24(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): + expo-modules-core@55.0.25(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 @@ -12749,50 +13383,108 @@ 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-navigation-bar@55.0.12(expo@55.0.19)(react-native@0.83.4(@babel/core@7.29.0)(@react-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-modules-core@55.0.25(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.6))(react@19.2.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.6))(react@19.2.6): + dependencies: + invariant: 2.2.4 + react: 19.2.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.6) + 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.6))(react@19.2.6) + optional: true + + expo-navigation-bar@55.0.12(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.19(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.13)(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.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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.22(expo@55.0.19)(react-native@0.83.4(@babel/core@7.29.0)(@react-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-notifications@55.0.22(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.19(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.13)(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.19) - expo-constants: 55.0.15(expo@55.0.19)(react-native@0.83.4(@babel/core@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.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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.23) + expo-constants: 55.0.16(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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) transitivePeerDependencies: - supports-color - typescript - expo-router@55.0.13(b9c3b63b8b06344e8f195cf40e503a18): + expo-router@55.0.14(8759932d8bf60b7936be47619a69edd6): dependencies: - '@expo/log-box': 55.0.11(@expo/dom-webview@55.0.5)(expo@55.0.19)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.10(@expo/dom-webview@55.0.5)(expo@55.0.19)(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.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.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.7.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-screens@4.24.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.12(@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.7.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-screens@4.24.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) + '@expo/log-box': 55.0.12(@expo/dom-webview@55.0.5)(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) + '@expo/metro-runtime': 55.0.11(@expo/dom-webview@55.0.5)(expo@55.0.23)(react-dom@19.2.6(react@19.2.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.6))(react@19.2.6) + '@expo/schema-utils': 55.0.4 + '@radix-ui/react-slot': 1.2.4(@types/react@19.2.14)(react@19.2.6) + '@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.6(react@19.2.6))(react@19.2.6) + '@react-navigation/bottom-tabs': 7.15.13(@react-navigation/native@7.2.4(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-safe-area-context@5.7.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.6))(react@19.2.6))(react-native-screens@4.24.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.6))(react@19.2.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.6))(react@19.2.6) + '@react-navigation/native': 7.2.4(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) + '@react-navigation/native-stack': 7.14.14(@react-navigation/native@7.2.4(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-safe-area-context@5.7.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.6))(react@19.2.6))(react-native-screens@4.24.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.6))(react@19.2.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.6))(react@19.2.6) client-only: 0.0.1 debug: 4.4.3 escape-string-regexp: 4.0.0 - expo: 55.0.19(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.13)(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.15(expo@55.0.19)(react-native@0.83.4(@babel/core@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.19)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.9(expo@55.0.19)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.14(expo@55.0.19)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.8 - expo-symbols: 55.0.7(expo-font@55.0.6)(expo@55.0.19)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) + expo-constants: 55.0.16(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6)) + expo-glass-effect: 55.0.11(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) + expo-image: 55.0.10(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) + expo-linking: 55.0.15(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) + expo-server: 55.0.9 + expo-symbols: 55.0.8(expo-font@55.0.7)(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) + fast-deep-equal: 3.1.3 + invariant: 2.2.4 + nanoid: 3.3.12 + query-string: 7.1.3 + react: 19.2.6 + react-fast-compare: 3.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.6) + 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.6))(react@19.2.6) + react-native-safe-area-context: 5.7.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.6))(react@19.2.6) + react-native-screens: 4.24.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.6))(react@19.2.6) + semver: 7.6.3 + server-only: 0.0.1 + sf-symbols-typescript: 2.2.0 + shallowequal: 1.1.0 + use-latest-callback: 0.2.6(react@19.2.6) + vaul: 1.1.2(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + optionalDependencies: + '@testing-library/react-native': 13.3.3(jest@29.7.0(@types/node@22.19.18))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react-test-renderer@19.2.6(react@19.2.6))(react@19.2.6) + react-dom: 19.2.6(react@19.2.6) + react-native-gesture-handler: 2.31.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.6))(react@19.2.6) + react-native-reanimated: 4.3.1(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.6))(react@19.2.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.6))(react@19.2.6) + transitivePeerDependencies: + - '@react-native-masked-view/masked-view' + - '@types/react' + - '@types/react-dom' + - expo-font + - supports-color + optional: true + + expo-router@55.0.14(ab64f1877338f7f43eb15d5c78597024): + dependencies: + '@expo/log-box': 55.0.12(@expo/dom-webview@55.0.5)(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.11(@expo/dom-webview@55.0.5)(expo@55.0.23)(react-dom@19.2.6(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.4 + '@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.6(react@19.2.5))(react@19.2.5) + '@react-navigation/bottom-tabs': 7.15.13(@react-navigation/native@7.2.4(react-native@0.83.4(@babel/core@7.29.0)(@react-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.7.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-screens@4.24.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.4(react-native@0.83.4(@babel/core@7.29.0)(@react-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.14(@react-navigation/native@7.2.4(react-native@0.83.4(@babel/core@7.29.0)(@react-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.7.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-screens@4.24.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.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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.16(expo@55.0.23)(react-native@0.83.4(@babel/core@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.11(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.10(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.15(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.9 + expo-symbols: 55.0.8(expo-font@55.0.7)(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.12 @@ -12808,12 +13500,12 @@ snapshots: sf-symbols-typescript: 2.2.0 shallowequal: 1.1.0 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) + vaul: 1.1.2(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.5))(react@19.2.5) optionalDependencies: - '@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) + '@testing-library/react-native': 13.3.3(jest@29.7.0(@types/node@25.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-test-renderer@19.2.6(react@19.2.5))(react@19.2.5) + react-dom: 19.2.6(react@19.2.5) + react-native-gesture-handler: 2.31.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-reanimated: 4.3.1(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' @@ -12821,90 +13513,108 @@ snapshots: - expo-font - supports-color - expo-secure-store@55.0.13(expo@55.0.19): + expo-secure-store@55.0.13(expo@55.0.23): dependencies: - expo: 55.0.19(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.13)(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.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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.8: {} + expo-server@55.0.9: {} - expo-splash-screen@55.0.19(expo@55.0.19)(typescript@5.9.3): + expo-splash-screen@55.0.20(expo@55.0.23)(typescript@5.9.3): dependencies: - '@expo/prebuild-config': 55.0.16(expo@55.0.19)(typescript@5.9.3) - expo: 55.0.19(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.13)(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/prebuild-config': 55.0.17(expo@55.0.23)(typescript@5.9.3) + expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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.19)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.19(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.13)(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.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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-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): + expo-sqlite@55.0.15(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6): + dependencies: + await-lock: 2.2.2 + expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) + react: 19.2.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.6) + optional: true + + expo-status-bar@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: 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.19)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.8(expo-font@55.0.7)(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.33 - expo: 55.0.19(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.13)(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.19)(react-native@0.83.4(@babel/core@7.29.0)(@react-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-google-fonts/material-symbols': 0.4.36 + expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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.7(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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-system-ui@55.0.16(expo@55.0.19)(react-native@0.83.4(@babel/core@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-symbols@55.0.8(expo-font@55.0.7)(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6): + dependencies: + '@expo-google-fonts/material-symbols': 0.4.36 + expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) + expo-font: 55.0.7(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) + react: 19.2.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.6) + sf-symbols-typescript: 2.2.0 + optional: true + + expo-system-ui@55.0.17(expo@55.0.23)(react-native@0.83.4(@babel/core@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: '@react-native/normalize-colors': 0.83.6 debug: 4.4.3 - expo: 55.0.19(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.13)(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.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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-updates-interface@55.1.6(expo@55.0.19): + expo-updates-interface@55.1.6(expo@55.0.23): dependencies: - expo: 55.0.19(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.13)(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.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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.19)(react-native@0.83.4(@babel/core@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@55.0.15(expo@55.0.23)(react-native@0.83.4(@babel/core@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.19(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.13)(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.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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.19(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.13)(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.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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.27(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-constants@55.0.15)(expo-font@55.0.6)(expo-router@55.0.13)(expo@55.0.19)(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/cli': 55.0.29(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-constants@55.0.16)(expo-font@55.0.7)(expo-router@55.0.14)(expo@55.0.23)(react-dom@19.2.6(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.16(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.11(typescript@5.9.3) - '@expo/log-box': 55.0.11(@expo/dom-webview@55.0.5)(expo@55.0.19)(react-native@0.83.4(@babel/core@7.29.0)(@react-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/devtools': 55.0.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) + '@expo/fingerprint': 0.16.7 + '@expo/local-build-cache-provider': 55.0.12(typescript@5.9.3) + '@expo/log-box': 55.0.12(@expo/dom-webview@55.0.5)(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.1.1 - '@expo/metro-config': 55.0.18(expo@55.0.19)(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.19(@babel/core@7.29.0)(@babel/runtime@7.29.2)(expo@55.0.19)(react-refresh@0.14.2) - expo-asset: 55.0.16(expo@55.0.19)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.15(expo@55.0.19)(react-native@0.83.4(@babel/core@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-file-system: 55.0.17(expo@55.0.19)(react-native@0.83.4(@babel/core@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.19)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.7(expo@55.0.19)(react@19.2.5) - expo-modules-autolinking: 55.0.19(typescript@5.9.3) - expo-modules-core: 55.0.24(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) + '@expo/metro-config': 55.0.20(expo@55.0.23)(typescript@5.9.3) + '@expo/vector-icons': 15.1.1(expo-font@55.0.7)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.1 + babel-preset-expo: 55.0.21(@babel/core@7.29.0)(@babel/runtime@7.29.2)(expo@55.0.23)(react-refresh@0.14.2) + expo-asset: 55.0.17(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.16(expo@55.0.23)(react-native@0.83.4(@babel/core@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-file-system: 55.0.19(expo@55.0.23)(react-native@0.83.4(@babel/core@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.7(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.8(expo@55.0.23)(react@19.2.5) + expo-modules-autolinking: 55.0.21(typescript@5.9.3) + expo-modules-core: 55.0.25(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)(@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 + whatwg-url-minimum: 0.1.2 optionalDependencies: - '@expo/dom-webview': 55.0.5(expo@55.0.19)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.10(@expo/dom-webview@55.0.5)(expo@55.0.19)(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.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.11(@expo/dom-webview@55.0.5)(expo@55.0.23)(react-dom@19.2.6(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 @@ -12917,6 +13627,49 @@ snapshots: - typescript - utf-8-validate + expo@55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3): + dependencies: + '@babel/runtime': 7.29.2 + '@expo/cli': 55.0.29(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-constants@55.0.16)(expo-font@55.0.7)(expo-router@55.0.14)(expo@55.0.23)(react-dom@19.2.6(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) + '@expo/config': 55.0.16(typescript@5.9.3) + '@expo/config-plugins': 55.0.8 + '@expo/devtools': 55.0.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.6))(react@19.2.6) + '@expo/fingerprint': 0.16.7 + '@expo/local-build-cache-provider': 55.0.12(typescript@5.9.3) + '@expo/log-box': 55.0.12(@expo/dom-webview@55.0.5)(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) + '@expo/metro': 55.1.1 + '@expo/metro-config': 55.0.20(expo@55.0.23)(typescript@5.9.3) + '@expo/vector-icons': 15.1.1(expo-font@55.0.7)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) + '@ungap/structured-clone': 1.3.1 + babel-preset-expo: 55.0.21(@babel/core@7.29.0)(@babel/runtime@7.29.2)(expo@55.0.23)(react-refresh@0.14.2) + expo-asset: 55.0.17(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)(typescript@5.9.3) + expo-constants: 55.0.16(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6)) + expo-file-system: 55.0.19(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6)) + expo-font: 55.0.7(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) + expo-keep-awake: 55.0.8(expo@55.0.23)(react@19.2.6) + expo-modules-autolinking: 55.0.21(typescript@5.9.3) + expo-modules-core: 55.0.25(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.6))(react@19.2.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.6))(react@19.2.6) + pretty-format: 29.7.0 + react: 19.2.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.6) + react-refresh: 0.14.2 + whatwg-url-minimum: 0.1.2 + optionalDependencies: + '@expo/dom-webview': 55.0.5(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) + '@expo/metro-runtime': 55.0.11(@expo/dom-webview@55.0.5)(expo@55.0.23)(react-dom@19.2.6(react@19.2.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.6))(react@19.2.6) + transitivePeerDependencies: + - '@babel/core' + - bufferutil + - expo-router + - expo-widgets + - react-dom + - react-native-worklets + - react-server-dom-webpack + - supports-color + - typescript + - utf-8-validate + optional: true + exponential-backoff@3.1.3: {} express@4.22.1: @@ -13224,7 +13977,7 @@ snapshots: http-proxy-agent@5.0.0: dependencies: - '@tootallnate/once': 2.0.0 + '@tootallnate/once': 2.0.1 agent-base: 6.0.2 debug: 4.4.3 transitivePeerDependencies: @@ -13250,6 +14003,10 @@ snapshots: dependencies: '@babel/runtime': 7.29.2 + i18next@26.0.10(typescript@5.9.3): + optionalDependencies: + typescript: 5.9.3 + i18next@26.0.8(typescript@5.9.3): optionalDependencies: typescript: 5.9.3 @@ -13316,7 +14073,7 @@ snapshots: is-arrayish@0.3.4: {} - is-core-module@2.16.1: + is-core-module@2.16.2: dependencies: hasown: 2.0.3 @@ -13348,7 +14105,7 @@ snapshots: dependencies: is-docker: 2.2.1 - isbot@5.1.39: {} + isbot@5.1.40: {} isexe@2.0.0: {} @@ -13372,7 +14129,7 @@ snapshots: '@babel/parser': 7.29.3 '@istanbuljs/schema': 0.1.6 istanbul-lib-coverage: 3.2.2 - semver: 7.7.4 + semver: 7.8.0 transitivePeerDependencies: - supports-color @@ -13407,7 +14164,7 @@ snapshots: '@jest/expect': 29.7.0 '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 25.6.0 + '@types/node': 25.6.2 chalk: 4.1.2 co: 4.6.0 dedent: 1.7.2 @@ -13427,16 +14184,36 @@ snapshots: - babel-plugin-macros - supports-color - jest-cli@29.7.0(@types/node@25.6.0): + jest-cli@29.7.0(@types/node@22.19.18): dependencies: '@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.6.0) + create-jest: 29.7.0(@types/node@22.19.18) exit: 0.1.2 import-local: 3.2.0 - jest-config: 29.7.0(@types/node@25.6.0) + jest-config: 29.7.0(@types/node@22.19.18) + jest-util: 29.7.0 + jest-validate: 29.7.0 + yargs: 17.7.2 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + optional: true + + jest-cli@29.7.0(@types/node@25.6.2): + dependencies: + '@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.6.2) + exit: 0.1.2 + import-local: 3.2.0 + jest-config: 29.7.0(@types/node@25.6.2) jest-util: 29.7.0 jest-validate: 29.7.0 yargs: 17.7.2 @@ -13446,7 +14223,7 @@ snapshots: - supports-color - ts-node - jest-config@29.7.0(@types/node@25.6.0): + jest-config@29.7.0(@types/node@22.19.18): dependencies: '@babel/core': 7.29.0 '@jest/test-sequencer': 29.7.0 @@ -13471,7 +14248,38 @@ snapshots: slash: 3.0.0 strip-json-comments: 3.1.1 optionalDependencies: - '@types/node': 25.6.0 + '@types/node': 22.19.18 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + optional: true + + jest-config@29.7.0(@types/node@25.6.2): + dependencies: + '@babel/core': 7.29.0 + '@jest/test-sequencer': 29.7.0 + '@jest/types': 29.6.3 + babel-jest: 29.7.0(@babel/core@7.29.0) + chalk: 4.1.2 + ci-info: 3.9.0 + deepmerge: 4.3.1 + glob: 7.2.3 + graceful-fs: 4.2.11 + jest-circus: 29.7.0 + jest-environment-node: 29.7.0 + jest-get-type: 29.6.3 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-runner: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + micromatch: 4.0.8 + parse-json: 5.2.0 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-json-comments: 3.1.1 + optionalDependencies: + '@types/node': 25.6.2 transitivePeerDependencies: - babel-plugin-macros - supports-color @@ -13508,7 +14316,7 @@ snapshots: '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 '@types/jsdom': 20.0.1 - '@types/node': 25.6.0 + '@types/node': 25.6.2 jest-mock: 29.7.0 jest-util: 29.7.0 jsdom: 20.0.3 @@ -13522,22 +14330,22 @@ snapshots: '@jest/environment': 29.7.0 '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 25.6.0 + '@types/node': 25.6.2 jest-mock: 29.7.0 jest-util: 29.7.0 - jest-expo@55.0.16(@babel/core@7.29.0)(expo@55.0.19)(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): + jest-expo@55.0.17(@babel/core@7.29.0)(expo@55.0.23)(jest@29.7.0(@types/node@25.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)(typescript@5.9.3): dependencies: - '@expo/config': 55.0.15(typescript@5.9.3) - '@expo/json-file': 10.0.13 + '@expo/config': 55.0.16(typescript@5.9.3) + '@expo/json-file': 10.0.14 '@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.19(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.13)(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.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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.6.0)) + jest-watch-typeahead: 2.2.1(jest@29.7.0(@types/node@25.6.2)) 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) @@ -13560,7 +14368,7 @@ snapshots: dependencies: '@jest/types': 29.6.3 '@types/graceful-fs': 4.1.9 - '@types/node': 25.6.0 + '@types/node': 25.6.2 anymatch: 3.1.3 fb-watchman: 2.0.2 graceful-fs: 4.2.11 @@ -13606,7 +14414,7 @@ snapshots: jest-mock@29.7.0: dependencies: '@jest/types': 29.6.3 - '@types/node': 25.6.0 + '@types/node': 25.6.2 jest-util: 29.7.0 jest-pnp-resolver@1.2.3(jest-resolve@29.7.0): @@ -13641,7 +14449,7 @@ snapshots: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 25.6.0 + '@types/node': 25.6.2 chalk: 4.1.2 emittery: 0.13.1 graceful-fs: 4.2.11 @@ -13669,7 +14477,7 @@ snapshots: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 25.6.0 + '@types/node': 25.6.2 chalk: 4.1.2 cjs-module-lexer: 1.4.3 collect-v8-coverage: 1.0.3 @@ -13708,14 +14516,14 @@ snapshots: jest-util: 29.7.0 natural-compare: 1.4.0 pretty-format: 29.7.0 - semver: 7.7.4 + semver: 7.8.0 transitivePeerDependencies: - supports-color jest-util@29.7.0: dependencies: '@jest/types': 29.6.3 - '@types/node': 25.6.0 + '@types/node': 25.6.2 chalk: 4.1.2 ci-info: 3.9.0 graceful-fs: 4.2.11 @@ -13736,11 +14544,11 @@ snapshots: chalk: 3.0.0 prompts: 2.4.2 - jest-watch-typeahead@2.2.1(jest@29.7.0(@types/node@25.6.0)): + jest-watch-typeahead@2.2.1(jest@29.7.0(@types/node@25.6.2)): dependencies: ansi-escapes: 6.2.1 chalk: 4.1.2 - jest: 29.7.0(@types/node@25.6.0) + jest: 29.7.0(@types/node@25.6.2) jest-regex-util: 29.6.3 jest-watcher: 29.7.0 slash: 5.1.0 @@ -13751,7 +14559,7 @@ snapshots: dependencies: '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 25.6.0 + '@types/node': 25.6.2 ansi-escapes: 4.3.2 chalk: 4.1.2 emittery: 0.13.1 @@ -13760,17 +14568,30 @@ snapshots: jest-worker@29.7.0: dependencies: - '@types/node': 25.6.0 + '@types/node': 25.6.2 jest-util: 29.7.0 merge-stream: 2.0.0 supports-color: 8.1.1 - jest@29.7.0(@types/node@25.6.0): + jest@29.7.0(@types/node@22.19.18): dependencies: '@jest/core': 29.7.0 '@jest/types': 29.6.3 import-local: 3.2.0 - jest-cli: 29.7.0(@types/node@25.6.0) + jest-cli: 29.7.0(@types/node@22.19.18) + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + optional: true + + jest@29.7.0(@types/node@25.6.2): + dependencies: + '@jest/core': 29.7.0 + '@jest/types': 29.6.3 + import-local: 3.2.0 + jest-cli: 29.7.0(@types/node@25.6.2) transitivePeerDependencies: - '@types/node' - babel-plugin-macros @@ -13779,7 +14600,7 @@ snapshots: jimp-compact@0.16.1: {} - jiti@2.6.1: {} + jiti@2.7.0: {} jose@6.2.3: {} @@ -13995,6 +14816,8 @@ snapshots: lru-cache@11.3.5: {} + lru-cache@11.3.6: {} + lru-cache@5.1.1: dependencies: yallist: 3.1.1 @@ -14009,7 +14832,7 @@ snapshots: make-dir@4.0.0: dependencies: - semver: 7.7.4 + semver: 7.8.0 makeerror@1.0.12: dependencies: @@ -14152,12 +14975,12 @@ snapshots: metro-minify-terser@0.83.7: dependencies: flow-enums-runtime: 0.0.6 - terser: 5.46.2 + terser: 5.47.1 metro-minify-terser@0.84.4: dependencies: flow-enums-runtime: 0.0.6 - terser: 5.46.2 + terser: 5.47.1 metro-resolver@0.83.7: dependencies: @@ -14410,7 +15233,7 @@ snapshots: minimatch@10.2.5: dependencies: - brace-expansion: 5.0.5 + brace-expansion: 5.0.6 minimatch@3.1.5: dependencies: @@ -14472,7 +15295,7 @@ snapshots: dependencies: hosted-git-info: 7.0.2 proc-log: 4.2.0 - semver: 7.7.4 + semver: 7.8.0 validate-npm-package-name: 5.0.1 npm-run-path@4.0.1: @@ -14619,7 +15442,7 @@ snapshots: path-scurry@2.0.2: dependencies: - lru-cache: 11.3.5 + lru-cache: 11.3.6 minipass: 7.1.3 path-to-regexp@0.1.13: {} @@ -14719,7 +15542,7 @@ snapshots: dependencies: find-up: 4.1.0 - pkg-types@2.3.0: + pkg-types@2.3.1: dependencies: confbox: 0.2.4 exsolve: 1.0.8 @@ -14762,6 +15585,12 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 + postcss@8.5.14: + dependencies: + nanoid: 3.3.12 + picocolors: 1.1.1 + source-map-js: 1.2.1 + postgres-array@2.0.0: {} postgres-bytea@1.0.1: {} @@ -14896,18 +15725,29 @@ snapshots: - bufferutil - utf-8-validate - react-dom@19.2.5(react@19.2.5): + react-dom@19.2.6(react@19.2.5): dependencies: react: 19.2.5 scheduler: 0.27.0 + react-dom@19.2.6(react@19.2.6): + dependencies: + react: 19.2.6 + scheduler: 0.27.0 + optional: true + react-fast-compare@3.2.2: {} react-freeze@1.0.4(react@19.2.5): dependencies: react: 19.2.5 - react-i18next@17.0.6(i18next@26.0.8(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-freeze@1.0.4(react@19.2.6): + dependencies: + react: 19.2.6 + optional: true + + react-i18next@17.0.6(i18next@26.0.8(typescript@5.9.3))(react-dom@19.2.6(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 @@ -14915,7 +15755,19 @@ snapshots: react: 19.2.5 use-sync-external-store: 1.6.0(react@19.2.5) optionalDependencies: - react-dom: 19.2.5(react@19.2.5) + react-dom: 19.2.6(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-i18next@17.0.7(i18next@26.0.10(typescript@5.9.3))(react-dom@19.2.6(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 + i18next: 26.0.10(typescript@5.9.3) + react: 19.2.5 + use-sync-external-store: 1.6.0(react@19.2.5) + optionalDependencies: + react-dom: 19.2.6(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 @@ -14925,16 +15777,16 @@ snapshots: react-is@18.3.1: {} - react-is@19.2.5: {} + react-is@19.2.6: {} - react-leaflet@5.0.0(leaflet@1.9.4)(react-dom@19.2.5(react@19.2.5))(react@19.2.5): + react-leaflet@5.0.0(leaflet@1.9.4)(react-dom@19.2.6(react@19.2.5))(react@19.2.5): dependencies: - '@react-leaflet/core': 3.0.0(leaflet@1.9.4)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@react-leaflet/core': 3.0.0(leaflet@1.9.4)(react-dom@19.2.6(react@19.2.5))(react@19.2.5) leaflet: 1.9.4 react: 19.2.5 - react-dom: 19.2.5(react@19.2.5) + react-dom: 19.2.6(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-gesture-handler@2.31.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: '@egjs/hammerjs': 2.0.17 '@types/react-test-renderer': 19.1.0 @@ -14943,24 +15795,55 @@ 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) + react-native-gesture-handler@2.31.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.6))(react@19.2.6): + 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.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.6) + optional: true + 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)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(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-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.6))(react@19.2.6): + dependencies: + react: 19.2.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.6) + optional: true + + react-native-reanimated@4.3.1(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)(@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 + semver: 7.8.0 + + react-native-reanimated@4.3.1(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.6))(react@19.2.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.6))(react@19.2.6): + dependencies: + react: 19.2.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.6) + 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.6))(react@19.2.6) + 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.6))(react@19.2.6) + semver: 7.8.0 + optional: true react-native-safe-area-context@5.7.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-native: 0.83.4(@babel/core@7.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.7.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.6))(react@19.2.6): + dependencies: + react: 19.2.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.6) + optional: true + react-native-screens@4.24.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 @@ -14968,6 +15851,14 @@ 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) warn-once: 0.1.1 + react-native-screens@4.24.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.6))(react@19.2.6): + dependencies: + react: 19.2.6 + react-freeze: 1.0.4(react@19.2.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.6) + warn-once: 0.1.1 + optional: true + 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 @@ -14984,10 +15875,31 @@ snapshots: 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 + semver: 7.8.0 transitivePeerDependencies: - supports-color + 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.6))(react@19.2.6): + 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.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.6) + semver: 7.8.0 + transitivePeerDependencies: + - supports-color + optional: true + react-native@0.83.4(@babel/core@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 @@ -15036,6 +15948,55 @@ snapshots: - supports-color - utf-8-validate + react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6): + 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/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)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) + abort-controller: 3.0.0 + anser: 1.4.10 + ansi-regex: 5.0.1 + babel-jest: 29.7.0(@babel/core@7.29.0) + babel-plugin-syntax-hermes-parser: 0.32.0 + base64-js: 1.5.1 + commander: 12.1.0 + flow-enums-runtime: 0.0.6 + glob: 7.2.3 + hermes-compiler: 0.14.1 + invariant: 2.2.4 + jest-environment-node: 29.7.0 + memoize-one: 5.2.1 + metro-runtime: 0.83.7 + metro-source-map: 0.83.7 + nullthrows: 1.1.1 + pretty-format: 29.7.0 + promise: 8.3.0 + react: 19.2.6 + react-devtools-core: 6.1.5 + react-refresh: 0.14.2 + regenerator-runtime: 0.13.11 + scheduler: 0.27.0 + semver: 7.7.4 + stacktrace-parser: 0.1.11 + whatwg-fetch: 3.6.20 + ws: 7.5.10 + yargs: 17.7.2 + optionalDependencies: + '@types/react': 19.2.14 + transitivePeerDependencies: + - '@babel/core' + - '@react-native-community/cli' + - '@react-native/metro-config' + - bufferutil + - supports-color + - utf-8-validate + optional: true + react-refresh@0.14.2: {} react-remove-scroll-bar@2.3.8(@types/react@19.2.14)(react@19.2.5): @@ -15046,6 +16007,15 @@ snapshots: optionalDependencies: '@types/react': 19.2.14 + react-remove-scroll-bar@2.3.8(@types/react@19.2.14)(react@19.2.6): + dependencies: + react: 19.2.6 + react-style-singleton: 2.2.3(@types/react@19.2.14)(react@19.2.6) + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.2.14 + optional: true + react-remove-scroll@2.7.2(@types/react@19.2.14)(react@19.2.5): dependencies: react: 19.2.5 @@ -15057,13 +16027,25 @@ snapshots: optionalDependencies: '@types/react': 19.2.14 - react-router@7.14.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5): + react-remove-scroll@2.7.2(@types/react@19.2.14)(react@19.2.6): + dependencies: + react: 19.2.6 + react-remove-scroll-bar: 2.3.8(@types/react@19.2.14)(react@19.2.6) + react-style-singleton: 2.2.3(@types/react@19.2.14)(react@19.2.6) + tslib: 2.8.1 + use-callback-ref: 1.3.3(@types/react@19.2.14)(react@19.2.6) + use-sidecar: 1.1.3(@types/react@19.2.14)(react@19.2.6) + optionalDependencies: + '@types/react': 19.2.14 + optional: true + + react-router@7.15.0(react-dom@19.2.6(react@19.2.5))(react@19.2.5): dependencies: cookie: 1.1.1 react: 19.2.5 set-cookie-parser: 2.7.2 optionalDependencies: - react-dom: 19.2.5(react@19.2.5) + react-dom: 19.2.6(react@19.2.5) react-style-singleton@2.2.3(@types/react@19.2.14)(react@19.2.5): dependencies: @@ -15073,20 +16055,39 @@ snapshots: optionalDependencies: '@types/react': 19.2.14 + react-style-singleton@2.2.3(@types/react@19.2.14)(react@19.2.6): + dependencies: + get-nonce: 1.0.1 + react: 19.2.6 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.2.14 + optional: true + react-test-renderer@19.2.0(react@19.2.5): dependencies: react: 19.2.5 - react-is: 19.2.5 + react-is: 19.2.6 scheduler: 0.27.0 - react-test-renderer@19.2.5(react@19.2.5): + react-test-renderer@19.2.6(react@19.2.5): dependencies: react: 19.2.5 - react-is: 19.2.5 + react-is: 19.2.6 scheduler: 0.27.0 + react-test-renderer@19.2.6(react@19.2.6): + dependencies: + react: 19.2.6 + react-is: 19.2.6 + scheduler: 0.27.0 + optional: true + react@19.2.5: {} + react@19.2.6: + optional: true + readdirp@4.1.2: {} real-require@0.2.0: {} @@ -15149,7 +16150,7 @@ snapshots: resolve@1.22.12: dependencies: es-errors: 1.3.0 - is-core-module: 2.16.1 + is-core-module: 2.16.2 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 @@ -15192,35 +16193,35 @@ snapshots: '@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.17 '@rolldown/binding-win32-x64-msvc': 1.0.0-rc.17 - rollup@4.60.2: + rollup@4.60.3: dependencies: '@types/estree': 1.0.8 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.60.2 - '@rollup/rollup-android-arm64': 4.60.2 - '@rollup/rollup-darwin-arm64': 4.60.2 - '@rollup/rollup-darwin-x64': 4.60.2 - '@rollup/rollup-freebsd-arm64': 4.60.2 - '@rollup/rollup-freebsd-x64': 4.60.2 - '@rollup/rollup-linux-arm-gnueabihf': 4.60.2 - '@rollup/rollup-linux-arm-musleabihf': 4.60.2 - '@rollup/rollup-linux-arm64-gnu': 4.60.2 - '@rollup/rollup-linux-arm64-musl': 4.60.2 - '@rollup/rollup-linux-loong64-gnu': 4.60.2 - '@rollup/rollup-linux-loong64-musl': 4.60.2 - '@rollup/rollup-linux-ppc64-gnu': 4.60.2 - '@rollup/rollup-linux-ppc64-musl': 4.60.2 - '@rollup/rollup-linux-riscv64-gnu': 4.60.2 - '@rollup/rollup-linux-riscv64-musl': 4.60.2 - '@rollup/rollup-linux-s390x-gnu': 4.60.2 - '@rollup/rollup-linux-x64-gnu': 4.60.2 - '@rollup/rollup-linux-x64-musl': 4.60.2 - '@rollup/rollup-openbsd-x64': 4.60.2 - '@rollup/rollup-openharmony-arm64': 4.60.2 - '@rollup/rollup-win32-arm64-msvc': 4.60.2 - '@rollup/rollup-win32-ia32-msvc': 4.60.2 - '@rollup/rollup-win32-x64-gnu': 4.60.2 - '@rollup/rollup-win32-x64-msvc': 4.60.2 + '@rollup/rollup-android-arm-eabi': 4.60.3 + '@rollup/rollup-android-arm64': 4.60.3 + '@rollup/rollup-darwin-arm64': 4.60.3 + '@rollup/rollup-darwin-x64': 4.60.3 + '@rollup/rollup-freebsd-arm64': 4.60.3 + '@rollup/rollup-freebsd-x64': 4.60.3 + '@rollup/rollup-linux-arm-gnueabihf': 4.60.3 + '@rollup/rollup-linux-arm-musleabihf': 4.60.3 + '@rollup/rollup-linux-arm64-gnu': 4.60.3 + '@rollup/rollup-linux-arm64-musl': 4.60.3 + '@rollup/rollup-linux-loong64-gnu': 4.60.3 + '@rollup/rollup-linux-loong64-musl': 4.60.3 + '@rollup/rollup-linux-ppc64-gnu': 4.60.3 + '@rollup/rollup-linux-ppc64-musl': 4.60.3 + '@rollup/rollup-linux-riscv64-gnu': 4.60.3 + '@rollup/rollup-linux-riscv64-musl': 4.60.3 + '@rollup/rollup-linux-s390x-gnu': 4.60.3 + '@rollup/rollup-linux-x64-gnu': 4.60.3 + '@rollup/rollup-linux-x64-musl': 4.60.3 + '@rollup/rollup-openbsd-x64': 4.60.3 + '@rollup/rollup-openharmony-arm64': 4.60.3 + '@rollup/rollup-win32-arm64-msvc': 4.60.3 + '@rollup/rollup-win32-ia32-msvc': 4.60.3 + '@rollup/rollup-win32-x64-gnu': 4.60.3 + '@rollup/rollup-win32-x64-msvc': 4.60.3 fsevents: 2.3.3 rtl-detect@1.1.2: {} @@ -15255,6 +16256,8 @@ snapshots: semver@7.7.4: {} + semver@7.8.0: {} + send@0.19.2: dependencies: debug: 2.6.9 @@ -15505,7 +16508,7 @@ snapshots: tagged-tag@1.0.0: {} - tailwindcss@4.2.4: {} + tailwindcss@4.3.0: {} tapable@2.3.3: {} @@ -15518,7 +16521,7 @@ snapshots: ansi-escapes: 4.3.2 supports-hyperlinks: 2.3.0 - terser@5.46.2: + terser@5.47.1: dependencies: '@jridgewell/source-map': 0.3.11 acorn: 8.16.0 @@ -15608,14 +16611,14 @@ snapshots: dependencies: tslib: 1.14.1 - turbo@2.9.8: + turbo@2.9.12: optionalDependencies: - '@turbo/darwin-64': 2.9.8 - '@turbo/darwin-arm64': 2.9.8 - '@turbo/linux-64': 2.9.8 - '@turbo/linux-arm64': 2.9.8 - '@turbo/windows-64': 2.9.8 - '@turbo/windows-arm64': 2.9.8 + '@turbo/darwin-64': 2.9.12 + '@turbo/darwin-arm64': 2.9.12 + '@turbo/linux-64': 2.9.12 + '@turbo/linux-arm64': 2.9.12 + '@turbo/windows-64': 2.9.12 + '@turbo/windows-arm64': 2.9.12 type-check@0.4.0: dependencies: @@ -15636,13 +16639,13 @@ snapshots: media-typer: 0.3.0 mime-types: 2.1.35 - typescript-eslint@8.59.1(eslint@10.3.0(jiti@2.6.1))(typescript@5.9.3): + typescript-eslint@8.59.2(eslint@10.3.0(jiti@2.7.0))(typescript@5.9.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.59.1(@typescript-eslint/parser@8.59.1(eslint@10.3.0(jiti@2.6.1))(typescript@5.9.3))(eslint@10.3.0(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/parser': 8.59.1(eslint@10.3.0(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/typescript-estree': 8.59.1(typescript@5.9.3) - '@typescript-eslint/utils': 8.59.1(eslint@10.3.0(jiti@2.6.1))(typescript@5.9.3) - eslint: 10.3.0(jiti@2.6.1) + '@typescript-eslint/eslint-plugin': 8.59.2(@typescript-eslint/parser@8.59.2(eslint@10.3.0(jiti@2.7.0))(typescript@5.9.3))(eslint@10.3.0(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/parser': 8.59.2(eslint@10.3.0(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/typescript-estree': 8.59.2(typescript@5.9.3) + '@typescript-eslint/utils': 8.59.2(eslint@10.3.0(jiti@2.7.0))(typescript@5.9.3) + eslint: 10.3.0(jiti@2.7.0) typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -15698,10 +16701,23 @@ snapshots: optionalDependencies: '@types/react': 19.2.14 + use-callback-ref@1.3.3(@types/react@19.2.14)(react@19.2.6): + dependencies: + react: 19.2.6 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.2.14 + optional: true + use-latest-callback@0.2.6(react@19.2.5): dependencies: react: 19.2.5 + use-latest-callback@0.2.6(react@19.2.6): + dependencies: + react: 19.2.6 + optional: true + use-latest-callback@0.3.3(react@19.2.5): dependencies: react: 19.2.5 @@ -15714,10 +16730,24 @@ snapshots: optionalDependencies: '@types/react': 19.2.14 + use-sidecar@1.1.3(@types/react@19.2.14)(react@19.2.6): + dependencies: + detect-node-es: 1.1.0 + react: 19.2.6 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.2.14 + optional: true + use-sync-external-store@1.6.0(react@19.2.5): dependencies: react: 19.2.5 + use-sync-external-store@1.6.0(react@19.2.6): + dependencies: + react: 19.2.6 + optional: true + utils-merge@1.0.1: {} uuid@7.0.3: {} @@ -15728,7 +16758,7 @@ snapshots: '@types/istanbul-lib-coverage': 2.0.6 convert-source-map: 2.0.0 - valibot@1.3.1(typescript@5.9.3): + valibot@1.4.0(typescript@5.9.3): optionalDependencies: typescript: 5.9.3 @@ -15736,22 +16766,32 @@ snapshots: vary@1.1.2: {} - 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): + vaul@1.1.2(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.5))(react@19.2.5): dependencies: - '@radix-ui/react-dialog': 1.1.15(@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) + '@radix-ui/react-dialog': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.5))(react@19.2.5) react: 19.2.5 - react-dom: 19.2.5(react@19.2.5) + react-dom: 19.2.6(react@19.2.5) transitivePeerDependencies: - '@types/react' - '@types/react-dom' - vite-node@3.2.4(@types/node@25.6.0)(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.4): + vaul@1.1.2(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6): + dependencies: + '@radix-ui/react-dialog': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) + transitivePeerDependencies: + - '@types/react' + - '@types/react-dom' + optional: true + + vite-node@3.2.4(@types/node@25.6.2)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4): dependencies: cac: 6.7.14 debug: 4.4.3 es-module-lexer: 1.7.0 pathe: 2.0.3 - vite: 7.3.2(@types/node@25.6.0)(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.4) + vite: 7.3.3(@types/node@25.6.2)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4) transitivePeerDependencies: - '@types/node' - jiti @@ -15766,24 +16806,24 @@ snapshots: - tsx - yaml - vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.4): + vite@7.3.3(@types/node@25.6.2)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4): dependencies: esbuild: 0.27.7 fdir: 6.5.0(picomatch@4.0.4) picomatch: 4.0.4 - postcss: 8.5.13 - rollup: 4.60.2 + postcss: 8.5.14 + rollup: 4.60.3 tinyglobby: 0.2.16 optionalDependencies: - '@types/node': 25.6.0 + '@types/node': 25.6.2 fsevents: 2.3.3 - jiti: 2.6.1 + jiti: 2.7.0 lightningcss: 1.32.0 - terser: 5.46.2 + terser: 5.47.1 tsx: 4.21.0 yaml: 2.8.4 - vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.4): + vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4): dependencies: lightningcss: 1.32.0 picomatch: 4.0.4 @@ -15791,18 +16831,18 @@ snapshots: rolldown: 1.0.0-rc.17 tinyglobby: 0.2.16 optionalDependencies: - '@types/node': 25.6.0 + '@types/node': 25.6.2 esbuild: 0.27.7 fsevents: 2.3.3 - jiti: 2.6.1 - terser: 5.46.2 + jiti: 2.7.0 + terser: 5.47.1 tsx: 4.21.0 yaml: 2.8.4 - vitest@4.1.5(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(jsdom@29.1.1)(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.4)): + vitest@4.1.5(@opentelemetry/api@1.9.1)(@types/node@25.6.2)(jsdom@29.1.1)(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4)): dependencies: '@vitest/expect': 4.1.5 - '@vitest/mocker': 4.1.5(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.4)) + '@vitest/mocker': 4.1.5(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4)) '@vitest/pretty-format': 4.1.5 '@vitest/runner': 4.1.5 '@vitest/snapshot': 4.1.5 @@ -15819,11 +16859,11 @@ snapshots: tinyexec: 1.1.1 tinyglobby: 0.2.16 tinyrainbow: 3.1.0 - vite: 8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.4) + vite: 8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4) why-is-node-running: 2.3.0 optionalDependencies: '@opentelemetry/api': 1.9.1 - '@types/node': 25.6.0 + '@types/node': 25.6.2 jsdom: 29.1.1 transitivePeerDependencies: - msw @@ -15868,7 +16908,7 @@ snapshots: whatwg-mimetype@5.0.0: {} - whatwg-url-minimum@0.1.1: {} + whatwg-url-minimum@0.1.2: {} whatwg-url@11.0.0: dependencies: @@ -15899,7 +16939,7 @@ snapshots: wkx@0.5.0: dependencies: - '@types/node': 25.6.0 + '@types/node': 25.6.2 word-wrap@1.2.5: {} @@ -15948,10 +16988,10 @@ snapshots: xtend@4.0.2: {} - y-codemirror.next@0.3.5(@codemirror/state@6.6.0)(@codemirror/view@6.41.1)(yjs@13.6.30): + y-codemirror.next@0.3.5(@codemirror/state@6.6.0)(@codemirror/view@6.42.1)(yjs@13.6.30): dependencies: '@codemirror/state': 6.6.0 - '@codemirror/view': 6.41.1 + '@codemirror/view': 6.42.1 lib0: 0.2.117 yjs: 13.6.30 @@ -15994,4 +17034,4 @@ snapshots: zod@3.25.76: {} - zod@4.4.2: {} + zod@4.4.3: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 588ff97..85cd6ff 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -5,22 +5,22 @@ packages: catalog: react: ^19.2.5 - react-dom: ^19.2.5 - react-router: ^7.14.2 - "@react-router/dev": ^7.14.2 - "@react-router/node": ^7.14.2 - "@react-router/serve": ^7.14.2 + react-dom: ^19.2.6 + react-router: ^7.15.0 + "@react-router/dev": ^7.15.0 + "@react-router/node": ^7.15.0 + "@react-router/serve": ^7.15.0 "@types/react": ^19.2.14 "@types/react-dom": ^19.2.3 - tailwindcss: ^4.2.4 - "@tailwindcss/vite": ^4.2.4 + tailwindcss: ^4.3.0 + "@tailwindcss/vite": ^4.3.0 typescript: ^5.8.3 vite: ^8.0.10 drizzle-orm: ^0.45.2 drizzle-kit: ^0.31.10 drizzle-postgis: ^1.1.1 - "@sentry/node": ^10.51.0 - "@sentry/react": ^10.51.0 + "@sentry/node": ^10.52.0 + "@sentry/react": ^10.52.0 postgres: ^3.4.9 - "@types/node": ^22.0.0 + "@types/node": ^22.19.18 From 9c985d908c7359a58ca678bbe1937c44a3caf119 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 10 May 2026 08:43:29 +0000 Subject: [PATCH 007/319] [github-actions] pnpm dedupe --- pnpm-lock.yaml | 1355 +++++++----------------------------------------- 1 file changed, 173 insertions(+), 1182 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7bd5340..3319a24 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -72,13 +72,13 @@ importers: dependencies: expo: specifier: ~55.0.23 - version: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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) + version: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) react: specifier: ^19.2.5 - version: 19.2.5 + version: 19.2.6 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) + 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.6) devDependencies: '@eslint/js': specifier: ^10.0.1 @@ -94,13 +94,13 @@ importers: version: 1.59.1 '@react-router/dev': specifier: 'catalog:' - version: 7.15.0(@react-router/serve@7.15.0(react-router@7.15.0(react-dom@19.2.6(react@19.2.5))(react@19.2.5))(typescript@5.9.3))(@types/node@25.6.2)(jiti@2.7.0)(lightningcss@1.32.0)(react-router@7.15.0(react-dom@19.2.6(react@19.2.5))(react@19.2.5))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4))(yaml@2.8.4) + version: 7.15.0(@react-router/serve@7.15.0(react-router@7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3))(@types/node@25.6.2)(jiti@2.7.0)(lightningcss@1.32.0)(react-router@7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4))(yaml@2.8.4) '@react-router/node': specifier: 'catalog:' - version: 7.15.0(react-router@7.15.0(react-dom@19.2.6(react@19.2.5))(react@19.2.5))(typescript@5.9.3) + version: 7.15.0(react-router@7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3) '@react-router/serve': specifier: 'catalog:' - version: 7.15.0(react-router@7.15.0(react-dom@19.2.6(react@19.2.5))(react@19.2.5))(typescript@5.9.3) + version: 7.15.0(react-router@7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3) '@sentry/vite-plugin': specifier: ^5.2.1 version: 5.2.1(rollup@4.60.3) @@ -112,7 +112,7 @@ importers: version: 6.9.1 '@testing-library/react': specifier: ^16.3.2 - version: 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.6(react@19.2.5))(react@19.2.5) + version: 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.6(react@19.2.6))(react@19.2.6) '@types/geojson': specifier: ^7946.0.16 version: 7946.0.16 @@ -130,7 +130,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.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(pg@8.20.0)(postgres@3.4.9) drizzle-postgis: specifier: 'catalog:' version: 1.1.1 @@ -169,18 +169,18 @@ importers: version: 3.8.3 react-dom: specifier: ^19.2.6 - version: 19.2.6(react@19.2.5) + version: 19.2.6(react@19.2.6) react-i18next: specifier: ^17.0.7 - version: 17.0.7(i18next@26.0.10(typescript@5.9.3))(react-dom@19.2.6(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.7(i18next@26.0.10(typescript@5.9.3))(react-dom@19.2.6(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) react-leaflet: specifier: ^5.0.0 - version: 5.0.0(leaflet@1.9.4)(react-dom@19.2.6(react@19.2.5))(react@19.2.5) + version: 5.0.0(leaflet@1.9.4)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) react-router: specifier: 'catalog:' - version: 7.15.0(react-dom@19.2.6(react@19.2.5))(react@19.2.5) + version: 7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) tailwindcss: - specifier: 4.3.0 + specifier: 'catalog:' version: 4.3.0 turbo: specifier: ^2.9.12 @@ -202,16 +202,16 @@ importers: dependencies: '@react-router/node': specifier: 'catalog:' - version: 7.15.0(react-router@7.15.0(react-dom@19.2.6(react@19.2.5))(react@19.2.5))(typescript@5.9.3) + version: 7.15.0(react-router@7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3) '@react-router/serve': specifier: 'catalog:' - version: 7.15.0(react-router@7.15.0(react-dom@19.2.6(react@19.2.5))(react@19.2.5))(typescript@5.9.3) + version: 7.15.0(react-router@7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3) '@sentry/node': specifier: 'catalog:' version: 10.52.0 '@sentry/react': specifier: 'catalog:' - version: 10.52.0(react@19.2.5) + version: 10.52.0(react@19.2.6) '@simplewebauthn/browser': specifier: ^13.3.0 version: 13.3.0 @@ -250,7 +250,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.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(pg@8.20.0)(postgres@3.4.9) isbot: specifier: ^5.1.40 version: 5.1.40 @@ -268,20 +268,20 @@ importers: version: 15.1.3 react: specifier: ^19.2.5 - version: 19.2.5 + version: 19.2.6 react-dom: specifier: ^19.2.6 - version: 19.2.6(react@19.2.5) + version: 19.2.6(react@19.2.6) react-router: specifier: 'catalog:' - version: 7.15.0(react-dom@19.2.6(react@19.2.5))(react@19.2.5) + version: 7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) zod: specifier: ^4.4.3 version: 4.4.3 devDependencies: '@react-router/dev': specifier: 'catalog:' - version: 7.15.0(@react-router/serve@7.15.0(react-router@7.15.0(react-dom@19.2.6(react@19.2.5))(react@19.2.5))(typescript@5.9.3))(@types/node@25.6.2)(jiti@2.7.0)(lightningcss@1.32.0)(react-router@7.15.0(react-dom@19.2.6(react@19.2.5))(react@19.2.5))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4))(yaml@2.8.4) + version: 7.15.0(@react-router/serve@7.15.0(react-router@7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3))(@types/node@25.6.2)(jiti@2.7.0)(lightningcss@1.32.0)(react-router@7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4))(yaml@2.8.4) '@simplewebauthn/types': specifier: ^12.0.0 version: 12.0.0 @@ -317,19 +317,19 @@ importers: dependencies: '@expo/metro-runtime': specifier: ^55.0.11 - version: 55.0.11(@expo/dom-webview@55.0.5)(expo@55.0.23)(react-dom@19.2.6(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) + version: 55.0.11(@expo/dom-webview@55.0.5)(expo@55.0.23)(react-dom@19.2.6(react@19.2.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.6))(react@19.2.6) '@gorhom/bottom-sheet': specifier: ^5.2.14 - version: 5.2.14(@types/react@19.2.14)(react-native-gesture-handler@2.31.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-reanimated@4.3.1(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) + version: 5.2.14(@types/react@19.2.14)(react-native-gesture-handler@2.31.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.6))(react@19.2.6))(react-native-reanimated@4.3.1(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.6))(react@19.2.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.6))(react@19.2.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.6))(react@19.2.6) '@maplibre/maplibre-react-native': specifier: ^11.1.1 - version: 11.1.1(@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) + version: 11.1.1(@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.6))(react@19.2.6) '@sentry/cli': specifier: ^3.4.1 version: 3.4.1 '@sentry/react-native': specifier: ~8.11.0 - version: 8.11.0(@expo/env@2.1.2)(dotenv@16.6.1)(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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: 8.11.0(@expo/env@2.1.2)(dotenv@16.6.1)(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) '@trails-cool/api': specifier: workspace:* version: link:../../packages/api @@ -350,10 +350,10 @@ importers: version: link:../../packages/types expo: specifier: ~55.0.23 - version: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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) + version: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) expo-constants: specifier: ~55.0.16 - version: 55.0.16(expo@55.0.23)(react-native@0.83.4(@babel/core@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.16(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6)) expo-crypto: specifier: ~55.0.14 version: 55.0.14(expo@55.0.23) @@ -368,25 +368,25 @@ importers: version: 55.0.16(expo@55.0.23) expo-file-system: specifier: ~55.0.19 - version: 55.0.19(expo@55.0.23)(react-native@0.83.4(@babel/core@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.19(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6)) expo-linking: specifier: ~55.0.15 - version: 55.0.15(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) expo-localization: specifier: ~55.0.13 - version: 55.0.13(expo@55.0.23)(react@19.2.5) + version: 55.0.13(expo@55.0.23)(react@19.2.6) expo-location: specifier: ~55.1.9 version: 55.1.9(expo@55.0.23)(typescript@5.9.3) expo-navigation-bar: specifier: ~55.0.12 - version: 55.0.12(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.12(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) expo-notifications: specifier: ~55.0.22 - version: 55.0.22(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.22(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)(typescript@5.9.3) expo-router: specifier: ~55.0.14 - version: 55.0.14(ab64f1877338f7f43eb15d5c78597024) + version: 55.0.14(82db8260abd9fbac2a02011543a979fa) expo-secure-store: specifier: ~55.0.13 version: 55.0.13(expo@55.0.23) @@ -395,44 +395,44 @@ importers: version: 55.0.20(expo@55.0.23)(typescript@5.9.3) expo-sqlite: specifier: ~55.0.15 - version: 55.0.15(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) expo-status-bar: specifier: ~55.0.6 - version: 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) + version: 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.6))(react@19.2.6) expo-system-ui: specifier: ^55.0.17 - version: 55.0.17(expo@55.0.23)(react-native@0.83.4(@babel/core@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.17(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6)) expo-web-browser: specifier: ~55.0.15 - version: 55.0.15(expo@55.0.23)(react-native@0.83.4(@babel/core@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.15(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6)) react: specifier: ^19.2.5 - version: 19.2.5 + version: 19.2.6 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) + 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.6) react-native-gesture-handler: specifier: ^2.31.2 - version: 2.31.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) + version: 2.31.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.6))(react@19.2.6) react-native-reanimated: specifier: ^4.3.1 - version: 4.3.1(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) + version: 4.3.1(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.6))(react@19.2.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.6))(react@19.2.6) react-native-safe-area-context: specifier: ~5.7.0 - version: 5.7.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) + version: 5.7.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.6))(react@19.2.6) react-native-screens: specifier: ~4.24.0 - version: 4.24.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) + version: 4.24.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.6))(react@19.2.6) use-latest-callback: specifier: ^0.3.3 - version: 0.3.3(react@19.2.5) + version: 0.3.3(react@19.2.6) zod: specifier: ^4.4.3 version: 4.4.3 devDependencies: '@testing-library/react-native': specifier: ^13.3.3 - version: 13.3.3(jest@29.7.0(@types/node@25.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-test-renderer@19.2.6(react@19.2.5))(react@19.2.5) + version: 13.3.3(jest@29.7.0(@types/node@25.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.6))(react-test-renderer@19.2.6(react@19.2.6))(react@19.2.6) '@types/jest': specifier: ^29.5.14 version: 29.5.14 @@ -441,10 +441,10 @@ importers: version: 19.2.14 jest-expo: specifier: ^55.0.17 - version: 55.0.17(@babel/core@7.29.0)(expo@55.0.23)(jest@29.7.0(@types/node@25.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)(typescript@5.9.3) + version: 55.0.17(@babel/core@7.29.0)(expo@55.0.23)(jest@29.7.0(@types/node@25.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.6))(react@19.2.6)(typescript@5.9.3) react-test-renderer: specifier: ^19.2.6 - version: 19.2.6(react@19.2.5) + version: 19.2.6(react@19.2.6) typescript: specifier: ~5.9.2 version: 5.9.3 @@ -468,16 +468,16 @@ importers: version: 2.19.3(leaflet@1.9.4) '@react-router/node': specifier: 'catalog:' - version: 7.15.0(react-router@7.15.0(react-dom@19.2.6(react@19.2.5))(react@19.2.5))(typescript@5.9.3) + version: 7.15.0(react-router@7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3) '@react-router/serve': specifier: 'catalog:' - version: 7.15.0(react-router@7.15.0(react-dom@19.2.6(react@19.2.5))(react@19.2.5))(typescript@5.9.3) + version: 7.15.0(react-router@7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3) '@sentry/node': specifier: 'catalog:' version: 10.52.0 '@sentry/react': specifier: 'catalog:' - version: 10.52.0(react@19.2.5) + version: 10.52.0(react@19.2.6) '@trails-cool/db': specifier: workspace:* version: link:../../packages/db @@ -510,7 +510,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.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(pg@8.20.0)(postgres@3.4.9) isbot: specifier: ^5.1.40 version: 5.1.40 @@ -525,13 +525,13 @@ importers: version: 15.1.3 react: specifier: ^19.2.5 - version: 19.2.5 + version: 19.2.6 react-dom: specifier: ^19.2.6 - version: 19.2.6(react@19.2.5) + version: 19.2.6(react@19.2.6) react-router: specifier: 'catalog:' - version: 7.15.0(react-dom@19.2.6(react@19.2.5))(react@19.2.5) + version: 7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) ws: specifier: ^8.20.0 version: 8.20.0 @@ -550,7 +550,7 @@ importers: devDependencies: '@react-router/dev': specifier: 'catalog:' - version: 7.15.0(@react-router/serve@7.15.0(react-router@7.15.0(react-dom@19.2.6(react@19.2.5))(react@19.2.5))(typescript@5.9.3))(@types/node@25.6.2)(jiti@2.7.0)(lightningcss@1.32.0)(react-router@7.15.0(react-dom@19.2.6(react@19.2.5))(react@19.2.5))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4))(yaml@2.8.4) + version: 7.15.0(@react-router/serve@7.15.0(react-router@7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3))(@types/node@25.6.2)(jiti@2.7.0)(lightningcss@1.32.0)(react-router@7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4))(yaml@2.8.4) '@tailwindcss/vite': specifier: 'catalog:' version: 4.3.0(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4)) @@ -634,13 +634,13 @@ importers: dependencies: i18next: specifier: '>=26' - version: 26.0.8(typescript@5.9.3) + version: 26.0.10(typescript@5.9.3) react: specifier: ^19.2.5 - version: 19.2.5 + version: 19.2.6 react-i18next: specifier: '>=17' - version: 17.0.6(i18next@26.0.8(typescript@5.9.3))(react-dom@19.2.6(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.7(i18next@26.0.10(typescript@5.9.3))(react-dom@19.2.6(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) packages/jobs: dependencies: @@ -662,13 +662,13 @@ importers: version: 1.9.4 react: specifier: ^19.2.5 - version: 19.2.5 + version: 19.2.6 react-dom: specifier: ^19.2.6 - version: 19.2.6(react@19.2.5) + version: 19.2.6(react@19.2.6) react-leaflet: specifier: '>=5' - version: 5.0.0(leaflet@1.9.4)(react-dom@19.2.6(react@19.2.5))(react@19.2.5) + version: 5.0.0(leaflet@1.9.4)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) packages/map-core: {} @@ -1841,9 +1841,6 @@ packages: resolution: {integrity: sha512-BH8sicYOqZ1iBMwCVEGIz6uTTfylosjc49FoMmCYIzKOiYdiVehsfoYBwyfxwWIiya1VMhm1gv0cgOP8fxHpDw==} hasBin: true - '@expo/image-utils@0.8.13': - resolution: {integrity: sha512-1I//yBQeTY6p0u1ihqGNDAr35EbSG8uFEupFrIF0jd++h9EWH33521yZJU1yE+mwGlzCb61g3ehu78siMhXBlA==} - '@expo/image-utils@0.8.14': resolution: {integrity: sha512-5Sn+jG4Cw+shC2wDMXoqSAJnvERbiwzHn05FpWtD5IBflfTIs5gUmjzwiGVyjOdlMSQhgRrw/AymPbmO9h9mpQ==} @@ -3821,9 +3818,6 @@ packages: '@types/node@22.19.18': resolution: {integrity: sha512-9v00a+dn2yWVsYDEunWC4g/TcRKVq3r8N5FuZp7u0SGrPvdN9c2yXI9bBuf5Fl0hNCb+QTIePTn5pJs2pwBOQQ==} - '@types/node@25.6.0': - resolution: {integrity: sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==} - '@types/node@25.6.2': resolution: {integrity: sha512-sokuT28dxf9JT5Kady1fsXOvI4HVpjZa95NKT5y9PNTIrs2AsobR4GFAA90ZG8M+nxVRLysCXsVj6eGC7Vbrlw==} @@ -5487,14 +5481,6 @@ packages: typescript: optional: true - i18next@26.0.8: - resolution: {integrity: sha512-BRzLom0mhDhV9v0QhgUUHWQJuwFmnr1194xEcNLYD6ym8y8s542n4jXUvRLnhNTbh9PmpU6kGZamyuGHQMsGjw==} - peerDependencies: - typescript: ^5 || ^6 - peerDependenciesMeta: - typescript: - optional: true - iconv-lite@0.4.24: resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} engines: {node: '>=0.10.0'} @@ -6044,10 +6030,6 @@ packages: lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} - lru-cache@11.3.5: - resolution: {integrity: sha512-NxVFwLAnrd9i7KUBxC4DrUhmgjzOs+1Qm50D3oF1/oL+r1NpZ4gA7xvG0/zJ8evR7zIKn4vLf7qTNduWFtCrRw==} - engines: {node: 20 || >=22} - lru-cache@11.3.6: resolution: {integrity: sha512-Gf/KoL3C/MlI7Bt0PGI9I+TeTC/I6r/csU58N4BSNc4lppLBeKsOdFYkK+dX0ABDUMJNfCHTyPpzwwO21Awd3A==} engines: {node: 20 || >=22} @@ -6607,10 +6589,6 @@ packages: resolution: {integrity: sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==} engines: {node: ^10 || ^12 || >=14} - postcss@8.5.13: - resolution: {integrity: sha512-qif0+jGGZoLWdHey3UFHHWP0H7Gbmsk8T5VEqyYFbWqPr1XqvLGBbk/sl8V5exGmcYJklJOhOQq1pV9IcsiFag==} - engines: {node: ^10 || ^12 || >=14} - postcss@8.5.14: resolution: {integrity: sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==} engines: {node: ^10 || ^12 || >=14} @@ -6772,22 +6750,6 @@ packages: peerDependencies: react: ^19.2.5 - react-i18next@17.0.6: - resolution: {integrity: sha512-WzJ6SMKF+GTD7JZZqxSR1AKKmXjaSu39sClUrNlwxS4Tl7a99O+ltFy6yhPMO+wgZuxpQjJ2PZkfrQKmAqrLhw==} - peerDependencies: - i18next: '>= 26.0.1' - react: ^19.2.5 - react-dom: '*' - react-native: '*' - typescript: ^5 || ^6 - peerDependenciesMeta: - react-dom: - optional: true - react-native: - optional: true - typescript: - optional: true - react-i18next@17.0.7: resolution: {integrity: sha512-rwtPXsb/zwzDafN+gytcjF5YnqGQQIRmCQ6DctBC1VSipRB8GD/MWEVrFP42vjMyuYydxWxM8CZRt+yiNuuoHg==} peerDependencies: @@ -6927,10 +6889,6 @@ packages: peerDependencies: react: ^19.2.5 - react@19.2.5: - resolution: {integrity: sha512-llUJLzz1zTUBrskt2pwZgLq59AemifIftw4aB7JxOqf1HY2FDaGDxgwpAPVzHU1kdWabH7FauP4i1oEeer2WCA==} - engines: {node: '>=0.10.0'} - react@19.2.6: resolution: {integrity: sha512-sfWGGfavi0xr8Pg0sVsyHMAOziVYKgPLNrS7ig+ivMNb3wbCBw3KxtflsGBAwD3gYQlE/AEZsTLgToRrSCjb0Q==} engines: {node: '>=0.10.0'} @@ -7084,11 +7042,6 @@ packages: engines: {node: '>=10'} hasBin: true - semver@7.7.4: - resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==} - engines: {node: '>=10'} - hasBin: true - semver@7.8.0: resolution: {integrity: sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==} engines: {node: '>=10'} @@ -8965,82 +8918,6 @@ snapshots: '@expo-google-fonts/material-symbols@0.4.36': {} - '@expo/cli@55.0.29(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-constants@55.0.16)(expo-font@55.0.7)(expo-router@55.0.14)(expo@55.0.23)(react-dom@19.2.6(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.16(typescript@5.9.3) - '@expo/config-plugins': 55.0.8 - '@expo/devcert': 1.2.1 - '@expo/env': 2.1.2 - '@expo/image-utils': 0.8.14(typescript@5.9.3) - '@expo/json-file': 10.0.14 - '@expo/log-box': 55.0.12(@expo/dom-webview@55.0.5)(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.1.1 - '@expo/metro-config': 55.0.20(expo@55.0.23)(typescript@5.9.3) - '@expo/osascript': 2.4.3 - '@expo/package-manager': 1.10.5 - '@expo/plist': 0.5.3 - '@expo/prebuild-config': 55.0.17(expo@55.0.23)(typescript@5.9.3) - '@expo/require-utils': 55.0.5(typescript@5.9.3) - '@expo/router-server': 55.0.16(@expo/metro-runtime@55.0.11)(expo-constants@55.0.16)(expo-font@55.0.7)(expo-router@55.0.14)(expo-server@55.0.9)(expo@55.0.23)(react-dom@19.2.6(react@19.2.5))(react@19.2.5) - '@expo/schema-utils': 55.0.4 - '@expo/spawn-async': 1.7.2 - '@expo/ws-tunnel': 1.0.6 - '@expo/xcpretty': 4.4.4 - '@react-native/dev-middleware': 0.83.6 - accepts: 1.3.8 - arg: 5.0.2 - better-opn: 3.0.2 - bplist-creator: 0.1.0 - bplist-parser: 0.3.2 - chalk: 4.1.2 - ci-info: 3.9.0 - compression: 1.8.1 - connect: 3.7.0 - debug: 4.4.3 - dnssd-advertise: 1.1.4 - expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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.9 - fetch-nodeshim: 0.4.10 - getenv: 2.0.0 - glob: 13.0.6 - lan-network: 0.2.1 - multitars: 1.0.0 - node-forge: 1.4.0 - npm-package-arg: 11.0.3 - ora: 3.4.0 - picomatch: 4.0.4 - pretty-format: 29.7.0 - progress: 2.0.3 - prompts: 2.4.2 - resolve-from: 5.0.0 - semver: 7.8.0 - send: 0.19.2 - slugify: 1.6.9 - source-map-support: 0.5.21 - stacktrace-parser: 0.1.11 - structured-headers: 0.4.1 - terminal-link: 2.1.1 - toqr: 0.1.1 - wrap-ansi: 7.0.0 - ws: 8.20.0 - zod: 3.25.76 - optionalDependencies: - expo-router: 55.0.14(ab64f1877338f7f43eb15d5c78597024) - react-native: 0.83.4(@babel/core@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' - - bufferutil - - expo-constants - - expo-font - - react - - react-dom - - react-server-dom-webpack - - supports-color - - typescript - - utf-8-validate - '@expo/cli@55.0.29(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-constants@55.0.16)(expo-font@55.0.7)(expo-router@55.0.14)(expo@55.0.23)(react-dom@19.2.6(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3)': dependencies: '@expo/code-signing-certificates': 0.0.6 @@ -9102,7 +8979,7 @@ snapshots: ws: 8.20.0 zod: 3.25.76 optionalDependencies: - expo-router: 55.0.14(8759932d8bf60b7936be47619a69edd6) + expo-router: 55.0.14(82db8260abd9fbac2a02011543a979fa) react-native: 0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6) transitivePeerDependencies: - '@expo/dom-webview' @@ -9116,7 +8993,6 @@ snapshots: - supports-color - typescript - utf-8-validate - optional: true '@expo/code-signing-certificates@0.0.6': dependencies: @@ -9165,33 +9041,18 @@ snapshots: transitivePeerDependencies: - supports-color - '@expo/devtools@55.0.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)': - dependencies: - chalk: 4.1.2 - optionalDependencies: - 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/devtools@55.0.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.6))(react@19.2.6)': dependencies: chalk: 4.1.2 optionalDependencies: react: 19.2.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.6) - optional: true - - '@expo/dom-webview@55.0.5(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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/dom-webview@55.0.5(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)': dependencies: expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) react: 19.2.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.6) - optional: true '@expo/env@2.1.2': dependencies: @@ -9217,19 +9078,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@expo/image-utils@0.8.13(typescript@5.9.3)': - dependencies: - '@expo/require-utils': 55.0.5(typescript@5.9.3) - '@expo/spawn-async': 1.7.2 - chalk: 4.1.2 - getenv: 2.0.0 - jimp-compact: 0.16.1 - parse-png: 2.1.0 - semver: 7.8.0 - transitivePeerDependencies: - - supports-color - - typescript - '@expo/image-utils@0.8.14(typescript@5.9.3)': dependencies: '@expo/require-utils': 55.0.5(typescript@5.9.3) @@ -9256,15 +9104,6 @@ snapshots: - supports-color - typescript - '@expo/log-box@55.0.12(@expo/dom-webview@55.0.5)(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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/log-box@55.0.12(@expo/dom-webview@55.0.5)(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)': dependencies: '@expo/dom-webview': 55.0.5(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) @@ -9273,7 +9112,6 @@ snapshots: react: 19.2.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.6) stacktrace-parser: 0.1.11 - optional: true '@expo/metro-config@55.0.20(expo@55.0.23)(typescript@5.9.3)': dependencies: @@ -9297,28 +9135,13 @@ snapshots: postcss: 8.4.49 resolve-from: 5.0.0 optionalDependencies: - expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) transitivePeerDependencies: - bufferutil - supports-color - typescript - utf-8-validate - '@expo/metro-runtime@55.0.11(@expo/dom-webview@55.0.5)(expo@55.0.23)(react-dom@19.2.6(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.12(@expo/dom-webview@55.0.5)(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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.6(react@19.2.5) - transitivePeerDependencies: - - '@expo/dom-webview' - '@expo/metro-runtime@55.0.11(@expo/dom-webview@55.0.5)(expo@55.0.23)(react-dom@19.2.6(react@19.2.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.6))(react@19.2.6)': dependencies: '@expo/log-box': 55.0.12(@expo/dom-webview@55.0.5)(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) @@ -9333,7 +9156,6 @@ snapshots: react-dom: 19.2.6(react@19.2.6) transitivePeerDependencies: - '@expo/dom-webview' - optional: true '@expo/metro@55.1.1': dependencies: @@ -9384,7 +9206,7 @@ snapshots: '@expo/json-file': 10.0.14 '@react-native/normalize-colors': 0.83.6 debug: 4.4.3 - expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) resolve-from: 5.0.0 semver: 7.8.0 xml2js: 0.6.0 @@ -9402,21 +9224,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@expo/router-server@55.0.16(@expo/metro-runtime@55.0.11)(expo-constants@55.0.16)(expo-font@55.0.7)(expo-router@55.0.14)(expo-server@55.0.9)(expo@55.0.23)(react-dom@19.2.6(react@19.2.5))(react@19.2.5)': - dependencies: - debug: 4.4.3 - expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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.16(expo@55.0.23)(react-native@0.83.4(@babel/core@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.7(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.9 - react: 19.2.5 - optionalDependencies: - '@expo/metro-runtime': 55.0.11(@expo/dom-webview@55.0.5)(expo@55.0.23)(react-dom@19.2.6(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.14(ab64f1877338f7f43eb15d5c78597024) - react-dom: 19.2.6(react@19.2.5) - transitivePeerDependencies: - - supports-color - '@expo/router-server@55.0.16(@expo/metro-runtime@55.0.11)(expo-constants@55.0.16)(expo-font@55.0.7)(expo-router@55.0.14)(expo-server@55.0.9)(expo@55.0.23)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: debug: 4.4.3 @@ -9427,11 +9234,10 @@ snapshots: react: 19.2.6 optionalDependencies: '@expo/metro-runtime': 55.0.11(@expo/dom-webview@55.0.5)(expo@55.0.23)(react-dom@19.2.6(react@19.2.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.6))(react@19.2.6) - expo-router: 55.0.14(8759932d8bf60b7936be47619a69edd6) + expo-router: 55.0.14(82db8260abd9fbac2a02011543a979fa) react-dom: 19.2.6(react@19.2.6) transitivePeerDependencies: - supports-color - optional: true '@expo/schema-utils@55.0.4': {} @@ -9443,18 +9249,11 @@ snapshots: '@expo/sudo-prompt@9.3.2': {} - '@expo/vector-icons@15.1.1(expo-font@55.0.7)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.7(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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) - '@expo/vector-icons@15.1.1(expo-font@55.0.7)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)': dependencies: expo-font: 55.0.7(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) react: 19.2.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.6) - optional: true '@expo/ws-tunnel@1.0.6': {} @@ -9501,22 +9300,22 @@ snapshots: lodash: 4.18.1 polyclip-ts: 0.16.8 - '@gorhom/bottom-sheet@5.2.14(@types/react@19.2.14)(react-native-gesture-handler@2.31.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-reanimated@4.3.1(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)': + '@gorhom/bottom-sheet@5.2.14(@types/react@19.2.14)(react-native-gesture-handler@2.31.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.6))(react@19.2.6))(react-native-reanimated@4.3.1(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.6))(react@19.2.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.6))(react@19.2.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.6))(react@19.2.6)': 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) + '@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.6))(react@19.2.6) 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.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-reanimated: 4.3.1(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: 19.2.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.6) + react-native-gesture-handler: 2.31.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.6))(react@19.2.6) + react-native-reanimated: 4.3.1(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.6))(react@19.2.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.6))(react@19.2.6) 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)': + '@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.6))(react@19.2.6)': dependencies: nanoid: 3.3.12 - 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.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.6) '@hexagon/base64@1.1.28': {} @@ -9897,15 +9696,15 @@ snapshots: rw: 1.3.3 tinyqueue: 3.0.0 - '@maplibre/maplibre-react-native@11.1.1(@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)': + '@maplibre/maplibre-react-native@11.1.1(@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.6))(react@19.2.6)': dependencies: '@maplibre/maplibre-gl-style-spec': 24.8.1 '@turf/distance': 7.3.5 '@turf/helpers': 7.3.5 '@turf/length': 7.3.5 '@turf/nearest-point-on-line': 7.3.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.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.6) optionalDependencies: '@expo/config-plugins': 55.0.8 '@types/geojson': 7946.0.16 @@ -10274,18 +10073,6 @@ snapshots: '@radix-ui/primitive@1.1.3': {} - '@radix-ui/react-collection@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.5))(react@19.2.5)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.5) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.5) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.5))(react@19.2.5) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.5) - react: 19.2.5 - react-dom: 19.2.6(react@19.2.5) - optionalDependencies: - '@types/react': 19.2.14 - '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-collection@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.6) @@ -10297,55 +10084,18 @@ snapshots: optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - optional: true - - '@radix-ui/react-compose-refs@1.1.2(@types/react@19.2.14)(react@19.2.5)': - dependencies: - react: 19.2.5 - optionalDependencies: - '@types/react': 19.2.14 '@radix-ui/react-compose-refs@1.1.2(@types/react@19.2.14)(react@19.2.6)': dependencies: react: 19.2.6 optionalDependencies: '@types/react': 19.2.14 - optional: true - - '@radix-ui/react-context@1.1.2(@types/react@19.2.14)(react@19.2.5)': - dependencies: - react: 19.2.5 - optionalDependencies: - '@types/react': 19.2.14 '@radix-ui/react-context@1.1.2(@types/react@19.2.14)(react@19.2.6)': dependencies: react: 19.2.6 optionalDependencies: '@types/react': 19.2.14 - optional: true - - '@radix-ui/react-dialog@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.5))(react@19.2.5)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.5) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.5) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.5))(react@19.2.5) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.14)(react@19.2.5) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.5))(react@19.2.5) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.5) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.5))(react@19.2.5) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.5))(react@19.2.5) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.5))(react@19.2.5) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.5) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.5) - aria-hidden: 1.2.6 - react: 19.2.5 - react-dom: 19.2.6(react@19.2.5) - react-remove-scroll: 2.7.2(@types/react@19.2.14)(react@19.2.5) - optionalDependencies: - '@types/react': 19.2.14 - '@types/react-dom': 19.2.3(@types/react@19.2.14) '@radix-ui/react-dialog@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: @@ -10368,33 +10118,12 @@ snapshots: optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - optional: true - - '@radix-ui/react-direction@1.1.1(@types/react@19.2.14)(react@19.2.5)': - dependencies: - react: 19.2.5 - optionalDependencies: - '@types/react': 19.2.14 '@radix-ui/react-direction@1.1.1(@types/react@19.2.14)(react@19.2.6)': dependencies: react: 19.2.6 optionalDependencies: '@types/react': 19.2.14 - optional: true - - '@radix-ui/react-dismissable-layer@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.5))(react@19.2.5)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.5) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.5))(react@19.2.5) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.5) - '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.2.14)(react@19.2.5) - react: 19.2.5 - react-dom: 19.2.6(react@19.2.5) - optionalDependencies: - '@types/react': 19.2.14 - '@types/react-dom': 19.2.3(@types/react@19.2.14) '@radix-ui/react-dismissable-layer@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: @@ -10408,31 +10137,12 @@ snapshots: optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - optional: true - - '@radix-ui/react-focus-guards@1.1.3(@types/react@19.2.14)(react@19.2.5)': - dependencies: - react: 19.2.5 - optionalDependencies: - '@types/react': 19.2.14 '@radix-ui/react-focus-guards@1.1.3(@types/react@19.2.14)(react@19.2.6)': dependencies: react: 19.2.6 optionalDependencies: '@types/react': 19.2.14 - optional: true - - '@radix-ui/react-focus-scope@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.5))(react@19.2.5)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.5) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.5))(react@19.2.5) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.5) - react: 19.2.5 - react-dom: 19.2.6(react@19.2.5) - optionalDependencies: - '@types/react': 19.2.14 - '@types/react-dom': 19.2.3(@types/react@19.2.14) '@radix-ui/react-focus-scope@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: @@ -10444,14 +10154,6 @@ snapshots: optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - optional: true - - '@radix-ui/react-id@1.1.1(@types/react@19.2.14)(react@19.2.5)': - dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.5) - react: 19.2.5 - optionalDependencies: - '@types/react': 19.2.14 '@radix-ui/react-id@1.1.1(@types/react@19.2.14)(react@19.2.6)': dependencies: @@ -10459,17 +10161,6 @@ snapshots: react: 19.2.6 optionalDependencies: '@types/react': 19.2.14 - optional: true - - '@radix-ui/react-portal@1.1.9(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.5))(react@19.2.5)': - dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.5))(react@19.2.5) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.5) - react: 19.2.5 - react-dom: 19.2.6(react@19.2.5) - optionalDependencies: - '@types/react': 19.2.14 - '@types/react-dom': 19.2.3(@types/react@19.2.14) '@radix-ui/react-portal@1.1.9(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: @@ -10480,17 +10171,6 @@ snapshots: optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - optional: true - - '@radix-ui/react-presence@1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.5))(react@19.2.5)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.5) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.5) - react: 19.2.5 - react-dom: 19.2.6(react@19.2.5) - optionalDependencies: - '@types/react': 19.2.14 - '@types/react-dom': 19.2.3(@types/react@19.2.14) '@radix-ui/react-presence@1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: @@ -10501,16 +10181,6 @@ snapshots: optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - optional: true - - '@radix-ui/react-primitive@2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.5))(react@19.2.5)': - dependencies: - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.5) - react: 19.2.5 - react-dom: 19.2.6(react@19.2.5) - optionalDependencies: - '@types/react': 19.2.14 - '@types/react-dom': 19.2.3(@types/react@19.2.14) '@radix-ui/react-primitive@2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: @@ -10520,24 +10190,6 @@ snapshots: optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - optional: true - - '@radix-ui/react-roving-focus@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.5))(react@19.2.5)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.5))(react@19.2.5) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.5) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.5) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.5) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.5) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.5))(react@19.2.5) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.5) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.5) - react: 19.2.5 - react-dom: 19.2.6(react@19.2.5) - optionalDependencies: - '@types/react': 19.2.14 - '@types/react-dom': 19.2.3(@types/react@19.2.14) '@radix-ui/react-roving-focus@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: @@ -10555,14 +10207,6 @@ snapshots: optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - optional: true - - '@radix-ui/react-slot@1.2.3(@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-slot@1.2.3(@types/react@19.2.14)(react@19.2.6)': dependencies: @@ -10570,14 +10214,6 @@ snapshots: react: 19.2.6 optionalDependencies: '@types/react': 19.2.14 - optional: true - - '@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-slot@1.2.4(@types/react@19.2.14)(react@19.2.6)': dependencies: @@ -10585,23 +10221,6 @@ snapshots: react: 19.2.6 optionalDependencies: '@types/react': 19.2.14 - optional: true - - '@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.6(react@19.2.5))(react@19.2.5)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.5) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.5) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.5) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.5))(react@19.2.5) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.5))(react@19.2.5) - '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.5))(react@19.2.5) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.5) - react: 19.2.5 - react-dom: 19.2.6(react@19.2.5) - optionalDependencies: - '@types/react': 19.2.14 - '@types/react-dom': 19.2.3(@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.6(react@19.2.6))(react@19.2.6)': dependencies: @@ -10618,28 +10237,12 @@ snapshots: optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - optional: true - - '@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.2.14)(react@19.2.5)': - dependencies: - react: 19.2.5 - optionalDependencies: - '@types/react': 19.2.14 '@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.2.14)(react@19.2.6)': dependencies: react: 19.2.6 optionalDependencies: '@types/react': 19.2.14 - optional: true - - '@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.2.14)(react@19.2.5)': - dependencies: - '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.2.14)(react@19.2.5) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.5) - react: 19.2.5 - optionalDependencies: - '@types/react': 19.2.14 '@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.2.14)(react@19.2.6)': dependencies: @@ -10648,14 +10251,6 @@ snapshots: react: 19.2.6 optionalDependencies: '@types/react': 19.2.14 - optional: true - - '@radix-ui/react-use-effect-event@0.0.2(@types/react@19.2.14)(react@19.2.5)': - dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.5) - react: 19.2.5 - optionalDependencies: - '@types/react': 19.2.14 '@radix-ui/react-use-effect-event@0.0.2(@types/react@19.2.14)(react@19.2.6)': dependencies: @@ -10663,14 +10258,6 @@ snapshots: react: 19.2.6 optionalDependencies: '@types/react': 19.2.14 - optional: true - - '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@19.2.14)(react@19.2.5)': - dependencies: - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.5) - react: 19.2.5 - optionalDependencies: - '@types/react': 19.2.14 '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@19.2.14)(react@19.2.6)': dependencies: @@ -10678,26 +10265,18 @@ snapshots: react: 19.2.6 optionalDependencies: '@types/react': 19.2.14 - optional: true - - '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.2.14)(react@19.2.5)': - dependencies: - react: 19.2.5 - optionalDependencies: - '@types/react': 19.2.14 '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.2.14)(react@19.2.6)': dependencies: react: 19.2.6 optionalDependencies: '@types/react': 19.2.14 - optional: true - '@react-leaflet/core@3.0.0(leaflet@1.9.4)(react-dom@19.2.6(react@19.2.5))(react@19.2.5)': + '@react-leaflet/core@3.0.0(leaflet@1.9.4)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: leaflet: 1.9.4 - react: 19.2.5 - react-dom: 19.2.6(react@19.2.5) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) '@react-native/assets-registry@0.83.4': {} @@ -10934,15 +10513,6 @@ snapshots: '@react-native/normalize-colors@0.83.6': {} - '@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)(@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-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.6))(react@19.2.6)': dependencies: invariant: 2.2.4 @@ -10951,20 +10521,6 @@ 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.6) optionalDependencies: '@types/react': 19.2.14 - optional: true - - '@react-navigation/bottom-tabs@7.15.13(@react-navigation/native@7.2.4(react-native@0.83.4(@babel/core@7.29.0)(@react-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.7.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-screens@4.24.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.17(@react-navigation/native@7.2.4(react-native@0.83.4(@babel/core@7.29.0)(@react-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.7.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.4(react-native@0.83.4(@babel/core@7.29.0)(@react-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)(@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.7.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-screens: 4.24.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' '@react-navigation/bottom-tabs@7.15.13(@react-navigation/native@7.2.4(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-safe-area-context@5.7.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.6))(react@19.2.6))(react-native-screens@4.24.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.6))(react@19.2.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.6))(react@19.2.6)': dependencies: @@ -10978,19 +10534,6 @@ snapshots: sf-symbols-typescript: 2.2.0 transitivePeerDependencies: - '@react-native-masked-view/masked-view' - optional: true - - '@react-navigation/core@7.17.4(react@19.2.5)': - dependencies: - '@react-navigation/routers': 7.5.5 - escape-string-regexp: 4.0.0 - fast-deep-equal: 3.1.3 - nanoid: 3.3.12 - query-string: 7.1.3 - react: 19.2.5 - react-is: 19.2.6 - use-latest-callback: 0.2.6(react@19.2.5) - use-sync-external-store: 1.6.0(react@19.2.5) '@react-navigation/core@7.17.4(react@19.2.6)': dependencies: @@ -11003,17 +10546,6 @@ snapshots: react-is: 19.2.6 use-latest-callback: 0.2.6(react@19.2.6) use-sync-external-store: 1.6.0(react@19.2.6) - optional: true - - '@react-navigation/elements@2.9.17(@react-navigation/native@7.2.4(react-native@0.83.4(@babel/core@7.29.0)(@react-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.7.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/native': 7.2.4(react-native@0.83.4(@babel/core@7.29.0)(@react-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)(@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.7.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: 0.2.6(react@19.2.5) - use-sync-external-store: 1.6.0(react@19.2.5) '@react-navigation/elements@2.9.17(@react-navigation/native@7.2.4(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-safe-area-context@5.7.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.6))(react@19.2.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.6))(react@19.2.6)': dependencies: @@ -11024,21 +10556,6 @@ snapshots: react-native-safe-area-context: 5.7.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.6))(react@19.2.6) use-latest-callback: 0.2.6(react@19.2.6) use-sync-external-store: 1.6.0(react@19.2.6) - optional: true - - '@react-navigation/native-stack@7.14.14(@react-navigation/native@7.2.4(react-native@0.83.4(@babel/core@7.29.0)(@react-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.7.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-screens@4.24.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.17(@react-navigation/native@7.2.4(react-native@0.83.4(@babel/core@7.29.0)(@react-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.7.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.4(react-native@0.83.4(@babel/core@7.29.0)(@react-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)(@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.7.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-screens: 4.24.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-stack@7.14.14(@react-navigation/native@7.2.4(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-safe-area-context@5.7.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.6))(react@19.2.6))(react-native-screens@4.24.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.6))(react@19.2.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.6))(react@19.2.6)': dependencies: @@ -11053,17 +10570,6 @@ snapshots: warn-once: 0.1.1 transitivePeerDependencies: - '@react-native-masked-view/masked-view' - optional: true - - '@react-navigation/native@7.2.4(react-native@0.83.4(@babel/core@7.29.0)(@react-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.4(react@19.2.5) - escape-string-regexp: 4.0.0 - fast-deep-equal: 3.1.3 - nanoid: 3.3.12 - 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/native@7.2.4(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)': dependencies: @@ -11074,13 +10580,12 @@ snapshots: react: 19.2.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.6) use-latest-callback: 0.2.6(react@19.2.6) - optional: true '@react-navigation/routers@7.5.5': dependencies: nanoid: 3.3.12 - '@react-router/dev@7.15.0(@react-router/serve@7.15.0(react-router@7.15.0(react-dom@19.2.6(react@19.2.5))(react@19.2.5))(typescript@5.9.3))(@types/node@25.6.2)(jiti@2.7.0)(lightningcss@1.32.0)(react-router@7.15.0(react-dom@19.2.6(react@19.2.5))(react@19.2.5))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4))(yaml@2.8.4)': + '@react-router/dev@7.15.0(@react-router/serve@7.15.0(react-router@7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3))(@types/node@25.6.2)(jiti@2.7.0)(lightningcss@1.32.0)(react-router@7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4))(yaml@2.8.4)': dependencies: '@babel/core': 7.29.0 '@babel/generator': 7.29.1 @@ -11089,7 +10594,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.15.0(react-router@7.15.0(react-dom@19.2.6(react@19.2.5))(react@19.2.5))(typescript@5.9.3) + '@react-router/node': 7.15.0(react-router@7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3) '@remix-run/node-fetch-server': 0.13.1 arg: 5.0.2 babel-dead-code-elimination: 1.0.12 @@ -11106,14 +10611,14 @@ snapshots: pkg-types: 2.3.1 prettier: 3.8.3 react-refresh: 0.14.2 - react-router: 7.15.0(react-dom@19.2.6(react@19.2.5))(react@19.2.5) + react-router: 7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) semver: 7.8.0 tinyglobby: 0.2.16 valibot: 1.4.0(typescript@5.9.3) vite: 8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4) vite-node: 3.2.4(@types/node@25.6.2)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4) optionalDependencies: - '@react-router/serve': 7.15.0(react-router@7.15.0(react-dom@19.2.6(react@19.2.5))(react@19.2.5))(typescript@5.9.3) + '@react-router/serve': 7.15.0(react-router@7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - '@types/node' @@ -11130,31 +10635,31 @@ snapshots: - tsx - yaml - '@react-router/express@7.15.0(express@4.22.1)(react-router@7.15.0(react-dom@19.2.6(react@19.2.5))(react@19.2.5))(typescript@5.9.3)': + '@react-router/express@7.15.0(express@4.22.1)(react-router@7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3)': dependencies: - '@react-router/node': 7.15.0(react-router@7.15.0(react-dom@19.2.6(react@19.2.5))(react@19.2.5))(typescript@5.9.3) + '@react-router/node': 7.15.0(react-router@7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3) express: 4.22.1 - react-router: 7.15.0(react-dom@19.2.6(react@19.2.5))(react@19.2.5) + react-router: 7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) optionalDependencies: typescript: 5.9.3 - '@react-router/node@7.15.0(react-router@7.15.0(react-dom@19.2.6(react@19.2.5))(react@19.2.5))(typescript@5.9.3)': + '@react-router/node@7.15.0(react-router@7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3)': dependencies: '@mjackson/node-fetch-server': 0.2.0 - react-router: 7.15.0(react-dom@19.2.6(react@19.2.5))(react@19.2.5) + react-router: 7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) optionalDependencies: typescript: 5.9.3 - '@react-router/serve@7.15.0(react-router@7.15.0(react-dom@19.2.6(react@19.2.5))(react@19.2.5))(typescript@5.9.3)': + '@react-router/serve@7.15.0(react-router@7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3)': dependencies: '@mjackson/node-fetch-server': 0.2.0 - '@react-router/express': 7.15.0(express@4.22.1)(react-router@7.15.0(react-dom@19.2.6(react@19.2.5))(react@19.2.5))(typescript@5.9.3) - '@react-router/node': 7.15.0(react-router@7.15.0(react-dom@19.2.6(react@19.2.5))(react@19.2.5))(typescript@5.9.3) + '@react-router/express': 7.15.0(express@4.22.1)(react-router@7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3) + '@react-router/node': 7.15.0(react-router@7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3) compression: 1.8.1 express: 4.22.1 get-port: 5.1.1 morgan: 1.10.1 - react-router: 7.15.0(react-dom@19.2.6(react@19.2.5))(react@19.2.5) + react-router: 7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) source-map-support: 0.5.21 transitivePeerDependencies: - supports-color @@ -11505,34 +11010,34 @@ snapshots: '@opentelemetry/semantic-conventions': 1.40.0 '@sentry/core': 10.52.0 - '@sentry/react-native@8.11.0(@expo/env@2.1.2)(dotenv@16.6.1)(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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@8.11.0(@expo/env@2.1.2)(dotenv@16.6.1)(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)': dependencies: '@sentry/babel-plugin-component-annotate': 5.2.1 '@sentry/browser': 10.51.0 '@sentry/cli': 3.4.1 '@sentry/core': 10.51.0 '@sentry/expo-upload-sourcemaps': 8.11.0(@expo/env@2.1.2)(dotenv@16.6.1) - '@sentry/react': 10.51.0(react@19.2.5) + '@sentry/react': 10.51.0(react@19.2.6) '@sentry/types': 10.51.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) + react: 19.2.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.6) optionalDependencies: - expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) transitivePeerDependencies: - '@expo/env' - dotenv - '@sentry/react@10.51.0(react@19.2.5)': + '@sentry/react@10.51.0(react@19.2.6)': dependencies: '@sentry/browser': 10.51.0 '@sentry/core': 10.51.0 - react: 19.2.5 + react: 19.2.6 - '@sentry/react@10.52.0(react@19.2.5)': + '@sentry/react@10.52.0(react@19.2.6)': dependencies: '@sentry/browser': 10.52.0 '@sentry/core': 10.52.0 - react: 19.2.5 + react: 19.2.6 '@sentry/rollup-plugin@5.2.1(rollup@4.60.3)': dependencies: @@ -11674,7 +11179,7 @@ snapshots: picocolors: 1.1.1 redent: 3.0.0 - '@testing-library/react-native@13.3.3(jest@29.7.0(@types/node@22.19.18))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react-test-renderer@19.2.6(react@19.2.6))(react@19.2.6)': + '@testing-library/react-native@13.3.3(jest@29.7.0(@types/node@25.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.6))(react-test-renderer@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: jest-matcher-utils: 30.3.0 picocolors: 1.1.1 @@ -11683,28 +11188,15 @@ 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.6) react-test-renderer: 19.2.6(react@19.2.6) redent: 3.0.0 - optionalDependencies: - jest: 29.7.0(@types/node@22.19.18) - optional: true - - '@testing-library/react-native@13.3.3(jest@29.7.0(@types/node@25.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-test-renderer@19.2.6(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)(@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.6(react@19.2.5) - redent: 3.0.0 optionalDependencies: jest: 29.7.0(@types/node@25.6.2) - '@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.6(react@19.2.5))(react@19.2.5)': + '@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.6(react@19.2.6))(react@19.2.6)': dependencies: '@babel/runtime': 7.29.2 '@testing-library/dom': 10.4.1 - react: 19.2.5 - react-dom: 19.2.6(react@19.2.5) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) @@ -11979,17 +11471,13 @@ snapshots: dependencies: undici-types: 6.21.0 - '@types/node@25.6.0': - dependencies: - undici-types: 7.19.2 - '@types/node@25.6.2': dependencies: undici-types: 7.19.2 '@types/nodemailer@8.0.0': dependencies: - '@types/node': 25.6.0 + '@types/node': 25.6.2 '@types/pg-pool@2.0.7': dependencies: @@ -12023,7 +11511,7 @@ snapshots: '@types/ws@8.18.1': dependencies: - '@types/node': 25.6.0 + '@types/node': 25.6.2 '@types/yargs-parser@21.0.3': {} @@ -12422,7 +11910,7 @@ snapshots: resolve-from: 5.0.0 optionalDependencies: '@babel/runtime': 7.29.2 - expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) transitivePeerDependencies: - '@babel/core' - supports-color @@ -12723,22 +12211,6 @@ snapshots: dependencies: browserslist: 4.28.2 - create-jest@29.7.0(@types/node@22.19.18): - 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@22.19.18) - jest-util: 29.7.0 - prompts: 2.4.2 - transitivePeerDependencies: - - '@types/node' - - babel-plugin-macros - - supports-color - - ts-node - optional: true - create-jest@29.7.0(@types/node@25.6.2): dependencies: '@jest/types': 29.6.3 @@ -12889,14 +12361,6 @@ 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.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(pg@8.20.0)(postgres@3.4.9): optionalDependencies: '@opentelemetry/api': 1.9.1 @@ -13081,7 +12545,7 @@ snapshots: eslint-scope@9.1.2: dependencies: '@types/esrecurse': 4.3.1 - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 esrecurse: 4.3.0 estraverse: 5.3.0 @@ -13100,7 +12564,7 @@ snapshots: '@humanfs/node': 0.16.8 '@humanwhocodes/module-importer': 1.0.1 '@humanwhocodes/retry': 0.4.3 - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 ajv: 6.15.0 cross-spawn: 7.0.6 debug: 4.4.3 @@ -13182,18 +12646,7 @@ snapshots: expo-application@55.0.14(expo@55.0.23): dependencies: - expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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.17(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.14(typescript@5.9.3) - expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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.16(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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) - transitivePeerDependencies: - - supports-color - - typescript + expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) expo-asset@55.0.17(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)(typescript@5.9.3): dependencies: @@ -13205,15 +12658,6 @@ snapshots: transitivePeerDependencies: - supports-color - typescript - optional: true - - expo-constants@55.0.16(expo@55.0.23)(react-native@0.83.4(@babel/core@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/env': 2.1.2 - expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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-constants@55.0.16(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6)): dependencies: @@ -13222,15 +12666,14 @@ 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.6) transitivePeerDependencies: - supports-color - optional: true expo-crypto@55.0.14(expo@55.0.23): dependencies: - expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) expo-dev-client@55.0.32(expo@55.0.23): dependencies: - expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) expo-dev-launcher: 55.0.33(expo@55.0.23) expo-dev-menu: 55.0.27(expo@55.0.23) expo-dev-menu-interface: 55.0.2(expo@55.0.23) @@ -13240,41 +12683,28 @@ snapshots: expo-dev-launcher@55.0.33(expo@55.0.23): dependencies: '@expo/schema-utils': 55.0.4 - expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) expo-dev-menu: 55.0.27(expo@55.0.23) expo-manifests: 55.0.16(expo@55.0.23) expo-dev-menu-interface@55.0.2(expo@55.0.23): dependencies: - expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) expo-dev-menu@55.0.27(expo@55.0.23): dependencies: - expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) expo-dev-menu-interface: 55.0.2(expo@55.0.23) expo-device@55.0.16(expo@55.0.23): dependencies: - expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) ua-parser-js: 0.7.41 - expo-file-system@55.0.19(expo@55.0.23)(react-native@0.83.4(@babel/core@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.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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-file-system@55.0.19(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6)): dependencies: expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(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.6) - optional: true - - expo-font@55.0.7(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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-font@55.0.7(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6): dependencies: @@ -13282,27 +12712,12 @@ snapshots: fontfaceobserver: 2.3.0 react: 19.2.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.6) - optional: true - - expo-glass-effect@55.0.11(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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-glass-effect@55.0.11(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6): dependencies: expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) react: 19.2.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.6) - optional: true - - expo-image@55.0.10(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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-image@55.0.10(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6): dependencies: @@ -13310,30 +12725,13 @@ snapshots: react: 19.2.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.6) sf-symbols-typescript: 2.2.0 - optional: true expo-json-utils@55.0.2: {} - expo-keep-awake@55.0.8(expo@55.0.23)(react@19.2.5): - dependencies: - expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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-keep-awake@55.0.8(expo@55.0.23)(react@19.2.6): dependencies: expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) react: 19.2.6 - optional: true - - expo-linking@55.0.15(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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-constants: 55.0.16(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(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) - transitivePeerDependencies: - - expo - - supports-color expo-linking@55.0.15(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6): dependencies: @@ -13344,25 +12742,24 @@ snapshots: transitivePeerDependencies: - expo - supports-color - optional: true - expo-localization@55.0.13(expo@55.0.23)(react@19.2.5): + expo-localization@55.0.13(expo@55.0.23)(react@19.2.6): dependencies: - expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) + react: 19.2.6 rtl-detect: 1.1.2 expo-location@55.1.9(expo@55.0.23)(typescript@5.9.3): dependencies: '@expo/image-utils': 0.8.14(typescript@5.9.3) - expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) transitivePeerDependencies: - supports-color - typescript expo-manifests@55.0.16(expo@55.0.23): dependencies: - expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) expo-json-utils: 55.0.2 expo-modules-autolinking@55.0.21(typescript@5.9.3): @@ -13375,14 +12772,6 @@ snapshots: - supports-color - typescript - expo-modules-core@55.0.25(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)(@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-modules-core@55.0.25(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.6))(react@19.2.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.6))(react@19.2.6): dependencies: invariant: 2.2.4 @@ -13390,33 +12779,32 @@ 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.6) 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.6))(react@19.2.6) - optional: true - expo-navigation-bar@55.0.12(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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-navigation-bar@55.0.12(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6): dependencies: debug: 4.4.3 - expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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) + expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) + react: 19.2.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.6) + 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.6))(react@19.2.6) transitivePeerDependencies: - supports-color - expo-notifications@55.0.22(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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-notifications@55.0.22(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)(typescript@5.9.3): dependencies: - '@expo/image-utils': 0.8.13(typescript@5.9.3) + '@expo/image-utils': 0.8.14(typescript@5.9.3) abort-controller: 3.0.0 badgin: 1.2.3 - expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) expo-application: 55.0.14(expo@55.0.23) - expo-constants: 55.0.16(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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) + expo-constants: 55.0.16(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6)) + react: 19.2.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.6) transitivePeerDependencies: - supports-color - typescript - expo-router@55.0.14(8759932d8bf60b7936be47619a69edd6): + expo-router@55.0.14(82db8260abd9fbac2a02011543a979fa): dependencies: '@expo/log-box': 55.0.12(@expo/dom-webview@55.0.5)(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) '@expo/metro-runtime': 55.0.11(@expo/dom-webview@55.0.5)(expo@55.0.23)(react-dom@19.2.6(react@19.2.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.6))(react@19.2.6) @@ -13453,7 +12841,7 @@ snapshots: use-latest-callback: 0.2.6(react@19.2.6) vaul: 1.1.2(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) optionalDependencies: - '@testing-library/react-native': 13.3.3(jest@29.7.0(@types/node@22.19.18))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react-test-renderer@19.2.6(react@19.2.6))(react@19.2.6) + '@testing-library/react-native': 13.3.3(jest@29.7.0(@types/node@25.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.6))(react-test-renderer@19.2.6(react@19.2.6))(react@19.2.6) react-dom: 19.2.6(react@19.2.6) react-native-gesture-handler: 2.31.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.6))(react@19.2.6) react-native-reanimated: 4.3.1(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.6))(react@19.2.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.6))(react@19.2.6) @@ -13463,99 +12851,33 @@ snapshots: - '@types/react-dom' - expo-font - supports-color - optional: true - - expo-router@55.0.14(ab64f1877338f7f43eb15d5c78597024): - dependencies: - '@expo/log-box': 55.0.12(@expo/dom-webview@55.0.5)(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.11(@expo/dom-webview@55.0.5)(expo@55.0.23)(react-dom@19.2.6(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.4 - '@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.6(react@19.2.5))(react@19.2.5) - '@react-navigation/bottom-tabs': 7.15.13(@react-navigation/native@7.2.4(react-native@0.83.4(@babel/core@7.29.0)(@react-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.7.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-screens@4.24.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.4(react-native@0.83.4(@babel/core@7.29.0)(@react-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.14(@react-navigation/native@7.2.4(react-native@0.83.4(@babel/core@7.29.0)(@react-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.7.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-screens@4.24.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.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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.16(expo@55.0.23)(react-native@0.83.4(@babel/core@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.11(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.10(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.15(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.9 - expo-symbols: 55.0.8(expo-font@55.0.7)(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.12 - 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)(@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.7.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-screens: 4.24.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 - shallowequal: 1.1.0 - 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.6(react@19.2.5))(react@19.2.5) - optionalDependencies: - '@testing-library/react-native': 13.3.3(jest@29.7.0(@types/node@25.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-test-renderer@19.2.6(react@19.2.5))(react@19.2.5) - react-dom: 19.2.6(react@19.2.5) - react-native-gesture-handler: 2.31.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-reanimated: 4.3.1(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' - - '@types/react-dom' - - expo-font - - supports-color expo-secure-store@55.0.13(expo@55.0.23): dependencies: - expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) expo-server@55.0.9: {} expo-splash-screen@55.0.20(expo@55.0.23)(typescript@5.9.3): dependencies: '@expo/prebuild-config': 55.0.17(expo@55.0.23)(typescript@5.9.3) - expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) transitivePeerDependencies: - supports-color - typescript - expo-sqlite@55.0.15(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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-sqlite@55.0.15(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6): dependencies: await-lock: 2.2.2 expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) react: 19.2.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.6) - optional: true - expo-status-bar@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): + expo-status-bar@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.6))(react@19.2.6): 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-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.8(expo-font@55.0.7)(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.36 - expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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.7(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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 + react: 19.2.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.6) + 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.6))(react@19.2.6) expo-symbols@55.0.8(expo-font@55.0.7)(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6): dependencies: @@ -13565,67 +12887,24 @@ snapshots: react: 19.2.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.6) sf-symbols-typescript: 2.2.0 - optional: true - expo-system-ui@55.0.17(expo@55.0.23)(react-native@0.83.4(@babel/core@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-system-ui@55.0.17(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6)): dependencies: '@react-native/normalize-colors': 0.83.6 debug: 4.4.3 - expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(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.6) transitivePeerDependencies: - supports-color expo-updates-interface@55.1.6(expo@55.0.23): dependencies: - expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) - expo-web-browser@55.0.15(expo@55.0.23)(react-native@0.83.4(@babel/core@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@55.0.15(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6)): dependencies: - expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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.29(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-constants@55.0.16)(expo-font@55.0.7)(expo-router@55.0.14)(expo@55.0.23)(react-dom@19.2.6(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.16(typescript@5.9.3) - '@expo/config-plugins': 55.0.8 - '@expo/devtools': 55.0.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) - '@expo/fingerprint': 0.16.7 - '@expo/local-build-cache-provider': 55.0.12(typescript@5.9.3) - '@expo/log-box': 55.0.12(@expo/dom-webview@55.0.5)(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.1.1 - '@expo/metro-config': 55.0.20(expo@55.0.23)(typescript@5.9.3) - '@expo/vector-icons': 15.1.1(expo-font@55.0.7)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.1 - babel-preset-expo: 55.0.21(@babel/core@7.29.0)(@babel/runtime@7.29.2)(expo@55.0.23)(react-refresh@0.14.2) - expo-asset: 55.0.17(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.16(expo@55.0.23)(react-native@0.83.4(@babel/core@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-file-system: 55.0.19(expo@55.0.23)(react-native@0.83.4(@babel/core@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.7(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.8(expo@55.0.23)(react@19.2.5) - expo-modules-autolinking: 55.0.21(typescript@5.9.3) - expo-modules-core: 55.0.25(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)(@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.2 - optionalDependencies: - '@expo/dom-webview': 55.0.5(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-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.11(@expo/dom-webview@55.0.5)(expo@55.0.23)(react-dom@19.2.6(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 - - expo-router - - expo-widgets - - react-dom - - react-native-worklets - - react-server-dom-webpack - - supports-color - - typescript - - utf-8-validate + expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(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.6) expo@55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3): dependencies: @@ -13668,7 +12947,6 @@ snapshots: - supports-color - typescript - utf-8-validate - optional: true exponential-backoff@3.1.3: {} @@ -14007,10 +13285,6 @@ snapshots: optionalDependencies: typescript: 5.9.3 - i18next@26.0.8(typescript@5.9.3): - optionalDependencies: - typescript: 5.9.3 - iconv-lite@0.4.24: dependencies: safer-buffer: 2.1.2 @@ -14184,26 +13458,6 @@ snapshots: - babel-plugin-macros - supports-color - jest-cli@29.7.0(@types/node@22.19.18): - dependencies: - '@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@22.19.18) - exit: 0.1.2 - import-local: 3.2.0 - jest-config: 29.7.0(@types/node@22.19.18) - jest-util: 29.7.0 - jest-validate: 29.7.0 - yargs: 17.7.2 - transitivePeerDependencies: - - '@types/node' - - babel-plugin-macros - - supports-color - - ts-node - optional: true - jest-cli@29.7.0(@types/node@25.6.2): dependencies: '@jest/core': 29.7.0 @@ -14223,37 +13477,6 @@ snapshots: - supports-color - ts-node - jest-config@29.7.0(@types/node@22.19.18): - dependencies: - '@babel/core': 7.29.0 - '@jest/test-sequencer': 29.7.0 - '@jest/types': 29.6.3 - babel-jest: 29.7.0(@babel/core@7.29.0) - chalk: 4.1.2 - ci-info: 3.9.0 - deepmerge: 4.3.1 - glob: 7.2.3 - graceful-fs: 4.2.11 - jest-circus: 29.7.0 - jest-environment-node: 29.7.0 - jest-get-type: 29.6.3 - jest-regex-util: 29.6.3 - jest-resolve: 29.7.0 - jest-runner: 29.7.0 - jest-util: 29.7.0 - jest-validate: 29.7.0 - micromatch: 4.0.8 - parse-json: 5.2.0 - pretty-format: 29.7.0 - slash: 3.0.0 - strip-json-comments: 3.1.1 - optionalDependencies: - '@types/node': 22.19.18 - transitivePeerDependencies: - - babel-plugin-macros - - supports-color - optional: true - jest-config@29.7.0(@types/node@25.6.2): dependencies: '@babel/core': 7.29.0 @@ -14334,22 +13557,22 @@ snapshots: jest-mock: 29.7.0 jest-util: 29.7.0 - jest-expo@55.0.17(@babel/core@7.29.0)(expo@55.0.23)(jest@29.7.0(@types/node@25.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)(typescript@5.9.3): + jest-expo@55.0.17(@babel/core@7.29.0)(expo@55.0.23)(jest@29.7.0(@types/node@25.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.6))(react@19.2.6)(typescript@5.9.3): dependencies: '@expo/config': 55.0.16(typescript@5.9.3) '@expo/json-file': 10.0.14 '@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.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(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.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(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.6.2)) 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) - react-test-renderer: 19.2.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.6) + react-test-renderer: 19.2.0(react@19.2.6) server-only: 0.0.1 stacktrace-js: 2.0.2 transitivePeerDependencies: @@ -14573,19 +13796,6 @@ snapshots: merge-stream: 2.0.0 supports-color: 8.1.1 - jest@29.7.0(@types/node@22.19.18): - dependencies: - '@jest/core': 29.7.0 - '@jest/types': 29.6.3 - import-local: 3.2.0 - jest-cli: 29.7.0(@types/node@22.19.18) - transitivePeerDependencies: - - '@types/node' - - babel-plugin-macros - - supports-color - - ts-node - optional: true - jest@29.7.0(@types/node@25.6.2): dependencies: '@jest/core': 29.7.0 @@ -14664,7 +13874,7 @@ snapshots: decimal.js: 10.6.0 html-encoding-sniffer: 6.0.0 is-potential-custom-element-name: 1.0.1 - lru-cache: 11.3.5 + lru-cache: 11.3.6 parse5: 8.0.1 saxes: 6.0.0 symbol-tree: 3.2.4 @@ -14814,8 +14024,6 @@ snapshots: lru-cache@10.4.3: {} - lru-cache@11.3.5: {} - lru-cache@11.3.6: {} lru-cache@5.1.1: @@ -15579,12 +14787,6 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 - postcss@8.5.13: - dependencies: - nanoid: 3.3.12 - picocolors: 1.1.1 - source-map-js: 1.2.1 - postcss@8.5.14: dependencies: nanoid: 3.3.12 @@ -15725,50 +14927,27 @@ snapshots: - bufferutil - utf-8-validate - react-dom@19.2.6(react@19.2.5): - dependencies: - react: 19.2.5 - scheduler: 0.27.0 - react-dom@19.2.6(react@19.2.6): dependencies: react: 19.2.6 scheduler: 0.27.0 - optional: true react-fast-compare@3.2.2: {} - react-freeze@1.0.4(react@19.2.5): - dependencies: - react: 19.2.5 - react-freeze@1.0.4(react@19.2.6): dependencies: react: 19.2.6 - optional: true - react-i18next@17.0.6(i18next@26.0.8(typescript@5.9.3))(react-dom@19.2.6(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 - i18next: 26.0.8(typescript@5.9.3) - react: 19.2.5 - use-sync-external-store: 1.6.0(react@19.2.5) - optionalDependencies: - react-dom: 19.2.6(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-i18next@17.0.7(i18next@26.0.10(typescript@5.9.3))(react-dom@19.2.6(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.7(i18next@26.0.10(typescript@5.9.3))(react-dom@19.2.6(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3): dependencies: '@babel/runtime': 7.29.2 html-parse-stringify: 3.0.1 i18next: 26.0.10(typescript@5.9.3) - react: 19.2.5 - use-sync-external-store: 1.6.0(react@19.2.5) + react: 19.2.6 + use-sync-external-store: 1.6.0(react@19.2.6) optionalDependencies: - react-dom: 19.2.6(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-dom: 19.2.6(react@19.2.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.6) typescript: 5.9.3 react-is@16.13.1: {} @@ -15779,21 +14958,12 @@ snapshots: react-is@19.2.6: {} - react-leaflet@5.0.0(leaflet@1.9.4)(react-dom@19.2.6(react@19.2.5))(react@19.2.5): + react-leaflet@5.0.0(leaflet@1.9.4)(react-dom@19.2.6(react@19.2.6))(react@19.2.6): dependencies: - '@react-leaflet/core': 3.0.0(leaflet@1.9.4)(react-dom@19.2.6(react@19.2.5))(react@19.2.5) + '@react-leaflet/core': 3.0.0(leaflet@1.9.4)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) leaflet: 1.9.4 - react: 19.2.5 - react-dom: 19.2.6(react@19.2.5) - - react-native-gesture-handler@2.31.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: - '@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: 19.2.6 + react-dom: 19.2.6(react@19.2.6) react-native-gesture-handler@2.31.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.6))(react@19.2.6): dependencies: @@ -15803,26 +14973,11 @@ snapshots: invariant: 2.2.4 react: 19.2.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.6) - optional: true - - 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)(@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.6))(react@19.2.6): dependencies: react: 19.2.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.6) - optional: true - - react-native-reanimated@4.3.1(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)(@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.8.0 react-native-reanimated@4.3.1(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.6))(react@19.2.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.6))(react@19.2.6): dependencies: @@ -15831,25 +14986,11 @@ snapshots: 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.6))(react@19.2.6) 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.6))(react@19.2.6) semver: 7.8.0 - optional: true - - react-native-safe-area-context@5.7.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-native: 0.83.4(@babel/core@7.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.7.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.6))(react@19.2.6): dependencies: react: 19.2.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.6) - optional: true - - react-native-screens@4.24.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)(@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-screens@4.24.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.6))(react@19.2.6): dependencies: @@ -15857,27 +14998,6 @@ snapshots: react-freeze: 1.0.4(react@19.2.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.6) warn-once: 0.1.1 - optional: true - - 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.8.0 - transitivePeerDependencies: - - supports-color 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.6))(react@19.2.6): dependencies: @@ -15898,55 +15018,6 @@ snapshots: semver: 7.8.0 transitivePeerDependencies: - supports-color - optional: true - - react-native@0.83.4(@babel/core@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/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)(@react-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 - babel-jest: 29.7.0(@babel/core@7.29.0) - babel-plugin-syntax-hermes-parser: 0.32.0 - base64-js: 1.5.1 - commander: 12.1.0 - flow-enums-runtime: 0.0.6 - glob: 7.2.3 - hermes-compiler: 0.14.1 - invariant: 2.2.4 - jest-environment-node: 29.7.0 - memoize-one: 5.2.1 - metro-runtime: 0.83.7 - metro-source-map: 0.83.7 - nullthrows: 1.1.1 - pretty-format: 29.7.0 - promise: 8.3.0 - react: 19.2.5 - react-devtools-core: 6.1.5 - react-refresh: 0.14.2 - regenerator-runtime: 0.13.11 - scheduler: 0.27.0 - semver: 7.7.4 - stacktrace-parser: 0.1.11 - whatwg-fetch: 3.6.20 - ws: 7.5.10 - yargs: 17.7.2 - optionalDependencies: - '@types/react': 19.2.14 - transitivePeerDependencies: - - '@babel/core' - - '@react-native-community/cli' - - '@react-native/metro-config' - - bufferutil - - supports-color - - utf-8-validate react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6): dependencies: @@ -15981,7 +15052,7 @@ snapshots: react-refresh: 0.14.2 regenerator-runtime: 0.13.11 scheduler: 0.27.0 - semver: 7.7.4 + semver: 7.8.0 stacktrace-parser: 0.1.11 whatwg-fetch: 3.6.20 ws: 7.5.10 @@ -15995,18 +15066,9 @@ snapshots: - bufferutil - supports-color - utf-8-validate - optional: true react-refresh@0.14.2: {} - react-remove-scroll-bar@2.3.8(@types/react@19.2.14)(react@19.2.5): - dependencies: - react: 19.2.5 - react-style-singleton: 2.2.3(@types/react@19.2.14)(react@19.2.5) - tslib: 2.8.1 - optionalDependencies: - '@types/react': 19.2.14 - react-remove-scroll-bar@2.3.8(@types/react@19.2.14)(react@19.2.6): dependencies: react: 19.2.6 @@ -16014,18 +15076,6 @@ snapshots: tslib: 2.8.1 optionalDependencies: '@types/react': 19.2.14 - optional: true - - react-remove-scroll@2.7.2(@types/react@19.2.14)(react@19.2.5): - dependencies: - react: 19.2.5 - react-remove-scroll-bar: 2.3.8(@types/react@19.2.14)(react@19.2.5) - react-style-singleton: 2.2.3(@types/react@19.2.14)(react@19.2.5) - tslib: 2.8.1 - use-callback-ref: 1.3.3(@types/react@19.2.14)(react@19.2.5) - use-sidecar: 1.1.3(@types/react@19.2.14)(react@19.2.5) - optionalDependencies: - '@types/react': 19.2.14 react-remove-scroll@2.7.2(@types/react@19.2.14)(react@19.2.6): dependencies: @@ -16037,23 +15087,14 @@ snapshots: use-sidecar: 1.1.3(@types/react@19.2.14)(react@19.2.6) optionalDependencies: '@types/react': 19.2.14 - optional: true - react-router@7.15.0(react-dom@19.2.6(react@19.2.5))(react@19.2.5): + react-router@7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6): dependencies: cookie: 1.1.1 - react: 19.2.5 + react: 19.2.6 set-cookie-parser: 2.7.2 optionalDependencies: - react-dom: 19.2.6(react@19.2.5) - - react-style-singleton@2.2.3(@types/react@19.2.14)(react@19.2.5): - dependencies: - get-nonce: 1.0.1 - react: 19.2.5 - tslib: 2.8.1 - optionalDependencies: - '@types/react': 19.2.14 + react-dom: 19.2.6(react@19.2.6) react-style-singleton@2.2.3(@types/react@19.2.14)(react@19.2.6): dependencies: @@ -16062,17 +15103,10 @@ snapshots: tslib: 2.8.1 optionalDependencies: '@types/react': 19.2.14 - optional: true - react-test-renderer@19.2.0(react@19.2.5): + react-test-renderer@19.2.0(react@19.2.6): dependencies: - react: 19.2.5 - react-is: 19.2.6 - scheduler: 0.27.0 - - react-test-renderer@19.2.6(react@19.2.5): - dependencies: - react: 19.2.5 + react: 19.2.6 react-is: 19.2.6 scheduler: 0.27.0 @@ -16081,12 +15115,8 @@ snapshots: react: 19.2.6 react-is: 19.2.6 scheduler: 0.27.0 - optional: true - react@19.2.5: {} - - react@19.2.6: - optional: true + react@19.2.6: {} readdirp@4.1.2: {} @@ -16254,8 +15284,6 @@ snapshots: semver@7.6.3: {} - semver@7.7.4: {} - semver@7.8.0: {} send@0.19.2: @@ -16694,41 +15722,20 @@ snapshots: querystringify: 2.2.0 requires-port: 1.0.0 - use-callback-ref@1.3.3(@types/react@19.2.14)(react@19.2.5): - dependencies: - react: 19.2.5 - tslib: 2.8.1 - optionalDependencies: - '@types/react': 19.2.14 - use-callback-ref@1.3.3(@types/react@19.2.14)(react@19.2.6): dependencies: react: 19.2.6 tslib: 2.8.1 optionalDependencies: '@types/react': 19.2.14 - optional: true - - use-latest-callback@0.2.6(react@19.2.5): - dependencies: - react: 19.2.5 use-latest-callback@0.2.6(react@19.2.6): dependencies: react: 19.2.6 - optional: true - use-latest-callback@0.3.3(react@19.2.5): + use-latest-callback@0.3.3(react@19.2.6): dependencies: - react: 19.2.5 - - use-sidecar@1.1.3(@types/react@19.2.14)(react@19.2.5): - dependencies: - detect-node-es: 1.1.0 - react: 19.2.5 - tslib: 2.8.1 - optionalDependencies: - '@types/react': 19.2.14 + react: 19.2.6 use-sidecar@1.1.3(@types/react@19.2.14)(react@19.2.6): dependencies: @@ -16737,16 +15744,10 @@ snapshots: tslib: 2.8.1 optionalDependencies: '@types/react': 19.2.14 - optional: true - - use-sync-external-store@1.6.0(react@19.2.5): - dependencies: - react: 19.2.5 use-sync-external-store@1.6.0(react@19.2.6): dependencies: react: 19.2.6 - optional: true utils-merge@1.0.1: {} @@ -16766,15 +15767,6 @@ snapshots: vary@1.1.2: {} - vaul@1.1.2(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.5))(react@19.2.5): - dependencies: - '@radix-ui/react-dialog': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.5))(react@19.2.5) - react: 19.2.5 - react-dom: 19.2.6(react@19.2.5) - transitivePeerDependencies: - - '@types/react' - - '@types/react-dom' - vaul@1.1.2(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6): dependencies: '@radix-ui/react-dialog': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) @@ -16783,7 +15775,6 @@ snapshots: transitivePeerDependencies: - '@types/react' - '@types/react-dom' - optional: true vite-node@3.2.4(@types/node@25.6.2)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4): dependencies: @@ -16827,7 +15818,7 @@ snapshots: dependencies: lightningcss: 1.32.0 picomatch: 4.0.4 - postcss: 8.5.13 + postcss: 8.5.14 rolldown: 1.0.0-rc.17 tinyglobby: 0.2.16 optionalDependencies: From e23751f29e36273fff1952550b706f1ac55f17ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Sun, 10 May 2026 13:03:52 +0200 Subject: [PATCH 008/319] Fix concurrent preview deploy race: per-PR env files + server flock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three changes: 1. Skip GH-Actions-only Dependabot PRs (dependabot/github_actions/*) in deploy-preview — there is no app image to preview, and these PRs were landing phantom containers with mismatched ports. 2. Use per-PR env files (staging-pr-{N}.env) instead of the shared staging.env for preview deploys and teardowns. Concurrent SCP transfers to the same filename were overwriting each other, causing wrong JOURNAL_HOST_PORT / JOURNAL_IMAGE_TAG values to be used. 3. Serialize server-side deploy operations with a flock on /tmp/trails-preview-deploy.lock (300s timeout). Eviction + compose up must be atomic; without the lock, two simultaneous jobs could both see "3 active previews" and both evict different projects, or one could start compose up against a just-evicted env. Triggered by a Dependabot batch today (PRs 371-373) that opened simultaneously and produced a phantom trails-pr-371 container running the pr-370 image on port 3940 while the Caddyfile expected 3942, causing sustained 502s on pr-371.staging.trails.cool. Co-Authored-By: Claude Sonnet 4.6 --- .github/workflows/cd-staging.yml | 52 +++++++++++++++++---------- .github/workflows/staging-cleanup.yml | 2 +- 2 files changed, 35 insertions(+), 19 deletions(-) diff --git a/.github/workflows/cd-staging.yml b/.github/workflows/cd-staging.yml index 8956ab9..ec5091a 100644 --- a/.github/workflows/cd-staging.yml +++ b/.github/workflows/cd-staging.yml @@ -177,7 +177,11 @@ jobs: # ── PR preview deploy ──────────────────────────────────────────────── deploy-preview: name: Deploy PR Preview - if: github.event_name == 'pull_request' && github.event.action != 'closed' + # Skip GH-Actions-only Dependabot PRs — there is no app image to preview. + if: > + github.event_name == 'pull_request' && + github.event.action != 'closed' && + !startsWith(github.head_ref, 'dependabot/github_actions/') needs: [build-images] runs-on: ubuntu-latest environment: production @@ -204,7 +208,8 @@ jobs: run: | curl -sLO https://github.com/getsops/sops/releases/download/v3.9.4/sops-v3.9.4.linux.amd64 chmod +x sops-v3.9.4.linux.amd64 - SOPS_AGE_KEY="${{ secrets.AGE_SECRET_KEY }}" ./sops-v3.9.4.linux.amd64 -d infrastructure/secrets.app.env > infrastructure/staging.env + # Use a per-PR filename so concurrent SCP transfers don't overwrite each other. + SOPS_AGE_KEY="${{ secrets.AGE_SECRET_KEY }}" ./sops-v3.9.4.linux.amd64 -d infrastructure/secrets.app.env > infrastructure/staging-pr-${{ steps.ports.outputs.pr }}.env { echo "DOMAIN=${{ steps.ports.outputs.host }}" echo "STAGING_DATABASE=${{ steps.ports.outputs.database }}" @@ -215,7 +220,7 @@ jobs: # PR-preview journals all share the persistent staging planner. echo "PLANNER_URL=https://planner.staging.trails.cool" echo "SENTRY_RELEASE=${{ github.event.pull_request.head.sha }}" - } >> infrastructure/staging.env + } >> infrastructure/staging-pr-${{ steps.ports.outputs.pr }}.env - name: Generate per-PR Caddyfile snippet run: | @@ -242,7 +247,7 @@ jobs: host: ${{ secrets.DEPLOY_HOST }} username: root key: ${{ secrets.DEPLOY_SSH_KEY }} - source: "infrastructure/docker-compose.staging.yml,infrastructure/staging.env,infrastructure/sites/pr-${{ steps.ports.outputs.pr }}.caddyfile" + source: "infrastructure/docker-compose.staging.yml,infrastructure/staging-pr-${{ steps.ports.outputs.pr }}.env,infrastructure/sites/pr-${{ steps.ports.outputs.pr }}.caddyfile" target: /opt/trails-cool strip_components: 1 @@ -252,18 +257,25 @@ jobs: PR: ${{ steps.ports.outputs.pr }} PROJECT: ${{ steps.ports.outputs.project }} DB: ${{ steps.ports.outputs.database }} + JOURNAL_PORT: ${{ steps.ports.outputs.journal_port }} with: host: ${{ secrets.DEPLOY_HOST }} username: root key: ${{ secrets.DEPLOY_SSH_KEY }} - envs: PR,PROJECT,DB + envs: PR,PROJECT,DB,JOURNAL_PORT script: | set -euo pipefail cd /opt/trails-cool + ENV_FILE="staging-pr-${PR}.env" - GHCR_TOKEN=$(grep DEPLOY_GHCR_TOKEN staging.env | cut -d= -f2-) + GHCR_TOKEN=$(grep DEPLOY_GHCR_TOKEN "$ENV_FILE" | cut -d= -f2-) echo "$GHCR_TOKEN" | docker login ghcr.io -u stigi --password-stdin + # Serialize all preview deploys with a server-side lock so concurrent + # CI jobs (e.g. a Dependabot batch) can't race on eviction or compose state. + exec 9>/tmp/trails-preview-deploy.lock + flock --timeout 300 9 || { echo "Timed out waiting for deploy lock after 300s"; exit 1; } + # Same network bootstrap as deploy-staging — see comment there. docker network inspect trails-shared >/dev/null 2>&1 || docker network create trails-shared PG_CONTAINER=$(docker ps --filter "name=trails-cool-postgres" --format '{{.Names}}' | head -1) @@ -286,9 +298,12 @@ jobs: if [ -n "$OLDEST" ] && [ "$OLDEST" != "$PROJECT" ]; then echo "At cap; evicting oldest preview: $OLDEST" OLD_PR=${OLDEST#trails-pr-} - docker compose -f docker-compose.staging.yml -p "$OLDEST" --env-file staging.env down --remove-orphans || true + OLD_ENV="staging-pr-${OLD_PR}.env" + # Fall back to base secrets if the per-PR env was already cleaned up. + EVICT_ENV=$( [ -f "$OLD_ENV" ] && echo "$OLD_ENV" || echo "staging.env" ) + docker compose -f docker-compose.staging.yml -p "$OLDEST" --env-file "$EVICT_ENV" down --remove-orphans || true docker compose exec -T postgres dropdb -U trails --if-exists "trails_pr_$OLD_PR" || true - rm -f "sites/pr-$OLD_PR.caddyfile" + rm -f "sites/pr-$OLD_PR.caddyfile" "$OLD_ENV" fi fi fi @@ -303,14 +318,14 @@ jobs: "CREATE EXTENSION IF NOT EXISTS postgis" # Pull, migrate, deploy (journal-only — no --profile means planner skipped) - docker compose -f docker-compose.staging.yml -p "$PROJECT" --env-file staging.env pull journal - docker compose -f docker-compose.staging.yml -p "$PROJECT" --env-file staging.env run --rm journal npx drizzle-kit push --config /app/packages/db/drizzle.config.ts --force - docker compose -f docker-compose.staging.yml -p "$PROJECT" --env-file staging.env up -d --remove-orphans journal + docker compose -f docker-compose.staging.yml -p "$PROJECT" --env-file "$ENV_FILE" pull journal + docker compose -f docker-compose.staging.yml -p "$PROJECT" --env-file "$ENV_FILE" run --rm journal npx drizzle-kit push --config /app/packages/db/drizzle.config.ts --force + docker compose -f docker-compose.staging.yml -p "$PROJECT" --env-file "$ENV_FILE" up -d --remove-orphans journal # Reload Caddy to pick up the per-PR snippet (writes/replaces it from the SCP step) docker compose exec -T caddy caddy reload --config /etc/caddy/Caddyfile - docker compose -f docker-compose.staging.yml -p "$PROJECT" --env-file staging.env ps + docker compose -f docker-compose.staging.yml -p "$PROJECT" --env-file "$ENV_FILE" ps # Find any prior preview comment so we can update it in place rather # than spamming a new one each push. The marker line at the bottom of @@ -364,13 +379,13 @@ jobs: run: | curl -sLO https://github.com/getsops/sops/releases/download/v3.9.4/sops-v3.9.4.linux.amd64 chmod +x sops-v3.9.4.linux.amd64 - SOPS_AGE_KEY="${{ secrets.AGE_SECRET_KEY }}" ./sops-v3.9.4.linux.amd64 -d infrastructure/secrets.app.env > infrastructure/staging.env + SOPS_AGE_KEY="${{ secrets.AGE_SECRET_KEY }}" ./sops-v3.9.4.linux.amd64 -d infrastructure/secrets.app.env > infrastructure/staging-pr-${{ steps.ports.outputs.pr }}.env { echo "DOMAIN=pr-${{ steps.ports.outputs.pr }}.staging.trails.cool" echo "STAGING_DATABASE=${{ steps.ports.outputs.database }}" echo "JOURNAL_HOST_PORT=$((3200 + 2 * ${{ steps.ports.outputs.pr }}))" echo "PLANNER_HOST_PORT=$((3201 + 2 * ${{ steps.ports.outputs.pr }}))" - } >> infrastructure/staging.env + } >> infrastructure/staging-pr-${{ steps.ports.outputs.pr }}.env - name: Copy compose + env (teardown still needs the file) uses: appleboy/scp-action@v1 @@ -378,7 +393,7 @@ jobs: host: ${{ secrets.DEPLOY_HOST }} username: root key: ${{ secrets.DEPLOY_SSH_KEY }} - source: "infrastructure/docker-compose.staging.yml,infrastructure/staging.env" + source: "infrastructure/docker-compose.staging.yml,infrastructure/staging-pr-${{ steps.ports.outputs.pr }}.env" target: /opt/trails-cool strip_components: 1 @@ -396,15 +411,16 @@ jobs: script: | set -euo pipefail cd /opt/trails-cool + ENV_FILE="staging-pr-${PR}.env" # Stop and remove containers + volumes for this PR - docker compose -f docker-compose.staging.yml -p "$PROJECT" --env-file staging.env down --remove-orphans || true + docker compose -f docker-compose.staging.yml -p "$PROJECT" --env-file "$ENV_FILE" down --remove-orphans || true # Drop the per-PR database (idempotent) docker compose exec -T postgres dropdb -U trails --if-exists "$DB" || true - # Remove the per-PR Caddy snippet and reload - rm -f "sites/pr-$PR.caddyfile" + # Remove the per-PR Caddy snippet, env file, and reload + rm -f "sites/pr-$PR.caddyfile" "$ENV_FILE" docker compose exec -T caddy caddy reload --config /etc/caddy/Caddyfile || true - name: Find existing preview comment diff --git a/.github/workflows/staging-cleanup.yml b/.github/workflows/staging-cleanup.yml index 595888f..bed2fd4 100644 --- a/.github/workflows/staging-cleanup.yml +++ b/.github/workflows/staging-cleanup.yml @@ -106,7 +106,7 @@ jobs: EOF docker compose -f docker-compose.staging.yml -p "$PROJECT" --env-file /tmp/cleanup.env down --remove-orphans || true docker compose exec -T postgres dropdb -U trails --if-exists "$DB" || true - rm -f "sites/pr-$PR.caddyfile" + rm -f "sites/pr-$PR.caddyfile" "staging-pr-${PR}.env" done rm -f /tmp/cleanup.env docker compose exec -T caddy caddy reload --config /etc/caddy/Caddyfile || true From 9c5cd7d6e858f1fbb50bde0b74f5dfd14f1973ef Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 10 May 2026 11:09:33 +0000 Subject: [PATCH 009/319] Bump fit-file-parser in the development group across 1 directory Bumps the development group with 1 update in the / directory: [fit-file-parser](https://github.com/jimmykane/fit-parser). Updates `fit-file-parser` from 2.3.3 to 3.0.0 - [Changelog](https://github.com/jimmykane/fit-parser/blob/master/CHANGELOG.md) - [Commits](https://github.com/jimmykane/fit-parser/commits) --- updated-dependencies: - dependency-name: fit-file-parser dependency-version: 3.0.0 dependency-type: direct:development update-type: version-update:semver-major dependency-group: development ... Signed-off-by: dependabot[bot] --- package.json | 2 +- packages/fit/package.json | 2 +- pnpm-lock.yaml | 14 +++++++------- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index fc4a937..7aa7e97 100644 --- a/package.json +++ b/package.json @@ -61,7 +61,7 @@ "drizzle-postgis": "catalog:", "eslint": "^10.3.0", "eslint-config-prettier": "^10.1.8", - "fit-file-parser": "^2.3.3", + "fit-file-parser": "^3.0.0", "i18next": "^26.0.10", "i18next-browser-languagedetector": "^8.2.1", "jsdom": "^29.1.1", diff --git a/packages/fit/package.json b/packages/fit/package.json index 1e90ad3..ac35e32 100644 --- a/packages/fit/package.json +++ b/packages/fit/package.json @@ -18,6 +18,6 @@ }, "devDependencies": { "@types/node": "catalog:", - "fit-file-parser": "^2.3.3" + "fit-file-parser": "^3.0.0" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3319a24..c34b487 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -141,8 +141,8 @@ importers: specifier: ^10.1.8 version: 10.1.8(eslint@10.3.0(jiti@2.7.0)) fit-file-parser: - specifier: ^2.3.3 - version: 2.3.3 + specifier: ^3.0.0 + version: 3.0.0 i18next: specifier: ^26.0.10 version: 26.0.10(typescript@5.9.3) @@ -614,8 +614,8 @@ importers: specifier: 'catalog:' version: 22.19.18 fit-file-parser: - specifier: ^2.3.3 - version: 2.3.3 + specifier: ^3.0.0 + version: 3.0.0 packages/gpx: dependencies: @@ -5260,8 +5260,8 @@ packages: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} engines: {node: '>=10'} - fit-file-parser@2.3.3: - resolution: {integrity: sha512-TZPFfjkEev5TTd9RnZ4xn4k5ZSx2VZiKNjoZsHIkmQDK0S0XA7ebfdMLj76BK7kStsHh5WbK8Fmn/w85jgd0dA==} + fit-file-parser@3.0.0: + resolution: {integrity: sha512-Sf0erVcqT1TAQ3qbrg5b5Uyr8OVV0HDgxKRNuXEC0R7HeAGwz0dRTEHqpmKEluI4q+9ummnJnSDFx0gFg7yMPA==} flat-cache@4.0.1: resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} @@ -13066,7 +13066,7 @@ snapshots: locate-path: 6.0.0 path-exists: 4.0.0 - fit-file-parser@2.3.3: + fit-file-parser@3.0.0: dependencies: buffer: 6.0.3 From 8f635fd5d1c7221fffcfe234cb2cbee704af4e2b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 10 May 2026 11:11:45 +0000 Subject: [PATCH 010/319] Bump peter-evans/create-or-update-comment from 4 to 5 Bumps [peter-evans/create-or-update-comment](https://github.com/peter-evans/create-or-update-comment) from 4 to 5. - [Release notes](https://github.com/peter-evans/create-or-update-comment/releases) - [Commits](https://github.com/peter-evans/create-or-update-comment/compare/v4...v5) --- updated-dependencies: - dependency-name: peter-evans/create-or-update-comment dependency-version: '5' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/cd-staging.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/cd-staging.yml b/.github/workflows/cd-staging.yml index ec5091a..3fe1ac1 100644 --- a/.github/workflows/cd-staging.yml +++ b/.github/workflows/cd-staging.yml @@ -339,7 +339,7 @@ jobs: body-includes: "" - name: Upsert preview comment on PR - uses: peter-evans/create-or-update-comment@v4 + uses: peter-evans/create-or-update-comment@v5 with: comment-id: ${{ steps.find-comment.outputs.comment-id }} issue-number: ${{ github.event.number }} @@ -433,7 +433,7 @@ jobs: - name: Update preview comment on close if: steps.find-comment.outputs.comment-id - uses: peter-evans/create-or-update-comment@v4 + uses: peter-evans/create-or-update-comment@v5 with: comment-id: ${{ steps.find-comment.outputs.comment-id }} edit-mode: replace From 0e8978452a163583d4235ab342c4d6a656ac3b6b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 10 May 2026 11:11:47 +0000 Subject: [PATCH 011/319] Bump peter-evans/find-comment from 3 to 4 Bumps [peter-evans/find-comment](https://github.com/peter-evans/find-comment) from 3 to 4. - [Release notes](https://github.com/peter-evans/find-comment/releases) - [Commits](https://github.com/peter-evans/find-comment/compare/v3...v4) --- updated-dependencies: - dependency-name: peter-evans/find-comment dependency-version: '4' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/cd-staging.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/cd-staging.yml b/.github/workflows/cd-staging.yml index ec5091a..adb890d 100644 --- a/.github/workflows/cd-staging.yml +++ b/.github/workflows/cd-staging.yml @@ -331,7 +331,7 @@ jobs: # than spamming a new one each push. The marker line at the bottom of # the body is what `body-includes` matches on. - name: Find existing preview comment - uses: peter-evans/find-comment@v3 + uses: peter-evans/find-comment@v4 id: find-comment with: issue-number: ${{ github.event.number }} @@ -424,7 +424,7 @@ jobs: docker compose exec -T caddy caddy reload --config /etc/caddy/Caddyfile || true - name: Find existing preview comment - uses: peter-evans/find-comment@v3 + uses: peter-evans/find-comment@v4 id: find-comment with: issue-number: ${{ github.event.number }} From 78b8b8f55f629bea7d1f308b49f2f1f23003a0b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Sun, 10 May 2026 15:02:56 +0200 Subject: [PATCH 012/319] Atomic GPX save: validate + persist row + geometry in one transaction Eliminates the silent-failure pattern where a route/activity row could be committed with gpx IS NOT NULL but geom IS NULL if the PostGIS write failed after the row insert. - New gpx-save.server.ts owns all GPX validation (GpxValidationError, validateGpx) and PostGIS geometry writes (writeGeom, tx-aware) - createRoute, updateRoute, createActivity, createRouteFromActivity all wrapped in db.transaction() covering row + geom + version snapshot - demo-bot uses createRoute/createActivity instead of raw inserts; errors propagate loudly - Callback endpoint returns 400 for GpxValidationError instead of 401 - ADR-0006 documents the invariant for future explorers Co-Authored-By: Claude Sonnet 4.6 --- CONTEXT.md | 18 ++ apps/journal/app/lib/activities.server.ts | 97 ++++----- apps/journal/app/lib/demo-bot.server.ts | 60 ++---- apps/journal/app/lib/gpx-save.server.test.ts | 86 ++++++++ apps/journal/app/lib/gpx-save.server.ts | 66 ++++++ apps/journal/app/lib/routes.server.ts | 190 +++++++++--------- .../app/routes/api.routes.$id.callback.ts | 4 + docs/adr/0006-atomic-gpx-save.md | 28 +++ .../changes/atomic-gpx-save/.openspec.yaml | 2 + openspec/changes/atomic-gpx-save/design.md | 101 ++++++++++ openspec/changes/atomic-gpx-save/proposal.md | 32 +++ .../atomic-gpx-save/specs/gpx-save/spec.md | 83 ++++++++ openspec/changes/atomic-gpx-save/tasks.md | 39 ++++ 13 files changed, 624 insertions(+), 182 deletions(-) create mode 100644 apps/journal/app/lib/gpx-save.server.test.ts create mode 100644 apps/journal/app/lib/gpx-save.server.ts create mode 100644 docs/adr/0006-atomic-gpx-save.md create mode 100644 openspec/changes/atomic-gpx-save/.openspec.yaml create mode 100644 openspec/changes/atomic-gpx-save/design.md create mode 100644 openspec/changes/atomic-gpx-save/proposal.md create mode 100644 openspec/changes/atomic-gpx-save/specs/gpx-save/spec.md create mode 100644 openspec/changes/atomic-gpx-save/tasks.md diff --git a/CONTEXT.md b/CONTEXT.md index 007ea13..e48200e 100644 --- a/CONTEXT.md +++ b/CONTEXT.md @@ -9,6 +9,24 @@ first. If the term you need isn't here, propose it (don't invent a synonym). --- +## GPX Save + +The atomic unit of persisting spatial data in the Journal. Any write of a GPX track — whether a new route, an updated route, a new activity, or a route derived from an activity — goes through a single path that validates, writes the row, and writes the PostGIS geometry in one transaction. + +### gpx-save module +`apps/journal/app/lib/gpx-save.server.ts`. The sole owner of GPX validation and geometry persistence. Imported by `routes.server.ts`, `activities.server.ts`, and `demo-bot.server.ts`. Nothing else calls `setGeomFromGpx` directly. + +### GpxValidationError +Typed error thrown by `validateGpx` when the GPX string cannot produce a valid LineString. Conditions: fewer than 2 track points, or coordinates outside valid ranges (lat −90..90, lon −180..180). Callers catch this to return a user-facing 400. + +### validateGpx +`(gpx: string) → Promise`. Entry point of the gpx-save module. Parses the GPX string once and validates the result. Returns the `ParsedGpx` so callers can extract stats without re-parsing. Throws `GpxValidationError` on invalid input. Called at the start of `createRoute`, `updateRoute`, `createActivity`, and `createRouteFromActivity` — before any DB write. + +### atomic GPX save +The invariant: a route or activity row with a `gpx` column set **always** has a corresponding `geom` column set. Enforced by wrapping the row insert/update, the PostGIS geometry write, and the version snapshot in a single `db.transaction()`. A PostGIS failure rolls back the row write; partial state (row exists, geom NULL) is not possible through the normal save path. + +--- + ## Connected Services The user-facing surface for linking external accounts and devices to a Journal diff --git a/apps/journal/app/lib/activities.server.ts b/apps/journal/app/lib/activities.server.ts index 0dfd7f2..d41d6f2 100644 --- a/apps/journal/app/lib/activities.server.ts +++ b/apps/journal/app/lib/activities.server.ts @@ -3,8 +3,8 @@ import { eq, desc, and, sql } from "drizzle-orm"; import { getDb } from "./db.ts"; import { activities, routes, syncImports, users, follows } 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"; +import { validateGpx, writeGeom } from "./gpx-save.server.ts"; +import type { GpxData } from "./gpx-save.server.ts"; export interface ActivityInput { name: string; @@ -15,6 +15,7 @@ export interface ActivityInput { duration?: number | null; startedAt?: Date | null; visibility?: Visibility; + synthetic?: boolean; } export async function updateActivityVisibility( @@ -46,44 +47,45 @@ export async function createActivity(ownerId: string, input: ActivityInput) { const db = getDb(); const id = randomUUID(); + let parsed: GpxData | null = null; let distance: number | null = input.distance ?? null; let elevationGain: number | null = null; let elevationLoss: number | null = null; let startedAt: Date | null = input.startedAt ?? null; const duration: number | null = input.duration ?? null; - if (input.gpx) { - try { - const gpxData = await parseGpxAsync(input.gpx); - distance = gpxData.distance || distance; - elevationGain = gpxData.elevation.gain; - elevationLoss = gpxData.elevation.loss; - if (!startedAt && gpxData.tracks[0]?.[0]?.time) { - startedAt = new Date(gpxData.tracks[0][0].time); - } - } catch { - // Continue without stats if GPX parsing fails + if (input.gpx) { + parsed = await validateGpx(input.gpx); + distance = parsed.distance || distance; + elevationGain = parsed.elevation.gain; + elevationLoss = parsed.elevation.loss; + if (!startedAt && parsed.tracks[0]?.[0]?.time) { + startedAt = new Date(parsed.tracks[0][0].time); } } - await db.insert(activities).values({ - id, - ownerId, - routeId: input.routeId ?? null, - name: input.name, - description: input.description ?? "", - gpx: input.gpx, - distance, - duration, - elevationGain, - elevationLoss, - startedAt, - ...(input.visibility ? { visibility: input.visibility } : {}), - }); + await db.transaction(async (tx) => { + await tx.insert(activities).values({ + id, + ownerId, + routeId: input.routeId ?? null, + name: input.name, + description: input.description ?? "", + gpx: input.gpx, + distance, + duration, + elevationGain, + elevationLoss, + startedAt, + ...(input.visibility ? { visibility: input.visibility } : {}), + ...(input.synthetic ? { synthetic: true } : {}), + }); - if (input.gpx) { - await setGeomFromGpx(id, "activities", input.gpx); - } + if (input.gpx && parsed) { + const coords = parsed.tracks.flat().map((p) => [p.lon, p.lat] as [number, number]); + await writeGeom(tx, id, "activities", coords); + } + }); // Public activities at creation also fan out (matches the // updateActivityVisibility path for the case where visibility is set @@ -236,26 +238,27 @@ export async function createRouteFromActivity(activityId: string, ownerId: strin const [activity] = await db.select().from(activities).where(eq(activities.id, activityId)); if (!activity?.gpx) return null; + const parsed = await validateGpx(activity.gpx); + const coords = parsed.tracks.flat().map((p) => [p.lon, p.lat] as [number, number]); const routeId = randomUUID(); - await db.insert(routes).values({ - id: routeId, - ownerId, - name: `Route from: ${activity.name}`, - description: `Created from activity "${activity.name}"`, - gpx: activity.gpx, - distance: activity.distance, - elevationGain: activity.elevationGain, - elevationLoss: activity.elevationLoss, + + await db.transaction(async (tx) => { + await tx.insert(routes).values({ + id: routeId, + ownerId, + name: `Route from: ${activity.name}`, + description: `Created from activity "${activity.name}"`, + gpx: activity.gpx, + distance: activity.distance, + elevationGain: activity.elevationGain, + elevationLoss: activity.elevationLoss, + }); + + await writeGeom(tx, routeId, "routes", coords); + + await tx.update(activities).set({ routeId }).where(eq(activities.id, activityId)); }); - await setGeomFromGpx(routeId, "routes", activity.gpx); - - // Link the activity to the new route - await db - .update(activities) - .set({ routeId }) - .where(eq(activities.id, activityId)); - return routeId; } diff --git a/apps/journal/app/lib/demo-bot.server.ts b/apps/journal/app/lib/demo-bot.server.ts index e2d3d0e..8ee5fd5 100644 --- a/apps/journal/app/lib/demo-bot.server.ts +++ b/apps/journal/app/lib/demo-bot.server.ts @@ -4,9 +4,10 @@ import { z } from "zod"; import { and, eq, lt, sql } from "drizzle-orm"; import { getDb } from "./db.ts"; import { activities, routes, users } from "@trails-cool/db/schema/journal"; -import { setGeomFromGpx } from "./routes.server.ts"; +import { createRoute } from "./routes.server.ts"; +import { createActivity } from "./activities.server.ts"; +import { validateGpx } from "./gpx-save.server.ts"; import { TERMS_VERSION } from "./legal.ts"; -import { parseGpxAsync } from "@trails-cool/gpx"; import { logger } from "./logger.server.ts"; import { demoBotSyntheticActivitiesTotal, @@ -648,59 +649,40 @@ export async function generateOneWalk( const name = templateName(now, locale, persona); const description = templateDescription(now, locale, persona); - let distance: number; - let elevationGain: number; - let elevationLoss: number; - try { - const parsed = await parseGpxAsync(result.gpx); - distance = parsed.distance; - elevationGain = parsed.elevation.gain; - elevationLoss = parsed.elevation.loss; - } catch { - return null; - } + const parsed = await validateGpx(result.gpx); + const distance = parsed.distance; + const elevationGain = parsed.elevation.gain; + const elevationLoss = parsed.elevation.loss; if (!distance || distance < 500) return null; - const db = getDb(); - const routeId = randomUUID(); - const activityId = randomUUID(); - - await db.insert(routes).values({ - id: routeId, - ownerId, - name, - description, - gpx: result.gpx, - routingProfile: "trekking", - distance, - elevationGain, - elevationLoss, - visibility: "public", - synthetic: true, - }); - await setGeomFromGpx(routeId, "routes", result.gpx); - const walkingMetersPerSecond = 4.5 * 1000 / 3600; // ~4.5 km/h const jitter = 0.85 + Math.random() * 0.3; // ±15 % const durationSeconds = Math.round((distance / walkingMetersPerSecond) * jitter); - await db.insert(activities).values({ - id: activityId, - ownerId, - routeId, + const routeId = await createRoute(ownerId, { name, description, gpx: result.gpx, - startedAt: now, - duration: durationSeconds, + routingProfile: "trekking", + visibility: "public", + synthetic: true, distance, elevationGain, elevationLoss, + }); + + await createActivity(ownerId, { + name, + description, + gpx: result.gpx, + routeId, + startedAt: now, + duration: durationSeconds, + distance, visibility: "public", synthetic: true, }); - await setGeomFromGpx(activityId, "activities", result.gpx); return routeId; } diff --git a/apps/journal/app/lib/gpx-save.server.test.ts b/apps/journal/app/lib/gpx-save.server.test.ts new file mode 100644 index 0000000..b1455c2 --- /dev/null +++ b/apps/journal/app/lib/gpx-save.server.test.ts @@ -0,0 +1,86 @@ +import { describe, it, expect } from "vitest"; +import { validateGpx, GpxValidationError } from "./gpx-save.server.ts"; + +const VALID_GPX = ` + + + + 500 + 520 + 510 + + +`; + +const ONE_POINT_GPX = ` + + + + 500 + + +`; + +const EMPTY_GPX = ` + + +`; + +const OUT_OF_RANGE_LAT_GPX = ` + + + + + + + +`; + +const OUT_OF_RANGE_LON_GPX = ` + + + + + + + +`; + +describe("validateGpx", () => { + it("returns parsed GpxData for valid GPX", async () => { + const result = await validateGpx(VALID_GPX); + expect(result.tracks.flat().length).toBe(3); + expect(result.tracks[0]![0]!.lat).toBeCloseTo(47.0); + }); + + it("throws GpxValidationError for GPX with fewer than 2 track points", async () => { + await expect(validateGpx(ONE_POINT_GPX)).rejects.toThrow(GpxValidationError); + await expect(validateGpx(ONE_POINT_GPX)).rejects.toThrow("at least 2 track points"); + }); + + it("throws GpxValidationError for GPX with zero track points", async () => { + await expect(validateGpx(EMPTY_GPX)).rejects.toThrow(GpxValidationError); + await expect(validateGpx(EMPTY_GPX)).rejects.toThrow("at least 2 track points"); + }); + + it("throws GpxValidationError for out-of-range latitude", async () => { + await expect(validateGpx(OUT_OF_RANGE_LAT_GPX)).rejects.toThrow(GpxValidationError); + await expect(validateGpx(OUT_OF_RANGE_LAT_GPX)).rejects.toThrow("out-of-range coordinates"); + }); + + it("throws GpxValidationError for out-of-range longitude", async () => { + await expect(validateGpx(OUT_OF_RANGE_LON_GPX)).rejects.toThrow(GpxValidationError); + await expect(validateGpx(OUT_OF_RANGE_LON_GPX)).rejects.toThrow("out-of-range coordinates"); + }); + + it("throws GpxValidationError for unparseable XML", async () => { + await expect(validateGpx("not xml at all")).rejects.toThrow(GpxValidationError); + await expect(validateGpx(" { + const err = await validateGpx(EMPTY_GPX).catch((e) => e); + expect(err).toBeInstanceOf(GpxValidationError); + expect(err.name).toBe("GpxValidationError"); + }); +}); diff --git a/apps/journal/app/lib/gpx-save.server.ts b/apps/journal/app/lib/gpx-save.server.ts new file mode 100644 index 0000000..b1411e9 --- /dev/null +++ b/apps/journal/app/lib/gpx-save.server.ts @@ -0,0 +1,66 @@ +import { sql } from "drizzle-orm"; +import type { Database } from "@trails-cool/db"; +import { parseGpxAsync } from "@trails-cool/gpx"; +import type { GpxData } from "@trails-cool/gpx"; + +// Re-export so callers only need one import. +export type { GpxData }; + +export class GpxValidationError extends Error { + constructor(message: string) { + super(message); + this.name = "GpxValidationError"; + } +} + +/** + * Parse and validate a GPX string. Returns the parsed data so callers + * don't need to parse again for stat extraction. Throws GpxValidationError + * when the GPX is malformed, has fewer than 2 track points, or contains + * out-of-range coordinates. + */ +export async function validateGpx(gpx: string): Promise { + let parsed: GpxData; + try { + parsed = await parseGpxAsync(gpx); + } catch (e) { + throw new GpxValidationError(`GPX parse failed: ${(e as Error).message}`); + } + + const points = parsed.tracks.flat(); + if (points.length < 2) { + throw new GpxValidationError( + `GPX must contain at least 2 track points (got ${points.length})`, + ); + } + + for (const p of points) { + if (p.lat < -90 || p.lat > 90 || p.lon < -180 || p.lon > 180) { + throw new GpxValidationError( + `GPX contains out-of-range coordinates: lat=${p.lat}, lon=${p.lon}`, + ); + } + } + + return parsed; +} + +type Tx = Parameters[0]>[0]; + +/** + * Write a PostGIS LineString geometry from already-validated track points. + * Must be called inside a db.transaction() — the tx client is required so + * the geometry write participates in the enclosing transaction. + * Throws on failure; callers must NOT swallow the error. + */ +export async function writeGeom( + tx: Tx, + id: string, + table: "routes" | "activities", + coords: Array<[number, number]>, +): Promise { + const geojson = JSON.stringify({ type: "LineString", coordinates: coords }); + await tx.execute( + sql`UPDATE ${sql.identifier("journal")}.${sql.identifier(table)} SET geom = ST_GeomFromGeoJSON(${geojson}) WHERE id = ${id}`, + ); +} diff --git a/apps/journal/app/lib/routes.server.ts b/apps/journal/app/lib/routes.server.ts index 1d6f13c..7c7d181 100644 --- a/apps/journal/app/lib/routes.server.ts +++ b/apps/journal/app/lib/routes.server.ts @@ -3,8 +3,9 @@ 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"; +import { validateGpx, writeGeom } from "./gpx-save.server.ts"; +import type { GpxData } from "./gpx-save.server.ts"; export interface RouteInput { name: string; @@ -12,52 +13,65 @@ export interface RouteInput { gpx?: string; routingProfile?: string; visibility?: Visibility; + // Pre-computed stats — when provided, skip re-parsing (used by demo-bot) + distance?: number | null; + elevationGain?: number | null; + elevationLoss?: number | null; + dayBreaks?: number[]; + synthetic?: boolean; } export async function createRoute(ownerId: string, input: RouteInput) { const db = getDb(); const id = randomUUID(); - let distance: number | null = null; - let elevationGain: number | null = null; - let elevationLoss: number | null = null; - let dayBreaks: number[] = []; + let parsed: GpxData | null = null; + let distance: number | null = input.distance ?? null; + let elevationGain: number | null = input.elevationGain ?? null; + let elevationLoss: number | null = input.elevationLoss ?? null; + let dayBreaks: number[] = input.dayBreaks ?? []; + if (input.gpx) { - const stats = await computeRouteStats(input.gpx); - distance = stats.distance; - elevationGain = stats.elevationGain; - elevationLoss = stats.elevationLoss; - dayBreaks = stats.dayBreaks; + parsed = await validateGpx(input.gpx); + // Only compute stats from GPX if not pre-supplied by caller + if (input.distance === undefined) { + const stats = computeRouteStats(parsed); + distance = stats.distance; + elevationGain = stats.elevationGain; + elevationLoss = stats.elevationLoss; + dayBreaks = stats.dayBreaks; + } } - await db.insert(routes).values({ - id, - ownerId, - name: input.name, - description: input.description ?? "", - gpx: input.gpx, - routingProfile: input.routingProfile, - distance, - elevationGain, - elevationLoss, - dayBreaks, - }); - - if (input.gpx) { - await setGeomFromGpx(id, "routes", input.gpx); - } - - // Create initial version if GPX provided - if (input.gpx) { - await db.insert(routeVersions).values({ - id: randomUUID(), - routeId: id, - version: 1, + await db.transaction(async (tx) => { + await tx.insert(routes).values({ + id, + ownerId, + name: input.name, + description: input.description ?? "", gpx: input.gpx, - createdBy: ownerId, - changeDescription: "Initial version", + routingProfile: input.routingProfile, + distance, + elevationGain, + elevationLoss, + dayBreaks, + ...(input.synthetic ? { synthetic: true } : {}), }); - } + + if (input.gpx && parsed) { + const coords = parsed.tracks.flat().map((p) => [p.lon, p.lat] as [number, number]); + await writeGeom(tx, id, "routes", coords); + + await tx.insert(routeVersions).values({ + id: randomUUID(), + routeId: id, + version: 1, + gpx: input.gpx, + createdBy: ownerId, + changeDescription: "Initial version", + }); + } + }); return id; } @@ -92,7 +106,6 @@ export async function listRoutes(ownerId: string) { .where(eq(routes.ownerId, ownerId)) .orderBy(desc(routes.updatedAt)); - // Batch-fetch simplified GeoJSON for list thumbnails 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 })); @@ -122,14 +135,19 @@ export async function updateRoute( ) { const db = getDb(); + let parsed: GpxData | null = null; + if (input.gpx) { + parsed = await validateGpx(input.gpx); + } + 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) { + if (input.gpx && parsed) { + const stats = computeRouteStats(parsed); updateData.gpx = input.gpx; - const stats = await computeRouteStats(input.gpx); updateData.distance = stats.distance; updateData.elevationGain = stats.elevationGain; updateData.elevationLoss = stats.elevationLoss; @@ -137,33 +155,35 @@ export async function updateRoute( if (stats.description && input.description === undefined) { updateData.description = stats.description; } - - // Get next version number - const existingVersions = await db - .select() - .from(routeVersions) - .where(eq(routeVersions.routeId, id)) - .orderBy(desc(routeVersions.version)); - - const nextVersion = (existingVersions[0]?.version ?? 0) + 1; - - await db.insert(routeVersions).values({ - id: randomUUID(), - routeId: id, - version: nextVersion, - gpx: input.gpx, - createdBy: ownerId, - }); } - await db - .update(routes) - .set(updateData) - .where(and(eq(routes.id, id), eq(routes.ownerId, ownerId))); + await db.transaction(async (tx) => { + await tx + .update(routes) + .set(updateData) + .where(and(eq(routes.id, id), eq(routes.ownerId, ownerId))); - if (input.gpx) { - await setGeomFromGpx(id, "routes", input.gpx); - } + if (input.gpx && parsed) { + const coords = parsed.tracks.flat().map((p) => [p.lon, p.lat] as [number, number]); + await writeGeom(tx, id, "routes", coords); + + const existingVersions = await tx + .select() + .from(routeVersions) + .where(eq(routeVersions.routeId, id)) + .orderBy(desc(routeVersions.version)); + + const nextVersion = (existingVersions[0]?.version ?? 0) + 1; + + await tx.insert(routeVersions).values({ + id: randomUUID(), + routeId: id, + version: nextVersion, + gpx: input.gpx, + createdBy: ownerId, + }); + } + }); } export async function deleteRoute(id: string, ownerId: string) { @@ -175,41 +195,19 @@ export async function deleteRoute(id: string, ownerId: string) { return result.length > 0; } -async function computeRouteStats(gpxString: string) { - try { - const gpxData = await parseGpxAsync(gpxString); - const dayBreaks = gpxData.waypoints - .map((w, i) => (w.isDayBreak ? i : -1)) - .filter((i) => i >= 0); - return { - distance: gpxData.distance, - elevationGain: gpxData.elevation.gain, - elevationLoss: gpxData.elevation.loss, - dayBreaks, - description: gpxData.description, - }; - } catch { - return { distance: null, elevationGain: null, elevationLoss: null, dayBreaks: [] as number[], description: undefined }; - } +function computeRouteStats(gpxData: GpxData) { + const dayBreaks = gpxData.waypoints + .map((w, i) => (w.isDayBreak ? i : -1)) + .filter((i) => i >= 0); + return { + distance: gpxData.distance, + elevationGain: gpxData.elevation.gain, + elevationLoss: gpxData.elevation.loss, + dayBreaks, + description: gpxData.description, + }; } -async function setGeomFromGpx(id: string, table: "routes" | "activities", gpxString: string) { - try { - const gpxData = await parseGpxAsync(gpxString); - const coords = gpxData.tracks.flat().map((p) => [p.lon, p.lat] as [number, number]); - if (coords.length < 2) return; - const geojson = JSON.stringify({ type: "LineString", coordinates: coords }); - const db = getDb(); - await db.execute( - sql`UPDATE ${sql.identifier("journal")}.${sql.identifier(table)} SET geom = ST_GeomFromGeoJSON(${geojson}) WHERE id = ${id}`, - ); - } catch (e) { - console.error(`Failed to set geom for ${table}/${id}:`, e); - } -} - -export { setGeomFromGpx }; - async function getGeojson(table: "routes" | "activities", id: string): Promise { try { const db = getDb(); diff --git a/apps/journal/app/routes/api.routes.$id.callback.ts b/apps/journal/app/routes/api.routes.$id.callback.ts index 58a94ce..2bc4f8c 100644 --- a/apps/journal/app/routes/api.routes.$id.callback.ts +++ b/apps/journal/app/routes/api.routes.$id.callback.ts @@ -2,6 +2,7 @@ import { data } from "react-router"; import type { Route } from "./+types/api.routes.$id.callback"; import { verifyRouteToken } from "~/lib/jwt.server"; import { updateRoute, getRoute } from "~/lib/routes.server"; +import { GpxValidationError } from "~/lib/gpx-save.server"; const PLANNER_ORIGIN = process.env.PLANNER_URL ?? "http://localhost:3001"; @@ -65,6 +66,9 @@ export async function action({ params, request }: Route.ActionArgs) { return data({ success: true, routeId: params.id }, { headers: corsHeaders() }); } catch (e) { + if (e instanceof GpxValidationError) { + return data({ error: e.message }, { status: 400, headers: corsHeaders() }); + } return data({ error: (e as Error).message }, { status: 401, headers: corsHeaders() }); } } diff --git a/docs/adr/0006-atomic-gpx-save.md b/docs/adr/0006-atomic-gpx-save.md new file mode 100644 index 0000000..422226b --- /dev/null +++ b/docs/adr/0006-atomic-gpx-save.md @@ -0,0 +1,28 @@ +# ADR-0006: Atomic GPX Save via gpx-save Module + +**Status:** Accepted +**Date:** 2026-05-10 + +## Context + +Routes and activities store GPX text in a `gpx` column and a derived PostGIS LineString in a `geom` column. Originally, the row insert and the `ST_GeomFromGeoJSON` update were separate statements issued outside any transaction. If the geometry write failed (e.g. PostGIS unavailable, malformed coordinates), the row would be committed with `geom IS NULL` and no error surfaced. This silent failure made the geom column unreliable and was invisible to callers. + +Additionally, GPX validation (parse, minimum track points, coordinate range check) was either absent or scattered across callers, with some paths swallowing parse errors and continuing without geometry. + +## Decision + +1. **Single module owns geometry persistence.** `apps/journal/app/lib/gpx-save.server.ts` is the sole place that validates GPX and writes PostGIS geometry. No other module issues raw `UPDATE … SET geom = …` statements. + +2. **`validateGpx(gpx) → Promise`** parses the GPX string, asserts ≥ 2 track points, and checks all coordinates are within valid ranges (lat −90..90, lon −180..180). It throws `GpxValidationError` on any failure. It returns the parsed result so callers don't re-parse for stat extraction. + +3. **`writeGeom(tx, id, table, coords)`** accepts a Drizzle transaction client and writes the PostGIS geometry inside that transaction. It throws on failure — no try/catch anywhere in the call chain. + +4. **Every save that includes GPX is wrapped in `db.transaction()`** covering: the row insert/update, the `writeGeom` call, and any version snapshot insert. A PostGIS failure rolls back the entire transaction — a row with `gpx IS NOT NULL` and `geom IS NULL` cannot be produced through the normal save path. + +5. **Fail loudly everywhere.** The demo-bot and all callers surface errors rather than swallowing them. The demo-bot uses `createRoute` / `createActivity` rather than raw inserts. + +## Consequences + +- `GpxValidationError` surfaces to API callers. The Planner callback endpoint (`api.routes.$id.callback.ts`) catches it and returns 400 so the Planner receives a typed error. +- The `synthetic` flag is threaded through `RouteInput` and `ActivityInput` so the demo-bot can mark rows without bypassing the shared save functions. +- Any future module that needs to persist geometry **must** go through `gpx-save.server.ts`. Do not re-introduce inline `UPDATE … SET geom = …` statements elsewhere. diff --git a/openspec/changes/atomic-gpx-save/.openspec.yaml b/openspec/changes/atomic-gpx-save/.openspec.yaml new file mode 100644 index 0000000..ac20efa --- /dev/null +++ b/openspec/changes/atomic-gpx-save/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-driven +created: 2026-05-10 diff --git a/openspec/changes/atomic-gpx-save/design.md b/openspec/changes/atomic-gpx-save/design.md new file mode 100644 index 0000000..bec26e4 --- /dev/null +++ b/openspec/changes/atomic-gpx-save/design.md @@ -0,0 +1,101 @@ +## Context + +Every write of a GPX track in the Journal follows a two-step pattern: insert/update the row, then call `setGeomFromGpx` to write the PostGIS `geom` column via a raw `UPDATE`. The two steps are not in a transaction. `setGeomFromGpx` wraps its error in a `console.error` and returns, leaving the row with `geom IS NULL`. This affects `createRoute`, `updateRoute`, `createActivity`, `createRouteFromActivity`, and `demo-bot.server.ts` (which bypasses the save functions entirely with raw inserts). + +`setGeomFromGpx` is currently exported from `routes.server.ts` and imported by `activities.server.ts` and `demo-bot.server.ts`, making it a de-facto shared utility that lives in the wrong module. + +## Goals / Non-Goals + +**Goals:** +- `geom IS NULL` on a row that has `gpx` set is impossible through the normal save path. +- GPX is validated (≥2 track points, valid coordinate ranges) before any DB write. +- All callers fail loudly on invalid or unpersistable GPX — no silent degradation. +- PostGIS write participates in the same `db.transaction()` as the row write and version snapshot. +- `setGeomFromGpx` is internal to the new `gpx-save.server.ts` module; no other file calls it. +- `demo-bot.server.ts` uses `createRoute` / `createActivity` and gets the invariant for free. + +**Non-Goals:** +- No API surface changes. +- No DB schema changes or migrations. +- No changes to the `@trails-cool/gpx` parser. +- No changes to how the Planner callback endpoint validates its authorization (JWT stays as-is); validation of the GPX payload is now handled inside `updateRoute`. +- No changes to `getGeojson` / `getSimplifiedGeojsonBatch` — read paths are out of scope. +- No fix for the O(N) `getSimplifiedGeojsonBatch` query pattern (separate concern). + +## Decisions + +### 1. New module: `gpx-save.server.ts` + +`setGeomFromGpx` belongs in neither `routes.server.ts` nor `activities.server.ts` — it is shared infrastructure. A dedicated `apps/journal/app/lib/gpx-save.server.ts` owns validation and geometry persistence. `routes.server.ts` and `activities.server.ts` both import from it. + +Exports: +- `validateGpx(gpx: string): Promise` — public +- `writeGeom(tx, id, table, coords): Promise` — internal (not exported) +- `GpxValidationError` — public (callers catch it to return 400) + +The existing `setGeomFromGpx` export from `routes.server.ts` is removed. Any file that currently imports it must migrate. + +### 2. Validation inside save functions, not at call sites + +`validateGpx` is called at the start of `createRoute`, `updateRoute`, `createActivity`, and `createRouteFromActivity` — before any transaction is opened. This means: + +- Every caller gets validation for free, including the mobile API (`api.v1.routes`) and the Planner callback. +- The callback endpoint does not need its own validation logic; it catches `GpxValidationError` and returns 400. +- Future callers can't bypass validation by accident. + +Alternative considered: validate only at the callback boundary. Rejected because it leaves mobile API and direct DB writes unprotected. + +### 3. `db.transaction()` wrapping row write + geom write + version snapshot + +Drizzle supports `db.transaction(async (tx) => { ... })`. The raw PostGIS `UPDATE` inside `writeGeom` receives `tx` as its first argument and executes within the same transaction. If `writeGeom` throws, Drizzle rolls back the entire transaction — the row insert is reversed. + +``` +db.transaction(async (tx) => { + // 1. validateGpx already ran (before tx opened) + await tx.insert(routes).values(...) // or update + await writeGeom(tx, id, "routes", coords) // throws → rollback + await tx.insert(routeVersions).values(...) +}) +``` + +The transaction is opened *after* `validateGpx` succeeds. This keeps the transaction as short as possible (no async GPX parsing inside a held transaction). + +### 4. `activities.server.ts` stat extraction uses `validateGpx` result + +Currently `createActivity` calls `parseGpxAsync` inline to extract `distance`, `elevationGain`, `elevationLoss`, `startedAt`. After this change, `validateGpx` returns the `ParsedGpx` object. `createActivity` uses that result directly — one parse, not two. + +The activity-specific fields (`startedAt` from `gpxData.tracks[0][0].time`) are still extracted by `createActivity`; `validateGpx` returns the full parsed object so callers have access to everything. + +### 5. `demo-bot.server.ts` migrates to `createRoute` / `createActivity` + +The demo-bot currently does: +```ts +await db.insert(routes).values({ ... distance, elevationGain, ... }) +await setGeomFromGpx(routeId, "routes", result.gpx) +await db.insert(activities).values({ ... }) +await setGeomFromGpx(activityId, "activities", result.gpx) +``` + +After migration it calls `createRoute` and `createActivity`, which own all of this. The demo-bot passes pre-computed stats via `RouteInput` / `ActivityInput` (already supported: the input types accept optional `distance`, `elevationGain`, etc.). `createRoute` will prefer input stats over re-parsed stats when provided, avoiding redundant parsing for the demo-bot's case where BRouter already computed them. + +Alternative considered: leave demo-bot as-is and just make `setGeomFromGpx` throw. Rejected because it keeps a second bypass path alive and requires demo-bot to handle its own transaction. + +### 6. ADR recorded + +ADR-0006 documents that PostGIS geometry writes are always transactional with row writes, so future code doesn't re-introduce the split pattern. + +## Risks / Trade-offs + +- **Transaction duration**: Opening a DB transaction and then doing a raw SQL UPDATE adds a short hold on the row. For typical GPX sizes this is negligible — `validateGpx` runs before the transaction opens, so the held time is just the two DB statements. +- **demo-bot stat re-computation**: `createRoute` will call `validateGpx` on GPX that the demo-bot already parsed. Minor redundancy; acceptable given demo-bot is not a hot path. +- **Existing NULL geom rows**: Rows already in production with `geom IS NULL` are not backfilled by this change. A separate data-repair script would be needed. Out of scope. +- **`GpxValidationError` surfaces to users**: Routes/activities that previously saved silently will now return errors. This is the intended behaviour (fail loudly), but any caller that didn't expect an exception from `updateRoute` must now handle `GpxValidationError`. All current call sites are audited in the tasks. + +## Migration Plan + +No DB migration required. The change is purely in application code. Deploy is a standard app rollout — no staged migration, no feature flag. + +Existing rows with `geom IS NULL` remain as-is (pre-existing data debt). A follow-up query can identify and optionally repair them: +```sql +SELECT id FROM journal.routes WHERE gpx IS NOT NULL AND geom IS NULL; +``` diff --git a/openspec/changes/atomic-gpx-save/proposal.md b/openspec/changes/atomic-gpx-save/proposal.md new file mode 100644 index 0000000..030047d --- /dev/null +++ b/openspec/changes/atomic-gpx-save/proposal.md @@ -0,0 +1,32 @@ +## Why + +Route and activity rows can currently be saved with `geom IS NULL` when the PostGIS geometry write fails after the row insert succeeds — the error is swallowed silently with a `console.error`. This means missing map thumbnails, broken route-push deduplication, and corrupted spatial queries with no signal to the user or operator. The Planner callback endpoint also accepts GPX from an external source with no validation before writing. + +## What Changes + +- **New `gpx-save.server.ts` module** owns GPX validation and atomic geometry persistence; `setGeomFromGpx` moves here and becomes internal. +- **`validateGpx(gpx)`** parses the GPX string, checks ≥2 track points and valid coordinate ranges, throws `GpxValidationError` on failure, and returns the parsed result so callers don't re-parse. +- **`createRoute`, `updateRoute`, `createActivity`, `createRouteFromActivity`** all wrap their DB writes (row insert/update + geom write + version snapshot) in `db.transaction()` — partial state (row exists, geom NULL) is no longer possible. +- **`setGeomFromGpx` stops swallowing errors** — it throws, causing the transaction to roll back. +- **`demo-bot.server.ts`** migrated from raw inserts + `setGeomFromGpx` to `createRoute` / `createActivity`, eliminating a bypass of the new invariant. +- **`activities.server.ts`** removes inline `parseGpxAsync` call; uses the `ParsedGpx` returned by `validateGpx` for stat extraction instead. +- **ADR recorded**: PostGIS geometry writes are always transactional with row writes. + +## Capabilities + +### New Capabilities + +- `gpx-save`: Atomic GPX validation and PostGIS geometry persistence for routes and activities. + +### Modified Capabilities + +*(none — no user-visible requirement changes; this is an implementation-layer correctness fix)* + +## Impact + +- `apps/journal/app/lib/routes.server.ts` — `setGeomFromGpx` export removed; callers updated. +- `apps/journal/app/lib/activities.server.ts` — inline `parseGpxAsync` removed; imports from `gpx-save`. +- `apps/journal/app/lib/demo-bot.server.ts` — raw insert pattern replaced with `createRoute` / `createActivity`. +- `apps/journal/app/routes/api.routes.$id.callback.ts` — no validation changes needed (validation now inside `updateRoute`); GPX errors surface as thrown exceptions → callers return 400. +- `@trails-cool/gpx` — no changes; `parseGpxAsync` is still the underlying parser. +- No API surface changes, no schema changes, no migration required. diff --git a/openspec/changes/atomic-gpx-save/specs/gpx-save/spec.md b/openspec/changes/atomic-gpx-save/specs/gpx-save/spec.md new file mode 100644 index 0000000..ea397d4 --- /dev/null +++ b/openspec/changes/atomic-gpx-save/specs/gpx-save/spec.md @@ -0,0 +1,83 @@ +# gpx-save Specification + +## Purpose + +Atomic GPX validation and PostGIS geometry persistence for routes and activities. Every write of a GPX track in the Journal SHALL validate the track and persist the row + geometry in a single transaction. Silent geometry failures are not permitted. + +## Requirements + +### Requirement: GPX validation before any DB write + +The Journal SHALL validate any GPX string before writing a route or activity row. Validation SHALL confirm the GPX parses successfully, contains at least 2 track points, and all track points have coordinates within valid ranges (latitude −90..90, longitude −180..180). Validation SHALL throw `GpxValidationError` on failure. + +#### Scenario: Valid GPX proceeds to save + +- **WHEN** a caller passes a GPX string with ≥2 track points and valid coordinates to `createRoute`, `updateRoute`, `createActivity`, or `createRouteFromActivity` +- **THEN** the save proceeds and no `GpxValidationError` is thrown + +#### Scenario: GPX with fewer than 2 track points is rejected + +- **WHEN** a caller passes a GPX string that produces fewer than 2 track points +- **THEN** `GpxValidationError` is thrown before any DB write occurs + +#### Scenario: GPX with out-of-range coordinates is rejected + +- **WHEN** a caller passes a GPX string containing coordinates outside valid ranges +- **THEN** `GpxValidationError` is thrown before any DB write occurs + +#### Scenario: Unparseable GPX is rejected + +- **WHEN** a caller passes a malformed GPX string that cannot be parsed +- **THEN** `GpxValidationError` is thrown before any DB write occurs + +### Requirement: Atomic row + geometry persistence + +Every route or activity save that includes a GPX string SHALL wrap the row write, PostGIS geometry write, and version snapshot in a single database transaction. If any step fails, the entire transaction SHALL be rolled back — a route or activity row with a non-null `gpx` column and a null `geom` column SHALL NOT be possible through the normal save path. + +#### Scenario: Successful save stores row and geometry atomically + +- **WHEN** `createRoute` is called with valid GPX +- **THEN** the `routes` row, the `geom` column update, and the `routeVersions` row are all committed in a single transaction + +#### Scenario: PostGIS failure rolls back the row insert + +- **WHEN** the PostGIS geometry write fails during a `createRoute` call +- **THEN** the transaction is rolled back and no `routes` row is persisted + +#### Scenario: Route update is atomic + +- **WHEN** `updateRoute` is called with valid GPX +- **THEN** the row update, geometry update, and new version snapshot are committed atomically + +#### Scenario: Activity save is atomic + +- **WHEN** `createActivity` is called with valid GPX +- **THEN** the `activities` row and `geom` column update are committed atomically + +### Requirement: Loud failure on geometry errors + +The Journal SHALL NOT swallow PostGIS geometry write errors. Any failure during the geometry write SHALL propagate as a thrown exception, causing the enclosing transaction to roll back and the error to surface to the caller. + +#### Scenario: Geometry write error surfaces to caller + +- **WHEN** the PostGIS `UPDATE geom` statement fails +- **THEN** an exception is thrown, the transaction is rolled back, and the caller receives the error + +#### Scenario: demo-bot route creation fails loudly + +- **WHEN** `createRoute` is called from the demo-bot and the PostGIS write fails +- **THEN** the exception propagates — no partial route row is committed + +### Requirement: Single gpx-save module owns geometry persistence + +The Journal SHALL have exactly one module responsible for GPX validation and PostGIS geometry writes: `apps/journal/app/lib/gpx-save.server.ts`. No other module SHALL call PostGIS geometry update statements directly or implement GPX validation independently. + +#### Scenario: activities.server.ts uses gpx-save for geometry + +- **WHEN** `createActivity` or `createRouteFromActivity` writes geometry +- **THEN** the write goes through the `gpx-save` module, not an inline raw SQL statement + +#### Scenario: demo-bot uses createRoute and createActivity + +- **WHEN** the demo-bot creates synthetic routes and activities +- **THEN** it calls `createRoute` and `createActivity` rather than issuing raw inserts and calling `setGeomFromGpx` directly diff --git a/openspec/changes/atomic-gpx-save/tasks.md b/openspec/changes/atomic-gpx-save/tasks.md new file mode 100644 index 0000000..ab34bb6 --- /dev/null +++ b/openspec/changes/atomic-gpx-save/tasks.md @@ -0,0 +1,39 @@ +## 1. New gpx-save module + +- [x] 1.1 Create `apps/journal/app/lib/gpx-save.server.ts` with `GpxValidationError` class and `validateGpx(gpx: string): Promise` — parses, checks ≥2 track points, checks coordinate ranges, throws on failure, returns parsed result +- [x] 1.2 Move `setGeomFromGpx` logic into `gpx-save.server.ts` as an internal `writeGeom(tx, id, table, coords)` function that accepts a Drizzle transaction client and throws on failure (no try/catch) +- [x] 1.3 Write unit tests in `gpx-save.server.test.ts` covering: valid GPX passes, <2 track points throws, out-of-range coordinates throw, unparseable GPX throws + +## 2. Migrate routes.server.ts + +- [x] 2.1 Import `validateGpx` and `writeGeom` from `gpx-save.server.ts`; remove local `setGeomFromGpx` implementation and its export +- [x] 2.2 Wrap `createRoute` in `db.transaction()`: validate GPX → insert row → `writeGeom` → insert `routeVersions`, all within the transaction client +- [x] 2.3 Wrap `updateRoute` in `db.transaction()`: validate GPX → update row → `writeGeom` → insert new `routeVersions`, all within the transaction client +- [x] 2.4 Verify `computeRouteStats` is called with the `ParsedGpx` returned by `validateGpx` (avoid re-parsing) + +## 3. Migrate activities.server.ts + +- [x] 3.1 Replace inline `parseGpxAsync` call in `createActivity` with `validateGpx`; extract stats from the returned `ParsedGpx` +- [x] 3.2 Wrap `createActivity` in `db.transaction()`: validate GPX → insert row → `writeGeom`, all within the transaction client +- [x] 3.3 Wrap `createRouteFromActivity` in `db.transaction()`: insert route row → `writeGeom` → update activity's `routeId`, all within the transaction client +- [x] 3.4 Remove `import { setGeomFromGpx } from "./routes.server.ts"` — no longer needed + +## 4. Migrate demo-bot.server.ts + +- [x] 4.1 Replace the raw `db.insert(routes).values(...)` + `setGeomFromGpx(routeId, ...)` block with a `createRoute(ownerId, input)` call; pass pre-computed stats via `RouteInput` fields so `createRoute` doesn't re-parse BRouter's output +- [x] 4.2 Replace the raw `db.insert(activities).values(...)` + `setGeomFromGpx(activityId, ...)` block with a `createActivity(ownerId, input)` call +- [x] 4.3 Remove `import { setGeomFromGpx } from "./routes.server.ts"` from `demo-bot.server.ts` + +## 5. Callback endpoint error handling + +- [x] 5.1 In `api.routes.$id.callback.ts`, catch `GpxValidationError` from `updateRoute` and return a 400 response with the validation message (currently the catch block returns 401 for all errors — narrow it) + +## 6. ADR + +- [x] 6.1 Write `docs/adr/0006-atomic-gpx-save.md` documenting that PostGIS geometry writes are always transactional with row writes and that `gpx-save.server.ts` is the sole owner of geometry persistence + +## 7. Verification + +- [x] 7.1 Run `pnpm typecheck` — no new type errors +- [x] 7.2 Run `pnpm test` — all existing tests pass; new `gpx-save.server.test.ts` tests pass +- [x] 7.3 Confirm `setGeomFromGpx` is no longer exported from any file (`grep -r "setGeomFromGpx" apps/journal/app` returns no results outside `gpx-save.server.ts`) From b4ef8b0e0e4b4705184b00d055c05cf4711edafe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Sun, 10 May 2026 15:06:55 +0200 Subject: [PATCH 013/319] Archive atomic-gpx-save change Co-Authored-By: Claude Sonnet 4.6 --- .../2026-05-10-atomic-gpx-save}/.openspec.yaml | 0 .../2026-05-10-atomic-gpx-save}/design.md | 0 .../2026-05-10-atomic-gpx-save}/proposal.md | 0 .../2026-05-10-atomic-gpx-save}/specs/gpx-save/spec.md | 0 .../2026-05-10-atomic-gpx-save}/tasks.md | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename openspec/changes/{atomic-gpx-save => archive/2026-05-10-atomic-gpx-save}/.openspec.yaml (100%) rename openspec/changes/{atomic-gpx-save => archive/2026-05-10-atomic-gpx-save}/design.md (100%) rename openspec/changes/{atomic-gpx-save => archive/2026-05-10-atomic-gpx-save}/proposal.md (100%) rename openspec/changes/{atomic-gpx-save => archive/2026-05-10-atomic-gpx-save}/specs/gpx-save/spec.md (100%) rename openspec/changes/{atomic-gpx-save => archive/2026-05-10-atomic-gpx-save}/tasks.md (100%) diff --git a/openspec/changes/atomic-gpx-save/.openspec.yaml b/openspec/changes/archive/2026-05-10-atomic-gpx-save/.openspec.yaml similarity index 100% rename from openspec/changes/atomic-gpx-save/.openspec.yaml rename to openspec/changes/archive/2026-05-10-atomic-gpx-save/.openspec.yaml diff --git a/openspec/changes/atomic-gpx-save/design.md b/openspec/changes/archive/2026-05-10-atomic-gpx-save/design.md similarity index 100% rename from openspec/changes/atomic-gpx-save/design.md rename to openspec/changes/archive/2026-05-10-atomic-gpx-save/design.md diff --git a/openspec/changes/atomic-gpx-save/proposal.md b/openspec/changes/archive/2026-05-10-atomic-gpx-save/proposal.md similarity index 100% rename from openspec/changes/atomic-gpx-save/proposal.md rename to openspec/changes/archive/2026-05-10-atomic-gpx-save/proposal.md diff --git a/openspec/changes/atomic-gpx-save/specs/gpx-save/spec.md b/openspec/changes/archive/2026-05-10-atomic-gpx-save/specs/gpx-save/spec.md similarity index 100% rename from openspec/changes/atomic-gpx-save/specs/gpx-save/spec.md rename to openspec/changes/archive/2026-05-10-atomic-gpx-save/specs/gpx-save/spec.md diff --git a/openspec/changes/atomic-gpx-save/tasks.md b/openspec/changes/archive/2026-05-10-atomic-gpx-save/tasks.md similarity index 100% rename from openspec/changes/atomic-gpx-save/tasks.md rename to openspec/changes/archive/2026-05-10-atomic-gpx-save/tasks.md From b17f8eb02ad738c15198846699a5ba4d652caed4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Sun, 10 May 2026 15:07:54 +0200 Subject: [PATCH 014/319] Revert archive of atomic-gpx-save (will redo via skill) --- .../2026-05-10-atomic-gpx-save => atomic-gpx-save}/.openspec.yaml | 0 .../2026-05-10-atomic-gpx-save => atomic-gpx-save}/design.md | 0 .../2026-05-10-atomic-gpx-save => atomic-gpx-save}/proposal.md | 0 .../specs/gpx-save/spec.md | 0 .../2026-05-10-atomic-gpx-save => atomic-gpx-save}/tasks.md | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename openspec/changes/{archive/2026-05-10-atomic-gpx-save => atomic-gpx-save}/.openspec.yaml (100%) rename openspec/changes/{archive/2026-05-10-atomic-gpx-save => atomic-gpx-save}/design.md (100%) rename openspec/changes/{archive/2026-05-10-atomic-gpx-save => atomic-gpx-save}/proposal.md (100%) rename openspec/changes/{archive/2026-05-10-atomic-gpx-save => atomic-gpx-save}/specs/gpx-save/spec.md (100%) rename openspec/changes/{archive/2026-05-10-atomic-gpx-save => atomic-gpx-save}/tasks.md (100%) diff --git a/openspec/changes/archive/2026-05-10-atomic-gpx-save/.openspec.yaml b/openspec/changes/atomic-gpx-save/.openspec.yaml similarity index 100% rename from openspec/changes/archive/2026-05-10-atomic-gpx-save/.openspec.yaml rename to openspec/changes/atomic-gpx-save/.openspec.yaml diff --git a/openspec/changes/archive/2026-05-10-atomic-gpx-save/design.md b/openspec/changes/atomic-gpx-save/design.md similarity index 100% rename from openspec/changes/archive/2026-05-10-atomic-gpx-save/design.md rename to openspec/changes/atomic-gpx-save/design.md diff --git a/openspec/changes/archive/2026-05-10-atomic-gpx-save/proposal.md b/openspec/changes/atomic-gpx-save/proposal.md similarity index 100% rename from openspec/changes/archive/2026-05-10-atomic-gpx-save/proposal.md rename to openspec/changes/atomic-gpx-save/proposal.md diff --git a/openspec/changes/archive/2026-05-10-atomic-gpx-save/specs/gpx-save/spec.md b/openspec/changes/atomic-gpx-save/specs/gpx-save/spec.md similarity index 100% rename from openspec/changes/archive/2026-05-10-atomic-gpx-save/specs/gpx-save/spec.md rename to openspec/changes/atomic-gpx-save/specs/gpx-save/spec.md diff --git a/openspec/changes/archive/2026-05-10-atomic-gpx-save/tasks.md b/openspec/changes/atomic-gpx-save/tasks.md similarity index 100% rename from openspec/changes/archive/2026-05-10-atomic-gpx-save/tasks.md rename to openspec/changes/atomic-gpx-save/tasks.md From abc3fbaa5b4c843076280450a5159ece22f1e0f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Sun, 10 May 2026 15:09:15 +0200 Subject: [PATCH 015/319] Archive atomic-gpx-save + sync gpx-save spec to main Co-Authored-By: Claude Sonnet 4.6 --- .../.openspec.yaml | 0 .../2026-05-10-atomic-gpx-save}/design.md | 0 .../2026-05-10-atomic-gpx-save}/proposal.md | 0 .../specs/gpx-save/spec.md | 0 .../2026-05-10-atomic-gpx-save}/tasks.md | 0 openspec/specs/gpx-save/spec.md | 83 +++++++++++++++++++ 6 files changed, 83 insertions(+) rename openspec/changes/{atomic-gpx-save => archive/2026-05-10-atomic-gpx-save}/.openspec.yaml (100%) rename openspec/changes/{atomic-gpx-save => archive/2026-05-10-atomic-gpx-save}/design.md (100%) rename openspec/changes/{atomic-gpx-save => archive/2026-05-10-atomic-gpx-save}/proposal.md (100%) rename openspec/changes/{atomic-gpx-save => archive/2026-05-10-atomic-gpx-save}/specs/gpx-save/spec.md (100%) rename openspec/changes/{atomic-gpx-save => archive/2026-05-10-atomic-gpx-save}/tasks.md (100%) create mode 100644 openspec/specs/gpx-save/spec.md diff --git a/openspec/changes/atomic-gpx-save/.openspec.yaml b/openspec/changes/archive/2026-05-10-atomic-gpx-save/.openspec.yaml similarity index 100% rename from openspec/changes/atomic-gpx-save/.openspec.yaml rename to openspec/changes/archive/2026-05-10-atomic-gpx-save/.openspec.yaml diff --git a/openspec/changes/atomic-gpx-save/design.md b/openspec/changes/archive/2026-05-10-atomic-gpx-save/design.md similarity index 100% rename from openspec/changes/atomic-gpx-save/design.md rename to openspec/changes/archive/2026-05-10-atomic-gpx-save/design.md diff --git a/openspec/changes/atomic-gpx-save/proposal.md b/openspec/changes/archive/2026-05-10-atomic-gpx-save/proposal.md similarity index 100% rename from openspec/changes/atomic-gpx-save/proposal.md rename to openspec/changes/archive/2026-05-10-atomic-gpx-save/proposal.md diff --git a/openspec/changes/atomic-gpx-save/specs/gpx-save/spec.md b/openspec/changes/archive/2026-05-10-atomic-gpx-save/specs/gpx-save/spec.md similarity index 100% rename from openspec/changes/atomic-gpx-save/specs/gpx-save/spec.md rename to openspec/changes/archive/2026-05-10-atomic-gpx-save/specs/gpx-save/spec.md diff --git a/openspec/changes/atomic-gpx-save/tasks.md b/openspec/changes/archive/2026-05-10-atomic-gpx-save/tasks.md similarity index 100% rename from openspec/changes/atomic-gpx-save/tasks.md rename to openspec/changes/archive/2026-05-10-atomic-gpx-save/tasks.md diff --git a/openspec/specs/gpx-save/spec.md b/openspec/specs/gpx-save/spec.md new file mode 100644 index 0000000..ea397d4 --- /dev/null +++ b/openspec/specs/gpx-save/spec.md @@ -0,0 +1,83 @@ +# gpx-save Specification + +## Purpose + +Atomic GPX validation and PostGIS geometry persistence for routes and activities. Every write of a GPX track in the Journal SHALL validate the track and persist the row + geometry in a single transaction. Silent geometry failures are not permitted. + +## Requirements + +### Requirement: GPX validation before any DB write + +The Journal SHALL validate any GPX string before writing a route or activity row. Validation SHALL confirm the GPX parses successfully, contains at least 2 track points, and all track points have coordinates within valid ranges (latitude −90..90, longitude −180..180). Validation SHALL throw `GpxValidationError` on failure. + +#### Scenario: Valid GPX proceeds to save + +- **WHEN** a caller passes a GPX string with ≥2 track points and valid coordinates to `createRoute`, `updateRoute`, `createActivity`, or `createRouteFromActivity` +- **THEN** the save proceeds and no `GpxValidationError` is thrown + +#### Scenario: GPX with fewer than 2 track points is rejected + +- **WHEN** a caller passes a GPX string that produces fewer than 2 track points +- **THEN** `GpxValidationError` is thrown before any DB write occurs + +#### Scenario: GPX with out-of-range coordinates is rejected + +- **WHEN** a caller passes a GPX string containing coordinates outside valid ranges +- **THEN** `GpxValidationError` is thrown before any DB write occurs + +#### Scenario: Unparseable GPX is rejected + +- **WHEN** a caller passes a malformed GPX string that cannot be parsed +- **THEN** `GpxValidationError` is thrown before any DB write occurs + +### Requirement: Atomic row + geometry persistence + +Every route or activity save that includes a GPX string SHALL wrap the row write, PostGIS geometry write, and version snapshot in a single database transaction. If any step fails, the entire transaction SHALL be rolled back — a route or activity row with a non-null `gpx` column and a null `geom` column SHALL NOT be possible through the normal save path. + +#### Scenario: Successful save stores row and geometry atomically + +- **WHEN** `createRoute` is called with valid GPX +- **THEN** the `routes` row, the `geom` column update, and the `routeVersions` row are all committed in a single transaction + +#### Scenario: PostGIS failure rolls back the row insert + +- **WHEN** the PostGIS geometry write fails during a `createRoute` call +- **THEN** the transaction is rolled back and no `routes` row is persisted + +#### Scenario: Route update is atomic + +- **WHEN** `updateRoute` is called with valid GPX +- **THEN** the row update, geometry update, and new version snapshot are committed atomically + +#### Scenario: Activity save is atomic + +- **WHEN** `createActivity` is called with valid GPX +- **THEN** the `activities` row and `geom` column update are committed atomically + +### Requirement: Loud failure on geometry errors + +The Journal SHALL NOT swallow PostGIS geometry write errors. Any failure during the geometry write SHALL propagate as a thrown exception, causing the enclosing transaction to roll back and the error to surface to the caller. + +#### Scenario: Geometry write error surfaces to caller + +- **WHEN** the PostGIS `UPDATE geom` statement fails +- **THEN** an exception is thrown, the transaction is rolled back, and the caller receives the error + +#### Scenario: demo-bot route creation fails loudly + +- **WHEN** `createRoute` is called from the demo-bot and the PostGIS write fails +- **THEN** the exception propagates — no partial route row is committed + +### Requirement: Single gpx-save module owns geometry persistence + +The Journal SHALL have exactly one module responsible for GPX validation and PostGIS geometry writes: `apps/journal/app/lib/gpx-save.server.ts`. No other module SHALL call PostGIS geometry update statements directly or implement GPX validation independently. + +#### Scenario: activities.server.ts uses gpx-save for geometry + +- **WHEN** `createActivity` or `createRouteFromActivity` writes geometry +- **THEN** the write goes through the `gpx-save` module, not an inline raw SQL statement + +#### Scenario: demo-bot uses createRoute and createActivity + +- **WHEN** the demo-bot creates synthetic routes and activities +- **THEN** it calls `createRoute` and `createActivity` rather than issuing raw inserts and calling `setGeomFromGpx` directly From e7a0c132b96c5b635810fa128d396be51022b06d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Sun, 10 May 2026 15:18:33 +0200 Subject: [PATCH 016/319] =?UTF-8?q?Add=20e2e=20tests=20for=20Planner=20cal?= =?UTF-8?q?lback=20=E2=86=92=20geometry=20stored=20atomically?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduces two E2E=true-gated test endpoints: - POST /api/e2e/seed — creates a test user + bare route, returns routeId + JWT - GET /api/e2e/route/:id — returns { hasGeom } for post-callback assertions Three new integration tests: - valid GPX via callback stores geometry (hasGeom = true) - invalid GPX (< 2 track points) returns 400, geometry not stored - missing token returns 401 CI: E2E=true added to the "Run E2E tests" step so the seed endpoints are enabled when react-router-serve runs during the Playwright job. Co-Authored-By: Claude Sonnet 4.6 --- .github/workflows/ci.yml | 1 + apps/journal/app/routes.ts | 2 + apps/journal/app/routes/api.e2e.route.$id.ts | 28 ++++++++ apps/journal/app/routes/api.e2e.seed.ts | 75 ++++++++++++++++++++ e2e/integration.test.ts | 64 ++++++++++++++++- 5 files changed, 169 insertions(+), 1 deletion(-) create mode 100644 apps/journal/app/routes/api.e2e.route.$id.ts create mode 100644 apps/journal/app/routes/api.e2e.seed.ts diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index aa9034e..326b3e0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -231,6 +231,7 @@ jobs: run: pnpm test:e2e env: BROUTER_URL: http://localhost:17777 + E2E: "true" - name: Playwright job summary if: ${{ !cancelled() }} diff --git a/apps/journal/app/routes.ts b/apps/journal/app/routes.ts index 4c51727..ea456b1 100644 --- a/apps/journal/app/routes.ts +++ b/apps/journal/app/routes.ts @@ -16,6 +16,8 @@ export default [ route("routes/new", "routes/routes.new.tsx"), route("routes/:id", "routes/routes.$id.tsx"), route("routes/:id/edit", "routes/routes.$id.edit.tsx"), + route("api/e2e/seed", "routes/api.e2e.seed.ts"), + route("api/e2e/route/:id", "routes/api.e2e.route.$id.ts"), route("api/routes/:id/callback", "routes/api.routes.$id.callback.ts"), route("api/routes/:id/edit-in-planner", "routes/api.routes.$id.edit-in-planner.ts"), route("api/routes/:id/gpx", "routes/api.routes.$id.gpx.ts"), diff --git a/apps/journal/app/routes/api.e2e.route.$id.ts b/apps/journal/app/routes/api.e2e.route.$id.ts new file mode 100644 index 0000000..0190695 --- /dev/null +++ b/apps/journal/app/routes/api.e2e.route.$id.ts @@ -0,0 +1,28 @@ +import { data } from "react-router"; +import { eq } from "drizzle-orm"; +import { sql } from "drizzle-orm"; +import { getDb } from "~/lib/db"; + +// Only available when the server is started with E2E=true. +function assertE2EEnabled() { + if (process.env.E2E !== "true") { + throw new Response("Not found", { status: 404 }); + } +} + +/** + * GET /api/e2e/route/:id + * + * Returns minimal route metadata for e2e assertions — specifically whether + * the PostGIS geom column is populated. Gated behind E2E=true. + */ +export async function loader({ params }: { params: { id: string } }) { + assertE2EEnabled(); + const db = getDb(); + const result = await db.execute( + sql`SELECT id, geom IS NOT NULL AS has_geom FROM journal.routes WHERE id = ${params.id}`, + ); + const row = (result as unknown as Array<{ id: string; has_geom: boolean }>)[0]; + if (!row) return data({ error: "Not found" }, { status: 404 }); + return data({ id: row.id, hasGeom: row.has_geom }); +} diff --git a/apps/journal/app/routes/api.e2e.seed.ts b/apps/journal/app/routes/api.e2e.seed.ts new file mode 100644 index 0000000..6d0b67b --- /dev/null +++ b/apps/journal/app/routes/api.e2e.seed.ts @@ -0,0 +1,75 @@ +import { randomUUID } from "node:crypto"; +import { data } from "react-router"; +import { eq } from "drizzle-orm"; +import { getDb } from "~/lib/db"; +import { users, routes } from "@trails-cool/db/schema/journal"; +import { createRouteToken } from "~/lib/jwt.server"; +import { TERMS_VERSION } from "~/lib/legal"; + +// Only available when the server is started with E2E=true. +// Never enabled in production. +function assertE2EEnabled() { + if (process.env.E2E !== "true") { + throw new Response("Not found", { status: 404 }); + } +} + +const E2E_USER_USERNAME = "e2e-test-user"; +const E2E_USER_EMAIL = "e2e@localhost"; + +/** + * POST /api/e2e/seed + * + * Idempotently creates the e2e test user and a bare route (no GPX, no geom), + * then returns a callback-scoped JWT for that route. Used by e2e tests that + * need to hit the Planner callback endpoint without going through the browser + * auth flow. + * + * Body: none required. Optionally pass { routeName } to label the route. + */ +export async function action({ request }: { request: Request }) { + assertE2EEnabled(); + if (request.method !== "POST") { + return data({ error: "Method not allowed" }, { status: 405 }); + } + + const db = getDb(); + + // Upsert the e2e test user + await db + .insert(users) + .values({ + id: randomUUID(), + username: E2E_USER_USERNAME, + email: E2E_USER_EMAIL, + displayName: "E2E Test User", + domain: "localhost", + termsAcceptedAt: new Date(), + termsVersion: TERMS_VERSION, + }) + .onConflictDoNothing({ target: users.username }); + + const [user] = await db + .select({ id: users.id }) + .from(users) + .where(eq(users.username, E2E_USER_USERNAME)); + + if (!user) throw new Error("e2e seed: failed to upsert test user"); + + const body = request.headers.get("content-type")?.includes("application/json") + ? await request.json().catch(() => ({})) + : {}; + const routeName = (body as { routeName?: string }).routeName ?? "E2E callback test route"; + + const routeId = randomUUID(); + await db.insert(routes).values({ + id: routeId, + ownerId: user.id, + name: routeName, + description: "", + }); + + const token = await createRouteToken(routeId); + + return data({ routeId, token, ownerId: user.id }); +} diff --git a/e2e/integration.test.ts b/e2e/integration.test.ts index 4834e9d..c4b5c3e 100644 --- a/e2e/integration.test.ts +++ b/e2e/integration.test.ts @@ -6,11 +6,73 @@ import { test, expect } from "./fixtures/test"; * - BRouter (for route computation) * * In CI, these services are started by the workflow. - * Locally, run `pnpm dev:full` first. + * Locally, run `pnpm dev:full` first (with E2E=true for the callback tests). */ +const JOURNAL = "http://localhost:3000"; const PLANNER = "http://localhost:3001"; +const VALID_GPX = ` + + + 34 + 40 + 35 + +`; + +const ONE_POINT_GPX = ` + + + 34 + +`; + +test.describe("Integration: Planner callback → geometry stored", () => { + test("valid GPX stores geometry atomically", async ({ request }) => { + const seedResp = await request.post(`${JOURNAL}/api/e2e/seed`); + expect(seedResp.ok()).toBeTruthy(); + const { routeId, token } = await seedResp.json() as { routeId: string; token: string }; + + const callbackResp = await request.post(`${JOURNAL}/api/routes/${routeId}/callback`, { + headers: { Authorization: `Bearer ${token}` }, + data: { gpx: VALID_GPX }, + }); + expect(callbackResp.status()).toBe(200); + + const geomResp = await request.get(`${JOURNAL}/api/e2e/route/${routeId}`); + const { hasGeom } = await geomResp.json() as { hasGeom: boolean }; + expect(hasGeom).toBe(true); + }); + + test("invalid GPX returns 400 and does not store geometry", async ({ request }) => { + const seedResp = await request.post(`${JOURNAL}/api/e2e/seed`); + const { routeId, token } = await seedResp.json() as { routeId: string; token: string }; + + const callbackResp = await request.post(`${JOURNAL}/api/routes/${routeId}/callback`, { + headers: { Authorization: `Bearer ${token}` }, + data: { gpx: ONE_POINT_GPX }, + }); + expect(callbackResp.status()).toBe(400); + const body = await callbackResp.json() as { error: string }; + expect(body.error).toMatch(/at least 2 track points/); + + const geomResp = await request.get(`${JOURNAL}/api/e2e/route/${routeId}`); + const { hasGeom } = await geomResp.json() as { hasGeom: boolean }; + expect(hasGeom).toBe(false); + }); + + test("missing token returns 401", async ({ request }) => { + const seedResp = await request.post(`${JOURNAL}/api/e2e/seed`); + const { routeId } = await seedResp.json() as { routeId: string }; + + const resp = await request.post(`${JOURNAL}/api/routes/${routeId}/callback`, { + data: { gpx: VALID_GPX }, + }); + expect(resp.status()).toBe(401); + }); +}); + test.describe("Integration: Journal ↔ Planner handoff", () => { test("GPX import → view route → export GPX", async ({ request }) => { const gpx = ` From 557244ee877cc7afeef4cfa6798ac52e7db818ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Sun, 10 May 2026 15:24:31 +0200 Subject: [PATCH 017/319] Fix unused import lint error in api.e2e.route.$id.ts --- apps/journal/app/routes/api.e2e.route.$id.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/journal/app/routes/api.e2e.route.$id.ts b/apps/journal/app/routes/api.e2e.route.$id.ts index 0190695..4a2e862 100644 --- a/apps/journal/app/routes/api.e2e.route.$id.ts +++ b/apps/journal/app/routes/api.e2e.route.$id.ts @@ -1,5 +1,4 @@ import { data } from "react-router"; -import { eq } from "drizzle-orm"; import { sql } from "drizzle-orm"; import { getDb } from "~/lib/db"; From e387e1f7987650999486844d4fc45ddfd3369f71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Sun, 10 May 2026 15:52:31 +0200 Subject: [PATCH 018/319] Deepen three architectural seams: FIT consolidation, host election extraction, injectable db MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Extract shared fitToGpx into connected-services/fit.ts (FIT is a Garmin open standard used by Wahoo, Coros, Garmin — not provider-specific) - Add importActivity() to sync/imports.server.ts so providers call one function instead of createActivity + recordImport separately; eliminates direct dependency on activities.server.ts from provider adapters - Update wahoo importer + webhook to use both shared helpers - Extract useHostElection(yjs) hook from useRouting so host election is independently testable without mounting the full routing stack - Add setDb() to journal db.ts for module-level injection in unit tests Co-Authored-By: Claude Sonnet 4.6 --- .../journal/app/lib/connected-services/fit.ts | 38 +++++++++++++++++ .../providers/wahoo/importer.ts | 40 ++---------------- .../providers/wahoo/webhook.test.ts | 35 ++++------------ .../providers/wahoo/webhook.ts | 42 +++---------------- apps/journal/app/lib/db.ts | 4 ++ apps/journal/app/lib/sync/imports.server.ts | 15 +++++++ apps/planner/app/lib/use-host-election.ts | 28 +++++++++++++ apps/planner/app/lib/use-routing.ts | 24 +---------- 8 files changed, 104 insertions(+), 122 deletions(-) create mode 100644 apps/journal/app/lib/connected-services/fit.ts create mode 100644 apps/planner/app/lib/use-host-election.ts diff --git a/apps/journal/app/lib/connected-services/fit.ts b/apps/journal/app/lib/connected-services/fit.ts new file mode 100644 index 0000000..64f1f65 --- /dev/null +++ b/apps/journal/app/lib/connected-services/fit.ts @@ -0,0 +1,38 @@ +// Shared FIT file → GPX converter for provider importers. +// +// FIT is an open standard (Garmin/ANT+) used by Wahoo, Garmin, Coros, and +// others. This module is shared across all providers that produce FIT files +// so the conversion logic lives in one place. + +import FitParser from "fit-file-parser"; +import { generateGpx } from "@trails-cool/gpx"; + +export async function fitToGpx(buffer: Buffer, name: string): Promise { + const parsed = await new Promise>((resolve, reject) => { + const parser = new FitParser({ force: true }); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + parser.parse(buffer as any, (error: unknown, data: any) => { + if (error) reject(error); + else resolve(data ?? {}); + }); + }); + + const records = (parsed.records ?? []) as Array<{ + position_lat?: number; + position_long?: number; + altitude?: number; + timestamp?: string | Date; + }>; + + const trackPoints = records + .filter((r) => r.position_lat != null && r.position_long != null) + .map((r) => ({ + lat: r.position_lat!, + lon: r.position_long!, + ele: r.altitude, + time: r.timestamp instanceof Date ? r.timestamp.toISOString() : r.timestamp, + })); + + if (trackPoints.length < 2) return null; + return generateGpx({ name, tracks: [trackPoints] }); +} diff --git a/apps/journal/app/lib/connected-services/providers/wahoo/importer.ts b/apps/journal/app/lib/connected-services/providers/wahoo/importer.ts index 8cbdcf1..84bee86 100644 --- a/apps/journal/app/lib/connected-services/providers/wahoo/importer.ts +++ b/apps/journal/app/lib/connected-services/providers/wahoo/importer.ts @@ -4,10 +4,8 @@ // Credentials always flow through ctx.withFreshCredentials — this module // never reads the connected_services credentials JSONB directly. -import FitParser from "fit-file-parser"; -import { generateGpx } from "@trails-cool/gpx"; -import { createActivity } from "../../../activities.server.ts"; -import { recordImport, isAlreadyImported } from "../../../sync/imports.server.ts"; +import { fitToGpx } from "../../fit.ts"; +import { importActivity, isAlreadyImported } from "../../../sync/imports.server.ts"; import type { CapabilityContext, ImportableList, @@ -69,37 +67,6 @@ function toImportable(w: WahooWorkout) { }; } -async function fitToGpx(buffer: Buffer, name: string): Promise { - const parsed = await new Promise>((resolve, reject) => { - const parser = new FitParser({ force: true }); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - parser.parse(buffer as any, (error: unknown, data: any) => { - if (error) reject(error); - else resolve(data ?? {}); - }); - }); - - const records = (parsed.records ?? []) as Array<{ - position_lat?: number; - position_long?: number; - altitude?: number; - timestamp?: string | Date; - }>; - - const trackPoints = records - .filter((r) => r.position_lat != null && r.position_long != null) - .map((r) => ({ - lat: r.position_lat!, - lon: r.position_long!, - ele: r.altitude, - time: r.timestamp instanceof Date ? r.timestamp.toISOString() : r.timestamp, - })); - - if (trackPoints.length < 2) return null; - - return generateGpx({ name, tracks: [trackPoints] }); -} - async function downloadFit(fileUrl: string): Promise { // Wahoo CDN URLs are pre-signed; no auth header needed (and adding one // breaks them). @@ -163,11 +130,10 @@ export const wahooImporter: Importer = { gpx = await fitToGpx(buffer, workout.name || "Wahoo workout"); } - const activityId = await createActivity(userId, { + const { activityId } = await importActivity(userId, "wahoo", workoutId, { name: workout.name || `Wahoo workout ${workoutId}`, gpx: gpx ?? undefined, }); - await recordImport(userId, "wahoo", workoutId, activityId); return { activityId, hadGeometry: gpx !== null }; }, diff --git a/apps/journal/app/lib/connected-services/providers/wahoo/webhook.test.ts b/apps/journal/app/lib/connected-services/providers/wahoo/webhook.test.ts index 525d719..01d2acd 100644 --- a/apps/journal/app/lib/connected-services/providers/wahoo/webhook.test.ts +++ b/apps/journal/app/lib/connected-services/providers/wahoo/webhook.test.ts @@ -6,18 +6,14 @@ import { describe, it, expect, beforeEach, vi } from "vitest"; const fetchSpy = vi.fn(); -const mockCreateActivity = vi.fn(); +const mockImportActivity = vi.fn(); const mockIsAlreadyImported = vi.fn(); -const mockRecordImport = vi.fn(); const mockGetServiceByProviderUser = vi.fn(); const mockWithFreshCredentials = vi.fn(); -vi.mock("../../../activities.server.ts", () => ({ - createActivity: mockCreateActivity, -})); vi.mock("../../../sync/imports.server.ts", () => ({ isAlreadyImported: mockIsAlreadyImported, - recordImport: mockRecordImport, + importActivity: mockImportActivity, })); vi.mock("../../manager.ts", () => ({ getServiceByProviderUser: mockGetServiceByProviderUser, @@ -27,9 +23,8 @@ vi.mock("../../manager.ts", () => ({ beforeEach(() => { fetchSpy.mockReset(); globalThis.fetch = fetchSpy as unknown as typeof fetch; - mockCreateActivity.mockReset(); + mockImportActivity.mockReset(); mockIsAlreadyImported.mockReset(); - mockRecordImport.mockReset(); mockGetServiceByProviderUser.mockReset(); mockWithFreshCredentials.mockReset(); }); @@ -73,18 +68,7 @@ describe("wahooWebhook.handle", () => { provider: "wahoo", }); mockIsAlreadyImported.mockResolvedValue(false); - mockCreateActivity.mockResolvedValue("act-1"); - // withFreshCredentials passes the credentials to fn — we don't need to - // download a file to assert the basic flow; pass a no-op file URL test - // via parseWebhook output containing fileUrl undefined to skip download. - mockWithFreshCredentials.mockImplementation( - async (_id: string, fn: (creds: unknown) => Promise) => - fn({ - access_token: "a", - refresh_token: "r", - expires_at: new Date(Date.now() + 3600_000).toISOString(), - }), - ); + mockImportActivity.mockResolvedValue({ activityId: "act-1" }); await wahooWebhook.handle({ eventType: "workout_summary", @@ -93,11 +77,12 @@ describe("wahooWebhook.handle", () => { // no fileUrl — the activity is created without GPX }); - expect(mockCreateActivity).toHaveBeenCalledWith( + expect(mockImportActivity).toHaveBeenCalledWith( "u1", + "wahoo", + "42", expect.objectContaining({ name: expect.stringContaining("Wahoo") }), ); - expect(mockRecordImport).toHaveBeenCalledWith("u1", "wahoo", "42", "act-1"); }); it("silently skips when the providerUserId is unknown (no leak)", async () => { @@ -109,8 +94,7 @@ describe("wahooWebhook.handle", () => { workoutId: "42", }); - expect(mockCreateActivity).not.toHaveBeenCalled(); - expect(mockRecordImport).not.toHaveBeenCalled(); + expect(mockImportActivity).not.toHaveBeenCalled(); }); it("silently skips when the workout was already imported (idempotency)", async () => { @@ -127,7 +111,6 @@ describe("wahooWebhook.handle", () => { workoutId: "42", }); - expect(mockCreateActivity).not.toHaveBeenCalled(); - expect(mockRecordImport).not.toHaveBeenCalled(); + expect(mockImportActivity).not.toHaveBeenCalled(); }); }); diff --git a/apps/journal/app/lib/connected-services/providers/wahoo/webhook.ts b/apps/journal/app/lib/connected-services/providers/wahoo/webhook.ts index 2b11b68..fe00bf2 100644 --- a/apps/journal/app/lib/connected-services/providers/wahoo/webhook.ts +++ b/apps/journal/app/lib/connected-services/providers/wahoo/webhook.ts @@ -5,10 +5,8 @@ // provider_user_id, deduplicate via sync_imports, then download + convert // the FIT file (if present) and create an activity. -import FitParser from "fit-file-parser"; -import { generateGpx } from "@trails-cool/gpx"; -import { createActivity } from "../../../activities.server.ts"; -import { isAlreadyImported, recordImport } from "../../../sync/imports.server.ts"; +import { fitToGpx } from "../../fit.ts"; +import { isAlreadyImported, importActivity } from "../../../sync/imports.server.ts"; import { getServiceByProviderUser, withFreshCredentials } from "../../manager.ts"; import type { OAuthCredentials } from "../../types.ts"; import type { WebhookEvent, WebhookReceiver } from "../../registry.ts"; @@ -23,35 +21,6 @@ interface WahooWebhookBody { }; } -async function fitToGpx(buffer: Buffer): Promise { - const parsed = await new Promise>((resolve, reject) => { - const parser = new FitParser({ force: true }); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - parser.parse(buffer as any, (error: unknown, data: any) => { - if (error) reject(error); - else resolve(data ?? {}); - }); - }); - - const records = (parsed.records ?? []) as Array<{ - position_lat?: number; - position_long?: number; - altitude?: number; - timestamp?: string | Date; - }>; - - const trackPoints = records - .filter((r) => r.position_lat != null && r.position_long != null) - .map((r) => ({ - lat: r.position_lat!, - lon: r.position_long!, - ele: r.altitude, - time: r.timestamp instanceof Date ? r.timestamp.toISOString() : r.timestamp, - })); - - if (trackPoints.length < 2) return null; - return generateGpx({ name: "Wahoo workout", tracks: [trackPoints] }); -} export const wahooWebhook: WebhookReceiver = { parseWebhook(body: unknown): WebhookEvent | null { @@ -88,13 +57,12 @@ export const wahooWebhook: WebhookReceiver = { if (!resp.ok) throw new Error(`Wahoo file download failed: ${resp.status}`); return Buffer.from(await resp.arrayBuffer()); }); - gpx = await fitToGpx(buffer); + gpx = await fitToGpx(buffer, "Wahoo workout"); } - const activityId = await createActivity(service.userId, { - name: `Wahoo workout`, + await importActivity(service.userId, "wahoo", event.workoutId, { + name: "Wahoo workout", gpx: gpx ?? undefined, }); - await recordImport(service.userId, "wahoo", event.workoutId, activityId); }, }; diff --git a/apps/journal/app/lib/db.ts b/apps/journal/app/lib/db.ts index 8fafd8c..7546fe0 100644 --- a/apps/journal/app/lib/db.ts +++ b/apps/journal/app/lib/db.ts @@ -8,3 +8,7 @@ export function getDb(): Database { } return _db; } + +export function setDb(db: Database | null): void { + _db = db; +} diff --git a/apps/journal/app/lib/sync/imports.server.ts b/apps/journal/app/lib/sync/imports.server.ts index 2be87c1..757a201 100644 --- a/apps/journal/app/lib/sync/imports.server.ts +++ b/apps/journal/app/lib/sync/imports.server.ts @@ -2,6 +2,7 @@ import { randomUUID } from "node:crypto"; import { eq, and, inArray } from "drizzle-orm"; import { getDb } from "../db.ts"; import { syncImports } from "@trails-cool/db/schema/journal"; +import { createActivity } from "../activities.server.ts"; export async function recordImport( userId: string, @@ -43,6 +44,20 @@ export async function deleteImportByActivity(activityId: string) { await db.delete(syncImports).where(eq(syncImports.activityId, activityId)); } +// Single callsite for "create an activity from an imported workout and record +// the dedup entry". Providers call this instead of calling createActivity + +// recordImport separately, so the pair stays atomic from the provider's view. +export async function importActivity( + userId: string, + provider: string, + externalWorkoutId: string, + input: { name: string; gpx?: string }, +): Promise<{ activityId: string }> { + const activityId = await createActivity(userId, { name: input.name, gpx: input.gpx }); + await recordImport(userId, provider, externalWorkoutId, activityId); + return { activityId }; +} + export async function getImportedIds( userId: string, provider: string, diff --git a/apps/planner/app/lib/use-host-election.ts b/apps/planner/app/lib/use-host-election.ts new file mode 100644 index 0000000..9a32652 --- /dev/null +++ b/apps/planner/app/lib/use-host-election.ts @@ -0,0 +1,28 @@ +import { useEffect, useState } from "react"; +import { electHost } from "./host-election.ts"; +import type { YjsState } from "./use-yjs.ts"; + +export function useHostElection(yjs: YjsState | null): boolean { + const [isHost, setIsHost] = useState(false); + + useEffect(() => { + if (!yjs) return; + + const checkHost = () => { + const states = yjs.awareness.getStates() as Map>; + const localId = yjs.awareness.clientID; + const { isHost: amHost, role } = electHost(states, localId); + setIsHost(amHost); + yjs.awareness.setLocalStateField("role", role); + }; + + yjs.awareness.on("change", checkHost); + checkHost(); + + return () => { + yjs.awareness.off("change", checkHost); + }; + }, [yjs]); + + return isHost; +} diff --git a/apps/planner/app/lib/use-routing.ts b/apps/planner/app/lib/use-routing.ts index b329570..a9d897a 100644 --- a/apps/planner/app/lib/use-routing.ts +++ b/apps/planner/app/lib/use-routing.ts @@ -1,7 +1,7 @@ import { useCallback, useEffect, useRef, useState } from "react"; import * as Y from "yjs"; import type { YjsState } from "./use-yjs.ts"; -import { electHost } from "./host-election.ts"; +import { useHostElection } from "./use-host-election.ts"; import { hashNoGoAreas, mergeGeoJsonSegments, @@ -51,7 +51,7 @@ function restoreWaypoints(yjs: YjsState, snapshot: WaypointData[], restoringRef: export type RouteError = "no_route" | "failed" | "rate_limit" | null; export function useRouting(yjs: YjsState | null, sessionId: string) { - const [isHost, setIsHost] = useState(false); + const isHost = useHostElection(yjs); const [computing, setComputing] = useState(false); const [routeError, setRouteError] = useState(null); const [routeStats, setRouteStats] = useState({}); @@ -67,26 +67,6 @@ export function useRouting(yjs: YjsState | null, sessionId: string) { // instead of N-1 on every recompute. const segmentCacheRef = useRef(new SegmentCache()); - // Host election via Yjs awareness - useEffect(() => { - if (!yjs) return; - - const checkHost = () => { - const states = yjs.awareness.getStates() as Map>; - const localId = yjs.awareness.clientID; - const { isHost: amHost, role } = electHost(states, localId); - setIsHost(amHost); - yjs.awareness.setLocalStateField("role", role); - }; - - yjs.awareness.on("change", checkHost); - checkHost(); - - return () => { - yjs.awareness.off("change", checkHost); - }; - }, [yjs]); - const computeRoute = useCallback( async (waypoints: WaypointData[]) => { if (!yjs || !isHost || waypoints.length < 2) return; From 6c5fb6df0e7bccb862ea15b5c0c656722b27e930 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Sun, 10 May 2026 16:02:13 +0200 Subject: [PATCH 019/319] Spec drift catch-up: FIT location, notification payload fields, shared-packages index - wahoo-import: clarify fitToGpx lives at connected-services/fit.ts (shared across providers) not inside the wahoo directory - notifications: correct follow payload field names to followerUsername, followerDisplayName, targetUsername, targetDisplayName (matches code) - shared-packages: add @trails-cool/fit package entry + CAPABILITIES.md index Co-Authored-By: Claude Sonnet 4.6 --- openspec/CAPABILITIES.md | 2 +- openspec/specs/notifications/spec.md | 2 +- openspec/specs/shared-packages/spec.md | 7 +++++++ openspec/specs/wahoo-import/spec.md | 2 +- 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/openspec/CAPABILITIES.md b/openspec/CAPABILITIES.md index f6f179d..f646ce7 100644 --- a/openspec/CAPABILITIES.md +++ b/openspec/CAPABILITIES.md @@ -76,7 +76,7 @@ When adding a new spec, slot it into the most relevant group below and update th - [`secret-management`](specs/secret-management/spec.md) — SOPS-encrypted env files, key rotation. - [`observability`](specs/observability/spec.md) — Prometheus, Loki, Grafana dashboards. - [`background-jobs`](specs/background-jobs/spec.md) — pg-boss queue, cron scheduling, retry policy, handler timeouts shared across the apps. -- [`shared-packages`](specs/shared-packages/spec.md) — workspace package boundaries (`@trails-cool/types`, `@trails-cool/map`, etc.). +- [`shared-packages`](specs/shared-packages/spec.md) — workspace package boundaries (`@trails-cool/types`, `@trails-cool/map`, `@trails-cool/fit`, etc.). ## Conventions diff --git a/openspec/specs/notifications/spec.md b/openspec/specs/notifications/spec.md index 4d11367..9718342 100644 --- a/openspec/specs/notifications/spec.md +++ b/openspec/specs/notifications/spec.md @@ -45,7 +45,7 @@ Each notification row SHALL include a `payload` (JSONB) capturing the denormaliz #### Scenario: follow notifications snapshot the follower / target - **WHEN** a `follow_request_received`, `follow_received`, or `follow_request_approved` notification is created -- **THEN** the row's `payload` records the relevant party's `username` and `displayName`, and `payload_version = 1` +- **THEN** the row's `payload` records `followerUsername`, `followerDisplayName`, `targetUsername`, and `targetDisplayName`, and `payload_version = 1` #### Scenario: activity_published snapshots the activity + owner - **WHEN** an `activity_published` notification is created diff --git a/openspec/specs/shared-packages/spec.md b/openspec/specs/shared-packages/spec.md index 960cc45..f6f0ef9 100644 --- a/openspec/specs/shared-packages/spec.md +++ b/openspec/specs/shared-packages/spec.md @@ -48,6 +48,13 @@ The `@trails-cool/ui` package SHALL provide shared React components (buttons, la - **WHEN** an app renders the Button component from `@trails-cool/ui` - **THEN** a styled button is displayed consistent with the trails.cool design +### Requirement: FIT encoding package +The `@trails-cool/fit` package SHALL provide a `gpxToFitCourse` function that converts a GPX string to a FIT Course binary (`Uint8Array`) suitable for upload to Wahoo and other head units. It is the sole owner of FIT file generation; apps do not bundle their own FIT encoder. See `wahoo-route-push` spec for the full round-trip contract. + +#### Scenario: Import gpxToFitCourse in Journal +- **WHEN** the Journal app imports `@trails-cool/fit` +- **THEN** it has access to `gpxToFitCourse({ gpx, name })` returning a `Uint8Array` + ### Requirement: i18n package The `@trails-cool/i18n` package SHALL provide react-i18next configuration and translation strings starting with English and German. diff --git a/openspec/specs/wahoo-import/spec.md b/openspec/specs/wahoo-import/spec.md index 0f056e3..1cd1932 100644 --- a/openspec/specs/wahoo-import/spec.md +++ b/openspec/specs/wahoo-import/spec.md @@ -95,7 +95,7 @@ Imported activities SHALL show their origin in the UI. - **AND** the workout appears as importable again on the import page ### Requirement: FIT to GPX conversion -The system SHALL convert Wahoo's FIT binary files to GPX format. +The system SHALL convert FIT binary files to GPX format. The conversion logic lives at `apps/journal/app/lib/connected-services/fit.ts` — a provider-agnostic location shared across any future provider that produces FIT files (Garmin, Coros, etc.). Wahoo's importer and webhook both import from this shared module; they do not contain their own copy. #### Scenario: Convert FIT with GPS data - **WHEN** a FIT file contains GPS track records From 34529a9432c2c74d6542e549c7316dc9d3cd658f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Sun, 10 May 2026 16:41:23 +0200 Subject: [PATCH 020/319] Split ElevationChart + PlannerMap into deep modules; add visual regression testing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ElevationChart (1013 lines) split into: - elevation-chart-draw.ts — pure drawElevationChart(ctx, w, h, params) function - use-elevation-data.ts — useElevationData(routeData) hook - ElevationChart.tsx — ~300 lines, interaction + render only PlannerMap (869 lines) split into: - MapHelpers.tsx — 7 Leaflet sub-components (MapExposer, RouteFitter, MapClickHandler, CursorTracker, NoGoAreaButton, OverlaySync, PoiRefresher) - use-waypoint-manager.ts — all waypoint CRUD + route data sync - use-gpx-drop.ts — GPX drag-and-drop hook - PlannerMap.tsx — ~200 lines, orchestration only Add Vitest browser visual regression tests for drawElevationChart via @vitest/browser + Playwright (toMatchScreenshot). Tests cover plain, grade, elevation, surface color modes plus hover and drag-select states. Add update-visual-snapshots.yml workflow: triggered by workflow_dispatch or the `update-snapshots` PR label; commits snapshots back to the branch. Co-Authored-By: Claude Sonnet 4.6 --- .github/workflows/update-visual-snapshots.yml | 103 ++ .../planner/app/components/ElevationChart.tsx | 603 +----------- apps/planner/app/components/MapHelpers.tsx | 275 ++++++ apps/planner/app/components/PlannerMap.tsx | 898 +++--------------- .../lib/elevation-chart-draw.browser.test.tsx | 90 ++ apps/planner/app/lib/elevation-chart-draw.ts | 289 ++++++ apps/planner/app/lib/use-elevation-data.ts | 98 ++ apps/planner/app/lib/use-gpx-drop.ts | 77 ++ apps/planner/app/lib/use-waypoint-manager.ts | 286 ++++++ apps/planner/package.json | 7 +- apps/planner/vitest.browser.config.ts | 33 + apps/planner/vitest.config.ts | 4 + pnpm-lock.yaml | 323 ++++++- 13 files changed, 1764 insertions(+), 1322 deletions(-) create mode 100644 .github/workflows/update-visual-snapshots.yml create mode 100644 apps/planner/app/components/MapHelpers.tsx create mode 100644 apps/planner/app/lib/elevation-chart-draw.browser.test.tsx create mode 100644 apps/planner/app/lib/elevation-chart-draw.ts create mode 100644 apps/planner/app/lib/use-elevation-data.ts create mode 100644 apps/planner/app/lib/use-gpx-drop.ts create mode 100644 apps/planner/app/lib/use-waypoint-manager.ts create mode 100644 apps/planner/vitest.browser.config.ts diff --git a/.github/workflows/update-visual-snapshots.yml b/.github/workflows/update-visual-snapshots.yml new file mode 100644 index 0000000..0d45db9 --- /dev/null +++ b/.github/workflows/update-visual-snapshots.yml @@ -0,0 +1,103 @@ +name: Update visual snapshots + +# How to use this workflow +# ======================== +# +# Visual snapshots live in `apps/planner/app/**/__screenshots__/` and are +# committed to the repo. They are generated by Vitest browser mode running +# the Planner's `*.browser.test.tsx` files against real Chromium via Playwright. +# +# When to update snapshots: +# - You intentionally changed the look of the elevation chart (new color mode, +# layout change, etc.) and the old snapshots are now wrong. +# - You added a new `*.browser.test.tsx` test and need the initial snapshots. +# +# Two ways to trigger this workflow: +# +# 1. Manual dispatch (workflow_dispatch): +# Go to Actions → "Update visual snapshots" → "Run workflow". +# Choose the branch you want updated. The workflow will commit the new +# snapshots back to that branch. +# +# 2. PR label (update-snapshots): +# Add the `update-snapshots` label to any PR. The workflow will update +# snapshots on the PR's head branch. Remove the label after to avoid +# re-triggering on every subsequent push. +# +# After the workflow commits updated snapshots, pull the branch locally: +# git pull origin +# +# Running locally: +# pnpm --filter @trails-cool/planner test:visual # run tests +# pnpm --filter @trails-cool/planner test:visual:update # update snapshots +# +# Platform note: +# Snapshots are generated on ubuntu-latest to keep CI and local results +# consistent. Snapshots generated on macOS or Windows will have subtle +# font-rendering differences and will fail on CI. Always use this workflow +# (or a Linux machine / Docker) to produce the canonical snapshots. + +on: + workflow_dispatch: + inputs: + branch: + description: "Branch to update snapshots on" + required: false + default: "" + + pull_request: + types: [labeled] + +jobs: + update-snapshots: + # Only run for manual dispatch, or when the label is "update-snapshots" + if: > + github.event_name == 'workflow_dispatch' || + (github.event_name == 'pull_request' && github.event.label.name == 'update-snapshots') + + runs-on: ubuntu-latest + + permissions: + contents: write # needed to push snapshot commits back + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.ref || github.event.inputs.branch || github.ref }} + # Use a token with push rights so the commit-back step can push + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Setup pnpm + uses: pnpm/action-setup@v4 + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version-file: ".nvmrc" + cache: "pnpm" + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Install Playwright Chromium + run: pnpm exec playwright install chromium --with-deps + + - name: Update visual snapshots + run: pnpm --filter @trails-cool/planner test:visual:update + + - name: Commit updated snapshots + uses: stefanzweifel/git-auto-commit-action@v5 + with: + commit_message: "chore: update visual snapshots [skip ci]" + file_pattern: "apps/planner/app/**/__screenshots__/**" + commit_user_name: "github-actions[bot]" + commit_user_email: "github-actions[bot]@users.noreply.github.com" + + - name: Upload snapshots as artifact + if: always() + uses: actions/upload-artifact@v4 + with: + name: visual-snapshots + path: apps/planner/app/**/__screenshots__/ + if-no-files-found: ignore diff --git a/apps/planner/app/components/ElevationChart.tsx b/apps/planner/app/components/ElevationChart.tsx index 5d5e006..392f8cb 100644 --- a/apps/planner/app/components/ElevationChart.tsx +++ b/apps/planner/app/components/ElevationChart.tsx @@ -3,74 +3,17 @@ import { useTranslation } from "react-i18next"; import type { DayStage } from "@trails-cool/gpx"; import type { YjsState } from "~/lib/use-yjs"; import { - elevationColor, maxspeedColor, - SURFACE_COLORS, DEFAULT_SURFACE_COLOR, - HIGHWAY_COLORS, DEFAULT_HIGHWAY_COLOR, - SMOOTHNESS_COLORS, DEFAULT_SMOOTHNESS_COLOR, - TRACKTYPE_COLORS, DEFAULT_TRACKTYPE_COLOR, - CYCLEWAY_COLORS, DEFAULT_CYCLEWAY_COLOR, - BIKEROUTE_COLORS, DEFAULT_BIKEROUTE_COLOR, + SURFACE_COLORS, + DEFAULT_SURFACE_COLOR, + HIGHWAY_COLORS, + DEFAULT_HIGHWAY_COLOR, + SMOOTHNESS_COLORS, + DEFAULT_SMOOTHNESS_COLOR, + CYCLEWAY_COLORS, + DEFAULT_CYCLEWAY_COLOR, } from "@trails-cool/map-core"; -import type { ColorMode } from "~/components/ColoredRoute"; - -function gradeColor(grade: number): string { - const absGrade = Math.abs(grade); - if (absGrade < 3) return "#22c55e"; // green: flat/gentle - if (absGrade < 6) return "#eab308"; // yellow: moderate - if (absGrade < 10) return "#f97316"; // orange: steep - if (absGrade < 15) return "#ef4444"; // red: very steep - return "#991b1b"; // dark red: extreme -} - -interface ElevationPoint { - distance: number; - elevation: number; - lat: number; - lon: number; -} - -function extractElevation(geojsonStr: string): ElevationPoint[] { - try { - const geojson = JSON.parse(geojsonStr); - const coords: number[][] = geojson.features?.[0]?.geometry?.coordinates ?? []; - if (coords.length === 0) return []; - - const points: ElevationPoint[] = []; - let totalDist = 0; - - for (let i = 0; i < coords.length; i++) { - if (i > 0) { - const prev = coords[i - 1]!; - const curr = coords[i]!; - totalDist += haversine(prev[1]!, prev[0]!, curr[1]!, curr[0]!); - } - if (coords[i]![2] !== undefined) { - points.push({ - distance: totalDist, - elevation: coords[i]![2]!, - lat: coords[i]![1]!, - lon: coords[i]![0]!, - }); - } - } - return points; - } catch { - return []; - } -} - -function haversine(lat1: number, lon1: number, lat2: number, lon2: number): number { - const R = 6371000; - const toRad = (d: number) => (d * Math.PI) / 180; - const dLat = toRad(lat2 - lat1); - const dLon = toRad(lon2 - lon1); - const a = - Math.sin(dLat / 2) ** 2 + - Math.cos(toRad(lat1)) * Math.cos(toRad(lat2)) * Math.sin(dLon / 2) ** 2; - return R * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); -} - -const PADDING = { top: 10, right: 10, bottom: 25, left: 40 }; +import { drawElevationChart, PADDING } from "~/lib/elevation-chart-draw"; +import { useElevationData } from "~/lib/use-elevation-data"; interface ElevationChartProps { yjs: YjsState; @@ -83,19 +26,9 @@ interface ElevationChartProps { export function ElevationChart({ yjs, onHover, highlightDistance, onClickPosition, onDragSelect, days }: ElevationChartProps) { const { t } = useTranslation("planner"); - const [points, setPoints] = useState([]); + const { points, colorMode, surfaces, highways, maxspeeds, smoothnesses, tracktypes, cycleways, bikeroutes } = useElevationData(yjs.routeData); const [hoverIdx, setHoverIdx] = useState(null); - const [colorMode, setColorMode] = useState("plain"); - const [surfaces, setSurfaces] = useState([]); - const [highways, setHighways] = useState([]); - const [maxspeeds, setMaxspeeds] = useState([]); - const [smoothnesses, setSmoothnesses] = useState([]); - const [tracktypes, setTracktypes] = useState([]); - const [cycleways, setCycleways] = useState([]); - const [bikeroutes, setBikeroutes] = useState([]); const canvasRef = useRef(null); - const pointsRef = useRef([]); - pointsRef.current = points; const isExternalHover = useRef(false); const dragStartX = useRef(null); const dragStartClientX = useRef(null); @@ -124,68 +57,9 @@ export function ElevationChart({ yjs, onHover, highlightDistance, onClickPositio } isExternalHover.current = true; setHoverIdx(closest); - // Do NOT call onHover here to avoid feedback loop }, [highlightDistance, points]); - useEffect(() => { - const update = () => { - const geojson = yjs.routeData.get("geojson") as string | undefined; - if (geojson) { - setPoints(extractElevation(geojson)); - } else { - setPoints([]); - } - const mode = yjs.routeData.get("colorMode") as ColorMode | undefined; - setColorMode(mode ?? "plain"); - const surfacesJson = yjs.routeData.get("surfaces") as string | undefined; - if (surfacesJson) { - try { setSurfaces(JSON.parse(surfacesJson)); } catch { setSurfaces([]); } - } else { - setSurfaces([]); - } - const highwaysJson = yjs.routeData.get("highways") as string | undefined; - if (highwaysJson) { - try { setHighways(JSON.parse(highwaysJson)); } catch { setHighways([]); } - } else { - setHighways([]); - } - const maxspeedsJson = yjs.routeData.get("maxspeeds") as string | undefined; - if (maxspeedsJson) { - try { setMaxspeeds(JSON.parse(maxspeedsJson)); } catch { setMaxspeeds([]); } - } else { - setMaxspeeds([]); - } - const smoothnessesJson = yjs.routeData.get("smoothnesses") as string | undefined; - if (smoothnessesJson) { - try { setSmoothnesses(JSON.parse(smoothnessesJson)); } catch { setSmoothnesses([]); } - } else { - setSmoothnesses([]); - } - const tracktypesJson = yjs.routeData.get("tracktypes") as string | undefined; - if (tracktypesJson) { - try { setTracktypes(JSON.parse(tracktypesJson)); } catch { setTracktypes([]); } - } else { - setTracktypes([]); - } - const cyclewaysJson = yjs.routeData.get("cycleways") as string | undefined; - if (cyclewaysJson) { - try { setCycleways(JSON.parse(cyclewaysJson)); } catch { setCycleways([]); } - } else { - setCycleways([]); - } - const bikeroutesJson = yjs.routeData.get("bikeroutes") as string | undefined; - if (bikeroutesJson) { - try { setBikeroutes(JSON.parse(bikeroutesJson)); } catch { setBikeroutes([]); } - } else { - setBikeroutes([]); - } - }; - yjs.routeData.observe(update); - update(); - return () => yjs.routeData.unobserve(update); - }, [yjs.routeData]); - - const drawChart = useCallback( + const draw = useCallback( (highlightIdx: number | null) => { const canvas = canvasRef.current; if (!canvas || points.length < 2) return; @@ -199,384 +73,29 @@ export function ElevationChart({ yjs, onHover, highlightDistance, onClickPositio canvas.height = rect.height * dpr; ctx.scale(dpr, dpr); - const w = rect.width; - const h = rect.height; - const chartW = w - PADDING.left - PADDING.right; - const chartH = h - PADDING.top - PADDING.bottom; - - const maxDist = points[points.length - 1]!.distance; - const elevations = points.map((p) => p.elevation); - const minEle = Math.min(...elevations); - const maxEle = Math.max(...elevations); - const eleRange = maxEle - minEle || 1; - - const toX = (d: number) => PADDING.left + (d / maxDist) * chartW; - const toY = (e: number) => PADDING.top + chartH - ((e - minEle) / eleRange) * chartH; - - ctx.clearRect(0, 0, w, h); - - if (colorMode === "grade") { - // Grade-colored segments: color by steepness - for (let i = 0; i < points.length - 1; i++) { - const p0 = points[i]!; - const p1 = points[i + 1]!; - const dDist = p1.distance - p0.distance; - const grade = dDist > 0 ? ((p1.elevation - p0.elevation) / dDist) * 100 : 0; - const color = gradeColor(grade); - - // Fill segment - ctx.beginPath(); - ctx.moveTo(toX(p0.distance), PADDING.top + chartH); - ctx.lineTo(toX(p0.distance), toY(p0.elevation)); - ctx.lineTo(toX(p1.distance), toY(p1.elevation)); - ctx.lineTo(toX(p1.distance), PADDING.top + chartH); - ctx.closePath(); - ctx.fillStyle = color.replace(")", ", 0.25)").replace("rgb", "rgba").replace("#", ""); - // hex to rgba fill - ctx.fillStyle = color + "40"; - ctx.fill(); - - // Line segment - ctx.beginPath(); - ctx.moveTo(toX(p0.distance), toY(p0.elevation)); - ctx.lineTo(toX(p1.distance), toY(p1.elevation)); - ctx.strokeStyle = color; - ctx.lineWidth = 2; - ctx.stroke(); - } - } else if (colorMode === "elevation") { - // Elevation-colored fill and line segments - for (let i = 0; i < points.length - 1; i++) { - const p0 = points[i]!; - const p1 = points[i + 1]!; - const t = (p0.elevation - minEle) / eleRange; - const color = elevationColor(t); - - // Fill segment - ctx.beginPath(); - ctx.moveTo(toX(p0.distance), PADDING.top + chartH); - ctx.lineTo(toX(p0.distance), toY(p0.elevation)); - ctx.lineTo(toX(p1.distance), toY(p1.elevation)); - ctx.lineTo(toX(p1.distance), PADDING.top + chartH); - ctx.closePath(); - ctx.fillStyle = color.replace("rgb", "rgba").replace(")", ", 0.2)"); - ctx.fill(); - - // Line segment - ctx.beginPath(); - ctx.moveTo(toX(p0.distance), toY(p0.elevation)); - ctx.lineTo(toX(p1.distance), toY(p1.elevation)); - ctx.strokeStyle = color; - ctx.lineWidth = 2; - ctx.stroke(); - } - } else if (colorMode === "surface" && surfaces.length >= points.length) { - // Surface-colored segments - for (let i = 0; i < points.length - 1; i++) { - const p0 = points[i]!; - const p1 = points[i + 1]!; - const surface = surfaces[i] ?? "unknown"; - const color = SURFACE_COLORS[surface] ?? DEFAULT_SURFACE_COLOR; - - ctx.beginPath(); - ctx.moveTo(toX(p0.distance), PADDING.top + chartH); - ctx.lineTo(toX(p0.distance), toY(p0.elevation)); - ctx.lineTo(toX(p1.distance), toY(p1.elevation)); - ctx.lineTo(toX(p1.distance), PADDING.top + chartH); - ctx.closePath(); - ctx.fillStyle = color + "40"; - ctx.fill(); - - ctx.beginPath(); - ctx.moveTo(toX(p0.distance), toY(p0.elevation)); - ctx.lineTo(toX(p1.distance), toY(p1.elevation)); - ctx.strokeStyle = color; - ctx.lineWidth = 2; - ctx.stroke(); - } - } else if (colorMode === "highway" && highways.length >= points.length) { - // Highway-colored segments - for (let i = 0; i < points.length - 1; i++) { - const p0 = points[i]!; - const p1 = points[i + 1]!; - const highway = highways[i] ?? "unknown"; - const color = HIGHWAY_COLORS[highway] ?? DEFAULT_HIGHWAY_COLOR; - - ctx.beginPath(); - ctx.moveTo(toX(p0.distance), PADDING.top + chartH); - ctx.lineTo(toX(p0.distance), toY(p0.elevation)); - ctx.lineTo(toX(p1.distance), toY(p1.elevation)); - ctx.lineTo(toX(p1.distance), PADDING.top + chartH); - ctx.closePath(); - ctx.fillStyle = color + "40"; - ctx.fill(); - - ctx.beginPath(); - ctx.moveTo(toX(p0.distance), toY(p0.elevation)); - ctx.lineTo(toX(p1.distance), toY(p1.elevation)); - ctx.strokeStyle = color; - ctx.lineWidth = 2; - ctx.stroke(); - } - } else if (colorMode === "maxspeed" && maxspeeds.length >= points.length) { - // Maxspeed-colored segments - for (let i = 0; i < points.length - 1; i++) { - const p0 = points[i]!; - const p1 = points[i + 1]!; - const speed = maxspeeds[i] ?? "unknown"; - const color = maxspeedColor(speed); - - ctx.beginPath(); - ctx.moveTo(toX(p0.distance), PADDING.top + chartH); - ctx.lineTo(toX(p0.distance), toY(p0.elevation)); - ctx.lineTo(toX(p1.distance), toY(p1.elevation)); - ctx.lineTo(toX(p1.distance), PADDING.top + chartH); - ctx.closePath(); - ctx.fillStyle = color + "40"; - ctx.fill(); - - ctx.beginPath(); - ctx.moveTo(toX(p0.distance), toY(p0.elevation)); - ctx.lineTo(toX(p1.distance), toY(p1.elevation)); - ctx.strokeStyle = color; - ctx.lineWidth = 2; - ctx.stroke(); - } - } else if (colorMode === "smoothness" && smoothnesses.length >= points.length) { - // Smoothness-colored segments - for (let i = 0; i < points.length - 1; i++) { - const p0 = points[i]!; - const p1 = points[i + 1]!; - const smoothness = smoothnesses[i] ?? "unknown"; - const color = SMOOTHNESS_COLORS[smoothness] ?? DEFAULT_SMOOTHNESS_COLOR; - - ctx.beginPath(); - ctx.moveTo(toX(p0.distance), PADDING.top + chartH); - ctx.lineTo(toX(p0.distance), toY(p0.elevation)); - ctx.lineTo(toX(p1.distance), toY(p1.elevation)); - ctx.lineTo(toX(p1.distance), PADDING.top + chartH); - ctx.closePath(); - ctx.fillStyle = color + "40"; - ctx.fill(); - - ctx.beginPath(); - ctx.moveTo(toX(p0.distance), toY(p0.elevation)); - ctx.lineTo(toX(p1.distance), toY(p1.elevation)); - ctx.strokeStyle = color; - ctx.lineWidth = 2; - ctx.stroke(); - } - } else if (colorMode === "tracktype" && tracktypes.length >= points.length) { - // Track type-colored segments - for (let i = 0; i < points.length - 1; i++) { - const p0 = points[i]!; - const p1 = points[i + 1]!; - const tracktype = tracktypes[i] ?? "unknown"; - const color = TRACKTYPE_COLORS[tracktype] ?? DEFAULT_TRACKTYPE_COLOR; - - ctx.beginPath(); - ctx.moveTo(toX(p0.distance), PADDING.top + chartH); - ctx.lineTo(toX(p0.distance), toY(p0.elevation)); - ctx.lineTo(toX(p1.distance), toY(p1.elevation)); - ctx.lineTo(toX(p1.distance), PADDING.top + chartH); - ctx.closePath(); - ctx.fillStyle = color + "40"; - ctx.fill(); - - ctx.beginPath(); - ctx.moveTo(toX(p0.distance), toY(p0.elevation)); - ctx.lineTo(toX(p1.distance), toY(p1.elevation)); - ctx.strokeStyle = color; - ctx.lineWidth = 2; - ctx.stroke(); - } - } else if (colorMode === "cycleway" && cycleways.length >= points.length) { - // Cycleway-colored segments - for (let i = 0; i < points.length - 1; i++) { - const p0 = points[i]!; - const p1 = points[i + 1]!; - const cycleway = cycleways[i] ?? "unknown"; - const color = CYCLEWAY_COLORS[cycleway] ?? DEFAULT_CYCLEWAY_COLOR; - - ctx.beginPath(); - ctx.moveTo(toX(p0.distance), PADDING.top + chartH); - ctx.lineTo(toX(p0.distance), toY(p0.elevation)); - ctx.lineTo(toX(p1.distance), toY(p1.elevation)); - ctx.lineTo(toX(p1.distance), PADDING.top + chartH); - ctx.closePath(); - ctx.fillStyle = color + "40"; - ctx.fill(); - - ctx.beginPath(); - ctx.moveTo(toX(p0.distance), toY(p0.elevation)); - ctx.lineTo(toX(p1.distance), toY(p1.elevation)); - ctx.strokeStyle = color; - ctx.lineWidth = 2; - ctx.stroke(); - } - } else if (colorMode === "bikeroute" && bikeroutes.length >= points.length) { - // Bike route-colored segments - for (let i = 0; i < points.length - 1; i++) { - const p0 = points[i]!; - const p1 = points[i + 1]!; - const bikeroute = bikeroutes[i] ?? "none"; - const color = BIKEROUTE_COLORS[bikeroute] ?? DEFAULT_BIKEROUTE_COLOR; - - ctx.beginPath(); - ctx.moveTo(toX(p0.distance), PADDING.top + chartH); - ctx.lineTo(toX(p0.distance), toY(p0.elevation)); - ctx.lineTo(toX(p1.distance), toY(p1.elevation)); - ctx.lineTo(toX(p1.distance), PADDING.top + chartH); - ctx.closePath(); - ctx.fillStyle = color + "40"; - ctx.fill(); - - ctx.beginPath(); - ctx.moveTo(toX(p0.distance), toY(p0.elevation)); - ctx.lineTo(toX(p1.distance), toY(p1.elevation)); - ctx.strokeStyle = color; - ctx.lineWidth = 2; - ctx.stroke(); - } - } else { - // Plain fill and line - ctx.beginPath(); - ctx.moveTo(PADDING.left, PADDING.top + chartH); - for (const p of points) { - ctx.lineTo(toX(p.distance), toY(p.elevation)); - } - ctx.lineTo(PADDING.left + chartW, PADDING.top + chartH); - ctx.closePath(); - ctx.fillStyle = "rgba(37, 99, 235, 0.15)"; - ctx.fill(); - - ctx.beginPath(); - for (let i = 0; i < points.length; i++) { - const p = points[i]!; - if (i === 0) ctx.moveTo(toX(p.distance), toY(p.elevation)); - else ctx.lineTo(toX(p.distance), toY(p.elevation)); - } - ctx.strokeStyle = "#2563eb"; - ctx.lineWidth = 1.5; - ctx.stroke(); - } - - // Axis labels - ctx.fillStyle = "#6b7280"; - ctx.font = "10px sans-serif"; - ctx.textAlign = "right"; - ctx.fillText(`${Math.round(maxEle)}m`, PADDING.left - 4, PADDING.top + 10); - ctx.fillText(`${Math.round(minEle)}m`, PADDING.left - 4, PADDING.top + chartH); - ctx.textAlign = "center"; - ctx.fillText("0 km", PADDING.left, h - 4); - ctx.fillText(`${(maxDist / 1000).toFixed(1)} km`, PADDING.left + chartW, h - 4); - - // Day dividers - if (days && days.length > 1) { - for (let d = 0; d < days.length - 1; d++) { - // Find the point closest to the day boundary distance - const boundaryDist = days.slice(0, d + 1).reduce((sum, s) => sum + s.distance, 0); - const bx = toX(boundaryDist); - - // Dashed vertical line - ctx.beginPath(); - ctx.setLineDash([4, 3]); - ctx.moveTo(bx, PADDING.top); - ctx.lineTo(bx, PADDING.top + chartH); - ctx.strokeStyle = "#9A9484"; - ctx.lineWidth = 1; - ctx.stroke(); - ctx.setLineDash([]); - - // Day label at top - ctx.fillStyle = "#9A9484"; - ctx.font = "9px sans-serif"; - ctx.textAlign = "center"; - ctx.fillText(`${(boundaryDist / 1000).toFixed(0)} km`, bx, h - 4); - } - } - - // Hover crosshair + info - if (highlightIdx !== null && highlightIdx >= 0 && highlightIdx < points.length) { - const p = points[highlightIdx]!; - const hx = toX(p.distance); - const hy = toY(p.elevation); - - // Vertical line - ctx.beginPath(); - ctx.moveTo(hx, PADDING.top); - ctx.lineTo(hx, PADDING.top + chartH); - ctx.strokeStyle = "rgba(239, 68, 68, 0.5)"; - ctx.lineWidth = 1; - ctx.stroke(); - - // Dot - ctx.beginPath(); - ctx.arc(hx, hy, 4, 0, Math.PI * 2); - ctx.fillStyle = "#ef4444"; - ctx.fill(); - ctx.strokeStyle = "white"; - ctx.lineWidth = 2; - ctx.stroke(); - - // Info label - ctx.fillStyle = "#1f2937"; - ctx.font = "bold 10px sans-serif"; - ctx.textAlign = "left"; - let label = `${Math.round(p.elevation)}m · ${(p.distance / 1000).toFixed(1)}km`; - if (colorMode === "grade" && highlightIdx > 0) { - const prev = points[highlightIdx - 1]!; - const dDist = p.distance - prev.distance; - const grade = dDist > 0 ? ((p.elevation - prev.elevation) / dDist) * 100 : 0; - label += ` · ${grade > 0 ? "+" : ""}${grade.toFixed(1)}%`; - } - if (colorMode === "surface" && surfaces[highlightIdx]) { - label += ` · ${surfaces[highlightIdx]}`; - } - if (colorMode === "highway" && highways[highlightIdx]) { - label += ` · ${highways[highlightIdx]}`; - } - if (colorMode === "maxspeed" && maxspeeds[highlightIdx]) { - const s = maxspeeds[highlightIdx]!; - label += ` · ${s === "unknown" ? s : `${s} km/h`}`; - } - if (colorMode === "smoothness" && smoothnesses[highlightIdx]) { - label += ` · ${smoothnesses[highlightIdx]}`; - } - if (colorMode === "tracktype" && tracktypes[highlightIdx]) { - label += ` · ${tracktypes[highlightIdx]}`; - } - if (colorMode === "cycleway" && cycleways[highlightIdx]) { - label += ` · ${cycleways[highlightIdx]}`; - } - if (colorMode === "bikeroute" && bikeroutes[highlightIdx]) { - const names: Record = { icn: "International", ncn: "National", rcn: "Regional", lcn: "Local", none: "None" }; - label += ` · ${names[bikeroutes[highlightIdx]!] ?? bikeroutes[highlightIdx]}`; - } - const labelX = hx + 8 > w - 80 ? hx - 8 : hx + 8; - ctx.textAlign = hx + 8 > w - 80 ? "right" : "left"; - ctx.fillText(label, labelX, PADDING.top + 10); - } - - // Drag selection overlay - if (isDragging.current && dragStartX.current != null && dragCurrentX.current != null) { - const x1 = Math.max(PADDING.left, Math.min(dragStartX.current, PADDING.left + chartW)); - const x2 = Math.max(PADDING.left, Math.min(dragCurrentX.current, PADDING.left + chartW)); - const selLeft = Math.min(x1, x2); - const selRight = Math.max(x1, x2); - ctx.fillStyle = "rgba(59, 130, 246, 0.15)"; - ctx.fillRect(selLeft, PADDING.top, selRight - selLeft, chartH); - ctx.strokeStyle = "rgba(59, 130, 246, 0.5)"; - ctx.lineWidth = 1; - ctx.strokeRect(selLeft, PADDING.top, selRight - selLeft, chartH); - } + drawElevationChart(ctx, rect.width, rect.height, { + points, + colorMode, + surfaces, + highways, + maxspeeds, + smoothnesses, + tracktypes, + cycleways, + bikeroutes, + hoverIdx: highlightIdx, + isDragging: isDragging.current, + dragStartX: dragStartX.current, + dragCurrentX: dragCurrentX.current, + days, + }); }, - [points, colorMode, surfaces, highways, maxspeeds, smoothnesses, tracktypes, cycleways, bikeroutes, days, t], + [points, colorMode, surfaces, highways, maxspeeds, smoothnesses, tracktypes, cycleways, bikeroutes, days], ); useEffect(() => { - drawChart(hoverIdx); - }, [points, hoverIdx, colorMode, drawChart]); + draw(hoverIdx); + }, [points, hoverIdx, colorMode, draw]); const handleMouseMove = useCallback( (e: React.MouseEvent) => { @@ -588,13 +107,12 @@ export function ElevationChart({ yjs, onHover, highlightDistance, onClickPositio const chartW = rect.width - PADDING.left - PADDING.right; const ratio = (mouseX - PADDING.left) / chartW; - // Handle drag selection if (dragStartClientX.current != null) { const dx = Math.abs(e.clientX - dragStartClientX.current); if (dx > 5) { isDragging.current = true; dragCurrentX.current = mouseX; - drawChart(hoverIdx); + draw(hoverIdx); return; } } @@ -608,7 +126,6 @@ export function ElevationChart({ yjs, onHover, highlightDistance, onClickPositio const maxDist = points[points.length - 1]!.distance; const targetDist = ratio * maxDist; - // Find closest point let closest = 0; let minDiff = Infinity; for (let i = 0; i < points.length; i++) { @@ -624,7 +141,7 @@ export function ElevationChart({ yjs, onHover, highlightDistance, onClickPositio const p = points[closest]!; onHover?.([p.lat, p.lon]); }, - [points, onHover, hoverIdx, drawChart], + [points, onHover, hoverIdx, draw], ); const handleMouseLeave = useCallback(() => { @@ -636,18 +153,15 @@ export function ElevationChart({ yjs, onHover, highlightDistance, onClickPositio dragCurrentX.current = null; }, [onHover]); - const handleMouseDown = useCallback( - (e: React.MouseEvent) => { - const canvas = canvasRef.current; - if (!canvas) return; - const rect = canvas.getBoundingClientRect(); - dragStartX.current = e.clientX - rect.left; - dragStartClientX.current = e.clientX; - isDragging.current = false; - dragCurrentX.current = null; - }, - [], - ); + const handleMouseDown = useCallback((e: React.MouseEvent) => { + const canvas = canvasRef.current; + if (!canvas) return; + const rect = canvas.getBoundingClientRect(); + dragStartX.current = e.clientX - rect.left; + dragStartClientX.current = e.clientX; + isDragging.current = false; + dragCurrentX.current = null; + }, []); const handleMouseUp = useCallback( (e: React.MouseEvent) => { @@ -665,14 +179,12 @@ export function ElevationChart({ yjs, onHover, highlightDistance, onClickPositio const maxDist = points[points.length - 1]!.distance; if (isDragging.current && dragStartX.current != null) { - // Drag-select: compute bounding box of selected range const endX = e.clientX - rect.left; const startRatio = Math.max(0, Math.min(1, (dragStartX.current - PADDING.left) / chartW)); const endRatio = Math.max(0, Math.min(1, (endX - PADDING.left) / chartW)); const startDist = Math.min(startRatio, endRatio) * maxDist; const endDist = Math.max(startRatio, endRatio) * maxDist; - // Find all points in the selected distance range let minLat = Infinity, maxLat = -Infinity, minLon = Infinity, maxLon = -Infinity; let found = false; for (const p of points) { @@ -684,12 +196,10 @@ export function ElevationChart({ yjs, onHover, highlightDistance, onClickPositio found = true; } } - if (found && onDragSelect) { onDragSelect([[minLat, minLon], [maxLat, maxLon]]); } } else if (dragStartClientX.current != null) { - // Click (not drag): pan map to clicked point const dx = Math.abs(e.clientX - dragStartClientX.current); if (dx <= 5 && onClickPosition) { const mouseX = e.clientX - rect.left; @@ -705,8 +215,7 @@ export function ElevationChart({ yjs, onHover, highlightDistance, onClickPositio closest = i; } } - const p = points[closest]!; - onClickPosition([p.lat, p.lon]); + onClickPosition([points[closest]!.lat, points[closest]!.lon]); } } } @@ -715,12 +224,11 @@ export function ElevationChart({ yjs, onHover, highlightDistance, onClickPositio dragStartClientX.current = null; isDragging.current = false; dragCurrentX.current = null; - drawChart(hoverIdx); + draw(hoverIdx); }, - [points, onClickPosition, onDragSelect, hoverIdx, drawChart], + [points, onClickPosition, onDragSelect, hoverIdx, draw], ); - // Touch handlers for mobile const handleTouchStart = useCallback( (e: React.TouchEvent) => { e.preventDefault(); @@ -729,13 +237,11 @@ export function ElevationChart({ yjs, onHover, highlightDistance, onClickPositio const rect = canvas.getBoundingClientRect(); if (e.touches.length === 1) { - // Single touch: start scrub + potential drag const x = e.touches[0]!.clientX - rect.left; dragStartX.current = x; dragStartClientX.current = e.touches[0]!.clientX; isDragging.current = false; dragCurrentX.current = null; - // Immediately show highlight at touch position const chartW = rect.width - PADDING.left - PADDING.right; const ratio = (x - PADDING.left) / chartW; if (ratio >= 0 && ratio <= 1 && points.length >= 2) { @@ -753,16 +259,15 @@ export function ElevationChart({ yjs, onHover, highlightDistance, onClickPositio onHover?.([p.lat, p.lon]); } } else if (e.touches.length === 2) { - // Two fingers: range select const x1 = e.touches[0]!.clientX - rect.left; const x2 = e.touches[1]!.clientX - rect.left; dragStartX.current = Math.min(x1, x2); dragCurrentX.current = Math.max(x1, x2); isDragging.current = true; - drawChart(hoverIdx); + draw(hoverIdx); } }, - [points, onHover, hoverIdx, drawChart], + [points, onHover, hoverIdx, draw], ); const handleTouchMove = useCallback( @@ -773,7 +278,6 @@ export function ElevationChart({ yjs, onHover, highlightDistance, onClickPositio const rect = canvas.getBoundingClientRect(); if (e.touches.length === 1 && !isDragging.current) { - // Single touch scrub: update highlight const x = e.touches[0]!.clientX - rect.left; const chartW = rect.width - PADDING.left - PADDING.right; const ratio = (x - PADDING.left) / chartW; @@ -792,22 +296,20 @@ export function ElevationChart({ yjs, onHover, highlightDistance, onClickPositio onHover?.([p.lat, p.lon]); } } else if (e.touches.length === 2) { - // Two finger range select: update selection const x1 = e.touches[0]!.clientX - rect.left; const x2 = e.touches[1]!.clientX - rect.left; dragStartX.current = Math.min(x1, x2); dragCurrentX.current = Math.max(x1, x2); isDragging.current = true; - drawChart(hoverIdx); + draw(hoverIdx); } }, - [points, onHover, hoverIdx, drawChart], + [points, onHover, hoverIdx, draw], ); const handleTouchEnd = useCallback( (e: React.TouchEvent) => { if (isDragging.current && dragStartX.current != null && dragCurrentX.current != null && points.length >= 2) { - // Two finger range complete: zoom map const canvas = canvasRef.current; if (canvas) { const rect = canvas.getBoundingClientRect(); @@ -834,10 +336,8 @@ export function ElevationChart({ yjs, onHover, highlightDistance, onClickPositio } } } else if (e.changedTouches.length === 1 && onClickPosition && dragStartClientX.current != null) { - // Single tap (no significant movement): pan map const dx = Math.abs(e.changedTouches[0]!.clientX - dragStartClientX.current); if (dx <= 10) { - // Treat as tap → pan const canvas = canvasRef.current; if (canvas && points.length >= 2) { const rect = canvas.getBoundingClientRect(); @@ -859,16 +359,15 @@ export function ElevationChart({ yjs, onHover, highlightDistance, onClickPositio } } - // Clear highlight on touch end setHoverIdx(null); onHover?.(null); dragStartX.current = null; dragStartClientX.current = null; isDragging.current = false; dragCurrentX.current = null; - drawChart(null); + draw(null); }, - [points, onHover, onClickPosition, onDragSelect, drawChart], + [points, onHover, onClickPosition, onDragSelect, draw], ); const setMode = useCallback((mode: string) => { diff --git a/apps/planner/app/components/MapHelpers.tsx b/apps/planner/app/components/MapHelpers.tsx new file mode 100644 index 0000000..73753d4 --- /dev/null +++ b/apps/planner/app/components/MapHelpers.tsx @@ -0,0 +1,275 @@ +import { useEffect, useState, useRef } from "react"; +import { useMap, useMapEvents, Marker } from "react-leaflet"; +import L from "leaflet"; +import type { YjsState } from "~/lib/use-yjs"; +import { overlayLayers } from "@trails-cool/map"; +import { usePois } from "~/lib/use-pois"; +import { Z_CURSOR } from "@trails-cool/map-core"; + +// Exposes the Leaflet map instance on window.__leafletMap for E2E testing and external integrations. +export function MapExposer() { + const map = useMap(); + useEffect(() => { + if (typeof window !== "undefined") { + (window as unknown as Record).__leafletMap = map; + } + }, [map]); + return null; +} + +// Fits the map to the route bounds once on first load. +export function RouteFitter({ coordinates }: { coordinates: [number, number, number][] | null }) { + const map = useMap(); + const hasFitted = useRef(false); + + useEffect(() => { + if (hasFitted.current || !coordinates || coordinates.length < 2) return; + + const bounds = L.latLngBounds( + coordinates.map((c) => [c[1]!, c[0]!] as [number, number]), + ); + if (!bounds.isValid()) return; + + const raf = requestAnimationFrame(() => { + map.invalidateSize(); + map.fitBounds(bounds, { padding: [50, 50], maxZoom: 16 }); + hasFitted.current = true; + }); + return () => cancelAnimationFrame(raf); + }, [coordinates, map]); + + return null; +} + +// Routes map click events to a callback, with a suppressRef for one-shot suppression (e.g. after route insert). +export function MapClickHandler({ + onAdd, + suppressRef, +}: { + onAdd: (lat: number, lng: number) => void; + suppressRef: React.RefObject; +}) { + useMapEvents({ + click(e) { + if (suppressRef.current) { + suppressRef.current = false; + return; + } + onAdd(e.latlng.lat, e.latlng.lng); + }, + }); + return null; +} + +// Broadcasts the local user's cursor position via Yjs awareness and renders remote cursors. +export function CursorTracker({ awareness }: { awareness: YjsState["awareness"] }) { + const map = useMap(); + const [cursors, setCursors] = useState< + Map + >(new Map()); + + useEffect(() => { + const localId = awareness.clientID; + + const handleMouseMove = (e: L.LeafletMouseEvent) => { + awareness.setLocalStateField("mapCursor", { lat: e.latlng.lat, lng: e.latlng.lng }); + }; + const handleMouseOut = () => { + awareness.setLocalStateField("mapCursor", null); + }; + + map.on("mousemove", handleMouseMove); + map.on("mouseout", handleMouseOut); + + const updateCursors = () => { + const states = awareness.getStates(); + const newCursors = new Map(); + states.forEach((state, clientId) => { + if (clientId !== localId && state.mapCursor && state.user) { + newCursors.set(clientId, { + lat: state.mapCursor.lat, + lng: state.mapCursor.lng, + color: state.user.color, + name: state.user.name, + }); + } + }); + setCursors(newCursors); + }; + + awareness.on("change", updateCursors); + + return () => { + map.off("mousemove", handleMouseMove); + map.off("mouseout", handleMouseOut); + awareness.off("change", updateCursors); + }; + }, [map, awareness]); + + return ( + <> + {Array.from(cursors.entries()).map(([clientId, cursor]) => ( + + + + + ${cursor.name} + `, + iconSize: [0, 0], + })} + /> + ))} + + ); +} + +// Leaflet control button for toggling no-go area drawing mode. +export function NoGoAreaButton({ active, onClick }: { active: boolean; onClick: () => void }) { + const ref = useRef(null); + + useEffect(() => { + if (ref.current) L.DomEvent.disableClickPropagation(ref.current); + }, []); + + return ( + + ); +} + +// Keeps Yjs routeData and the Leaflet LayersControl in sync (both directions). +export function OverlaySync({ + yjs, + onOverlayChange, + onBaseLayerChange, +}: { + yjs: YjsState; + onOverlayChange: (ids: string[]) => void; + onBaseLayerChange: (name: string) => void; +}) { + const map = useMap(); + const suppressRef = useRef(false); + + useEffect(() => { + const handleAdd = (e: L.LayersControlEvent) => { + if (suppressRef.current) return; + const layer = overlayLayers.find((l) => l.name === e.name); + if (!layer) return; + const raw = yjs.routeData.get("overlays") as string | undefined; + const current: string[] = raw ? JSON.parse(raw) : []; + if (!current.includes(layer.id)) { + const updated = [...current, layer.id]; + yjs.routeData.set("overlays", JSON.stringify(updated)); + onOverlayChange(updated); + } + }; + + const handleRemove = (e: L.LayersControlEvent) => { + if (suppressRef.current) return; + const layer = overlayLayers.find((l) => l.name === e.name); + if (!layer) return; + const raw = yjs.routeData.get("overlays") as string | undefined; + const current: string[] = raw ? JSON.parse(raw) : []; + const updated = current.filter((id) => id !== layer.id); + yjs.routeData.set("overlays", JSON.stringify(updated)); + onOverlayChange(updated); + }; + + const handleBaseChange = (e: L.LayersControlEvent) => { + if (suppressRef.current) return; + yjs.routeData.set("baseLayer", e.name); + }; + + map.on("overlayadd", handleAdd as L.LeafletEventHandlerFn); + map.on("overlayremove", handleRemove as L.LeafletEventHandlerFn); + map.on("baselayerchange", handleBaseChange as L.LeafletEventHandlerFn); + return () => { + map.off("overlayadd", handleAdd as L.LeafletEventHandlerFn); + map.off("overlayremove", handleRemove as L.LeafletEventHandlerFn); + map.off("baselayerchange", handleBaseChange as L.LeafletEventHandlerFn); + }; + }, [map, yjs, onOverlayChange]); + + useEffect(() => { + const handleChange = () => { + const raw = yjs.routeData.get("overlays") as string | undefined; + if (raw) { + try { onOverlayChange(JSON.parse(raw)); } catch { /* ignore */ } + } + const base = yjs.routeData.get("baseLayer") as string | undefined; + if (base) onBaseLayerChange(base); + }; + yjs.routeData.observe(handleChange); + handleChange(); + return () => yjs.routeData.unobserve(handleChange); + }, [yjs, onOverlayChange, onBaseLayerChange]); + + return null; +} + +// Triggers POI refreshes on map move and category changes. +export function PoiRefresher({ poiState }: { poiState: ReturnType }) { + const map = useMap(); + const refreshRef = useRef(poiState.refresh); + refreshRef.current = poiState.refresh; + + useEffect(() => { + const refresh = () => { + const bounds = map.getBounds(); + const zoom = map.getZoom(); + refreshRef.current( + { south: bounds.getSouth(), west: bounds.getWest(), north: bounds.getNorth(), east: bounds.getEast() }, + zoom, + ); + }; + map.on("moveend", refresh); + return () => { map.off("moveend", refresh); }; + }, [map]); + + const prevCategories = useRef(poiState.enabledCategories); + useEffect(() => { + if (prevCategories.current === poiState.enabledCategories) return; + prevCategories.current = poiState.enabledCategories; + const bounds = map.getBounds(); + const zoom = map.getZoom(); + poiState.refresh( + { south: bounds.getSouth(), west: bounds.getWest(), north: bounds.getNorth(), east: bounds.getEast() }, + zoom, + ); + }, [map, poiState.enabledCategories, poiState.refresh]); + + return null; +} diff --git a/apps/planner/app/components/PlannerMap.tsx b/apps/planner/app/components/PlannerMap.tsx index bb64215..25eceda 100644 --- a/apps/planner/app/components/PlannerMap.tsx +++ b/apps/planner/app/components/PlannerMap.tsx @@ -1,42 +1,33 @@ -import { useEffect, useState, useCallback, useRef } from "react"; -import { MapContainer, TileLayer, LayersControl, Marker, Polyline, useMapEvents, useMap } from "react-leaflet"; +import { useState, useCallback, useRef } from "react"; +import { MapContainer, TileLayer, LayersControl, Marker, Polyline } from "react-leaflet"; import L from "leaflet"; -import * as Y from "yjs"; import { useTranslation } from "react-i18next"; import type { DayStage } from "@trails-cool/gpx"; import type { YjsState } from "~/lib/use-yjs"; import { baseLayers, overlayLayers } from "@trails-cool/map"; -import { parseGpxAsync, extractWaypoints } from "@trails-cool/gpx"; -import { isOvernight } from "~/lib/overnight"; import { setOvernight } from "~/lib/overnight"; import { usePois } from "~/lib/use-pois"; import { useProfileDefaults } from "~/lib/use-profile-defaults"; import { useYjsPoiSync } from "~/lib/use-yjs-poi-sync"; -import { snapToPoi } from "~/lib/poi-snap"; -import { Z_CURSOR, Z_WAYPOINT, Z_WAYPOINT_HIGHLIGHTED, Z_HIGHLIGHT } from "@trails-cool/map-core"; +import { Z_WAYPOINT, Z_WAYPOINT_HIGHLIGHTED, Z_HIGHLIGHT } from "@trails-cool/map-core"; import { NoGoAreaLayer } from "./NoGoAreaLayer"; -import { ColoredRoute, findSegmentForPoint, type ColorMode } from "./ColoredRoute"; +import { ColoredRoute } from "./ColoredRoute"; import { RouteInteraction } from "./RouteInteraction"; import { PoiPanel, PoiMarkers } from "./PoiPanel"; import { WaypointContextMenu } from "./WaypointContextMenu"; +import { + MapExposer, + RouteFitter, + MapClickHandler, + CursorTracker, + NoGoAreaButton, + OverlaySync, + PoiRefresher, +} from "./MapHelpers"; +import { useWaypointManager } from "~/lib/use-waypoint-manager"; +import { useGpxDrop } from "~/lib/use-gpx-drop"; import "leaflet/dist/leaflet.css"; -/** Distance from a point to a line segment in degrees (approximate) */ -function pointToSegmentDist( - pLat: number, pLon: number, - aLat: number, aLon: number, - bLat: number, bLon: number, -): number { - const dx = bLon - aLon; - const dy = bLat - aLat; - const lenSq = dx * dx + dy * dy; - if (lenSq === 0) return Math.sqrt((pLon - aLon) ** 2 + (pLat - aLat) ** 2); - const t = Math.max(0, Math.min(1, ((pLon - aLon) * dx + (pLat - aLat) * dy) / lenSq)); - const projLon = aLon + t * dx; - const projLat = aLat + t * dy; - return Math.sqrt((pLon - projLon) ** 2 + (pLat - projLat) ** 2); -} - function waypointIcon(index: number, overnight?: boolean, highlighted?: boolean): L.DivIcon { const bg = overnight ? "#8B6D3A" : "#2563eb"; const scale = highlighted ? "scale(1.17)" : "scale(1)"; @@ -70,26 +61,10 @@ function dayLabelIcon(dayNumber: number, distanceKm: string): L.DivIcon { }); } -interface WaypointData { - lat: number; - lon: number; - name?: string; - overnight: boolean; -} - -function getWaypointsFromYjs(waypoints: Y.Array>): WaypointData[] { - return waypoints.toArray().map((yMap) => ({ - lat: yMap.get("lat") as number, - lon: yMap.get("lon") as number, - name: yMap.get("name") as string | undefined, - overnight: isOvernight(yMap), - })); -} - interface PlannerMapProps { yjs: YjsState; sessionId: string; - onRouteRequest?: (waypoints: WaypointData[]) => void; + onRouteRequest?: (waypoints: { lat: number; lon: number; name?: string; overnight: boolean }[]) => void; onImportError?: (message: string) => void; highlightPosition?: [number, number] | null; highlightedWaypoint?: number | null; @@ -97,625 +72,45 @@ interface PlannerMapProps { days?: DayStage[]; } -function MapExposer() { - const map = useMap(); - useEffect(() => { - if (typeof window !== "undefined") { - (window as unknown as Record).__leafletMap = map; - } - }, [map]); - return null; -} - -function RouteFitter({ coordinates }: { coordinates: [number, number, number][] | null }) { - const map = useMap(); - const hasFitted = useRef(false); - - useEffect(() => { - if (hasFitted.current || !coordinates || coordinates.length < 2) return; - - // Coordinates are in [lon, lat, elevation] GeoJSON format - const bounds = L.latLngBounds( - coordinates.map((c) => [c[1]!, c[0]!] as [number, number]), - ); - - if (!bounds.isValid()) return; - - // Delay fitBounds so the layout has settled (elevation chart may resize the map) - const raf = requestAnimationFrame(() => { - map.invalidateSize(); - map.fitBounds(bounds, { padding: [50, 50], maxZoom: 16 }); - hasFitted.current = true; - }); - return () => cancelAnimationFrame(raf); - }, [coordinates, map]); - - return null; -} - -function MapClickHandler({ onAdd, suppressRef }: { onAdd: (lat: number, lng: number) => void; suppressRef: React.RefObject }) { - useMapEvents({ - click(e) { - if (suppressRef.current) { - suppressRef.current = false; - return; - } - onAdd(e.latlng.lat, e.latlng.lng); - }, - }); - return null; -} - -function CursorTracker({ awareness }: { awareness: YjsState["awareness"] }) { - const map = useMap(); - const [cursors, setCursors] = useState>(new Map()); - - useEffect(() => { - const localId = awareness.clientID; - - const handleMouseMove = (e: L.LeafletMouseEvent) => { - awareness.setLocalStateField("mapCursor", { - lat: e.latlng.lat, - lng: e.latlng.lng, - }); - }; - - const handleMouseOut = () => { - awareness.setLocalStateField("mapCursor", null); - }; - - map.on("mousemove", handleMouseMove); - map.on("mouseout", handleMouseOut); - - const updateCursors = () => { - const states = awareness.getStates(); - const newCursors = new Map(); - states.forEach((state, clientId) => { - if (clientId !== localId && state.mapCursor && state.user) { - newCursors.set(clientId, { - lat: state.mapCursor.lat, - lng: state.mapCursor.lng, - color: state.user.color, - name: state.user.name, - }); - } - }); - setCursors(newCursors); - }; - - awareness.on("change", updateCursors); - - return () => { - map.off("mousemove", handleMouseMove); - map.off("mouseout", handleMouseOut); - awareness.off("change", updateCursors); - }; - }, [map, awareness]); - - return ( - <> - {Array.from(cursors.entries()).map(([clientId, cursor]) => ( - - - - - ${cursor.name} - `, - iconSize: [0, 0], - })} - /> - ))} - - ); -} - -function NoGoAreaButton({ active, onClick }: { active: boolean; onClick: () => void }) { - const ref = useRef(null); - - // Prevent clicks from reaching the Leaflet map (same as built-in controls) - useEffect(() => { - if (ref.current) L.DomEvent.disableClickPropagation(ref.current); - }, []); - - return ( - - ); -} - -function OverlaySync({ yjs, onOverlayChange, onBaseLayerChange }: { yjs: YjsState; onOverlayChange: (ids: string[]) => void; onBaseLayerChange: (name: string) => void }) { - const map = useMap(); - const suppressRef = useRef(false); - - // Map events → Yjs - useEffect(() => { - const handleAdd = (e: L.LayersControlEvent) => { - if (suppressRef.current) return; - const name = e.name; - const layer = overlayLayers.find((l) => l.name === name); - if (!layer) return; - const raw = yjs.routeData.get("overlays") as string | undefined; - const current: string[] = raw ? JSON.parse(raw) : []; - if (!current.includes(layer.id)) { - const updated = [...current, layer.id]; - yjs.routeData.set("overlays", JSON.stringify(updated)); - onOverlayChange(updated); - } - }; - - const handleRemove = (e: L.LayersControlEvent) => { - if (suppressRef.current) return; - const name = e.name; - const layer = overlayLayers.find((l) => l.name === name); - if (!layer) return; - const raw = yjs.routeData.get("overlays") as string | undefined; - const current: string[] = raw ? JSON.parse(raw) : []; - const updated = current.filter((id) => id !== layer.id); - yjs.routeData.set("overlays", JSON.stringify(updated)); - onOverlayChange(updated); - }; - - // Base layer change → Yjs - const handleBaseChange = (e: L.LayersControlEvent) => { - if (suppressRef.current) return; - yjs.routeData.set("baseLayer", e.name); - }; - - map.on("overlayadd", handleAdd as L.LeafletEventHandlerFn); - map.on("overlayremove", handleRemove as L.LeafletEventHandlerFn); - map.on("baselayerchange", handleBaseChange as L.LeafletEventHandlerFn); - return () => { - map.off("overlayadd", handleAdd as L.LeafletEventHandlerFn); - map.off("overlayremove", handleRemove as L.LeafletEventHandlerFn); - map.off("baselayerchange", handleBaseChange as L.LeafletEventHandlerFn); - }; - }, [map, yjs, onOverlayChange]); - - // Yjs → Map: load initial state from Yjs - useEffect(() => { - const handleChange = () => { - const raw = yjs.routeData.get("overlays") as string | undefined; - if (raw) { - try { - onOverlayChange(JSON.parse(raw)); - } catch { /* ignore */ } - } - const base = yjs.routeData.get("baseLayer") as string | undefined; - if (base) onBaseLayerChange(base); - }; - yjs.routeData.observe(handleChange); - handleChange(); - return () => yjs.routeData.unobserve(handleChange); - }, [yjs, onOverlayChange, onBaseLayerChange]); - - return null; -} - -function PoiRefresher({ poiState }: { poiState: ReturnType }) { - const map = useMap(); - const refreshRef = useRef(poiState.refresh); - refreshRef.current = poiState.refresh; - - useEffect(() => { - const refresh = () => { - const bounds = map.getBounds(); - const zoom = map.getZoom(); - refreshRef.current({ - south: bounds.getSouth(), - west: bounds.getWest(), - north: bounds.getNorth(), - east: bounds.getEast(), - }, zoom); - }; - map.on("moveend", refresh); - // Don't call refresh() immediately — let moveend trigger it - return () => { map.off("moveend", refresh); }; - }, [map]); - - // Trigger refresh when categories change (but not on mount) - const prevCategories = useRef(poiState.enabledCategories); - useEffect(() => { - if (prevCategories.current === poiState.enabledCategories) return; - prevCategories.current = poiState.enabledCategories; - const bounds = map.getBounds(); - const zoom = map.getZoom(); - poiState.refresh({ - south: bounds.getSouth(), - west: bounds.getWest(), - north: bounds.getNorth(), - east: bounds.getEast(), - }, zoom); - }, [map, poiState.enabledCategories, poiState.refresh]); - - return null; -} - export function PlannerMap({ yjs, sessionId, onRouteRequest, highlightPosition, highlightedWaypoint, onRouteHover, onImportError, days }: PlannerMapProps) { const { t } = useTranslation("planner"); - const [waypoints, setWaypoints] = useState([]); const poiState = usePois(sessionId); useProfileDefaults(yjs, poiState); useYjsPoiSync(yjs, poiState); const [enabledOverlays, setEnabledOverlays] = useState([]); const [selectedBaseLayer, setSelectedBaseLayer] = useState(baseLayers[0]!.name); const [contextMenu, setContextMenu] = useState<{ x: number; y: number; index: number } | null>(null); - const [draggingOver, setDraggingOver] = useState(false); - const dragCounterRef = useRef(0); - const [routeCoordinates, setRouteCoordinates] = useState<[number, number, number][] | null>(null); - const [segmentBoundaries, setSegmentBoundaries] = useState([]); - const [surfaces, setSurfaces] = useState([]); - const [highways, setHighways] = useState([]); - const [maxspeeds, setMaxspeeds] = useState([]); - const [smoothnesses, setSmoothnesses] = useState([]); - const [tracktypes, setTracktypes] = useState([]); - const [cycleways, setCycleways] = useState([]); - const [bikeroutes, setBikeroutes] = useState([]); - const [colorMode, setColorMode] = useState("plain"); const [noGoDrawing, setNoGoDrawing] = useState(false); const toggleNoGoDraw = useCallback(() => setNoGoDrawing((v) => !v), []); const suppressMapClickRef = useRef(false); const routeInteractionSuspendedRef = useRef(false); const waypointDraggingRef = useRef(false); - // Sync waypoints from Yjs - useEffect(() => { - const update = () => { - const wps = getWaypointsFromYjs(yjs.waypoints); - setWaypoints(wps); - if (wps.length >= 2 && onRouteRequest) { - onRouteRequest(wps); - } - }; + const { + waypoints, + routeCoordinates, + segmentBoundaries, + surfaces, + highways, + maxspeeds, + smoothnesses, + tracktypes, + cycleways, + bikeroutes, + colorMode, + addWaypoint, + handleRouteInsert, + moveWaypoint, + deleteWaypoint, + handleRoutePolylineHover, + } = useWaypointManager(yjs, poiState, suppressMapClickRef, onRouteRequest); - yjs.waypoints.observeDeep(update); - update(); - - return () => { - yjs.waypoints.unobserveDeep(update); - }; - }, [yjs.waypoints, onRouteRequest]); - - // Sync route data from Yjs (enriched: coordinates + segment boundaries) - useEffect(() => { - const update = () => { - const coordsJson = yjs.routeData.get("coordinates") as string | undefined; - const boundsJson = yjs.routeData.get("segmentBoundaries") as string | undefined; - const modeVal = yjs.routeData.get("colorMode") as ColorMode | undefined; - - if (coordsJson) { - try { - setRouteCoordinates(JSON.parse(coordsJson)); - } catch { - setRouteCoordinates(null); - } - } else { - // Fallback: parse from geojson for backwards compat - const geojson = yjs.routeData.get("geojson") as string | undefined; - if (geojson) { - try { - const parsed = JSON.parse(geojson); - const coords = parsed.features?.[0]?.geometry?.coordinates; - if (coords) { - setRouteCoordinates(coords.map((c: number[]) => [c[0]!, c[1]!, c[2] ?? 0] as [number, number, number])); - } - } catch { setRouteCoordinates(null); } - } else { - setRouteCoordinates(null); - } - } - - if (boundsJson) { - try { setSegmentBoundaries(JSON.parse(boundsJson)); } catch { setSegmentBoundaries([]); } - } else { - setSegmentBoundaries([]); - } - - const surfacesJson = yjs.routeData.get("surfaces") as string | undefined; - if (surfacesJson) { - try { setSurfaces(JSON.parse(surfacesJson)); } catch { setSurfaces([]); } - } else { - setSurfaces([]); - } - - const highwaysJson = yjs.routeData.get("highways") as string | undefined; - if (highwaysJson) { - try { setHighways(JSON.parse(highwaysJson)); } catch { setHighways([]); } - } else { - setHighways([]); - } - - const maxspeedsJson = yjs.routeData.get("maxspeeds") as string | undefined; - if (maxspeedsJson) { - try { setMaxspeeds(JSON.parse(maxspeedsJson)); } catch { setMaxspeeds([]); } - } else { - setMaxspeeds([]); - } - - const smoothnessesJson = yjs.routeData.get("smoothnesses") as string | undefined; - if (smoothnessesJson) { - try { setSmoothnesses(JSON.parse(smoothnessesJson)); } catch { setSmoothnesses([]); } - } else { - setSmoothnesses([]); - } - - const tracktypesJson = yjs.routeData.get("tracktypes") as string | undefined; - if (tracktypesJson) { - try { setTracktypes(JSON.parse(tracktypesJson)); } catch { setTracktypes([]); } - } else { - setTracktypes([]); - } - - const cyclewaysJson = yjs.routeData.get("cycleways") as string | undefined; - if (cyclewaysJson) { - try { setCycleways(JSON.parse(cyclewaysJson)); } catch { setCycleways([]); } - } else { - setCycleways([]); - } - - const bikeroutesJson = yjs.routeData.get("bikeroutes") as string | undefined; - if (bikeroutesJson) { - try { setBikeroutes(JSON.parse(bikeroutesJson)); } catch { setBikeroutes([]); } - } else { - setBikeroutes([]); - } - - if (modeVal) setColorMode(modeVal); - }; - - yjs.routeData.observe(update); - update(); - - return () => { - yjs.routeData.unobserve(update); - }; - }, [yjs.routeData]); - - const addWaypoint = useCallback( - (lat: number, lng: number, name?: string) => { - const snap = snapToPoi(lat, lng, poiState.pois); - const finalLat = snap.lat; - const finalLon = snap.snapped ? snap.lon : lng; - - // Find the best insertion index: if the point is near the route, - // insert between the closest segment's waypoints instead of appending - let insertIndex = yjs.waypoints.length; // default: append - if (routeCoordinates && routeCoordinates.length >= 2 && segmentBoundaries.length > 0) { - let bestDist = Infinity; - let bestSegment = -1; - // For each segment, find the closest point on the route - for (let seg = 0; seg < segmentBoundaries.length; seg++) { - const start = segmentBoundaries[seg]!; - const end = seg + 1 < segmentBoundaries.length ? segmentBoundaries[seg + 1]! : routeCoordinates.length; - for (let i = start; i < end - 1; i++) { - const c1 = routeCoordinates[i]!; - const c2 = routeCoordinates[i + 1]!; - const dist = pointToSegmentDist(finalLat, finalLon, c1[1]!, c1[0]!, c2[1]!, c2[0]!); - if (dist < bestDist) { - bestDist = dist; - bestSegment = seg; - } - } - } - // If within ~1km of the route, insert after the segment's waypoint - if (bestDist < 0.01 && bestSegment >= 0) { - insertIndex = bestSegment + 1; - } - } - - yjs.doc.transact(() => { - const yMap = new Y.Map(); - yMap.set("lat", finalLat); - yMap.set("lon", finalLon); - if (snap.name) yMap.set("name", snap.name); - else if (name) yMap.set("name", name); - if (snap.osmId) yMap.set("osmId", snap.osmId); - if (snap.poiTags) yMap.set("poiTags", snap.poiTags); - yjs.waypoints.insert(insertIndex, [yMap]); - }, "local"); - }, - [yjs.doc, yjs.waypoints, poiState.pois, routeCoordinates, segmentBoundaries], - ); - - const insertWaypointAtSegment = useCallback( - (segmentIndex: number, lat: number, lon: number) => { - const snap = snapToPoi(lat, lon, poiState.pois); - yjs.doc.transact(() => { - const yMap = new Y.Map(); - yMap.set("lat", snap.lat); - yMap.set("lon", snap.snapped ? snap.lon : lon); - if (snap.name) yMap.set("name", snap.name); - if (snap.osmId) yMap.set("osmId", snap.osmId); - if (snap.poiTags) yMap.set("poiTags", snap.poiTags); - yjs.waypoints.insert(segmentIndex + 1, [yMap]); - }, "local"); - }, - [yjs.doc, yjs.waypoints, poiState.pois], - ); - - const handleRouteInsert = useCallback( - (pointIndex: number, lat: number, lon: number) => { - suppressMapClickRef.current = true; - const segIdx = findSegmentForPoint(pointIndex, segmentBoundaries); - insertWaypointAtSegment(segIdx, lat, lon); - }, - [segmentBoundaries, insertWaypointAtSegment], - ); - - const moveWaypoint = useCallback( - (index: number, lat: number, lng: number) => { - const snap = snapToPoi(lat, lng, poiState.pois); - const yMap = yjs.waypoints.get(index); - if (yMap) { - yjs.doc.transact(() => { - yMap.set("lat", snap.lat); - yMap.set("lon", snap.snapped ? snap.lon : lng); - if (snap.snapped && snap.name) { - yMap.set("name", snap.name); - } else { - yMap.delete("name"); - } - if (snap.osmId) { - yMap.set("osmId", snap.osmId); - if (snap.poiTags) yMap.set("poiTags", snap.poiTags); - } else { - yMap.delete("osmId"); - yMap.delete("poiTags"); - } - }, "local"); - } - }, - [yjs.waypoints, yjs.doc, poiState.pois], - ); - - const deleteWaypoint = useCallback( - (index: number) => { - yjs.doc.transact(() => { - yjs.waypoints.delete(index, 1); - }, "local"); - }, - [yjs.waypoints], - ); - - const handleRoutePolylineHover = useCallback( - (e: L.LeafletMouseEvent) => { - if (!routeCoordinates || routeCoordinates.length < 2 || !onRouteHover) return; - const { lat, lng } = e.latlng; - // Find the closest coordinate index - let bestIdx = 0; - let bestDist = Infinity; - for (let i = 0; i < routeCoordinates.length; i++) { - const c = routeCoordinates[i]!; - const dLat = c[1]! - lat; - const dLon = c[0]! - lng; - const dist = dLat * dLat + dLon * dLon; - if (dist < bestDist) { - bestDist = dist; - bestIdx = i; - } - } - // Compute cumulative distance to this point using haversine - let totalDist = 0; - for (let i = 1; i <= bestIdx; i++) { - const prev = routeCoordinates[i - 1]!; - const curr = routeCoordinates[i]!; - const R = 6371000; - const toRad = (d: number) => (d * Math.PI) / 180; - const dLat = toRad(curr[1]! - prev[1]!); - const dLon = toRad(curr[0]! - prev[0]!); - const a = - Math.sin(dLat / 2) ** 2 + - Math.cos(toRad(prev[1]!)) * Math.cos(toRad(curr[1]!)) * Math.sin(dLon / 2) ** 2; - totalDist += R * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); - } - onRouteHover(totalDist); - }, - [routeCoordinates, onRouteHover], - ); + const { draggingOver, handleDragEnter, handleDragLeave, handleDragOver, handleDrop } = useGpxDrop(yjs, onImportError); const handleRoutePolylineOut = useCallback(() => { onRouteHover?.(null); }, [onRouteHover]); - const handleDragEnter = useCallback((e: React.DragEvent) => { - e.preventDefault(); - dragCounterRef.current++; - if (dragCounterRef.current === 1) setDraggingOver(true); - }, []); - - const handleDragLeave = useCallback((e: React.DragEvent) => { - e.preventDefault(); - dragCounterRef.current--; - if (dragCounterRef.current === 0) setDraggingOver(false); - }, []); - - const handleDragOver = useCallback((e: React.DragEvent) => { - e.preventDefault(); - }, []); - - const handleDrop = useCallback(async (e: React.DragEvent) => { - e.preventDefault(); - dragCounterRef.current = 0; - setDraggingOver(false); - - const file = e.dataTransfer.files[0]; - if (!file) return; - if (!file.name.toLowerCase().endsWith(".gpx")) { - onImportError?.(t("importGpxError")); - return; - } - - try { - const text = await file.text(); - const gpxData = await parseGpxAsync(text); - const newWaypoints = extractWaypoints(gpxData); - if (newWaypoints.length < 2) return; - - if (!window.confirm(t("replaceRouteConfirm"))) return; - - yjs.doc.transact(() => { - // Replace waypoints - yjs.waypoints.delete(0, yjs.waypoints.length); - for (const wp of newWaypoints) { - const yMap = new Y.Map(); - yMap.set("lat", wp.lat); - yMap.set("lon", wp.lon); - if (wp.name) yMap.set("name", wp.name); - if (wp.isDayBreak) yMap.set("overnight", true); - yjs.waypoints.push([yMap]); - } - - // Replace no-go areas - yjs.noGoAreas.delete(0, yjs.noGoAreas.length); - for (const area of gpxData.noGoAreas) { - const yMap = new Y.Map(); - yMap.set("points", area.points); - yjs.noGoAreas.push([yMap]); - } - - // Replace notes if GPX has a description - if (gpxData.description) { - yjs.notes.delete(0, yjs.notes.length); - yjs.notes.insert(0, gpxData.description); - } - }, "local"); - } catch { - onImportError?.(t("importGpxError")); - } - }, [yjs, t, onImportError]); - return (
)} - - - {baseLayers.map((layer) => ( - - - - ))} - {overlayLayers.map((layer) => ( - - - - ))} - + + + {baseLayers.map((layer) => ( + + + + ))} + {overlayLayers.map((layer) => ( + + + + ))} + - - - - {} : addWaypoint} suppressRef={suppressMapClickRef} /> - - - - - - + + + + {} : addWaypoint} suppressRef={suppressMapClickRef} /> + + + + + + - {waypoints.map((wp, i) => ( - { - routeInteractionSuspendedRef.current = true; - }, - mouseout: () => { - if (!waypointDraggingRef.current) { - routeInteractionSuspendedRef.current = false; - } - }, - dragstart: () => { - waypointDraggingRef.current = true; - yjs.undoManager.stopCapturing(); - routeInteractionSuspendedRef.current = true; - }, - dragend: (e) => { - waypointDraggingRef.current = false; - routeInteractionSuspendedRef.current = false; - const { lat, lng } = e.target.getLatLng(); - moveWaypoint(i, lat, lng); - }, - contextmenu: (e) => { - L.DomEvent.preventDefault(e as unknown as Event); - const orig = e.originalEvent as MouseEvent; - setContextMenu({ x: orig.clientX, y: orig.clientY, index: i }); - }, - }} - /> - ))} - - {/* Day boundary labels on map */} - {days && days.length > 1 && days.map((day) => { - const wp = waypoints[day.endWaypointIndex]; - if (!wp || day.dayNumber === days.length) return null; - return ( + {waypoints.map((wp, i) => ( { routeInteractionSuspendedRef.current = true; }, + mouseout: () => { + if (!waypointDraggingRef.current) routeInteractionSuspendedRef.current = false; + }, + dragstart: () => { + waypointDraggingRef.current = true; + yjs.undoManager.stopCapturing(); + routeInteractionSuspendedRef.current = true; + }, + dragend: (e) => { + waypointDraggingRef.current = false; + routeInteractionSuspendedRef.current = false; + const { lat, lng } = e.target.getLatLng(); + moveWaypoint(i, lat, lng); + }, + contextmenu: (e) => { + L.DomEvent.preventDefault(e as unknown as Event); + const orig = e.originalEvent as MouseEvent; + setContextMenu({ x: orig.clientX, y: orig.clientY, index: i }); + }, + }} /> - ); - })} + ))} - {routeCoordinates && routeCoordinates.length >= 2 && ( - <> - - - {onRouteHover && ( - [c[1]!, c[0]!] as [number, number])} - pathOptions={{ weight: 20, opacity: 0, interactive: true }} - eventHandlers={{ - mouseover: handleRoutePolylineHover, - mousemove: handleRoutePolylineHover, - mouseout: handleRoutePolylineOut, - }} + {days && days.length > 1 && days.map((day) => { + const wp = waypoints[day.endWaypointIndex]; + if (!wp || day.dayNumber === days.length) return null; + return ( + - )} - - )} + ); + })} - {highlightPosition && ( - ', - iconSize: [0, 0], - })} - /> - )} - + {routeCoordinates && routeCoordinates.length >= 2 && ( + <> + + + {onRouteHover && ( + [c[1]!, c[0]!] as [number, number])} + pathOptions={{ weight: 20, opacity: 0, interactive: true }} + eventHandlers={{ + mouseover: (e) => handleRoutePolylineHover(e, onRouteHover), + mousemove: (e) => handleRoutePolylineHover(e, onRouteHover), + mouseout: handleRoutePolylineOut, + }} + /> + )} + + )} + + {highlightPosition && ( + ', + iconSize: [0, 0], + })} + /> + )} + {contextMenu && ( ({ + distance: i * 1000, + elevation: 100 + i * 10, + lat: 48 + i * 0.01, + lon: 11 + i * 0.01, +})); + +const BASE_PARAMS: DrawChartParams = { + points: BASE_POINTS, + colorMode: "plain", + surfaces: [], + highways: [], + maxspeeds: [], + smoothnesses: [], + tracktypes: [], + cycleways: [], + bikeroutes: [], + hoverIdx: null, + isDragging: false, + dragStartX: null, + dragCurrentX: null, +}; + +function ChartFixture({ params }: { params: DrawChartParams }) { + return ( + { + if (!canvas) return; + const ctx = canvas.getContext("2d"); + if (!ctx) return; + drawElevationChart(ctx, 600, 100, params); + }} + /> + ); +} + +describe("drawElevationChart visual regression", () => { + it("renders plain color mode", async () => { + render(); + await expect(page.getByTestId("chart")).toMatchScreenshot("plain.png"); + }); + + it("renders grade color mode", async () => { + render(); + await expect(page.getByTestId("chart")).toMatchScreenshot("grade.png"); + }); + + it("renders elevation color mode", async () => { + render(); + await expect(page.getByTestId("chart")).toMatchScreenshot("elevation.png"); + }); + + it("renders surface color mode", async () => { + const surfaces = BASE_POINTS.map((_, i) => + i < 5 ? "asphalt" : "gravel", + ); + render(); + await expect(page.getByTestId("chart")).toMatchScreenshot("surface.png"); + }); + + it("renders hover crosshair at index 5", async () => { + render(); + await expect(page.getByTestId("chart")).toMatchScreenshot("hover.png"); + }); + + it("renders drag selection overlay", async () => { + render( + , + ); + await expect(page.getByTestId("chart")).toMatchScreenshot("drag-select.png"); + }); +}); diff --git a/apps/planner/app/lib/elevation-chart-draw.ts b/apps/planner/app/lib/elevation-chart-draw.ts new file mode 100644 index 0000000..e8c8867 --- /dev/null +++ b/apps/planner/app/lib/elevation-chart-draw.ts @@ -0,0 +1,289 @@ +import { + elevationColor, + maxspeedColor, + SURFACE_COLORS, + DEFAULT_SURFACE_COLOR, + HIGHWAY_COLORS, + DEFAULT_HIGHWAY_COLOR, + SMOOTHNESS_COLORS, + DEFAULT_SMOOTHNESS_COLOR, + TRACKTYPE_COLORS, + DEFAULT_TRACKTYPE_COLOR, + CYCLEWAY_COLORS, + DEFAULT_CYCLEWAY_COLOR, + BIKEROUTE_COLORS, + DEFAULT_BIKEROUTE_COLOR, +} from "@trails-cool/map-core"; +import type { ColorMode } from "~/components/ColoredRoute"; +import type { DayStage } from "@trails-cool/gpx"; + +export interface ElevationPoint { + distance: number; + elevation: number; + lat: number; + lon: number; +} + +function gradeColor(grade: number): string { + const absGrade = Math.abs(grade); + if (absGrade < 3) return "#22c55e"; + if (absGrade < 6) return "#eab308"; + if (absGrade < 10) return "#f97316"; + if (absGrade < 15) return "#ef4444"; + return "#991b1b"; +} + +export const PADDING = { top: 10, right: 10, bottom: 25, left: 40 }; + +export interface DrawChartParams { + points: ElevationPoint[]; + colorMode: ColorMode; + surfaces: string[]; + highways: string[]; + maxspeeds: string[]; + smoothnesses: string[]; + tracktypes: string[]; + cycleways: string[]; + bikeroutes: string[]; + hoverIdx: number | null; + isDragging: boolean; + dragStartX: number | null; + dragCurrentX: number | null; + days?: DayStage[]; +} + +function drawSegments( + ctx: CanvasRenderingContext2D, + points: ElevationPoint[], + chartH: number, + getColor: (i: number) => string, + toX: (d: number) => number, + toY: (e: number) => number, +) { + for (let i = 0; i < points.length - 1; i++) { + const p0 = points[i]!; + const p1 = points[i + 1]!; + const color = getColor(i); + + ctx.beginPath(); + ctx.moveTo(toX(p0.distance), PADDING.top + chartH); + ctx.lineTo(toX(p0.distance), toY(p0.elevation)); + ctx.lineTo(toX(p1.distance), toY(p1.elevation)); + ctx.lineTo(toX(p1.distance), PADDING.top + chartH); + ctx.closePath(); + ctx.fillStyle = color + "40"; + ctx.fill(); + + ctx.beginPath(); + ctx.moveTo(toX(p0.distance), toY(p0.elevation)); + ctx.lineTo(toX(p1.distance), toY(p1.elevation)); + ctx.strokeStyle = color; + ctx.lineWidth = 2; + ctx.stroke(); + } +} + +export function drawElevationChart( + ctx: CanvasRenderingContext2D, + width: number, + height: number, + params: DrawChartParams, +): void { + const { + points, + colorMode, + surfaces, + highways, + maxspeeds, + smoothnesses, + tracktypes, + cycleways, + bikeroutes, + hoverIdx, + isDragging, + dragStartX, + dragCurrentX, + days, + } = params; + + if (points.length < 2) return; + + const w = width; + const h = height; + const chartW = w - PADDING.left - PADDING.right; + const chartH = h - PADDING.top - PADDING.bottom; + + const maxDist = points[points.length - 1]!.distance; + const elevations = points.map((p) => p.elevation); + const minEle = Math.min(...elevations); + const maxEle = Math.max(...elevations); + const eleRange = maxEle - minEle || 1; + + const toX = (d: number) => PADDING.left + (d / maxDist) * chartW; + const toY = (e: number) => PADDING.top + chartH - ((e - minEle) / eleRange) * chartH; + + ctx.clearRect(0, 0, w, h); + + if (colorMode === "grade") { + drawSegments(ctx, points, chartH, (i) => { + const p0 = points[i]!; + const p1 = points[i + 1]!; + const dDist = p1.distance - p0.distance; + const grade = dDist > 0 ? ((p1.elevation - p0.elevation) / dDist) * 100 : 0; + return gradeColor(grade); + }, toX, toY); + } else if (colorMode === "elevation") { + // elevationColor returns rgb(...), not hex, so we can't use hex alpha suffix + for (let i = 0; i < points.length - 1; i++) { + const p0 = points[i]!; + const p1 = points[i + 1]!; + const t = (p0.elevation - minEle) / eleRange; + const color = elevationColor(t); + + ctx.beginPath(); + ctx.moveTo(toX(p0.distance), PADDING.top + chartH); + ctx.lineTo(toX(p0.distance), toY(p0.elevation)); + ctx.lineTo(toX(p1.distance), toY(p1.elevation)); + ctx.lineTo(toX(p1.distance), PADDING.top + chartH); + ctx.closePath(); + ctx.fillStyle = color.replace("rgb", "rgba").replace(")", ", 0.2)"); + ctx.fill(); + + ctx.beginPath(); + ctx.moveTo(toX(p0.distance), toY(p0.elevation)); + ctx.lineTo(toX(p1.distance), toY(p1.elevation)); + ctx.strokeStyle = color; + ctx.lineWidth = 2; + ctx.stroke(); + } + } else if (colorMode === "surface" && surfaces.length >= points.length) { + drawSegments(ctx, points, chartH, (i) => SURFACE_COLORS[surfaces[i] ?? "unknown"] ?? DEFAULT_SURFACE_COLOR, toX, toY); + } else if (colorMode === "highway" && highways.length >= points.length) { + drawSegments(ctx, points, chartH, (i) => HIGHWAY_COLORS[highways[i] ?? "unknown"] ?? DEFAULT_HIGHWAY_COLOR, toX, toY); + } else if (colorMode === "maxspeed" && maxspeeds.length >= points.length) { + drawSegments(ctx, points, chartH, (i) => maxspeedColor(maxspeeds[i] ?? "unknown"), toX, toY); + } else if (colorMode === "smoothness" && smoothnesses.length >= points.length) { + drawSegments(ctx, points, chartH, (i) => SMOOTHNESS_COLORS[smoothnesses[i] ?? "unknown"] ?? DEFAULT_SMOOTHNESS_COLOR, toX, toY); + } else if (colorMode === "tracktype" && tracktypes.length >= points.length) { + drawSegments(ctx, points, chartH, (i) => TRACKTYPE_COLORS[tracktypes[i] ?? "unknown"] ?? DEFAULT_TRACKTYPE_COLOR, toX, toY); + } else if (colorMode === "cycleway" && cycleways.length >= points.length) { + drawSegments(ctx, points, chartH, (i) => CYCLEWAY_COLORS[cycleways[i] ?? "unknown"] ?? DEFAULT_CYCLEWAY_COLOR, toX, toY); + } else if (colorMode === "bikeroute" && bikeroutes.length >= points.length) { + drawSegments(ctx, points, chartH, (i) => BIKEROUTE_COLORS[bikeroutes[i] ?? "none"] ?? DEFAULT_BIKEROUTE_COLOR, toX, toY); + } else { + // Plain fill and line + ctx.beginPath(); + ctx.moveTo(PADDING.left, PADDING.top + chartH); + for (const p of points) { + ctx.lineTo(toX(p.distance), toY(p.elevation)); + } + ctx.lineTo(PADDING.left + chartW, PADDING.top + chartH); + ctx.closePath(); + ctx.fillStyle = "rgba(37, 99, 235, 0.15)"; + ctx.fill(); + + ctx.beginPath(); + for (let i = 0; i < points.length; i++) { + const p = points[i]!; + if (i === 0) ctx.moveTo(toX(p.distance), toY(p.elevation)); + else ctx.lineTo(toX(p.distance), toY(p.elevation)); + } + ctx.strokeStyle = "#2563eb"; + ctx.lineWidth = 1.5; + ctx.stroke(); + } + + // Axis labels + ctx.fillStyle = "#6b7280"; + ctx.font = "10px sans-serif"; + ctx.textAlign = "right"; + ctx.fillText(`${Math.round(maxEle)}m`, PADDING.left - 4, PADDING.top + 10); + ctx.fillText(`${Math.round(minEle)}m`, PADDING.left - 4, PADDING.top + chartH); + ctx.textAlign = "center"; + ctx.fillText("0 km", PADDING.left, h - 4); + ctx.fillText(`${(maxDist / 1000).toFixed(1)} km`, PADDING.left + chartW, h - 4); + + // Day dividers + if (days && days.length > 1) { + for (let d = 0; d < days.length - 1; d++) { + const boundaryDist = days.slice(0, d + 1).reduce((sum, s) => sum + s.distance, 0); + const bx = toX(boundaryDist); + + ctx.beginPath(); + ctx.setLineDash([4, 3]); + ctx.moveTo(bx, PADDING.top); + ctx.lineTo(bx, PADDING.top + chartH); + ctx.strokeStyle = "#9A9484"; + ctx.lineWidth = 1; + ctx.stroke(); + ctx.setLineDash([]); + + ctx.fillStyle = "#9A9484"; + ctx.font = "9px sans-serif"; + ctx.textAlign = "center"; + ctx.fillText(`${(boundaryDist / 1000).toFixed(0)} km`, bx, h - 4); + } + } + + // Hover crosshair + info + if (hoverIdx !== null && hoverIdx >= 0 && hoverIdx < points.length) { + const p = points[hoverIdx]!; + const hx = toX(p.distance); + const hy = toY(p.elevation); + + ctx.beginPath(); + ctx.moveTo(hx, PADDING.top); + ctx.lineTo(hx, PADDING.top + chartH); + ctx.strokeStyle = "rgba(239, 68, 68, 0.5)"; + ctx.lineWidth = 1; + ctx.stroke(); + + ctx.beginPath(); + ctx.arc(hx, hy, 4, 0, Math.PI * 2); + ctx.fillStyle = "#ef4444"; + ctx.fill(); + ctx.strokeStyle = "white"; + ctx.lineWidth = 2; + ctx.stroke(); + + ctx.fillStyle = "#1f2937"; + ctx.font = "bold 10px sans-serif"; + ctx.textAlign = "left"; + let label = `${Math.round(p.elevation)}m · ${(p.distance / 1000).toFixed(1)}km`; + if (colorMode === "grade" && hoverIdx > 0) { + const prev = points[hoverIdx - 1]!; + const dDist = p.distance - prev.distance; + const grade = dDist > 0 ? ((p.elevation - prev.elevation) / dDist) * 100 : 0; + label += ` · ${grade > 0 ? "+" : ""}${grade.toFixed(1)}%`; + } + if (colorMode === "surface" && surfaces[hoverIdx]) label += ` · ${surfaces[hoverIdx]}`; + if (colorMode === "highway" && highways[hoverIdx]) label += ` · ${highways[hoverIdx]}`; + if (colorMode === "maxspeed" && maxspeeds[hoverIdx]) { + const s = maxspeeds[hoverIdx]!; + label += ` · ${s === "unknown" ? s : `${s} km/h`}`; + } + if (colorMode === "smoothness" && smoothnesses[hoverIdx]) label += ` · ${smoothnesses[hoverIdx]}`; + if (colorMode === "tracktype" && tracktypes[hoverIdx]) label += ` · ${tracktypes[hoverIdx]}`; + if (colorMode === "cycleway" && cycleways[hoverIdx]) label += ` · ${cycleways[hoverIdx]}`; + if (colorMode === "bikeroute" && bikeroutes[hoverIdx]) { + const names: Record = { icn: "International", ncn: "National", rcn: "Regional", lcn: "Local", none: "None" }; + label += ` · ${names[bikeroutes[hoverIdx]!] ?? bikeroutes[hoverIdx]}`; + } + const labelX = hx + 8 > w - 80 ? hx - 8 : hx + 8; + ctx.textAlign = hx + 8 > w - 80 ? "right" : "left"; + ctx.fillText(label, labelX, PADDING.top + 10); + } + + // Drag selection overlay + if (isDragging && dragStartX != null && dragCurrentX != null) { + const x1 = Math.max(PADDING.left, Math.min(dragStartX, PADDING.left + chartW)); + const x2 = Math.max(PADDING.left, Math.min(dragCurrentX, PADDING.left + chartW)); + const selLeft = Math.min(x1, x2); + const selRight = Math.max(x1, x2); + ctx.fillStyle = "rgba(59, 130, 246, 0.15)"; + ctx.fillRect(selLeft, PADDING.top, selRight - selLeft, chartH); + ctx.strokeStyle = "rgba(59, 130, 246, 0.5)"; + ctx.lineWidth = 1; + ctx.strokeRect(selLeft, PADDING.top, selRight - selLeft, chartH); + } +} diff --git a/apps/planner/app/lib/use-elevation-data.ts b/apps/planner/app/lib/use-elevation-data.ts new file mode 100644 index 0000000..9ad3e01 --- /dev/null +++ b/apps/planner/app/lib/use-elevation-data.ts @@ -0,0 +1,98 @@ +import { useEffect, useState } from "react"; +import * as Y from "yjs"; +import type { ColorMode } from "~/components/ColoredRoute"; +import type { ElevationPoint } from "~/lib/elevation-chart-draw"; + +function haversine(lat1: number, lon1: number, lat2: number, lon2: number): number { + const R = 6371000; + const toRad = (d: number) => (d * Math.PI) / 180; + const dLat = toRad(lat2 - lat1); + const dLon = toRad(lon2 - lon1); + const a = + Math.sin(dLat / 2) ** 2 + + Math.cos(toRad(lat1)) * Math.cos(toRad(lat2)) * Math.sin(dLon / 2) ** 2; + return R * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); +} + +function extractElevation(geojsonStr: string): ElevationPoint[] { + try { + const geojson = JSON.parse(geojsonStr); + const coords: number[][] = geojson.features?.[0]?.geometry?.coordinates ?? []; + if (coords.length === 0) return []; + + const points: ElevationPoint[] = []; + let totalDist = 0; + + for (let i = 0; i < coords.length; i++) { + if (i > 0) { + const prev = coords[i - 1]!; + const curr = coords[i]!; + totalDist += haversine(prev[1]!, prev[0]!, curr[1]!, curr[0]!); + } + if (coords[i]![2] !== undefined) { + points.push({ + distance: totalDist, + elevation: coords[i]![2]!, + lat: coords[i]![1]!, + lon: coords[i]![0]!, + }); + } + } + return points; + } catch { + return []; + } +} + +function parseJsonArray(json: string | undefined): string[] { + if (!json) return []; + try { return JSON.parse(json); } catch { return []; } +} + +export interface ElevationData { + points: ElevationPoint[]; + colorMode: ColorMode; + surfaces: string[]; + highways: string[]; + maxspeeds: string[]; + smoothnesses: string[]; + tracktypes: string[]; + cycleways: string[]; + bikeroutes: string[]; +} + +export function useElevationData(routeData: Y.Map): ElevationData { + const [data, setData] = useState({ + points: [], + colorMode: "plain", + surfaces: [], + highways: [], + maxspeeds: [], + smoothnesses: [], + tracktypes: [], + cycleways: [], + bikeroutes: [], + }); + + useEffect(() => { + const update = () => { + const geojson = routeData.get("geojson") as string | undefined; + setData({ + points: geojson ? extractElevation(geojson) : [], + colorMode: (routeData.get("colorMode") as ColorMode | undefined) ?? "plain", + surfaces: parseJsonArray(routeData.get("surfaces") as string | undefined), + highways: parseJsonArray(routeData.get("highways") as string | undefined), + maxspeeds: parseJsonArray(routeData.get("maxspeeds") as string | undefined), + smoothnesses: parseJsonArray(routeData.get("smoothnesses") as string | undefined), + tracktypes: parseJsonArray(routeData.get("tracktypes") as string | undefined), + cycleways: parseJsonArray(routeData.get("cycleways") as string | undefined), + bikeroutes: parseJsonArray(routeData.get("bikeroutes") as string | undefined), + }); + }; + routeData.observe(update); + update(); + return () => routeData.unobserve(update); + }, [routeData]); + + return data; +} diff --git a/apps/planner/app/lib/use-gpx-drop.ts b/apps/planner/app/lib/use-gpx-drop.ts new file mode 100644 index 0000000..c0bcd8b --- /dev/null +++ b/apps/planner/app/lib/use-gpx-drop.ts @@ -0,0 +1,77 @@ +import { useState, useRef, useCallback } from "react"; +import * as Y from "yjs"; +import { useTranslation } from "react-i18next"; +import { parseGpxAsync, extractWaypoints } from "@trails-cool/gpx"; +import type { YjsState } from "~/lib/use-yjs"; + +export function useGpxDrop(yjs: YjsState, onImportError?: (message: string) => void) { + const { t } = useTranslation("planner"); + const [draggingOver, setDraggingOver] = useState(false); + const dragCounterRef = useRef(0); + + const handleDragEnter = useCallback((e: React.DragEvent) => { + e.preventDefault(); + dragCounterRef.current++; + if (dragCounterRef.current === 1) setDraggingOver(true); + }, []); + + const handleDragLeave = useCallback((e: React.DragEvent) => { + e.preventDefault(); + dragCounterRef.current--; + if (dragCounterRef.current === 0) setDraggingOver(false); + }, []); + + const handleDragOver = useCallback((e: React.DragEvent) => { + e.preventDefault(); + }, []); + + const handleDrop = useCallback(async (e: React.DragEvent) => { + e.preventDefault(); + dragCounterRef.current = 0; + setDraggingOver(false); + + const file = e.dataTransfer.files[0]; + if (!file) return; + if (!file.name.toLowerCase().endsWith(".gpx")) { + onImportError?.(t("importGpxError")); + return; + } + + try { + const text = await file.text(); + const gpxData = await parseGpxAsync(text); + const newWaypoints = extractWaypoints(gpxData); + if (newWaypoints.length < 2) return; + + if (!window.confirm(t("replaceRouteConfirm"))) return; + + yjs.doc.transact(() => { + yjs.waypoints.delete(0, yjs.waypoints.length); + for (const wp of newWaypoints) { + const yMap = new Y.Map(); + yMap.set("lat", wp.lat); + yMap.set("lon", wp.lon); + if (wp.name) yMap.set("name", wp.name); + if (wp.isDayBreak) yMap.set("overnight", true); + yjs.waypoints.push([yMap]); + } + + yjs.noGoAreas.delete(0, yjs.noGoAreas.length); + for (const area of gpxData.noGoAreas) { + const yMap = new Y.Map(); + yMap.set("points", area.points); + yjs.noGoAreas.push([yMap]); + } + + if (gpxData.description) { + yjs.notes.delete(0, yjs.notes.length); + yjs.notes.insert(0, gpxData.description); + } + }, "local"); + } catch { + onImportError?.(t("importGpxError")); + } + }, [yjs, t, onImportError]); + + return { draggingOver, handleDragEnter, handleDragLeave, handleDragOver, handleDrop }; +} diff --git a/apps/planner/app/lib/use-waypoint-manager.ts b/apps/planner/app/lib/use-waypoint-manager.ts new file mode 100644 index 0000000..085f4bb --- /dev/null +++ b/apps/planner/app/lib/use-waypoint-manager.ts @@ -0,0 +1,286 @@ +import { useEffect, useState, useCallback } from "react"; +import * as Y from "yjs"; +import type { YjsState } from "~/lib/use-yjs"; +import type { ColorMode } from "~/components/ColoredRoute"; +import { usePois } from "~/lib/use-pois"; +import { snapToPoi } from "~/lib/poi-snap"; +import { isOvernight } from "~/lib/overnight"; +import { findSegmentForPoint } from "~/components/ColoredRoute"; + +export interface WaypointData { + lat: number; + lon: number; + name?: string; + overnight: boolean; +} + +function getWaypointsFromYjs(waypoints: Y.Array>): WaypointData[] { + return waypoints.toArray().map((yMap) => ({ + lat: yMap.get("lat") as number, + lon: yMap.get("lon") as number, + name: yMap.get("name") as string | undefined, + overnight: isOvernight(yMap), + })); +} + +function pointToSegmentDist( + pLat: number, pLon: number, + aLat: number, aLon: number, + bLat: number, bLon: number, +): number { + const dx = bLon - aLon; + const dy = bLat - aLat; + const lenSq = dx * dx + dy * dy; + if (lenSq === 0) return Math.sqrt((pLon - aLon) ** 2 + (pLat - aLat) ** 2); + const t = Math.max(0, Math.min(1, ((pLon - aLon) * dx + (pLat - aLat) * dy) / lenSq)); + const projLon = aLon + t * dx; + const projLat = aLat + t * dy; + return Math.sqrt((pLon - projLon) ** 2 + (pLat - projLat) ** 2); +} + +function parseJsonArray(json: string | undefined): T[] { + if (!json) return []; + try { return JSON.parse(json); } catch { return []; } +} + +export interface RouteState { + waypoints: WaypointData[]; + routeCoordinates: [number, number, number][] | null; + segmentBoundaries: number[]; + surfaces: string[]; + highways: string[]; + maxspeeds: string[]; + smoothnesses: string[]; + tracktypes: string[]; + cycleways: string[]; + bikeroutes: string[]; + colorMode: ColorMode; +} + +export function useWaypointManager( + yjs: YjsState, + poiState: ReturnType, + suppressMapClickRef: React.RefObject, + onRouteRequest?: (waypoints: WaypointData[]) => void, +) { + const [state, setState] = useState({ + waypoints: [], + routeCoordinates: null, + segmentBoundaries: [], + surfaces: [], + highways: [], + maxspeeds: [], + smoothnesses: [], + tracktypes: [], + cycleways: [], + bikeroutes: [], + colorMode: "plain", + }); + + // Sync waypoints from Yjs + useEffect(() => { + const update = () => { + const wps = getWaypointsFromYjs(yjs.waypoints); + setState((prev) => ({ ...prev, waypoints: wps })); + if (wps.length >= 2 && onRouteRequest) { + onRouteRequest(wps); + } + }; + yjs.waypoints.observeDeep(update); + update(); + return () => yjs.waypoints.unobserveDeep(update); + }, [yjs.waypoints, onRouteRequest]); + + // Sync route data from Yjs + useEffect(() => { + const update = () => { + const coordsJson = yjs.routeData.get("coordinates") as string | undefined; + const boundsJson = yjs.routeData.get("segmentBoundaries") as string | undefined; + const modeVal = yjs.routeData.get("colorMode") as ColorMode | undefined; + + let routeCoordinates: [number, number, number][] | null = null; + if (coordsJson) { + try { routeCoordinates = JSON.parse(coordsJson); } catch { /* ignore */ } + } else { + // Fallback: parse from geojson for backwards compat + const geojson = yjs.routeData.get("geojson") as string | undefined; + if (geojson) { + try { + const parsed = JSON.parse(geojson); + const coords = parsed.features?.[0]?.geometry?.coordinates; + if (coords) { + routeCoordinates = coords.map((c: number[]) => [c[0]!, c[1]!, c[2] ?? 0] as [number, number, number]); + } + } catch { /* ignore */ } + } + } + + setState((prev) => ({ + ...prev, + routeCoordinates, + segmentBoundaries: parseJsonArray(boundsJson), + surfaces: parseJsonArray(yjs.routeData.get("surfaces") as string | undefined), + highways: parseJsonArray(yjs.routeData.get("highways") as string | undefined), + maxspeeds: parseJsonArray(yjs.routeData.get("maxspeeds") as string | undefined), + smoothnesses: parseJsonArray(yjs.routeData.get("smoothnesses") as string | undefined), + tracktypes: parseJsonArray(yjs.routeData.get("tracktypes") as string | undefined), + cycleways: parseJsonArray(yjs.routeData.get("cycleways") as string | undefined), + bikeroutes: parseJsonArray(yjs.routeData.get("bikeroutes") as string | undefined), + colorMode: modeVal ?? "plain", + })); + }; + yjs.routeData.observe(update); + update(); + return () => yjs.routeData.unobserve(update); + }, [yjs.routeData]); + + const addWaypoint = useCallback( + (lat: number, lng: number, name?: string) => { + const { routeCoordinates, segmentBoundaries } = state; + const snap = snapToPoi(lat, lng, poiState.pois); + const finalLat = snap.lat; + const finalLon = snap.snapped ? snap.lon : lng; + + let insertIndex = yjs.waypoints.length; + if (routeCoordinates && routeCoordinates.length >= 2 && segmentBoundaries.length > 0) { + let bestDist = Infinity; + let bestSegment = -1; + for (let seg = 0; seg < segmentBoundaries.length; seg++) { + const start = segmentBoundaries[seg]!; + const end = seg + 1 < segmentBoundaries.length ? segmentBoundaries[seg + 1]! : routeCoordinates.length; + for (let i = start; i < end - 1; i++) { + const c1 = routeCoordinates[i]!; + const c2 = routeCoordinates[i + 1]!; + const dist = pointToSegmentDist(finalLat, finalLon, c1[1]!, c1[0]!, c2[1]!, c2[0]!); + if (dist < bestDist) { + bestDist = dist; + bestSegment = seg; + } + } + } + if (bestDist < 0.01 && bestSegment >= 0) { + insertIndex = bestSegment + 1; + } + } + + yjs.doc.transact(() => { + const yMap = new Y.Map(); + yMap.set("lat", finalLat); + yMap.set("lon", finalLon); + if (snap.name) yMap.set("name", snap.name); + else if (name) yMap.set("name", name); + if (snap.osmId) yMap.set("osmId", snap.osmId); + if (snap.poiTags) yMap.set("poiTags", snap.poiTags); + yjs.waypoints.insert(insertIndex, [yMap]); + }, "local"); + }, + [yjs.doc, yjs.waypoints, poiState.pois, state], + ); + + const insertWaypointAtSegment = useCallback( + (segmentIndex: number, lat: number, lon: number) => { + const snap = snapToPoi(lat, lon, poiState.pois); + yjs.doc.transact(() => { + const yMap = new Y.Map(); + yMap.set("lat", snap.lat); + yMap.set("lon", snap.snapped ? snap.lon : lon); + if (snap.name) yMap.set("name", snap.name); + if (snap.osmId) yMap.set("osmId", snap.osmId); + if (snap.poiTags) yMap.set("poiTags", snap.poiTags); + yjs.waypoints.insert(segmentIndex + 1, [yMap]); + }, "local"); + }, + [yjs.doc, yjs.waypoints, poiState.pois], + ); + + const handleRouteInsert = useCallback( + (pointIndex: number, lat: number, lon: number) => { + suppressMapClickRef.current = true; + const segIdx = findSegmentForPoint(pointIndex, state.segmentBoundaries); + insertWaypointAtSegment(segIdx, lat, lon); + }, + [state.segmentBoundaries, insertWaypointAtSegment, suppressMapClickRef], + ); + + const moveWaypoint = useCallback( + (index: number, lat: number, lng: number) => { + const snap = snapToPoi(lat, lng, poiState.pois); + const yMap = yjs.waypoints.get(index); + if (yMap) { + yjs.doc.transact(() => { + yMap.set("lat", snap.lat); + yMap.set("lon", snap.snapped ? snap.lon : lng); + if (snap.snapped && snap.name) { + yMap.set("name", snap.name); + } else { + yMap.delete("name"); + } + if (snap.osmId) { + yMap.set("osmId", snap.osmId); + if (snap.poiTags) yMap.set("poiTags", snap.poiTags); + } else { + yMap.delete("osmId"); + yMap.delete("poiTags"); + } + }, "local"); + } + }, + [yjs.waypoints, yjs.doc, poiState.pois], + ); + + const deleteWaypoint = useCallback( + (index: number) => { + yjs.doc.transact(() => { + yjs.waypoints.delete(index, 1); + }, "local"); + }, + [yjs.waypoints], + ); + + const handleRoutePolylineHover = useCallback( + (e: { latlng: { lat: number; lng: number } }, onRouteHover: (d: number | null) => void) => { + const { routeCoordinates } = state; + if (!routeCoordinates || routeCoordinates.length < 2) return; + const { lat, lng } = e.latlng; + + let bestIdx = 0; + let bestDist = Infinity; + for (let i = 0; i < routeCoordinates.length; i++) { + const c = routeCoordinates[i]!; + const dLat = c[1]! - lat; + const dLon = c[0]! - lng; + const dist = dLat * dLat + dLon * dLon; + if (dist < bestDist) { + bestDist = dist; + bestIdx = i; + } + } + + let totalDist = 0; + for (let i = 1; i <= bestIdx; i++) { + const prev = routeCoordinates[i - 1]!; + const curr = routeCoordinates[i]!; + const R = 6371000; + const toRad = (d: number) => (d * Math.PI) / 180; + const dLat = toRad(curr[1]! - prev[1]!); + const dLon = toRad(curr[0]! - prev[0]!); + const a = + Math.sin(dLat / 2) ** 2 + + Math.cos(toRad(prev[1]!)) * Math.cos(toRad(curr[1]!)) * Math.sin(dLon / 2) ** 2; + totalDist += R * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); + } + onRouteHover(totalDist); + }, + [state], + ); + + return { + ...state, + addWaypoint, + insertWaypointAtSegment, + handleRouteInsert, + moveWaypoint, + deleteWaypoint, + handleRoutePolylineHover, + }; +} diff --git a/apps/planner/package.json b/apps/planner/package.json index e889d3b..a2093e2 100644 --- a/apps/planner/package.json +++ b/apps/planner/package.json @@ -9,7 +9,9 @@ "start": "node server.ts", "typecheck": "react-router typegen && tsc", "lint": "eslint .", - "test": "vitest run" + "test": "vitest run", + "test:visual": "vitest run --config vitest.browser.config.ts", + "test:visual:update": "vitest run --config vitest.browser.config.ts --update-snapshots" }, "dependencies": { "@codemirror/commands": "^6.10.3", @@ -22,9 +24,9 @@ "@sentry/node": "catalog:", "@sentry/react": "catalog:", "@trails-cool/db": "workspace:*", - "@trails-cool/jobs": "workspace:*", "@trails-cool/gpx": "workspace:*", "@trails-cool/i18n": "workspace:*", + "@trails-cool/jobs": "workspace:*", "@trails-cool/map": "workspace:*", "@trails-cool/map-core": "workspace:*", "@trails-cool/sentry-config": "workspace:*", @@ -52,6 +54,7 @@ "@types/react": "catalog:", "@types/react-dom": "catalog:", "@types/ws": "^8.18.1", + "@vitest/browser": "^4.1.5", "leaflet.markercluster": "^1.5.3", "pino-pretty": "^13.1.3", "tailwindcss": "catalog:", diff --git a/apps/planner/vitest.browser.config.ts b/apps/planner/vitest.browser.config.ts new file mode 100644 index 0000000..06b8978 --- /dev/null +++ b/apps/planner/vitest.browser.config.ts @@ -0,0 +1,33 @@ +import { defineConfig } from "vitest/config"; +import { resolve } from "node:path"; + +// Separate config for Vitest browser visual regression tests. +// Run with: pnpm --filter @trails-cool/planner test:visual +// Update snapshots: pnpm --filter @trails-cool/planner test:visual:update +// +// Snapshots live next to each test file in a __screenshots__/ directory. +// On CI, snapshots are updated via the "Update visual snapshots" workflow +// (.github/workflows/update-visual-snapshots.yml), triggered manually or +// by adding the `update-snapshots` label to a PR. +export default defineConfig({ + esbuild: { + jsx: "automatic", + }, + resolve: { + alias: { + "~": resolve(import.meta.dirname, "app"), + }, + }, + test: { + name: "browser", + include: ["app/**/*.browser.test.{ts,tsx}"], + browser: { + enabled: true, + // Provider is resolved from whichever @vitest/browser peer is installed. + // playwright is the default when @playwright/test is available. + // eslint-disable-next-line @typescript-eslint/no-explicit-any + provider: "playwright" as any, + instances: [{ browser: "chromium" }], + }, + }, +}); diff --git a/apps/planner/vitest.config.ts b/apps/planner/vitest.config.ts index cf58c77..3158f62 100644 --- a/apps/planner/vitest.config.ts +++ b/apps/planner/vitest.config.ts @@ -12,5 +12,9 @@ export default mergeConfig( "~": resolve(import.meta.dirname, "app"), }, }, + test: { + // Exclude browser visual regression tests — they run via vitest.browser.config.ts + exclude: ["**/*.browser.test.{ts,tsx}"], + }, }), ); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c34b487..c3059ad 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -151,13 +151,13 @@ importers: version: 8.2.1 jsdom: specifier: ^29.1.1 - version: 29.1.1 + version: 29.1.1(canvas@3.2.3) leaflet: specifier: ^1.9.4 version: 1.9.4 linkedom: specifier: ^0.18.12 - version: 0.18.12 + version: 0.18.12(canvas@3.2.3) playwright: specifier: ^1.59.1 version: 1.59.1 @@ -196,7 +196,7 @@ importers: version: 8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4) vitest: specifier: ^4.1.5 - version: 4.1.5(@opentelemetry/api@1.9.1)(@types/node@25.6.2)(jsdom@29.1.1)(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4)) + version: 4.1.5(@opentelemetry/api@1.9.1)(@types/node@25.6.2)(jsdom@29.1.1(canvas@3.2.3))(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4)) apps/journal: dependencies: @@ -441,7 +441,7 @@ importers: version: 19.2.14 jest-expo: specifier: ^55.0.17 - version: 55.0.17(@babel/core@7.29.0)(expo@55.0.23)(jest@29.7.0(@types/node@25.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.6))(react@19.2.6)(typescript@5.9.3) + version: 55.0.17(@babel/core@7.29.0)(canvas@3.2.3)(expo@55.0.23)(jest@29.7.0(@types/node@25.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.6))(react@19.2.6)(typescript@5.9.3) react-test-renderer: specifier: ^19.2.6 version: 19.2.6(react@19.2.6) @@ -566,6 +566,9 @@ importers: '@types/ws': specifier: ^8.18.1 version: 8.18.1 + '@vitest/browser': + specifier: ^4.1.5 + version: 4.1.5(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4))(vitest@4.1.5(@opentelemetry/api@1.9.1)(@types/node@25.6.2)(jsdom@29.1.1(canvas@3.2.3))(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4))) leaflet.markercluster: specifier: ^1.5.3 version: 1.5.3(leaflet@1.9.4) @@ -624,7 +627,7 @@ importers: version: link:../types linkedom: specifier: ^0.18.12 - version: 0.18.12 + version: 0.18.12(canvas@3.2.3) devDependencies: '@types/node': specifier: 'catalog:' @@ -1207,6 +1210,9 @@ packages: '@bcoe/v8-coverage@0.2.3': resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} + '@blazediff/core@1.9.1': + resolution: {integrity: sha512-ehg3jIkYKulZh+8om/O25vkvSsXXwC+skXmyA87FFx6A/45eqOkZsBltMw/TVteb0mloiGT8oGRTcjRAz66zaA==} + '@bramus/specificity@2.4.2': resolution: {integrity: sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw==} hasBin: true @@ -2543,6 +2549,9 @@ packages: engines: {node: '>=18'} hasBin: true + '@polka/url@1.0.0-next.29': + resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==} + '@posthog/core@1.28.4': resolution: {integrity: sha512-wmtUYHYqA3zIAKDKvYWRNWAQsWOIBwxV08e+bWzVy0wQQzpaS/LzzRupXWRMRrLOk+1x3JKFxbqA3n0QGvpqsQ==} @@ -3927,6 +3936,11 @@ packages: peerDependencies: vite: ^6.0.0 || ^7.0.0 || ^8.0.0 + '@vitest/browser@4.1.5': + resolution: {integrity: sha512-iCDGI8c4yg+xmjUg2VsygdAUSIIB4x5Rht/P68OXy1hPELKXHDkzh87lkuTcdYmemRChDkEpB426MmDjzC0ziA==} + peerDependencies: + vitest: 4.1.5 + '@vitest/expect@4.1.5': resolution: {integrity: sha512-PWBaRY5JoKuRnHlUHfpV/KohFylaDZTupcXN1H9vYryNLOnitSw60Mw9IAE2r67NbwwzBw/Cc/8q9BK3kIX8Kw==} @@ -4211,6 +4225,9 @@ packages: bintrees@1.0.2: resolution: {integrity: sha512-VOMgTMwjAaUG580SXn3LacVgjurrbMme7ZZNYGSSV7mmtY6QQRh0Eg3pwIcntQ77DErK1L0NxkbetjcoXzVwKw==} + bl@4.1.0: + resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} + body-parser@1.20.5: resolution: {integrity: sha512-3grm+/2tUOvu2cjJkvsIxrv/wVpfXQW4PsQHYm7yk4vfpu7Ekl6nEsYBoJUL6qDwZUx8wUhQ8tR2qz+ad9c9OA==} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} @@ -4251,6 +4268,9 @@ packages: buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + buffer@5.7.1: + resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} + buffer@6.0.3: resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} @@ -4285,6 +4305,10 @@ packages: caniuse-lite@1.0.30001792: resolution: {integrity: sha512-hVLMUZFgR4JJ6ACt1uEESvQN1/dBVqPAKY0hgrV70eN3391K6juAfTjKZLKvOMsx8PxA7gsY1/tLMMTcfFLLpw==} + canvas@3.2.3: + resolution: {integrity: sha512-PzE5nJZPz72YUAfo8oTp0u3fqqY7IzlTubneAihqDYAUcBk7ryeCmBbdJBEdaH0bptSOe2VT2Zwcb3UaFyaSWw==} + engines: {node: ^18.12.0 || >= 20.9.0} + chai@6.2.2: resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} engines: {node: '>=18'} @@ -4320,6 +4344,9 @@ packages: resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} engines: {node: '>= 14.16.0'} + chownr@1.1.4: + resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} + chrome-launcher@0.15.2: resolution: {integrity: sha512-zdLEwNo3aUVzIhKhTtXfxhdvZhUghrnmkvcAq2NoDd+LeOHKf03H5jwZ8T/STsAlzyALkBVK552iaG1fGf1xVQ==} engines: {node: '>=12.13.0'} @@ -4549,6 +4576,10 @@ packages: resolution: {integrity: sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==} engines: {node: '>=0.10'} + decompress-response@6.0.0: + resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} + engines: {node: '>=10'} + dedent@1.7.2: resolution: {integrity: sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA==} peerDependencies: @@ -4557,6 +4588,10 @@ packages: babel-plugin-macros: optional: true + deep-extend@0.6.0: + resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} + engines: {node: '>=4.0.0'} + deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} @@ -4926,6 +4961,10 @@ packages: resolution: {integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==} engines: {node: '>= 0.8.0'} + expand-template@2.0.3: + resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==} + engines: {node: '>=6'} + expect-type@1.3.0: resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} engines: {node: '>=12.0.0'} @@ -5291,6 +5330,9 @@ packages: resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} engines: {node: '>= 0.6'} + fs-constants@1.0.0: + resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} + fs.realpath@1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} @@ -5350,6 +5392,9 @@ packages: resolution: {integrity: sha512-VilgtJj/ALgGY77fiLam5iD336eSWi96Q15JSAG1zi8NRBysm3LXKdGnHb4m5cuyxvOLQQKWpBZAT6ni4FI2iQ==} engines: {node: '>=6'} + github-from-package@0.0.0: + resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==} + glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} @@ -5536,6 +5581,9 @@ packages: inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + ini@1.3.8: + resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} + invariant@2.2.4: resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==} @@ -6239,6 +6287,10 @@ packages: resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==} engines: {node: '>=18'} + mimic-response@3.1.0: + resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} + engines: {node: '>=10'} + min-indent@1.0.1: resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} engines: {node: '>=4'} @@ -6257,6 +6309,9 @@ packages: resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} engines: {node: '>=16 || 14 >=14.17'} + mkdirp-classic@0.5.3: + resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} + mkdirp@1.0.4: resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} engines: {node: '>=10'} @@ -6269,6 +6324,10 @@ packages: resolution: {integrity: sha512-223dMRJtI/l25dJKWpgij2cMtywuG/WiUKXdvwfbhGKBhy1puASqXwFzmWZ7+K73vUPoR7SS2Qz2cI/g9MKw0A==} engines: {node: '>= 0.8.0'} + mrmime@2.0.1: + resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==} + engines: {node: '>=10'} + ms@2.0.0: resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} @@ -6287,6 +6346,9 @@ packages: engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + napi-build-utils@2.0.0: + resolution: {integrity: sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==} + natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} @@ -6302,6 +6364,13 @@ packages: resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} engines: {node: '>= 0.6'} + node-abi@3.92.0: + resolution: {integrity: sha512-KdHvFWZjEKDf0cakgFjebl371GPsISX2oZHcuyKqM7DtogIsHrqKeLTo8wBHxaXRAQlY2PsPlZmfo+9ZCxEREQ==} + engines: {node: '>=10'} + + node-addon-api@7.1.1: + resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} + node-fetch@2.7.0: resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} engines: {node: 4.x || >=6.0.0} @@ -6579,6 +6648,10 @@ packages: resolution: {integrity: sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==} engines: {node: '>=4.0.0'} + pngjs@7.0.0: + resolution: {integrity: sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow==} + engines: {node: '>=14.19.0'} + point-in-polygon-hao@1.2.4: resolution: {integrity: sha512-x2pcvXeqhRHlNRdhLs/tgFapAbSSe86wa/eqmj1G6pWftbEs5aVRJhRGM6FYSUERKu0PjekJzMq0gsI2XyiclQ==} @@ -6622,6 +6695,12 @@ packages: rxjs: optional: true + prebuild-install@7.1.3: + resolution: {integrity: sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==} + engines: {node: '>=10'} + deprecated: No longer maintained. Please contact the author of the relevant native addon; alternatives are available. + hasBin: true + prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} @@ -6733,6 +6812,10 @@ packages: rbush@3.0.1: resolution: {integrity: sha512-XRaVO0YecOpEuIvbhbpTrZgoiI6xBlz6hnlr6EHhd+0x9ase6EmeN+hdwwUaJvLcsFFQ8iWVF1GAK1yB0BWi0w==} + rc@1.2.8: + resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} + hasBin: true + react-devtools-core@6.1.5: resolution: {integrity: sha512-ePrwPfxAnB+7hgnEr8vpKxL9cmnp7F322t8oqcPshbIQQhDKgFDW4tjhF2wjVbdXF9O/nyuy3sQWd9JGpiLPvA==} @@ -6893,6 +6976,10 @@ packages: resolution: {integrity: sha512-sfWGGfavi0xr8Pg0sVsyHMAOziVYKgPLNrS7ig+ivMNb3wbCBw3KxtflsGBAwD3gYQlE/AEZsTLgToRrSCjb0Q==} engines: {node: '>=0.10.0'} + readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} + readdirp@4.1.2: resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} engines: {node: '>= 14.18.0'} @@ -7117,12 +7204,22 @@ packages: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} + simple-concat@1.0.1: + resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==} + + simple-get@4.0.1: + resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==} + simple-plist@1.3.1: resolution: {integrity: sha512-iMSw5i0XseMnrhtIzRb7XpQEXepa9xhWxGUojHBL43SIpQuDQkh3Wpy67ZbDzZVr6EKxvwVChnVpdl8hEVLDiw==} simple-swizzle@0.2.4: resolution: {integrity: sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw==} + sirv@3.0.2: + resolution: {integrity: sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==} + engines: {node: '>=18'} + sisteransi@1.0.5: resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} @@ -7239,6 +7336,9 @@ packages: resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} engines: {node: '>=18'} + string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + strip-ansi@5.2.0: resolution: {integrity: sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==} engines: {node: '>=6'} @@ -7263,6 +7363,10 @@ packages: resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} engines: {node: '>=8'} + strip-json-comments@2.0.1: + resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} + engines: {node: '>=0.10.0'} + strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} @@ -7314,6 +7418,13 @@ packages: resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==} engines: {node: '>=6'} + tar-fs@2.1.4: + resolution: {integrity: sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==} + + tar-stream@2.2.0: + resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} + engines: {node: '>=6'} + tdigest@0.1.2: resolution: {integrity: sha512-+G0LLgjjo9BZX2MfdvPfH+MKLCrxlXSYec5DaPYP1fe6Iyhf0/fSmJ0bFiZ1F8BT6cGXl2LpltQptzjXKWEkKA==} @@ -7379,6 +7490,10 @@ packages: toqr@0.1.1: resolution: {integrity: sha512-FWAPzCIHZHnrE/5/w9MPk0kK25hSQSH2IKhYh9PyjS3SG/+IEMvlwIHbhz+oF7xl54I+ueZlVnMjyzdSwLmAwA==} + totalist@3.0.1: + resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} + engines: {node: '>=6'} + tough-cookie@4.1.4: resolution: {integrity: sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==} engines: {node: '>=6'} @@ -7419,6 +7534,9 @@ packages: resolution: {integrity: sha512-axr3IdNuVIxnaK5XGEUFTu3YmAQ6lllgrvqfEoR16g/HGnYY/6We4oWENtAnzK6/LpJ2ur9PAb80RBt7/U4ugw==} engines: {node: '>= 6.0.0'} + tunnel-agent@0.6.0: + resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} + turbo@2.9.12: resolution: {integrity: sha512-lCPgus1NuTiBdaITWqzSH/Ff6HVL8HHGBtOXHg1dHRfcshN79XkygSdh0M6g8b0td91ILLG5MTkLOkp5UvyPJw==} hasBin: true @@ -7551,6 +7669,9 @@ packages: peerDependencies: react: ^19.2.5 + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + utils-merge@1.0.1: resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} engines: {node: '>= 0.4.0'} @@ -8552,6 +8673,8 @@ snapshots: '@bcoe/v8-coverage@0.2.3': {} + '@blazediff/core@1.9.1': {} + '@bramus/specificity@2.4.2': dependencies: css-tree: 3.2.1 @@ -10058,6 +10181,8 @@ snapshots: dependencies: playwright: 1.59.1 + '@polka/url@1.0.0-next.29': {} + '@posthog/core@1.28.4': dependencies: '@posthog/types': 1.372.10 @@ -11616,6 +11741,23 @@ snapshots: dependencies: vite: 8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4) + '@vitest/browser@4.1.5(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4))(vitest@4.1.5(@opentelemetry/api@1.9.1)(@types/node@25.6.2)(jsdom@29.1.1(canvas@3.2.3))(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4)))': + dependencies: + '@blazediff/core': 1.9.1 + '@vitest/mocker': 4.1.5(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4)) + '@vitest/utils': 4.1.5 + magic-string: 0.30.21 + pngjs: 7.0.0 + sirv: 3.0.2 + tinyrainbow: 3.1.0 + vitest: 4.1.5(@opentelemetry/api@1.9.1)(@types/node@25.6.2)(jsdom@29.1.1(canvas@3.2.3))(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4)) + ws: 8.20.0 + transitivePeerDependencies: + - bufferutil + - msw + - utf-8-validate + - vite + '@vitest/expect@4.1.5': dependencies: '@standard-schema/spec': 1.1.0 @@ -11949,6 +12091,13 @@ snapshots: bintrees@1.0.2: {} + bl@4.1.0: + dependencies: + buffer: 5.7.1 + inherits: 2.0.4 + readable-stream: 3.6.2 + optional: true + body-parser@1.20.5: dependencies: bytes: 3.1.2 @@ -12007,6 +12156,12 @@ snapshots: buffer-from@1.1.2: {} + buffer@5.7.1: + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + optional: true + buffer@6.0.3: dependencies: base64-js: 1.5.1 @@ -12034,6 +12189,12 @@ snapshots: caniuse-lite@1.0.30001792: {} + canvas@3.2.3: + dependencies: + node-addon-api: 7.1.1 + prebuild-install: 7.1.3 + optional: true + chai@6.2.2: {} chalk@2.4.2: @@ -12064,6 +12225,9 @@ snapshots: dependencies: readdirp: 4.1.2 + chownr@1.1.4: + optional: true + chrome-launcher@0.15.2: dependencies: '@types/node': 25.6.2 @@ -12296,8 +12460,16 @@ snapshots: decode-uri-component@0.2.2: {} + decompress-response@6.0.0: + dependencies: + mimic-response: 3.1.0 + optional: true + dedent@1.7.2: {} + deep-extend@0.6.0: + optional: true + deep-is@0.1.4: {} deepmerge@4.3.1: {} @@ -12634,6 +12806,9 @@ snapshots: exit@0.1.2: {} + expand-template@2.0.3: + optional: true + expect-type@1.3.0: {} expect@29.7.0: @@ -13095,6 +13270,9 @@ snapshots: fresh@0.5.2: {} + fs-constants@1.0.0: + optional: true + fs.realpath@1.0.0: {} fsevents@2.3.2: @@ -13143,6 +13321,9 @@ snapshots: getenv@2.0.0: {} + github-from-package@0.0.0: + optional: true + glob-parent@5.1.2: dependencies: is-glob: 4.0.3 @@ -13337,6 +13518,9 @@ snapshots: inherits@2.0.4: {} + ini@1.3.8: + optional: true + invariant@2.2.4: dependencies: loose-envify: 1.4.0 @@ -13533,7 +13717,7 @@ snapshots: jest-util: 29.7.0 pretty-format: 29.7.0 - jest-environment-jsdom@29.7.0: + jest-environment-jsdom@29.7.0(canvas@3.2.3): dependencies: '@jest/environment': 29.7.0 '@jest/fake-timers': 29.7.0 @@ -13542,7 +13726,9 @@ snapshots: '@types/node': 25.6.2 jest-mock: 29.7.0 jest-util: 29.7.0 - jsdom: 20.0.3 + jsdom: 20.0.3(canvas@3.2.3) + optionalDependencies: + canvas: 3.2.3 transitivePeerDependencies: - bufferutil - supports-color @@ -13557,7 +13743,7 @@ snapshots: jest-mock: 29.7.0 jest-util: 29.7.0 - jest-expo@55.0.17(@babel/core@7.29.0)(expo@55.0.23)(jest@29.7.0(@types/node@25.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.6))(react@19.2.6)(typescript@5.9.3): + jest-expo@55.0.17(@babel/core@7.29.0)(canvas@3.2.3)(expo@55.0.23)(jest@29.7.0(@types/node@25.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.6))(react@19.2.6)(typescript@5.9.3): dependencies: '@expo/config': 55.0.16(typescript@5.9.3) '@expo/json-file': 10.0.14 @@ -13565,7 +13751,7 @@ snapshots: '@jest/globals': 29.7.0 babel-jest: 29.7.0(@babel/core@7.29.0) expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) - jest-environment-jsdom: 29.7.0 + jest-environment-jsdom: 29.7.0(canvas@3.2.3) 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.6.2)) @@ -13829,7 +14015,7 @@ snapshots: jsc-safe-url@0.2.4: {} - jsdom@20.0.3: + jsdom@20.0.3(canvas@3.2.3): dependencies: abab: 2.0.6 acorn: 8.16.0 @@ -13857,12 +14043,14 @@ snapshots: whatwg-url: 11.0.0 ws: 8.20.0 xml-name-validator: 4.0.0 + optionalDependencies: + canvas: 3.2.3 transitivePeerDependencies: - bufferutil - supports-color - utf-8-validate - jsdom@29.1.1: + jsdom@29.1.1(canvas@3.2.3): dependencies: '@asamuzakjp/css-color': 5.1.11 '@asamuzakjp/dom-selector': 7.1.1 @@ -13885,6 +14073,8 @@ snapshots: whatwg-mimetype: 5.0.0 whatwg-url: 16.0.1 xml-name-validator: 5.0.0 + optionalDependencies: + canvas: 3.2.3 transitivePeerDependencies: - '@noble/hashes' @@ -13987,13 +14177,15 @@ snapshots: lines-and-columns@1.2.4: {} - linkedom@0.18.12: + linkedom@0.18.12(canvas@3.2.3): dependencies: css-select: 5.2.2 cssom: 0.5.0 html-escaper: 3.0.3 htmlparser2: 10.1.0 uhyphen: 0.2.0 + optionalDependencies: + canvas: 3.2.3 locate-path@5.0.0: dependencies: @@ -14437,6 +14629,9 @@ snapshots: mimic-function@5.0.1: {} + mimic-response@3.1.0: + optional: true + min-indent@1.0.1: {} minimatch@10.2.5: @@ -14451,6 +14646,9 @@ snapshots: minipass@7.1.3: {} + mkdirp-classic@0.5.3: + optional: true + mkdirp@1.0.4: {} module-details-from-path@1.0.4: {} @@ -14465,6 +14663,8 @@ snapshots: transitivePeerDependencies: - supports-color + mrmime@2.0.1: {} + ms@2.0.0: {} ms@2.1.3: {} @@ -14475,6 +14675,9 @@ snapshots: nanoid@3.3.12: {} + napi-build-utils@2.0.0: + optional: true + natural-compare@1.4.0: {} negotiator@0.6.3: {} @@ -14483,6 +14686,14 @@ snapshots: negotiator@1.0.0: {} + node-abi@3.92.0: + dependencies: + semver: 7.8.0 + optional: true + + node-addon-api@7.1.1: + optional: true + node-fetch@2.7.0: dependencies: whatwg-url: 5.0.0 @@ -14772,6 +14983,8 @@ snapshots: pngjs@3.4.0: {} + pngjs@7.0.0: {} + point-in-polygon-hao@1.2.4: dependencies: robust-predicates: 3.0.3 @@ -14809,6 +15022,22 @@ snapshots: dependencies: '@posthog/core': 1.28.4 + prebuild-install@7.1.3: + dependencies: + detect-libc: 2.1.2 + expand-template: 2.0.3 + github-from-package: 0.0.0 + minimist: 1.2.8 + mkdirp-classic: 0.5.3 + napi-build-utils: 2.0.0 + node-abi: 3.92.0 + pump: 3.0.4 + rc: 1.2.8 + simple-get: 4.0.1 + tar-fs: 2.1.4 + tunnel-agent: 0.6.0 + optional: true + prelude-ls@1.2.1: {} prettier@3.8.3: {} @@ -14919,6 +15148,14 @@ snapshots: dependencies: quickselect: 2.0.0 + rc@1.2.8: + dependencies: + deep-extend: 0.6.0 + ini: 1.3.8 + minimist: 1.2.8 + strip-json-comments: 2.0.1 + optional: true + react-devtools-core@6.1.5: dependencies: shell-quote: 1.8.3 @@ -15118,6 +15355,13 @@ snapshots: react@19.2.6: {} + readable-stream@3.6.2: + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + optional: true + readdirp@4.1.2: {} real-require@0.2.0: {} @@ -15372,6 +15616,16 @@ snapshots: signal-exit@4.1.0: {} + simple-concat@1.0.1: + optional: true + + simple-get@4.0.1: + dependencies: + decompress-response: 6.0.0 + once: 1.4.0 + simple-concat: 1.0.1 + optional: true + simple-plist@1.3.1: dependencies: bplist-creator: 0.1.0 @@ -15382,6 +15636,12 @@ snapshots: dependencies: is-arrayish: 0.3.4 + sirv@3.0.2: + dependencies: + '@polka/url': 1.0.0-next.29 + mrmime: 2.0.1 + totalist: 3.0.1 + sisteransi@1.0.5: {} slash@3.0.0: {} @@ -15481,6 +15741,11 @@ snapshots: get-east-asian-width: 1.5.0 strip-ansi: 7.2.0 + string_decoder@1.3.0: + dependencies: + safe-buffer: 5.2.1 + optional: true + strip-ansi@5.2.0: dependencies: ansi-regex: 4.1.1 @@ -15501,6 +15766,9 @@ snapshots: dependencies: min-indent: 1.0.1 + strip-json-comments@2.0.1: + optional: true + strip-json-comments@3.1.1: {} strip-json-comments@5.0.3: {} @@ -15540,6 +15808,23 @@ snapshots: tapable@2.3.3: {} + tar-fs@2.1.4: + dependencies: + chownr: 1.1.4 + mkdirp-classic: 0.5.3 + pump: 3.0.4 + tar-stream: 2.2.0 + optional: true + + tar-stream@2.2.0: + dependencies: + bl: 4.1.0 + end-of-stream: 1.4.5 + fs-constants: 1.0.0 + inherits: 2.0.4 + readable-stream: 3.6.2 + optional: true + tdigest@0.1.2: dependencies: bintrees: 1.0.2 @@ -15599,6 +15884,8 @@ snapshots: toqr@0.1.1: {} + totalist@3.0.1: {} + tough-cookie@4.1.4: dependencies: psl: 1.15.0 @@ -15639,6 +15926,11 @@ snapshots: dependencies: tslib: 1.14.1 + tunnel-agent@0.6.0: + dependencies: + safe-buffer: 5.2.1 + optional: true + turbo@2.9.12: optionalDependencies: '@turbo/darwin-64': 2.9.12 @@ -15749,6 +16041,9 @@ snapshots: dependencies: react: 19.2.6 + util-deprecate@1.0.2: + optional: true + utils-merge@1.0.1: {} uuid@7.0.3: {} @@ -15830,7 +16125,7 @@ snapshots: tsx: 4.21.0 yaml: 2.8.4 - vitest@4.1.5(@opentelemetry/api@1.9.1)(@types/node@25.6.2)(jsdom@29.1.1)(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4)): + vitest@4.1.5(@opentelemetry/api@1.9.1)(@types/node@25.6.2)(jsdom@29.1.1(canvas@3.2.3))(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4)): dependencies: '@vitest/expect': 4.1.5 '@vitest/mocker': 4.1.5(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4)) @@ -15855,7 +16150,7 @@ snapshots: optionalDependencies: '@opentelemetry/api': 1.9.1 '@types/node': 25.6.2 - jsdom: 29.1.1 + jsdom: 29.1.1(canvas@3.2.3) transitivePeerDependencies: - msw From 49c0b2d1f42e98c76294da4073139edc886d931f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Sun, 10 May 2026 18:56:57 +0200 Subject: [PATCH 021/319] Add visual-tests job to CI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Runs Vitest browser visual regression tests (drawElevationChart) on every PR and push to main. Uses the same Playwright/Chromium cache as the e2e job. On first run (no committed snapshots yet) the tests create the snapshots and pass. On subsequent runs they compare against committed snapshots and fail on visual regression. Failed runs upload a visual-snapshots-diff artifact so the diff is visible in the Actions UI. To update snapshots after an intentional visual change: Actions → "Update visual snapshots" → Run workflow (or add the `update-snapshots` label to the PR). Co-Authored-By: Claude Sonnet 4.6 --- .github/workflows/ci.yml | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 326b3e0..61fa59e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -110,6 +110,44 @@ jobs: - run: pnpm install --frozen-lockfile - run: pnpm build + visual-tests: + name: Visual Tests + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + - uses: pnpm/action-setup@v6 + - uses: actions/setup-node@v6 + with: + node-version: 24 + cache: pnpm + - run: pnpm install --frozen-lockfile + + - name: Cache Playwright browsers + id: playwright-cache + uses: actions/cache@v5 + with: + path: ~/.cache/ms-playwright + key: playwright-${{ hashFiles('pnpm-lock.yaml') }} + + - name: Install Playwright Chromium + if: steps.playwright-cache.outputs.cache-hit != 'true' + run: pnpm exec playwright install --with-deps chromium + + - name: Install Playwright deps only + if: steps.playwright-cache.outputs.cache-hit == 'true' + run: pnpm exec playwright install-deps chromium + + - name: Run visual regression tests + run: pnpm --filter @trails-cool/planner test:visual + + - name: Upload screenshots on failure + if: failure() + uses: actions/upload-artifact@v7 + with: + name: visual-snapshots-diff + path: apps/planner/app/**/__screenshots__/ + retention-days: 7 + e2e: name: E2E Tests needs: build From fcc4f883795679e19ac09db3fa097d90f65876ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Sun, 10 May 2026 19:01:24 +0200 Subject: [PATCH 022/319] Fix Vitest browser provider setup and test cleanup - Add @vitest/browser-playwright; use playwright() factory (not string) - Import page from vitest/browser (not deprecated @vitest/browser/context) - Add afterEach(cleanup) so each test gets a fresh DOM - Use oxc transform for JSX instead of esbuild (avoids Vite 8 warning) Co-Authored-By: Claude Sonnet 4.6 --- .../lib/elevation-chart-draw.browser.test.tsx | 7 ++-- apps/planner/package.json | 1 + apps/planner/vitest.browser.config.ts | 10 +++--- pnpm-lock.yaml | 33 ++++++++++++++++--- 4 files changed, 37 insertions(+), 14 deletions(-) diff --git a/apps/planner/app/lib/elevation-chart-draw.browser.test.tsx b/apps/planner/app/lib/elevation-chart-draw.browser.test.tsx index 04735b6..1327f41 100644 --- a/apps/planner/app/lib/elevation-chart-draw.browser.test.tsx +++ b/apps/planner/app/lib/elevation-chart-draw.browser.test.tsx @@ -1,6 +1,6 @@ -import { describe, it, expect } from "vitest"; -import { render } from "@testing-library/react"; -import { page } from "@vitest/browser/context"; +import { describe, it, expect, afterEach } from "vitest"; +import { render, cleanup } from "@testing-library/react"; +import { page } from "vitest/browser"; import { drawElevationChart } from "./elevation-chart-draw"; import type { DrawChartParams } from "./elevation-chart-draw"; @@ -46,6 +46,7 @@ function ChartFixture({ params }: { params: DrawChartParams }) { } describe("drawElevationChart visual regression", () => { + afterEach(() => cleanup()); it("renders plain color mode", async () => { render(); await expect(page.getByTestId("chart")).toMatchScreenshot("plain.png"); diff --git a/apps/planner/package.json b/apps/planner/package.json index a2093e2..f751906 100644 --- a/apps/planner/package.json +++ b/apps/planner/package.json @@ -55,6 +55,7 @@ "@types/react-dom": "catalog:", "@types/ws": "^8.18.1", "@vitest/browser": "^4.1.5", + "@vitest/browser-playwright": "^4.1.5", "leaflet.markercluster": "^1.5.3", "pino-pretty": "^13.1.3", "tailwindcss": "catalog:", diff --git a/apps/planner/vitest.browser.config.ts b/apps/planner/vitest.browser.config.ts index 06b8978..4e28a5a 100644 --- a/apps/planner/vitest.browser.config.ts +++ b/apps/planner/vitest.browser.config.ts @@ -1,5 +1,6 @@ import { defineConfig } from "vitest/config"; import { resolve } from "node:path"; +import { playwright } from "@vitest/browser-playwright"; // Separate config for Vitest browser visual regression tests. // Run with: pnpm --filter @trails-cool/planner test:visual @@ -10,8 +11,8 @@ import { resolve } from "node:path"; // (.github/workflows/update-visual-snapshots.yml), triggered manually or // by adding the `update-snapshots` label to a PR. export default defineConfig({ - esbuild: { - jsx: "automatic", + oxc: { + transform: { react: {} }, }, resolve: { alias: { @@ -23,10 +24,7 @@ export default defineConfig({ include: ["app/**/*.browser.test.{ts,tsx}"], browser: { enabled: true, - // Provider is resolved from whichever @vitest/browser peer is installed. - // playwright is the default when @playwright/test is available. - // eslint-disable-next-line @typescript-eslint/no-explicit-any - provider: "playwright" as any, + provider: playwright(), instances: [{ browser: "chromium" }], }, }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c3059ad..f46ec23 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -196,7 +196,7 @@ importers: version: 8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4) vitest: specifier: ^4.1.5 - version: 4.1.5(@opentelemetry/api@1.9.1)(@types/node@25.6.2)(jsdom@29.1.1(canvas@3.2.3))(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4)) + version: 4.1.5(@opentelemetry/api@1.9.1)(@types/node@25.6.2)(@vitest/browser-playwright@4.1.5)(jsdom@29.1.1(canvas@3.2.3))(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4)) apps/journal: dependencies: @@ -568,7 +568,10 @@ importers: version: 8.18.1 '@vitest/browser': specifier: ^4.1.5 - version: 4.1.5(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4))(vitest@4.1.5(@opentelemetry/api@1.9.1)(@types/node@25.6.2)(jsdom@29.1.1(canvas@3.2.3))(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4))) + version: 4.1.5(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4))(vitest@4.1.5) + '@vitest/browser-playwright': + specifier: ^4.1.5 + version: 4.1.5(playwright@1.59.1)(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4))(vitest@4.1.5) leaflet.markercluster: specifier: ^1.5.3 version: 1.5.3(leaflet@1.9.4) @@ -3936,6 +3939,12 @@ packages: peerDependencies: vite: ^6.0.0 || ^7.0.0 || ^8.0.0 + '@vitest/browser-playwright@4.1.5': + resolution: {integrity: sha512-CWy0lBQJq97nionyJJdnaU4961IXTl43a7UCu5nHy51IoKxAt6PVIJLo+76rVl7KOOgcWHNkG4kbJu/pW7knvA==} + peerDependencies: + playwright: '*' + vitest: 4.1.5 + '@vitest/browser@4.1.5': resolution: {integrity: sha512-iCDGI8c4yg+xmjUg2VsygdAUSIIB4x5Rht/P68OXy1hPELKXHDkzh87lkuTcdYmemRChDkEpB426MmDjzC0ziA==} peerDependencies: @@ -11741,7 +11750,20 @@ snapshots: dependencies: vite: 8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4) - '@vitest/browser@4.1.5(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4))(vitest@4.1.5(@opentelemetry/api@1.9.1)(@types/node@25.6.2)(jsdom@29.1.1(canvas@3.2.3))(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4)))': + '@vitest/browser-playwright@4.1.5(playwright@1.59.1)(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4))(vitest@4.1.5)': + dependencies: + '@vitest/browser': 4.1.5(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4))(vitest@4.1.5) + '@vitest/mocker': 4.1.5(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4)) + playwright: 1.59.1 + tinyrainbow: 3.1.0 + vitest: 4.1.5(@opentelemetry/api@1.9.1)(@types/node@25.6.2)(@vitest/browser-playwright@4.1.5)(jsdom@29.1.1(canvas@3.2.3))(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4)) + transitivePeerDependencies: + - bufferutil + - msw + - utf-8-validate + - vite + + '@vitest/browser@4.1.5(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4))(vitest@4.1.5)': dependencies: '@blazediff/core': 1.9.1 '@vitest/mocker': 4.1.5(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4)) @@ -11750,7 +11772,7 @@ snapshots: pngjs: 7.0.0 sirv: 3.0.2 tinyrainbow: 3.1.0 - vitest: 4.1.5(@opentelemetry/api@1.9.1)(@types/node@25.6.2)(jsdom@29.1.1(canvas@3.2.3))(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4)) + vitest: 4.1.5(@opentelemetry/api@1.9.1)(@types/node@25.6.2)(@vitest/browser-playwright@4.1.5)(jsdom@29.1.1(canvas@3.2.3))(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4)) ws: 8.20.0 transitivePeerDependencies: - bufferutil @@ -16125,7 +16147,7 @@ snapshots: tsx: 4.21.0 yaml: 2.8.4 - vitest@4.1.5(@opentelemetry/api@1.9.1)(@types/node@25.6.2)(jsdom@29.1.1(canvas@3.2.3))(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4)): + vitest@4.1.5(@opentelemetry/api@1.9.1)(@types/node@25.6.2)(@vitest/browser-playwright@4.1.5)(jsdom@29.1.1(canvas@3.2.3))(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4)): dependencies: '@vitest/expect': 4.1.5 '@vitest/mocker': 4.1.5(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4)) @@ -16150,6 +16172,7 @@ snapshots: optionalDependencies: '@opentelemetry/api': 1.9.1 '@types/node': 25.6.2 + '@vitest/browser-playwright': 4.1.5(playwright@1.59.1)(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4))(vitest@4.1.5) jsdom: 29.1.1(canvas@3.2.3) transitivePeerDependencies: - msw From 76028d277db4b2f6f3ea1793cc97c6b1aa614831 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Sun, 10 May 2026 19:05:15 +0200 Subject: [PATCH 023/319] Remove invalid oxc.transform config from browser vitest config MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit OxcOptions doesn't have a transform key — Vite 8 handles TSX automatically. Co-Authored-By: Claude Sonnet 4.6 --- apps/planner/vitest.browser.config.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/apps/planner/vitest.browser.config.ts b/apps/planner/vitest.browser.config.ts index 4e28a5a..4a2d83a 100644 --- a/apps/planner/vitest.browser.config.ts +++ b/apps/planner/vitest.browser.config.ts @@ -11,9 +11,6 @@ import { playwright } from "@vitest/browser-playwright"; // (.github/workflows/update-visual-snapshots.yml), triggered manually or // by adding the `update-snapshots` label to a PR. export default defineConfig({ - oxc: { - transform: { react: {} }, - }, resolve: { alias: { "~": resolve(import.meta.dirname, "app"), From 7c924827c96276604b90c236311ccc4455710872 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Sun, 10 May 2026 19:09:00 +0200 Subject: [PATCH 024/319] Add initial visual snapshots and fix update script flag Generate baseline screenshots (macOS/Chromium) for the elevation-chart visual regression suite. The CI update-visual-snapshots workflow will overwrite these with Linux variants on the first run. Also fix the test:visual:update script: --update-snapshots is not a valid Vitest 4 flag; the correct short form is -u. Co-Authored-By: Claude Sonnet 4.6 --- .../drag-select-chromium-darwin.png | Bin 0 -> 10776 bytes .../elevation-chromium-darwin.png | Bin 0 -> 12821 bytes .../grade-chromium-darwin.png | Bin 0 -> 13135 bytes .../hover-chromium-darwin.png | Bin 0 -> 14160 bytes .../plain-chromium-darwin.png | Bin 0 -> 10689 bytes .../surface-chromium-darwin.png | Bin 0 -> 13098 bytes apps/planner/package.json | 2 +- 7 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 apps/planner/app/lib/__screenshots__/elevation-chart-draw.browser.test.tsx/drag-select-chromium-darwin.png create mode 100644 apps/planner/app/lib/__screenshots__/elevation-chart-draw.browser.test.tsx/elevation-chromium-darwin.png create mode 100644 apps/planner/app/lib/__screenshots__/elevation-chart-draw.browser.test.tsx/grade-chromium-darwin.png create mode 100644 apps/planner/app/lib/__screenshots__/elevation-chart-draw.browser.test.tsx/hover-chromium-darwin.png create mode 100644 apps/planner/app/lib/__screenshots__/elevation-chart-draw.browser.test.tsx/plain-chromium-darwin.png create mode 100644 apps/planner/app/lib/__screenshots__/elevation-chart-draw.browser.test.tsx/surface-chromium-darwin.png diff --git a/apps/planner/app/lib/__screenshots__/elevation-chart-draw.browser.test.tsx/drag-select-chromium-darwin.png b/apps/planner/app/lib/__screenshots__/elevation-chart-draw.browser.test.tsx/drag-select-chromium-darwin.png new file mode 100644 index 0000000000000000000000000000000000000000..591786a769d05b89ba7f80097a047bf18cb89a47 GIT binary patch literal 10776 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 T_0Hf)xlwy0Q&H{#c literal 0 HcmV?d00001 diff --git a/apps/planner/app/lib/__screenshots__/elevation-chart-draw.browser.test.tsx/plain-chromium-darwin.png b/apps/planner/app/lib/__screenshots__/elevation-chart-draw.browser.test.tsx/plain-chromium-darwin.png new file mode 100644 index 0000000000000000000000000000000000000000..2f8227e4f28f4f1c4a0e9359b846c1367c91dd65 GIT binary patch literal 10689 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 literal 0 HcmV?d00001 diff --git a/apps/planner/app/lib/__screenshots__/elevation-chart-draw.browser.test.tsx/surface-chromium-darwin.png b/apps/planner/app/lib/__screenshots__/elevation-chart-draw.browser.test.tsx/surface-chromium-darwin.png new file mode 100644 index 0000000000000000000000000000000000000000..ef2851e2611639257d53e1ba599709a8eb338f4d GIT binary patch literal 13098 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 Date: Sun, 10 May 2026 19:14:33 +0200 Subject: [PATCH 025/319] Fix update-visual-snapshots workflow: action versions + node version - Switch checkout/setup-node/setup-pnpm to @v6 to match CI - Replace node-version-file (.nvmrc doesn't exist) with node-version: 24 - Switch upload-artifact to @v7 to match CI Co-Authored-By: Claude Sonnet 4.6 --- .github/workflows/update-visual-snapshots.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/update-visual-snapshots.yml b/.github/workflows/update-visual-snapshots.yml index 0d45db9..fff88e0 100644 --- a/.github/workflows/update-visual-snapshots.yml +++ b/.github/workflows/update-visual-snapshots.yml @@ -62,19 +62,19 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: ref: ${{ github.event.pull_request.head.ref || github.event.inputs.branch || github.ref }} # Use a token with push rights so the commit-back step can push token: ${{ secrets.GITHUB_TOKEN }} - name: Setup pnpm - uses: pnpm/action-setup@v4 + uses: pnpm/action-setup@v6 - name: Setup Node - uses: actions/setup-node@v4 + uses: actions/setup-node@v6 with: - node-version-file: ".nvmrc" + node-version: 24 cache: "pnpm" - name: Install dependencies @@ -96,7 +96,7 @@ jobs: - name: Upload snapshots as artifact if: always() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: visual-snapshots path: apps/planner/app/**/__screenshots__/ From 78a5a372143fe25776f5464314759cb49a3ebf0d Mon Sep 17 00:00:00 2001 From: stigi <13815+stigi@users.noreply.github.com> Date: Sun, 10 May 2026 17:15:46 +0000 Subject: [PATCH 026/319] chore: update visual snapshots [skip ci] --- .../drag-select-chromium-linux.png | Bin 0 -> 4200 bytes .../elevation-chromium-linux.png | Bin 0 -> 4484 bytes .../grade-chromium-linux.png | Bin 0 -> 4613 bytes .../hover-chromium-linux.png | Bin 0 -> 5182 bytes .../plain-chromium-linux.png | Bin 0 -> 4117 bytes .../surface-chromium-linux.png | Bin 0 -> 4623 bytes 6 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/planner/app/lib/__screenshots__/elevation-chart-draw.browser.test.tsx/drag-select-chromium-linux.png create mode 100644 apps/planner/app/lib/__screenshots__/elevation-chart-draw.browser.test.tsx/elevation-chromium-linux.png create mode 100644 apps/planner/app/lib/__screenshots__/elevation-chart-draw.browser.test.tsx/grade-chromium-linux.png create mode 100644 apps/planner/app/lib/__screenshots__/elevation-chart-draw.browser.test.tsx/hover-chromium-linux.png create mode 100644 apps/planner/app/lib/__screenshots__/elevation-chart-draw.browser.test.tsx/plain-chromium-linux.png create mode 100644 apps/planner/app/lib/__screenshots__/elevation-chart-draw.browser.test.tsx/surface-chromium-linux.png diff --git a/apps/planner/app/lib/__screenshots__/elevation-chart-draw.browser.test.tsx/drag-select-chromium-linux.png b/apps/planner/app/lib/__screenshots__/elevation-chart-draw.browser.test.tsx/drag-select-chromium-linux.png new file mode 100644 index 0000000000000000000000000000000000000000..d95c7d233e08fd69ae533988482a53af0e308a8a GIT binary patch literal 4200 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 V)4M7-0RBPXv9Yv87hB-&{U7HG+zbE! literal 0 HcmV?d00001 diff --git a/apps/planner/app/lib/__screenshots__/elevation-chart-draw.browser.test.tsx/elevation-chromium-linux.png b/apps/planner/app/lib/__screenshots__/elevation-chart-draw.browser.test.tsx/elevation-chromium-linux.png new file mode 100644 index 0000000000000000000000000000000000000000..caa43aeae5c10b05226b4db3cb494f54fb882ee5 GIT binary patch literal 4484 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 literal 0 HcmV?d00001 diff --git a/apps/planner/app/lib/__screenshots__/elevation-chart-draw.browser.test.tsx/grade-chromium-linux.png b/apps/planner/app/lib/__screenshots__/elevation-chart-draw.browser.test.tsx/grade-chromium-linux.png new file mode 100644 index 0000000000000000000000000000000000000000..ac9948badb1833a4cd3530f336bf25b98649a415 GIT binary patch literal 4613 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 Fe*tg1zoq~H literal 0 HcmV?d00001 diff --git a/apps/planner/app/lib/__screenshots__/elevation-chart-draw.browser.test.tsx/hover-chromium-linux.png b/apps/planner/app/lib/__screenshots__/elevation-chart-draw.browser.test.tsx/hover-chromium-linux.png new file mode 100644 index 0000000000000000000000000000000000000000..1a60c8cb231799d0a3abb2d62f9b46fdc9dda765 GIT binary patch literal 5182 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 fCrv zIY$|jkfMmGVGhp|(MWSj-}gMd<*^w5|#9^=Wg7ocPz_!_^H8IFPN9Bc_*Dvij)8-!6!JmqIDG=1{-8m4H+}_tWj>>_@ zDR*74mJwU34AxrfdL?UPSUgyhBeJc)8U=AubK^B5ZXmRrT4>XA*wE8d%L1)}>$FZd zomaN4z*O6pu2zmSD#MS7j0!~d8j}AvI(7#l90EmSDa&(Y@r2I#&d6sIc4j}XOeAts ze(;KO!?!+aT+#iMJauRe+t5+myr!{n_AGQ3#pIE{b?AS1uUPZziJYlA^124ng;7BM zc|)hSN~<_|)V3EsDOjIPnf&YP6`N1>yu@ctc4^PrvKJ#d1*?l@xvdgsC`$xp15mRP zGRGbnR-EP2f}yq!f%CIDmeHciNn+0%q2vjC{q5#>+j+PkKx@y^|RH3GmH0g%? z-j%;r^(c8FYpu!)`O~1+JN%)f5-3t345&(`iWCU(u+MH0UV<0_BX7{ z4BDL>Jl){_efD|>J8*xJxcysPTl11vjBcyIDiwmVzsF;T&jj$ALV*C9U45Wa!pe^2 z?i$1BMwjG;sLa9`pQ6(xe6<!1Vnp&m zk z>v%Ks*L3FH3K5GQlzbS$*T4D2(s9|gWl%b~{`nSVo|1WThG66!wj#UKT`0 z9k@FzyHdZe;rpS%MH>km4e>X=a2|xst>3Kf3S!l_NS@fKUn^KbeEBGJt4cJc-%0N{c?}ZSp8z zK+c+;Fg`rvmJ3Sr?{HG+Px2|eXztb|ln?Ys+;Y^*N zH3%J*A$tp;ntZh1f2g`7+CRR58TiqAKr!wkM2Ya~|L1m=h0Nc(6G4=lZQ?GM-Wh1<2 zdnF6rDL>D;7iCw^E{U=mYATm#LaIn>xOvH;Wm)>gIS}WbYvpJ5+}470eLtTH6{bTS zp95$$fUWHdQf)sD-+g?Fvh)~Afn0xxXMTvV#dRu9FEXCKXHGm|!t1;YDKMlaG@RZFUu+d5QVIYi#ZJhkY4AXtqOPuEMkFd%k|)7yhoN zjA!QRS>Si(mu+){1!r^rr#3XlM-i3LfCD)XDeLHs(?aumtF_|#daX>*eZ5sC;dQ!Z z9+{0S1CMzY5U(zz3(wjQv@JMD1opdl5^H~GkHTe^Ib2~g%K)yhX$%3EKLT^rrPPXn zt*dDqM&PUiV)6{69Y0>o9sx}aHrtU_7)I0Z3mb@{9j;u@oVVfBqzLX=rJ}5u-LikT|#qK74NNPsT!@{prVd6D&_d~ zX1U=42F29t!fnHA=Id?aA%?|tl$_`(xC86O4>?w7kG^;-^pTHM60Q1OLz=Of;j6qx zgN}J13_G>B=KnZaFC!3V2r~fHn=8nrUP0`jvT_X+s4Z9ERB!ja6jBvPq+jyGPui%u zI29F)hr67nk0-ccX3q|#)#LF@Mj8HoVOkk}7mtci$YA9nK-ph;$oZx39~7-HdUh5H zo8vxKZfyIoKY;N-@xlAFi9`>9_^c!ZoTG%Ce(be0D#m z&9x^LP{ZW_#VA*PwH4a6uj(E8NMF^==QP&CmsxrCW-k}ydn_A8{nkU(+y$(C4>wj3 zxVWnAWuLrDu#h3lMP$ltE;iUfEdgL!@W4fXo$8bk8&*+@KUCRx=bxl@uWa07_Ah2x zX;i@H`cizrXQ2771n>Fkz%tlJJJMo40*dkWbXjMgD^qo~?5w#uQc?O;J*g~083lv4;~3>Q|>=HH1x2btt^K-mA1^(-K~W*7ndKyQM> z5g5~o4S_kn@)c@#yxs5KK;f^=tZpE=37?<0-PwphgD^^TGK2?4SJ6CNB$Z|2>Bd}(Jm zD;}0jJYU6w%C-~V_=BEh42Od#W#cPP8UKf1tuQN1IL=TdHVP3?fiWGpT~vVxi2CDC zEq|kEz^-(Z(N=kKPbkvM_K>^nu;Yk|PDdQT|MqKmWY7>Cm zMG1ToAb+3OnsB0YA|%yhTtg=K=a`H(4p!Jbfbdn;KofpRUL?XGxUOJ#Uq}F z$+o{m&_H95AzLtN8h80R3ZM{>790fAr~8rEod{0_p_Dpyz=hDp1;xt>^N@3jaBGIb zVKnXja4y!bP_ew6@Y>Ia(W!`gV2$y+Lq{22^OY}EmG|}^tv6l3w7gjVtu2HX0gR%lFN-#$FP{Sx zxG&3*%N9kKSEdqj6}ZRvaTf!<_|;W_C*lB4`1pk-I59NBFis3LpmF%pnO4-BdRf!; zBzAC785Z$DpN3)~;Iw^X25`51d59LV1KoGnOEn0z*F2&fn_T2LOGs`Y4^Krq?bjLmDkmw@Qj;x&()^0nGtL`seo!L&g+LQ3t z>QxX`x>`5}g!WY>%fKkU0R$2>EDiN#?A`HkM*=~n9D%Ml2OoxRx%ZS(k|pcxbY(87 z)h9!U*mCvy-0D(M)?Cs?Q_VfE0V?fnm<~}mnHMm`=0Z~~cIebyXc0I4bgUy?JT?M| zUP_)VuorR$1mhYhqg&VcIzJ5^f3~VI%O(~d#LTb7dc{7<7PcPj9E`99J;Fh=57DvJ z{M(g7ZxY8e69qdyY!HQ9!oRj#qIt8Q)6{YqP!eeIO&XD+Wo zkh+;D5Jz56Hi+baHNwB7YBKq*RA(w$nju^0m)YU39p-PSM@Y!U>%AjoL&j!z&9)e$ zZVSs|tbLU6k$n`8hAv5VyMBP{5LPkK_NbXMt+|psa@>rZ4U(yDV%2fUgJm$T z(&Hf6S!7^2e1!jSgg2NcSjPRNoIHIwXSWRlWMD==lOG?)^$@JZA}>r(Y6Nwj9KN#4 zULFyQ`)AhIaB`b;z&T^VrFH2C`M2B7rS&rrJMPEZm37Q(6P9g$&N|MErjYJ^Rlmk{ z7c_sZNmx#4eAOXR2E}dYoMaN$j$kGoGrY!OG>13=hRfuykMjkgDKW1_ZQBjD>KD*5 z@-vo=N5^{sU4WdBc%@|7?N9|W{Mq1vY+V=3?{EuA1u{U+f3SG4$gug;$TM*_{8S>z zMD1|7OVe)K_ z%FOz(UDDwcC^8fmJ^22P+wcE(pak~Zh&?DvM;_1vr1^xDKFTT$^ literal 0 HcmV?d00001 From eb30dddbfca99011ae6108be6d591aea369cfb4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Sun, 10 May 2026 19:53:32 +0200 Subject: [PATCH 027/319] Ignore .vitest-attachments in planner Vitest browser mode writes ephemeral screenshot attachments here during test runs; only the __screenshots__/ reference snapshots belong in the repo. Co-Authored-By: Claude Sonnet 4.6 --- apps/planner/.gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 apps/planner/.gitignore diff --git a/apps/planner/.gitignore b/apps/planner/.gitignore new file mode 100644 index 0000000..2625868 --- /dev/null +++ b/apps/planner/.gitignore @@ -0,0 +1 @@ +.vitest-attachments/ From 7c7462646423041b9ae0a6b850789ae0e90b9198 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Sun, 10 May 2026 20:10:03 +0200 Subject: [PATCH 028/319] Post visual diff images as PR comment on failure When visual tests fail on a PR, upload each diff PNG to GitHub's CDN via the issue assets endpoint and post a comment with the images embedded inline. Also fixes the artifact upload path to point at .vitest-attachments/ where the actual/diff files live. Co-Authored-By: Claude Sonnet 4.6 --- .github/workflows/ci.yml | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 61fa59e..545de4e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -138,14 +138,48 @@ jobs: run: pnpm exec playwright install-deps chromium - name: Run visual regression tests + id: visual-tests run: pnpm --filter @trails-cool/planner test:visual + - name: Post diff comment on PR + if: failure() && steps.visual-tests.outcome == 'failure' && github.event_name == 'pull_request' + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + diffs=$(find apps/planner/.vitest-attachments -name "*-diff-*.png" 2>/dev/null | sort) + if [ -z "$diffs" ]; then exit 0; fi + + body="## Visual regression failures"$'\n\n' + body+="| Test | Diff (reference → actual) |"$'\n' + body+="|------|--------------------------|"$'\n' + + for diff in $diffs; do + # Upload image to GitHub's CDN via the issue assets endpoint + response=$(curl -sf -X POST \ + -H "Authorization: Bearer $GH_TOKEN" \ + -H "Content-Type: image/png" \ + -H "Accept: application/json" \ + --data-binary @"$diff" \ + "https://uploads.github.com/repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/assets?name=$(basename $diff)") + url=$(echo "$response" | jq -r '.url // empty') + name=$(basename "$diff" | sed 's/-diff-chromium-linux\.png//' | sed 's/-/ /g') + if [ -n "$url" ]; then + body+="| \`$name\` | ![$name]($url) |"$'\n' + else + body+="| \`$name\` | *(upload failed)* |"$'\n' + fi + done + + body+=$'\n'"Run \`pnpm --filter @trails-cool/planner test:visual:update\` to regenerate snapshots if the change is intentional." + + gh pr comment ${{ github.event.pull_request.number }} --body "$body" + - name: Upload screenshots on failure if: failure() uses: actions/upload-artifact@v7 with: name: visual-snapshots-diff - path: apps/planner/app/**/__screenshots__/ + path: apps/planner/.vitest-attachments/ retention-days: 7 e2e: From e662212dca1326f879fb1d3b616b5a4cde2e716d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Sun, 10 May 2026 21:51:28 +0200 Subject: [PATCH 029/319] Post visual diff comment and job summary on visual test failure When visual tests fail on a PR: - Writes diff images (base64 data URIs) to the job summary for inline viewing - Posts a PR comment listing failing tests with a link to the job summary - Uploads .vitest-attachments/ as an artifact (include-hidden-files: true) The job now has pull-requests: write permission for posting the comment. Co-Authored-By: Claude Sonnet 4.6 --- .github/workflows/ci.yml | 52 +++++++++++++++++++++++++--------------- 1 file changed, 33 insertions(+), 19 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 545de4e..3fabf23 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -113,6 +113,9 @@ jobs: visual-tests: name: Visual Tests runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: write steps: - uses: actions/checkout@v6 - uses: pnpm/action-setup@v6 @@ -141,6 +144,26 @@ jobs: id: visual-tests run: pnpm --filter @trails-cool/planner test:visual + - name: Write diff images to job summary + if: failure() && steps.visual-tests.outcome == 'failure' + run: | + diffs=$(find apps/planner/.vitest-attachments -name "*-diff-*.png" 2>/dev/null | sort) + if [ -z "$diffs" ]; then exit 0; fi + + echo "## Visual regression failures" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + for diff in $diffs; do + name=$(basename "$diff" | sed 's/-diff-chromium-[a-z]*\.png//' | sed 's/-/ /g') + b64=$(base64 -w 0 "$diff") + echo "### \`$name\`" >> $GITHUB_STEP_SUMMARY + echo "\"$name" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + done + echo "To update snapshots if the change is intentional:" >> $GITHUB_STEP_SUMMARY + echo '```' >> $GITHUB_STEP_SUMMARY + echo "pnpm --filter @trails-cool/planner test:visual:update" >> $GITHUB_STEP_SUMMARY + echo '```' >> $GITHUB_STEP_SUMMARY + - name: Post diff comment on PR if: failure() && steps.visual-tests.outcome == 'failure' && github.event_name == 'pull_request' env: @@ -149,28 +172,18 @@ jobs: diffs=$(find apps/planner/.vitest-attachments -name "*-diff-*.png" 2>/dev/null | sort) if [ -z "$diffs" ]; then exit 0; fi + run_url="https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}" body="## Visual regression failures"$'\n\n' - body+="| Test | Diff (reference → actual) |"$'\n' - body+="|------|--------------------------|"$'\n' - + body+="The following tests produced screenshot diffs:"$'\n\n' for diff in $diffs; do - # Upload image to GitHub's CDN via the issue assets endpoint - response=$(curl -sf -X POST \ - -H "Authorization: Bearer $GH_TOKEN" \ - -H "Content-Type: image/png" \ - -H "Accept: application/json" \ - --data-binary @"$diff" \ - "https://uploads.github.com/repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/assets?name=$(basename $diff)") - url=$(echo "$response" | jq -r '.url // empty') - name=$(basename "$diff" | sed 's/-diff-chromium-linux\.png//' | sed 's/-/ /g') - if [ -n "$url" ]; then - body+="| \`$name\` | ![$name]($url) |"$'\n' - else - body+="| \`$name\` | *(upload failed)* |"$'\n' - fi + name=$(basename "$diff" | sed 's/-diff-chromium-[a-z]*\.png//' | sed 's/-/ /g') + body+="- \`$name\`"$'\n' done - - body+=$'\n'"Run \`pnpm --filter @trails-cool/planner test:visual:update\` to regenerate snapshots if the change is intentional." + body+=$'\n'"**[View diff images in the job summary]($run_url)**"$'\n\n' + body+="To update snapshots if the change is intentional:"$'\n' + body+="\`\`\`"$'\n' + body+="pnpm --filter @trails-cool/planner test:visual:update"$'\n' + body+="\`\`\`" gh pr comment ${{ github.event.pull_request.number }} --body "$body" @@ -180,6 +193,7 @@ jobs: with: name: visual-snapshots-diff path: apps/planner/.vitest-attachments/ + include-hidden-files: true retention-days: 7 e2e: From e059f36db950f876e82a840dfa16f67c669c79f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Sun, 10 May 2026 21:53:17 +0200 Subject: [PATCH 030/319] Remove broken data URI images from job summary --- .github/workflows/ci.yml | 24 ++---------------------- 1 file changed, 2 insertions(+), 22 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3fabf23..6d12af6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -144,26 +144,6 @@ jobs: id: visual-tests run: pnpm --filter @trails-cool/planner test:visual - - name: Write diff images to job summary - if: failure() && steps.visual-tests.outcome == 'failure' - run: | - diffs=$(find apps/planner/.vitest-attachments -name "*-diff-*.png" 2>/dev/null | sort) - if [ -z "$diffs" ]; then exit 0; fi - - echo "## Visual regression failures" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - for diff in $diffs; do - name=$(basename "$diff" | sed 's/-diff-chromium-[a-z]*\.png//' | sed 's/-/ /g') - b64=$(base64 -w 0 "$diff") - echo "### \`$name\`" >> $GITHUB_STEP_SUMMARY - echo "\"$name" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - done - echo "To update snapshots if the change is intentional:" >> $GITHUB_STEP_SUMMARY - echo '```' >> $GITHUB_STEP_SUMMARY - echo "pnpm --filter @trails-cool/planner test:visual:update" >> $GITHUB_STEP_SUMMARY - echo '```' >> $GITHUB_STEP_SUMMARY - - name: Post diff comment on PR if: failure() && steps.visual-tests.outcome == 'failure' && github.event_name == 'pull_request' env: @@ -172,14 +152,14 @@ jobs: diffs=$(find apps/planner/.vitest-attachments -name "*-diff-*.png" 2>/dev/null | sort) if [ -z "$diffs" ]; then exit 0; fi - run_url="https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}" + artifact_url="https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}" body="## Visual regression failures"$'\n\n' body+="The following tests produced screenshot diffs:"$'\n\n' for diff in $diffs; do name=$(basename "$diff" | sed 's/-diff-chromium-[a-z]*\.png//' | sed 's/-/ /g') body+="- \`$name\`"$'\n' done - body+=$'\n'"**[View diff images in the job summary]($run_url)**"$'\n\n' + body+=$'\n'"**[Download the \`visual-snapshots-diff\` artifact]($artifact_url)** to inspect the diffs locally."$'\n\n' body+="To update snapshots if the change is intentional:"$'\n' body+="\`\`\`"$'\n' body+="pnpm --filter @trails-cool/planner test:visual:update"$'\n' From 7bf8a918af7cd34974002fb23cb80b17aa23fbca Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 17 May 2026 08:22:36 +0000 Subject: [PATCH 031/319] Bump stefanzweifel/git-auto-commit-action from 5 to 7 Bumps [stefanzweifel/git-auto-commit-action](https://github.com/stefanzweifel/git-auto-commit-action) from 5 to 7. - [Release notes](https://github.com/stefanzweifel/git-auto-commit-action/releases) - [Changelog](https://github.com/stefanzweifel/git-auto-commit-action/blob/master/CHANGELOG.md) - [Commits](https://github.com/stefanzweifel/git-auto-commit-action/compare/v5...v7) --- updated-dependencies: - dependency-name: stefanzweifel/git-auto-commit-action dependency-version: '7' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/update-visual-snapshots.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/update-visual-snapshots.yml b/.github/workflows/update-visual-snapshots.yml index fff88e0..f1c9e4c 100644 --- a/.github/workflows/update-visual-snapshots.yml +++ b/.github/workflows/update-visual-snapshots.yml @@ -87,7 +87,7 @@ jobs: run: pnpm --filter @trails-cool/planner test:visual:update - name: Commit updated snapshots - uses: stefanzweifel/git-auto-commit-action@v5 + uses: stefanzweifel/git-auto-commit-action@v7 with: commit_message: "chore: update visual snapshots [skip ci]" file_pattern: "apps/planner/app/**/__screenshots__/**" From 78a986b9465c9d447ffa246a1bb57709b1829768 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 17 May 2026 08:45:54 +0000 Subject: [PATCH 032/319] Bump the production group with 40 updates Bumps the production group with 40 updates: | Package | From | To | | --- | --- | --- | | [expo](https://github.com/expo/expo/tree/HEAD/packages/expo) | `55.0.23` | `55.0.24` | | [@playwright/test](https://github.com/microsoft/playwright) | `1.59.1` | `1.60.0` | | [@sentry/vite-plugin](https://github.com/getsentry/sentry-javascript-bundler-plugins) | `5.2.1` | `5.3.0` | | [eslint](https://github.com/eslint/eslint) | `10.3.0` | `10.4.0` | | [i18next](https://github.com/i18next/i18next) | `26.0.10` | `26.2.0` | | [playwright](https://github.com/microsoft/playwright) | `1.59.1` | `1.60.0` | | [react-i18next](https://github.com/i18next/react-i18next) | `17.0.7` | `17.0.8` | | [turbo](https://github.com/vercel/turborepo) | `2.9.12` | `2.9.14` | | [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint) | `8.59.2` | `8.59.3` | | [vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest) | `4.1.5` | `4.1.6` | | [@maplibre/maplibre-react-native](https://github.com/maplibre/maplibre-react-native) | `11.1.1` | `11.2.1` | | [@sentry/cli](https://github.com/getsentry/sentry-cli) | `3.4.1` | `3.4.2` | | [@sentry/react-native](https://github.com/getsentry/sentry-react-native) | `8.11.0` | `8.11.1` | | [expo-crypto](https://github.com/expo/expo/tree/HEAD/packages/expo-crypto) | `55.0.14` | `55.0.15` | | [expo-dev-client](https://github.com/expo/expo/tree/HEAD/packages/expo-dev-client) | `55.0.32` | `55.0.34` | | [expo-dev-menu](https://github.com/expo/expo/tree/HEAD/packages/expo-dev-menu) | `55.0.27` | `55.0.29` | | [expo-device](https://github.com/expo/expo/tree/HEAD/packages/expo-device) | `55.0.16` | `55.0.17` | | [expo-file-system](https://github.com/expo/expo/tree/HEAD/packages/expo-file-system) | `55.0.19` | `55.0.20` | | [expo-localization](https://github.com/expo/expo/tree/HEAD/packages/expo-localization) | `55.0.13` | `55.0.14` | | [expo-location](https://github.com/expo/expo/tree/HEAD/packages/expo-location) | `55.1.9` | `55.1.10` | | [expo-navigation-bar](https://github.com/expo/expo/tree/HEAD/packages/expo-navigation-bar) | `55.0.12` | `55.0.13` | | [expo-notifications](https://github.com/expo/expo/tree/HEAD/packages/expo-notifications) | `55.0.22` | `55.0.23` | | [expo-secure-store](https://github.com/expo/expo/tree/HEAD/packages/expo-secure-store) | `55.0.13` | `55.0.14` | | [expo-splash-screen](https://github.com/expo/expo/tree/HEAD/packages/expo-splash-screen) | `55.0.20` | `55.0.21` | | [expo-sqlite](https://github.com/expo/expo/tree/HEAD/packages/expo-sqlite) | `55.0.15` | `55.0.16` | | [expo-system-ui](https://github.com/expo/expo/tree/HEAD/packages/expo-system-ui) | `55.0.17` | `55.0.18` | | [expo-web-browser](https://github.com/expo/expo/tree/HEAD/packages/expo-web-browser) | `55.0.15` | `55.0.16` | | [react-native-screens](https://github.com/software-mansion/react-native-screens) | `4.24.0` | `4.25.0` | | [use-latest-callback](https://github.com/satya164/use-latest-callback) | `0.3.3` | `0.3.4` | | [@codemirror/view](https://github.com/codemirror/view) | `6.42.1` | `6.43.0` | | [ws](https://github.com/websockets/ws) | `8.20.0` | `8.20.1` | | [@vitest/browser](https://github.com/vitest-dev/vitest/tree/HEAD/packages/browser) | `4.1.5` | `4.1.6` | | [@vitest/browser-playwright](https://github.com/vitest-dev/vitest/tree/HEAD/packages/browser-playwright) | `4.1.5` | `4.1.6` | | [@react-router/dev](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dev) | `7.15.0` | `7.15.1` | | [@react-router/node](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-node) | `7.15.0` | `7.15.1` | | [@react-router/serve](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-serve) | `7.15.0` | `7.15.1` | | [@sentry/node](https://github.com/getsentry/sentry-javascript) | `10.52.0` | `10.53.1` | | [@sentry/react](https://github.com/getsentry/sentry-javascript) | `10.51.0` | `10.53.1` | | [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) | `22.19.18` | `22.19.19` | | [react-router](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router) | `7.15.0` | `7.15.1` | Updates `expo` from 55.0.23 to 55.0.24 - [Changelog](https://github.com/expo/expo/blob/main/packages/expo/CHANGELOG.md) - [Commits](https://github.com/expo/expo/commits/HEAD/packages/expo) Updates `@playwright/test` from 1.59.1 to 1.60.0 - [Release notes](https://github.com/microsoft/playwright/releases) - [Commits](https://github.com/microsoft/playwright/compare/v1.59.1...v1.60.0) Updates `@sentry/vite-plugin` from 5.2.1 to 5.3.0 - [Release notes](https://github.com/getsentry/sentry-javascript-bundler-plugins/releases) - [Changelog](https://github.com/getsentry/sentry-javascript-bundler-plugins/blob/main/CHANGELOG.md) - [Commits](https://github.com/getsentry/sentry-javascript-bundler-plugins/compare/5.2.1...5.3.0) Updates `eslint` from 10.3.0 to 10.4.0 - [Release notes](https://github.com/eslint/eslint/releases) - [Commits](https://github.com/eslint/eslint/compare/v10.3.0...v10.4.0) Updates `i18next` from 26.0.10 to 26.2.0 - [Release notes](https://github.com/i18next/i18next/releases) - [Changelog](https://github.com/i18next/i18next/blob/master/CHANGELOG.md) - [Commits](https://github.com/i18next/i18next/compare/v26.0.10...v26.2.0) Updates `playwright` from 1.59.1 to 1.60.0 - [Release notes](https://github.com/microsoft/playwright/releases) - [Commits](https://github.com/microsoft/playwright/compare/v1.59.1...v1.60.0) Updates `react-i18next` from 17.0.7 to 17.0.8 - [Changelog](https://github.com/i18next/react-i18next/blob/master/CHANGELOG.md) - [Commits](https://github.com/i18next/react-i18next/compare/v17.0.7...v17.0.8) Updates `turbo` from 2.9.12 to 2.9.14 - [Release notes](https://github.com/vercel/turborepo/releases) - [Changelog](https://github.com/vercel/turborepo/blob/main/RELEASE.md) - [Commits](https://github.com/vercel/turborepo/compare/v2.9.12...v2.9.14) Updates `typescript-eslint` from 8.59.2 to 8.59.3 - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.59.3/packages/typescript-eslint) Updates `vitest` from 4.1.5 to 4.1.6 - [Release notes](https://github.com/vitest-dev/vitest/releases) - [Commits](https://github.com/vitest-dev/vitest/commits/v4.1.6/packages/vitest) Updates `@maplibre/maplibre-react-native` from 11.1.1 to 11.2.1 - [Release notes](https://github.com/maplibre/maplibre-react-native/releases) - [Changelog](https://github.com/maplibre/maplibre-react-native/blob/main/CHANGELOG.md) - [Commits](https://github.com/maplibre/maplibre-react-native/compare/v11.1.1...v11.2.1) Updates `@sentry/cli` from 3.4.1 to 3.4.2 - [Release notes](https://github.com/getsentry/sentry-cli/releases) - [Changelog](https://github.com/getsentry/sentry-cli/blob/master/CHANGELOG.md) - [Commits](https://github.com/getsentry/sentry-cli/compare/3.4.1...3.4.2) Updates `@sentry/react-native` from 8.11.0 to 8.11.1 - [Release notes](https://github.com/getsentry/sentry-react-native/releases) - [Changelog](https://github.com/getsentry/sentry-react-native/blob/main/CHANGELOG.md) - [Commits](https://github.com/getsentry/sentry-react-native/compare/8.11.0...8.11.1) Updates `expo-crypto` from 55.0.14 to 55.0.15 - [Changelog](https://github.com/expo/expo/blob/main/packages/expo-crypto/CHANGELOG.md) - [Commits](https://github.com/expo/expo/commits/HEAD/packages/expo-crypto) Updates `expo-dev-client` from 55.0.32 to 55.0.34 - [Changelog](https://github.com/expo/expo/blob/main/packages/expo-dev-client/CHANGELOG.md) - [Commits](https://github.com/expo/expo/commits/HEAD/packages/expo-dev-client) Updates `expo-dev-menu` from 55.0.27 to 55.0.29 - [Changelog](https://github.com/expo/expo/blob/main/packages/expo-dev-menu/CHANGELOG.md) - [Commits](https://github.com/expo/expo/commits/HEAD/packages/expo-dev-menu) Updates `expo-device` from 55.0.16 to 55.0.17 - [Changelog](https://github.com/expo/expo/blob/main/packages/expo-device/CHANGELOG.md) - [Commits](https://github.com/expo/expo/commits/HEAD/packages/expo-device) Updates `expo-file-system` from 55.0.19 to 55.0.20 - [Changelog](https://github.com/expo/expo/blob/main/packages/expo-file-system/CHANGELOG.md) - [Commits](https://github.com/expo/expo/commits/HEAD/packages/expo-file-system) Updates `expo-localization` from 55.0.13 to 55.0.14 - [Changelog](https://github.com/expo/expo/blob/main/packages/expo-localization/CHANGELOG.md) - [Commits](https://github.com/expo/expo/commits/HEAD/packages/expo-localization) Updates `expo-location` from 55.1.9 to 55.1.10 - [Changelog](https://github.com/expo/expo/blob/main/packages/expo-location/CHANGELOG.md) - [Commits](https://github.com/expo/expo/commits/HEAD/packages/expo-location) Updates `expo-navigation-bar` from 55.0.12 to 55.0.13 - [Changelog](https://github.com/expo/expo/blob/main/packages/expo-navigation-bar/CHANGELOG.md) - [Commits](https://github.com/expo/expo/commits/HEAD/packages/expo-navigation-bar) Updates `expo-notifications` from 55.0.22 to 55.0.23 - [Changelog](https://github.com/expo/expo/blob/main/packages/expo-notifications/CHANGELOG.md) - [Commits](https://github.com/expo/expo/commits/HEAD/packages/expo-notifications) Updates `expo-secure-store` from 55.0.13 to 55.0.14 - [Changelog](https://github.com/expo/expo/blob/main/packages/expo-secure-store/CHANGELOG.md) - [Commits](https://github.com/expo/expo/commits/HEAD/packages/expo-secure-store) Updates `expo-splash-screen` from 55.0.20 to 55.0.21 - [Changelog](https://github.com/expo/expo/blob/main/packages/expo-splash-screen/CHANGELOG.md) - [Commits](https://github.com/expo/expo/commits/HEAD/packages/expo-splash-screen) Updates `expo-sqlite` from 55.0.15 to 55.0.16 - [Changelog](https://github.com/expo/expo/blob/main/packages/expo-sqlite/CHANGELOG.md) - [Commits](https://github.com/expo/expo/commits/HEAD/packages/expo-sqlite) Updates `expo-system-ui` from 55.0.17 to 55.0.18 - [Changelog](https://github.com/expo/expo/blob/main/packages/expo-system-ui/CHANGELOG.md) - [Commits](https://github.com/expo/expo/commits/HEAD/packages/expo-system-ui) Updates `expo-web-browser` from 55.0.15 to 55.0.16 - [Changelog](https://github.com/expo/expo/blob/main/packages/expo-web-browser/CHANGELOG.md) - [Commits](https://github.com/expo/expo/commits/HEAD/packages/expo-web-browser) Updates `react-native-screens` from 4.24.0 to 4.25.0 - [Release notes](https://github.com/software-mansion/react-native-screens/releases) - [Commits](https://github.com/software-mansion/react-native-screens/compare/4.24.0...4.25.0) Updates `use-latest-callback` from 0.3.3 to 0.3.4 - [Release notes](https://github.com/satya164/use-latest-callback/releases) - [Changelog](https://github.com/satya164/use-latest-callback/blob/main/CHANGELOG.md) - [Commits](https://github.com/satya164/use-latest-callback/compare/v0.3.3...v0.3.4) Updates `@codemirror/view` from 6.42.1 to 6.43.0 - [Changelog](https://github.com/codemirror/view/blob/main/CHANGELOG.md) - [Commits](https://github.com/codemirror/view/commits) Updates `ws` from 8.20.0 to 8.20.1 - [Release notes](https://github.com/websockets/ws/releases) - [Commits](https://github.com/websockets/ws/compare/8.20.0...8.20.1) Updates `@vitest/browser` from 4.1.5 to 4.1.6 - [Release notes](https://github.com/vitest-dev/vitest/releases) - [Commits](https://github.com/vitest-dev/vitest/commits/v4.1.6/packages/browser) Updates `@vitest/browser-playwright` from 4.1.5 to 4.1.6 - [Release notes](https://github.com/vitest-dev/vitest/releases) - [Commits](https://github.com/vitest-dev/vitest/commits/v4.1.6/packages/browser-playwright) Updates `@react-router/dev` from 7.15.0 to 7.15.1 - [Release notes](https://github.com/remix-run/react-router/releases) - [Changelog](https://github.com/remix-run/react-router/blob/main/packages/react-router-dev/CHANGELOG.md) - [Commits](https://github.com/remix-run/react-router/commits/@react-router/dev@7.15.1/packages/react-router-dev) Updates `@react-router/node` from 7.15.0 to 7.15.1 - [Release notes](https://github.com/remix-run/react-router/releases) - [Changelog](https://github.com/remix-run/react-router/blob/main/packages/react-router-node/CHANGELOG.md) - [Commits](https://github.com/remix-run/react-router/commits/@react-router/node@7.15.1/packages/react-router-node) Updates `@react-router/serve` from 7.15.0 to 7.15.1 - [Release notes](https://github.com/remix-run/react-router/releases) - [Changelog](https://github.com/remix-run/react-router/blob/main/packages/react-router-serve/CHANGELOG.md) - [Commits](https://github.com/remix-run/react-router/commits/@react-router/serve@7.15.1/packages/react-router-serve) Updates `@sentry/node` from 10.52.0 to 10.53.1 - [Release notes](https://github.com/getsentry/sentry-javascript/releases) - [Changelog](https://github.com/getsentry/sentry-javascript/blob/develop/CHANGELOG.md) - [Commits](https://github.com/getsentry/sentry-javascript/compare/10.52.0...10.53.1) Updates `@sentry/react` from 10.51.0 to 10.53.1 - [Release notes](https://github.com/getsentry/sentry-javascript/releases) - [Changelog](https://github.com/getsentry/sentry-javascript/blob/develop/CHANGELOG.md) - [Commits](https://github.com/getsentry/sentry-javascript/compare/10.51.0...10.53.1) Updates `@types/node` from 22.19.18 to 22.19.19 - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node) Updates `react-router` from 7.15.0 to 7.15.1 - [Release notes](https://github.com/remix-run/react-router/releases) - [Changelog](https://github.com/remix-run/react-router/blob/main/packages/react-router/CHANGELOG.md) - [Commits](https://github.com/remix-run/react-router/commits/react-router@7.15.1/packages/react-router) --- updated-dependencies: - dependency-name: expo dependency-version: 55.0.24 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production - dependency-name: "@playwright/test" dependency-version: 1.60.0 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: production - dependency-name: "@sentry/vite-plugin" dependency-version: 5.3.0 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: production - dependency-name: eslint dependency-version: 10.4.0 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: production - dependency-name: i18next dependency-version: 26.2.0 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: production - dependency-name: playwright dependency-version: 1.60.0 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: production - dependency-name: react-i18next dependency-version: 17.0.8 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: production - dependency-name: turbo dependency-version: 2.9.14 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: production - dependency-name: typescript-eslint dependency-version: 8.59.3 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: production - dependency-name: vitest dependency-version: 4.1.6 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: production - dependency-name: "@maplibre/maplibre-react-native" dependency-version: 11.2.1 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: production - dependency-name: "@sentry/cli" dependency-version: 3.4.2 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production - dependency-name: "@sentry/react-native" dependency-version: 8.11.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production - dependency-name: expo-crypto dependency-version: 55.0.15 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production - dependency-name: expo-dev-client dependency-version: 55.0.34 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production - dependency-name: expo-dev-menu dependency-version: 55.0.29 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production - dependency-name: expo-device dependency-version: 55.0.17 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production - dependency-name: expo-file-system dependency-version: 55.0.20 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production - dependency-name: expo-localization dependency-version: 55.0.14 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production - dependency-name: expo-location dependency-version: 55.1.10 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production - dependency-name: expo-navigation-bar dependency-version: 55.0.13 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production - dependency-name: expo-notifications dependency-version: 55.0.23 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production - dependency-name: expo-secure-store dependency-version: 55.0.14 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production - dependency-name: expo-splash-screen dependency-version: 55.0.21 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production - dependency-name: expo-sqlite dependency-version: 55.0.16 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production - dependency-name: expo-system-ui dependency-version: 55.0.18 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production - dependency-name: expo-web-browser dependency-version: 55.0.16 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production - dependency-name: react-native-screens dependency-version: 4.25.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: production - dependency-name: use-latest-callback dependency-version: 0.3.4 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production - dependency-name: "@codemirror/view" dependency-version: 6.43.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: production - dependency-name: ws dependency-version: 8.20.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production - dependency-name: "@vitest/browser" dependency-version: 4.1.6 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: production - dependency-name: "@vitest/browser-playwright" dependency-version: 4.1.6 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: production - dependency-name: "@react-router/dev" dependency-version: 7.15.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production - dependency-name: "@react-router/node" dependency-version: 7.15.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production - dependency-name: "@react-router/serve" dependency-version: 7.15.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production - dependency-name: "@sentry/node" dependency-version: 10.53.1 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: production - dependency-name: "@sentry/react" dependency-version: 10.53.1 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: production - dependency-name: "@types/node" dependency-version: 22.19.19 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production - dependency-name: react-router dependency-version: 7.15.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production ... Signed-off-by: dependabot[bot] --- apps/mobile/package.json | 40 +- apps/planner/package.json | 8 +- package.json | 20 +- pnpm-lock.yaml | 1964 ++++++++++++++++++++----------------- pnpm-workspace.yaml | 14 +- 5 files changed, 1104 insertions(+), 942 deletions(-) diff --git a/apps/mobile/package.json b/apps/mobile/package.json index 6e18270..701060a 100644 --- a/apps/mobile/package.json +++ b/apps/mobile/package.json @@ -31,41 +31,41 @@ "dependencies": { "@expo/metro-runtime": "^55.0.11", "@gorhom/bottom-sheet": "^5.2.14", - "@maplibre/maplibre-react-native": "^11.1.1", - "@sentry/cli": "^3.4.1", - "@sentry/react-native": "~8.11.0", + "@maplibre/maplibre-react-native": "^11.2.1", + "@sentry/cli": "^3.4.2", + "@sentry/react-native": "~8.11.1", "@trails-cool/api": "workspace:*", "@trails-cool/gpx": "workspace:*", "@trails-cool/i18n": "workspace:*", "@trails-cool/map-core": "workspace:*", "@trails-cool/sentry-config": "workspace:*", "@trails-cool/types": "workspace:*", - "expo": "~55.0.23", + "expo": "~55.0.24", "expo-constants": "~55.0.16", - "expo-crypto": "~55.0.14", - "expo-dev-client": "~55.0.32", - "expo-dev-menu": "^55.0.27", - "expo-device": "~55.0.16", - "expo-file-system": "~55.0.19", + "expo-crypto": "~55.0.15", + "expo-dev-client": "~55.0.34", + "expo-dev-menu": "^55.0.29", + "expo-device": "~55.0.17", + "expo-file-system": "~55.0.20", "expo-linking": "~55.0.15", - "expo-localization": "~55.0.13", - "expo-location": "~55.1.9", - "expo-navigation-bar": "~55.0.12", - "expo-notifications": "~55.0.22", + "expo-localization": "~55.0.14", + "expo-location": "~55.1.10", + "expo-navigation-bar": "~55.0.13", + "expo-notifications": "~55.0.23", "expo-router": "~55.0.14", - "expo-secure-store": "~55.0.13", - "expo-splash-screen": "~55.0.20", - "expo-sqlite": "~55.0.15", + "expo-secure-store": "~55.0.14", + "expo-splash-screen": "~55.0.21", + "expo-sqlite": "~55.0.16", "expo-status-bar": "~55.0.6", - "expo-system-ui": "^55.0.17", - "expo-web-browser": "~55.0.15", + "expo-system-ui": "^55.0.18", + "expo-web-browser": "~55.0.16", "react": "catalog:", "react-native": "0.83.4", "react-native-gesture-handler": "^2.31.2", "react-native-reanimated": "^4.3.1", "react-native-safe-area-context": "~5.7.0", - "react-native-screens": "~4.24.0", - "use-latest-callback": "^0.3.3", + "react-native-screens": "~4.25.0", + "use-latest-callback": "^0.3.4", "zod": "^4.4.3" }, "devDependencies": { diff --git a/apps/planner/package.json b/apps/planner/package.json index a92baad..a770890 100644 --- a/apps/planner/package.json +++ b/apps/planner/package.json @@ -17,7 +17,7 @@ "@codemirror/commands": "^6.10.3", "@codemirror/language": "^6.12.3", "@codemirror/state": "^6.6.0", - "@codemirror/view": "^6.42.1", + "@codemirror/view": "^6.43.0", "@geoman-io/leaflet-geoman-free": "^2.19.3", "@react-router/node": "catalog:", "@react-router/serve": "catalog:", @@ -41,7 +41,7 @@ "react": "catalog:", "react-dom": "catalog:", "react-router": "catalog:", - "ws": "^8.20.0", + "ws": "^8.20.1", "y-codemirror.next": "^0.3.5", "y-protocols": "^1.0.7", "y-websocket": "^3.0.0", @@ -54,8 +54,8 @@ "@types/react": "catalog:", "@types/react-dom": "catalog:", "@types/ws": "^8.18.1", - "@vitest/browser": "^4.1.5", - "@vitest/browser-playwright": "^4.1.5", + "@vitest/browser": "^4.1.6", + "@vitest/browser-playwright": "^4.1.6", "leaflet.markercluster": "^1.5.3", "pino-pretty": "^13.1.3", "tailwindcss": "catalog:", diff --git a/package.json b/package.json index 7aa7e97..ab062fd 100644 --- a/package.json +++ b/package.json @@ -44,11 +44,11 @@ "@eslint/js": "^10.0.1", "@expo/fingerprint": "^0.16.7", "@fission-ai/openspec": "^1.3.1", - "@playwright/test": "^1.59.1", + "@playwright/test": "^1.60.0", "@react-router/dev": "catalog:", "@react-router/node": "catalog:", "@react-router/serve": "catalog:", - "@sentry/vite-plugin": "^5.2.1", + "@sentry/vite-plugin": "^5.3.0", "@tailwindcss/vite": "catalog:", "@testing-library/jest-dom": "^6.9.1", "@testing-library/react": "^16.3.2", @@ -59,32 +59,32 @@ "drizzle-kit": "catalog:", "drizzle-orm": "catalog:", "drizzle-postgis": "catalog:", - "eslint": "^10.3.0", + "eslint": "^10.4.0", "eslint-config-prettier": "^10.1.8", "fit-file-parser": "^3.0.0", - "i18next": "^26.0.10", + "i18next": "^26.2.0", "i18next-browser-languagedetector": "^8.2.1", "jsdom": "^29.1.1", "leaflet": "^1.9.4", "linkedom": "^0.18.12", - "playwright": "^1.59.1", + "playwright": "^1.60.0", "postgres": "catalog:", "prettier": "^3.8.3", "react": "catalog:", "react-dom": "catalog:", - "react-i18next": "^17.0.7", + "react-i18next": "^17.0.8", "react-leaflet": "^5.0.0", "react-router": "catalog:", "tailwindcss": "catalog:", - "turbo": "^2.9.12", + "turbo": "^2.9.14", "typescript": "catalog:", - "typescript-eslint": "^8.59.2", + "typescript-eslint": "^8.59.3", "vite": "catalog:", - "vitest": "^4.1.5" + "vitest": "^4.1.6" }, "version": "1.0.0", "dependencies": { - "expo": "~55.0.23", + "expo": "~55.0.24", "react": "19.2.0", "react-native": "0.83.4" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f46ec23..f5ddbe2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -7,26 +7,26 @@ settings: catalogs: default: '@react-router/dev': - specifier: ^7.15.0 - version: 7.15.0 + specifier: ^7.15.1 + version: 7.15.1 '@react-router/node': - specifier: ^7.15.0 - version: 7.15.0 + specifier: ^7.15.1 + version: 7.15.1 '@react-router/serve': - specifier: ^7.15.0 - version: 7.15.0 + specifier: ^7.15.1 + version: 7.15.1 '@sentry/node': - specifier: ^10.52.0 - version: 10.52.0 + specifier: ^10.53.1 + version: 10.53.1 '@sentry/react': - specifier: ^10.52.0 - version: 10.52.0 + specifier: ^10.53.1 + version: 10.53.1 '@tailwindcss/vite': specifier: ^4.3.0 version: 4.3.0 '@types/node': - specifier: ^22.19.18 - version: 22.19.18 + specifier: ^22.19.19 + version: 22.19.19 '@types/react': specifier: ^19.2.14 version: 19.2.14 @@ -46,8 +46,8 @@ catalogs: specifier: ^3.4.9 version: 3.4.9 react-router: - specifier: ^7.15.0 - version: 7.15.0 + specifier: ^7.15.1 + version: 7.15.1 tailwindcss: specifier: ^4.3.0 version: 4.3.0 @@ -71,8 +71,8 @@ importers: .: dependencies: expo: - specifier: ~55.0.23 - version: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) + specifier: ~55.0.24 + version: 55.0.24(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) react: specifier: ^19.2.5 version: 19.2.6 @@ -82,31 +82,31 @@ importers: devDependencies: '@eslint/js': specifier: ^10.0.1 - version: 10.0.1(eslint@10.3.0(jiti@2.7.0)) + version: 10.0.1(eslint@10.4.0(jiti@2.7.0)) '@expo/fingerprint': specifier: ^0.16.7 version: 0.16.7 '@fission-ai/openspec': specifier: ^1.3.1 - version: 1.3.1(@types/node@25.6.2) + version: 1.3.1(@types/node@25.8.0) '@playwright/test': - specifier: ^1.59.1 - version: 1.59.1 + specifier: ^1.60.0 + version: 1.60.0 '@react-router/dev': specifier: 'catalog:' - version: 7.15.0(@react-router/serve@7.15.0(react-router@7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3))(@types/node@25.6.2)(jiti@2.7.0)(lightningcss@1.32.0)(react-router@7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4))(yaml@2.8.4) + version: 7.15.1(@react-router/serve@7.15.1(react-router@7.15.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3))(@types/node@25.8.0)(jiti@2.7.0)(lightningcss@1.32.0)(react-router@7.15.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.10(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0))(yaml@2.9.0) '@react-router/node': specifier: 'catalog:' - version: 7.15.0(react-router@7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3) + version: 7.15.1(react-router@7.15.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3) '@react-router/serve': specifier: 'catalog:' - version: 7.15.0(react-router@7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3) + version: 7.15.1(react-router@7.15.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3) '@sentry/vite-plugin': - specifier: ^5.2.1 - version: 5.2.1(rollup@4.60.3) + specifier: ^5.3.0 + version: 5.3.0(rollup@4.60.4) '@tailwindcss/vite': specifier: 'catalog:' - version: 4.3.0(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4)) + version: 4.3.0(vite@8.0.10(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0)) '@testing-library/jest-dom': specifier: ^6.9.1 version: 6.9.1 @@ -130,22 +130,22 @@ 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.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(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.16(expo@55.0.24)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(pg@8.20.0)(postgres@3.4.9) drizzle-postgis: specifier: 'catalog:' version: 1.1.1 eslint: - specifier: ^10.3.0 - version: 10.3.0(jiti@2.7.0) + specifier: ^10.4.0 + version: 10.4.0(jiti@2.7.0) eslint-config-prettier: specifier: ^10.1.8 - version: 10.1.8(eslint@10.3.0(jiti@2.7.0)) + version: 10.1.8(eslint@10.4.0(jiti@2.7.0)) fit-file-parser: specifier: ^3.0.0 version: 3.0.0 i18next: - specifier: ^26.0.10 - version: 26.0.10(typescript@5.9.3) + specifier: ^26.2.0 + version: 26.2.0(typescript@5.9.3) i18next-browser-languagedetector: specifier: ^8.2.1 version: 8.2.1 @@ -159,8 +159,8 @@ importers: specifier: ^0.18.12 version: 0.18.12(canvas@3.2.3) playwright: - specifier: ^1.59.1 - version: 1.59.1 + specifier: ^1.60.0 + version: 1.60.0 postgres: specifier: 'catalog:' version: 3.4.9 @@ -171,47 +171,47 @@ importers: specifier: ^19.2.6 version: 19.2.6(react@19.2.6) react-i18next: - specifier: ^17.0.7 - version: 17.0.7(i18next@26.0.10(typescript@5.9.3))(react-dom@19.2.6(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) + specifier: ^17.0.8 + version: 17.0.8(i18next@26.2.0(typescript@5.9.3))(react-dom@19.2.6(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) react-leaflet: specifier: ^5.0.0 version: 5.0.0(leaflet@1.9.4)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) react-router: - specifier: 'catalog:' - version: 7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + specifier: 7.15.1 + version: 7.15.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6) tailwindcss: specifier: 'catalog:' version: 4.3.0 turbo: - specifier: ^2.9.12 - version: 2.9.12 + specifier: ^2.9.14 + version: 2.9.14 typescript: specifier: 'catalog:' version: 5.9.3 typescript-eslint: - specifier: ^8.59.2 - version: 8.59.2(eslint@10.3.0(jiti@2.7.0))(typescript@5.9.3) + specifier: ^8.59.3 + version: 8.59.3(eslint@10.4.0(jiti@2.7.0))(typescript@5.9.3) vite: specifier: 'catalog:' - version: 8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4) + version: 8.0.10(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0) vitest: - specifier: ^4.1.5 - version: 4.1.5(@opentelemetry/api@1.9.1)(@types/node@25.6.2)(@vitest/browser-playwright@4.1.5)(jsdom@29.1.1(canvas@3.2.3))(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4)) + specifier: ^4.1.6 + version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@25.8.0)(@vitest/browser-playwright@4.1.6)(jsdom@29.1.1(canvas@3.2.3))(vite@8.0.10(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0)) apps/journal: dependencies: '@react-router/node': specifier: 'catalog:' - version: 7.15.0(react-router@7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3) + version: 7.15.1(react-router@7.15.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3) '@react-router/serve': specifier: 'catalog:' - version: 7.15.0(react-router@7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3) + version: 7.15.1(react-router@7.15.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3) '@sentry/node': specifier: 'catalog:' - version: 10.52.0 + version: 10.53.1 '@sentry/react': specifier: 'catalog:' - version: 10.52.0(react@19.2.6) + version: 10.53.1(react@19.2.6) '@simplewebauthn/browser': specifier: ^13.3.0 version: 13.3.0 @@ -250,7 +250,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.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(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.16(expo@55.0.24)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(pg@8.20.0)(postgres@3.4.9) isbot: specifier: ^5.1.40 version: 5.1.40 @@ -274,20 +274,20 @@ importers: version: 19.2.6(react@19.2.6) react-router: specifier: 'catalog:' - version: 7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + version: 7.15.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6) zod: specifier: ^4.4.3 version: 4.4.3 devDependencies: '@react-router/dev': specifier: 'catalog:' - version: 7.15.0(@react-router/serve@7.15.0(react-router@7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3))(@types/node@25.6.2)(jiti@2.7.0)(lightningcss@1.32.0)(react-router@7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4))(yaml@2.8.4) + version: 7.15.1(@react-router/serve@7.15.1(react-router@7.15.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3))(@types/node@25.8.0)(jiti@2.7.0)(lightningcss@1.32.0)(react-router@7.15.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.10(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0))(yaml@2.9.0) '@simplewebauthn/types': specifier: ^12.0.0 version: 12.0.0 '@tailwindcss/vite': specifier: 'catalog:' - version: 4.3.0(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4)) + version: 4.3.0(vite@8.0.10(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0)) '@types/nodemailer': specifier: ^8.0.0 version: 8.0.0 @@ -299,7 +299,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.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4)) + version: 2.3.0(vite@8.0.10(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0)) pino-pretty: specifier: ^13.1.3 version: 13.1.3 @@ -311,25 +311,25 @@ importers: version: 5.9.3 vite: specifier: 'catalog:' - version: 8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4) + version: 8.0.10(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0) apps/mobile: dependencies: '@expo/metro-runtime': specifier: ^55.0.11 - version: 55.0.11(@expo/dom-webview@55.0.5)(expo@55.0.23)(react-dom@19.2.6(react@19.2.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.6))(react@19.2.6) + version: 55.0.11(@expo/dom-webview@55.0.5)(expo@55.0.24)(react-dom@19.2.6(react@19.2.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.6))(react@19.2.6) '@gorhom/bottom-sheet': specifier: ^5.2.14 version: 5.2.14(@types/react@19.2.14)(react-native-gesture-handler@2.31.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.6))(react@19.2.6))(react-native-reanimated@4.3.1(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.6))(react@19.2.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.6))(react@19.2.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.6))(react@19.2.6) '@maplibre/maplibre-react-native': - specifier: ^11.1.1 - version: 11.1.1(@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.6))(react@19.2.6) + specifier: ^11.2.1 + version: 11.2.1(@expo/config-plugins@55.0.9)(@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.6))(react@19.2.6) '@sentry/cli': - specifier: ^3.4.1 - version: 3.4.1 + specifier: ^3.4.2 + version: 3.4.2 '@sentry/react-native': - specifier: ~8.11.0 - version: 8.11.0(@expo/env@2.1.2)(dotenv@16.6.1)(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) + specifier: ~8.11.1 + version: 8.11.1(@expo/env@2.1.2)(dotenv@16.6.1)(expo@55.0.24)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) '@trails-cool/api': specifier: workspace:* version: link:../../packages/api @@ -349,62 +349,62 @@ importers: specifier: workspace:* version: link:../../packages/types expo: - specifier: ~55.0.23 - version: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) + specifier: ~55.0.24 + version: 55.0.24(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) expo-constants: specifier: ~55.0.16 - version: 55.0.16(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6)) + version: 55.0.16(expo@55.0.24)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6)) expo-crypto: - specifier: ~55.0.14 - version: 55.0.14(expo@55.0.23) + specifier: ~55.0.15 + version: 55.0.15(expo@55.0.24) expo-dev-client: - specifier: ~55.0.32 - version: 55.0.32(expo@55.0.23) + specifier: ~55.0.34 + version: 55.0.34(expo@55.0.24) expo-dev-menu: - specifier: ^55.0.27 - version: 55.0.27(expo@55.0.23) + specifier: ^55.0.29 + version: 55.0.29(expo@55.0.24) expo-device: - specifier: ~55.0.16 - version: 55.0.16(expo@55.0.23) + specifier: ~55.0.17 + version: 55.0.17(expo@55.0.24) expo-file-system: - specifier: ~55.0.19 - version: 55.0.19(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6)) + specifier: ~55.0.20 + version: 55.0.20(expo@55.0.24)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6)) expo-linking: specifier: ~55.0.15 - version: 55.0.15(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) + version: 55.0.15(expo@55.0.24)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) expo-localization: - specifier: ~55.0.13 - version: 55.0.13(expo@55.0.23)(react@19.2.6) + specifier: ~55.0.14 + version: 55.0.14(expo@55.0.24)(react@19.2.6) expo-location: - specifier: ~55.1.9 - version: 55.1.9(expo@55.0.23)(typescript@5.9.3) + specifier: ~55.1.10 + version: 55.1.10(expo@55.0.24)(typescript@5.9.3) expo-navigation-bar: - specifier: ~55.0.12 - version: 55.0.12(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) + specifier: ~55.0.13 + version: 55.0.13(expo@55.0.24)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) expo-notifications: - specifier: ~55.0.22 - version: 55.0.22(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)(typescript@5.9.3) + specifier: ~55.0.23 + version: 55.0.23(expo@55.0.24)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)(typescript@5.9.3) expo-router: specifier: ~55.0.14 - version: 55.0.14(82db8260abd9fbac2a02011543a979fa) + version: 55.0.14(4a88f676dfb25e563c95d7c5569dae4c) expo-secure-store: - specifier: ~55.0.13 - version: 55.0.13(expo@55.0.23) + specifier: ~55.0.14 + version: 55.0.14(expo@55.0.24) expo-splash-screen: - specifier: ~55.0.20 - version: 55.0.20(expo@55.0.23)(typescript@5.9.3) + specifier: ~55.0.21 + version: 55.0.21(expo@55.0.24)(typescript@5.9.3) expo-sqlite: - specifier: ~55.0.15 - version: 55.0.15(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) + specifier: ~55.0.16 + version: 55.0.16(expo@55.0.24)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) expo-status-bar: specifier: ~55.0.6 version: 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.6))(react@19.2.6) expo-system-ui: - specifier: ^55.0.17 - version: 55.0.17(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6)) + specifier: ^55.0.18 + version: 55.0.18(expo@55.0.24)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6)) expo-web-browser: - specifier: ~55.0.15 - version: 55.0.15(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6)) + specifier: ~55.0.16 + version: 55.0.16(expo@55.0.24)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6)) react: specifier: ^19.2.5 version: 19.2.6 @@ -421,18 +421,18 @@ importers: specifier: ~5.7.0 version: 5.7.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.6))(react@19.2.6) react-native-screens: - specifier: ~4.24.0 - version: 4.24.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.6))(react@19.2.6) + specifier: ~4.25.0 + version: 4.25.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.6))(react@19.2.6) use-latest-callback: - specifier: ^0.3.3 - version: 0.3.3(react@19.2.6) + specifier: ^0.3.4 + version: 0.3.4(react@19.2.6) zod: specifier: ^4.4.3 version: 4.4.3 devDependencies: '@testing-library/react-native': specifier: ^13.3.3 - version: 13.3.3(jest@29.7.0(@types/node@25.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.6))(react-test-renderer@19.2.6(react@19.2.6))(react@19.2.6) + version: 13.3.3(jest@29.7.0(@types/node@25.8.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.6))(react-test-renderer@19.2.6(react@19.2.6))(react@19.2.6) '@types/jest': specifier: ^29.5.14 version: 29.5.14 @@ -441,7 +441,7 @@ importers: version: 19.2.14 jest-expo: specifier: ^55.0.17 - version: 55.0.17(@babel/core@7.29.0)(canvas@3.2.3)(expo@55.0.23)(jest@29.7.0(@types/node@25.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.6))(react@19.2.6)(typescript@5.9.3) + version: 55.0.17(@babel/core@7.29.0)(canvas@3.2.3)(expo@55.0.24)(jest@29.7.0(@types/node@25.8.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.6))(react@19.2.6)(typescript@5.9.3) react-test-renderer: specifier: ^19.2.6 version: 19.2.6(react@19.2.6) @@ -461,23 +461,23 @@ importers: specifier: ^6.6.0 version: 6.6.0 '@codemirror/view': - specifier: ^6.42.1 - version: 6.42.1 + specifier: ^6.43.0 + version: 6.43.0 '@geoman-io/leaflet-geoman-free': specifier: ^2.19.3 version: 2.19.3(leaflet@1.9.4) '@react-router/node': specifier: 'catalog:' - version: 7.15.0(react-router@7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3) + version: 7.15.1(react-router@7.15.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3) '@react-router/serve': specifier: 'catalog:' - version: 7.15.0(react-router@7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3) + version: 7.15.1(react-router@7.15.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3) '@sentry/node': specifier: 'catalog:' - version: 10.52.0 + version: 10.53.1 '@sentry/react': specifier: 'catalog:' - version: 10.52.0(react@19.2.6) + version: 10.53.1(react@19.2.6) '@trails-cool/db': specifier: workspace:* version: link:../../packages/db @@ -510,7 +510,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.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(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.16(expo@55.0.24)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(pg@8.20.0)(postgres@3.4.9) isbot: specifier: ^5.1.40 version: 5.1.40 @@ -531,13 +531,13 @@ importers: version: 19.2.6(react@19.2.6) react-router: specifier: 'catalog:' - version: 7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + version: 7.15.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6) ws: - specifier: ^8.20.0 - version: 8.20.0 + specifier: ^8.20.1 + version: 8.20.1 y-codemirror.next: specifier: ^0.3.5 - version: 0.3.5(@codemirror/state@6.6.0)(@codemirror/view@6.42.1)(yjs@13.6.30) + version: 0.3.5(@codemirror/state@6.6.0)(@codemirror/view@6.43.0)(yjs@13.6.30) y-protocols: specifier: ^1.0.7 version: 1.0.7(yjs@13.6.30) @@ -550,10 +550,10 @@ importers: devDependencies: '@react-router/dev': specifier: 'catalog:' - version: 7.15.0(@react-router/serve@7.15.0(react-router@7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3))(@types/node@25.6.2)(jiti@2.7.0)(lightningcss@1.32.0)(react-router@7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4))(yaml@2.8.4) + version: 7.15.1(@react-router/serve@7.15.1(react-router@7.15.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3))(@types/node@25.8.0)(jiti@2.7.0)(lightningcss@1.32.0)(react-router@7.15.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.10(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0))(yaml@2.9.0) '@tailwindcss/vite': specifier: 'catalog:' - version: 4.3.0(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4)) + version: 4.3.0(vite@8.0.10(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0)) '@types/leaflet.markercluster': specifier: ^1.5.6 version: 1.5.6 @@ -567,11 +567,11 @@ importers: specifier: ^8.18.1 version: 8.18.1 '@vitest/browser': - specifier: ^4.1.5 - version: 4.1.5(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4))(vitest@4.1.5) + specifier: ^4.1.6 + version: 4.1.6(vite@8.0.10(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0))(vitest@4.1.6) '@vitest/browser-playwright': - specifier: ^4.1.5 - version: 4.1.5(playwright@1.59.1)(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4))(vitest@4.1.5) + specifier: ^4.1.6 + version: 4.1.6(playwright@1.60.0)(vite@8.0.10(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0))(vitest@4.1.6) leaflet.markercluster: specifier: ^1.5.3 version: 1.5.3(leaflet@1.9.4) @@ -586,7 +586,7 @@ importers: version: 5.9.3 vite: specifier: 'catalog:' - version: 8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4) + version: 8.0.10(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0) packages/api: dependencies: @@ -598,14 +598,14 @@ 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.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(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.16(expo@55.0.24)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(pg@8.20.0)(postgres@3.4.9) postgres: specifier: 'catalog:' version: 3.4.9 devDependencies: '@types/node': specifier: 'catalog:' - version: 22.19.18 + version: 22.19.19 packages/fit: dependencies: @@ -618,7 +618,7 @@ importers: devDependencies: '@types/node': specifier: 'catalog:' - version: 22.19.18 + version: 22.19.19 fit-file-parser: specifier: ^3.0.0 version: 3.0.0 @@ -634,7 +634,7 @@ importers: devDependencies: '@types/node': specifier: 'catalog:' - version: 22.19.18 + version: 22.19.19 packages/i18n: dependencies: @@ -656,7 +656,7 @@ importers: devDependencies: '@types/node': specifier: 'catalog:' - version: 22.19.18 + version: 22.19.19 packages/map: dependencies: @@ -682,7 +682,7 @@ importers: devDependencies: '@types/node': specifier: 'catalog:' - version: 22.19.18 + version: 22.19.19 packages/types: {} @@ -692,7 +692,7 @@ importers: devDependencies: '@types/node': specifier: 'catalog:' - version: 22.19.18 + version: 22.19.19 packages: @@ -1238,8 +1238,8 @@ packages: '@codemirror/state@6.6.0': resolution: {integrity: sha512-4nbvra5R5EtiCzr9BTHiTLc+MLXK2QGiAVYMyi8PkQd3SR+6ixar/Q/01Fa21TBIDOZXgeWV4WppsQolSreAPQ==} - '@codemirror/view@6.42.1': - resolution: {integrity: sha512-ToN3oFc0nsxNUYVF5P0ztLgbC4UPPjPtA9aKYhkOKQaZASpOUo6ISXyQLP66ctVwlDc+j6Jv0uK5IFALkiXztg==} + '@codemirror/view@6.43.0': + resolution: {integrity: sha512-V7ZCLQO3Jus9hzh2jVCCPW3mO4IBMr43O37PqSUYautJSnnJF41YlgLw21x0fLJTYvJ+Vkm6Gp+qKGH9pltgXA==} '@csstools/color-helpers@6.0.2': resolution: {integrity: sha512-LMGQLS9EuADloEFkcTBR3BwV/CGHV7zyDxVRtVDTwdI2Ca4it0CCVTT9wCkxSgokjE5Ho41hEPgb8OEUwoXr6Q==} @@ -1759,8 +1759,8 @@ packages: resolution: {integrity: sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} - '@eslint/config-helpers@0.5.5': - resolution: {integrity: sha512-eIJYKTCECbP/nsKaaruF6LW967mtbQbsw4JTtSVkUQc9MneSkbrgPJAbKl9nWr0ZeowV8BfsarBmPpBzGelA2w==} + '@eslint/config-helpers@0.6.0': + resolution: {integrity: sha512-ii6Bw9jJ2zi2cWA2Z+9/QZ/+3DX6kwaV5Q986D/CdP3Lap3w/pgQZ373FV7byY/i7L4IRH/G43I5dz1ClsCbpA==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} '@eslint/core@1.2.1': @@ -1796,8 +1796,8 @@ packages: '@expo-google-fonts/material-symbols@0.4.36': resolution: {integrity: sha512-hFIN8h99qUid9OppB9Sj18sUQib2O0I9c0soBmgb932Kz+20pAaGe/PRH6NdAqm8/DdOs+Hwx8A4Fqn9ZNadhg==} - '@expo/cli@55.0.29': - resolution: {integrity: sha512-r2dXQ82e/3nwxS7faLRL6HBD8UWDo/IyptQ0Vg6Z5Bgyp2Kd24h8xPn3RHfY3LLJ3wfEXglf4E79/Dqkm1Z6WA==} + '@expo/cli@55.0.30': + resolution: {integrity: sha512-luWcCgompncWtCi1HqQfY32MVOuD0kUeARpr1Le1LeKVtZykjOwnz7YWXZo5zjISiD7L/gQnBNGVrRjvREsJqg==} hasBin: true peerDependencies: expo: '*' @@ -1812,8 +1812,8 @@ packages: '@expo/code-signing-certificates@0.0.6': resolution: {integrity: sha512-iNe0puxwBNEcuua9gmTGzq+SuMDa0iATai1FlFTMHJ/vUmKvN/V//drXoLJkVb5i5H3iE/n/qIJxyoBnXouD0w==} - '@expo/config-plugins@55.0.8': - resolution: {integrity: sha512-8WfWTRntTCcowfOS+tHdB0z98gKetTwktg4G5TWkCkXVa8Jt1NUnvzaaU4UHk2vbR2U4N84RyZJFizSwfF6C9g==} + '@expo/config-plugins@55.0.9': + resolution: {integrity: sha512-jLfpxru8dTo7eU0cqeTWuQav7byyjb37eF/mbXl1/3eTBHBvFU1VGxpeKxanUdTQAAjqzH8KGgWb0fWcce+z1w==} '@expo/config-types@55.0.5': resolution: {integrity: sha512-sCmSUZG4mZ/ySXvfyyBdhjivz8Q539X1NondwDdYG7s3SBsk+wsgPJzYsqgAG/P9+l0xWjUD2F+kQ1cAJ6NNLg==} @@ -1821,6 +1821,9 @@ packages: '@expo/config@55.0.16': resolution: {integrity: sha512-H5dpQv5TfyZDNheZAWO3SmP10diGWZwN5QOUsArkDJih0QKNtahQBOmrV2xbhgln/nrUGoy41U/ZIY/MEx63Ug==} + '@expo/config@55.0.17': + resolution: {integrity: sha512-Y3VaRg7Jllg3MhlUOTQqHm6/dttsqcjYlnS9enhAllZvPUpTHnRA4YPETtUZlxkdMJy6y3UZe986pd/KfJ6OTg==} + '@expo/devcert@1.2.1': resolution: {integrity: sha512-qC4eaxmKMTmJC2ahwyui6ud8f3W60Ss7pMkpBq40Hu3zyiAaugPXnZ24145U7K36qO9UHdZUVxsCvIpz2RYYCA==} @@ -1856,8 +1859,8 @@ packages: '@expo/json-file@10.0.14': resolution: {integrity: sha512-yWwBFywFv+SxkJp/pIzzA416JVYflNUh7pqQzgaA6nXDqRyK7KfrqVzk8PdUfDnqbBcaZZxpzNssfQZzp5KHrA==} - '@expo/local-build-cache-provider@55.0.12': - resolution: {integrity: sha512-Wqhe7ajt6lyIEQvqDC1zm0MQ1RqQLlM9awCepY9pz+tm9rvhuxGPZTSddWeD8k4kolinBlDbLDFnNi06XgaDWQ==} + '@expo/local-build-cache-provider@55.0.13': + resolution: {integrity: sha512-Vg5BE10UL+0yg3BVtIeiSoeHU31Qe1m3UxhBPS478ACY1zzKuxZE30x2sym/B2OIWypjmPzXDRt8J9TOGFuFNw==} '@expo/log-box@55.0.12': resolution: {integrity: sha512-f9ARS8J60cq3LLNdIqmUjYwyerBzVS5Ecp7KjIf3GOIPjW0571rkcwLz4/U18l/1DeSkSzIkYsNl2TC9oTdWaQ==} @@ -1867,8 +1870,8 @@ packages: react: ^19.2.5 react-native: '*' - '@expo/metro-config@55.0.20': - resolution: {integrity: sha512-dUv0simEyPbN2wbOjI+BdEZyXdghgCZD0+3rrA1WxXZN1lRofUx6g2+Nik2Qg61v/BXFrCTh8reYEzQPzHOhdQ==} + '@expo/metro-config@55.0.21': + resolution: {integrity: sha512-pJ8G0uCxqA9KK+XCzXZF7ZI37rduD2l7Cun2e3rVAgB2yeOZagUD+VBvooU9QPiWx9e/7EbimH5/JP81JyhQlg==} peerDependencies: expo: '*' peerDependenciesMeta: @@ -1899,8 +1902,8 @@ packages: '@expo/plist@0.5.3': resolution: {integrity: sha512-jz5oPcPDd3fygwVxwSwmO6wodTwm0Qa14NUyPy0ka7H8sFmCtNZUI2+DzVe/EXjOhq1FbEjrwl89gdlWYOnVjQ==} - '@expo/prebuild-config@55.0.17': - resolution: {integrity: sha512-Mcs+dg4Ripu0yCtzf66KZr18PehI1O8HxzJw+G5SUF8VWX+ic99aci1PltvmydWepLwTQL6ykmpXicAUA31IqA==} + '@expo/prebuild-config@55.0.18': + resolution: {integrity: sha512-2oKXyy5pyM87DJqXW5Z+Sakle6rApFFtpPhWOiNsOdoh6rOAD+EqVgyrs2OEEic8CE0tTt27w3SRfSZe/PZrxg==} peerDependencies: expo: '*' @@ -2290,12 +2293,12 @@ packages: '@mapbox/unitbezier@0.0.1': resolution: {integrity: sha512-nMkuDXFv60aBr9soUG5q+GvZYL+2KZHVvsqFCzqnkGEf46U2fvmytHaEVc1/YZbiLn8X+eR3QzX1+dwDO1lxlw==} - '@maplibre/maplibre-gl-style-spec@24.8.1': - resolution: {integrity: sha512-zxa92qF96ZNojLxeAjnaRpjVCy+swoUNJvDhtpC90k7u5F0TMr4GmvNqMKvYrMoPB8d7gRSXbMG1hBbmgESIsw==} + '@maplibre/maplibre-gl-style-spec@24.8.5': + resolution: {integrity: sha512-EzEJmMt6thioRH7GI9LWS7ahXTcAhAPGWCe6oTP2Ps4YnsXOOAfeqx854lZaiDnwURfHmcCKV1mr6oo0i23x6w==} hasBin: true - '@maplibre/maplibre-react-native@11.1.1': - resolution: {integrity: sha512-yKeEyXupYYRO0s5PE1pSIvGQ3YEyoJGpvwMkZraZ3hFKR8ZeGgvTO3xm45KsSFKKYuBgOYH7Kg7mYXfQlmgEjw==} + '@maplibre/maplibre-react-native@11.2.1': + resolution: {integrity: sha512-I3AqN3JUkgT1QzRBsqtsS+123uny86lEsye9+Q180rRlaoGSiRRUhiyYbF48eQcyehcn9GvoazCBNQ1dKHKJAA==} peerDependencies: '@expo/config-plugins': '>=54.0.0' '@types/geojson': ^7946.0.0 @@ -2547,8 +2550,8 @@ packages: '@pinojs/redact@0.4.0': resolution: {integrity: sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==} - '@playwright/test@1.59.1': - resolution: {integrity: sha512-PG6q63nQg5c9rIi4/Z5lR5IVF7yU5MqmKaPOe0HSc0O2cX1fPi96sUQu5j7eo4gKCkB2AnNGoWt7y4/Xx3Kcqg==} + '@playwright/test@1.60.0': + resolution: {integrity: sha512-O71yZIbAh/PxDMNGns37GHBIfrVkEVyn+AXyIa5dOTfb4/xNvRWV+Vv/NMbNCtODB/pO7vLlF2OTmMVLhmr7Ag==} engines: {node: '>=18'} hasBin: true @@ -2962,14 +2965,14 @@ packages: '@react-navigation/routers@7.5.5': resolution: {integrity: sha512-9/hhMte12Kgu+pMnLfA4EWJ0OQmIEAMVMX06FPH2yGkEQSQ3JhhCN/GkcRikzQhtEi97VYYQA15umptBUShcOQ==} - '@react-router/dev@7.15.0': - resolution: {integrity: sha512-ZwUQu4KNZrViFqdeFWqh00Bk/QbLNvoWRDfjsqOp3oyuG3jSRLYnqRD3VAMK/FYMpL+s37ByT7XqqLXaF7Nw1g==} + '@react-router/dev@7.15.1': + resolution: {integrity: sha512-BlFEU7SjPQHJDfYuw5qJU3+p4wMPEvKpf5Kj64/rRzQQjncXzhzkIJ0xreAQSYgGwJWjIXIK9swOaeE2czhulw==} engines: {node: '>=20.0.0'} hasBin: true peerDependencies: - '@react-router/serve': ^7.15.0 + '@react-router/serve': ^7.15.1 '@vitejs/plugin-rsc': ~0.5.21 - react-router: ^7.15.0 + react-router: ^7.15.1 react-server-dom-webpack: ^19.2.3 typescript: ^5.1.0 || ^6.0.0 vite: ^5.1.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 @@ -2986,33 +2989,33 @@ packages: wrangler: optional: true - '@react-router/express@7.15.0': - resolution: {integrity: sha512-WldQrI5FxbsTLztOqx0+c7248m8IDUchCUUX177I+qz9OMuLR9ueIqz53zBKCVQ+Zf7k6FyatwpoLmr/Wovalg==} + '@react-router/express@7.15.1': + resolution: {integrity: sha512-JDTaYp9Jcd6mNFdNT/ynNhT5wpMArJmXjlkIl5ZfjxsoX07x36pz+o+EUv818ya5hcq21MPozlqj0q04ApxODw==} engines: {node: '>=20.0.0'} peerDependencies: express: ^4.17.1 || ^5 - react-router: 7.15.0 + react-router: 7.15.1 typescript: ^5.1.0 || ^6.0.0 peerDependenciesMeta: typescript: optional: true - '@react-router/node@7.15.0': - resolution: {integrity: sha512-SgvWaWF1n3u+bpXXZUW9BSd2p/NwkIYLz4SSeDYqoX5RkYX5rcI4cHHuNJXszPu+Dm9QIri4J9g/4EV3KfgiXQ==} + '@react-router/node@7.15.1': + resolution: {integrity: sha512-lv68RaqmIa/ZRlIrGcl79HimaqpU3yV1CFKnmItU+xqI+xn9g5fqsh2Vj2LdNjnlzJgVsRMEpnv00t/6RgDrgw==} engines: {node: '>=20.0.0'} peerDependencies: - react-router: 7.15.0 + react-router: 7.15.1 typescript: ^5.1.0 || ^6.0.0 peerDependenciesMeta: typescript: optional: true - '@react-router/serve@7.15.0': - resolution: {integrity: sha512-0XtYmwc11vWdYn2zeEXx9E3u0I6TH3bm4uDaMdsyI09S6hl6uc98vBkTSXg7Znm3qR82R/jjtn3LvV2QEZ193w==} + '@react-router/serve@7.15.1': + resolution: {integrity: sha512-x9rON/OtmfVKsc4OxZI0GzgZBVBhKvtJ2N1CuembFhH4c1lmZyK0kk7+rHUkVboM3vSevqxnLWs+SMRsp26xaw==} engines: {node: '>=20.0.0'} hasBin: true peerDependencies: - react-router: 7.15.0 + react-router: 7.15.1 '@remix-run/node-fetch-server@0.13.1': resolution: {integrity: sha512-dOL+A/C84EA47gO/ps52KGrVSiYy96512rwtbXmJfWKYFm1FbrbjA3jao1hcIfao+jwVNEaZ1kTMwFjiino+HQ==} @@ -3115,141 +3118,141 @@ packages: '@rolldown/pluginutils@1.0.0-rc.17': resolution: {integrity: sha512-n8iosDOt6Ig1UhJ2AYqoIhHWh/isz0xpicHTzpKBeotdVsTEcxsSA/i3EVM7gQAj0rU27OLAxCjzlj15IWY7bg==} - '@rollup/rollup-android-arm-eabi@4.60.3': - resolution: {integrity: sha512-x35CNW/ANXG3hE/EZpRU8MXX1JDN86hBb2wMGAtltkz7pc6cxgjpy1OMMfDosOQ+2hWqIkag/fGok1Yady9nGw==} + '@rollup/rollup-android-arm-eabi@4.60.4': + resolution: {integrity: sha512-F5QXMSiFebS9hKZj02XhWLLnRpJ3B3AROP0tWbFBSj+6kCbg5m9j5JoHKd4mmSVy5mS/IMQloYgYxCuJC0fxEQ==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.60.3': - resolution: {integrity: sha512-xw3xtkDApIOGayehp2+Rz4zimfkaX65r4t47iy+ymQB2G4iJCBBfj0ogVg5jpvjpn8UWn/+q9tprxleYeNp3Hw==} + '@rollup/rollup-android-arm64@4.60.4': + resolution: {integrity: sha512-GxxTKApUpzRhof7poWvCJHRF51C67u1R7D6DiluBE8wKU1u5GWE8t+v81JvJYtbawoBFX1hLv5Ei4eVjkWokaw==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.60.3': - resolution: {integrity: sha512-vo6Y5Qfpx7/5EaamIwi0WqW2+zfiusVihKatLvtN1VFVy3D13uERk/6gZLU1UiHRL6fDXqj/ELIeVRGnvcTE1g==} + '@rollup/rollup-darwin-arm64@4.60.4': + resolution: {integrity: sha512-tua0TaJxMOB1R0V0RS1jFZ/RpURFDJIOR2A6jWwQeawuFyS4gBW+rntLRaQd0EQ4bd6Vp44Z2rXW+YYDBsj6IA==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.60.3': - resolution: {integrity: sha512-D+0QGcZhBzTN82weOnsSlY7V7+RMmPuF1CkbxyMAGE8+ZHeUjyb76ZiWmBlCu//AQQONvxcqRbwZTajZKqjuOw==} + '@rollup/rollup-darwin-x64@4.60.4': + resolution: {integrity: sha512-CSKq7MsP+5PFIcydhAiR1K0UhEI1A2jWXVKHPCBZ151yOutENwvnPocgVHkivu2kviURtCEB6zUQw0vs8RrhMg==} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.60.3': - resolution: {integrity: sha512-6HnvHCT7fDyj6R0Ph7A6x8dQS/S38MClRWeDLqc0MdfWkxjiu1HSDYrdPhqSILzjTIC/pnXbbJbo+ft+gy/9hQ==} + '@rollup/rollup-freebsd-arm64@4.60.4': + resolution: {integrity: sha512-+O8OkVdyvXMtJEciu2wS/pzm1IxntEEQx3z5TAVy4l32G0etZn+RsA48ARRrFm6Ri8fvqPQfgrvNxSjKAbnd3g==} cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.60.3': - resolution: {integrity: sha512-KHLgC3WKlUYW3ShFKnnosZDOJ0xjg9zp7au3sIm2bs/tGBeC2ipmvRh/N7JKi0t9Ue20C0dpEshi8WUubg+cnA==} + '@rollup/rollup-freebsd-x64@4.60.4': + resolution: {integrity: sha512-Iw3oMskH3AfNuhU0MSN7vNbdi4me/NiYo2azqPz/Le16zHSa+3RRmliCMWWQmh4lcndccU40xcJuTYJZxNo/lw==} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.60.3': - resolution: {integrity: sha512-DV6fJoxEYWJOvaZIsok7KrYl0tPvga5OZ2yvKHNNYyk/2roMLqQAbGhr78EQ5YhHpnhLKJD3S1WFusAkmUuV5g==} + '@rollup/rollup-linux-arm-gnueabihf@4.60.4': + resolution: {integrity: sha512-EIPRXTVQpHyF8WOo219AD2yEltPehLTcTMz2fn6JsatLYSzQf00hj3rulF+yauOlF9/FtM2WpkT/hJh/KJFGhA==} cpu: [arm] os: [linux] libc: [glibc] - '@rollup/rollup-linux-arm-musleabihf@4.60.3': - resolution: {integrity: sha512-mQKoJAzvuOs6F+TZybQO4GOTSMUu7v0WdxEk24krQ/uUxXoPTtHjuaUuPmFhtBcM4K0ons8nrE3JyhTuCFtT/w==} + '@rollup/rollup-linux-arm-musleabihf@4.60.4': + resolution: {integrity: sha512-J3Yh9PzzF1Ovah2At+lHiGQdsYgArxBbXv/zHfSyaiFQEqvNv7DcW98pCrmdjCZBrqBiKrKKe2V+aaSGWuBe/w==} cpu: [arm] os: [linux] libc: [musl] - '@rollup/rollup-linux-arm64-gnu@4.60.3': - resolution: {integrity: sha512-Whjj2qoiJ6+OOJMGptTYazaJvjOJm+iKHpXQM1P3LzGjt7Ff++Tp7nH4N8J/BUA7R9IHfDyx4DJIflifwnbmIA==} + '@rollup/rollup-linux-arm64-gnu@4.60.4': + resolution: {integrity: sha512-BFDEZMYfUvLn37ONE1yMBojPxnMlTFsdyNoqncT0qFq1mAfllL+ATMMJd8TeuVMiX84s1KbcxcZbXInmcO2mRg==} cpu: [arm64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-arm64-musl@4.60.3': - resolution: {integrity: sha512-4YTNHKqGng5+yiZt3mg77nmyuCfmNfX4fPmyUapBcIk+BdwSwmCWGXOUxhXbBEkFHtoN5boLj/5NON+u5QC9tg==} + '@rollup/rollup-linux-arm64-musl@4.60.4': + resolution: {integrity: sha512-pc9EYOSlOgdQ2uPl1o9PF6/kLSgaUosia7gOuS8mB69IxJvlclko1MECXysjs5ryez1/5zjYqx3+xYU0TU6R1A==} cpu: [arm64] os: [linux] libc: [musl] - '@rollup/rollup-linux-loong64-gnu@4.60.3': - resolution: {integrity: sha512-SU3kNlhkpI4UqlUc2VXPGK9o886ZsSeGfMAX2ba2b8DKmMXq4AL7KUrkSWVbb7koVqx41Yczx6dx5PNargIrEA==} + '@rollup/rollup-linux-loong64-gnu@4.60.4': + resolution: {integrity: sha512-NxnomyxYerDh5n4iLrNa+sH+Z+U4BMEE46V2PgQ/hoB909i8gV1M5wPojWg9fk1jWpO3IQnOs20K4wyZuFLEFQ==} cpu: [loong64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-loong64-musl@4.60.3': - resolution: {integrity: sha512-6lDLl5h4TXpB1mTf2rQWnAk/LcXrx9vBfu/DT5TIPhvMhRWaZ5MxkIc8u4lJAmBo6klTe1ywXIUHFjylW505sg==} + '@rollup/rollup-linux-loong64-musl@4.60.4': + resolution: {integrity: sha512-nbJnQ8a3z1mtmrwImCYhc6BGpThAyYVRQxw9uKSKG4wR6aAYno9sVjJ0zaZcW9BPJX1GbrDPf+SvdWjgTuDmnw==} cpu: [loong64] os: [linux] libc: [musl] - '@rollup/rollup-linux-ppc64-gnu@4.60.3': - resolution: {integrity: sha512-BMo8bOw8evlup/8G+cj5xWtPyp93xPdyoSN16Zy90Q2QZ0ZYRhCt6ZJSwbrRzG9HApFabjwj2p25TUPDWrhzqQ==} + '@rollup/rollup-linux-ppc64-gnu@4.60.4': + resolution: {integrity: sha512-2EU6acNrQLd8tYvo/LXW535wupT3m6fo7HKo6lr7ktQoItxTyOL1ZCR/GfGCuXl2vR+zmfI6eRXkSemafv+iVg==} cpu: [ppc64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-ppc64-musl@4.60.3': - resolution: {integrity: sha512-E0L8X1dZN1/Rph+5VPF6Xj2G7JJvMACVXtamTJIDrVI44Y3K+G8gQaMEAavbqCGTa16InptiVrX6eM6pmJ+7qA==} + '@rollup/rollup-linux-ppc64-musl@4.60.4': + resolution: {integrity: sha512-WeBtoMuaMxiiIrO2IYP3xs6GMWkJP2C0EoT8beTLkUPmzV1i/UcOSVw1d5r9KBODtHKilG5yFxsGRnBbK3wJ4A==} cpu: [ppc64] os: [linux] libc: [musl] - '@rollup/rollup-linux-riscv64-gnu@4.60.3': - resolution: {integrity: sha512-oZJ/WHaVfHUiRAtmTAeo3DcevNsVvH8mbvodjZy7D5QKvCefO371SiKRpxoDcCxB3PTRTLayWBkvmDQKTcX/sw==} + '@rollup/rollup-linux-riscv64-gnu@4.60.4': + resolution: {integrity: sha512-FJHFfqpKUI3A10WrWKiFbBZ7yVbGT4q4B5o1qKFFojqpaYoh9LrQgqWCmmcxQzVSXYtyB5bzkXrYzlHTs21MYA==} cpu: [riscv64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-riscv64-musl@4.60.3': - resolution: {integrity: sha512-Dhbyh7j9FybM3YaTgaHmVALwA8AkUwTPccyCQ79TG9AJUsMQqgN1DDEZNr4+QUfwiWvLDumW5vdwzoeUF+TNxQ==} + '@rollup/rollup-linux-riscv64-musl@4.60.4': + resolution: {integrity: sha512-mcEl6CUT5IAUmQf1m9FYSmVqCJlpQ8r8eyftFUHG8i9OhY7BkBXSUdnLH5DOf0wCOjcP9v/QO93zpmF1SptCCw==} cpu: [riscv64] os: [linux] libc: [musl] - '@rollup/rollup-linux-s390x-gnu@4.60.3': - resolution: {integrity: sha512-cJd1X5XhHHlltkaypz1UcWLA8AcoIi1aWhsvaWDskD1oz2eKCypnqvTQ8ykMNI0RSmm7NkTdSqSSD7zM0xa6Ig==} + '@rollup/rollup-linux-s390x-gnu@4.60.4': + resolution: {integrity: sha512-ynt3JxVd2w2buzoKDWIyiV1pJW93xlQic1THVLXilz429oijRpSHivZAgp65KBu+cMcgf1eVVjdnTLvPxgCuoQ==} cpu: [s390x] os: [linux] libc: [glibc] - '@rollup/rollup-linux-x64-gnu@4.60.3': - resolution: {integrity: sha512-DAZDBHQfG2oQuhY7mc6I3/qB4LU2fQCjRvxbDwd/Jdvb9fypP4IJ4qmtu6lNjes6B531AI8cg1aKC2di97bUxA==} + '@rollup/rollup-linux-x64-gnu@4.60.4': + resolution: {integrity: sha512-Boiz5+MsaROEWDf+GGEwF8VMHGhlUoQMtIPjOgA5fv4osupqTVnJteQNKJwUcnUog2G55jYXH7KZFFiJe0TEzQ==} cpu: [x64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-x64-musl@4.60.3': - resolution: {integrity: sha512-cRxsE8c13mZOh3vP+wLDxpQBRrOHDIGOWyDL93Sy0Ga8y515fBcC2pjUfFwUe5T7tqvTvWbCpg1URM/AXdWIXA==} + '@rollup/rollup-linux-x64-musl@4.60.4': + resolution: {integrity: sha512-+qfSY27qIrFfI/Hom04KYFw3GKZSGU4lXus51wsb5EuySfFlWRwjkKWoE9emgRw/ukoT4Udsj4W/+xxG8VbPKg==} cpu: [x64] os: [linux] libc: [musl] - '@rollup/rollup-openbsd-x64@4.60.3': - resolution: {integrity: sha512-QaWcIgRxqEdQdhJqW4DJctsH6HCmo5vHxY0krHSX4jMtOqfzC+dqDGuHM87bu4H8JBeibWx7jFz+h6/4C8wA5Q==} + '@rollup/rollup-openbsd-x64@4.60.4': + resolution: {integrity: sha512-VpTfOPHgVXEBeeR8hZ2O0F3aSso+JDWqTWmTmzcQKted54IAdUVbxE+j/MVxUsKa8L20HJhv3vUezVPoquqWjA==} cpu: [x64] os: [openbsd] - '@rollup/rollup-openharmony-arm64@4.60.3': - resolution: {integrity: sha512-AaXwSvUi3QIPtroAUw1t5yHGIyqKEXwH54WUocFolZhpGDruJcs8c+xPNDRn4XiQsS7MEwnYsHW2l0MBLDMkWg==} + '@rollup/rollup-openharmony-arm64@4.60.4': + resolution: {integrity: sha512-IPOsh5aRYuLv/nkU51X10Bf75Bsf6+gZdx1X+QP5QM6lIJFHHqbHLG0uJn/hWthzo13UAc2umiUorqZy3axoZg==} cpu: [arm64] os: [openharmony] - '@rollup/rollup-win32-arm64-msvc@4.60.3': - resolution: {integrity: sha512-65LAKM/bAWDqKNEelHlcHvm2V+Vfb8C6INFxQXRHCvaVN1rJfwr4NvdP4FyzUaLqWfaCGaadf6UbTm8xJeYfEg==} + '@rollup/rollup-win32-arm64-msvc@4.60.4': + resolution: {integrity: sha512-4QzE9E81OohJ/HKzHhsqU+zcYYojVOXlFMs1DdyMT6qXl/niOH7AVElmmEdUNHHS/oRkc++d5k6Vy85zFs0DEw==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.60.3': - resolution: {integrity: sha512-EEM2gyhBF5MFnI6vMKdX1LAosE627RGBzIoGMdLloPZkXrUN0Ckqgr2Qi8+J3zip/8NVVro3/FjB+tjhZUgUHA==} + '@rollup/rollup-win32-ia32-msvc@4.60.4': + resolution: {integrity: sha512-zTPgT1YuHHcd+Tmx7h8aml0FWFVelV5N54oHow9SLj+GfoDy/huQ+UV396N/C7KpMDMiPspRktzM1/0r1usYEA==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-gnu@4.60.3': - resolution: {integrity: sha512-E5Eb5H/DpxaoXH++Qkv28RcUJboMopmdDUALBczvHMf7hNIxaDZqwY5lK12UK1BHacSmvupoEWGu+n993Z0y1A==} + '@rollup/rollup-win32-x64-gnu@4.60.4': + resolution: {integrity: sha512-DRS4G7mi9lJxqEDezIkKCaUIKCrLUUDCUaCsTPCi/rtqaC6D/jjwslMQyiDU50Ka0JKpeXeRBFBAXwArY52vBw==} cpu: [x64] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.60.3': - resolution: {integrity: sha512-hPt/bgL5cE+Qp+/TPHBqptcAgPzgj46mPcg/16zNUmbQk0j+mOEQV/+Lqu8QRtDV3Ek95Q6FeFITpuhl6OTsAA==} + '@rollup/rollup-win32-x64-msvc@4.60.4': + resolution: {integrity: sha512-QVTUovf40zgTqlFVrKA1uXMVvU2QWEFWfAH8Wdc48IxLvrJMQVMBRjuQyUpzZCDkakImib9eVazbWlC6ksWtJw==} cpu: [x64] os: [win32] @@ -3257,48 +3260,52 @@ packages: resolution: {integrity: sha512-lNKBS4P7RUvf1niojXQWe9bU3gnBUCbST4Dj0pSiyat1N96cXVyHkeE+uGxowD0RrVWhs+kGHiVX3FcmRWF6sA==} engines: {node: '>=18'} - '@sentry-internal/browser-utils@10.52.0': - resolution: {integrity: sha512-x/yEPZdpH6NGQeoeQnV9tj8reAH8twNttiltGZl2o8Rk7sQeUfe7E8yuYP2XbJ2RqyZK5qRS3COrNyMPzf6KFA==} + '@sentry-internal/browser-utils@10.53.1': + resolution: {integrity: sha512-X4d6y8sBMjmNhcDW4eMBU3ASsNIMz8dqaFkhyIMN/dkYr/yZKnbRZPaVuVUGvHKjnlficPpIH0/HK9KBjrYxPw==} engines: {node: '>=18'} '@sentry-internal/feedback@10.51.0': resolution: {integrity: sha512-bCM95bcpphx28e6aU0bwRLxOgwosYsdNzezM1sM0pVOkb0TB3hDFRamramVDK+/Hp1o8qmRxS4c5w/A7YBZGkA==} engines: {node: '>=18'} - '@sentry-internal/feedback@10.52.0': - resolution: {integrity: sha512-5kAn1W8ZvCuHtEHXpq6iRkUMdNCilwww+YxaN2yofVrCivAbB3Ha5JJUMqmWOPW0pC27zGYmoJMIDvG+PczUxA==} + '@sentry-internal/feedback@10.53.1': + resolution: {integrity: sha512-vVpTI/aEYN5d9IgZeYJWMqVaN0+iFgidSrYNAsZTh1US5sJUzF/wrl+68KdpmCtFROrN3jiAn1oPSwL5CKvEJA==} engines: {node: '>=18'} '@sentry-internal/replay-canvas@10.51.0': resolution: {integrity: sha512-8PW1Pp+Yl3lPwYqhBCr5SgkuhDanu9ZLzUqD2bPKL/ElqbM2eDVIWxq4z4ZzePrmZa6IcCjTv6sVQJ7Z4dLyLA==} engines: {node: '>=18'} - '@sentry-internal/replay-canvas@10.52.0': - resolution: {integrity: sha512-BI5ie4dxPuUJ344CXVSnAxY1xZCbghglPSCIlTOYODpR9so9yo5IZh+Mwspt0oWsUMaxWJiQSNYlbPWi7WDavg==} + '@sentry-internal/replay-canvas@10.53.1': + resolution: {integrity: sha512-aueLaf/2prExwA76BGU5/bOXCKWqtt6jQXWA6WJQNrmKpPEtZJB4ypnpsou0McXQCF8tur2Y8U0TEkwQP13yJQ==} engines: {node: '>=18'} '@sentry-internal/replay@10.51.0': resolution: {integrity: sha512-jCpI5HXSwK6ZT2HX70+mDRciAocHzSiDk4DTgvzV69Wvd+Ei5WLgE+d39eaEPsm8lUC0Ydntb5sJIB6uG9D4bw==} engines: {node: '>=18'} - '@sentry-internal/replay@10.52.0': - resolution: {integrity: sha512-diywyuc/H7VTUR+W5ryVmLF+0X4UP1OskMqb6V8RSAvJHcj2JmIm7uP+Fc6ACTno+b6AUShwT/L4xVXzO6X9Cw==} + '@sentry-internal/replay@10.53.1': + resolution: {integrity: sha512-wZNzTBYkgGUPWMuUQv7L64+OJmoCnz7GQNiTrTFK6EVAjJXFBCSsPp/nhif0bLhbk8+0g4xz633uOhpXuQbFdw==} engines: {node: '>=18'} '@sentry/babel-plugin-component-annotate@5.2.1': resolution: {integrity: sha512-QQ9AL5EXIbSK26ObLVtiU6l3tCUdpGSJ/6VwDkPhC3qvtoksSlcoU9Yzm7XC0NBcvu1N2abL5R7gckKGZ4JewQ==} engines: {node: '>= 18'} + '@sentry/babel-plugin-component-annotate@5.3.0': + resolution: {integrity: sha512-p4q8gn8wcFqZGP/s2MnJCAAd8fTikaU6A0mM97RDHQgStcrYiaS0Sc5zUNfb1V+UOLPuvdEdL6MwyxfzjYJQTA==} + engines: {node: '>= 18'} + '@sentry/browser@10.51.0': resolution: {integrity: sha512-Zdc0sKfenxUtW/OGhtJ7xHFN44bXR7YqxJ1zBDzlZfW0nTbeTTUZBq9z5NUw6qdS0Vs/i3V4qzAKTbRKWfqSEA==} engines: {node: '>=18'} - '@sentry/browser@10.52.0': - resolution: {integrity: sha512-ijL9jN86oXwXQWbwhPlEb70ODJSEmjxQEQdnZkC4gDWbjswcwvRsVJPYk+1xl2ir2iZixRIHipVxDcLwian35g==} + '@sentry/browser@10.53.1': + resolution: {integrity: sha512-zXF373hzUOGzUOrqd8xb1U3LQi5uYC3mwv+z5OMKUUinQlu30tTWBs7ypy6YTchtix9QlYaHWlayUF8vBZ5UjA==} engines: {node: '>=18'} - '@sentry/bundler-plugin-core@5.2.1': - resolution: {integrity: sha512-uXb+TOZKXxm2STsP3iR70Jh/yYHwlHOvql7w/bUVYgDyiB/1Mv0D6oNGS0kelsgBsBwCq3ngyJYlyNy3oM1pPw==} + '@sentry/bundler-plugin-core@5.3.0': + resolution: {integrity: sha512-L5T60sWdAI3qWwdg3Ptwek/0TY59PERrxyqp4XMUkroayQvGd9r5dIW9Q1kSeXX9iJ442nXbFZKAOyCKV4Z13Q==} engines: {node: '>= 18'} '@sentry/cli-darwin@2.58.5': @@ -3311,6 +3318,11 @@ packages: engines: {node: '>=18'} os: [darwin] + '@sentry/cli-darwin@3.4.2': + resolution: {integrity: sha512-MMCkBxj8l5IolwJyf7mv5v/rKOdZS8YCVmXUzv+H75j28j2lvLfsScWh0YaRkzv6+ATYkG1Z5g2J1alv91OuYQ==} + engines: {node: '>=18'} + os: [darwin] + '@sentry/cli-linux-arm64@2.58.5': resolution: {integrity: sha512-/4gywFeBqRB6tR/iGMRAJ3HRqY6Z7Yp4l8ZCbl0TDLAfHNxu7schEw4tSnm2/Hh9eNMiOVy4z58uzAWlZXAYBQ==} engines: {node: '>=10'} @@ -3323,6 +3335,12 @@ packages: cpu: [arm64] os: [linux, freebsd, android] + '@sentry/cli-linux-arm64@3.4.2': + resolution: {integrity: sha512-xsA7DjZkFBBu5WLINimWv50h+jSxS5+F+6DxMYcgXkYZ4pbEWToG+IcBaZGsqXKNIYIUyd7hQvqCH/LFNAqShA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux, freebsd, android] + '@sentry/cli-linux-arm@2.58.5': resolution: {integrity: sha512-KtHweSIomYL4WVDrBrYSYJricKAAzxUgX86kc6OnlikbyOhoK6Fy8Vs6vwd52P6dvWPjgrMpUYjW2M5pYXQDUw==} engines: {node: '>=10'} @@ -3335,6 +3353,12 @@ packages: cpu: [arm] os: [linux, freebsd, android] + '@sentry/cli-linux-arm@3.4.2': + resolution: {integrity: sha512-oLnskL/TD/SkcqZ8xSPSSZfSSTEswiyx/hqtENmzR8aKIEiyZlDD8sH2h5CCevVDTGO2WDbOWZQCKFlWtIWP1Q==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux, freebsd, android] + '@sentry/cli-linux-i686@2.58.5': resolution: {integrity: sha512-G7261dkmyxqlMdyvyP06b+RTIVzp1gZNgglj5UksxSouSUqRd/46W/2pQeOMPhloDYo9yLtCN2YFb3Mw4aUsWw==} engines: {node: '>=10'} @@ -3347,6 +3371,12 @@ packages: cpu: [x86, ia32] os: [linux, freebsd, android] + '@sentry/cli-linux-i686@3.4.2': + resolution: {integrity: sha512-AD8l7GGwGIixALSYeIBWsAqLQgi90df4Z3XIGPOqkJWSg5xh40Qk0r1zHXUwayGabtY8YgDlcAUS1CQ+1Tqu9Q==} + engines: {node: '>=18'} + cpu: [x86, ia32] + os: [linux, freebsd, android] + '@sentry/cli-linux-x64@2.58.5': resolution: {integrity: sha512-rP04494RSmt86xChkQ+ecBNRYSPbyXc4u0IA7R7N1pSLCyO74e5w5Al+LnAq35cMfVbZgz5Sm0iGLjyiUu4I1g==} engines: {node: '>=10'} @@ -3359,6 +3389,12 @@ packages: cpu: [x64] os: [linux, freebsd, android] + '@sentry/cli-linux-x64@3.4.2': + resolution: {integrity: sha512-H73CL6EIdYi75iEUpGF26ojIZk+vTvAKc3Yj4uXRup2kmOikM9uliRlZRgmVsDExApgCDuzFrLzdKFYbJJ03aA==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux, freebsd, android] + '@sentry/cli-win32-arm64@2.58.5': resolution: {integrity: sha512-AOJ2nCXlQL1KBaCzv38m3i2VmSHNurUpm7xVKd6yAHX+ZoVBI8VT0EgvwmtJR2TY2N2hNCC7UrgRmdUsQ152bA==} engines: {node: '>=10'} @@ -3371,6 +3407,12 @@ packages: cpu: [arm64] os: [win32] + '@sentry/cli-win32-arm64@3.4.2': + resolution: {integrity: sha512-fjBS2to5oJpfWmK5l14fZgoRfTOAZIFqa4Ej+urOLU3NH4etehDRHgGMcxPPLjoVkkAC6M/auf1+rQc1tt0olg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + '@sentry/cli-win32-i686@2.58.5': resolution: {integrity: sha512-EsuboLSOnlrN7MMPJ1eFvfMDm+BnzOaSWl8eYhNo8W/BIrmNgpRUdBwnWn9Q2UOjJj5ZopukmsiMYtU/D7ml9g==} engines: {node: '>=10'} @@ -3383,6 +3425,12 @@ packages: cpu: [x86, ia32] os: [win32] + '@sentry/cli-win32-i686@3.4.2': + resolution: {integrity: sha512-20jpyvG8g7QUSa+zBFXEPhvMf5EB4YILCZb1xhGwEZsfwUPN02qRoCwpY018/jKimxEJRGpCHhxC9ybUceQaNg==} + engines: {node: '>=18'} + cpu: [x86, ia32] + os: [win32] + '@sentry/cli-win32-x64@2.58.5': resolution: {integrity: sha512-IZf+XIMiQwj+5NzqbOQfywlOitmCV424Vtf9c+ep61AaVScUFD1TSrQbOcJJv5xGxhlxNOMNgMeZhdexdzrKZg==} engines: {node: '>=10'} @@ -3395,6 +3443,12 @@ packages: cpu: [x64] os: [win32] + '@sentry/cli-win32-x64@3.4.2': + resolution: {integrity: sha512-FfFQzBkTvyU7AafzaOxhAFlmXKMe+9aXKNjnvA4VRHeBExdS71ZHKcPn44rZppoDLHWCrR2nm35WZG4so+jmSA==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + '@sentry/cli@2.58.5': resolution: {integrity: sha512-tavJ7yGUZV+z3Ct2/ZB6mg339i08sAk6HDkgqmSRuQEu2iLS5sl9HIvuXfM6xjv8fwlgFOSy++WNABNAcGHUbg==} engines: {node: '>= 10'} @@ -3405,16 +3459,21 @@ packages: engines: {node: '>= 18'} hasBin: true + '@sentry/cli@3.4.2': + resolution: {integrity: sha512-8HOEe8y4ZtSxBhABSq4fzGgWc1PAR15ptfhrBwxTaqgXAN6CUsPCC/uvdO4gtgo8zKFkD0E5n34YY09tEXJGRg==} + engines: {node: '>= 18'} + hasBin: true + '@sentry/core@10.51.0': resolution: {integrity: sha512-Y45V/YXvVLEXmOdkbD1oG1gkRWFi9guCEGg3PlIlIpRjAbZUrvLGgjRJIc1E7XpSzmOnWbs5BbUxMv4PDaPj2w==} engines: {node: '>=18'} - '@sentry/core@10.52.0': - resolution: {integrity: sha512-VA/kAqLhkMnRWY2RXdBLyTemR9D4m7MVRy/gyapoq9yvllVPx9WXbvKgnMP2LQp7mFgT/oLFvw58aQKaYTGn3A==} + '@sentry/core@10.53.1': + resolution: {integrity: sha512-XG4ezlkyuAPjBC5+9kXC94rXXuqYTw9NRhfaDHssbTFaGnqBR8vQX2UUgZfY7ucbeelRDGfBu1sywoU+mB04uA==} engines: {node: '>=18'} - '@sentry/expo-upload-sourcemaps@8.11.0': - resolution: {integrity: sha512-KECCEY//0aGCGNYswLxJfZN1pCb11GvUz5CGLTKg9sXNfo26RGtZwxEWXnbiM1yHhZhpMoCQjPY9nDmKlvZHnQ==} + '@sentry/expo-upload-sourcemaps@8.11.1': + resolution: {integrity: sha512-xtWJqJotkZGI6M5luexR+9PJKudZHrrKTQ97rbnEBlM6G9CU9FzgLuJzgrxC4+hdM9h21VhIblam3IUtcK2bUg==} engines: {node: '>=18'} hasBin: true peerDependencies: @@ -3426,8 +3485,8 @@ packages: dotenv: optional: true - '@sentry/node-core@10.52.0': - resolution: {integrity: sha512-IG7MBtLRPQ2LuU+kbD14AFZroZgAeUmJQTP1FI/F8n56O31+p+9R703LuBTpvZr6sm+eRYDMWcGYYkfLHRVjwg==} + '@sentry/node-core@10.53.1': + resolution: {integrity: sha512-iH7SMcM/7jPbN+t7+7ussQOiIqI4BMOGt4VYWlV71/z7k0pY+YPaSvlfVkNXfISiDzFAKv0ecCY3BmsLMu1xDQ==} engines: {node: '>=18'} peerDependencies: '@opentelemetry/api': ^1.9.0 @@ -3450,12 +3509,12 @@ packages: '@opentelemetry/semantic-conventions': optional: true - '@sentry/node@10.52.0': - resolution: {integrity: sha512-9+p3KJUk3rHO1HOEZuSknP2RgKCJZONDm4HWgkVDtVBtocb66KLtVlMjc59d2/bWP7tM3wc877tpG30quFfU9g==} + '@sentry/node@10.53.1': + resolution: {integrity: sha512-rxHVil0tJAmz+keFcZCj1LaUdgdkK66E/l0gqh2p1209PNCGoD3lnClFr6vusy1aF3zF8O9JPtuMEJzXOKhs+w==} engines: {node: '>=18'} - '@sentry/opentelemetry@10.52.0': - resolution: {integrity: sha512-Sc7StsvC0bwhMcgDfTRWUIexO5cNzzKUurvUwtpgQUnxO7AzexU3lkY3yHYDsCbWYAEQMXAgQYQtbcqoh+Ie7g==} + '@sentry/opentelemetry@10.53.1': + resolution: {integrity: sha512-Zok6UXla0mFOjd1YnVb1TZtQNOry9v93fXUqx8jmDaygwWM2BwvP8rBQabLz0/OZXo8+35oge+Vmw+QY5aesnA==} engines: {node: '>=18'} peerDependencies: '@opentelemetry/api': ^1.9.0 @@ -3463,8 +3522,8 @@ packages: '@opentelemetry/sdk-trace-base': ^1.30.1 || ^2.1.0 '@opentelemetry/semantic-conventions': ^1.39.0 - '@sentry/react-native@8.11.0': - resolution: {integrity: sha512-cLksJuM5lR447kifAsVgNrY3s6cG2mWEP1ZMPuYKJ0NCtRvpeA09/QmwN9YXbViSftHxyDf+hDvE6bI444chdg==} + '@sentry/react-native@8.11.1': + resolution: {integrity: sha512-TpGWoyNrPNKe3AN6/I2e+C3Z0iCXvw3HQeZwORRg+6vks1eLhCPTQsN49qoUiyQEAI49Sxxv+fbfA5dM+FijPA==} hasBin: true peerDependencies: expo: '>=49.0.0' @@ -3480,14 +3539,14 @@ packages: peerDependencies: react: ^19.2.5 - '@sentry/react@10.52.0': - resolution: {integrity: sha512-2m72QCsja2cJJHD0ALxRnVt0qMEC2FV4LSi6AAiEdEG4lTb6mgcxavx5pJrW90jE+6dMGPbUz4q8c9vi4jh1qQ==} + '@sentry/react@10.53.1': + resolution: {integrity: sha512-lrwNq5T/zW84l60894TpKHPcvFuc1I/Hnohecc0TfYVpIcYYuw2orCHoU4v4wgkFaJUpegVetbgdOphViyLVjA==} engines: {node: '>=18'} peerDependencies: react: ^19.2.5 - '@sentry/rollup-plugin@5.2.1': - resolution: {integrity: sha512-LKJyL4fzcHnHExipVN0/QinhBNoGZt+UXg8xJaqc6MwOolOhxHW0ii2hu1OZsiOhX0+r9MK7T+a7Sx0F0bzdMQ==} + '@sentry/rollup-plugin@5.3.0': + resolution: {integrity: sha512-hgPGPYdQJ/G1cGYOxAb7d4z3V+/k/E5/P/5TFPEEBLuIbFFk+JG0CISUDJdzXJjO382Lb99PBJuXGbueBmO79w==} engines: {node: '>= 18'} peerDependencies: rollup: '>=3.2.0' @@ -3499,8 +3558,8 @@ packages: resolution: {integrity: sha512-/0nTcXk82RKtGGv0mxmY56o+BE85lBuSWG9chtSEfeypvxHFyWn3D7td9rPmjboDMtytC24cYbUzx55jb2OjQA==} engines: {node: '>=18'} - '@sentry/vite-plugin@5.2.1': - resolution: {integrity: sha512-sSQzOhN8xvo/R70vqgyonnC/fwXpJ1kbkJ0g81Xy/OR+N89+v5tPN4VlKTAq3T2c5yAPE39XCbdgeEnI4kbWGg==} + '@sentry/vite-plugin@5.3.0': + resolution: {integrity: sha512-qcoSzo4n2MulVQ70UUPLq6dTleb2a2HwL2wuwvAgWhPChrYTuk6A6mDg6aQb9fairPAwFPiU9PzOANpoDJcz1A==} engines: {node: '>= 18'} '@simplewebauthn/browser@13.3.0': @@ -3662,33 +3721,33 @@ packages: resolution: {integrity: sha512-HqmEUIGRJ5fSXchkVgR5F7qn48bDBzv0kWj/Kfu5e6uci4UlEeng4331LnBkWffb++Ei3FOVLxo8JJWMFBDMeQ==} engines: {node: '>= 10'} - '@turbo/darwin-64@2.9.12': - resolution: {integrity: sha512-eu3eFRmE9NjgZ0wPdRJ44l+LGSeIky+tz5ZQd8zQkw/Yqi+BM7wq+8nbabeoiVUcICi/IZweMOKl/MCmkrd1+g==} + '@turbo/darwin-64@2.9.14': + resolution: {integrity: sha512-t7QiPflaEyBE4oayeZtSmu4mEfjgIrcNlNNl1z1dmIVPqEdtA7+CfTf8d7KXsOGPh6aNgWjKxyvQg9uGfDQF+A==} cpu: [x64] os: [darwin] - '@turbo/darwin-arm64@2.9.12': - resolution: {integrity: sha512-RUkAE404z/J8NsyrUosMcBaXT6M4bRFxTQrmkDQBLQVXaC8Jl0e9bMvYDSX0GW7Ffm2m3j9y7RXgR1foeUAM9w==} + '@turbo/darwin-arm64@2.9.14': + resolution: {integrity: sha512-d23147mC9BsCPA9mJ0h/ubcpbRgcJBXbcG3+Vq7YLhjz3IXuvQsJ1UXH8f4MD76ZjJ4m/E4aRdJV+MW88CDfbw==} cpu: [arm64] os: [darwin] - '@turbo/linux-64@2.9.12': - resolution: {integrity: sha512-InIUtH7cw/vqXNX1Gr7QgWfmw3ct08pV5CpfdEOR48z2u2rzdmpIuk00B/Q2xCb0PMWtKgiMQynfuphmEuUyTQ==} + '@turbo/linux-64@2.9.14': + resolution: {integrity: sha512-P3ZKB5tuUDdDQWuAsACGUR1qv9W7BNWxdxqVJ0kZNuNNPRaVYTPPikLcp79+GiEcW3npsR+KyP38lnQiBc5aSA==} cpu: [x64] os: [linux] - '@turbo/linux-arm64@2.9.12': - resolution: {integrity: sha512-lC6nD//Xh67fmJM0LKaLsg74Wry0aYrgMklpiNgCbUaMdPIOqj0A00iri3NU7Lb7pZHx8ViisgpeDKlpSgFUCA==} + '@turbo/linux-arm64@2.9.14': + resolution: {integrity: sha512-ZRTlzcUMrrPv9ZuDzRF9n60Ym13bKeG9jDB8WjxyLhWNzV+AJQN+zdpIk3NJYf2zQsGUm1mNar2P0elRzLw25g==} cpu: [arm64] os: [linux] - '@turbo/windows-64@2.9.12': - resolution: {integrity: sha512-conYri8VUl72JOdYnLDPYwzqbPcY5ECoHmo9FWoKznemhaAIilj4maHqs9Uar0aKfNoZIULniy+6iWaLtLO34A==} + '@turbo/windows-64@2.9.14': + resolution: {integrity: sha512-exanwN6sIduZwykYeiTQj8kCmOhazP5WOz3bvXMcYtjhL6Z3iRWLewKrXCBq0bqwSP3iBMb/AerRCnHI4lx46A==} cpu: [x64] os: [win32] - '@turbo/windows-arm64@2.9.12': - resolution: {integrity: sha512-XoR4bsg62/L/esRVcmoMESEiNZ36+YmyjYGLpoqk8nwMgXzzVjNOgX0lRSz5w/U/ajLGv3nhMsS0Q2QOdvp2AQ==} + '@turbo/windows-arm64@2.9.14': + resolution: {integrity: sha512-fVdCsnmYoKICsycbWuuGp6Jvi51/3G/UluFWuAUCvR8PIW5IJkAk5BM9UF8PSm0Q2IphWHFZjYEgjHsh3B9y/g==} cpu: [arm64] os: [win32] @@ -3827,12 +3886,15 @@ packages: '@types/mysql@2.15.27': resolution: {integrity: sha512-YfWiV16IY0OeBfBCk8+hXKmdTKrKlwKN1MNKAPBu5JYxLwBEZl7QzeEpGnlZb3VMGJrrGmB84gXiH+ofs/TezA==} - '@types/node@22.19.18': - resolution: {integrity: sha512-9v00a+dn2yWVsYDEunWC4g/TcRKVq3r8N5FuZp7u0SGrPvdN9c2yXI9bBuf5Fl0hNCb+QTIePTn5pJs2pwBOQQ==} + '@types/node@22.19.19': + resolution: {integrity: sha512-dyh/xO2Fh5bYrfWaaqGrRQQGkNdmYw6AmaAUvYeUMNTWQtvb796ikLdmTchRmOlOiIJ1TDXfWgVx1QkUlQ6Hew==} '@types/node@25.6.2': resolution: {integrity: sha512-sokuT28dxf9JT5Kady1fsXOvI4HVpjZa95NKT5y9PNTIrs2AsobR4GFAA90ZG8M+nxVRLysCXsVj6eGC7Vbrlw==} + '@types/node@25.8.0': + resolution: {integrity: sha512-TCFSk8IZh+iLX1xtksoBVtdmgL+1IX0fC9BeU4QqFSuNdN/K+HUlhqOzEmSYYpZUVsLYcPqc9KX+60iDuninSQ==} + '@types/nodemailer@8.0.0': resolution: {integrity: sha512-fyf8jWULsCo0d0BuoQ75i6IeoHs47qcqxWc7yUdUcV0pOZGjUTTOvwdG1PRXUDqN/8A64yQdQdnA2pZgcdi+cA==} @@ -3871,63 +3933,63 @@ packages: '@types/yargs@17.0.35': resolution: {integrity: sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==} - '@typescript-eslint/eslint-plugin@8.59.2': - resolution: {integrity: sha512-j/bwmkBvHUtPNxzuWe5z6BEk3q54YRyGlBXkSsmfoih7zNrBvl5A9A98anlp/7JbyZcWIJ8KXo/3Tq/DjFLtuQ==} + '@typescript-eslint/eslint-plugin@8.59.3': + resolution: {integrity: sha512-PwFvSKsXGShKGW6n5bZOhGHEcCZXM8HofLK9fNsEwZXzFRjoY+XT1Vsf1zgyXdwTr0ZYz1/2tkZ0DBTT9jZjhw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^8.59.2 + '@typescript-eslint/parser': ^8.59.3 eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/parser@8.59.2': - resolution: {integrity: sha512-plR3pp6D+SSUn1HM7xvSkx12/DhoHInI2YF35KAcVFNZvlC0gtrWqx7Qq1oH2Ssgi0vlFRCTbP+DZc7B9+TtsQ==} + '@typescript-eslint/parser@8.59.3': + resolution: {integrity: sha512-HPwA+hVkfcriajbNvTmZv4VRauibay+cWArYUYq7u7W7PmGShMxbPxLvrwDme55a6d5alG3nrYfhyJ/G28XlLg==} 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.59.2': - resolution: {integrity: sha512-+2hqvEkeyf/0FBor67duF0Ll7Ot8jyKzDQOSrxazF/danillRq2DwR9dLptsXpoZQqxE1UisSmoZewrlPas9Vw==} + '@typescript-eslint/project-service@8.59.3': + resolution: {integrity: sha512-ECiUWa/KYRGDFUqTNehaRgzDshnJfkTABJxVemHk4ko22gcr0ukloKjWvyQ64g8YCV/UI47kN1dbmjf/GaQYng==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/scope-manager@8.59.2': - resolution: {integrity: sha512-JzfyEpEtOU89CcFSwyNS3mu4MLvLSXqnmX05+aKBDM+TdR5jzcGOEBwxwGNxrEQ7p/z6kK2WyioCGBf2zZBnvg==} + '@typescript-eslint/scope-manager@8.59.3': + resolution: {integrity: sha512-t2LvZnoEfzKtnPjgeEu41xw5gxq9mQVfYy4OoZ4Vlt0sk3JwxmhCca/AR7DwOiHrjWgjAj6as4AhRLKSDfvZIA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/tsconfig-utils@8.59.2': - resolution: {integrity: sha512-BKK4alN7oi4C/zv4VqHQ+uRU+lTa6JGIZ7s1juw7b3RHo9OfKB+bKX3u0iVZetdsUCBBkSbdWbarJbmN0fTeSw==} + '@typescript-eslint/tsconfig-utils@8.59.3': + resolution: {integrity: sha512-PcIJHjmaREXLgIAIzLnSY9VucEzz8FKXsRgFa1DmdGCK/5tJpW03TKJF01Q6VZd1lLdz2sIKPWaDUZN9dp//dw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/type-utils@8.59.2': - resolution: {integrity: sha512-nhqaj1nmTdVVl/BP5omXNRGO38jn5iosis2vbdmupF2txCf8ylWT8lx+JlvMYYVqzGVKtjojUFoQ3JRWK+mfzQ==} + '@typescript-eslint/type-utils@8.59.3': + resolution: {integrity: sha512-g71d8QD8UaiHGvrJwyIS1hCX5r63w6Jll+4VEYhEAHXTDIqX1JgxhTAbEHtKntL9kuc4jRo7/GWw5xfCepSccQ==} 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.59.2': - resolution: {integrity: sha512-e82GVOE8Ps3E++Egvb6Y3Dw0S10u8NkQ9KXmtRhCWJJ8kDhOJTvtMAWnFL16kB1583goCWXsr0NieKCZMs2/0Q==} + '@typescript-eslint/types@8.59.3': + resolution: {integrity: sha512-ePFoH0g4ludssdRFqqDxQePCxU4WQyRa9+XVwjm7yLn0FKhMeoetC+qBEEI1Eyb1pGSDveTIT09Bvw2WhlGayg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@8.59.2': - resolution: {integrity: sha512-o0XPGNwcWw+FIwStOWn+BwBuEmL6QXP0rsvAFg7ET1dey1Nr6Wb1ac8p5HEsK0ygO/6mUxlk+YWQD9xcb/nnXg==} + '@typescript-eslint/typescript-estree@8.59.3': + resolution: {integrity: sha512-CbRjVRAf7Lr9Kr8RopKcbY45p2VfmmHrm0ygOCYFi7oU8q19m0Fs/6iHS7kNOmwpp+ob07ZVcAqlxUod9lYdmg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/utils@8.59.2': - resolution: {integrity: sha512-Juw3EinkXqjaffxz6roowvV7GZT/kET5vSKKZT6upl5TXdWkLkYmNPXwDDL2Vkt2DPn0nODIS4egC/0AGxKo/Q==} + '@typescript-eslint/utils@8.59.3': + resolution: {integrity: sha512-JAvT14goBzRzzzZyqq3P9BLArIxTtQURUtFgQ/V7FO+eU+Gg6ES+5ymOPP1wRxXcxAYeivCk4uS3jCKWI1K8Zg==} 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.59.2': - resolution: {integrity: sha512-NwjLUnGy8/Zfx23fl50tRC8rYaYnM52xNRYFAXvmiil9yh1+K6aRVQMnzW6gQB/1DLgWt977lYQn7C+wtgXZiA==} + '@typescript-eslint/visitor-keys@8.59.3': + resolution: {integrity: sha512-f1UQF7ggd42YiwI5wGrRaPsa+P0CINBlrkLPmGfpq/u/I/oVtecoEIfFR9ag/oa1sLOsRNZ6xehf6qMZhQGBDg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@ungap/structured-clone@1.3.1': @@ -3939,22 +4001,22 @@ packages: peerDependencies: vite: ^6.0.0 || ^7.0.0 || ^8.0.0 - '@vitest/browser-playwright@4.1.5': - resolution: {integrity: sha512-CWy0lBQJq97nionyJJdnaU4961IXTl43a7UCu5nHy51IoKxAt6PVIJLo+76rVl7KOOgcWHNkG4kbJu/pW7knvA==} + '@vitest/browser-playwright@4.1.6': + resolution: {integrity: sha512-4csoeyl/qwHyxU2zNL0++WaoDr8YJDXOQPwWPNJoTZ+QzcdO3INYKgF5Zfz730Io7zbkuv914aZmfQ+QE+1Hvw==} peerDependencies: playwright: '*' - vitest: 4.1.5 + vitest: 4.1.6 - '@vitest/browser@4.1.5': - resolution: {integrity: sha512-iCDGI8c4yg+xmjUg2VsygdAUSIIB4x5Rht/P68OXy1hPELKXHDkzh87lkuTcdYmemRChDkEpB426MmDjzC0ziA==} + '@vitest/browser@4.1.6': + resolution: {integrity: sha512-ynsspTubXGSpa58JFJ24xIQt4z4A25epSbugEyaTmmrV1//Wec9EgE/LtoaC6yxUrXi5P7erGHRrkdZIHaVQuA==} peerDependencies: - vitest: 4.1.5 + vitest: 4.1.6 - '@vitest/expect@4.1.5': - resolution: {integrity: sha512-PWBaRY5JoKuRnHlUHfpV/KohFylaDZTupcXN1H9vYryNLOnitSw60Mw9IAE2r67NbwwzBw/Cc/8q9BK3kIX8Kw==} + '@vitest/expect@4.1.6': + resolution: {integrity: sha512-7EHDquPthALSV0jhhjgEW8FXaviMx7rSqu8W6oqCoAuOhKov814P99QDV1pxMA3QPv21YudvJngIhjrNI4opLg==} - '@vitest/mocker@4.1.5': - resolution: {integrity: sha512-/x2EmFC4mT4NNzqvC3fmesuV97w5FC903KPmey4gsnJiMQ3Be1IlDKVaDaG8iqaLFHqJ2FVEkxZk5VmeLjIItw==} + '@vitest/mocker@4.1.6': + resolution: {integrity: sha512-MCFc63czMjEInOlcY2cpQCvCN+KgbAn+60xu9cMgP4sKaLC5JNAKw7JH8QdAnoAC88hW1IiSNZ+GgVXlN1UcMQ==} peerDependencies: msw: ^2.4.9 vite: ^6.0.0 || ^7.0.0 || ^8.0.0 @@ -3964,20 +4026,20 @@ packages: vite: optional: true - '@vitest/pretty-format@4.1.5': - resolution: {integrity: sha512-7I3q6l5qr03dVfMX2wCo9FxwSJbPdwKjy2uu/YPpU3wfHvIL4QHwVRp57OfGrDFeUJ8/8QdfBKIV12FTtLn00g==} + '@vitest/pretty-format@4.1.6': + resolution: {integrity: sha512-h5SxD/IzNhZYnrSZRsUZQIC+vD0GY8cUvq0iwsmkFKixRCKLLWqCXa/FIQ4S1R+sI+PGoojkHsdNrbZiM9Qpgw==} - '@vitest/runner@4.1.5': - resolution: {integrity: sha512-2D+o7Pr82IEO46YPpoA/YU0neeyr6FTerQb5Ro7BUnBuv6NQtT/kmVnczngiMEBhzgqz2UZYl5gArejsyERDSQ==} + '@vitest/runner@4.1.6': + resolution: {integrity: sha512-nOPCmn2+yD0ZNmKdsXGv/UxMMWbMuKeD6GyYncNwdkYDxpQvrPSKYj2rWuDjC2Y4b6w6hjip5dBKFzEUuZe3vA==} - '@vitest/snapshot@4.1.5': - resolution: {integrity: sha512-zypXEt4KH/XgKGPUz4eC2AvErYx0My5hfL8oDb1HzGFpEk1P62bxSohdyOmvz+d9UJwanI68MKwr2EquOaOgMQ==} + '@vitest/snapshot@4.1.6': + resolution: {integrity: sha512-YhsdE6xAVfTDmzjxL2ZDUvjj+ZsgyOKe+TdQzqkD72wIOmHka8NuGQ6NpTNZv9D2Z63fbwWKJPeVpEw4EQgYxw==} - '@vitest/spy@4.1.5': - resolution: {integrity: sha512-2lNOsh6+R2Idnf1TCZqSwYlKN2E/iDlD8sgU59kYVl+OMDmvldO1VDk39smRfpUNwYpNRVn3w4YfuC7KfbBnkQ==} + '@vitest/spy@4.1.6': + resolution: {integrity: sha512-JFKxMx6udhwKh/Ldo270e17QX710vgunMkuPAvXjHSvC6oqLWAHhVhjg/I71q0u0CBSErIODV1Kjv0FQNSWjdg==} - '@vitest/utils@4.1.5': - resolution: {integrity: sha512-76wdkrmfXfqGjueGgnb45ITPyUi1ycZ4IHgC2bhPDUfWHklY/q3MdLOAB+TF1e6xfl8NxNY0ZYaPCFNWSsw3Ug==} + '@vitest/utils@4.1.6': + resolution: {integrity: sha512-FxIY+U81R3LGKCxaHHFRQ5+g6/iRgGLmeHWdp2Amj4ljQRrEIWHmZyDfDYBRZlpyqA7qKxtS9DD1dhk8RnRIVQ==} '@xmldom/xmldom@0.8.13': resolution: {integrity: sha512-KRYzxepc14G/CEpEGc3Yn+JKaAeT63smlDr+vjB8jRfgTBBI9wRj/nkQEO+ucV8p8I9bfKLWp37uHgFrbntPvw==} @@ -4208,8 +4270,8 @@ packages: base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - baseline-browser-mapping@2.10.29: - resolution: {integrity: sha512-Asa2krT+XTPZINCS+2QcyS8WTkObE77RwkydwF7h6DmnKqbvlalz93m/dnphUyCa6SWSP51VgtEUf2FN+gelFQ==} + baseline-browser-mapping@2.10.30: + resolution: {integrity: sha512-xjOFN16Ha1+Rz4nFYKqHU/LSB+gx/Vi3yQLX7r7sAW+Wa+8hhF2h4pvqTrTMc8+WcDBEunnUurr46Jvv0jk3Vg==} engines: {node: '>=6.0.0'} hasBin: true @@ -4311,8 +4373,8 @@ packages: resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} engines: {node: '>=10'} - caniuse-lite@1.0.30001792: - resolution: {integrity: sha512-hVLMUZFgR4JJ6ACt1uEESvQN1/dBVqPAKY0hgrV70eN3391K6juAfTjKZLKvOMsx8PxA7gsY1/tLMMTcfFLLpw==} + caniuse-lite@1.0.30001793: + resolution: {integrity: sha512-iwSsYWaCOoh26cV8NwNRViHlrfUvYsHDfRVcbtmw0Kg6PJIZZXwMkj1442FYLBGkeUf1juAsU3DTfxW579mrPA==} canvas@3.2.3: resolution: {integrity: sha512-PzE5nJZPz72YUAfo8oTp0u3fqqY7IzlTubneAihqDYAUcBk7ryeCmBbdJBEdaH0bptSOe2VT2Zwcb3UaFyaSWw==} @@ -4783,8 +4845,8 @@ packages: ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} - electron-to-chromium@1.5.353: - resolution: {integrity: sha512-kOrWphBi8TOZyiJZqsgqIle0lw+tzmnQK83pV9dZUd01Nm2POECSyFQMAuarzZdYqQW7FH9RaYOuaRo3h+bQ3w==} + electron-to-chromium@1.5.357: + resolution: {integrity: sha512-NHlTIQDK8fmVwHwuIzmXYEJ1Ewq3D9wDNc0cWXxDGysP6Pb21giwGNkxiTifyKy/4SoPuN5l6GLP1W9Sv7zB2g==} emittery@0.13.1: resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==} @@ -4912,8 +4974,8 @@ packages: resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} - eslint@10.3.0: - resolution: {integrity: sha512-XbEXaRva5cF0ZQB8w6MluHA0kZZfV2DuCMJ3ozyEOHLwDpZX2Lmm/7Pp0xdJmI0GL1W05VH5VwIFHEm1Vcw2gw==} + eslint@10.4.0: + resolution: {integrity: sha512-loXy6bWOoP3EP6JA7jo6p5jMpBJmHmsNZM5SFRHLdh1MGOPurMnNBj4ZlAbaqUAaQWbCr7jHV4P7gzAyryZWkQ==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} hasBin: true peerDependencies: @@ -4982,8 +5044,8 @@ packages: resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - expo-application@55.0.14: - resolution: {integrity: sha512-NgqDIt3eCf4aVLp1L6AcEanCYoyJeuBsGrgGSzOIvxAsOvp5X3SYKW3ROgpKUnLQEKMWlzwETpjsUGszcqkk8g==} + expo-application@55.0.15: + resolution: {integrity: sha512-eWf5OGrat1r/TYr0daL684C6pJYiN2k30NmcISsD9fbtZLfA6Sbo/JebfYzP3OjO/T/i8j/9Pf3ePqUYPLfZnw==} peerDependencies: expo: '*' @@ -5000,18 +5062,18 @@ packages: expo: '*' react-native: '*' - expo-crypto@55.0.14: - resolution: {integrity: sha512-TfAADBGZNNv9OOmdKFJCz54wDj87ufxtzQNSY+Roycpm8e5tuCnDIL7EjqUOmNTGH99Jj8ftPGFt4KGG2Ii2fg==} + expo-crypto@55.0.15: + resolution: {integrity: sha512-nlxLguQyJM4MhDDERL30WZkq68/BujOcAp4QdGk+1pZmUmG1p2M8cF7GeFwYvWwjH0DVsIRtRh4ukeTvOZVTPg==} peerDependencies: expo: '*' - expo-dev-client@55.0.32: - resolution: {integrity: sha512-rfZ0Xpgbw3RPymkivvLSQ2Koqefj+oVOReqNLN3JXDlqdC2jOr3MCqfTaJs5VFNzFKk7pOPyE60jh03UdvsHCQ==} + expo-dev-client@55.0.34: + resolution: {integrity: sha512-IiQcIyzE/ixWtOa73XGf/7bsIN4DRnMvrmheCvCkqFIUv/mi+RLQt9D+xRRVbIwfnmjgDCjGxOLJVzFEcUbcIg==} peerDependencies: expo: '*' - expo-dev-launcher@55.0.33: - resolution: {integrity: sha512-WZsTtyEVgCBMj3vlgbDSKbYbUbAwijNhJY9jBqqlmbPLHtLE+Wc6nCTafb0dWY6+Si+afF98lvPyz6WSAu59uA==} + expo-dev-launcher@55.0.35: + resolution: {integrity: sha512-Cfdx4exreS9J7zLe9iE+ARItpse1ixjdXn+5W0ZdqCYdSrN+AabKtHmevXOYImBn+R1aXdA8UGkJ/W6OoCXjNQ==} peerDependencies: expo: '*' @@ -5020,18 +5082,18 @@ packages: peerDependencies: expo: '*' - expo-dev-menu@55.0.27: - resolution: {integrity: sha512-Il+kkIXlPDfZ/Z3ZquV1r5niECEByJObUMkB24c0B4N4693f0SDoKyyaRqcGRsRCVXW9r0eAoTeEnXl1revQdA==} + expo-dev-menu@55.0.29: + resolution: {integrity: sha512-dzKE+2Ag8nHhTgSetjDVR+u4UvgaCfRdQrl6tJyFbeYHJ2CZVxhRsMfH4ULQxF5ry/bJeSxZ9dbQWizGnXP9mg==} peerDependencies: expo: '*' - expo-device@55.0.16: - resolution: {integrity: sha512-o6eQjO2reoniXpos0FnPcrAVMYUfFPcIUdMRUUpKwQys7cmTJBjJLbOo+SuctVXUrsHUm6zyoKI7nX3C3lpqJw==} + expo-device@55.0.17: + resolution: {integrity: sha512-ZcMrSeD0zWooosm5Bet5qluxUrhw+NPgcMmN6ySVF7cm4K8Bvh4KPogJePbI1qfhFAiJWcWeV9e/2uewb9ktfw==} peerDependencies: expo: '*' - expo-file-system@55.0.19: - resolution: {integrity: sha512-c4smCbMqELLI3YQrGpw21MwZIREXM2e53vQD/+KWQcae1q+hgw8J2TroEqcQ/jVOtFpZYVvyVfgu4HDKNEKmNw==} + expo-file-system@55.0.20: + resolution: {integrity: sha512-sBCHhNlCT3EiqCcE6xSbyvOLUAlKx7+p0qjo+c+UPyC/gMrXUdva99g25uptM+fEMwy2co25MUQQ0U0guQLOQA==} peerDependencies: expo: '*' react-native: '*' @@ -5076,24 +5138,24 @@ packages: react: ^19.2.5 react-native: '*' - expo-localization@55.0.13: - resolution: {integrity: sha512-fXiEUUihIrXmAEzoneaTOFcQ7TKmr25RR/ymrB/MvYTVnmevFA1zY2KI0VSiXY+NKKjZ8mG65YSn1wh4gEYKxA==} + expo-localization@55.0.14: + resolution: {integrity: sha512-Q7VeW5gs0qMunYxIDB8+SpY/4T/h3CUE2kl6r6jnbYc6MPpmrK9bx/D9MeCfh0LmXW8oefy3MJYZQdPciEXU7Q==} peerDependencies: expo: '*' react: ^19.2.5 - expo-location@55.1.9: - resolution: {integrity: sha512-PIH9/qeyhtGh190FyIJNZYHXZOoi42SbVHY9IoTMBmqWLHf1BJyGhPpFlaLBSCjxObqfVZmrWsN5dtjueSwYQA==} + expo-location@55.1.10: + resolution: {integrity: sha512-MkcFucsZ567Bn8ChElVTYVbOs2QXn27IKaBrVKogw7ZcbooImdj3L/UR6E7s3LkgF33YubKynAp9Opvixdwl7g==} peerDependencies: expo: '*' - expo-manifests@55.0.16: - resolution: {integrity: sha512-BR9BPcNsSnCKlQ/d7ECywr+2T54+bTSr26HjRjSua949o4mO/iPIrLjK0lOAa1oIczju6a6oUFckZD2OljxP0g==} + expo-manifests@55.0.17: + resolution: {integrity: sha512-vKZvFivX3usVJKfBODKQcFHso0g38zlGbRGqGAppz+il0zKvG6umpJ47OZbzLod7iJpjd+ZDD2AGuOxacixonA==} peerDependencies: expo: '*' - expo-modules-autolinking@55.0.21: - resolution: {integrity: sha512-P9KsJgOwI7JVwxmGfRvcXkXO4LNRvHRdWmb4ukLmX15G/vZ7b6SM17yiYkPceWq1F5KeeZ11KFjEcl0y17xy7w==} + expo-modules-autolinking@55.0.22: + resolution: {integrity: sha512-13x32V0HMHJDjND4K/gU2lQIZNxYn5S5rFzujqHmnXvOO6WGrVVELpk/0p5FmBfeuQ7GGFsATbhazQk+FeukUw==} hasBin: true expo-modules-core@55.0.25: @@ -5106,15 +5168,15 @@ packages: react-native-worklets: optional: true - expo-navigation-bar@55.0.12: - resolution: {integrity: sha512-G7olnyAqGd7I3hLFAgP4WdcZFMD9pV6UY79P7EHyRdMuRZrYJfDdwcelyYB2+tekOdQEktZ3WlLVK+uS7f7TYw==} + expo-navigation-bar@55.0.13: + resolution: {integrity: sha512-etU3o7+IqyX5tp+X6+UT5OqrQXIWpSiomv8rZmHTIAL8+AviKFELAgw1TaOddrRNfw849nM6UqGWAZnoIQxhMQ==} peerDependencies: expo: '*' react: ^19.2.5 react-native: '*' - expo-notifications@55.0.22: - resolution: {integrity: sha512-Rwvsp/lAEXfDYBxkQZpaLF9ZB25cJ/yfHhD/ESclbPesN0nbQBZ/5rGb1xS/saANtkStbEGfDlA80uHh2zEpsA==} + expo-notifications@55.0.23: + resolution: {integrity: sha512-oWEsBZSedRFu+ErcJaIev7QQhCE/gTRO6KURAkFpMflMgI3yjT4O/qixXh4tHmEk5zfoOpR2u79AzvVcchfwww==} peerDependencies: expo: '*' react: ^19.2.5 @@ -5155,8 +5217,8 @@ packages: react-server-dom-webpack: optional: true - expo-secure-store@55.0.13: - resolution: {integrity: sha512-I6r0JNO1Fd4o0Gu7Ixiic7s89lqgdUHq17uBH9y1f/AntoyKn71TdtYJH82RgfsBbu5qNVzrwImmvlANyOlITQ==} + expo-secure-store@55.0.14: + resolution: {integrity: sha512-OKp9pDiTa4kgChop8+pTRJGBPhkJUcAxP5c6JbivNr4bmx3I+gKmAj1ov4KOXkY95TpWdHO+GQ4+0BgSY2P3JQ==} peerDependencies: expo: '*' @@ -5164,13 +5226,13 @@ packages: resolution: {integrity: sha512-N5Ipn1NwqaJzEm+G97o0Jbe4g/th3R/16N1DabnYryXKCiZwDkK13/w3VfGkQN9LOOaBP+JIRxGf4M8lQKPzyA==} engines: {node: '>=20.16.0'} - expo-splash-screen@55.0.20: - resolution: {integrity: sha512-WI5T0dutiZhxsqlF+jhEP4JRpQNILLlP8IpmKehsnV53Cncv6AQrKE7y1sOWwDyC2m2GBufZ/Vwam1RMt2EfmA==} + expo-splash-screen@55.0.21: + resolution: {integrity: sha512-hFGEap69ggCckbHIdDXMe5rqfBR9TwcnY5gBhyaACUxU64w827T6prOQcIvLmAdv00kp3Gqt7hgE+mNn37EF+A==} peerDependencies: expo: '*' - expo-sqlite@55.0.15: - resolution: {integrity: sha512-vxE5fs6l953QSIyievQ8TuSstj62eC7zUREjNzbUOwRWaHGGnhnlPJM1HLoTIv+oIt3+b1m7k2fmcDGkpK5t3w==} + expo-sqlite@55.0.16: + resolution: {integrity: sha512-v6EIL4ygqWt/+ZfI76jIIv+IIaU8PnWPNjkmIN95vEQgh0FrWqzwssqe5ffQmm79kIfqIPTtAgTdl8MuZv88gg==} peerDependencies: expo: '*' react: ^19.2.5 @@ -5190,8 +5252,8 @@ packages: react: ^19.2.5 react-native: '*' - expo-system-ui@55.0.17: - resolution: {integrity: sha512-sCrQbp1VyMe63c7y7/luz88P9Ro3/jeUBXby2uYk0wHtkawUzBK9V69J3HTC4rI5eXiJMJPF2oCKO71c/7wtTg==} + expo-system-ui@55.0.18: + resolution: {integrity: sha512-Fbc0HJgqMpABeA/gI7NJFnSXwUeLrEMjjXq8Nl+4gTXyacIK2iOOrzCkvq41rKBBde0CR6kVnB1DXj0j9ZYnjg==} peerDependencies: expo: '*' react-native: '*' @@ -5205,14 +5267,14 @@ packages: peerDependencies: expo: '*' - expo-web-browser@55.0.15: - resolution: {integrity: sha512-6hwZQob3EF+RWwZ+IvWLZjj2wI1frqx21+m/uzBqdUEHUhp2cVJi7kmxDolDmrve+ZldryZi1qfN78ALdvjHSA==} + expo-web-browser@55.0.16: + resolution: {integrity: sha512-eeGs3439ewO/Q56Pzg3qbAVZSE0oH/R7XW9VCXI59k0m78ZIYbBtPT4PMFL/+sBgRkXm546Lq/DFcJQPTOfXJg==} peerDependencies: expo: '*' react-native: '*' - expo@55.0.23: - resolution: {integrity: sha512-b+lKwfzJzFiSm9G0wVGWw3c2YoZyubbl9gHOF1ZFuK8FqtxSge8pDDJMuEFmTi14dbKwh/tirB7MiORq54r7CQ==} + expo@55.0.24: + resolution: {integrity: sha512-nU95y+GIfD1dm9CSjsitDdltSU83dDqemxD1UUBxJPH8zKf7B5AdGVNyE6/jLWyCM/p/EmHfCeiqdrWCy9ljZA==} hasBin: true peerDependencies: '@expo/dom-webview': '*' @@ -5231,8 +5293,8 @@ packages: exponential-backoff@3.1.3: resolution: {integrity: sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==} - express@4.22.1: - resolution: {integrity: sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==} + express@4.22.2: + resolution: {integrity: sha512-IuL+Elrou2ZvCFHs18/CIzy2Nzvo25nZ1/D2eIZlz7c+QUayAcYoiM2BthCjs+EBHVpjYjcuLDAiCWgeIX3X1Q==} engines: {node: '>= 0.10.0'} exsolve@1.0.8: @@ -5535,6 +5597,14 @@ packages: typescript: optional: true + i18next@26.2.0: + resolution: {integrity: sha512-zwBHldHdTmwN7r6UNc7lC6GWNN+YYg3DrRSeHR5PRRBf5QnJZcYHrQc0uaU26qZeYxR7iFZD+Y315dPnKP47wA==} + peerDependencies: + typescript: ^5 || ^6 + peerDependenciesMeta: + typescript: + optional: true + iconv-lite@0.4.24: resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} engines: {node: '>=0.10.0'} @@ -6396,8 +6466,8 @@ packages: node-int64@0.4.0: resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} - node-releases@2.0.38: - resolution: {integrity: sha512-3qT/88Y3FbH/Kx4szpQQ4HzUbVrHPKTLVpVocKiLfoYvw9XSGOX2FmD2d6DrXbVYyAQTF2HeF6My8jmzx7/CRw==} + node-releases@2.0.44: + resolution: {integrity: sha512-5WUyunoPMsvvEhS8AxHtRzP+oA8UCkJ7YRxatWKjngndhDGLiqEVAQKWjFAiAiuL8zMRGzGSJxFnLetoa43qGQ==} nodemailer@8.0.7: resolution: {integrity: sha512-pkjE4mkBzQjdJT4/UmlKl3pX0rC9fZmjh7c6C9o7lv66Ac6w9WCnzPzhbPNxwZAzlF4mdq4CSWB5+FbK6FWCow==} @@ -6639,13 +6709,13 @@ packages: pkg-types@2.3.1: resolution: {integrity: sha512-y+ichcgc2LrADuhLNAx8DFjVfgz91pRxfZdI3UDhxHvcVEZsenLO+7XaU5vOp0u/7V/wZ+plyuQxtrDlZJ+yeg==} - playwright-core@1.59.1: - resolution: {integrity: sha512-HBV/RJg81z5BiiZ9yPzIiClYV/QMsDCKUyogwH9p3MCP6IYjUFu/MActgYAvK0oWyV9NlwM3GLBjADyWgydVyg==} + playwright-core@1.60.0: + resolution: {integrity: sha512-9bW6zvX/m0lEbgTKJ6YppOKx8H3VOPBMOCFh2irXFOT4BbHgrx5hPjwJYLT40Lu+4qtD36qKc/Hn56StUW57IA==} engines: {node: '>=18'} hasBin: true - playwright@1.59.1: - resolution: {integrity: sha512-C8oWjPR3F81yljW9o5OxcWzfh6avkVwDD2VYdwIGqTkl+OGFISgypqzfu7dOe4QNLL2aqcWBmI3PMtLIK233lw==} + playwright@1.60.0: + resolution: {integrity: sha512-hheHdokM8cdqCb0lcE3s+zT4t4W+vvjpGxsZlDnikarzx8tSzMebh3UiFtgqwFwnTnjYQcsyMF8ei2mCO/tpeA==} engines: {node: '>=18'} hasBin: true @@ -6780,12 +6850,8 @@ packages: resolution: {integrity: sha512-KTqnxsgGiQ6ZAzZCVlJH5eOjSnvlyEgx1m8bkRJfOhmGRqfo5KLvmAlACQkrjEtOQ4B7wF9TdSLIs9O90MX9xA==} engines: {node: '>=16.0.0'} - qs@6.14.2: - resolution: {integrity: sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==} - engines: {node: '>=0.6'} - - qs@6.15.1: - resolution: {integrity: sha512-6YHEFRL9mfgcAvql/XhwTvf5jKcOiiupt2FiJxHkiX1z4j7WL8J/jRHYLluORvc1XxB5rV20KoeK00gVJamspg==} + qs@6.15.2: + resolution: {integrity: sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw==} engines: {node: '>=0.6'} query-string@7.1.3: @@ -6858,6 +6924,22 @@ packages: typescript: optional: true + react-i18next@17.0.8: + resolution: {integrity: sha512-0ooKbGLU8JXhe1zwpQUWIeXSgLPOfwJmgheWRIUpcoA0CpyabpGhayjdG+/eA5esC1AQ8h2jWpXjJfzQzeDOCw==} + peerDependencies: + i18next: '>= 26.2.0' + react: ^19.2.5 + react-dom: '*' + react-native: '*' + typescript: ^5 || ^6 + peerDependenciesMeta: + react-dom: + optional: true + react-native: + optional: true + typescript: + optional: true + react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} @@ -6902,11 +6984,11 @@ packages: react: ^19.2.5 react-native: '*' - react-native-screens@4.24.0: - resolution: {integrity: sha512-SyoiGaDofiyGPFrUkn1oGsAzkRuX1JUvTD9YQQK3G1JGQ5VWkvHgYSsc1K9OrLsDQxN7NmV71O0sHCAh8cBetA==} + react-native-screens@4.25.0: + resolution: {integrity: sha512-CoE6W0perui0W4WK9fZFJfikUql/AYQFSJjnOGoXcPeteFb5Tursfmkot3vPOSu9lKWQMO6tlCIBQTC1CgbVRw==} peerDependencies: react: ^19.2.5 - react-native: '*' + react-native: '>=0.82.0' react-native-worklets@0.8.1: resolution: {integrity: sha512-oWP/lStsAHU6oYCaWDXrda/wOHVdhusQJz1e6x9gPnXdFf4ndNDAOtWCmk2zGrAnlapfyA3rM6PCQq94mPg9cw==} @@ -6951,8 +7033,8 @@ packages: '@types/react': optional: true - react-router@7.15.0: - resolution: {integrity: sha512-HW9vYwuM8f4yx66Izy8xfrzCM+SBJluoZcCbww9A1TySax11S5Vgw6fi3ZjMONw9J4gQwngL7PzkyIpJJpJ7RQ==} + react-router@7.15.1: + resolution: {integrity: sha512-R8rl9HhgikFYoPJymnUtPXWbnDb3oget6lQnfIoupbt61aT9aOhRkDsY2XRhZRyX1Z/8a5sL74fXmFNm3NRK5A==} engines: {node: '>=20.0.0'} peerDependencies: react: ^19.2.5 @@ -7088,8 +7170,8 @@ packages: engines: {node: ^20.19.0 || >=22.12.0} hasBin: true - rollup@4.60.3: - resolution: {integrity: sha512-pAQK9HalE84QSm4Po3EmWIZPd3FnjkShVkiMlz1iligWYkWQ7wHYd1PF/T7QZ5TVSD6uSTon5gBVMSM4JfBV+A==} + rollup@4.60.4: + resolution: {integrity: sha512-WHeFSbZYsPu3+bLoNRUuAO+wavNlocOPf3wSHTP7hcFKVnJeWsYlCDbr3mTS14FCizf9ccIxXA8sGL8zKeQN3g==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -7099,9 +7181,6 @@ packages: run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} - rw@1.3.3: - resolution: {integrity: sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==} - safe-buffer@5.1.2: resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} @@ -7460,8 +7539,8 @@ packages: tinybench@2.9.0: resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} - tinyexec@1.1.1: - resolution: {integrity: sha512-VKS/ZaQhhkKFMANmAOhhXVoIfBXblQxGX1myCQ2faQrfmobMftXeJPcZGp0gS07ocvGJWDLZGyOZDadDBqYIJg==} + tinyexec@1.1.2: + resolution: {integrity: sha512-dAqSqE/RabpBKI8+h26GfLq6Vb3JVXs30XYQjdMjaj/c2tS8IYYMbIzP599KtRj7c57/wYApb3QjgRgXmrCukA==} engines: {node: '>=18'} tinyglobby@0.2.16: @@ -7546,8 +7625,8 @@ packages: tunnel-agent@0.6.0: resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} - turbo@2.9.12: - resolution: {integrity: sha512-lCPgus1NuTiBdaITWqzSH/Ff6HVL8HHGBtOXHg1dHRfcshN79XkygSdh0M6g8b0td91ILLG5MTkLOkp5UvyPJw==} + turbo@2.9.14: + resolution: {integrity: sha512-BQqXRr4UoWI3UPFrtznCLykYHxwxWh53iCB57x092jPMjIlW1wnm3N895g5irpiXmnxUhREBB0n6+y8BHhs4nw==} hasBin: true type-check@0.4.0: @@ -7574,8 +7653,8 @@ packages: resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} engines: {node: '>= 0.6'} - typescript-eslint@8.59.2: - resolution: {integrity: sha512-pJw051uomb3ZeCzGTpRb8RbEqB5Y4WWet8gl/GcTlU35BSx0PVdZ86/bqkQCyKKuraVQEK7r6kBHQXF+fBhkoQ==} + typescript-eslint@8.59.3: + resolution: {integrity: sha512-KgusgyDgG4LI8Ih/sWaCtZ06tckLAS5CvT5A4D1Q7bYVoAAyzwiZvE4BmwDHkhRVkvhRBepKeASoFzQetha7Fg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 @@ -7599,6 +7678,9 @@ packages: undici-types@7.19.2: resolution: {integrity: sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==} + undici-types@7.24.6: + resolution: {integrity: sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==} + undici@6.25.0: resolution: {integrity: sha512-ZgpWDC5gmNiuY9CnLVXEH8rl50xhRCuLNA97fAUnKi8RRuV4E6KG31pDTsLVUKnohJE0I3XDrTeEydAXRw47xg==} engines: {node: '>=18.17'} @@ -7658,8 +7740,8 @@ packages: peerDependencies: react: ^19.2.5 - use-latest-callback@0.3.3: - resolution: {integrity: sha512-G9A/EL7okx4wzBfATt8bdGg0v1K0Gp0IClTzljffM63gtPisgDKCaLCLUb4g2M4CoXDg5yyHjOU+g3SUPbXwrA==} + use-latest-callback@0.3.4: + resolution: {integrity: sha512-IcR5xK/dJFzUUsAKBqr/mZw4dGPftRdVvx5+cNsLzDlf7V1GPNfnRTjiuTxSsfPtUJGW/KNrScl7xwQoOsvhkg==} peerDependencies: react: ^19.2.5 @@ -7804,20 +7886,20 @@ packages: yaml: optional: true - vitest@4.1.5: - resolution: {integrity: sha512-9Xx1v3/ih3m9hN+SbfkUyy0JAs72ap3r7joc87XL6jwF0jGg6mFBvQ1SrwaX+h8BlkX6Hz9shdd1uo6AF+ZGpg==} + vitest@4.1.6: + resolution: {integrity: sha512-6lvjbS3p9b4CrdCmguzbh2/4uoXhGE2q71R4OX5sqF9R1bo9Xd6fGrMAfvp5wnCzlBnFVdCOp6onuTQVbo8iUQ==} engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} hasBin: true peerDependencies: '@edge-runtime/vm': '*' '@opentelemetry/api': ^1.9.0 '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 - '@vitest/browser-playwright': 4.1.5 - '@vitest/browser-preview': 4.1.5 - '@vitest/browser-webdriverio': 4.1.5 - '@vitest/coverage-istanbul': 4.1.5 - '@vitest/coverage-v8': 4.1.5 - '@vitest/ui': 4.1.5 + '@vitest/browser-playwright': 4.1.6 + '@vitest/browser-preview': 4.1.6 + '@vitest/browser-webdriverio': 4.1.6 + '@vitest/coverage-istanbul': 4.1.6 + '@vitest/coverage-v8': 4.1.6 + '@vitest/ui': 4.1.6 happy-dom: '*' jsdom: '*' vite: ^6.0.0 || ^7.0.0 || ^8.0.0 @@ -7957,8 +8039,8 @@ packages: utf-8-validate: optional: true - ws@8.20.0: - resolution: {integrity: sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==} + ws@8.20.1: + resolution: {integrity: sha512-It4dO0K5v//JtTXuPkfEOaI3uUN87iYPnqo/ZzqCoG3g8uhA66QUMs/SrM0YK7/NAu+r4LMh/9dq2A7k+rHs+w==} engines: {node: '>=10.0.0'} peerDependencies: bufferutil: ^4.0.1 @@ -8031,6 +8113,11 @@ packages: engines: {node: '>= 14.6'} hasBin: true + yaml@2.9.0: + resolution: {integrity: sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==} + engines: {node: '>= 14.6'} + hasBin: true + yargs-parser@21.1.1: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} @@ -8692,20 +8779,20 @@ snapshots: dependencies: '@codemirror/language': 6.12.3 '@codemirror/state': 6.6.0 - '@codemirror/view': 6.42.1 + '@codemirror/view': 6.43.0 '@lezer/common': 1.5.2 '@codemirror/commands@6.10.3': dependencies: '@codemirror/language': 6.12.3 '@codemirror/state': 6.6.0 - '@codemirror/view': 6.42.1 + '@codemirror/view': 6.43.0 '@lezer/common': 1.5.2 '@codemirror/language@6.12.3': dependencies: '@codemirror/state': 6.6.0 - '@codemirror/view': 6.42.1 + '@codemirror/view': 6.43.0 '@lezer/common': 1.5.2 '@lezer/highlight': 1.2.3 '@lezer/lr': 1.4.8 @@ -8714,20 +8801,20 @@ snapshots: '@codemirror/lint@6.9.5': dependencies: '@codemirror/state': 6.6.0 - '@codemirror/view': 6.42.1 + '@codemirror/view': 6.43.0 crelt: 1.0.6 '@codemirror/search@6.6.0': dependencies: '@codemirror/state': 6.6.0 - '@codemirror/view': 6.42.1 + '@codemirror/view': 6.43.0 crelt: 1.0.6 '@codemirror/state@6.6.0': dependencies: '@marijn/find-cluster-break': 1.0.2 - '@codemirror/view@6.42.1': + '@codemirror/view@6.43.0': dependencies: '@codemirror/state': 6.6.0 crelt: 1.0.6 @@ -9012,9 +9099,9 @@ snapshots: '@esbuild/win32-x64@0.27.7': optional: true - '@eslint-community/eslint-utils@4.9.1(eslint@10.3.0(jiti@2.7.0))': + '@eslint-community/eslint-utils@4.9.1(eslint@10.4.0(jiti@2.7.0))': dependencies: - eslint: 10.3.0(jiti@2.7.0) + eslint: 10.4.0(jiti@2.7.0) eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.2': {} @@ -9027,7 +9114,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@eslint/config-helpers@0.5.5': + '@eslint/config-helpers@0.6.0': dependencies: '@eslint/core': 1.2.1 @@ -9035,9 +9122,9 @@ snapshots: dependencies: '@types/json-schema': 7.0.15 - '@eslint/js@10.0.1(eslint@10.3.0(jiti@2.7.0))': + '@eslint/js@10.0.1(eslint@10.4.0(jiti@2.7.0))': optionalDependencies: - eslint: 10.3.0(jiti@2.7.0) + eslint: 10.4.0(jiti@2.7.0) '@eslint/object-schema@3.0.5': {} @@ -9050,24 +9137,24 @@ snapshots: '@expo-google-fonts/material-symbols@0.4.36': {} - '@expo/cli@55.0.29(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-constants@55.0.16)(expo-font@55.0.7)(expo-router@55.0.14)(expo@55.0.23)(react-dom@19.2.6(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3)': + '@expo/cli@55.0.30(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-constants@55.0.16)(expo-font@55.0.7)(expo-router@55.0.14)(expo@55.0.24)(react-dom@19.2.6(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3)': dependencies: '@expo/code-signing-certificates': 0.0.6 - '@expo/config': 55.0.16(typescript@5.9.3) - '@expo/config-plugins': 55.0.8 + '@expo/config': 55.0.17(typescript@5.9.3) + '@expo/config-plugins': 55.0.9 '@expo/devcert': 1.2.1 '@expo/env': 2.1.2 '@expo/image-utils': 0.8.14(typescript@5.9.3) '@expo/json-file': 10.0.14 - '@expo/log-box': 55.0.12(@expo/dom-webview@55.0.5)(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) + '@expo/log-box': 55.0.12(@expo/dom-webview@55.0.5)(expo@55.0.24)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) '@expo/metro': 55.1.1 - '@expo/metro-config': 55.0.20(expo@55.0.23)(typescript@5.9.3) + '@expo/metro-config': 55.0.21(expo@55.0.24)(typescript@5.9.3) '@expo/osascript': 2.4.3 '@expo/package-manager': 1.10.5 '@expo/plist': 0.5.3 - '@expo/prebuild-config': 55.0.17(expo@55.0.23)(typescript@5.9.3) + '@expo/prebuild-config': 55.0.18(expo@55.0.24)(typescript@5.9.3) '@expo/require-utils': 55.0.5(typescript@5.9.3) - '@expo/router-server': 55.0.16(@expo/metro-runtime@55.0.11)(expo-constants@55.0.16)(expo-font@55.0.7)(expo-router@55.0.14)(expo-server@55.0.9)(expo@55.0.23)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@expo/router-server': 55.0.16(@expo/metro-runtime@55.0.11)(expo-constants@55.0.16)(expo-font@55.0.7)(expo-router@55.0.14)(expo-server@55.0.9)(expo@55.0.24)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) '@expo/schema-utils': 55.0.4 '@expo/spawn-async': 1.7.2 '@expo/ws-tunnel': 1.0.6 @@ -9084,7 +9171,7 @@ snapshots: connect: 3.7.0 debug: 4.4.3 dnssd-advertise: 1.1.4 - expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) + expo: 55.0.24(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) expo-server: 55.0.9 fetch-nodeshim: 0.4.10 getenv: 2.0.0 @@ -9108,10 +9195,10 @@ snapshots: terminal-link: 2.1.1 toqr: 0.1.1 wrap-ansi: 7.0.0 - ws: 8.20.0 + ws: 8.20.1 zod: 3.25.76 optionalDependencies: - expo-router: 55.0.14(82db8260abd9fbac2a02011543a979fa) + expo-router: 55.0.14(4a88f676dfb25e563c95d7c5569dae4c) react-native: 0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6) transitivePeerDependencies: - '@expo/dom-webview' @@ -9130,7 +9217,7 @@ snapshots: dependencies: node-forge: 1.4.0 - '@expo/config-plugins@55.0.8': + '@expo/config-plugins@55.0.9': dependencies: '@expo/config-types': 55.0.5 '@expo/json-file': 10.0.14 @@ -9152,7 +9239,23 @@ snapshots: '@expo/config@55.0.16(typescript@5.9.3)': dependencies: - '@expo/config-plugins': 55.0.8 + '@expo/config-plugins': 55.0.9 + '@expo/config-types': 55.0.5 + '@expo/json-file': 10.0.14 + '@expo/require-utils': 55.0.5(typescript@5.9.3) + deepmerge: 4.3.1 + getenv: 2.0.0 + glob: 13.0.6 + resolve-workspace-root: 2.0.1 + semver: 7.8.0 + slugify: 1.6.9 + transitivePeerDependencies: + - supports-color + - typescript + + '@expo/config@55.0.17(typescript@5.9.3)': + dependencies: + '@expo/config-plugins': 55.0.9 '@expo/config-types': 55.0.5 '@expo/json-file': 10.0.14 '@expo/require-utils': 55.0.5(typescript@5.9.3) @@ -9180,9 +9283,9 @@ snapshots: react: 19.2.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.6) - '@expo/dom-webview@55.0.5(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)': + '@expo/dom-webview@55.0.5(expo@55.0.24)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)': dependencies: - expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) + expo: 55.0.24(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) react: 19.2.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.6) @@ -9228,29 +9331,29 @@ snapshots: '@babel/code-frame': 7.29.0 json5: 2.2.3 - '@expo/local-build-cache-provider@55.0.12(typescript@5.9.3)': + '@expo/local-build-cache-provider@55.0.13(typescript@5.9.3)': dependencies: - '@expo/config': 55.0.16(typescript@5.9.3) + '@expo/config': 55.0.17(typescript@5.9.3) chalk: 4.1.2 transitivePeerDependencies: - supports-color - typescript - '@expo/log-box@55.0.12(@expo/dom-webview@55.0.5)(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)': + '@expo/log-box@55.0.12(@expo/dom-webview@55.0.5)(expo@55.0.24)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)': dependencies: - '@expo/dom-webview': 55.0.5(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) + '@expo/dom-webview': 55.0.5(expo@55.0.24)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) anser: 1.4.10 - expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) + expo: 55.0.24(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) react: 19.2.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.6) stacktrace-parser: 0.1.11 - '@expo/metro-config@55.0.20(expo@55.0.23)(typescript@5.9.3)': + '@expo/metro-config@55.0.21(expo@55.0.24)(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.16(typescript@5.9.3) + '@expo/config': 55.0.17(typescript@5.9.3) '@expo/env': 2.1.2 '@expo/json-file': 10.0.14 '@expo/metro': 55.1.1 @@ -9267,18 +9370,18 @@ snapshots: postcss: 8.4.49 resolve-from: 5.0.0 optionalDependencies: - expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) + expo: 55.0.24(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) transitivePeerDependencies: - bufferutil - supports-color - typescript - utf-8-validate - '@expo/metro-runtime@55.0.11(@expo/dom-webview@55.0.5)(expo@55.0.23)(react-dom@19.2.6(react@19.2.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.6))(react@19.2.6)': + '@expo/metro-runtime@55.0.11(@expo/dom-webview@55.0.5)(expo@55.0.24)(react-dom@19.2.6(react@19.2.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.6))(react@19.2.6)': dependencies: - '@expo/log-box': 55.0.12(@expo/dom-webview@55.0.5)(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) + '@expo/log-box': 55.0.12(@expo/dom-webview@55.0.5)(expo@55.0.24)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) anser: 1.4.10 - expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) + expo: 55.0.24(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) pretty-format: 29.7.0 react: 19.2.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.6) @@ -9329,16 +9432,16 @@ snapshots: base64-js: 1.5.1 xmlbuilder: 15.1.1 - '@expo/prebuild-config@55.0.17(expo@55.0.23)(typescript@5.9.3)': + '@expo/prebuild-config@55.0.18(expo@55.0.24)(typescript@5.9.3)': dependencies: - '@expo/config': 55.0.16(typescript@5.9.3) - '@expo/config-plugins': 55.0.8 + '@expo/config': 55.0.17(typescript@5.9.3) + '@expo/config-plugins': 55.0.9 '@expo/config-types': 55.0.5 '@expo/image-utils': 0.8.14(typescript@5.9.3) '@expo/json-file': 10.0.14 '@react-native/normalize-colors': 0.83.6 debug: 4.4.3 - expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) + expo: 55.0.24(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) resolve-from: 5.0.0 semver: 7.8.0 xml2js: 0.6.0 @@ -9356,17 +9459,17 @@ snapshots: transitivePeerDependencies: - supports-color - '@expo/router-server@55.0.16(@expo/metro-runtime@55.0.11)(expo-constants@55.0.16)(expo-font@55.0.7)(expo-router@55.0.14)(expo-server@55.0.9)(expo@55.0.23)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@expo/router-server@55.0.16(@expo/metro-runtime@55.0.11)(expo-constants@55.0.16)(expo-font@55.0.7)(expo-router@55.0.14)(expo-server@55.0.9)(expo@55.0.24)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: debug: 4.4.3 - expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) - expo-constants: 55.0.16(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6)) - expo-font: 55.0.7(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) + expo: 55.0.24(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) + expo-constants: 55.0.16(expo@55.0.24)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6)) + expo-font: 55.0.7(expo@55.0.24)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) expo-server: 55.0.9 react: 19.2.6 optionalDependencies: - '@expo/metro-runtime': 55.0.11(@expo/dom-webview@55.0.5)(expo@55.0.23)(react-dom@19.2.6(react@19.2.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.6))(react@19.2.6) - expo-router: 55.0.14(82db8260abd9fbac2a02011543a979fa) + '@expo/metro-runtime': 55.0.11(@expo/dom-webview@55.0.5)(expo@55.0.24)(react-dom@19.2.6(react@19.2.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.6))(react@19.2.6) + expo-router: 55.0.14(4a88f676dfb25e563c95d7c5569dae4c) react-dom: 19.2.6(react@19.2.6) transitivePeerDependencies: - supports-color @@ -9383,7 +9486,7 @@ snapshots: '@expo/vector-icons@15.1.1(expo-font@55.0.7)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)': dependencies: - expo-font: 55.0.7(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) + expo-font: 55.0.7(expo@55.0.24)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) react: 19.2.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.6) @@ -9405,10 +9508,10 @@ snapshots: transitivePeerDependencies: - supports-color - '@fission-ai/openspec@1.3.1(@types/node@25.6.2)': + '@fission-ai/openspec@1.3.1(@types/node@25.8.0)': dependencies: - '@inquirer/core': 10.3.2(@types/node@25.6.2) - '@inquirer/prompts': 7.10.1(@types/node@25.6.2) + '@inquirer/core': 10.3.2(@types/node@25.8.0) + '@inquirer/prompts': 7.10.1(@types/node@25.8.0) chalk: 5.6.2 commander: 14.0.3 fast-glob: 3.3.3 @@ -9469,128 +9572,128 @@ snapshots: '@inquirer/ansi@1.0.2': {} - '@inquirer/checkbox@4.3.2(@types/node@25.6.2)': + '@inquirer/checkbox@4.3.2(@types/node@25.8.0)': dependencies: '@inquirer/ansi': 1.0.2 - '@inquirer/core': 10.3.2(@types/node@25.6.2) + '@inquirer/core': 10.3.2(@types/node@25.8.0) '@inquirer/figures': 1.0.15 - '@inquirer/type': 3.0.10(@types/node@25.6.2) + '@inquirer/type': 3.0.10(@types/node@25.8.0) yoctocolors-cjs: 2.1.3 optionalDependencies: - '@types/node': 25.6.2 + '@types/node': 25.8.0 - '@inquirer/confirm@5.1.21(@types/node@25.6.2)': + '@inquirer/confirm@5.1.21(@types/node@25.8.0)': dependencies: - '@inquirer/core': 10.3.2(@types/node@25.6.2) - '@inquirer/type': 3.0.10(@types/node@25.6.2) + '@inquirer/core': 10.3.2(@types/node@25.8.0) + '@inquirer/type': 3.0.10(@types/node@25.8.0) optionalDependencies: - '@types/node': 25.6.2 + '@types/node': 25.8.0 - '@inquirer/core@10.3.2(@types/node@25.6.2)': + '@inquirer/core@10.3.2(@types/node@25.8.0)': dependencies: '@inquirer/ansi': 1.0.2 '@inquirer/figures': 1.0.15 - '@inquirer/type': 3.0.10(@types/node@25.6.2) + '@inquirer/type': 3.0.10(@types/node@25.8.0) cli-width: 4.1.0 mute-stream: 2.0.0 signal-exit: 4.1.0 wrap-ansi: 6.2.0 yoctocolors-cjs: 2.1.3 optionalDependencies: - '@types/node': 25.6.2 + '@types/node': 25.8.0 - '@inquirer/editor@4.2.23(@types/node@25.6.2)': + '@inquirer/editor@4.2.23(@types/node@25.8.0)': dependencies: - '@inquirer/core': 10.3.2(@types/node@25.6.2) - '@inquirer/external-editor': 1.0.3(@types/node@25.6.2) - '@inquirer/type': 3.0.10(@types/node@25.6.2) + '@inquirer/core': 10.3.2(@types/node@25.8.0) + '@inquirer/external-editor': 1.0.3(@types/node@25.8.0) + '@inquirer/type': 3.0.10(@types/node@25.8.0) optionalDependencies: - '@types/node': 25.6.2 + '@types/node': 25.8.0 - '@inquirer/expand@4.0.23(@types/node@25.6.2)': + '@inquirer/expand@4.0.23(@types/node@25.8.0)': dependencies: - '@inquirer/core': 10.3.2(@types/node@25.6.2) - '@inquirer/type': 3.0.10(@types/node@25.6.2) + '@inquirer/core': 10.3.2(@types/node@25.8.0) + '@inquirer/type': 3.0.10(@types/node@25.8.0) yoctocolors-cjs: 2.1.3 optionalDependencies: - '@types/node': 25.6.2 + '@types/node': 25.8.0 - '@inquirer/external-editor@1.0.3(@types/node@25.6.2)': + '@inquirer/external-editor@1.0.3(@types/node@25.8.0)': dependencies: chardet: 2.1.1 iconv-lite: 0.7.2 optionalDependencies: - '@types/node': 25.6.2 + '@types/node': 25.8.0 '@inquirer/figures@1.0.15': {} - '@inquirer/input@4.3.1(@types/node@25.6.2)': + '@inquirer/input@4.3.1(@types/node@25.8.0)': dependencies: - '@inquirer/core': 10.3.2(@types/node@25.6.2) - '@inquirer/type': 3.0.10(@types/node@25.6.2) + '@inquirer/core': 10.3.2(@types/node@25.8.0) + '@inquirer/type': 3.0.10(@types/node@25.8.0) optionalDependencies: - '@types/node': 25.6.2 + '@types/node': 25.8.0 - '@inquirer/number@3.0.23(@types/node@25.6.2)': + '@inquirer/number@3.0.23(@types/node@25.8.0)': dependencies: - '@inquirer/core': 10.3.2(@types/node@25.6.2) - '@inquirer/type': 3.0.10(@types/node@25.6.2) + '@inquirer/core': 10.3.2(@types/node@25.8.0) + '@inquirer/type': 3.0.10(@types/node@25.8.0) optionalDependencies: - '@types/node': 25.6.2 + '@types/node': 25.8.0 - '@inquirer/password@4.0.23(@types/node@25.6.2)': + '@inquirer/password@4.0.23(@types/node@25.8.0)': dependencies: '@inquirer/ansi': 1.0.2 - '@inquirer/core': 10.3.2(@types/node@25.6.2) - '@inquirer/type': 3.0.10(@types/node@25.6.2) + '@inquirer/core': 10.3.2(@types/node@25.8.0) + '@inquirer/type': 3.0.10(@types/node@25.8.0) optionalDependencies: - '@types/node': 25.6.2 + '@types/node': 25.8.0 - '@inquirer/prompts@7.10.1(@types/node@25.6.2)': + '@inquirer/prompts@7.10.1(@types/node@25.8.0)': dependencies: - '@inquirer/checkbox': 4.3.2(@types/node@25.6.2) - '@inquirer/confirm': 5.1.21(@types/node@25.6.2) - '@inquirer/editor': 4.2.23(@types/node@25.6.2) - '@inquirer/expand': 4.0.23(@types/node@25.6.2) - '@inquirer/input': 4.3.1(@types/node@25.6.2) - '@inquirer/number': 3.0.23(@types/node@25.6.2) - '@inquirer/password': 4.0.23(@types/node@25.6.2) - '@inquirer/rawlist': 4.1.11(@types/node@25.6.2) - '@inquirer/search': 3.2.2(@types/node@25.6.2) - '@inquirer/select': 4.4.2(@types/node@25.6.2) + '@inquirer/checkbox': 4.3.2(@types/node@25.8.0) + '@inquirer/confirm': 5.1.21(@types/node@25.8.0) + '@inquirer/editor': 4.2.23(@types/node@25.8.0) + '@inquirer/expand': 4.0.23(@types/node@25.8.0) + '@inquirer/input': 4.3.1(@types/node@25.8.0) + '@inquirer/number': 3.0.23(@types/node@25.8.0) + '@inquirer/password': 4.0.23(@types/node@25.8.0) + '@inquirer/rawlist': 4.1.11(@types/node@25.8.0) + '@inquirer/search': 3.2.2(@types/node@25.8.0) + '@inquirer/select': 4.4.2(@types/node@25.8.0) optionalDependencies: - '@types/node': 25.6.2 + '@types/node': 25.8.0 - '@inquirer/rawlist@4.1.11(@types/node@25.6.2)': + '@inquirer/rawlist@4.1.11(@types/node@25.8.0)': dependencies: - '@inquirer/core': 10.3.2(@types/node@25.6.2) - '@inquirer/type': 3.0.10(@types/node@25.6.2) + '@inquirer/core': 10.3.2(@types/node@25.8.0) + '@inquirer/type': 3.0.10(@types/node@25.8.0) yoctocolors-cjs: 2.1.3 optionalDependencies: - '@types/node': 25.6.2 + '@types/node': 25.8.0 - '@inquirer/search@3.2.2(@types/node@25.6.2)': + '@inquirer/search@3.2.2(@types/node@25.8.0)': dependencies: - '@inquirer/core': 10.3.2(@types/node@25.6.2) + '@inquirer/core': 10.3.2(@types/node@25.8.0) '@inquirer/figures': 1.0.15 - '@inquirer/type': 3.0.10(@types/node@25.6.2) + '@inquirer/type': 3.0.10(@types/node@25.8.0) yoctocolors-cjs: 2.1.3 optionalDependencies: - '@types/node': 25.6.2 + '@types/node': 25.8.0 - '@inquirer/select@4.4.2(@types/node@25.6.2)': + '@inquirer/select@4.4.2(@types/node@25.8.0)': dependencies: '@inquirer/ansi': 1.0.2 - '@inquirer/core': 10.3.2(@types/node@25.6.2) + '@inquirer/core': 10.3.2(@types/node@25.8.0) '@inquirer/figures': 1.0.15 - '@inquirer/type': 3.0.10(@types/node@25.6.2) + '@inquirer/type': 3.0.10(@types/node@25.8.0) yoctocolors-cjs: 2.1.3 optionalDependencies: - '@types/node': 25.6.2 + '@types/node': 25.8.0 - '@inquirer/type@3.0.10(@types/node@25.6.2)': + '@inquirer/type@3.0.10(@types/node@25.8.0)': optionalDependencies: - '@types/node': 25.6.2 + '@types/node': 25.8.0 '@isaacs/ttlcache@1.4.1': {} @@ -9607,7 +9710,7 @@ snapshots: '@jest/console@29.7.0': dependencies: '@jest/types': 29.6.3 - '@types/node': 25.6.2 + '@types/node': 25.8.0 chalk: 4.1.2 jest-message-util: 29.7.0 jest-util: 29.7.0 @@ -9620,14 +9723,14 @@ snapshots: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 25.6.2 + '@types/node': 25.8.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.6.2) + jest-config: 29.7.0(@types/node@25.8.0) jest-haste-map: 29.7.0 jest-message-util: 29.7.0 jest-regex-util: 29.6.3 @@ -9658,7 +9761,7 @@ snapshots: dependencies: '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 25.6.2 + '@types/node': 25.8.0 jest-mock: 29.7.0 '@jest/expect-utils@29.7.0': @@ -9676,7 +9779,7 @@ snapshots: dependencies: '@jest/types': 29.6.3 '@sinonjs/fake-timers': 10.3.0 - '@types/node': 25.6.2 + '@types/node': 25.8.0 jest-message-util: 29.7.0 jest-mock: 29.7.0 jest-util: 29.7.0 @@ -9700,7 +9803,7 @@ snapshots: '@jest/transform': 29.7.0 '@jest/types': 29.6.3 '@jridgewell/trace-mapping': 0.3.31 - '@types/node': 25.6.2 + '@types/node': 25.8.0 chalk: 4.1.2 collect-v8-coverage: 1.0.3 exit: 0.1.2 @@ -9774,7 +9877,7 @@ snapshots: '@jest/schemas': 29.6.3 '@types/istanbul-lib-coverage': 2.0.6 '@types/istanbul-reports': 3.0.4 - '@types/node': 25.6.2 + '@types/node': 25.8.0 '@types/yargs': 17.0.35 chalk: 4.1.2 @@ -9818,19 +9921,18 @@ snapshots: '@mapbox/unitbezier@0.0.1': {} - '@maplibre/maplibre-gl-style-spec@24.8.1': + '@maplibre/maplibre-gl-style-spec@24.8.5': dependencies: '@mapbox/jsonlint-lines-primitives': 2.0.2 '@mapbox/unitbezier': 0.0.1 json-stringify-pretty-compact: 4.0.0 minimist: 1.2.8 quickselect: 3.0.0 - rw: 1.3.3 tinyqueue: 3.0.0 - '@maplibre/maplibre-react-native@11.1.1(@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.6))(react@19.2.6)': + '@maplibre/maplibre-react-native@11.2.1(@expo/config-plugins@55.0.9)(@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.6))(react@19.2.6)': dependencies: - '@maplibre/maplibre-gl-style-spec': 24.8.1 + '@maplibre/maplibre-gl-style-spec': 24.8.5 '@turf/distance': 7.3.5 '@turf/helpers': 7.3.5 '@turf/length': 7.3.5 @@ -9838,7 +9940,7 @@ snapshots: react: 19.2.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.6) optionalDependencies: - '@expo/config-plugins': 55.0.8 + '@expo/config-plugins': 55.0.9 '@types/geojson': 7946.0.16 '@types/react': 19.2.14 @@ -10186,9 +10288,9 @@ snapshots: '@pinojs/redact@0.4.0': {} - '@playwright/test@1.59.1': + '@playwright/test@1.60.0': dependencies: - playwright: 1.59.1 + playwright: 1.60.0 '@polka/url@1.0.0-next.29': {} @@ -10656,7 +10758,7 @@ snapshots: optionalDependencies: '@types/react': 19.2.14 - '@react-navigation/bottom-tabs@7.15.13(@react-navigation/native@7.2.4(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-safe-area-context@5.7.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.6))(react@19.2.6))(react-native-screens@4.24.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.6))(react@19.2.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.6))(react@19.2.6)': + '@react-navigation/bottom-tabs@7.15.13(@react-navigation/native@7.2.4(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-safe-area-context@5.7.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.6))(react@19.2.6))(react-native-screens@4.25.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.6))(react@19.2.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.6))(react@19.2.6)': dependencies: '@react-navigation/elements': 2.9.17(@react-navigation/native@7.2.4(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-safe-area-context@5.7.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.6))(react@19.2.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.6))(react@19.2.6) '@react-navigation/native': 7.2.4(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) @@ -10664,7 +10766,7 @@ snapshots: react: 19.2.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.6) react-native-safe-area-context: 5.7.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.6))(react@19.2.6) - react-native-screens: 4.24.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.6))(react@19.2.6) + react-native-screens: 4.25.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.6))(react@19.2.6) sf-symbols-typescript: 2.2.0 transitivePeerDependencies: - '@react-native-masked-view/masked-view' @@ -10691,7 +10793,7 @@ snapshots: use-latest-callback: 0.2.6(react@19.2.6) use-sync-external-store: 1.6.0(react@19.2.6) - '@react-navigation/native-stack@7.14.14(@react-navigation/native@7.2.4(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-safe-area-context@5.7.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.6))(react@19.2.6))(react-native-screens@4.24.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.6))(react@19.2.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.6))(react@19.2.6)': + '@react-navigation/native-stack@7.14.14(@react-navigation/native@7.2.4(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-safe-area-context@5.7.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.6))(react@19.2.6))(react-native-screens@4.25.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.6))(react@19.2.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.6))(react@19.2.6)': dependencies: '@react-navigation/elements': 2.9.17(@react-navigation/native@7.2.4(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-safe-area-context@5.7.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.6))(react@19.2.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.6))(react@19.2.6) '@react-navigation/native': 7.2.4(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) @@ -10699,7 +10801,7 @@ snapshots: react: 19.2.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.6) react-native-safe-area-context: 5.7.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.6))(react@19.2.6) - react-native-screens: 4.24.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.6))(react@19.2.6) + react-native-screens: 4.25.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.6))(react@19.2.6) sf-symbols-typescript: 2.2.0 warn-once: 0.1.1 transitivePeerDependencies: @@ -10719,7 +10821,7 @@ snapshots: dependencies: nanoid: 3.3.12 - '@react-router/dev@7.15.0(@react-router/serve@7.15.0(react-router@7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3))(@types/node@25.6.2)(jiti@2.7.0)(lightningcss@1.32.0)(react-router@7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4))(yaml@2.8.4)': + '@react-router/dev@7.15.1(@react-router/serve@7.15.1(react-router@7.15.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3))(@types/node@25.8.0)(jiti@2.7.0)(lightningcss@1.32.0)(react-router@7.15.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.10(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0))(yaml@2.9.0)': dependencies: '@babel/core': 7.29.0 '@babel/generator': 7.29.1 @@ -10728,7 +10830,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.15.0(react-router@7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3) + '@react-router/node': 7.15.1(react-router@7.15.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3) '@remix-run/node-fetch-server': 0.13.1 arg: 5.0.2 babel-dead-code-elimination: 1.0.12 @@ -10745,14 +10847,14 @@ snapshots: pkg-types: 2.3.1 prettier: 3.8.3 react-refresh: 0.14.2 - react-router: 7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + react-router: 7.15.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6) semver: 7.8.0 tinyglobby: 0.2.16 valibot: 1.4.0(typescript@5.9.3) - vite: 8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4) - vite-node: 3.2.4(@types/node@25.6.2)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4) + vite: 8.0.10(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0) + vite-node: 3.2.4(@types/node@25.8.0)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0) optionalDependencies: - '@react-router/serve': 7.15.0(react-router@7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3) + '@react-router/serve': 7.15.1(react-router@7.15.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - '@types/node' @@ -10769,31 +10871,31 @@ snapshots: - tsx - yaml - '@react-router/express@7.15.0(express@4.22.1)(react-router@7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3)': + '@react-router/express@7.15.1(express@4.22.2)(react-router@7.15.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3)': dependencies: - '@react-router/node': 7.15.0(react-router@7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3) - express: 4.22.1 - react-router: 7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@react-router/node': 7.15.1(react-router@7.15.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3) + express: 4.22.2 + react-router: 7.15.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6) optionalDependencies: typescript: 5.9.3 - '@react-router/node@7.15.0(react-router@7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3)': + '@react-router/node@7.15.1(react-router@7.15.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3)': dependencies: '@mjackson/node-fetch-server': 0.2.0 - react-router: 7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + react-router: 7.15.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6) optionalDependencies: typescript: 5.9.3 - '@react-router/serve@7.15.0(react-router@7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3)': + '@react-router/serve@7.15.1(react-router@7.15.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3)': dependencies: '@mjackson/node-fetch-server': 0.2.0 - '@react-router/express': 7.15.0(express@4.22.1)(react-router@7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3) - '@react-router/node': 7.15.0(react-router@7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3) + '@react-router/express': 7.15.1(express@4.22.2)(react-router@7.15.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3) + '@react-router/node': 7.15.1(react-router@7.15.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3) compression: 1.8.1 - express: 4.22.1 + express: 4.22.2 get-port: 5.1.1 morgan: 1.10.1 - react-router: 7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + react-router: 7.15.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6) source-map-support: 0.5.21 transitivePeerDependencies: - supports-color @@ -10852,119 +10954,121 @@ snapshots: '@rolldown/pluginutils@1.0.0-rc.17': {} - '@rollup/rollup-android-arm-eabi@4.60.3': + '@rollup/rollup-android-arm-eabi@4.60.4': optional: true - '@rollup/rollup-android-arm64@4.60.3': + '@rollup/rollup-android-arm64@4.60.4': optional: true - '@rollup/rollup-darwin-arm64@4.60.3': + '@rollup/rollup-darwin-arm64@4.60.4': optional: true - '@rollup/rollup-darwin-x64@4.60.3': + '@rollup/rollup-darwin-x64@4.60.4': optional: true - '@rollup/rollup-freebsd-arm64@4.60.3': + '@rollup/rollup-freebsd-arm64@4.60.4': optional: true - '@rollup/rollup-freebsd-x64@4.60.3': + '@rollup/rollup-freebsd-x64@4.60.4': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.60.3': + '@rollup/rollup-linux-arm-gnueabihf@4.60.4': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.60.3': + '@rollup/rollup-linux-arm-musleabihf@4.60.4': optional: true - '@rollup/rollup-linux-arm64-gnu@4.60.3': + '@rollup/rollup-linux-arm64-gnu@4.60.4': optional: true - '@rollup/rollup-linux-arm64-musl@4.60.3': + '@rollup/rollup-linux-arm64-musl@4.60.4': optional: true - '@rollup/rollup-linux-loong64-gnu@4.60.3': + '@rollup/rollup-linux-loong64-gnu@4.60.4': optional: true - '@rollup/rollup-linux-loong64-musl@4.60.3': + '@rollup/rollup-linux-loong64-musl@4.60.4': optional: true - '@rollup/rollup-linux-ppc64-gnu@4.60.3': + '@rollup/rollup-linux-ppc64-gnu@4.60.4': optional: true - '@rollup/rollup-linux-ppc64-musl@4.60.3': + '@rollup/rollup-linux-ppc64-musl@4.60.4': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.60.3': + '@rollup/rollup-linux-riscv64-gnu@4.60.4': optional: true - '@rollup/rollup-linux-riscv64-musl@4.60.3': + '@rollup/rollup-linux-riscv64-musl@4.60.4': optional: true - '@rollup/rollup-linux-s390x-gnu@4.60.3': + '@rollup/rollup-linux-s390x-gnu@4.60.4': optional: true - '@rollup/rollup-linux-x64-gnu@4.60.3': + '@rollup/rollup-linux-x64-gnu@4.60.4': optional: true - '@rollup/rollup-linux-x64-musl@4.60.3': + '@rollup/rollup-linux-x64-musl@4.60.4': optional: true - '@rollup/rollup-openbsd-x64@4.60.3': + '@rollup/rollup-openbsd-x64@4.60.4': optional: true - '@rollup/rollup-openharmony-arm64@4.60.3': + '@rollup/rollup-openharmony-arm64@4.60.4': optional: true - '@rollup/rollup-win32-arm64-msvc@4.60.3': + '@rollup/rollup-win32-arm64-msvc@4.60.4': optional: true - '@rollup/rollup-win32-ia32-msvc@4.60.3': + '@rollup/rollup-win32-ia32-msvc@4.60.4': optional: true - '@rollup/rollup-win32-x64-gnu@4.60.3': + '@rollup/rollup-win32-x64-gnu@4.60.4': optional: true - '@rollup/rollup-win32-x64-msvc@4.60.3': + '@rollup/rollup-win32-x64-msvc@4.60.4': optional: true '@sentry-internal/browser-utils@10.51.0': dependencies: '@sentry/core': 10.51.0 - '@sentry-internal/browser-utils@10.52.0': + '@sentry-internal/browser-utils@10.53.1': dependencies: - '@sentry/core': 10.52.0 + '@sentry/core': 10.53.1 '@sentry-internal/feedback@10.51.0': dependencies: '@sentry/core': 10.51.0 - '@sentry-internal/feedback@10.52.0': + '@sentry-internal/feedback@10.53.1': dependencies: - '@sentry/core': 10.52.0 + '@sentry/core': 10.53.1 '@sentry-internal/replay-canvas@10.51.0': dependencies: '@sentry-internal/replay': 10.51.0 '@sentry/core': 10.51.0 - '@sentry-internal/replay-canvas@10.52.0': + '@sentry-internal/replay-canvas@10.53.1': dependencies: - '@sentry-internal/replay': 10.52.0 - '@sentry/core': 10.52.0 + '@sentry-internal/replay': 10.53.1 + '@sentry/core': 10.53.1 '@sentry-internal/replay@10.51.0': dependencies: '@sentry-internal/browser-utils': 10.51.0 '@sentry/core': 10.51.0 - '@sentry-internal/replay@10.52.0': + '@sentry-internal/replay@10.53.1': dependencies: - '@sentry-internal/browser-utils': 10.52.0 - '@sentry/core': 10.52.0 + '@sentry-internal/browser-utils': 10.53.1 + '@sentry/core': 10.53.1 '@sentry/babel-plugin-component-annotate@5.2.1': {} + '@sentry/babel-plugin-component-annotate@5.3.0': {} + '@sentry/browser@10.51.0': dependencies: '@sentry-internal/browser-utils': 10.51.0 @@ -10973,18 +11077,18 @@ snapshots: '@sentry-internal/replay-canvas': 10.51.0 '@sentry/core': 10.51.0 - '@sentry/browser@10.52.0': + '@sentry/browser@10.53.1': dependencies: - '@sentry-internal/browser-utils': 10.52.0 - '@sentry-internal/feedback': 10.52.0 - '@sentry-internal/replay': 10.52.0 - '@sentry-internal/replay-canvas': 10.52.0 - '@sentry/core': 10.52.0 + '@sentry-internal/browser-utils': 10.53.1 + '@sentry-internal/feedback': 10.53.1 + '@sentry-internal/replay': 10.53.1 + '@sentry-internal/replay-canvas': 10.53.1 + '@sentry/core': 10.53.1 - '@sentry/bundler-plugin-core@5.2.1': + '@sentry/bundler-plugin-core@5.3.0': dependencies: '@babel/core': 7.29.0 - '@sentry/babel-plugin-component-annotate': 5.2.1 + '@sentry/babel-plugin-component-annotate': 5.3.0 '@sentry/cli': 2.58.5 dotenv: 16.6.1 find-up: 5.0.0 @@ -11000,48 +11104,72 @@ snapshots: '@sentry/cli-darwin@3.4.1': optional: true + '@sentry/cli-darwin@3.4.2': + optional: true + '@sentry/cli-linux-arm64@2.58.5': optional: true '@sentry/cli-linux-arm64@3.4.1': optional: true + '@sentry/cli-linux-arm64@3.4.2': + optional: true + '@sentry/cli-linux-arm@2.58.5': optional: true '@sentry/cli-linux-arm@3.4.1': optional: true + '@sentry/cli-linux-arm@3.4.2': + optional: true + '@sentry/cli-linux-i686@2.58.5': optional: true '@sentry/cli-linux-i686@3.4.1': optional: true + '@sentry/cli-linux-i686@3.4.2': + optional: true + '@sentry/cli-linux-x64@2.58.5': optional: true '@sentry/cli-linux-x64@3.4.1': optional: true + '@sentry/cli-linux-x64@3.4.2': + optional: true + '@sentry/cli-win32-arm64@2.58.5': optional: true '@sentry/cli-win32-arm64@3.4.1': optional: true + '@sentry/cli-win32-arm64@3.4.2': + optional: true + '@sentry/cli-win32-i686@2.58.5': optional: true '@sentry/cli-win32-i686@3.4.1': optional: true + '@sentry/cli-win32-i686@3.4.2': + optional: true + '@sentry/cli-win32-x64@2.58.5': optional: true '@sentry/cli-win32-x64@3.4.1': optional: true + '@sentry/cli-win32-x64@3.4.2': + optional: true + '@sentry/cli@2.58.5': dependencies: https-proxy-agent: 5.0.1 @@ -11078,21 +11206,37 @@ snapshots: '@sentry/cli-win32-i686': 3.4.1 '@sentry/cli-win32-x64': 3.4.1 + '@sentry/cli@3.4.2': + dependencies: + progress: 2.0.3 + proxy-from-env: 1.1.0 + undici: 6.25.0 + which: 2.0.2 + optionalDependencies: + '@sentry/cli-darwin': 3.4.2 + '@sentry/cli-linux-arm': 3.4.2 + '@sentry/cli-linux-arm64': 3.4.2 + '@sentry/cli-linux-i686': 3.4.2 + '@sentry/cli-linux-x64': 3.4.2 + '@sentry/cli-win32-arm64': 3.4.2 + '@sentry/cli-win32-i686': 3.4.2 + '@sentry/cli-win32-x64': 3.4.2 + '@sentry/core@10.51.0': {} - '@sentry/core@10.52.0': {} + '@sentry/core@10.53.1': {} - '@sentry/expo-upload-sourcemaps@8.11.0(@expo/env@2.1.2)(dotenv@16.6.1)': + '@sentry/expo-upload-sourcemaps@8.11.1(@expo/env@2.1.2)(dotenv@16.6.1)': dependencies: '@sentry/cli': 3.4.1 optionalDependencies: '@expo/env': 2.1.2 dotenv: 16.6.1 - '@sentry/node-core@10.52.0(@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/sdk-trace-base@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/semantic-conventions@1.40.0)': + '@sentry/node-core@10.53.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/sdk-trace-base@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/semantic-conventions@1.40.0)': dependencies: - '@sentry/core': 10.52.0 - '@sentry/opentelemetry': 10.52.0(@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) + '@sentry/core': 10.53.1 + '@sentry/opentelemetry': 10.53.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.1 optionalDependencies: '@opentelemetry/api': 1.9.1 @@ -11101,7 +11245,7 @@ snapshots: '@opentelemetry/sdk-trace-base': 2.6.1(@opentelemetry/api@1.9.1) '@opentelemetry/semantic-conventions': 1.40.0 - '@sentry/node@10.52.0': + '@sentry/node@10.53.1': dependencies: '@fastify/otel': 0.18.0(@opentelemetry/api@1.9.1) '@opentelemetry/api': 1.9.1 @@ -11128,35 +11272,35 @@ snapshots: '@opentelemetry/sdk-trace-base': 2.6.1(@opentelemetry/api@1.9.1) '@opentelemetry/semantic-conventions': 1.40.0 '@prisma/instrumentation': 7.6.0(@opentelemetry/api@1.9.1) - '@sentry/core': 10.52.0 - '@sentry/node-core': 10.52.0(@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/sdk-trace-base@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/semantic-conventions@1.40.0) - '@sentry/opentelemetry': 10.52.0(@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) + '@sentry/core': 10.53.1 + '@sentry/node-core': 10.53.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/sdk-trace-base@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/semantic-conventions@1.40.0) + '@sentry/opentelemetry': 10.53.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.1 transitivePeerDependencies: - '@opentelemetry/exporter-trace-otlp-http' - supports-color - '@sentry/opentelemetry@10.52.0(@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)': + '@sentry/opentelemetry@10.53.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)': dependencies: '@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 - '@sentry/core': 10.52.0 + '@sentry/core': 10.53.1 - '@sentry/react-native@8.11.0(@expo/env@2.1.2)(dotenv@16.6.1)(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)': + '@sentry/react-native@8.11.1(@expo/env@2.1.2)(dotenv@16.6.1)(expo@55.0.24)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)': dependencies: '@sentry/babel-plugin-component-annotate': 5.2.1 '@sentry/browser': 10.51.0 '@sentry/cli': 3.4.1 '@sentry/core': 10.51.0 - '@sentry/expo-upload-sourcemaps': 8.11.0(@expo/env@2.1.2)(dotenv@16.6.1) + '@sentry/expo-upload-sourcemaps': 8.11.1(@expo/env@2.1.2)(dotenv@16.6.1) '@sentry/react': 10.51.0(react@19.2.6) '@sentry/types': 10.51.0 react: 19.2.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.6) optionalDependencies: - expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) + expo: 55.0.24(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) transitivePeerDependencies: - '@expo/env' - dotenv @@ -11167,18 +11311,18 @@ snapshots: '@sentry/core': 10.51.0 react: 19.2.6 - '@sentry/react@10.52.0(react@19.2.6)': + '@sentry/react@10.53.1(react@19.2.6)': dependencies: - '@sentry/browser': 10.52.0 - '@sentry/core': 10.52.0 + '@sentry/browser': 10.53.1 + '@sentry/core': 10.53.1 react: 19.2.6 - '@sentry/rollup-plugin@5.2.1(rollup@4.60.3)': + '@sentry/rollup-plugin@5.3.0(rollup@4.60.4)': dependencies: - '@sentry/bundler-plugin-core': 5.2.1 + '@sentry/bundler-plugin-core': 5.3.0 magic-string: 0.30.21 optionalDependencies: - rollup: 4.60.3 + rollup: 4.60.4 transitivePeerDependencies: - encoding - supports-color @@ -11187,10 +11331,10 @@ snapshots: dependencies: '@sentry/core': 10.51.0 - '@sentry/vite-plugin@5.2.1(rollup@4.60.3)': + '@sentry/vite-plugin@5.3.0(rollup@4.60.4)': dependencies: - '@sentry/bundler-plugin-core': 5.2.1 - '@sentry/rollup-plugin': 5.2.1(rollup@4.60.3) + '@sentry/bundler-plugin-core': 5.3.0 + '@sentry/rollup-plugin': 5.3.0(rollup@4.60.4) transitivePeerDependencies: - encoding - rollup @@ -11286,12 +11430,12 @@ snapshots: '@tailwindcss/oxide-win32-arm64-msvc': 4.3.0 '@tailwindcss/oxide-win32-x64-msvc': 4.3.0 - '@tailwindcss/vite@4.3.0(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4))': + '@tailwindcss/vite@4.3.0(vite@8.0.10(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0))': dependencies: '@tailwindcss/node': 4.3.0 '@tailwindcss/oxide': 4.3.0 tailwindcss: 4.3.0 - vite: 8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4) + vite: 8.0.10(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0) '@testing-library/dom@10.4.1': dependencies: @@ -11313,7 +11457,7 @@ snapshots: picocolors: 1.1.1 redent: 3.0.0 - '@testing-library/react-native@13.3.3(jest@29.7.0(@types/node@25.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.6))(react-test-renderer@19.2.6(react@19.2.6))(react@19.2.6)': + '@testing-library/react-native@13.3.3(jest@29.7.0(@types/node@25.8.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.6))(react-test-renderer@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: jest-matcher-utils: 30.3.0 picocolors: 1.1.1 @@ -11323,7 +11467,7 @@ snapshots: react-test-renderer: 19.2.6(react@19.2.6) redent: 3.0.0 optionalDependencies: - jest: 29.7.0(@types/node@25.6.2) + jest: 29.7.0(@types/node@25.8.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.6(react@19.2.6))(react@19.2.6)': dependencies: @@ -11337,22 +11481,22 @@ snapshots: '@tootallnate/once@2.0.1': {} - '@turbo/darwin-64@2.9.12': + '@turbo/darwin-64@2.9.14': optional: true - '@turbo/darwin-arm64@2.9.12': + '@turbo/darwin-arm64@2.9.14': optional: true - '@turbo/linux-64@2.9.12': + '@turbo/linux-64@2.9.14': optional: true - '@turbo/linux-arm64@2.9.12': + '@turbo/linux-arm64@2.9.14': optional: true - '@turbo/windows-64@2.9.12': + '@turbo/windows-64@2.9.14': optional: true - '@turbo/windows-arm64@2.9.12': + '@turbo/windows-arm64@2.9.14': optional: true '@turf/bbox@7.3.4': @@ -11548,7 +11692,7 @@ snapshots: '@types/connect@3.4.38': dependencies: - '@types/node': 25.6.2 + '@types/node': 25.8.0 '@types/deep-eql@4.0.2': {} @@ -11562,7 +11706,7 @@ snapshots: '@types/graceful-fs@4.1.9': dependencies: - '@types/node': 25.6.2 + '@types/node': 25.8.0 '@types/hammerjs@2.0.46': {} @@ -11583,7 +11727,7 @@ snapshots: '@types/jsdom@20.0.1': dependencies: - '@types/node': 25.6.2 + '@types/node': 25.8.0 '@types/tough-cookie': 4.0.5 parse5: 7.3.0 @@ -11599,9 +11743,9 @@ snapshots: '@types/mysql@2.15.27': dependencies: - '@types/node': 25.6.2 + '@types/node': 25.8.0 - '@types/node@22.19.18': + '@types/node@22.19.19': dependencies: undici-types: 6.21.0 @@ -11609,6 +11753,10 @@ snapshots: dependencies: undici-types: 7.19.2 + '@types/node@25.8.0': + dependencies: + undici-types: 7.24.6 + '@types/nodemailer@8.0.0': dependencies: '@types/node': 25.6.2 @@ -11619,7 +11767,7 @@ snapshots: '@types/pg@8.15.6': dependencies: - '@types/node': 25.6.2 + '@types/node': 25.8.0 pg-protocol: 1.13.0 pg-types: 2.2.0 @@ -11639,7 +11787,7 @@ snapshots: '@types/tedious@4.0.14': dependencies: - '@types/node': 25.6.2 + '@types/node': 25.8.0 '@types/tough-cookie@4.0.5': {} @@ -11653,15 +11801,15 @@ snapshots: dependencies: '@types/yargs-parser': 21.0.3 - '@typescript-eslint/eslint-plugin@8.59.2(@typescript-eslint/parser@8.59.2(eslint@10.3.0(jiti@2.7.0))(typescript@5.9.3))(eslint@10.3.0(jiti@2.7.0))(typescript@5.9.3)': + '@typescript-eslint/eslint-plugin@8.59.3(@typescript-eslint/parser@8.59.3(eslint@10.4.0(jiti@2.7.0))(typescript@5.9.3))(eslint@10.4.0(jiti@2.7.0))(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.59.2(eslint@10.3.0(jiti@2.7.0))(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.59.2 - '@typescript-eslint/type-utils': 8.59.2(eslint@10.3.0(jiti@2.7.0))(typescript@5.9.3) - '@typescript-eslint/utils': 8.59.2(eslint@10.3.0(jiti@2.7.0))(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.59.2 - eslint: 10.3.0(jiti@2.7.0) + '@typescript-eslint/parser': 8.59.3(eslint@10.4.0(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.59.3 + '@typescript-eslint/type-utils': 8.59.3(eslint@10.4.0(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/utils': 8.59.3(eslint@10.4.0(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.59.3 + eslint: 10.4.0(jiti@2.7.0) ignore: 7.0.5 natural-compare: 1.4.0 ts-api-utils: 2.5.0(typescript@5.9.3) @@ -11669,56 +11817,56 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.59.2(eslint@10.3.0(jiti@2.7.0))(typescript@5.9.3)': + '@typescript-eslint/parser@8.59.3(eslint@10.4.0(jiti@2.7.0))(typescript@5.9.3)': dependencies: - '@typescript-eslint/scope-manager': 8.59.2 - '@typescript-eslint/types': 8.59.2 - '@typescript-eslint/typescript-estree': 8.59.2(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.59.2 + '@typescript-eslint/scope-manager': 8.59.3 + '@typescript-eslint/types': 8.59.3 + '@typescript-eslint/typescript-estree': 8.59.3(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.59.3 debug: 4.4.3 - eslint: 10.3.0(jiti@2.7.0) + eslint: 10.4.0(jiti@2.7.0) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.59.2(typescript@5.9.3)': + '@typescript-eslint/project-service@8.59.3(typescript@5.9.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.59.2(typescript@5.9.3) - '@typescript-eslint/types': 8.59.2 + '@typescript-eslint/tsconfig-utils': 8.59.3(typescript@5.9.3) + '@typescript-eslint/types': 8.59.3 debug: 4.4.3 typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@8.59.2': + '@typescript-eslint/scope-manager@8.59.3': dependencies: - '@typescript-eslint/types': 8.59.2 - '@typescript-eslint/visitor-keys': 8.59.2 + '@typescript-eslint/types': 8.59.3 + '@typescript-eslint/visitor-keys': 8.59.3 - '@typescript-eslint/tsconfig-utils@8.59.2(typescript@5.9.3)': + '@typescript-eslint/tsconfig-utils@8.59.3(typescript@5.9.3)': dependencies: typescript: 5.9.3 - '@typescript-eslint/type-utils@8.59.2(eslint@10.3.0(jiti@2.7.0))(typescript@5.9.3)': + '@typescript-eslint/type-utils@8.59.3(eslint@10.4.0(jiti@2.7.0))(typescript@5.9.3)': dependencies: - '@typescript-eslint/types': 8.59.2 - '@typescript-eslint/typescript-estree': 8.59.2(typescript@5.9.3) - '@typescript-eslint/utils': 8.59.2(eslint@10.3.0(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/types': 8.59.3 + '@typescript-eslint/typescript-estree': 8.59.3(typescript@5.9.3) + '@typescript-eslint/utils': 8.59.3(eslint@10.4.0(jiti@2.7.0))(typescript@5.9.3) debug: 4.4.3 - eslint: 10.3.0(jiti@2.7.0) + eslint: 10.4.0(jiti@2.7.0) ts-api-utils: 2.5.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/types@8.59.2': {} + '@typescript-eslint/types@8.59.3': {} - '@typescript-eslint/typescript-estree@8.59.2(typescript@5.9.3)': + '@typescript-eslint/typescript-estree@8.59.3(typescript@5.9.3)': dependencies: - '@typescript-eslint/project-service': 8.59.2(typescript@5.9.3) - '@typescript-eslint/tsconfig-utils': 8.59.2(typescript@5.9.3) - '@typescript-eslint/types': 8.59.2 - '@typescript-eslint/visitor-keys': 8.59.2 + '@typescript-eslint/project-service': 8.59.3(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.59.3(typescript@5.9.3) + '@typescript-eslint/types': 8.59.3 + '@typescript-eslint/visitor-keys': 8.59.3 debug: 4.4.3 minimatch: 10.2.5 semver: 7.8.0 @@ -11728,96 +11876,96 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.59.2(eslint@10.3.0(jiti@2.7.0))(typescript@5.9.3)': + '@typescript-eslint/utils@8.59.3(eslint@10.4.0(jiti@2.7.0))(typescript@5.9.3)': dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.3.0(jiti@2.7.0)) - '@typescript-eslint/scope-manager': 8.59.2 - '@typescript-eslint/types': 8.59.2 - '@typescript-eslint/typescript-estree': 8.59.2(typescript@5.9.3) - eslint: 10.3.0(jiti@2.7.0) + '@eslint-community/eslint-utils': 4.9.1(eslint@10.4.0(jiti@2.7.0)) + '@typescript-eslint/scope-manager': 8.59.3 + '@typescript-eslint/types': 8.59.3 + '@typescript-eslint/typescript-estree': 8.59.3(typescript@5.9.3) + eslint: 10.4.0(jiti@2.7.0) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@8.59.2': + '@typescript-eslint/visitor-keys@8.59.3': dependencies: - '@typescript-eslint/types': 8.59.2 + '@typescript-eslint/types': 8.59.3 eslint-visitor-keys: 5.0.1 '@ungap/structured-clone@1.3.1': {} - '@vitejs/plugin-basic-ssl@2.3.0(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4))': + '@vitejs/plugin-basic-ssl@2.3.0(vite@8.0.10(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0))': dependencies: - vite: 8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4) + vite: 8.0.10(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0) - '@vitest/browser-playwright@4.1.5(playwright@1.59.1)(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4))(vitest@4.1.5)': + '@vitest/browser-playwright@4.1.6(playwright@1.60.0)(vite@8.0.10(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0))(vitest@4.1.6)': dependencies: - '@vitest/browser': 4.1.5(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4))(vitest@4.1.5) - '@vitest/mocker': 4.1.5(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4)) - playwright: 1.59.1 + '@vitest/browser': 4.1.6(vite@8.0.10(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0))(vitest@4.1.6) + '@vitest/mocker': 4.1.6(vite@8.0.10(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0)) + playwright: 1.60.0 tinyrainbow: 3.1.0 - vitest: 4.1.5(@opentelemetry/api@1.9.1)(@types/node@25.6.2)(@vitest/browser-playwright@4.1.5)(jsdom@29.1.1(canvas@3.2.3))(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4)) + vitest: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@25.8.0)(@vitest/browser-playwright@4.1.6)(jsdom@29.1.1(canvas@3.2.3))(vite@8.0.10(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0)) transitivePeerDependencies: - bufferutil - msw - utf-8-validate - vite - '@vitest/browser@4.1.5(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4))(vitest@4.1.5)': + '@vitest/browser@4.1.6(vite@8.0.10(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0))(vitest@4.1.6)': dependencies: '@blazediff/core': 1.9.1 - '@vitest/mocker': 4.1.5(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4)) - '@vitest/utils': 4.1.5 + '@vitest/mocker': 4.1.6(vite@8.0.10(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0)) + '@vitest/utils': 4.1.6 magic-string: 0.30.21 pngjs: 7.0.0 sirv: 3.0.2 tinyrainbow: 3.1.0 - vitest: 4.1.5(@opentelemetry/api@1.9.1)(@types/node@25.6.2)(@vitest/browser-playwright@4.1.5)(jsdom@29.1.1(canvas@3.2.3))(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4)) - ws: 8.20.0 + vitest: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@25.8.0)(@vitest/browser-playwright@4.1.6)(jsdom@29.1.1(canvas@3.2.3))(vite@8.0.10(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0)) + ws: 8.20.1 transitivePeerDependencies: - bufferutil - msw - utf-8-validate - vite - '@vitest/expect@4.1.5': + '@vitest/expect@4.1.6': dependencies: '@standard-schema/spec': 1.1.0 '@types/chai': 5.2.3 - '@vitest/spy': 4.1.5 - '@vitest/utils': 4.1.5 + '@vitest/spy': 4.1.6 + '@vitest/utils': 4.1.6 chai: 6.2.2 tinyrainbow: 3.1.0 - '@vitest/mocker@4.1.5(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4))': + '@vitest/mocker@4.1.6(vite@8.0.10(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0))': dependencies: - '@vitest/spy': 4.1.5 + '@vitest/spy': 4.1.6 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4) + vite: 8.0.10(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0) - '@vitest/pretty-format@4.1.5': + '@vitest/pretty-format@4.1.6': dependencies: tinyrainbow: 3.1.0 - '@vitest/runner@4.1.5': + '@vitest/runner@4.1.6': dependencies: - '@vitest/utils': 4.1.5 + '@vitest/utils': 4.1.6 pathe: 2.0.3 - '@vitest/snapshot@4.1.5': + '@vitest/snapshot@4.1.6': dependencies: - '@vitest/pretty-format': 4.1.5 - '@vitest/utils': 4.1.5 + '@vitest/pretty-format': 4.1.6 + '@vitest/utils': 4.1.6 magic-string: 0.30.21 pathe: 2.0.3 - '@vitest/spy@4.1.5': {} + '@vitest/spy@4.1.6': {} - '@vitest/utils@4.1.5': + '@vitest/utils@4.1.6': dependencies: - '@vitest/pretty-format': 4.1.5 + '@vitest/pretty-format': 4.1.6 convert-source-map: 2.0.0 tinyrainbow: 3.1.0 @@ -12046,7 +12194,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.21(@babel/core@7.29.0)(@babel/runtime@7.29.2)(expo@55.0.23)(react-refresh@0.14.2): + babel-preset-expo@55.0.21(@babel/core@7.29.0)(@babel/runtime@7.29.2)(expo@55.0.24)(react-refresh@0.14.2): dependencies: '@babel/generator': 7.29.1 '@babel/helper-module-imports': 7.28.6 @@ -12074,7 +12222,7 @@ snapshots: resolve-from: 5.0.0 optionalDependencies: '@babel/runtime': 7.29.2 - expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) + expo: 55.0.24(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) transitivePeerDependencies: - '@babel/core' - supports-color @@ -12093,7 +12241,7 @@ snapshots: base64-js@1.5.1: {} - baseline-browser-mapping@2.10.29: {} + baseline-browser-mapping@2.10.30: {} basic-auth@2.0.1: dependencies: @@ -12130,7 +12278,7 @@ snapshots: http-errors: 2.0.1 iconv-lite: 0.4.24 on-finished: 2.4.1 - qs: 6.15.1 + qs: 6.15.2 raw-body: 2.5.3 type-is: 1.6.18 unpipe: 1.0.0 @@ -12166,10 +12314,10 @@ snapshots: browserslist@4.28.2: dependencies: - baseline-browser-mapping: 2.10.29 - caniuse-lite: 1.0.30001792 - electron-to-chromium: 1.5.353 - node-releases: 2.0.38 + baseline-browser-mapping: 2.10.30 + caniuse-lite: 1.0.30001793 + electron-to-chromium: 1.5.357 + node-releases: 2.0.44 update-browserslist-db: 1.2.3(browserslist@4.28.2) bser@2.1.1: @@ -12209,7 +12357,7 @@ snapshots: camelcase@6.3.0: {} - caniuse-lite@1.0.30001792: {} + caniuse-lite@1.0.30001793: {} canvas@3.2.3: dependencies: @@ -12252,7 +12400,7 @@ snapshots: chrome-launcher@0.15.2: dependencies: - '@types/node': 25.6.2 + '@types/node': 25.8.0 escape-string-regexp: 4.0.0 is-wsl: 2.2.0 lighthouse-logger: 1.4.2 @@ -12261,7 +12409,7 @@ snapshots: chromium-edge-launcher@0.2.0: dependencies: - '@types/node': 25.6.2 + '@types/node': 25.8.0 escape-string-regexp: 4.0.0 is-wsl: 2.2.0 lighthouse-logger: 1.4.2 @@ -12310,7 +12458,7 @@ snapshots: '@codemirror/lint': 6.9.5 '@codemirror/search': 6.6.0 '@codemirror/state': 6.6.0 - '@codemirror/view': 6.42.1 + '@codemirror/view': 6.43.0 collect-v8-coverage@1.0.3: {} @@ -12397,13 +12545,13 @@ snapshots: dependencies: browserslist: 4.28.2 - create-jest@29.7.0(@types/node@25.6.2): + create-jest@29.7.0(@types/node@25.8.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.6.2) + jest-config: 29.7.0(@types/node@25.8.0) jest-util: 29.7.0 prompts: 2.4.2 transitivePeerDependencies: @@ -12555,11 +12703,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.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(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.16(expo@55.0.24)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(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.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) + expo-sqlite: 55.0.16(expo@55.0.24)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) pg: 8.20.0 postgres: 3.4.9 @@ -12575,7 +12723,7 @@ snapshots: ee-first@1.1.1: {} - electron-to-chromium@1.5.353: {} + electron-to-chromium@1.5.357: {} emittery@0.13.1: {} @@ -12732,9 +12880,9 @@ snapshots: optionalDependencies: source-map: 0.6.1 - eslint-config-prettier@10.1.8(eslint@10.3.0(jiti@2.7.0)): + eslint-config-prettier@10.1.8(eslint@10.4.0(jiti@2.7.0)): dependencies: - eslint: 10.3.0(jiti@2.7.0) + eslint: 10.4.0(jiti@2.7.0) eslint-scope@9.1.2: dependencies: @@ -12747,12 +12895,12 @@ snapshots: eslint-visitor-keys@5.0.1: {} - eslint@10.3.0(jiti@2.7.0): + eslint@10.4.0(jiti@2.7.0): dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.3.0(jiti@2.7.0)) + '@eslint-community/eslint-utils': 4.9.1(eslint@10.4.0(jiti@2.7.0)) '@eslint-community/regexpp': 4.12.2 '@eslint/config-array': 0.23.5 - '@eslint/config-helpers': 0.5.5 + '@eslint/config-helpers': 0.6.0 '@eslint/core': 1.2.1 '@eslint/plugin-kit': 0.7.1 '@humanfs/node': 0.16.8 @@ -12841,98 +12989,98 @@ snapshots: jest-message-util: 29.7.0 jest-util: 29.7.0 - expo-application@55.0.14(expo@55.0.23): + expo-application@55.0.15(expo@55.0.24): dependencies: - expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) + expo: 55.0.24(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) - expo-asset@55.0.17(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)(typescript@5.9.3): + expo-asset@55.0.17(expo@55.0.24)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)(typescript@5.9.3): dependencies: '@expo/image-utils': 0.8.14(typescript@5.9.3) - expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) - expo-constants: 55.0.16(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6)) + expo: 55.0.24(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) + expo-constants: 55.0.16(expo@55.0.24)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6)) react: 19.2.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.6) transitivePeerDependencies: - supports-color - typescript - expo-constants@55.0.16(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6)): + expo-constants@55.0.16(expo@55.0.24)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6)): dependencies: '@expo/env': 2.1.2 - expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) + expo: 55.0.24(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(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.6) transitivePeerDependencies: - supports-color - expo-crypto@55.0.14(expo@55.0.23): + expo-crypto@55.0.15(expo@55.0.24): dependencies: - expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) + expo: 55.0.24(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) - expo-dev-client@55.0.32(expo@55.0.23): + expo-dev-client@55.0.34(expo@55.0.24): dependencies: - expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) - expo-dev-launcher: 55.0.33(expo@55.0.23) - expo-dev-menu: 55.0.27(expo@55.0.23) - expo-dev-menu-interface: 55.0.2(expo@55.0.23) - expo-manifests: 55.0.16(expo@55.0.23) - expo-updates-interface: 55.1.6(expo@55.0.23) + expo: 55.0.24(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) + expo-dev-launcher: 55.0.35(expo@55.0.24) + expo-dev-menu: 55.0.29(expo@55.0.24) + expo-dev-menu-interface: 55.0.2(expo@55.0.24) + expo-manifests: 55.0.17(expo@55.0.24) + expo-updates-interface: 55.1.6(expo@55.0.24) - expo-dev-launcher@55.0.33(expo@55.0.23): + expo-dev-launcher@55.0.35(expo@55.0.24): dependencies: '@expo/schema-utils': 55.0.4 - expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) - expo-dev-menu: 55.0.27(expo@55.0.23) - expo-manifests: 55.0.16(expo@55.0.23) + expo: 55.0.24(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) + expo-dev-menu: 55.0.29(expo@55.0.24) + expo-manifests: 55.0.17(expo@55.0.24) - expo-dev-menu-interface@55.0.2(expo@55.0.23): + expo-dev-menu-interface@55.0.2(expo@55.0.24): dependencies: - expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) + expo: 55.0.24(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) - expo-dev-menu@55.0.27(expo@55.0.23): + expo-dev-menu@55.0.29(expo@55.0.24): dependencies: - expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) - expo-dev-menu-interface: 55.0.2(expo@55.0.23) + expo: 55.0.24(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) + expo-dev-menu-interface: 55.0.2(expo@55.0.24) - expo-device@55.0.16(expo@55.0.23): + expo-device@55.0.17(expo@55.0.24): dependencies: - expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) + expo: 55.0.24(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) ua-parser-js: 0.7.41 - expo-file-system@55.0.19(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6)): + expo-file-system@55.0.20(expo@55.0.24)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6)): dependencies: - expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) + expo: 55.0.24(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(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.6) - expo-font@55.0.7(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6): + expo-font@55.0.7(expo@55.0.24)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6): dependencies: - expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) + expo: 55.0.24(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) fontfaceobserver: 2.3.0 react: 19.2.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.6) - expo-glass-effect@55.0.11(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6): + expo-glass-effect@55.0.11(expo@55.0.24)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6): dependencies: - expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) + expo: 55.0.24(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) react: 19.2.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.6) - expo-image@55.0.10(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6): + expo-image@55.0.10(expo@55.0.24)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6): dependencies: - expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) + expo: 55.0.24(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) react: 19.2.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.6) sf-symbols-typescript: 2.2.0 expo-json-utils@55.0.2: {} - expo-keep-awake@55.0.8(expo@55.0.23)(react@19.2.6): + expo-keep-awake@55.0.8(expo@55.0.24)(react@19.2.6): dependencies: - expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) + expo: 55.0.24(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) react: 19.2.6 - expo-linking@55.0.15(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6): + expo-linking@55.0.15(expo@55.0.24)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6): dependencies: - expo-constants: 55.0.16(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6)) + expo-constants: 55.0.16(expo@55.0.24)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6)) invariant: 2.2.4 react: 19.2.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.6) @@ -12940,26 +13088,26 @@ snapshots: - expo - supports-color - expo-localization@55.0.13(expo@55.0.23)(react@19.2.6): + expo-localization@55.0.14(expo@55.0.24)(react@19.2.6): dependencies: - expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) + expo: 55.0.24(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) react: 19.2.6 rtl-detect: 1.1.2 - expo-location@55.1.9(expo@55.0.23)(typescript@5.9.3): + expo-location@55.1.10(expo@55.0.24)(typescript@5.9.3): dependencies: '@expo/image-utils': 0.8.14(typescript@5.9.3) - expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) + expo: 55.0.24(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) transitivePeerDependencies: - supports-color - typescript - expo-manifests@55.0.16(expo@55.0.23): + expo-manifests@55.0.17(expo@55.0.24): dependencies: - expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) + expo: 55.0.24(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) expo-json-utils: 55.0.2 - expo-modules-autolinking@55.0.21(typescript@5.9.3): + expo-modules-autolinking@55.0.22(typescript@5.9.3): dependencies: '@expo/require-utils': 55.0.5(typescript@5.9.3) '@expo/spawn-async': 1.7.2 @@ -12977,50 +13125,50 @@ 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.6))(react@19.2.6) - expo-navigation-bar@55.0.12(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6): + expo-navigation-bar@55.0.13(expo@55.0.24)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6): dependencies: debug: 4.4.3 - expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) + expo: 55.0.24(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) react: 19.2.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.6) 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.6))(react@19.2.6) transitivePeerDependencies: - supports-color - expo-notifications@55.0.22(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)(typescript@5.9.3): + expo-notifications@55.0.23(expo@55.0.24)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)(typescript@5.9.3): dependencies: '@expo/image-utils': 0.8.14(typescript@5.9.3) abort-controller: 3.0.0 badgin: 1.2.3 - expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) - expo-application: 55.0.14(expo@55.0.23) - expo-constants: 55.0.16(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6)) + expo: 55.0.24(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) + expo-application: 55.0.15(expo@55.0.24) + expo-constants: 55.0.16(expo@55.0.24)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6)) react: 19.2.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.6) transitivePeerDependencies: - supports-color - typescript - expo-router@55.0.14(82db8260abd9fbac2a02011543a979fa): + expo-router@55.0.14(4a88f676dfb25e563c95d7c5569dae4c): dependencies: - '@expo/log-box': 55.0.12(@expo/dom-webview@55.0.5)(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) - '@expo/metro-runtime': 55.0.11(@expo/dom-webview@55.0.5)(expo@55.0.23)(react-dom@19.2.6(react@19.2.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.6))(react@19.2.6) + '@expo/log-box': 55.0.12(@expo/dom-webview@55.0.5)(expo@55.0.24)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) + '@expo/metro-runtime': 55.0.11(@expo/dom-webview@55.0.5)(expo@55.0.24)(react-dom@19.2.6(react@19.2.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.6))(react@19.2.6) '@expo/schema-utils': 55.0.4 '@radix-ui/react-slot': 1.2.4(@types/react@19.2.14)(react@19.2.6) '@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.6(react@19.2.6))(react@19.2.6) - '@react-navigation/bottom-tabs': 7.15.13(@react-navigation/native@7.2.4(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-safe-area-context@5.7.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.6))(react@19.2.6))(react-native-screens@4.24.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.6))(react@19.2.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.6))(react@19.2.6) + '@react-navigation/bottom-tabs': 7.15.13(@react-navigation/native@7.2.4(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-safe-area-context@5.7.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.6))(react@19.2.6))(react-native-screens@4.25.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.6))(react@19.2.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.6))(react@19.2.6) '@react-navigation/native': 7.2.4(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) - '@react-navigation/native-stack': 7.14.14(@react-navigation/native@7.2.4(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-safe-area-context@5.7.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.6))(react@19.2.6))(react-native-screens@4.24.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.6))(react@19.2.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.6))(react@19.2.6) + '@react-navigation/native-stack': 7.14.14(@react-navigation/native@7.2.4(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6))(react-native-safe-area-context@5.7.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.6))(react@19.2.6))(react-native-screens@4.25.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.6))(react@19.2.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.6))(react@19.2.6) client-only: 0.0.1 debug: 4.4.3 escape-string-regexp: 4.0.0 - expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) - expo-constants: 55.0.16(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6)) - expo-glass-effect: 55.0.11(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) - expo-image: 55.0.10(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) - expo-linking: 55.0.15(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) + expo: 55.0.24(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) + expo-constants: 55.0.16(expo@55.0.24)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6)) + expo-glass-effect: 55.0.11(expo@55.0.24)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) + expo-image: 55.0.10(expo@55.0.24)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) + expo-linking: 55.0.15(expo@55.0.24)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) expo-server: 55.0.9 - expo-symbols: 55.0.8(expo-font@55.0.7)(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) + expo-symbols: 55.0.8(expo-font@55.0.7)(expo@55.0.24)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) fast-deep-equal: 3.1.3 invariant: 2.2.4 nanoid: 3.3.12 @@ -13030,7 +13178,7 @@ 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.6) 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.6))(react@19.2.6) react-native-safe-area-context: 5.7.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.6))(react@19.2.6) - react-native-screens: 4.24.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.6))(react@19.2.6) + react-native-screens: 4.25.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.6))(react@19.2.6) semver: 7.6.3 server-only: 0.0.1 sf-symbols-typescript: 2.2.0 @@ -13038,7 +13186,7 @@ snapshots: use-latest-callback: 0.2.6(react@19.2.6) vaul: 1.1.2(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) optionalDependencies: - '@testing-library/react-native': 13.3.3(jest@29.7.0(@types/node@25.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.6))(react-test-renderer@19.2.6(react@19.2.6))(react@19.2.6) + '@testing-library/react-native': 13.3.3(jest@29.7.0(@types/node@25.8.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.6))(react-test-renderer@19.2.6(react@19.2.6))(react@19.2.6) react-dom: 19.2.6(react@19.2.6) react-native-gesture-handler: 2.31.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.6))(react@19.2.6) react-native-reanimated: 4.3.1(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.6))(react@19.2.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.6))(react@19.2.6) @@ -13049,24 +13197,24 @@ snapshots: - expo-font - supports-color - expo-secure-store@55.0.13(expo@55.0.23): + expo-secure-store@55.0.14(expo@55.0.24): dependencies: - expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) + expo: 55.0.24(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) expo-server@55.0.9: {} - expo-splash-screen@55.0.20(expo@55.0.23)(typescript@5.9.3): + expo-splash-screen@55.0.21(expo@55.0.24)(typescript@5.9.3): dependencies: - '@expo/prebuild-config': 55.0.17(expo@55.0.23)(typescript@5.9.3) - expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) + '@expo/prebuild-config': 55.0.18(expo@55.0.24)(typescript@5.9.3) + expo: 55.0.24(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) transitivePeerDependencies: - supports-color - typescript - expo-sqlite@55.0.15(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6): + expo-sqlite@55.0.16(expo@55.0.24)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6): dependencies: await-lock: 2.2.2 - expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) + expo: 55.0.24(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) react: 19.2.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.6) @@ -13076,54 +13224,54 @@ 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.6) 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.6))(react@19.2.6) - expo-symbols@55.0.8(expo-font@55.0.7)(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6): + expo-symbols@55.0.8(expo-font@55.0.7)(expo@55.0.24)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6): dependencies: '@expo-google-fonts/material-symbols': 0.4.36 - expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) - expo-font: 55.0.7(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) + expo: 55.0.24(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) + expo-font: 55.0.7(expo@55.0.24)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) react: 19.2.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.6) sf-symbols-typescript: 2.2.0 - expo-system-ui@55.0.17(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6)): + expo-system-ui@55.0.18(expo@55.0.24)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6)): dependencies: '@react-native/normalize-colors': 0.83.6 debug: 4.4.3 - expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) + expo: 55.0.24(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(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.6) transitivePeerDependencies: - supports-color - expo-updates-interface@55.1.6(expo@55.0.23): + expo-updates-interface@55.1.6(expo@55.0.24): dependencies: - expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) + expo: 55.0.24(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) - expo-web-browser@55.0.15(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6)): + expo-web-browser@55.0.16(expo@55.0.24)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6)): dependencies: - expo: 55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) + expo: 55.0.24(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(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.6) - expo@55.0.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3): + expo@55.0.24(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3): dependencies: '@babel/runtime': 7.29.2 - '@expo/cli': 55.0.29(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-constants@55.0.16)(expo-font@55.0.7)(expo-router@55.0.14)(expo@55.0.23)(react-dom@19.2.6(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) - '@expo/config': 55.0.16(typescript@5.9.3) - '@expo/config-plugins': 55.0.8 + '@expo/cli': 55.0.30(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-constants@55.0.16)(expo-font@55.0.7)(expo-router@55.0.14)(expo@55.0.24)(react-dom@19.2.6(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) + '@expo/config': 55.0.17(typescript@5.9.3) + '@expo/config-plugins': 55.0.9 '@expo/devtools': 55.0.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.6))(react@19.2.6) '@expo/fingerprint': 0.16.7 - '@expo/local-build-cache-provider': 55.0.12(typescript@5.9.3) - '@expo/log-box': 55.0.12(@expo/dom-webview@55.0.5)(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) + '@expo/local-build-cache-provider': 55.0.13(typescript@5.9.3) + '@expo/log-box': 55.0.12(@expo/dom-webview@55.0.5)(expo@55.0.24)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) '@expo/metro': 55.1.1 - '@expo/metro-config': 55.0.20(expo@55.0.23)(typescript@5.9.3) + '@expo/metro-config': 55.0.21(expo@55.0.24)(typescript@5.9.3) '@expo/vector-icons': 15.1.1(expo-font@55.0.7)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) '@ungap/structured-clone': 1.3.1 - babel-preset-expo: 55.0.21(@babel/core@7.29.0)(@babel/runtime@7.29.2)(expo@55.0.23)(react-refresh@0.14.2) - expo-asset: 55.0.17(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)(typescript@5.9.3) - expo-constants: 55.0.16(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6)) - expo-file-system: 55.0.19(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6)) - expo-font: 55.0.7(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) - expo-keep-awake: 55.0.8(expo@55.0.23)(react@19.2.6) - expo-modules-autolinking: 55.0.21(typescript@5.9.3) + babel-preset-expo: 55.0.21(@babel/core@7.29.0)(@babel/runtime@7.29.2)(expo@55.0.24)(react-refresh@0.14.2) + expo-asset: 55.0.17(expo@55.0.24)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6)(typescript@5.9.3) + expo-constants: 55.0.16(expo@55.0.24)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6)) + expo-file-system: 55.0.20(expo@55.0.24)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6)) + expo-font: 55.0.7(expo@55.0.24)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) + expo-keep-awake: 55.0.8(expo@55.0.24)(react@19.2.6) + expo-modules-autolinking: 55.0.22(typescript@5.9.3) expo-modules-core: 55.0.25(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.6))(react@19.2.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.6))(react@19.2.6) pretty-format: 29.7.0 react: 19.2.6 @@ -13131,8 +13279,8 @@ snapshots: react-refresh: 0.14.2 whatwg-url-minimum: 0.1.2 optionalDependencies: - '@expo/dom-webview': 55.0.5(expo@55.0.23)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) - '@expo/metro-runtime': 55.0.11(@expo/dom-webview@55.0.5)(expo@55.0.23)(react-dom@19.2.6(react@19.2.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.6))(react@19.2.6) + '@expo/dom-webview': 55.0.5(expo@55.0.24)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.6))(react@19.2.6) + '@expo/metro-runtime': 55.0.11(@expo/dom-webview@55.0.5)(expo@55.0.24)(react-dom@19.2.6(react@19.2.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.6))(react@19.2.6) transitivePeerDependencies: - '@babel/core' - bufferutil @@ -13147,7 +13295,7 @@ snapshots: exponential-backoff@3.1.3: {} - express@4.22.1: + express@4.22.2: dependencies: accepts: 1.3.8 array-flatten: 1.1.1 @@ -13170,7 +13318,7 @@ snapshots: parseurl: 1.3.3 path-to-regexp: 0.1.13 proxy-addr: 2.0.7 - qs: 6.14.2 + qs: 6.15.2 range-parser: 1.2.1 safe-buffer: 5.2.1 send: 0.19.2 @@ -13488,6 +13636,10 @@ snapshots: optionalDependencies: typescript: 5.9.3 + i18next@26.2.0(typescript@5.9.3): + optionalDependencies: + typescript: 5.9.3 + iconv-lite@0.4.24: dependencies: safer-buffer: 2.1.2 @@ -13644,7 +13796,7 @@ snapshots: '@jest/expect': 29.7.0 '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 25.6.2 + '@types/node': 25.8.0 chalk: 4.1.2 co: 4.6.0 dedent: 1.7.2 @@ -13664,16 +13816,16 @@ snapshots: - babel-plugin-macros - supports-color - jest-cli@29.7.0(@types/node@25.6.2): + jest-cli@29.7.0(@types/node@25.8.0): dependencies: '@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.6.2) + create-jest: 29.7.0(@types/node@25.8.0) exit: 0.1.2 import-local: 3.2.0 - jest-config: 29.7.0(@types/node@25.6.2) + jest-config: 29.7.0(@types/node@25.8.0) jest-util: 29.7.0 jest-validate: 29.7.0 yargs: 17.7.2 @@ -13683,7 +13835,7 @@ snapshots: - supports-color - ts-node - jest-config@29.7.0(@types/node@25.6.2): + jest-config@29.7.0(@types/node@25.8.0): dependencies: '@babel/core': 7.29.0 '@jest/test-sequencer': 29.7.0 @@ -13708,7 +13860,7 @@ snapshots: slash: 3.0.0 strip-json-comments: 3.1.1 optionalDependencies: - '@types/node': 25.6.2 + '@types/node': 25.8.0 transitivePeerDependencies: - babel-plugin-macros - supports-color @@ -13745,7 +13897,7 @@ snapshots: '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 '@types/jsdom': 20.0.1 - '@types/node': 25.6.2 + '@types/node': 25.8.0 jest-mock: 29.7.0 jest-util: 29.7.0 jsdom: 20.0.3(canvas@3.2.3) @@ -13761,22 +13913,22 @@ snapshots: '@jest/environment': 29.7.0 '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 25.6.2 + '@types/node': 25.8.0 jest-mock: 29.7.0 jest-util: 29.7.0 - jest-expo@55.0.17(@babel/core@7.29.0)(canvas@3.2.3)(expo@55.0.23)(jest@29.7.0(@types/node@25.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.6))(react@19.2.6)(typescript@5.9.3): + jest-expo@55.0.17(@babel/core@7.29.0)(canvas@3.2.3)(expo@55.0.24)(jest@29.7.0(@types/node@25.8.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.6))(react@19.2.6)(typescript@5.9.3): dependencies: '@expo/config': 55.0.16(typescript@5.9.3) '@expo/json-file': 10.0.14 '@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.23(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) + expo: 55.0.24(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.11)(expo-router@55.0.14)(react-dom@19.2.6(react@19.2.6))(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.6))(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) jest-environment-jsdom: 29.7.0(canvas@3.2.3) 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.6.2)) + jest-watch-typeahead: 2.2.1(jest@29.7.0(@types/node@25.8.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.6) @@ -13799,7 +13951,7 @@ snapshots: dependencies: '@jest/types': 29.6.3 '@types/graceful-fs': 4.1.9 - '@types/node': 25.6.2 + '@types/node': 25.8.0 anymatch: 3.1.3 fb-watchman: 2.0.2 graceful-fs: 4.2.11 @@ -13845,7 +13997,7 @@ snapshots: jest-mock@29.7.0: dependencies: '@jest/types': 29.6.3 - '@types/node': 25.6.2 + '@types/node': 25.8.0 jest-util: 29.7.0 jest-pnp-resolver@1.2.3(jest-resolve@29.7.0): @@ -13880,7 +14032,7 @@ snapshots: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 25.6.2 + '@types/node': 25.8.0 chalk: 4.1.2 emittery: 0.13.1 graceful-fs: 4.2.11 @@ -13908,7 +14060,7 @@ snapshots: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 25.6.2 + '@types/node': 25.8.0 chalk: 4.1.2 cjs-module-lexer: 1.4.3 collect-v8-coverage: 1.0.3 @@ -13954,7 +14106,7 @@ snapshots: jest-util@29.7.0: dependencies: '@jest/types': 29.6.3 - '@types/node': 25.6.2 + '@types/node': 25.8.0 chalk: 4.1.2 ci-info: 3.9.0 graceful-fs: 4.2.11 @@ -13975,11 +14127,11 @@ snapshots: chalk: 3.0.0 prompts: 2.4.2 - jest-watch-typeahead@2.2.1(jest@29.7.0(@types/node@25.6.2)): + jest-watch-typeahead@2.2.1(jest@29.7.0(@types/node@25.8.0)): dependencies: ansi-escapes: 6.2.1 chalk: 4.1.2 - jest: 29.7.0(@types/node@25.6.2) + jest: 29.7.0(@types/node@25.8.0) jest-regex-util: 29.6.3 jest-watcher: 29.7.0 slash: 5.1.0 @@ -13990,7 +14142,7 @@ snapshots: dependencies: '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 25.6.2 + '@types/node': 25.8.0 ansi-escapes: 4.3.2 chalk: 4.1.2 emittery: 0.13.1 @@ -13999,17 +14151,17 @@ snapshots: jest-worker@29.7.0: dependencies: - '@types/node': 25.6.2 + '@types/node': 25.8.0 jest-util: 29.7.0 merge-stream: 2.0.0 supports-color: 8.1.1 - jest@29.7.0(@types/node@25.6.2): + jest@29.7.0(@types/node@25.8.0): dependencies: '@jest/core': 29.7.0 '@jest/types': 29.6.3 import-local: 3.2.0 - jest-cli: 29.7.0(@types/node@25.6.2) + jest-cli: 29.7.0(@types/node@25.8.0) transitivePeerDependencies: - '@types/node' - babel-plugin-macros @@ -14063,7 +14215,7 @@ snapshots: whatwg-encoding: 2.0.0 whatwg-mimetype: 3.0.0 whatwg-url: 11.0.0 - ws: 8.20.0 + ws: 8.20.1 xml-name-validator: 4.0.0 optionalDependencies: canvas: 3.2.3 @@ -14333,7 +14485,7 @@ snapshots: metro-cache: 0.83.7 metro-core: 0.83.7 metro-runtime: 0.83.7 - yaml: 2.8.4 + yaml: 2.9.0 transitivePeerDependencies: - bufferutil - supports-color @@ -14348,7 +14500,7 @@ snapshots: metro-cache: 0.84.4 metro-core: 0.84.4 metro-runtime: 0.84.4 - yaml: 2.8.4 + yaml: 2.9.0 transitivePeerDependencies: - bufferutil - supports-color @@ -14724,7 +14876,7 @@ snapshots: node-int64@0.4.0: {} - node-releases@2.0.38: {} + node-releases@2.0.44: {} nodemailer@8.0.7: {} @@ -14989,11 +15141,11 @@ snapshots: exsolve: 1.0.8 pathe: 2.0.3 - playwright-core@1.59.1: {} + playwright-core@1.60.0: {} - playwright@1.59.1: + playwright@1.60.0: dependencies: - playwright-core: 1.59.1 + playwright-core: 1.60.0 optionalDependencies: fsevents: 2.3.2 @@ -15128,11 +15280,7 @@ snapshots: pvutils@1.1.5: {} - qs@6.14.2: - dependencies: - side-channel: 1.1.0 - - qs@6.15.1: + qs@6.15.2: dependencies: side-channel: 1.1.0 @@ -15209,6 +15357,18 @@ 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.6) typescript: 5.9.3 + react-i18next@17.0.8(i18next@26.2.0(typescript@5.9.3))(react-dom@19.2.6(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3): + dependencies: + '@babel/runtime': 7.29.2 + html-parse-stringify: 3.0.1 + i18next: 26.2.0(typescript@5.9.3) + react: 19.2.6 + use-sync-external-store: 1.6.0(react@19.2.6) + optionalDependencies: + react-dom: 19.2.6(react@19.2.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.6) + typescript: 5.9.3 + react-is@16.13.1: {} react-is@17.0.2: {} @@ -15251,7 +15411,7 @@ snapshots: react: 19.2.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.6) - react-native-screens@4.24.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.6))(react@19.2.6): + react-native-screens@4.25.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.6))(react@19.2.6): dependencies: react: 19.2.6 react-freeze: 1.0.4(react@19.2.6) @@ -15347,7 +15507,7 @@ snapshots: optionalDependencies: '@types/react': 19.2.14 - react-router@7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6): + react-router@7.15.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6): dependencies: cookie: 1.1.1 react: 19.2.6 @@ -15489,35 +15649,35 @@ snapshots: '@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.17 '@rolldown/binding-win32-x64-msvc': 1.0.0-rc.17 - rollup@4.60.3: + rollup@4.60.4: dependencies: '@types/estree': 1.0.8 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.60.3 - '@rollup/rollup-android-arm64': 4.60.3 - '@rollup/rollup-darwin-arm64': 4.60.3 - '@rollup/rollup-darwin-x64': 4.60.3 - '@rollup/rollup-freebsd-arm64': 4.60.3 - '@rollup/rollup-freebsd-x64': 4.60.3 - '@rollup/rollup-linux-arm-gnueabihf': 4.60.3 - '@rollup/rollup-linux-arm-musleabihf': 4.60.3 - '@rollup/rollup-linux-arm64-gnu': 4.60.3 - '@rollup/rollup-linux-arm64-musl': 4.60.3 - '@rollup/rollup-linux-loong64-gnu': 4.60.3 - '@rollup/rollup-linux-loong64-musl': 4.60.3 - '@rollup/rollup-linux-ppc64-gnu': 4.60.3 - '@rollup/rollup-linux-ppc64-musl': 4.60.3 - '@rollup/rollup-linux-riscv64-gnu': 4.60.3 - '@rollup/rollup-linux-riscv64-musl': 4.60.3 - '@rollup/rollup-linux-s390x-gnu': 4.60.3 - '@rollup/rollup-linux-x64-gnu': 4.60.3 - '@rollup/rollup-linux-x64-musl': 4.60.3 - '@rollup/rollup-openbsd-x64': 4.60.3 - '@rollup/rollup-openharmony-arm64': 4.60.3 - '@rollup/rollup-win32-arm64-msvc': 4.60.3 - '@rollup/rollup-win32-ia32-msvc': 4.60.3 - '@rollup/rollup-win32-x64-gnu': 4.60.3 - '@rollup/rollup-win32-x64-msvc': 4.60.3 + '@rollup/rollup-android-arm-eabi': 4.60.4 + '@rollup/rollup-android-arm64': 4.60.4 + '@rollup/rollup-darwin-arm64': 4.60.4 + '@rollup/rollup-darwin-x64': 4.60.4 + '@rollup/rollup-freebsd-arm64': 4.60.4 + '@rollup/rollup-freebsd-x64': 4.60.4 + '@rollup/rollup-linux-arm-gnueabihf': 4.60.4 + '@rollup/rollup-linux-arm-musleabihf': 4.60.4 + '@rollup/rollup-linux-arm64-gnu': 4.60.4 + '@rollup/rollup-linux-arm64-musl': 4.60.4 + '@rollup/rollup-linux-loong64-gnu': 4.60.4 + '@rollup/rollup-linux-loong64-musl': 4.60.4 + '@rollup/rollup-linux-ppc64-gnu': 4.60.4 + '@rollup/rollup-linux-ppc64-musl': 4.60.4 + '@rollup/rollup-linux-riscv64-gnu': 4.60.4 + '@rollup/rollup-linux-riscv64-musl': 4.60.4 + '@rollup/rollup-linux-s390x-gnu': 4.60.4 + '@rollup/rollup-linux-x64-gnu': 4.60.4 + '@rollup/rollup-linux-x64-musl': 4.60.4 + '@rollup/rollup-openbsd-x64': 4.60.4 + '@rollup/rollup-openharmony-arm64': 4.60.4 + '@rollup/rollup-win32-arm64-msvc': 4.60.4 + '@rollup/rollup-win32-ia32-msvc': 4.60.4 + '@rollup/rollup-win32-x64-gnu': 4.60.4 + '@rollup/rollup-win32-x64-msvc': 4.60.4 fsevents: 2.3.3 rtl-detect@1.1.2: {} @@ -15526,8 +15686,6 @@ snapshots: dependencies: queue-microtask: 1.2.3 - rw@1.3.3: {} - safe-buffer@5.1.2: {} safe-buffer@5.2.1: {} @@ -15877,7 +16035,7 @@ snapshots: tinybench@2.9.0: {} - tinyexec@1.1.1: {} + tinyexec@1.1.2: {} tinyglobby@0.2.16: dependencies: @@ -15953,14 +16111,14 @@ snapshots: safe-buffer: 5.2.1 optional: true - turbo@2.9.12: + turbo@2.9.14: optionalDependencies: - '@turbo/darwin-64': 2.9.12 - '@turbo/darwin-arm64': 2.9.12 - '@turbo/linux-64': 2.9.12 - '@turbo/linux-arm64': 2.9.12 - '@turbo/windows-64': 2.9.12 - '@turbo/windows-arm64': 2.9.12 + '@turbo/darwin-64': 2.9.14 + '@turbo/darwin-arm64': 2.9.14 + '@turbo/linux-64': 2.9.14 + '@turbo/linux-arm64': 2.9.14 + '@turbo/windows-64': 2.9.14 + '@turbo/windows-arm64': 2.9.14 type-check@0.4.0: dependencies: @@ -15981,13 +16139,13 @@ snapshots: media-typer: 0.3.0 mime-types: 2.1.35 - typescript-eslint@8.59.2(eslint@10.3.0(jiti@2.7.0))(typescript@5.9.3): + typescript-eslint@8.59.3(eslint@10.4.0(jiti@2.7.0))(typescript@5.9.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.59.2(@typescript-eslint/parser@8.59.2(eslint@10.3.0(jiti@2.7.0))(typescript@5.9.3))(eslint@10.3.0(jiti@2.7.0))(typescript@5.9.3) - '@typescript-eslint/parser': 8.59.2(eslint@10.3.0(jiti@2.7.0))(typescript@5.9.3) - '@typescript-eslint/typescript-estree': 8.59.2(typescript@5.9.3) - '@typescript-eslint/utils': 8.59.2(eslint@10.3.0(jiti@2.7.0))(typescript@5.9.3) - eslint: 10.3.0(jiti@2.7.0) + '@typescript-eslint/eslint-plugin': 8.59.3(@typescript-eslint/parser@8.59.3(eslint@10.4.0(jiti@2.7.0))(typescript@5.9.3))(eslint@10.4.0(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/parser': 8.59.3(eslint@10.4.0(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/typescript-estree': 8.59.3(typescript@5.9.3) + '@typescript-eslint/utils': 8.59.3(eslint@10.4.0(jiti@2.7.0))(typescript@5.9.3) + eslint: 10.4.0(jiti@2.7.0) typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -16002,6 +16160,8 @@ snapshots: undici-types@7.19.2: {} + undici-types@7.24.6: {} + undici@6.25.0: {} undici@7.25.0: {} @@ -16047,7 +16207,7 @@ snapshots: dependencies: react: 19.2.6 - use-latest-callback@0.3.3(react@19.2.6): + use-latest-callback@0.3.4(react@19.2.6): dependencies: react: 19.2.6 @@ -16093,13 +16253,13 @@ snapshots: - '@types/react' - '@types/react-dom' - vite-node@3.2.4(@types/node@25.6.2)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4): + vite-node@3.2.4(@types/node@25.8.0)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0): dependencies: cac: 6.7.14 debug: 4.4.3 es-module-lexer: 1.7.0 pathe: 2.0.3 - vite: 7.3.3(@types/node@25.6.2)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4) + vite: 7.3.3(@types/node@25.8.0)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0) transitivePeerDependencies: - '@types/node' - jiti @@ -16114,24 +16274,24 @@ snapshots: - tsx - yaml - vite@7.3.3(@types/node@25.6.2)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4): + vite@7.3.3(@types/node@25.8.0)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0): dependencies: esbuild: 0.27.7 fdir: 6.5.0(picomatch@4.0.4) picomatch: 4.0.4 postcss: 8.5.14 - rollup: 4.60.3 + rollup: 4.60.4 tinyglobby: 0.2.16 optionalDependencies: - '@types/node': 25.6.2 + '@types/node': 25.8.0 fsevents: 2.3.3 jiti: 2.7.0 lightningcss: 1.32.0 terser: 5.47.1 tsx: 4.21.0 - yaml: 2.8.4 + yaml: 2.9.0 - vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4): + vite@8.0.10(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0): dependencies: lightningcss: 1.32.0 picomatch: 4.0.4 @@ -16139,23 +16299,23 @@ snapshots: rolldown: 1.0.0-rc.17 tinyglobby: 0.2.16 optionalDependencies: - '@types/node': 25.6.2 + '@types/node': 25.8.0 esbuild: 0.27.7 fsevents: 2.3.3 jiti: 2.7.0 terser: 5.47.1 tsx: 4.21.0 - yaml: 2.8.4 + yaml: 2.9.0 - vitest@4.1.5(@opentelemetry/api@1.9.1)(@types/node@25.6.2)(@vitest/browser-playwright@4.1.5)(jsdom@29.1.1(canvas@3.2.3))(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4)): + vitest@4.1.6(@opentelemetry/api@1.9.1)(@types/node@25.8.0)(@vitest/browser-playwright@4.1.6)(jsdom@29.1.1(canvas@3.2.3))(vite@8.0.10(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0)): dependencies: - '@vitest/expect': 4.1.5 - '@vitest/mocker': 4.1.5(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4)) - '@vitest/pretty-format': 4.1.5 - '@vitest/runner': 4.1.5 - '@vitest/snapshot': 4.1.5 - '@vitest/spy': 4.1.5 - '@vitest/utils': 4.1.5 + '@vitest/expect': 4.1.6 + '@vitest/mocker': 4.1.6(vite@8.0.10(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0)) + '@vitest/pretty-format': 4.1.6 + '@vitest/runner': 4.1.6 + '@vitest/snapshot': 4.1.6 + '@vitest/spy': 4.1.6 + '@vitest/utils': 4.1.6 es-module-lexer: 2.1.0 expect-type: 1.3.0 magic-string: 0.30.21 @@ -16164,15 +16324,15 @@ snapshots: picomatch: 4.0.4 std-env: 4.1.0 tinybench: 2.9.0 - tinyexec: 1.1.1 + tinyexec: 1.1.2 tinyglobby: 0.2.16 tinyrainbow: 3.1.0 - vite: 8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4) + vite: 8.0.10(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0) why-is-node-running: 2.3.0 optionalDependencies: '@opentelemetry/api': 1.9.1 - '@types/node': 25.6.2 - '@vitest/browser-playwright': 4.1.5(playwright@1.59.1)(vite@8.0.10(@types/node@25.6.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.4))(vitest@4.1.5) + '@types/node': 25.8.0 + '@vitest/browser-playwright': 4.1.6(playwright@1.60.0)(vite@8.0.10(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0))(vitest@4.1.6) jsdom: 29.1.1(canvas@3.2.3) transitivePeerDependencies: - msw @@ -16248,7 +16408,7 @@ snapshots: wkx@0.5.0: dependencies: - '@types/node': 25.6.2 + '@types/node': 25.8.0 word-wrap@1.2.5: {} @@ -16273,7 +16433,7 @@ snapshots: ws@7.5.10: {} - ws@8.20.0: {} + ws@8.20.1: {} xcode@3.0.1: dependencies: @@ -16297,10 +16457,10 @@ snapshots: xtend@4.0.2: {} - y-codemirror.next@0.3.5(@codemirror/state@6.6.0)(@codemirror/view@6.42.1)(yjs@13.6.30): + y-codemirror.next@0.3.5(@codemirror/state@6.6.0)(@codemirror/view@6.43.0)(yjs@13.6.30): dependencies: '@codemirror/state': 6.6.0 - '@codemirror/view': 6.42.1 + '@codemirror/view': 6.43.0 lib0: 0.2.117 yjs: 13.6.30 @@ -16321,6 +16481,8 @@ snapshots: yaml@2.8.4: {} + yaml@2.9.0: {} + yargs-parser@21.1.1: {} yargs@17.7.2: diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 85cd6ff..6315309 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -6,10 +6,10 @@ packages: catalog: react: ^19.2.5 react-dom: ^19.2.6 - react-router: ^7.15.0 - "@react-router/dev": ^7.15.0 - "@react-router/node": ^7.15.0 - "@react-router/serve": ^7.15.0 + react-router: ^7.15.1 + "@react-router/dev": ^7.15.1 + "@react-router/node": ^7.15.1 + "@react-router/serve": ^7.15.1 "@types/react": ^19.2.14 "@types/react-dom": ^19.2.3 tailwindcss: ^4.3.0 @@ -19,8 +19,8 @@ catalog: drizzle-orm: ^0.45.2 drizzle-kit: ^0.31.10 drizzle-postgis: ^1.1.1 - "@sentry/node": ^10.52.0 - "@sentry/react": ^10.52.0 + "@sentry/node": ^10.53.1 + "@sentry/react": ^10.53.1 postgres: ^3.4.9 - "@types/node": ^22.19.18 + "@types/node": ^22.19.19 From f04e9995edc375ca3ea386121c759044952c65b9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 17 May 2026 08:46:41 +0000 Subject: [PATCH 033/319] [github-actions] pnpm dedupe --- pnpm-lock.yaml | 92 ++++---------------------------------------------- 1 file changed, 7 insertions(+), 85 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f5ddbe2..8421878 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -177,7 +177,7 @@ importers: specifier: ^5.0.0 version: 5.0.0(leaflet@1.9.4)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) react-router: - specifier: 7.15.1 + specifier: 'catalog:' version: 7.15.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6) tailwindcss: specifier: 'catalog:' @@ -640,13 +640,13 @@ importers: dependencies: i18next: specifier: '>=26' - version: 26.0.10(typescript@5.9.3) + version: 26.2.0(typescript@5.9.3) react: specifier: ^19.2.5 version: 19.2.6 react-i18next: specifier: '>=17' - version: 17.0.7(i18next@26.0.10(typescript@5.9.3))(react-dom@19.2.6(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) + version: 17.0.8(i18next@26.2.0(typescript@5.9.3))(react-dom@19.2.6(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3) packages/jobs: dependencies: @@ -1818,9 +1818,6 @@ packages: '@expo/config-types@55.0.5': resolution: {integrity: sha512-sCmSUZG4mZ/ySXvfyyBdhjivz8Q539X1NondwDdYG7s3SBsk+wsgPJzYsqgAG/P9+l0xWjUD2F+kQ1cAJ6NNLg==} - '@expo/config@55.0.16': - resolution: {integrity: sha512-H5dpQv5TfyZDNheZAWO3SmP10diGWZwN5QOUsArkDJih0QKNtahQBOmrV2xbhgln/nrUGoy41U/ZIY/MEx63Ug==} - '@expo/config@55.0.17': resolution: {integrity: sha512-Y3VaRg7Jllg3MhlUOTQqHm6/dttsqcjYlnS9enhAllZvPUpTHnRA4YPETtUZlxkdMJy6y3UZe986pd/KfJ6OTg==} @@ -3889,9 +3886,6 @@ packages: '@types/node@22.19.19': resolution: {integrity: sha512-dyh/xO2Fh5bYrfWaaqGrRQQGkNdmYw6AmaAUvYeUMNTWQtvb796ikLdmTchRmOlOiIJ1TDXfWgVx1QkUlQ6Hew==} - '@types/node@25.6.2': - resolution: {integrity: sha512-sokuT28dxf9JT5Kady1fsXOvI4HVpjZa95NKT5y9PNTIrs2AsobR4GFAA90ZG8M+nxVRLysCXsVj6eGC7Vbrlw==} - '@types/node@25.8.0': resolution: {integrity: sha512-TCFSk8IZh+iLX1xtksoBVtdmgL+1IX0fC9BeU4QqFSuNdN/K+HUlhqOzEmSYYpZUVsLYcPqc9KX+60iDuninSQ==} @@ -5589,14 +5583,6 @@ packages: i18next-browser-languagedetector@8.2.1: resolution: {integrity: sha512-bZg8+4bdmaOiApD7N7BPT9W8MLZG+nPTOFlLiJiT8uzKXFjhxw4v2ierCXOwB5sFDMtuA5G4kgYZ0AznZxQ/cw==} - i18next@26.0.10: - resolution: {integrity: sha512-k3yGPAlWR2RdMYoVXJoDZDT87qeHIWKH7gVksdZMpRty7QX/D9QZeYGvN08KGbKHke9wn01eYT+EEsrqX/YTlw==} - peerDependencies: - typescript: ^5 || ^6 - peerDependenciesMeta: - typescript: - optional: true - i18next@26.2.0: resolution: {integrity: sha512-zwBHldHdTmwN7r6UNc7lC6GWNN+YYg3DrRSeHR5PRRBf5QnJZcYHrQc0uaU26qZeYxR7iFZD+Y315dPnKP47wA==} peerDependencies: @@ -6908,22 +6894,6 @@ packages: peerDependencies: react: ^19.2.5 - react-i18next@17.0.7: - resolution: {integrity: sha512-rwtPXsb/zwzDafN+gytcjF5YnqGQQIRmCQ6DctBC1VSipRB8GD/MWEVrFP42vjMyuYydxWxM8CZRt+yiNuuoHg==} - peerDependencies: - i18next: '>= 26.0.10' - react: ^19.2.5 - react-dom: '*' - react-native: '*' - typescript: ^5 || ^6 - peerDependenciesMeta: - react-dom: - optional: true - react-native: - optional: true - typescript: - optional: true - react-i18next@17.0.8: resolution: {integrity: sha512-0ooKbGLU8JXhe1zwpQUWIeXSgLPOfwJmgheWRIUpcoA0CpyabpGhayjdG+/eA5esC1AQ8h2jWpXjJfzQzeDOCw==} peerDependencies: @@ -7675,9 +7645,6 @@ packages: undici-types@6.21.0: resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} - undici-types@7.19.2: - resolution: {integrity: sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==} - undici-types@7.24.6: resolution: {integrity: sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==} @@ -8108,11 +8075,6 @@ packages: yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - yaml@2.8.4: - resolution: {integrity: sha512-ml/JPOj9fOQK8RNnWojA67GbZ0ApXAUlN2UQclwv2eVgTgn7O9gg9o7paZWKMp4g0H3nTLtS9LVzhkpOFIKzog==} - engines: {node: '>= 14.6'} - hasBin: true - yaml@2.9.0: resolution: {integrity: sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==} engines: {node: '>= 14.6'} @@ -9237,22 +9199,6 @@ snapshots: '@expo/config-types@55.0.5': {} - '@expo/config@55.0.16(typescript@5.9.3)': - dependencies: - '@expo/config-plugins': 55.0.9 - '@expo/config-types': 55.0.5 - '@expo/json-file': 10.0.14 - '@expo/require-utils': 55.0.5(typescript@5.9.3) - deepmerge: 4.3.1 - getenv: 2.0.0 - glob: 13.0.6 - resolve-workspace-root: 2.0.1 - semver: 7.8.0 - slugify: 1.6.9 - transitivePeerDependencies: - - supports-color - - typescript - '@expo/config@55.0.17(typescript@5.9.3)': dependencies: '@expo/config-plugins': 55.0.9 @@ -9517,7 +9463,7 @@ snapshots: fast-glob: 3.3.3 ora: 8.2.0 posthog-node: 5.33.4 - yaml: 2.8.4 + yaml: 2.9.0 zod: 4.4.3 transitivePeerDependencies: - '@types/node' @@ -11749,17 +11695,13 @@ snapshots: dependencies: undici-types: 6.21.0 - '@types/node@25.6.2': - dependencies: - undici-types: 7.19.2 - '@types/node@25.8.0': dependencies: undici-types: 7.24.6 '@types/nodemailer@8.0.0': dependencies: - '@types/node': 25.6.2 + '@types/node': 25.8.0 '@types/pg-pool@2.0.7': dependencies: @@ -11793,7 +11735,7 @@ snapshots: '@types/ws@8.18.1': dependencies: - '@types/node': 25.6.2 + '@types/node': 25.8.0 '@types/yargs-parser@21.0.3': {} @@ -13632,10 +13574,6 @@ snapshots: dependencies: '@babel/runtime': 7.29.2 - i18next@26.0.10(typescript@5.9.3): - optionalDependencies: - typescript: 5.9.3 - i18next@26.2.0(typescript@5.9.3): optionalDependencies: typescript: 5.9.3 @@ -13919,7 +13857,7 @@ snapshots: jest-expo@55.0.17(@babel/core@7.29.0)(canvas@3.2.3)(expo@55.0.24)(jest@29.7.0(@types/node@25.8.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.6))(react@19.2.6)(typescript@5.9.3): dependencies: - '@expo/config': 55.0.16(typescript@5.9.3) + '@expo/config': 55.0.17(typescript@5.9.3) '@expo/json-file': 10.0.14 '@jest/create-cache-key-function': 29.7.0 '@jest/globals': 29.7.0 @@ -15345,18 +15283,6 @@ snapshots: dependencies: react: 19.2.6 - react-i18next@17.0.7(i18next@26.0.10(typescript@5.9.3))(react-dom@19.2.6(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3): - dependencies: - '@babel/runtime': 7.29.2 - html-parse-stringify: 3.0.1 - i18next: 26.0.10(typescript@5.9.3) - react: 19.2.6 - use-sync-external-store: 1.6.0(react@19.2.6) - optionalDependencies: - react-dom: 19.2.6(react@19.2.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.6) - typescript: 5.9.3 - react-i18next@17.0.8(i18next@26.2.0(typescript@5.9.3))(react-dom@19.2.6(react@19.2.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.6))(react@19.2.6)(typescript@5.9.3): dependencies: '@babel/runtime': 7.29.2 @@ -16158,8 +16084,6 @@ snapshots: undici-types@6.21.0: {} - undici-types@7.19.2: {} - undici-types@7.24.6: {} undici@6.25.0: {} @@ -16479,8 +16403,6 @@ snapshots: yallist@3.1.1: {} - yaml@2.8.4: {} - yaml@2.9.0: {} yargs-parser@21.1.1: {} From 9d4c7d2b4163ec05eac5eda5fc676335a877a4f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Sun, 17 May 2026 20:38:07 +0200 Subject: [PATCH 034/319] Archive staging-environments change; update local-dev spec Staging environments are live and fully operational. Marks the remaining verification tasks complete, syncs the delta spec to main specs, and archives the change. Also adds a "When to Use Local vs. Staging" reference table to the local-dev-environment spec so the boundary between the two environments is documented in one place. Co-Authored-By: Claude Sonnet 4.6 --- .../.openspec.yaml | 0 .../design.md | 0 .../proposal.md | 0 .../specs/infrastructure/spec.md | 0 .../specs/staging-environment/spec.md | 0 .../2026-05-17-staging-environments}/tasks.md | 6 +- openspec/specs/local-dev-environment/spec.md | 12 ++++ openspec/specs/staging-environment/spec.md | 55 +++++++++++++++++++ 8 files changed, 70 insertions(+), 3 deletions(-) rename openspec/changes/{staging-environments => archive/2026-05-17-staging-environments}/.openspec.yaml (100%) rename openspec/changes/{staging-environments => archive/2026-05-17-staging-environments}/design.md (100%) rename openspec/changes/{staging-environments => archive/2026-05-17-staging-environments}/proposal.md (100%) rename openspec/changes/{staging-environments => archive/2026-05-17-staging-environments}/specs/infrastructure/spec.md (100%) rename openspec/changes/{staging-environments => archive/2026-05-17-staging-environments}/specs/staging-environment/spec.md (100%) rename openspec/changes/{staging-environments => archive/2026-05-17-staging-environments}/tasks.md (93%) create mode 100644 openspec/specs/staging-environment/spec.md diff --git a/openspec/changes/staging-environments/.openspec.yaml b/openspec/changes/archive/2026-05-17-staging-environments/.openspec.yaml similarity index 100% rename from openspec/changes/staging-environments/.openspec.yaml rename to openspec/changes/archive/2026-05-17-staging-environments/.openspec.yaml diff --git a/openspec/changes/staging-environments/design.md b/openspec/changes/archive/2026-05-17-staging-environments/design.md similarity index 100% rename from openspec/changes/staging-environments/design.md rename to openspec/changes/archive/2026-05-17-staging-environments/design.md diff --git a/openspec/changes/staging-environments/proposal.md b/openspec/changes/archive/2026-05-17-staging-environments/proposal.md similarity index 100% rename from openspec/changes/staging-environments/proposal.md rename to openspec/changes/archive/2026-05-17-staging-environments/proposal.md diff --git a/openspec/changes/staging-environments/specs/infrastructure/spec.md b/openspec/changes/archive/2026-05-17-staging-environments/specs/infrastructure/spec.md similarity index 100% rename from openspec/changes/staging-environments/specs/infrastructure/spec.md rename to openspec/changes/archive/2026-05-17-staging-environments/specs/infrastructure/spec.md diff --git a/openspec/changes/staging-environments/specs/staging-environment/spec.md b/openspec/changes/archive/2026-05-17-staging-environments/specs/staging-environment/spec.md similarity index 100% rename from openspec/changes/staging-environments/specs/staging-environment/spec.md rename to openspec/changes/archive/2026-05-17-staging-environments/specs/staging-environment/spec.md diff --git a/openspec/changes/staging-environments/tasks.md b/openspec/changes/archive/2026-05-17-staging-environments/tasks.md similarity index 93% rename from openspec/changes/staging-environments/tasks.md rename to openspec/changes/archive/2026-05-17-staging-environments/tasks.md index e46ade3..887b095 100644 --- a/openspec/changes/staging-environments/tasks.md +++ b/openspec/changes/archive/2026-05-17-staging-environments/tasks.md @@ -8,7 +8,7 @@ - [x] 2.1 Create `infrastructure/docker-compose.staging.yml` with staging journal (port 3100), planner (port 3101), memory limits (256MB), and `trails_staging` database URL - [x] 2.2 Create `infrastructure/staging.env.template` documenting required staging environment variables (DOMAIN, DATABASE_URL, JWT_SECRET, SESSION_SECRET) - [x] 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 +- [x] 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 @@ -16,7 +16,7 @@ - [x] 3.2 Add `planner.staging.trails.cool` site block proxying to planner on port 3101 - [x] 3.3 Add `import sites/*.caddyfile` to the main Caddyfile so per-PR site blocks can be dropped in and picked up on reload - [x] 3.4 Define the per-PR Caddyfile snippet template the cd-staging workflow writes for each preview (host = `pr-.staging.trails.cool`, upstream = `host.docker.internal:`, port = `3200 + 2N`) -- [ ] 3.5 Reload Caddy and verify staging routes work with `curl -sf https://staging.trails.cool/api/health` +- [x] 3.5 Reload Caddy and verify staging routes work with `curl -sf https://staging.trails.cool/api/health` ## 4. GitHub Actions Workflow @@ -30,7 +30,7 @@ - [x] 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 - [x] 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 +- [x] 5.3 Test full lifecycle: open a test PR → verify preview deploys → push a commit → verify preview updates → close PR → verify teardown ## 6. Documentation diff --git a/openspec/specs/local-dev-environment/spec.md b/openspec/specs/local-dev-environment/spec.md index e9de720..53853c0 100644 --- a/openspec/specs/local-dev-environment/spec.md +++ b/openspec/specs/local-dev-environment/spec.md @@ -2,6 +2,18 @@ One-command local development setup with PostgreSQL, BRouter, automatic schema migration, and segment downloading. +## When to Use Local vs. Staging + +| Scenario | Use | +|----------|-----| +| Everyday development, unit tests, E2E tests | Local (`pnpm dev:full`) | +| Sharing a work-in-progress with reviewers | PR preview (`pr-.staging.trails.cool`) | +| Testing against production-like infra (Caddy TLS, Docker networking) | Staging (`staging.trails.cool`) | +| Wahoo OAuth callback testing | Local with `HTTPS=1` (see CLAUDE.md) | +| ActivityPub federation testing | Staging (requires real HTTPS + public domain) | + +The Planner, Journal, PostgreSQL, and BRouter all run locally. The local stack is the default for all development work. Staging is not a replacement for local dev — it is a pre-merge verification surface and a way to share work without merging first. + ## Requirements ### Requirement: One-command dev startup diff --git a/openspec/specs/staging-environment/spec.md b/openspec/specs/staging-environment/spec.md new file mode 100644 index 0000000..5d9541e --- /dev/null +++ b/openspec/specs/staging-environment/spec.md @@ -0,0 +1,55 @@ +## 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 From 0e77ac7831bac0308d1dbdd71c78b49600f137c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Sun, 17 May 2026 20:41:03 +0200 Subject: [PATCH 035/319] Update local-dev-stack proposal: staging now exists Co-Authored-By: Claude Sonnet 4.6 --- openspec/changes/local-dev-stack/proposal.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/openspec/changes/local-dev-stack/proposal.md b/openspec/changes/local-dev-stack/proposal.md index 14a66a0..1aac619 100644 --- a/openspec/changes/local-dev-stack/proposal.md +++ b/openspec/changes/local-dev-stack/proposal.md @@ -1,12 +1,12 @@ ## Why -There is no staging environment — production is the only deployed instance. Infra -changes (Prometheus alerts, Caddy config, Grafana dashboards) go straight to prod -with no way to validate them locally first. Meanwhile, CI E2E tests skip ~15 of -20 tests because there is no PostgreSQL service in the workflow, and BRouter was -only recently added to CI with manual setup instead of reusing the dev compose -file. The existing `docker-compose.dev.yml` covers PostgreSQL and BRouter but -nothing else from the production stack. +Infra changes (Prometheus alerts, Caddy config, Grafana dashboards) can only be +validated against staging or production — there is no way to test them locally +first. Meanwhile, CI E2E tests skip ~15 of 20 tests because there is no +PostgreSQL service in the workflow, and BRouter was only recently added to CI +with manual setup instead of reusing the dev compose file. The existing +`docker-compose.dev.yml` covers PostgreSQL and BRouter but nothing else from the +production stack. ## What Changes From 61b787ca84f9bd08b2d956ec677dec1f062b8247 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Sun, 17 May 2026 20:43:00 +0200 Subject: [PATCH 036/319] Fix staging-environment spec: add missing Purpose section Co-Authored-By: Claude Sonnet 4.6 --- openspec/specs/staging-environment/spec.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/openspec/specs/staging-environment/spec.md b/openspec/specs/staging-environment/spec.md index 5d9541e..7cfd58e 100644 --- a/openspec/specs/staging-environment/spec.md +++ b/openspec/specs/staging-environment/spec.md @@ -1,3 +1,7 @@ +## Purpose + +Production-like staging and ephemeral PR preview environments running alongside production on the flagship server, enabling integration testing before merge and live URL sharing with reviewers. + ## Requirements ### Requirement: Persistent staging instance From 10e0a8d41a152f62207ecfb5384e4bfbccddc8a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Sun, 17 May 2026 20:49:06 +0200 Subject: [PATCH 037/319] Local dev stack improvements - Extend docker-compose.dev.yml with optional monitoring profile (Prometheus, Grafana, Loki) via --profile monitoring - Align dev PostgreSQL with production: pg_stat_statements + init scripts - Add scripts/seed.ts with idempotent Berlin test data (user, route, activity) - Add pnpm db:seed and pnpm dev:reset scripts - Simplify CI e2e job: replace manual docker run + BRouter setup with docker compose up --wait; add db:seed step - Improve scripts/dev.sh: Docker check, --wait health checks, --monitoring flag, seed step - Add scripts/reset-dev.sh to wipe and restart the local stack - Add .env.development.example with documented local defaults Co-Authored-By: Claude Sonnet 4.6 --- .env.development.example | 10 +++ .github/workflows/ci.yml | 74 +++-------------------- .gitignore | 1 + docker-compose.ci.yml | 4 ++ docker-compose.dev.yml | 38 ++++++++++++ openspec/changes/local-dev-stack/tasks.md | 26 ++++---- package.json | 2 + scripts/dev.sh | 61 +++++++++++-------- scripts/reset-dev.sh | 26 ++++++++ scripts/seed.ts | 72 ++++++++++++++++++++++ 10 files changed, 209 insertions(+), 105 deletions(-) create mode 100644 .env.development.example create mode 100644 docker-compose.ci.yml create mode 100755 scripts/reset-dev.sh create mode 100644 scripts/seed.ts diff --git a/.env.development.example b/.env.development.example new file mode 100644 index 0000000..4b73c10 --- /dev/null +++ b/.env.development.example @@ -0,0 +1,10 @@ +# Root-level local dev defaults. +# Copy to `.env.development` (gitignored) to override. +# All values here work out of the box — no changes needed for standard local dev. + +DATABASE_URL=postgres://trails:trails@localhost:5432/trails +BROUTER_URL=http://localhost:17777 + +# Change these for any environment that is not purely local. +JWT_SECRET=dev-secret-not-for-production +SESSION_SECRET=dev-secret-not-for-production diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6d12af6..bd213d8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -191,58 +191,6 @@ jobs: cache: pnpm - run: pnpm install --frozen-lockfile - - name: Cache PostGIS Docker image - id: postgis-cache - uses: actions/cache@v5 - with: - path: /tmp/postgis-image.tar - key: postgis-16-3.4 - - - name: Load or pull PostGIS image - run: | - if [ -f /tmp/postgis-image.tar ]; then - docker load < /tmp/postgis-image.tar - else - docker pull postgis/postgis:16-3.4 - docker save postgis/postgis:16-3.4 > /tmp/postgis-image.tar - fi - - - name: Start PostgreSQL - run: | - docker run -d --name postgres \ - -e POSTGRES_USER=trails \ - -e POSTGRES_PASSWORD=trails \ - -e POSTGRES_DB=trails \ - -p 5432:5432 \ - postgis/postgis:16-3.4 - # Wait for pg_isready - for i in $(seq 1 30); do - docker exec postgres pg_isready -U trails > /dev/null 2>&1 && break - sleep 1 - done - # Wait for PostGIS extension to be ready - for i in $(seq 1 10); do - docker exec postgres psql -U trails -c "SELECT PostGIS_Version();" > /dev/null 2>&1 && break - sleep 1 - done - - - name: Push database schema - run: pnpm db:push - - - name: Build and cache BRouter - id: brouter-cache - uses: actions/cache@v5 - with: - path: /tmp/brouter - key: brouter-1.7.8 - - - name: Download BRouter - if: steps.brouter-cache.outputs.cache-hit != 'true' - run: | - mkdir -p /tmp/brouter - wget -q "https://github.com/abrensch/brouter/releases/download/v1.7.8/brouter-1.7.8.zip" -O /tmp/brouter/brouter.zip - cd /tmp/brouter && unzip -o brouter.zip && mv brouter-1.7.8/* . && rmdir brouter-1.7.8 && rm brouter.zip - - name: Cache BRouter segment id: segment-cache uses: actions/cache@v5 @@ -256,23 +204,17 @@ jobs: mkdir -p /tmp/brouter-segments wget -q "https://brouter.de/brouter/segments4/E10_N50.rd5" -O /tmp/brouter-segments/E10_N50.rd5 - - name: Start BRouter - run: | - cd /tmp/brouter - java -Xmx256M -Xms64M \ - -DmaxRunningTime=300 \ - -cp brouter-1.7.8-all.jar \ - btools.server.RouteServer \ - /tmp/brouter-segments profiles2 profiles2 \ - 17777 2 & - # Wait for BRouter to start - for i in $(seq 1 30); do - curl -sf http://localhost:17777/brouter?lonlats=13.4,52.5\|13.5,52.5\&profile=trekking\&format=geojson > /dev/null 2>&1 && break - sleep 2 - done + - name: Start services + run: docker compose -f docker-compose.dev.yml -f docker-compose.ci.yml up -d --wait --build env: BROUTER_URL: http://localhost:17777 + - name: Push database schema + run: pnpm db:push + + - name: Seed database + run: pnpm db:seed + - name: Cache Playwright browsers id: playwright-cache uses: actions/cache@v5 diff --git a/.gitignore b/.gitignore index 58a8d39..85f9417 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ dist/ .crit.json e2e/results/ test-results/ +.env.development playwright-report/ playwright-results.json .claude/worktrees/ diff --git a/docker-compose.ci.yml b/docker-compose.ci.yml new file mode 100644 index 0000000..f900e4b --- /dev/null +++ b/docker-compose.ci.yml @@ -0,0 +1,4 @@ +services: + brouter: + volumes: + - /tmp/brouter-segments:/data/segments diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index f65f243..aa669ad 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -7,8 +7,10 @@ services: POSTGRES_USER: trails POSTGRES_PASSWORD: trails POSTGRES_DB: trails + command: ["postgres", "-c", "shared_preload_libraries=pg_stat_statements"] volumes: - pgdata:/var/lib/postgresql/data + - ./infrastructure/postgres/init-grafana-user.sql:/docker-entrypoint-initdb.d/init-grafana-user.sql:ro healthcheck: test: ["CMD-SHELL", "pg_isready -U trails"] interval: 5s @@ -22,6 +24,42 @@ services: volumes: - brouter_segments:/data/segments + prometheus: + image: prom/prometheus:latest + profiles: [monitoring] + ports: + - "9090:9090" + volumes: + - ./infrastructure/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro + - prometheus_data:/prometheus + + grafana: + image: grafana/grafana:latest + profiles: [monitoring] + ports: + - "3002:3000" + environment: + GF_AUTH_ANONYMOUS_ENABLED: "true" + GF_AUTH_ANONYMOUS_ORG_ROLE: Admin + GF_AUTH_DISABLE_LOGIN_FORM: "true" + volumes: + - ./infrastructure/grafana/provisioning:/etc/grafana/provisioning:ro + - ./infrastructure/grafana/dashboards:/var/lib/grafana/dashboards:ro + - grafana_data:/var/lib/grafana + + loki: + image: grafana/loki:latest + profiles: [monitoring] + ports: + - "3100:3100" + volumes: + - ./infrastructure/loki/loki-config.yml:/etc/loki/local-config.yaml:ro + - loki_data:/loki + command: ["-config.file=/etc/loki/local-config.yaml"] + volumes: pgdata: brouter_segments: + prometheus_data: + grafana_data: + loki_data: diff --git a/openspec/changes/local-dev-stack/tasks.md b/openspec/changes/local-dev-stack/tasks.md index c2a0973..1db8b5f 100644 --- a/openspec/changes/local-dev-stack/tasks.md +++ b/openspec/changes/local-dev-stack/tasks.md @@ -1,30 +1,30 @@ ## 1. Docker Compose -- [ ] 1.1 Update dev PostgreSQL to match production: add `shared_preload_libraries=pg_stat_statements` command and mount `infrastructure/postgres/init-grafana-user.sql` as init script -- [ ] 1.2 Add Prometheus service with `monitoring` profile, mounting `infrastructure/prometheus/prometheus.yml` -- [ ] 1.3 Add Grafana service with `monitoring` profile, anonymous auth enabled, provisioned with local Prometheus and Loki datasources -- [ ] 1.4 Add Loki service with `monitoring` profile, mounting `infrastructure/loki/loki-config.yml` +- [x] 1.1 Update dev PostgreSQL to match production: add `shared_preload_libraries=pg_stat_statements` command and mount `infrastructure/postgres/init-grafana-user.sql` as init script +- [x] 1.2 Add Prometheus service with `monitoring` profile, mounting `infrastructure/prometheus/prometheus.yml` +- [x] 1.3 Add Grafana service with `monitoring` profile, anonymous auth enabled, provisioned with local Prometheus and Loki datasources +- [x] 1.4 Add Loki service with `monitoring` profile, mounting `infrastructure/loki/loki-config.yml` ## 2. Database -- [ ] 2.1 Create `scripts/seed.ts` with idempotent test data: user account, sample route (Berlin area), sample activity. Use Drizzle ORM, `ON CONFLICT DO NOTHING` -- [ ] 2.2 Add `pnpm db:seed` script to root package.json that runs `scripts/seed.ts` with `--experimental-strip-types` +- [x] 2.1 Create `scripts/seed.ts` with idempotent test data: user account, sample route (Berlin area), sample activity. Use Drizzle ORM, `ON CONFLICT DO NOTHING` +- [x] 2.2 Add `pnpm db:seed` script to root package.json that runs `scripts/seed.ts` with `--experimental-strip-types` ## 3. CI Integration -- [ ] 3.1 Replace manual `docker run` PostgreSQL setup in `ci.yml` e2e job with `docker compose -f docker-compose.dev.yml up -d --wait` -- [ ] 3.2 Replace manual BRouter download/start in `ci.yml` with the compose BRouter service plus cached segment mount -- [ ] 3.3 Add `pnpm db:seed` step after `pnpm db:push` in CI e2e job -- [ ] 3.4 Remove any E2E test skip workarounds that check for DB availability (the `withDb()` 503 skip pattern) +- [x] 3.1 Replace manual `docker run` PostgreSQL setup in `ci.yml` e2e job with `docker compose -f docker-compose.dev.yml up -d --wait` +- [x] 3.2 Replace manual BRouter download/start in `ci.yml` with the compose BRouter service plus cached segment mount +- [x] 3.3 Add `pnpm db:seed` step after `pnpm db:push` in CI e2e job +- [x] 3.4 Remove any E2E test skip workarounds that check for DB availability (the `withDb()` 503 skip pattern) ## 4. Scripts -- [ ] 4.1 Improve `scripts/dev.sh`: check Docker is running first, use `docker compose up -d --wait`, add `--monitoring` flag to start monitoring profile, run seed after schema push -- [ ] 4.2 Create `scripts/reset-dev.sh`: stop containers, remove volumes, restart — add as `pnpm dev:reset` in package.json +- [x] 4.1 Improve `scripts/dev.sh`: check Docker is running first, use `docker compose up -d --wait`, add `--monitoring` flag to start monitoring profile, run seed after schema push +- [x] 4.2 Create `scripts/reset-dev.sh`: stop containers, remove volumes, restart — add as `pnpm dev:reset` in package.json ## 5. Environment -- [ ] 5.1 Create `.env.development.example` with documented defaults (DATABASE_URL, BROUTER_URL, JWT_SECRET, SESSION_SECRET) and add `.env.development` to `.gitignore` +- [x] 5.1 Create `.env.development.example` with documented defaults (DATABASE_URL, BROUTER_URL, JWT_SECRET, SESSION_SECRET) and add `.env.development` to `.gitignore` ## 6. Verify diff --git a/package.json b/package.json index ab062fd..eabfd27 100644 --- a/package.json +++ b/package.json @@ -20,8 +20,10 @@ "db:push": "drizzle-kit push --config packages/db/drizzle.config.ts --force", "db:migrate-data": "tsx packages/db/src/migrate-data.ts", "db:studio": "drizzle-kit studio --config packages/db/drizzle.config.ts", + "db:seed": "node --experimental-strip-types scripts/seed.ts", "dev:services": "docker compose -f docker-compose.dev.yml up -d", "dev:full": "./scripts/dev.sh", + "dev:reset": "./scripts/reset-dev.sh", "dev:ios": "pnpm --filter @trails-cool/mobile ios", "dev:android": "pnpm --filter @trails-cool/mobile android", "openspec": "openspec" diff --git a/scripts/dev.sh b/scripts/dev.sh index 9d6d1e0..2e1ca44 100755 --- a/scripts/dev.sh +++ b/scripts/dev.sh @@ -6,50 +6,59 @@ PROJECT_DIR="$(dirname "$SCRIPT_DIR")" cd "$PROJECT_DIR" +# Parse flags +MONITORING=false +for arg in "$@"; do + case "$arg" in + --monitoring) MONITORING=true ;; + esac +done + +# Check Docker is running +if ! docker info > /dev/null 2>&1; then + echo "Error: Docker is not running. Please start Docker and try again." + exit 1 +fi + echo "=== trails.cool dev environment ===" echo "" # 1. Start Docker services -echo "Starting Docker services..." -docker compose -f docker-compose.dev.yml up -d +if [ "$MONITORING" = "true" ]; then + echo "Starting Docker services (with monitoring)..." + docker compose -f docker-compose.dev.yml --profile monitoring up -d --wait +else + echo "Starting Docker services..." + docker compose -f docker-compose.dev.yml up -d --wait +fi +echo "✓ Services are ready" -# 2. Wait for PostgreSQL -echo "Waiting for PostgreSQL..." -until docker compose -f docker-compose.dev.yml exec -T postgres pg_isready -U trails > /dev/null 2>&1; do - sleep 1 -done -echo "✓ PostgreSQL is ready" - -# 3. Push database schema +# 2. Push database schema echo "Pushing database schema..." pnpm db:push 2>&1 | tail -3 echo "✓ Database schema up to date" +# 3. Seed database +echo "Seeding database..." +pnpm db:seed +echo "✓ Database seeded" + # 4. Download BRouter segments if needed echo "Checking BRouter segments..." "$SCRIPT_DIR/download-dev-segments.sh" -# 5. Wait for BRouter (if segments are available) -if docker compose -f docker-compose.dev.yml ps brouter --format '{{.State}}' 2>/dev/null | grep -q "running"; then - echo "Waiting for BRouter..." - for i in $(seq 1 30); do - if curl -sf http://localhost:17777/brouter?lonlats=13.4,52.5\|13.5,52.5\&profile=trekking\&format=geojson > /dev/null 2>&1; then - echo "✓ BRouter is ready" - break - fi - if [ "$i" = "30" ]; then - echo "⚠ BRouter not responding (segments may still be loading). Continuing..." - fi - sleep 2 - done -fi - echo "" echo "=== Starting apps ===" echo " Journal: http://localhost:3000" echo " Planner: http://localhost:3001" echo " BRouter: http://localhost:17777" +if [ "$MONITORING" = "true" ]; then + echo " Grafana: http://localhost:3002" + echo " Prometheus: http://localhost:9090" +fi +echo "" +echo " Tip: pnpm dev:reset to wipe all data and start fresh" echo "" -# 6. Start both apps with turbo +# 5. Start both apps with turbo exec pnpm dev diff --git a/scripts/reset-dev.sh b/scripts/reset-dev.sh new file mode 100755 index 0000000..7b737dc --- /dev/null +++ b/scripts/reset-dev.sh @@ -0,0 +1,26 @@ +#!/bin/bash +set -euo pipefail + +PROJECT_DIR="$(cd "$(dirname "$0")/.." && pwd)" +cd "$PROJECT_DIR" + +if ! docker info > /dev/null 2>&1; then + echo "Error: Docker is not running. Please start Docker and try again." + exit 1 +fi + +echo "=== Resetting dev environment ===" +echo "This will stop all containers and wipe all local data volumes." +echo "" + +read -r -p "Are you sure? [y/N] " confirm +if [[ "$confirm" != "y" && "$confirm" != "Y" ]]; then + echo "Aborted." + exit 0 +fi + +echo "Stopping containers and removing volumes..." +docker compose -f docker-compose.dev.yml --profile monitoring down -v 2>/dev/null || \ + docker compose -f docker-compose.dev.yml down -v + +echo "✓ Done. Run 'pnpm dev:full' to start fresh." diff --git a/scripts/seed.ts b/scripts/seed.ts new file mode 100644 index 0000000..fcb5c34 --- /dev/null +++ b/scripts/seed.ts @@ -0,0 +1,72 @@ +import { createDb } from "../packages/db/src/index.ts"; +import { users, routes, activities } from "../packages/db/src/schema/journal.ts"; + +const db = createDb(); + +const SEED_USER_ID = "seed-user-dev"; +const SEED_ROUTE_ID = "seed-route-berlin"; +const SEED_ACTIVITY_ID = "seed-activity-berlin"; + +// Minimal GPX for a short Berlin route (Tiergarten area) +const BERLIN_GPX = ` + + + Tiergarten Loop + + 34 + 35 + 35 + 36 + 35 + 34 + + +`; + +await db + .insert(users) + .values({ + id: SEED_USER_ID, + email: "dev@trails.cool", + username: "devuser", + displayName: "Dev User", + domain: "localhost:3000", + profileVisibility: "public", + }) + .onConflictDoNothing(); + +await db + .insert(routes) + .values({ + id: SEED_ROUTE_ID, + ownerId: SEED_USER_ID, + name: "Tiergarten Loop", + description: "A short loop through Tiergarten for local dev testing.", + gpx: BERLIN_GPX, + routingProfile: "trekking", + distance: 1200, + elevationGain: 5, + elevationLoss: 5, + visibility: "public", + }) + .onConflictDoNothing(); + +await db + .insert(activities) + .values({ + id: SEED_ACTIVITY_ID, + ownerId: SEED_USER_ID, + routeId: SEED_ROUTE_ID, + name: "Morning walk in Tiergarten", + gpx: BERLIN_GPX, + startedAt: new Date("2024-06-01T08:00:00Z"), + duration: 1800, + distance: 1200, + elevationGain: 5, + elevationLoss: 5, + visibility: "public", + }) + .onConflictDoNothing(); + +console.log("✓ Seed complete"); +process.exit(0); From a2d125922e65add88dd179fe638388a34cd61a82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Sun, 17 May 2026 20:53:38 +0200 Subject: [PATCH 038/319] Fix Grafana dev provisioning: mount only datasources+dashboards Mounting the full production provisioning dir pulled in the alerting config which requires Pushover secrets. Mount only the two subdirs that make sense locally. Co-Authored-By: Claude Sonnet 4.6 --- docker-compose.dev.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index aa669ad..a184d30 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -43,7 +43,8 @@ services: GF_AUTH_ANONYMOUS_ORG_ROLE: Admin GF_AUTH_DISABLE_LOGIN_FORM: "true" volumes: - - ./infrastructure/grafana/provisioning:/etc/grafana/provisioning:ro + - ./infrastructure/grafana/provisioning/datasources:/etc/grafana/provisioning/datasources:ro + - ./infrastructure/grafana/provisioning/dashboards:/etc/grafana/provisioning/dashboards:ro - ./infrastructure/grafana/dashboards:/var/lib/grafana/dashboards:ro - grafana_data:/var/lib/grafana From 8fd3dda8c68d4de0f2a12862f48ddcdedbb5b1ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Sun, 17 May 2026 21:02:02 +0200 Subject: [PATCH 039/319] Add BRouter healthcheck so compose --wait blocks until routing is ready Without a healthcheck, --wait considers BRouter healthy as soon as the container starts, before it has loaded segments and opened its port. The healthcheck probes the routing endpoint directly, matching the old manual curl loop in CI. Co-Authored-By: Claude Sonnet 4.6 --- docker-compose.dev.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index a184d30..21a2391 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -23,6 +23,12 @@ services: - "17777:17777" volumes: - brouter_segments:/data/segments + healthcheck: + test: ["CMD-SHELL", "curl -sf 'http://localhost:17777/brouter?lonlats=13.4,52.5|13.5,52.5&profile=trekking&format=geojson' > /dev/null"] + interval: 10s + timeout: 10s + retries: 12 + start_period: 30s prometheus: image: prom/prometheus:latest From 4d0a865437fb5cb7a71f133c45011b8cf1814ff8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Sun, 17 May 2026 21:26:45 +0200 Subject: [PATCH 040/319] Fix BRouter healthcheck: use literal | and increase retry window Percent-encoding the | may confuse older curl; use a literal | inside single quotes instead. Also bump retries from 12 to 18 (total window 30s start + 180s probing) to cover slow first-run segment downloads. Co-Authored-By: Claude Sonnet 4.6 --- docker-compose.dev.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index 21a2391..2a6d7a9 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -27,7 +27,7 @@ services: test: ["CMD-SHELL", "curl -sf 'http://localhost:17777/brouter?lonlats=13.4,52.5|13.5,52.5&profile=trekking&format=geojson' > /dev/null"] interval: 10s timeout: 10s - retries: 12 + retries: 18 start_period: 30s prometheus: From 134cf4ccf160e685d114b26bcfba84f420a35fbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Sun, 17 May 2026 21:57:55 +0200 Subject: [PATCH 041/319] Simplify BRouter healthcheck to port liveness; add routing wait in CI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The routing probe healthcheck was too strict — BRouter is up but may not have the segment loaded yet, causing all probes to fail. Use a simple liveness check (curl exit 0 when server responds on any code) so --wait unblocks as soon as the server is up. Add an explicit routing readiness wait step in CI that actually confirms a route can be computed before running E2E tests. Co-Authored-By: Claude Sonnet 4.6 --- .github/workflows/ci.yml | 7 +++++++ docker-compose.dev.yml | 10 +++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bd213d8..665fad8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -209,6 +209,13 @@ jobs: env: BROUTER_URL: http://localhost:17777 + - name: Wait for BRouter routing + run: | + for i in $(seq 1 30); do + curl -sf 'http://localhost:17777/brouter?lonlats=13.4,52.5|13.5,52.5&profile=trekking&format=geojson' > /dev/null 2>&1 && break + sleep 3 + done + - name: Push database schema run: pnpm db:push diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index 2a6d7a9..ff29112 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -24,11 +24,11 @@ services: volumes: - brouter_segments:/data/segments healthcheck: - test: ["CMD-SHELL", "curl -sf 'http://localhost:17777/brouter?lonlats=13.4,52.5|13.5,52.5&profile=trekking&format=geojson' > /dev/null"] - interval: 10s - timeout: 10s - retries: 18 - start_period: 30s + test: ["CMD-SHELL", "curl -s http://localhost:17777/ > /dev/null 2>&1"] + interval: 5s + timeout: 5s + retries: 30 + start_period: 10s prometheus: image: prom/prometheus:latest From bea391c9fdceebf8c81ddcc7f73403e619730b68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Sun, 17 May 2026 22:12:16 +0200 Subject: [PATCH 042/319] Increase BRouter routing wait to 120s in CI BRouter needs time to parse the segment file into memory before it can serve routing requests. 90s was insufficient; 120s matches the margin the old explicit startup loop provided. Co-Authored-By: Claude Sonnet 4.6 --- .github/workflows/ci.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 665fad8..b8904ab 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -211,9 +211,10 @@ jobs: - name: Wait for BRouter routing run: | - for i in $(seq 1 30); do - curl -sf 'http://localhost:17777/brouter?lonlats=13.4,52.5|13.5,52.5&profile=trekking&format=geojson' > /dev/null 2>&1 && break - sleep 3 + for i in $(seq 1 60); do + curl -sf 'http://localhost:17777/brouter?lonlats=13.4,52.5|13.5,52.5&profile=trekking&format=geojson' > /dev/null 2>&1 && echo "BRouter ready" && break + [ "$i" = "60" ] && echo "BRouter not ready after 120s" && exit 1 + sleep 2 done - name: Push database schema From 1dcc518242be589794de1f265d2ee90acdb5c9d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Sun, 17 May 2026 22:44:23 +0200 Subject: [PATCH 043/319] Pre-seed BRouter volume in CI instead of bind mount override The bind mount override (docker-compose.ci.yml) failed because file permissions on the cached segment prevented the entrypoint from seeing the file, causing a fresh download on every CI run. Instead: create the named volume and copy the cached segment into it before compose starts, using alpine with explicit chmod. The entrypoint then finds the segment and skips the download, so BRouter starts in ~4s instead of ~2min. Co-Authored-By: Claude Sonnet 4.6 --- .github/workflows/ci.yml | 10 +++++++++- docker-compose.ci.yml | 4 ---- 2 files changed, 9 insertions(+), 5 deletions(-) delete mode 100644 docker-compose.ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b8904ab..fa19126 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -204,8 +204,16 @@ jobs: mkdir -p /tmp/brouter-segments wget -q "https://brouter.de/brouter/segments4/E10_N50.rd5" -O /tmp/brouter-segments/E10_N50.rd5 + - name: Pre-seed BRouter segment volume + run: | + docker volume create trails_brouter_segments + docker run --rm \ + -v /tmp/brouter-segments:/src:ro \ + -v trails_brouter_segments:/dst \ + alpine sh -c "cp /src/*.rd5 /dst/ && chmod a+r /dst/*.rd5" + - name: Start services - run: docker compose -f docker-compose.dev.yml -f docker-compose.ci.yml up -d --wait --build + run: docker compose -f docker-compose.dev.yml up -d --wait --build env: BROUTER_URL: http://localhost:17777 diff --git a/docker-compose.ci.yml b/docker-compose.ci.yml deleted file mode 100644 index f900e4b..0000000 --- a/docker-compose.ci.yml +++ /dev/null @@ -1,4 +0,0 @@ -services: - brouter: - volumes: - - /tmp/brouter-segments:/data/segments From 66ce852e96fff98bf1c6807971df4c70a3abe142 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Sun, 17 May 2026 23:01:49 +0200 Subject: [PATCH 044/319] Add BRouter routing wait diagnostic output Co-Authored-By: Claude Sonnet 4.6 --- .github/workflows/ci.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fa19126..80685bc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -220,7 +220,9 @@ jobs: - name: Wait for BRouter routing run: | for i in $(seq 1 60); do - curl -sf 'http://localhost:17777/brouter?lonlats=13.4,52.5|13.5,52.5&profile=trekking&format=geojson' > /dev/null 2>&1 && echo "BRouter ready" && break + RESP=$(curl -s 'http://localhost:17777/brouter?lonlats=13.4,52.5|13.5,52.5&profile=trekking&format=geojson' 2>/dev/null) + echo "attempt $i: $(echo "$RESP" | head -c 80)" + echo "$RESP" | grep -q "FeatureCollection" && echo "BRouter ready" && break [ "$i" = "60" ] && echo "BRouter not ready after 120s" && exit 1 sleep 2 done From d2a0b6e398ffde9de573b6903dba0038f536630e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Sun, 17 May 2026 23:06:30 +0200 Subject: [PATCH 045/319] Fix BRouter segment cache key: include version to avoid format mismatch The segment format changed between BRouter 1.7.8 and 1.7.9. The old cache key 'brouter-segment-E10_N50' served the v1.7.8 segment to the v1.7.9 binary, causing 'lookup version mismatch (old rd5?)' errors on every routing request. Include the BRouter version in the cache key so a fresh segment is downloaded whenever the binary version changes. Co-Authored-By: Claude Sonnet 4.6 --- .github/workflows/ci.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 80685bc..0494470 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -196,7 +196,7 @@ jobs: uses: actions/cache@v5 with: path: /tmp/brouter-segments - key: brouter-segment-E10_N50 + key: brouter-segment-E10_N50-v1.7.9 - name: Download Berlin segment if: steps.segment-cache.outputs.cache-hit != 'true' @@ -220,9 +220,7 @@ jobs: - name: Wait for BRouter routing run: | for i in $(seq 1 60); do - RESP=$(curl -s 'http://localhost:17777/brouter?lonlats=13.4,52.5|13.5,52.5&profile=trekking&format=geojson' 2>/dev/null) - echo "attempt $i: $(echo "$RESP" | head -c 80)" - echo "$RESP" | grep -q "FeatureCollection" && echo "BRouter ready" && break + curl -s 'http://localhost:17777/brouter?lonlats=13.4,52.5|13.5,52.5&profile=trekking&format=geojson' 2>/dev/null | grep -q "FeatureCollection" && echo "BRouter ready" && break [ "$i" = "60" ] && echo "BRouter not ready after 120s" && exit 1 sleep 2 done From 03791e981d1d55136dc659f7a9e4e348887feedf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Sun, 17 May 2026 23:10:24 +0200 Subject: [PATCH 046/319] Mark verification tasks complete Co-Authored-By: Claude Sonnet 4.6 --- openspec/changes/local-dev-stack/tasks.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/openspec/changes/local-dev-stack/tasks.md b/openspec/changes/local-dev-stack/tasks.md index 1db8b5f..bc7ebe6 100644 --- a/openspec/changes/local-dev-stack/tasks.md +++ b/openspec/changes/local-dev-stack/tasks.md @@ -28,7 +28,7 @@ ## 6. Verify -- [ ] 6.1 Test full local dev flow: `pnpm dev:full` starts services, pushes schema, seeds data, launches apps — create session, compute route, verify seeded data visible -- [ ] 6.2 Test monitoring profile: `pnpm dev:full -- --monitoring` starts Prometheus + Grafana + Loki, verify Grafana dashboards load at localhost:3002 -- [ ] 6.3 Test CI flow: push branch, verify e2e job uses compose, all ~20 E2E tests run (none skipped) -- [ ] 6.4 Test reset: `pnpm dev:reset` wipes volumes and restarts cleanly +- [x] 6.1 Test full local dev flow: `pnpm dev:full` starts services, pushes schema, seeds data, launches apps — create session, compute route, verify seeded data visible +- [x] 6.2 Test monitoring profile: `pnpm dev:full -- --monitoring` starts Prometheus + Grafana + Loki, verify Grafana dashboards load at localhost:3002 +- [x] 6.3 Test CI flow: push branch, verify e2e job uses compose, all ~20 E2E tests run (none skipped) +- [x] 6.4 Test reset: `pnpm dev:reset` wipes volumes and restarts cleanly From 970e0a0755d8c57c7360cccbd533e80b4e53ec24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Sun, 17 May 2026 23:10:58 +0200 Subject: [PATCH 047/319] Archive local-dev-stack change; sync delta spec to main Co-Authored-By: Claude Sonnet 4.6 --- .../.openspec.yaml | 0 .../2026-05-17-local-dev-stack}/design.md | 0 .../2026-05-17-local-dev-stack}/proposal.md | 0 .../specs/local-dev-environment/spec.md | 0 .../2026-05-17-local-dev-stack}/tasks.md | 0 openspec/specs/local-dev-environment/spec.md | 28 +++++++++++++++++++ 6 files changed, 28 insertions(+) rename openspec/changes/{local-dev-stack => archive/2026-05-17-local-dev-stack}/.openspec.yaml (100%) rename openspec/changes/{local-dev-stack => archive/2026-05-17-local-dev-stack}/design.md (100%) rename openspec/changes/{local-dev-stack => archive/2026-05-17-local-dev-stack}/proposal.md (100%) rename openspec/changes/{local-dev-stack => archive/2026-05-17-local-dev-stack}/specs/local-dev-environment/spec.md (100%) rename openspec/changes/{local-dev-stack => archive/2026-05-17-local-dev-stack}/tasks.md (100%) diff --git a/openspec/changes/local-dev-stack/.openspec.yaml b/openspec/changes/archive/2026-05-17-local-dev-stack/.openspec.yaml similarity index 100% rename from openspec/changes/local-dev-stack/.openspec.yaml rename to openspec/changes/archive/2026-05-17-local-dev-stack/.openspec.yaml diff --git a/openspec/changes/local-dev-stack/design.md b/openspec/changes/archive/2026-05-17-local-dev-stack/design.md similarity index 100% rename from openspec/changes/local-dev-stack/design.md rename to openspec/changes/archive/2026-05-17-local-dev-stack/design.md diff --git a/openspec/changes/local-dev-stack/proposal.md b/openspec/changes/archive/2026-05-17-local-dev-stack/proposal.md similarity index 100% rename from openspec/changes/local-dev-stack/proposal.md rename to openspec/changes/archive/2026-05-17-local-dev-stack/proposal.md diff --git a/openspec/changes/local-dev-stack/specs/local-dev-environment/spec.md b/openspec/changes/archive/2026-05-17-local-dev-stack/specs/local-dev-environment/spec.md similarity index 100% rename from openspec/changes/local-dev-stack/specs/local-dev-environment/spec.md rename to openspec/changes/archive/2026-05-17-local-dev-stack/specs/local-dev-environment/spec.md diff --git a/openspec/changes/local-dev-stack/tasks.md b/openspec/changes/archive/2026-05-17-local-dev-stack/tasks.md similarity index 100% rename from openspec/changes/local-dev-stack/tasks.md rename to openspec/changes/archive/2026-05-17-local-dev-stack/tasks.md diff --git a/openspec/specs/local-dev-environment/spec.md b/openspec/specs/local-dev-environment/spec.md index 53853c0..2edd2d2 100644 --- a/openspec/specs/local-dev-environment/spec.md +++ b/openspec/specs/local-dev-environment/spec.md @@ -51,3 +51,31 @@ The Planner SHALL be able to compute routes locally in the dev environment. #### Scenario: Compute a route in Berlin - **WHEN** a developer sends a route request with two Berlin waypoints to the local Planner - **THEN** the Planner proxies to local BRouter and returns a valid GeoJSON route + +### Requirement: Optional local monitoring stack +The dev environment SHALL support an optional monitoring profile matching the production stack. + +#### Scenario: Start with monitoring +- **WHEN** a developer runs `pnpm dev:full` with `--monitoring` +- **THEN** Prometheus, Grafana, and Loki start alongside the app services + +### Requirement: Production-aligned PostgreSQL config +The dev PostgreSQL SHALL match production configuration including pg_stat_statements. + +#### Scenario: pg_stat_statements available +- **WHEN** the dev PostgreSQL container starts +- **THEN** pg_stat_statements is enabled via initialization scripts + +### Requirement: Database seed script +The dev environment SHALL provide a seed script for consistent test data. + +#### Scenario: Seed database +- **WHEN** a developer runs `pnpm db:seed` +- **THEN** test users, routes, and activities are created idempotently in the local database + +### Requirement: Dev environment reset +The dev environment SHALL provide a command to tear down and recreate the local stack. + +#### Scenario: Reset dev environment +- **WHEN** a developer runs `pnpm dev:reset` +- **THEN** all Docker volumes are removed and containers are recreated From c3c0ffeeab5b09c13423981e039baf5fed8a49ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Sun, 17 May 2026 23:14:14 +0200 Subject: [PATCH 048/319] Update vite to 8.0.13 Co-Authored-By: Claude Sonnet 4.6 --- pnpm-lock.yaml | 228 ++++++++++++++++++++++++------------------------- 1 file changed, 114 insertions(+), 114 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8421878..3473a33 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -55,8 +55,8 @@ catalogs: specifier: ^5.8.3 version: 5.9.3 vite: - specifier: ^8.0.10 - version: 8.0.10 + specifier: ^8.0.13 + version: 8.0.13 overrides: picomatch@>=4.0.0 <4.0.4: 4.0.4 @@ -94,7 +94,7 @@ importers: version: 1.60.0 '@react-router/dev': specifier: 'catalog:' - version: 7.15.1(@react-router/serve@7.15.1(react-router@7.15.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3))(@types/node@25.8.0)(jiti@2.7.0)(lightningcss@1.32.0)(react-router@7.15.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.10(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0))(yaml@2.9.0) + version: 7.15.1(@react-router/serve@7.15.1(react-router@7.15.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3))(@types/node@25.8.0)(jiti@2.7.0)(lightningcss@1.32.0)(react-router@7.15.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.13(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0))(yaml@2.9.0) '@react-router/node': specifier: 'catalog:' version: 7.15.1(react-router@7.15.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3) @@ -106,7 +106,7 @@ importers: version: 5.3.0(rollup@4.60.4) '@tailwindcss/vite': specifier: 'catalog:' - version: 4.3.0(vite@8.0.10(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0)) + version: 4.3.0(vite@8.0.13(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0)) '@testing-library/jest-dom': specifier: ^6.9.1 version: 6.9.1 @@ -193,10 +193,10 @@ importers: version: 8.59.3(eslint@10.4.0(jiti@2.7.0))(typescript@5.9.3) vite: specifier: 'catalog:' - version: 8.0.10(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0) + version: 8.0.13(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0) vitest: specifier: ^4.1.6 - version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@25.8.0)(@vitest/browser-playwright@4.1.6)(jsdom@29.1.1(canvas@3.2.3))(vite@8.0.10(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0)) + version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@25.8.0)(@vitest/browser-playwright@4.1.6)(jsdom@29.1.1(canvas@3.2.3))(vite@8.0.13(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0)) apps/journal: dependencies: @@ -281,13 +281,13 @@ importers: devDependencies: '@react-router/dev': specifier: 'catalog:' - version: 7.15.1(@react-router/serve@7.15.1(react-router@7.15.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3))(@types/node@25.8.0)(jiti@2.7.0)(lightningcss@1.32.0)(react-router@7.15.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.10(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0))(yaml@2.9.0) + version: 7.15.1(@react-router/serve@7.15.1(react-router@7.15.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3))(@types/node@25.8.0)(jiti@2.7.0)(lightningcss@1.32.0)(react-router@7.15.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.13(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0))(yaml@2.9.0) '@simplewebauthn/types': specifier: ^12.0.0 version: 12.0.0 '@tailwindcss/vite': specifier: 'catalog:' - version: 4.3.0(vite@8.0.10(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0)) + version: 4.3.0(vite@8.0.13(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0)) '@types/nodemailer': specifier: ^8.0.0 version: 8.0.0 @@ -299,7 +299,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.10(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0)) + version: 2.3.0(vite@8.0.13(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0)) pino-pretty: specifier: ^13.1.3 version: 13.1.3 @@ -311,7 +311,7 @@ importers: version: 5.9.3 vite: specifier: 'catalog:' - version: 8.0.10(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0) + version: 8.0.13(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0) apps/mobile: dependencies: @@ -550,10 +550,10 @@ importers: devDependencies: '@react-router/dev': specifier: 'catalog:' - version: 7.15.1(@react-router/serve@7.15.1(react-router@7.15.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3))(@types/node@25.8.0)(jiti@2.7.0)(lightningcss@1.32.0)(react-router@7.15.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.10(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0))(yaml@2.9.0) + version: 7.15.1(@react-router/serve@7.15.1(react-router@7.15.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3))(@types/node@25.8.0)(jiti@2.7.0)(lightningcss@1.32.0)(react-router@7.15.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.13(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0))(yaml@2.9.0) '@tailwindcss/vite': specifier: 'catalog:' - version: 4.3.0(vite@8.0.10(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0)) + version: 4.3.0(vite@8.0.13(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0)) '@types/leaflet.markercluster': specifier: ^1.5.6 version: 1.5.6 @@ -568,10 +568,10 @@ importers: version: 8.18.1 '@vitest/browser': specifier: ^4.1.6 - version: 4.1.6(vite@8.0.10(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0))(vitest@4.1.6) + version: 4.1.6(vite@8.0.13(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0))(vitest@4.1.6) '@vitest/browser-playwright': specifier: ^4.1.6 - version: 4.1.6(playwright@1.60.0)(vite@8.0.10(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0))(vitest@4.1.6) + version: 4.1.6(playwright@1.60.0)(vite@8.0.13(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0))(vitest@4.1.6) leaflet.markercluster: specifier: ^1.5.3 version: 1.5.3(leaflet@1.9.4) @@ -586,7 +586,7 @@ importers: version: 5.9.3 vite: specifier: 'catalog:' - version: 8.0.10(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0) + version: 8.0.13(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0) packages/api: dependencies: @@ -2504,8 +2504,8 @@ packages: peerDependencies: '@opentelemetry/api': ^1.1.0 - '@oxc-project/types@0.127.0': - resolution: {integrity: sha512-aIYXQBo4lCbO4z0R3FHeucQHpF46l2LbMdxRvqvuRuW2OxdnSkcng5B8+K12spgLDj93rtN3+J2Vac/TIO+ciQ==} + '@oxc-project/types@0.130.0': + resolution: {integrity: sha512-ibD2usx9JRu7f5pu2tMKMI4cpA4NgXJQoYRP4pQ7Pxmn1l6k/53qWtQWZayhYy3X4QZkt90Ot+mJEaeXouio6Q==} '@peculiar/asn1-android@2.6.0': resolution: {integrity: sha512-cBRCKtYPF7vJGN76/yG8VbxRcHLPF3HnkoHhKOZeHpoVtbMYfY9ROKtH3DtYUY9m8uI1Mh47PRhHf2hSK3xcSQ==} @@ -3017,103 +3017,103 @@ packages: '@remix-run/node-fetch-server@0.13.1': resolution: {integrity: sha512-dOL+A/C84EA47gO/ps52KGrVSiYy96512rwtbXmJfWKYFm1FbrbjA3jao1hcIfao+jwVNEaZ1kTMwFjiino+HQ==} - '@rolldown/binding-android-arm64@1.0.0-rc.17': - resolution: {integrity: sha512-s70pVGhw4zqGeFnXWvAzJDlvxhlRollagdCCKRgOsgUOH3N1l0LIxf83AtGzmb5SiVM4Hjl5HyarMRfdfj3DaQ==} + '@rolldown/binding-android-arm64@1.0.1': + resolution: {integrity: sha512-fJI3I0r3C3Oj/zdBCpaCmBRZYf07xpaq4yCfDDoSFm+beWNzbIl26puW8RraUdugoJw/95zerNOn6jasAhzSmg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - '@rolldown/binding-darwin-arm64@1.0.0-rc.17': - resolution: {integrity: sha512-4ksWc9n0mhlZpZ9PMZgTGjeOPRu8MB1Z3Tz0Mo02eWfWCHMW1zN82Qz/pL/rC+yQa+8ZnutMF0JjJe7PjwasYw==} + '@rolldown/binding-darwin-arm64@1.0.1': + resolution: {integrity: sha512-cKnAhWEsV7TPcA/5EAteDp6KcJZBQ2G+BqE7zayMMi7kMvwRsbv7WT9aOnn0WNl4SKEIf43vjS31iUPu80nzXg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@rolldown/binding-darwin-x64@1.0.0-rc.17': - resolution: {integrity: sha512-SUSDOI6WwUVNcWxd02QEBjLdY1VPHvlEkw6T/8nYG322iYWCTxRb1vzk4E+mWWYehTp7ERibq54LSJGjmouOsw==} + '@rolldown/binding-darwin-x64@1.0.1': + resolution: {integrity: sha512-YKrVwQjIRBPo+5G/u03wGjbdy4q7pyzCe93DK9VJ7zkVmeg8LJ7GbgsiHWdR4xSoe4CAXRD7Bcjgbtr64bkXNg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@rolldown/binding-freebsd-x64@1.0.0-rc.17': - resolution: {integrity: sha512-hwnz3nw9dbJ05EDO/PvcjaaewqqDy7Y1rn1UO81l8iIK1GjenME75dl16ajbvSSMfv66WXSRCYKIqfgq2KCfxw==} + '@rolldown/binding-freebsd-x64@1.0.1': + resolution: {integrity: sha512-z/oBsREo46SsFqBwYtFe0kpJeBijAT48O/WXLI4suiCLBkr03RTtTJMCzSdDd2znlh8VJizL09XVkQgk8IZonw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.17': - resolution: {integrity: sha512-IS+W7epTcwANmFSQFrS1SivEXHtl1JtuQA9wlxrZTcNi6mx+FDOYrakGevvvTwgj2JvWiK8B29/qD9BELZPyXQ==} + '@rolldown/binding-linux-arm-gnueabihf@1.0.1': + resolution: {integrity: sha512-ik8q7GM11zxvYxFc2PeDcT6TBvhCQMaUxfph/M5l9sKuTs/Sjg3L+Byw0F7w0ZVLBZmx30P+gG0ECzzN+MFcmQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.17': - resolution: {integrity: sha512-e6usGaHKW5BMNZOymS1UcEYGowQMWcgZ71Z17Sl/h2+ZziNJ1a9n3Zvcz6LdRyIW5572wBCTH/Z+bKuZouGk9Q==} + '@rolldown/binding-linux-arm64-gnu@1.0.1': + resolution: {integrity: sha512-QoSx2EkyrrdZ6kcyE8stqZ62t0Yra8Fs5ia9lOxJrh6TMQJK7gQKmscdTHf7pOXKREKrVwOtJcQG3qVSfc866A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-arm64-musl@1.0.0-rc.17': - resolution: {integrity: sha512-b/CgbwAJpmrRLp02RPfhbudf5tZnN9nsPWK82znefso832etkem8H7FSZwxrOI9djcdTP7U6YfNhbRnh7djErg==} + '@rolldown/binding-linux-arm64-musl@1.0.1': + resolution: {integrity: sha512-uwNwFpwKeNiZawfAWBgg0VIztPTV3ihhh1vV334h9ivnNLorxnQMU6Fz8wG1Zb4Qh9LC1/MkcyT3YlDXG3Rsgg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [musl] - '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.17': - resolution: {integrity: sha512-4EII1iNGRUN5WwGbF/kOh/EIkoDN9HsupgLQoXfY+D1oyJm7/F4t5PYU5n8SWZgG0FEwakyM8pGgwcBYruGTlA==} + '@rolldown/binding-linux-ppc64-gnu@1.0.1': + resolution: {integrity: sha512-zY1bul7OWr7DFBiJ++wofXvnr8B45ce3QsQUhKrIhXsygAh7bTkwyeM1bi1a2g5C/yC/N8TZyGDEoMfm/l9mpg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.17': - resolution: {integrity: sha512-AH8oq3XqQo4IibpVXvPeLDI5pzkpYn0WiZAfT05kFzoJ6tQNzwRdDYQ45M8I/gslbodRZwW8uxLhbSBbkv96rA==} + '@rolldown/binding-linux-s390x-gnu@1.0.1': + resolution: {integrity: sha512-0frlsT/f4Ft6I7SMESTKnF3cZsdicQn1dCMkF/jT9wDLE+gGoiQfv1nmT9e+s7s/fekvvy6tZM2jHvI2tkbJDQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] libc: [glibc] - '@rolldown/binding-linux-x64-gnu@1.0.0-rc.17': - resolution: {integrity: sha512-cLnjV3xfo7KslbU41Z7z8BH/E1y5mzUYzAqih1d1MDaIGZRCMqTijqLv76/P7fyHuvUcfGsIpqCdddbxLLK9rA==} + '@rolldown/binding-linux-x64-gnu@1.0.1': + resolution: {integrity: sha512-XABVmGp9Tg0WspTVvwduTc4fpqy6JnAUrSQe6OuyqD/03nI7r0O9OWUkMIwFrjKAIqolvqoA4ZrJppgwE0Gxmw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-x64-musl@1.0.0-rc.17': - resolution: {integrity: sha512-0phclDw1spsL7dUB37sIARuis2tAgomCJXAHZlpt8PXZ4Ba0dRP1e+66lsRqrfhISeN9bEGNjQs+T/Fbd7oYGw==} + '@rolldown/binding-linux-x64-musl@1.0.1': + resolution: {integrity: sha512-bV4fzswuzVcKD90o/VM6QqKxnxlDq0g2BISDLNVmxrnhpv1DDbyPhCIjYfvzYLV+MvkKKnQt2Q6AO86SEBULUQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [musl] - '@rolldown/binding-openharmony-arm64@1.0.0-rc.17': - resolution: {integrity: sha512-0ag/hEgXOwgw4t8QyQvUCxvEg+V0KBcA6YuOx9g0r02MprutRF5dyljgm3EmR02O292UX7UeS6HzWHAl6KgyhA==} + '@rolldown/binding-openharmony-arm64@1.0.1': + resolution: {integrity: sha512-/Mh0Zhq3OP7fVs0kcQHZP6lZEthMGTaSf8UBQYSFEZDWGXXlEC+nJ6EqenaK2t4LBXMe3A+K/G2BVXXdtOr4PQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - '@rolldown/binding-wasm32-wasi@1.0.0-rc.17': - resolution: {integrity: sha512-LEXei6vo0E5wTGwpkJ4KoT3OZJRnglwldt5ziLzOlc6qqb55z4tWNq2A+PFqCJuvWWdP53CVhG1Z9NtToDPJrA==} + '@rolldown/binding-wasm32-wasi@1.0.1': + resolution: {integrity: sha512-+1xc9X45l8ufsBAm6Gjvx2qDRIY9lTVt0cgWNcJ+1gdhXvkbxePA60yRTwSTuXL09CMhyJmjpV7E3NoyxbqFQQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [wasm32] - '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.17': - resolution: {integrity: sha512-gUmyzBl3SPMa6hrqFUth9sVfcLBlYsbMzBx5PlexMroZStgzGqlZ26pYG89rBb45Mnia+oil6YAIFeEWGWhoZA==} + '@rolldown/binding-win32-arm64-msvc@1.0.1': + resolution: {integrity: sha512-1D+UqZdfnuR+Jy1GgMJwi85bD40H21uNmOPRWQhw4oRSuolZ/B5rixZ45DK2KXOTCvmVCecauWgEhbw8bI7tOw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - '@rolldown/binding-win32-x64-msvc@1.0.0-rc.17': - resolution: {integrity: sha512-3hkiolcUAvPB9FLb3UZdfjVVNWherN1f/skkGWJP/fgSQhYUZpSIRr0/I8ZK9TkF3F7kxvJAk0+IcKvPHk9qQg==} + '@rolldown/binding-win32-x64-msvc@1.0.1': + resolution: {integrity: sha512-INAycaWuhlOK3wk4mRHGsdgwYWmd9cChdPdE9bwWmy6rn9VqVNYNFGhOdXrofXUxwHIncSiPNb8tNm8knDVIeQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] - '@rolldown/pluginutils@1.0.0-rc.17': - resolution: {integrity: sha512-n8iosDOt6Ig1UhJ2AYqoIhHWh/isz0xpicHTzpKBeotdVsTEcxsSA/i3EVM7gQAj0rU27OLAxCjzlj15IWY7bg==} + '@rolldown/pluginutils@1.0.1': + resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==} '@rollup/rollup-android-arm-eabi@4.60.4': resolution: {integrity: sha512-F5QXMSiFebS9hKZj02XhWLLnRpJ3B3AROP0tWbFBSj+6kCbg5m9j5JoHKd4mmSVy5mS/IMQloYgYxCuJC0fxEQ==} @@ -3811,8 +3811,8 @@ packages: '@turf/truncate@7.3.4': resolution: {integrity: sha512-VPXdae9+RLLM19FMrJgt7QANBikm7DxPbfp/dXgzE4Ca7v+mJ4T1fYc7gCZDaqOrWMccHKbvv4iSuW7YZWdIIA==} - '@tybys/wasm-util@0.10.1': - resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} + '@tybys/wasm-util@0.10.2': + resolution: {integrity: sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==} '@types/aria-query@5.0.4': resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==} @@ -7135,8 +7135,8 @@ packages: robust-predicates@3.0.3: resolution: {integrity: sha512-NS3levdsRIUOmiJ8FZWCP7LG3QpJyrs/TE0Zpf1yvZu8cAJJ6QMW92H1c7kWpdIHo8RvmLxN/o2JXTKHp74lUA==} - rolldown@1.0.0-rc.17: - resolution: {integrity: sha512-ZrT53oAKrtA4+YtBWPQbtPOxIbVDbxT0orcYERKd63VJTF13zPcgXTvD4843L8pcsI7M6MErt8QtON6lrB9tyA==} + rolldown@1.0.1: + resolution: {integrity: sha512-X0KQHljNnEkWNqqiz9zJrGunh1B0HgOxLXvnFpCOcadzcy5qohZ3tqMEUg00vncoRovXuK3ZqCT9KnnKzoInFQ==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true @@ -7810,13 +7810,13 @@ packages: yaml: optional: true - vite@8.0.10: - resolution: {integrity: sha512-rZuUu9j6J5uotLDs+cAA4O5H4K1SfPliUlQwqa6YEwSrWDZzP4rhm00oJR5snMewjxF5V/K3D4kctsUTsIU9Mw==} + vite@8.0.13: + resolution: {integrity: sha512-MFtjBYgzmSxmgA4RAfjIyXWpGe1oALnjgUTzzV7QLx/TKxCzjtMH6Fd9/eVK+5Fg1qNoz5VAwsmMs/NofrmJvw==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: '@types/node': ^20.19.0 || >=22.12.0 - '@vitejs/devtools': ^0.1.0 + '@vitejs/devtools': ^0.1.18 esbuild: ^0.27.0 || ^0.28.0 jiti: '>=1.21.0' less: ^4.0.0 @@ -9898,7 +9898,7 @@ snapshots: dependencies: '@emnapi/core': 1.10.0 '@emnapi/runtime': 1.10.0 - '@tybys/wasm-util': 0.10.1 + '@tybys/wasm-util': 0.10.2 optional: true '@nodelib/fs.scandir@2.1.5': @@ -10134,7 +10134,7 @@ snapshots: '@opentelemetry/api': 1.9.1 '@opentelemetry/core': 2.6.1(@opentelemetry/api@1.9.1) - '@oxc-project/types@0.127.0': {} + '@oxc-project/types@0.130.0': {} '@peculiar/asn1-android@2.6.0': dependencies: @@ -10767,7 +10767,7 @@ snapshots: dependencies: nanoid: 3.3.12 - '@react-router/dev@7.15.1(@react-router/serve@7.15.1(react-router@7.15.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3))(@types/node@25.8.0)(jiti@2.7.0)(lightningcss@1.32.0)(react-router@7.15.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.10(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0))(yaml@2.9.0)': + '@react-router/dev@7.15.1(@react-router/serve@7.15.1(react-router@7.15.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3))(@types/node@25.8.0)(jiti@2.7.0)(lightningcss@1.32.0)(react-router@7.15.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.13(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0))(yaml@2.9.0)': dependencies: '@babel/core': 7.29.0 '@babel/generator': 7.29.1 @@ -10797,7 +10797,7 @@ snapshots: semver: 7.8.0 tinyglobby: 0.2.16 valibot: 1.4.0(typescript@5.9.3) - vite: 8.0.10(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0) + vite: 8.0.13(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0) vite-node: 3.2.4(@types/node@25.8.0)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0) optionalDependencies: '@react-router/serve': 7.15.1(react-router@7.15.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3) @@ -10849,56 +10849,56 @@ snapshots: '@remix-run/node-fetch-server@0.13.1': {} - '@rolldown/binding-android-arm64@1.0.0-rc.17': + '@rolldown/binding-android-arm64@1.0.1': optional: true - '@rolldown/binding-darwin-arm64@1.0.0-rc.17': + '@rolldown/binding-darwin-arm64@1.0.1': optional: true - '@rolldown/binding-darwin-x64@1.0.0-rc.17': + '@rolldown/binding-darwin-x64@1.0.1': optional: true - '@rolldown/binding-freebsd-x64@1.0.0-rc.17': + '@rolldown/binding-freebsd-x64@1.0.1': optional: true - '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.17': + '@rolldown/binding-linux-arm-gnueabihf@1.0.1': optional: true - '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.17': + '@rolldown/binding-linux-arm64-gnu@1.0.1': optional: true - '@rolldown/binding-linux-arm64-musl@1.0.0-rc.17': + '@rolldown/binding-linux-arm64-musl@1.0.1': optional: true - '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.17': + '@rolldown/binding-linux-ppc64-gnu@1.0.1': optional: true - '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.17': + '@rolldown/binding-linux-s390x-gnu@1.0.1': optional: true - '@rolldown/binding-linux-x64-gnu@1.0.0-rc.17': + '@rolldown/binding-linux-x64-gnu@1.0.1': optional: true - '@rolldown/binding-linux-x64-musl@1.0.0-rc.17': + '@rolldown/binding-linux-x64-musl@1.0.1': optional: true - '@rolldown/binding-openharmony-arm64@1.0.0-rc.17': + '@rolldown/binding-openharmony-arm64@1.0.1': optional: true - '@rolldown/binding-wasm32-wasi@1.0.0-rc.17': + '@rolldown/binding-wasm32-wasi@1.0.1': dependencies: '@emnapi/core': 1.10.0 '@emnapi/runtime': 1.10.0 '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) optional: true - '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.17': + '@rolldown/binding-win32-arm64-msvc@1.0.1': optional: true - '@rolldown/binding-win32-x64-msvc@1.0.0-rc.17': + '@rolldown/binding-win32-x64-msvc@1.0.1': optional: true - '@rolldown/pluginutils@1.0.0-rc.17': {} + '@rolldown/pluginutils@1.0.1': {} '@rollup/rollup-android-arm-eabi@4.60.4': optional: true @@ -11376,12 +11376,12 @@ snapshots: '@tailwindcss/oxide-win32-arm64-msvc': 4.3.0 '@tailwindcss/oxide-win32-x64-msvc': 4.3.0 - '@tailwindcss/vite@4.3.0(vite@8.0.10(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0))': + '@tailwindcss/vite@4.3.0(vite@8.0.13(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0))': dependencies: '@tailwindcss/node': 4.3.0 '@tailwindcss/oxide': 4.3.0 tailwindcss: 4.3.0 - vite: 8.0.10(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0) + vite: 8.0.13(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0) '@testing-library/dom@10.4.1': dependencies: @@ -11603,7 +11603,7 @@ snapshots: '@types/geojson': 7946.0.16 tslib: 2.8.1 - '@tybys/wasm-util@0.10.1': + '@tybys/wasm-util@0.10.2': dependencies: tslib: 2.8.1 optional: true @@ -11836,33 +11836,33 @@ snapshots: '@ungap/structured-clone@1.3.1': {} - '@vitejs/plugin-basic-ssl@2.3.0(vite@8.0.10(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0))': + '@vitejs/plugin-basic-ssl@2.3.0(vite@8.0.13(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0))': dependencies: - vite: 8.0.10(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0) + vite: 8.0.13(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0) - '@vitest/browser-playwright@4.1.6(playwright@1.60.0)(vite@8.0.10(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0))(vitest@4.1.6)': + '@vitest/browser-playwright@4.1.6(playwright@1.60.0)(vite@8.0.13(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0))(vitest@4.1.6)': dependencies: - '@vitest/browser': 4.1.6(vite@8.0.10(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0))(vitest@4.1.6) - '@vitest/mocker': 4.1.6(vite@8.0.10(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0)) + '@vitest/browser': 4.1.6(vite@8.0.13(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0))(vitest@4.1.6) + '@vitest/mocker': 4.1.6(vite@8.0.13(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0)) playwright: 1.60.0 tinyrainbow: 3.1.0 - vitest: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@25.8.0)(@vitest/browser-playwright@4.1.6)(jsdom@29.1.1(canvas@3.2.3))(vite@8.0.10(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0)) + vitest: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@25.8.0)(@vitest/browser-playwright@4.1.6)(jsdom@29.1.1(canvas@3.2.3))(vite@8.0.13(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0)) transitivePeerDependencies: - bufferutil - msw - utf-8-validate - vite - '@vitest/browser@4.1.6(vite@8.0.10(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0))(vitest@4.1.6)': + '@vitest/browser@4.1.6(vite@8.0.13(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0))(vitest@4.1.6)': dependencies: '@blazediff/core': 1.9.1 - '@vitest/mocker': 4.1.6(vite@8.0.10(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0)) + '@vitest/mocker': 4.1.6(vite@8.0.13(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0)) '@vitest/utils': 4.1.6 magic-string: 0.30.21 pngjs: 7.0.0 sirv: 3.0.2 tinyrainbow: 3.1.0 - vitest: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@25.8.0)(@vitest/browser-playwright@4.1.6)(jsdom@29.1.1(canvas@3.2.3))(vite@8.0.10(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0)) + vitest: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@25.8.0)(@vitest/browser-playwright@4.1.6)(jsdom@29.1.1(canvas@3.2.3))(vite@8.0.13(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0)) ws: 8.20.1 transitivePeerDependencies: - bufferutil @@ -11879,13 +11879,13 @@ snapshots: chai: 6.2.2 tinyrainbow: 3.1.0 - '@vitest/mocker@4.1.6(vite@8.0.10(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0))': + '@vitest/mocker@4.1.6(vite@8.0.13(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0))': dependencies: '@vitest/spy': 4.1.6 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 8.0.10(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0) + vite: 8.0.13(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0) '@vitest/pretty-format@4.1.6': dependencies: @@ -15554,26 +15554,26 @@ snapshots: robust-predicates@3.0.3: {} - rolldown@1.0.0-rc.17: + rolldown@1.0.1: dependencies: - '@oxc-project/types': 0.127.0 - '@rolldown/pluginutils': 1.0.0-rc.17 + '@oxc-project/types': 0.130.0 + '@rolldown/pluginutils': 1.0.1 optionalDependencies: - '@rolldown/binding-android-arm64': 1.0.0-rc.17 - '@rolldown/binding-darwin-arm64': 1.0.0-rc.17 - '@rolldown/binding-darwin-x64': 1.0.0-rc.17 - '@rolldown/binding-freebsd-x64': 1.0.0-rc.17 - '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-rc.17 - '@rolldown/binding-linux-arm64-gnu': 1.0.0-rc.17 - '@rolldown/binding-linux-arm64-musl': 1.0.0-rc.17 - '@rolldown/binding-linux-ppc64-gnu': 1.0.0-rc.17 - '@rolldown/binding-linux-s390x-gnu': 1.0.0-rc.17 - '@rolldown/binding-linux-x64-gnu': 1.0.0-rc.17 - '@rolldown/binding-linux-x64-musl': 1.0.0-rc.17 - '@rolldown/binding-openharmony-arm64': 1.0.0-rc.17 - '@rolldown/binding-wasm32-wasi': 1.0.0-rc.17 - '@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.17 - '@rolldown/binding-win32-x64-msvc': 1.0.0-rc.17 + '@rolldown/binding-android-arm64': 1.0.1 + '@rolldown/binding-darwin-arm64': 1.0.1 + '@rolldown/binding-darwin-x64': 1.0.1 + '@rolldown/binding-freebsd-x64': 1.0.1 + '@rolldown/binding-linux-arm-gnueabihf': 1.0.1 + '@rolldown/binding-linux-arm64-gnu': 1.0.1 + '@rolldown/binding-linux-arm64-musl': 1.0.1 + '@rolldown/binding-linux-ppc64-gnu': 1.0.1 + '@rolldown/binding-linux-s390x-gnu': 1.0.1 + '@rolldown/binding-linux-x64-gnu': 1.0.1 + '@rolldown/binding-linux-x64-musl': 1.0.1 + '@rolldown/binding-openharmony-arm64': 1.0.1 + '@rolldown/binding-wasm32-wasi': 1.0.1 + '@rolldown/binding-win32-arm64-msvc': 1.0.1 + '@rolldown/binding-win32-x64-msvc': 1.0.1 rollup@4.60.4: dependencies: @@ -16215,12 +16215,12 @@ snapshots: tsx: 4.21.0 yaml: 2.9.0 - vite@8.0.10(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0): + vite@8.0.13(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0): dependencies: lightningcss: 1.32.0 picomatch: 4.0.4 postcss: 8.5.14 - rolldown: 1.0.0-rc.17 + rolldown: 1.0.1 tinyglobby: 0.2.16 optionalDependencies: '@types/node': 25.8.0 @@ -16231,10 +16231,10 @@ snapshots: tsx: 4.21.0 yaml: 2.9.0 - vitest@4.1.6(@opentelemetry/api@1.9.1)(@types/node@25.8.0)(@vitest/browser-playwright@4.1.6)(jsdom@29.1.1(canvas@3.2.3))(vite@8.0.10(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0)): + vitest@4.1.6(@opentelemetry/api@1.9.1)(@types/node@25.8.0)(@vitest/browser-playwright@4.1.6)(jsdom@29.1.1(canvas@3.2.3))(vite@8.0.13(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0)): dependencies: '@vitest/expect': 4.1.6 - '@vitest/mocker': 4.1.6(vite@8.0.10(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0)) + '@vitest/mocker': 4.1.6(vite@8.0.13(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0)) '@vitest/pretty-format': 4.1.6 '@vitest/runner': 4.1.6 '@vitest/snapshot': 4.1.6 @@ -16251,12 +16251,12 @@ snapshots: tinyexec: 1.1.2 tinyglobby: 0.2.16 tinyrainbow: 3.1.0 - vite: 8.0.10(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0) + vite: 8.0.13(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0) why-is-node-running: 2.3.0 optionalDependencies: '@opentelemetry/api': 1.9.1 '@types/node': 25.8.0 - '@vitest/browser-playwright': 4.1.6(playwright@1.60.0)(vite@8.0.10(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0))(vitest@4.1.6) + '@vitest/browser-playwright': 4.1.6(playwright@1.60.0)(vite@8.0.13(@types/node@25.8.0)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.47.1)(tsx@4.21.0)(yaml@2.9.0))(vitest@4.1.6) jsdom: 29.1.1(canvas@3.2.3) transitivePeerDependencies: - msw From cff5b20f0ffb5fd31edd432049aacae055394002 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Sun, 17 May 2026 23:17:18 +0200 Subject: [PATCH 049/319] Fix catalog key ordering in pnpm-workspace.yaml after pnpm install pnpm reordered catalog keys alphabetically; also locks vite to ^8.0.13. Co-Authored-By: Claude Sonnet 4.6 --- pnpm-workspace.yaml | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 6315309..0e8a441 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -4,23 +4,22 @@ packages: - "scripts" catalog: - react: ^19.2.5 - react-dom: ^19.2.6 - react-router: ^7.15.1 "@react-router/dev": ^7.15.1 "@react-router/node": ^7.15.1 "@react-router/serve": ^7.15.1 - "@types/react": ^19.2.14 - "@types/react-dom": ^19.2.3 - tailwindcss: ^4.3.0 - "@tailwindcss/vite": ^4.3.0 - typescript: ^5.8.3 - vite: ^8.0.10 - drizzle-orm: ^0.45.2 - drizzle-kit: ^0.31.10 - drizzle-postgis: ^1.1.1 "@sentry/node": ^10.53.1 "@sentry/react": ^10.53.1 - postgres: ^3.4.9 + "@tailwindcss/vite": ^4.3.0 "@types/node": ^22.19.19 - + "@types/react": ^19.2.14 + "@types/react-dom": ^19.2.3 + drizzle-kit: ^0.31.10 + drizzle-orm: ^0.45.2 + drizzle-postgis: ^1.1.1 + postgres: ^3.4.9 + react: ^19.2.5 + react-dom: ^19.2.6 + react-router: ^7.15.1 + tailwindcss: ^4.3.0 + typescript: ^5.8.3 + vite: ^8.0.13 From 861701e881a72401fb50ed59276f3ac83889900e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Sun, 17 May 2026 23:32:38 +0200 Subject: [PATCH 050/319] Show POI details (phone, website, opening hours) on Journal route detail page Waypoints snapped to OSM POIs in the Planner now carry their metadata all the way through to the Journal: - Extend Waypoint type with osmId and poiTags fields - Extract osmId/poiTags from Yjs Y.Map in ExportButton and SaveToJournalButton - Encode POI metadata as extensions in GPX elements - Parse extensions back in the GPX parser - Display phone, website, opening hours, address on Journal route detail - E2E test for the full roundtrip; seed endpoint now defaults to public visibility Co-Authored-By: Claude Sonnet 4.6 --- apps/journal/app/routes/api.e2e.seed.ts | 2 + apps/journal/app/routes/routes.$id.tsx | 75 ++++++++++++++-- apps/planner/app/components/ExportButton.tsx | 3 + .../app/components/SaveToJournalButton.tsx | 3 + e2e/integration.test.ts | 51 +++++++++++ .../changes/journal-poi-details/design.md | 88 +++++++++++++++++++ openspec/changes/journal-poi-details/tasks.md | 11 +++ packages/gpx/src/generate.test.ts | 51 +++++++++++ packages/gpx/src/generate.ts | 17 +++- packages/gpx/src/parse.ts | 20 ++++- packages/i18n/src/locales/de.ts | 7 ++ packages/i18n/src/locales/en.ts | 7 ++ packages/types/src/index.ts | 15 ++++ 13 files changed, 341 insertions(+), 9 deletions(-) create mode 100644 openspec/changes/journal-poi-details/design.md create mode 100644 openspec/changes/journal-poi-details/tasks.md diff --git a/apps/journal/app/routes/api.e2e.seed.ts b/apps/journal/app/routes/api.e2e.seed.ts index 6d0b67b..91301a0 100644 --- a/apps/journal/app/routes/api.e2e.seed.ts +++ b/apps/journal/app/routes/api.e2e.seed.ts @@ -60,6 +60,7 @@ export async function action({ request }: { request: Request }) { ? await request.json().catch(() => ({})) : {}; const routeName = (body as { routeName?: string }).routeName ?? "E2E callback test route"; + const visibility = (body as { visibility?: string }).visibility ?? "public"; const routeId = randomUUID(); await db.insert(routes).values({ @@ -67,6 +68,7 @@ export async function action({ request }: { request: Request }) { ownerId: user.id, name: routeName, description: "", + visibility: visibility as "public" | "unlisted" | "private", }); const token = await createRouteToken(routeId); diff --git a/apps/journal/app/routes/routes.$id.tsx b/apps/journal/app/routes/routes.$id.tsx index a85c066..8e44af4 100644 --- a/apps/journal/app/routes/routes.$id.tsx +++ b/apps/journal/app/routes/routes.$id.tsx @@ -30,16 +30,26 @@ export async function loader({ params, request }: Route.LoaderArgs) { throw data({ error: "Route not found" }, { status: 404 }); } - // Compute per-day stats if route has day breaks and GPX + // Parse GPX once for day stats and waypoint POI data let dayStats: Array<{ dayNumber: number; startName?: string; endName?: string; distance: number; ascent: number; descent: number }> = []; - if (route.dayBreaks && route.dayBreaks.length > 0 && route.gpx) { + let waypoints: Array<{ lat: number; lon: number; name?: string; isDayBreak?: boolean; osmId?: number; poiTags?: Record }> = []; + if (route.gpx) { try { - const { computeDays } = await import("@trails-cool/gpx"); - const { parseGpxAsync } = await import("@trails-cool/gpx"); + const { computeDays, parseGpxAsync } = await import("@trails-cool/gpx"); const gpxData = await parseGpxAsync(route.gpx); - dayStats = computeDays(gpxData.waypoints, gpxData.tracks); + waypoints = gpxData.waypoints.map((w) => ({ + lat: w.lat, + lon: w.lon, + name: w.name, + isDayBreak: w.isDayBreak, + osmId: w.osmId, + poiTags: w.poiTags as Record | undefined, + })); + if (route.dayBreaks && route.dayBreaks.length > 0) { + dayStats = computeDays(gpxData.waypoints, gpxData.tracks); + } } catch { - // Fall back to no day stats + // Fall back to empty } } @@ -119,6 +129,7 @@ export async function loader({ params, request }: Route.LoaderArgs) { updatedAt: route.updatedAt.toISOString(), }, dayStats, + waypoints, versions: route.versions.map((v) => ({ version: v.version, changeDescription: v.changeDescription, @@ -187,7 +198,7 @@ export function meta({ data: loaderData }: Route.MetaArgs) { } export default function RouteDetailPage({ loaderData }: Route.ComponentProps) { - const { route, dayStats, versions, isOwner, wahooPush } = loaderData; + const { route, dayStats, waypoints, versions, isOwner, wahooPush } = loaderData; const { t, i18n } = useTranslation("journal"); const [editLoading, setEditLoading] = useState(false); const [highlightedDay, setHighlightedDay] = useState(null); @@ -387,6 +398,56 @@ export default function RouteDetailPage({ loaderData }: Route.ComponentProps) { )} + {waypoints.some((w) => w.osmId || w.poiTags) && ( +
+

{t("routes.waypoints")}

+
    + {waypoints.filter((w) => w.osmId || w.poiTags || w.name).map((w, i) => ( +
  • +

    + {w.name ?? `${w.lat.toFixed(5)}, ${w.lon.toFixed(5)}`} +

    + {w.poiTags && ( +
    + {w.poiTags.phone && ( +
    +
    {t("routes.poi.phone")}
    +
    {w.poiTags.phone}
    +
    + )} + {w.poiTags.website && ( +
    +
    {t("routes.poi.website")}
    +
    {w.poiTags.website}
    +
    + )} + {w.poiTags.opening_hours && ( +
    +
    {t("routes.poi.openingHours")}
    +
    {w.poiTags.opening_hours}
    +
    + )} + {(w.poiTags["addr:street"] || w.poiTags["addr:city"]) && ( +
    +
    {t("routes.poi.address")}
    +
    + {[ + w.poiTags["addr:street"] && `${w.poiTags["addr:street"]}${w.poiTags["addr:housenumber"] ? " " + w.poiTags["addr:housenumber"] : ""}`, + w.poiTags["addr:postcode"] && w.poiTags["addr:city"] + ? `${w.poiTags["addr:postcode"]} ${w.poiTags["addr:city"]}` + : w.poiTags["addr:city"], + ].filter(Boolean).join(", ")} +
    +
    + )} +
    + )} +
  • + ))} +
+
+ )} + {route.geojson && (
0 ? route.dayBreaks : undefined} highlightedDay={highlightedDay} /> diff --git a/apps/planner/app/components/ExportButton.tsx b/apps/planner/app/components/ExportButton.tsx index d673d0b..f58eb3b 100644 --- a/apps/planner/app/components/ExportButton.tsx +++ b/apps/planner/app/components/ExportButton.tsx @@ -4,6 +4,7 @@ import * as Y from "yjs"; import type { YjsState } from "~/lib/use-yjs"; import { generateGpx, computeDays } from "@trails-cool/gpx"; import type { TrackPoint, NoGoArea } from "@trails-cool/gpx"; +import type { WaypointPoiTags } from "@trails-cool/types"; function getTracks(yjs: YjsState): TrackPoint[][] { const geojsonStr = yjs.routeData.get("geojson") as string | undefined; @@ -24,6 +25,8 @@ function getWaypoints(yjs: YjsState) { lon: yMap.get("lon") as number, name: yMap.get("name") as string | undefined, isDayBreak: yMap.get("overnight") === true ? true : undefined, + osmId: yMap.get("osmId") as number | undefined, + poiTags: yMap.get("poiTags") as WaypointPoiTags | undefined, })); } diff --git a/apps/planner/app/components/SaveToJournalButton.tsx b/apps/planner/app/components/SaveToJournalButton.tsx index a2e178a..2ba7885 100644 --- a/apps/planner/app/components/SaveToJournalButton.tsx +++ b/apps/planner/app/components/SaveToJournalButton.tsx @@ -4,6 +4,7 @@ import * as Y from "yjs"; import type { YjsState } from "~/lib/use-yjs"; import { generateGpx } from "@trails-cool/gpx"; import type { TrackPoint, NoGoArea } from "@trails-cool/gpx"; +import type { WaypointPoiTags } from "@trails-cool/types"; interface SaveToJournalButtonProps { yjs: YjsState; @@ -46,6 +47,8 @@ export function SaveToJournalButton({ yjs, callbackUrl, callbackToken, returnUrl lon: yMap.get("lon") as number, name: yMap.get("name") as string | undefined, isDayBreak: yMap.get("overnight") === true ? true : undefined, + osmId: yMap.get("osmId") as number | undefined, + poiTags: yMap.get("poiTags") as WaypointPoiTags | undefined, })); const notes = yjs.notes.toString() || undefined; diff --git a/e2e/integration.test.ts b/e2e/integration.test.ts index c4b5c3e..4bad37c 100644 --- a/e2e/integration.test.ts +++ b/e2e/integration.test.ts @@ -120,6 +120,57 @@ test.describe("Integration: Journal ↔ Planner handoff", () => { }); }); +test.describe("Integration: POI metadata roundtrip", () => { + test("GPX with POI extensions round-trips through Journal and renders on detail page", async ({ page, request }) => { + const gpx = ` + + + Bike Shop Berlin + + + + + + + + + + 34 + 40 + 35 + +`; + + const seedResp = await request.post(`${JOURNAL}/api/e2e/seed`); + expect(seedResp.ok()).toBeTruthy(); + const { routeId, token } = await seedResp.json() as { routeId: string; token: string }; + + const callbackResp = await request.post(`${JOURNAL}/api/routes/${routeId}/callback`, { + headers: { Authorization: `Bearer ${token}` }, + data: { gpx }, + }); + expect(callbackResp.status()).toBe(200); + + // Navigate to route detail page and check POI details are rendered + await page.goto(`${JOURNAL}/routes/${routeId}`); + await expect(page.getByText("Bike Shop Berlin")).toBeVisible(); + await expect(page.getByText("+49 30 12345")).toBeVisible(); + await expect(page.getByText("Mo-Fr 09:00-18:00")).toBeVisible(); + await expect(page.getByRole("link", { name: "https://bikeshop.example" })).toBeVisible(); + }); + + test("GPX without POI extensions shows no waypoints section", async ({ page, request }) => { + const seedResp = await request.post(`${JOURNAL}/api/e2e/seed`); + const { routeId, token } = await seedResp.json() as { routeId: string; token: string }; + await request.post(`${JOURNAL}/api/routes/${routeId}/callback`, { + headers: { Authorization: `Bearer ${token}` }, + data: { gpx: VALID_GPX }, + }); + await page.goto(`${JOURNAL}/routes/${routeId}`); + await expect(page.getByText("Waypoints")).not.toBeVisible(); + }); +}); + test.describe("Integration: BRouter routing", () => { // Helper: mint a planner session so our /api/route calls satisfy // the session-bound gate introduced alongside this test file. diff --git a/openspec/changes/journal-poi-details/design.md b/openspec/changes/journal-poi-details/design.md new file mode 100644 index 0000000..e35819e --- /dev/null +++ b/openspec/changes/journal-poi-details/design.md @@ -0,0 +1,88 @@ +# Design: Journal POI Details + +## Data Flow + +POI metadata already flows from Overpass → POI snap → Yjs Y.Map (`osmId`, `poiTags`). The gap is that neither GPX export nor the Journal save extracts these fields. + +``` +Yjs Y.Map + { lat, lon, name, overnight, osmId, poiTags: { phone, website, ... } } + ↓ (currently drops osmId + poiTags) + Waypoint type → generateGpx → GPX + ↓ + Journal DB → route.gpx + ↓ (currently not parsed) + Journal route detail page +``` + +## Changes + +### 1. `@trails-cool/types` — extend `Waypoint` + +Add optional POI fields to the shared `Waypoint` interface: + +```ts +export interface Waypoint { + lat: number; + lon: number; + name?: string; + isDayBreak?: boolean; + osmId?: number; + poiTags?: { + phone?: string; + website?: string; + opening_hours?: string; + "addr:street"?: string; + "addr:housenumber"?: string; + "addr:postcode"?: string; + "addr:city"?: string; + amenity?: string; + tourism?: string; + shop?: string; + }; +} +``` + +### 2. Planner — extract `osmId` + `poiTags` from Yjs + +In `ExportButton.tsx` and `SaveToJournalButton.tsx`, add the two fields to the waypoint mapping: + +```ts +osmId: yMap.get("osmId") as number | undefined, +poiTags: yMap.get("poiTags") as Waypoint["poiTags"] | undefined, +``` + +### 3. GPX — encode/decode POI fields as `` + +**`generate.ts`**: When a waypoint has `osmId` or `poiTags`, emit a `` block inside ``. Always declare the `trails:` namespace on the root `` element (already done for noGoAreas, just extend the condition). + +```xml + + Fahrradhändler Müller + + + + + + + + +``` + +**`parse.ts`**: In `parseWaypoints`, query `trails:poi` (and unprefixed `poi`) extensions; read the `osmId` attribute and `trails:tag` children. + +### 4. Journal route detail — display POI metadata + +In `routes.$id.tsx`: +- Parse waypoints from `route.gpx` in the loader (already done for `dayStats`, can reuse that parse) +- Pass waypoints with POI data to the component +- Render a `WaypointList` section showing: waypoint name + coords, and if `poiTags` present: phone (tel: link), website (https: link), opening hours, address + +No new DB columns needed — everything lives in the GPX string already stored in `routes.gpx`. + +## Non-Goals + +- No new DB columns for POI data +- No Overpass lookups in the Journal +- No display of `osmId` to the user (internal reference only) +- Opening hours parsing/formatting: display raw string as-is diff --git a/openspec/changes/journal-poi-details/tasks.md b/openspec/changes/journal-poi-details/tasks.md new file mode 100644 index 0000000..c81161e --- /dev/null +++ b/openspec/changes/journal-poi-details/tasks.md @@ -0,0 +1,11 @@ +# Tasks: Journal POI Details + +- [x] Extend `Waypoint` type in `packages/types/src/index.ts` with `osmId` and `poiTags` fields +- [x] Extract `osmId` and `poiTags` from Yjs Y.Map in `apps/planner/app/components/ExportButton.tsx` +- [x] Extract `osmId` and `poiTags` from Yjs Y.Map in `apps/planner/app/components/SaveToJournalButton.tsx` +- [x] Encode POI fields as `` extensions in `packages/gpx/src/generate.ts` +- [x] Parse `` extensions back into waypoints in `packages/gpx/src/parse.ts` +- [x] Add unit tests for GPX POI encode/decode roundtrip in `packages/gpx/src/` +- [x] Pass parsed waypoints with POI data from the loader in `apps/journal/app/routes/routes.$id.tsx` +- [x] Render POI details (phone, website, opening hours, address) for waypoints in the Journal route detail page +- [x] Add i18n keys for POI section labels (phone, website, opening hours, address) diff --git a/packages/gpx/src/generate.test.ts b/packages/gpx/src/generate.test.ts index f92fab1..ac160ee 100644 --- a/packages/gpx/src/generate.test.ts +++ b/packages/gpx/src/generate.test.ts @@ -103,4 +103,55 @@ describe("generateGpx", () => { expect(gpx).toContain("Day 1: A - B"); expect(gpx).toContain("Day 2: B - C"); }); + + it("encodes POI metadata as trails:poi extensions", () => { + const gpx = generateGpx({ + waypoints: [ + { + lat: 52.52, + lon: 13.405, + name: "Bike Shop", + osmId: 123456, + poiTags: { phone: "+49 30 123", website: "https://example.com", opening_hours: "Mo-Fr 09:00-18:00" }, + }, + ], + }); + expect(gpx).toContain('xmlns:trails="https://trails.cool/gpx/1"'); + expect(gpx).toContain(''); + expect(gpx).toContain(''); + expect(gpx).toContain(''); + expect(gpx).toContain(''); + }); + + it("roundtrips POI metadata through generate + parse", async () => { + const gpx = generateGpx({ + waypoints: [ + { + lat: 52.52, + lon: 13.405, + name: "Campsite", + osmId: 987, + poiTags: { phone: "+49 30 999", website: "https://camp.example" }, + }, + { lat: 48.0, lon: 11.0, name: "Plain waypoint" }, + ], + }); + const parsed = await parseGpxAsync(gpx); + expect(parsed.waypoints).toHaveLength(2); + const poi = parsed.waypoints[0]!; + expect(poi.osmId).toBe(987); + expect(poi.poiTags?.phone).toBe("+49 30 999"); + expect(poi.poiTags?.website).toBe("https://camp.example"); + const plain = parsed.waypoints[1]!; + expect(plain.osmId).toBeUndefined(); + expect(plain.poiTags).toBeUndefined(); + }); + + it("omits extensions element when waypoint has no POI data", () => { + const gpx = generateGpx({ + waypoints: [{ lat: 52.0, lon: 13.0, name: "Plain" }], + }); + expect(gpx).not.toContain(""); + expect(gpx).not.toContain("trails:poi"); + }); }); diff --git a/packages/gpx/src/generate.ts b/packages/gpx/src/generate.ts index 064a5be..b7d1a39 100644 --- a/packages/gpx/src/generate.ts +++ b/packages/gpx/src/generate.ts @@ -17,7 +17,8 @@ export function generateGpx(options: { /** When true, splits tracks at overnight waypoints into separate elements per day */ splitByDay?: boolean; }): string { - const hasExtensions = options.noGoAreas && options.noGoAreas.length > 0; + const hasPoiWaypoints = options.waypoints?.some((w) => w.osmId || w.poiTags) ?? false; + const hasExtensions = (options.noGoAreas && options.noGoAreas.length > 0) || hasPoiWaypoints; const lines: string[] = [ '', 'overnight"); } + if (wpt.osmId !== undefined || (wpt.poiTags && Object.keys(wpt.poiTags).length > 0)) { + lines.push(" "); + const osmIdAttr = wpt.osmId !== undefined ? ` osmId="${wpt.osmId}"` : ""; + lines.push(` `); + if (wpt.poiTags) { + for (const [k, v] of Object.entries(wpt.poiTags)) { + if (v !== undefined) { + lines.push(` `); + } + } + } + lines.push(" "); + lines.push(" "); + } lines.push(" "); } } diff --git a/packages/gpx/src/parse.ts b/packages/gpx/src/parse.ts index 8e71d0f..9436a64 100644 --- a/packages/gpx/src/parse.ts +++ b/packages/gpx/src/parse.ts @@ -61,7 +61,25 @@ function parseWaypoints(doc: Document): Waypoint[] { const name = wpt.querySelector("name")?.textContent ?? undefined; const type = wpt.querySelector("type")?.textContent ?? undefined; const isDayBreak = type === "overnight" ? true : undefined; - return { lat, lon, name, isDayBreak }; + + const poiEl = wpt.querySelector("poi, trails\\:poi"); + let osmId: number | undefined; + let poiTags: Waypoint["poiTags"] | undefined; + if (poiEl) { + const rawOsmId = poiEl.getAttribute("osmId"); + if (rawOsmId) osmId = parseInt(rawOsmId, 10); + const tagEls = poiEl.querySelectorAll("tag, trails\\:tag"); + if (tagEls.length > 0) { + poiTags = {}; + for (const tagEl of Array.from(tagEls)) { + const k = tagEl.getAttribute("k"); + const v = tagEl.getAttribute("v"); + if (k && v) (poiTags as Record)[k] = v; + } + } + } + + return { lat, lon, name, isDayBreak, osmId, poiTags }; }); } diff --git a/packages/i18n/src/locales/de.ts b/packages/i18n/src/locales/de.ts index ee6346d..78fb7fa 100644 --- a/packages/i18n/src/locales/de.ts +++ b/packages/i18n/src/locales/de.ts @@ -225,6 +225,13 @@ export default { elevationGain: "Höhenmeter", dayBreakdown: "Tagesübersicht", dayLabel: "Tag {{n}}", + waypoints: "Wegpunkte", + poi: { + phone: "Telefon", + website: "Website", + openingHours: "Öffnungszeiten", + address: "Adresse", + }, noRoutesYet: "Noch keine Routen. Erstelle deine erste Route!", noMapPreview: "Keine Kartenvorschau", saveChanges: "Änderungen speichern", diff --git a/packages/i18n/src/locales/en.ts b/packages/i18n/src/locales/en.ts index 5bb5eca..d7ebc2a 100644 --- a/packages/i18n/src/locales/en.ts +++ b/packages/i18n/src/locales/en.ts @@ -225,6 +225,13 @@ export default { elevationGain: "Elevation Gain", dayBreakdown: "Day Breakdown", dayLabel: "Day {{n}}", + waypoints: "Waypoints", + poi: { + phone: "Phone", + website: "Website", + openingHours: "Hours", + address: "Address", + }, noRoutesYet: "No routes yet. Create your first route!", noMapPreview: "No map preview", saveChanges: "Save Changes", diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index 9681bf6..a391319 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -4,11 +4,26 @@ * These types are used by both the Planner and Journal apps. */ +export interface WaypointPoiTags { + phone?: string; + website?: string; + opening_hours?: string; + "addr:street"?: string; + "addr:housenumber"?: string; + "addr:postcode"?: string; + "addr:city"?: string; + amenity?: string; + tourism?: string; + shop?: string; +} + export interface Waypoint { lat: number; lon: number; name?: string; isDayBreak?: boolean; + osmId?: number; + poiTags?: WaypointPoiTags; } export interface RouteMetadata { From faf22278960071bc1049ff7166db2e7c790b4923 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Sun, 17 May 2026 23:33:37 +0200 Subject: [PATCH 051/319] Archive journal-poi-details change; sync journal-route-detail spec Co-Authored-By: Claude Sonnet 4.6 --- .../.openspec.yaml | 0 .../2026-05-17-journal-poi-details}/design.md | 0 .../proposal.md | 0 .../specs/journal-route-detail/spec.md | 0 .../2026-05-17-journal-poi-details}/tasks.md | 0 openspec/specs/journal-route-detail/spec.md | 20 +++++++++++++++++++ 6 files changed, 20 insertions(+) rename openspec/changes/{journal-poi-details => archive/2026-05-17-journal-poi-details}/.openspec.yaml (100%) rename openspec/changes/{journal-poi-details => archive/2026-05-17-journal-poi-details}/design.md (100%) rename openspec/changes/{journal-poi-details => archive/2026-05-17-journal-poi-details}/proposal.md (100%) rename openspec/changes/{journal-poi-details => archive/2026-05-17-journal-poi-details}/specs/journal-route-detail/spec.md (100%) rename openspec/changes/{journal-poi-details => archive/2026-05-17-journal-poi-details}/tasks.md (100%) create mode 100644 openspec/specs/journal-route-detail/spec.md diff --git a/openspec/changes/journal-poi-details/.openspec.yaml b/openspec/changes/archive/2026-05-17-journal-poi-details/.openspec.yaml similarity index 100% rename from openspec/changes/journal-poi-details/.openspec.yaml rename to openspec/changes/archive/2026-05-17-journal-poi-details/.openspec.yaml diff --git a/openspec/changes/journal-poi-details/design.md b/openspec/changes/archive/2026-05-17-journal-poi-details/design.md similarity index 100% rename from openspec/changes/journal-poi-details/design.md rename to openspec/changes/archive/2026-05-17-journal-poi-details/design.md diff --git a/openspec/changes/journal-poi-details/proposal.md b/openspec/changes/archive/2026-05-17-journal-poi-details/proposal.md similarity index 100% rename from openspec/changes/journal-poi-details/proposal.md rename to openspec/changes/archive/2026-05-17-journal-poi-details/proposal.md diff --git a/openspec/changes/journal-poi-details/specs/journal-route-detail/spec.md b/openspec/changes/archive/2026-05-17-journal-poi-details/specs/journal-route-detail/spec.md similarity index 100% rename from openspec/changes/journal-poi-details/specs/journal-route-detail/spec.md rename to openspec/changes/archive/2026-05-17-journal-poi-details/specs/journal-route-detail/spec.md diff --git a/openspec/changes/journal-poi-details/tasks.md b/openspec/changes/archive/2026-05-17-journal-poi-details/tasks.md similarity index 100% rename from openspec/changes/journal-poi-details/tasks.md rename to openspec/changes/archive/2026-05-17-journal-poi-details/tasks.md diff --git a/openspec/specs/journal-route-detail/spec.md b/openspec/specs/journal-route-detail/spec.md new file mode 100644 index 0000000..6236dc7 --- /dev/null +++ b/openspec/specs/journal-route-detail/spec.md @@ -0,0 +1,20 @@ +## Purpose + +The Journal route detail page displays a saved route with its metadata, map, elevation, day breakdown, and waypoint POI details. + +## Requirements + +### Requirement: POI metadata on route detail waypoints +The Journal route detail page SHALL display POI metadata (phone, address, website, opening hours) for waypoints that have associated OpenStreetMap POI data. + +#### Scenario: POI metadata displayed on waypoints +- **WHEN** a route detail page is loaded and a waypoint has POI metadata from the Planner +- **THEN** the waypoint displays the POI name, icon, and category alongside its coordinates + +#### Scenario: Phone, address, and website shown +- **WHEN** a waypoint has POI metadata including phone, address, or website +- **THEN** those details are shown in the waypoint detail section with appropriate links (tel: for phone, mailto: or https: for website) + +#### Scenario: Waypoints without POI data display normally +- **WHEN** a waypoint on the route detail page has no associated POI metadata +- **THEN** the waypoint displays as before with coordinates and name only, with no empty POI sections shown From d55981d1bf3fccf90d5bcfb00d0c9b4e14d09611 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Sun, 17 May 2026 23:35:06 +0200 Subject: [PATCH 052/319] Add docs/gpx-extensions.md documenting the trails: GPX namespace Co-Authored-By: Claude Sonnet 4.6 --- docs/gpx-extensions.md | 101 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 docs/gpx-extensions.md diff --git a/docs/gpx-extensions.md b/docs/gpx-extensions.md new file mode 100644 index 0000000..3b231e1 --- /dev/null +++ b/docs/gpx-extensions.md @@ -0,0 +1,101 @@ +# trails.cool GPX Extensions + +trails.cool uses a custom XML namespace to store planning metadata in GPX files. This allows round-tripping through export, import, and Journal save without losing information. + +## Namespace + +``` +xmlns:trails="https://trails.cool/gpx/1" +``` + +Declared on the root `` element whenever any extension is present. + +--- + +## `` — POI metadata on waypoints + +Stored inside ``. Carries the OpenStreetMap node ID and key tags for waypoints that were snapped to a POI in the Planner. + +### Syntax + +```xml + + Bike Shop Berlin + + + + + + + + + + + + +``` + +### Attributes + +| Attribute | Required | Description | +|-----------|----------|-------------| +| `osmId` | no | OSM node ID (integer). Present when the waypoint was snapped to a known OSM node. | + +### Child elements + +Each `` stores one OSM tag. The following keys are persisted: + +| Key | Description | +|-----|-------------| +| `phone` / `contact:phone` | Phone number | +| `website` | Website URL | +| `opening_hours` | OSM opening hours string (e.g. `Mo-Fr 09:00-18:00`) | +| `addr:street` | Street name | +| `addr:housenumber` | House number | +| `addr:postcode` | Postal code | +| `addr:city` | City | +| `amenity` | OSM amenity value (e.g. `bicycle_shop`) | +| `tourism` | OSM tourism value (e.g. `camp_site`) | +| `shop` | OSM shop value | + +### Display + +The Journal route detail page renders a **Waypoints** section when at least one waypoint has POI metadata. Phone numbers become `tel:` links; websites become `https:` links. + +--- + +## `` — Planning metadata on routes + +Stored inside the top-level `` element. Carries no-go areas defined in the Planner. + +### Syntax + +```xml + + + + + + + + + +``` + +### Elements + +| Element | Description | +|---------|-------------| +| `` | Container for all planning metadata. | +| `` | A no-go area polygon. Requires at least 3 `` children. Multiple `` elements are allowed. | +| `` | A vertex of the no-go polygon. | + +No-go areas are passed to BRouter when computing routes, which routes around them. They are preserved through export/import and Journal save. + +--- + +## Compatibility + +These extensions are **forward-compatible**: parsers that don't know the `trails:` namespace will ignore the `` blocks and load the file as a normal GPX. Geometry, waypoint names, and elevation data are always stored in standard GPX elements. + +The namespace URI `https://trails.cool/gpx/1` is versioned. If the schema changes incompatibly, the minor version will increment. From c2abb64ee0b5175b425ea83b374af3bde0fc4599 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Sun, 17 May 2026 23:58:21 +0200 Subject: [PATCH 053/319] Add per-waypoint notes and nearby POI snap to Planner MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `note` field on Waypoint type, stored in Yjs Y.Map and exported as `` inside `` in GPX - Inline textarea note editing in WaypointSidebar with auto-resize, character counter (500 max), save-on-blur, Escape cancel - Note indicator dot on map markers; note tooltip on hover - `useNearbyPois` hook: fetches POIs within 500m of selected waypoint via Overpass proxy, 500ms debounce, AbortController, 60s rate-limit suppression - NearbyPoiMarkers component: renders POI markers on map for selected waypoint with snap-to-POI on click - Nearby section in WaypointSidebar: list with snap buttons, spinner, empty/rate-limited states, "Show more" toggle (5 → all) - Unit tests for fetchNearbyPois bbox geometry and snap-to-POI Yjs transaction behaviour Co-Authored-By: Claude Sonnet 4.6 --- .../app/components/NearbyPoiMarkers.tsx | 49 +++++ apps/planner/app/components/PlannerMap.tsx | 71 +++++-- apps/planner/app/components/SessionView.tsx | 9 +- .../app/components/WaypointSidebar.tsx | 176 +++++++++++++++++- apps/planner/app/lib/overpass.test.ts | 60 +++++- apps/planner/app/lib/overpass.ts | 26 +++ apps/planner/app/lib/snap-to-poi.test.ts | 123 ++++++++++++ apps/planner/app/lib/use-nearby-pois.ts | 74 ++++++++ apps/planner/app/lib/use-waypoint-manager.ts | 2 + openspec/changes/waypoint-notes/tasks.md | 67 +++---- packages/gpx/src/generate.test.ts | 35 ++++ packages/gpx/src/generate.ts | 3 + packages/gpx/src/parse.ts | 3 +- packages/i18n/src/locales/de.ts | 12 ++ packages/i18n/src/locales/en.ts | 12 ++ packages/types/src/index.ts | 1 + 16 files changed, 665 insertions(+), 58 deletions(-) create mode 100644 apps/planner/app/components/NearbyPoiMarkers.tsx create mode 100644 apps/planner/app/lib/snap-to-poi.test.ts create mode 100644 apps/planner/app/lib/use-nearby-pois.ts diff --git a/apps/planner/app/components/NearbyPoiMarkers.tsx b/apps/planner/app/components/NearbyPoiMarkers.tsx new file mode 100644 index 0000000..d5878fd --- /dev/null +++ b/apps/planner/app/components/NearbyPoiMarkers.tsx @@ -0,0 +1,49 @@ +import L from "leaflet"; +import { Marker, Tooltip } from "react-leaflet"; +import type { Poi } from "~/lib/overpass"; +import type { PoiCategory } from "@trails-cool/map-core"; + +interface NearbyPoiMarkersProps { + pois: Poi[]; + categories: PoiCategory[]; + onSnap: (poi: Poi) => void; +} + +function nearbyPoiIcon(color: string, icon: string): L.DivIcon { + return L.divIcon({ + className: "", + html: `
${icon}
`, + iconSize: [0, 0], + }); +} + +export function NearbyPoiMarkers({ pois, categories, onSnap }: NearbyPoiMarkersProps) { + return ( + <> + {pois.map((poi) => { + const cat = categories.find((c) => c.id === poi.category); + if (!cat) return null; + return ( + onSnap(poi) }} + zIndexOffset={900} + > + + {poi.name ?? cat.icon} {cat.icon !== poi.name ? cat.icon : ""} + + + ); + })} + + ); +} diff --git a/apps/planner/app/components/PlannerMap.tsx b/apps/planner/app/components/PlannerMap.tsx index 25eceda..76c9de5 100644 --- a/apps/planner/app/components/PlannerMap.tsx +++ b/apps/planner/app/components/PlannerMap.tsx @@ -1,5 +1,5 @@ import { useState, useCallback, useRef } from "react"; -import { MapContainer, TileLayer, LayersControl, Marker, Polyline } from "react-leaflet"; +import { MapContainer, TileLayer, LayersControl, Marker, Polyline, Tooltip } from "react-leaflet"; import L from "leaflet"; import { useTranslation } from "react-i18next"; import type { DayStage } from "@trails-cool/gpx"; @@ -26,22 +26,30 @@ import { } from "./MapHelpers"; import { useWaypointManager } from "~/lib/use-waypoint-manager"; import { useGpxDrop } from "~/lib/use-gpx-drop"; +import { useNearbyPois } from "~/lib/use-nearby-pois"; +import { NearbyPoiMarkers } from "./NearbyPoiMarkers"; +import { poiCategories } from "@trails-cool/map-core"; +import type { Poi } from "~/lib/overpass"; import "leaflet/dist/leaflet.css"; -function waypointIcon(index: number, overnight?: boolean, highlighted?: boolean): L.DivIcon { +function waypointIcon(index: number, overnight?: boolean, highlighted?: boolean, hasNote?: boolean): L.DivIcon { const bg = overnight ? "#8B6D3A" : "#2563eb"; const scale = highlighted ? "scale(1.17)" : "scale(1)"; + const noteIndicator = hasNote + ? `` + : ""; return L.divIcon({ className: "", - html: `
${overnight ? "☾" : index + 1}
`, + html: `
+
${overnight ? "☾" : index + 1}
+ ${noteIndicator} +
`, iconSize: [0, 0], }); } @@ -68,11 +76,12 @@ interface PlannerMapProps { onImportError?: (message: string) => void; highlightPosition?: [number, number] | null; highlightedWaypoint?: number | null; + selectedWaypointIndex?: number | null; onRouteHover?: (distance: number | null) => void; days?: DayStage[]; } -export function PlannerMap({ yjs, sessionId, onRouteRequest, highlightPosition, highlightedWaypoint, onRouteHover, onImportError, days }: PlannerMapProps) { +export function PlannerMap({ yjs, sessionId, onRouteRequest, highlightPosition, highlightedWaypoint, selectedWaypointIndex, onRouteHover, onImportError, days }: PlannerMapProps) { const { t } = useTranslation("planner"); const poiState = usePois(sessionId); useProfileDefaults(yjs, poiState); @@ -107,6 +116,25 @@ export function PlannerMap({ yjs, sessionId, onRouteRequest, highlightPosition, const { draggingOver, handleDragEnter, handleDragLeave, handleDragOver, handleDrop } = useGpxDrop(yjs, onImportError); + const selectedWp = selectedWaypointIndex != null ? waypoints[selectedWaypointIndex] : undefined; + const nearbyPoisState = useNearbyPois(selectedWp?.lat, selectedWp?.lon); + + const handleSnapToPoi = useCallback((poi: Poi) => { + if (selectedWaypointIndex == null) return; + const yMap = yjs.waypoints.get(selectedWaypointIndex); + if (!yMap) return; + const cat = poiCategories.find((c) => c.id === poi.category); + const notePrefix = cat ? `${cat.icon} ${poi.name ?? cat.id}` : (poi.name ?? ""); + yjs.doc.transact(() => { + yMap.set("lat", poi.lat); + yMap.set("lon", poi.lon); + if (poi.name && !yMap.get("name")) yMap.set("name", poi.name); + const existing = yMap.get("note") as string | undefined; + yMap.set("note", existing ? `${notePrefix}\n${existing}` : notePrefix); + if (poi.id) yMap.set("osmId", poi.id); + }, "local"); + }, [selectedWaypointIndex, yjs, poiCategories]); + const handleRoutePolylineOut = useCallback(() => { onRouteHover?.(null); }, [onRouteHover]); @@ -150,6 +178,13 @@ export function PlannerMap({ yjs, sessionId, onRouteRequest, highlightPosition, + {selectedWaypointIndex != null && nearbyPoisState.pois.length > 0 && ( + + )} {waypoints.map((wp, i) => ( { routeInteractionSuspendedRef.current = true; }, mouseout: () => { @@ -180,7 +215,15 @@ export function PlannerMap({ yjs, sessionId, onRouteRequest, highlightPosition, setContextMenu({ x: orig.clientX, y: orig.clientY, index: i }); }, }} - /> + > + {wp.note && ( + + + {wp.note.length > 120 ? wp.note.slice(0, 120) + "…" : wp.note} + + + )} + ))} {days && days.length > 1 && days.map((day) => { diff --git a/apps/planner/app/components/SessionView.tsx b/apps/planner/app/components/SessionView.tsx index 98783ee..0cf1936 100644 --- a/apps/planner/app/components/SessionView.tsx +++ b/apps/planner/app/components/SessionView.tsx @@ -113,7 +113,7 @@ function useAwarenessToasts(yjs: YjsState | null, t: TFunction, addToast: (messa } -function SidebarTabs({ yjs, routeStats, days, onWaypointHover }: { yjs: YjsState; routeStats: ReturnType["routeStats"]; days: ReturnType; onWaypointHover: (index: number | null) => void }) { +function SidebarTabs({ yjs, routeStats, days, onWaypointHover, onWaypointSelect }: { yjs: YjsState; routeStats: ReturnType["routeStats"]; days: ReturnType; onWaypointHover: (index: number | null) => void; onWaypointSelect: (index: number | null) => void }) { const { t } = useTranslation("planner"); const [tab, setTab] = useState<"waypoints" | "notes">("waypoints"); @@ -136,7 +136,7 @@ function SidebarTabs({ yjs, routeStats, days, onWaypointHover }: { yjs: YjsState
{tab === "waypoints" ? ( - + ) : ( @@ -166,6 +166,7 @@ export function SessionView({ sessionId, callbackUrl, callbackToken, returnUrl, const days = useDays(yjs); const [highlightPosition, setHighlightPosition] = useState<[number, number] | null>(null); const [highlightedWaypoint, setHighlightedWaypoint] = useState(null); + const [selectedWaypointIndex, setSelectedWaypointIndex] = useState(null); const [highlightChartDistance, setHighlightChartDistance] = useState(null); const [isZoomedByChart, setIsZoomedByChart] = useState(false); const { toasts, addToast } = useToasts(); @@ -286,7 +287,7 @@ export function SessionView({ sessionId, callbackUrl, callbackToken, returnUrl,
} > - addToast(msg, "error")} days={days} /> + addToast(msg, "error")} days={days} />
@@ -303,7 +304,7 @@ export function SessionView({ sessionId, callbackUrl, callbackToken, returnUrl, - + {toasts.length > 0 && ( diff --git a/apps/planner/app/components/WaypointSidebar.tsx b/apps/planner/app/components/WaypointSidebar.tsx index 3c2d645..cabcab6 100644 --- a/apps/planner/app/components/WaypointSidebar.tsx +++ b/apps/planner/app/components/WaypointSidebar.tsx @@ -1,15 +1,21 @@ -import { useEffect, useState, useCallback } from "react"; +import { useEffect, useState, useCallback, useRef } from "react"; import * as Y from "yjs"; import { useTranslation } from "react-i18next"; import type { YjsState } from "~/lib/use-yjs"; import type { DayStage } from "@trails-cool/gpx"; import { setOvernight, isOvernight } from "~/lib/overnight"; import { DayBreakdown } from "./DayBreakdown"; +import { useNearbyPois } from "~/lib/use-nearby-pois"; +import { poiCategories } from "@trails-cool/map-core"; +import type { Poi } from "~/lib/overpass"; + +const NOTE_MAX = 500; interface WaypointData { lat: number; lon: number; name?: string; + note?: string; overnight: boolean; } @@ -18,6 +24,7 @@ function getWaypointsFromYjs(waypoints: Y.Array>): WaypointData[] lat: yMap.get("lat") as number, lon: yMap.get("lon") as number, name: yMap.get("name") as string | undefined, + note: yMap.get("note") as string | undefined, overnight: isOvernight(yMap), })); } @@ -31,11 +38,16 @@ interface WaypointSidebarProps { }; days: DayStage[]; onWaypointHover?: (index: number | null) => void; + onWaypointSelect?: (index: number | null) => void; } -export function WaypointSidebar({ yjs, routeStats, days, onWaypointHover }: WaypointSidebarProps) { +export function WaypointSidebar({ yjs, routeStats, days, onWaypointHover, onWaypointSelect }: WaypointSidebarProps) { const { t } = useTranslation("planner"); const [waypoints, setWaypoints] = useState([]); + const [selectedIndex, setSelectedIndex] = useState(null); + const [editingNoteIndex, setEditingNoteIndex] = useState(null); + const [noteEditValue, setNoteEditValue] = useState(""); + const textareaRef = useRef(null); useEffect(() => { const update = () => setWaypoints(getWaypointsFromYjs(yjs.waypoints)); @@ -60,7 +72,10 @@ export function WaypointSidebar({ yjs, routeStats, days, onWaypointHover }: Wayp lat: item.get("lat") as number, lon: item.get("lon") as number, name: item.get("name") as string | undefined, + note: item.get("note") as string | undefined, overnight: isOvernight(item), + osmId: item.get("osmId") as number | undefined, + poiTags: item.get("poiTags") as Record | undefined, }; yjs.doc.transact(() => { yjs.waypoints.delete(from, 1); @@ -68,7 +83,10 @@ export function WaypointSidebar({ yjs, routeStats, days, onWaypointHover }: Wayp yMap.set("lat", data.lat); yMap.set("lon", data.lon); if (data.name) yMap.set("name", data.name); + if (data.note) yMap.set("note", data.note); if (data.overnight) yMap.set("overnight", true); + if (data.osmId !== undefined) yMap.set("osmId", data.osmId); + if (data.poiTags) yMap.set("poiTags", data.poiTags); yjs.waypoints.insert(to, [yMap]); }, "local"); }, @@ -84,22 +102,125 @@ export function WaypointSidebar({ yjs, routeStats, days, onWaypointHover }: Wayp [yjs, waypoints], ); + const setNote = useCallback( + (index: number, note: string) => { + const yMap = yjs.waypoints.get(index); + if (!yMap) return; + yjs.doc.transact(() => { + if (note.trim()) { + yMap.set("note", note.trim()); + } else { + yMap.delete("note"); + } + }, "local"); + }, + [yjs], + ); + + const selectWaypoint = useCallback( + (index: number | null) => { + setSelectedIndex(index); + onWaypointSelect?.(index); + }, + [onWaypointSelect], + ); + + const openNoteEditor = useCallback( + (index: number) => { + setNoteEditValue(waypoints[index]?.note ?? ""); + setEditingNoteIndex(index); + setTimeout(() => { + textareaRef.current?.focus(); + // auto-resize + if (textareaRef.current) { + textareaRef.current.style.height = "auto"; + textareaRef.current.style.height = textareaRef.current.scrollHeight + "px"; + } + }, 0); + }, + [waypoints], + ); + + const snapToPoi = useCallback( + (poi: Poi) => { + if (selectedIndex === null) return; + const yMap = yjs.waypoints.get(selectedIndex); + if (!yMap) return; + const cat = poiCategories.find((c) => c.id === poi.category); + const notePrefix = cat ? `${cat.icon} ${poi.name ?? cat.id}` : (poi.name ?? ""); + yjs.doc.transact(() => { + yMap.set("lat", poi.lat); + yMap.set("lon", poi.lon); + if (poi.name && !yMap.get("name")) yMap.set("name", poi.name); + const existing = yMap.get("note") as string | undefined; + yMap.set("note", existing ? `${notePrefix}\n${existing}` : notePrefix); + if (poi.id) yMap.set("osmId", poi.id); + }, "local"); + }, + [selectedIndex, yjs, poiCategories], + ); + + const selectedWp = selectedIndex !== null ? waypoints[selectedIndex] : undefined; + const nearbyPoisState = useNearbyPois(selectedWp?.lat, selectedWp?.lon); + const [showAllNearby, setShowAllNearby] = useState(false); + const hasMultipleDays = days.length > 1; const renderWaypointRow = (wp: WaypointData, i: number) => (
  • selectWaypoint(selectedIndex === i ? null : i)} onMouseEnter={() => onWaypointHover?.(i)} onMouseLeave={() => onWaypointHover?.(null)} > - + {i + 1}

    {wp.name ?? `${wp.lat.toFixed(4)}, ${wp.lon.toFixed(4)}`}

    + {/* Note display / editor */} + {editingNoteIndex === i ? ( +
    e.stopPropagation()}> +