Merge branch 'main' into sec-upload-validation

This commit is contained in:
Ullrich Schäfer 2026-06-10 22:23:37 +02:00 committed by GitHub
commit 31ace379d7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 338 additions and 165 deletions

View file

@ -70,7 +70,7 @@
"zod": "^4.4.3"
},
"devDependencies": {
"@testing-library/react-native": "^13.3.3",
"@testing-library/react-native": "^14.0.0",
"@types/jest": "^29.5.14",
"@types/react": "~19.2.17",
"jest-expo": "^56.0.4",

View file

@ -44,6 +44,59 @@ describe("validateFetchUrl", () => {
});
});
describe("validateFetchUrl — private-address blocking (production)", () => {
beforeEach(() => {
vi.unstubAllEnvs();
// Production-without-E2E is the only mode that blocks (mirrors the
// requireSecret guard). Tests otherwise run as NODE_ENV=test → off.
vi.stubEnv("NODE_ENV", "production");
vi.stubEnv("E2E", "");
});
const blocked = [
"http://127.0.0.1/x",
"http://localhost:3000/x",
"http://sub.localhost/x",
"http://169.254.169.254/latest/meta-data/", // cloud metadata
"http://10.0.0.5/x",
"http://172.16.0.1/x",
"http://172.31.255.254/x",
"http://192.168.1.1/x",
"http://100.64.0.1/x", // CGNAT
"http://0.0.0.0/x",
"http://[::1]/x",
"http://[fc00::1]/x",
"http://[fe80::1]/x",
"http://[::ffff:127.0.0.1]/x",
];
for (const url of blocked) {
it(`blocks ${url}`, () => {
expect(validateFetchUrl(url).ok).toBe(false);
});
}
it("still allows public hosts", () => {
expect(validateFetchUrl("https://journal.trails.cool/api/cb").ok).toBe(true);
expect(validateFetchUrl("http://203.0.113.10/x").ok).toBe(true); // public IP literal
expect(validateFetchUrl("http://172.15.0.1/x").ok).toBe(true); // just outside RFC1918 /12
expect(validateFetchUrl("http://172.32.0.1/x").ok).toBe(true);
});
it("an explicit allowlist overrides private blocking (operator decision)", () => {
expect(
validateFetchUrl("http://10.0.0.2:3000/cb", { allowedHosts: ["10.0.0.2:3000"] }).ok,
).toBe(true);
});
it("does not block private hosts outside production (dev/e2e localhost flow)", () => {
vi.stubEnv("NODE_ENV", "development");
expect(validateFetchUrl("http://localhost:3000/cb").ok).toBe(true);
vi.stubEnv("NODE_ENV", "production");
vi.stubEnv("E2E", "true");
expect(validateFetchUrl("http://localhost:3000/cb").ok).toBe(true);
});
});
describe("validateRedirectUrl", () => {
it("accepts an absolute https URL", () => {
expect(validateRedirectUrl("https://trails.cool/r/123").ok).toBe(true);

View file

@ -16,6 +16,60 @@ export interface UrlValidationResult {
url?: URL;
}
/**
* Whether to reject callback hosts pointing at private / loopback /
* link-local / cloud-metadata ranges. Active in real production only
* mirrors the `requireSecret` guard in the journal's config.server.ts.
* Dev and E2E legitimately point the callback at the journal on
* `localhost`, so blocking there would break the save flow.
*/
function blockPrivateAddresses(): boolean {
return process.env.NODE_ENV === "production" && process.env.E2E !== "true";
}
function isBlockedIpv4(ip: string): boolean {
const o = ip.split(".").map((n) => Number(n));
// Malformed dotted-quad → treat as blocked (fail safe).
if (o.length !== 4 || o.some((n) => !Number.isInteger(n) || n < 0 || n > 255)) {
return true;
}
const [a, b] = o as [number, number, number, number];
if (a === 0 || a === 10 || a === 127) return true; // this-host, RFC1918 /8, loopback
if (a === 169 && b === 254) return true; // link-local incl. 169.254.169.254 metadata
if (a === 172 && b >= 16 && b <= 31) return true; // RFC1918 /12
if (a === 192 && b === 168) return true; // RFC1918 /16
if (a === 100 && b >= 64 && b <= 127) return true; // CGNAT 100.64/10
return false;
}
/**
* Literal private/loopback/link-local hosts. Catches IP literals and
* `localhost`; it does NOT resolve DNS, so a public name that resolves
* to a private IP (DNS-rebinding-style SSRF) is not blocked here set
* PLANNER_CALLBACK_ALLOWED_HOSTS to close that where the callback host
* is known ahead of time.
*/
function isBlockedHost(hostname: string): boolean {
// Node keeps IPv6 brackets on URL.hostname (e.g. "[::1]"); strip them.
const h = hostname.toLowerCase().replace(/^\[|\]$/g, "");
if (h === "localhost" || h.endsWith(".localhost")) return true;
if (h.includes(":")) {
// IPv6.
if (h === "::1" || h === "::") return true;
if (h.startsWith("fc") || h.startsWith("fd")) return true; // ULA fc00::/7
if (h.startsWith("fe8") || h.startsWith("fe9") || h.startsWith("fea") || h.startsWith("feb")) {
return true; // link-local fe80::/10
}
// IPv4-mapped (::ffff:a.b.c.d, which Node may render in hex form).
// Reaching IPv4 through a mapped address is inherently suspect for a
// callback target, so block the whole prefix.
if (h.startsWith("::ffff:")) return true;
return false;
}
if (/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(h)) return isBlockedIpv4(h);
return false;
}
/**
* Validate a URL string for use as a fetch target. Requires absolute
* http(s) URL. If `allowedHosts` is provided, the host must be on the
@ -39,9 +93,16 @@ export function validateFetchUrl(
return { ok: false, reason: `disallowed scheme ${parsed.protocol}` };
}
if (opts.allowedHosts && opts.allowedHosts.length > 0) {
// An explicit allowlist is the operator's decision and the strongest
// control; a host that matches it is trusted even if it's private.
if (!opts.allowedHosts.includes(parsed.host)) {
return { ok: false, reason: `host ${parsed.host} not on allowlist` };
}
} else if (blockPrivateAddresses() && isBlockedHost(parsed.hostname)) {
return {
ok: false,
reason: `host ${parsed.hostname} is a private/loopback/link-local address`,
};
}
return { ok: true, url: parsed };
}

View file

@ -16,6 +16,7 @@ import { data } from "react-router";
import type { Route } from "./+types/api.save-to-journal";
import { getSession } from "~/lib/sessions";
import { fetchWithTimeout } from "~/lib/http.server";
import { validateFetchUrl, getCallbackAllowedHosts } from "~/lib/url-validation.server";
interface SaveRequestBody {
sessionId?: unknown;
@ -51,6 +52,15 @@ export async function action({ request }: Route.ActionArgs) {
return data({ error: "session has no journal callback" }, { status: 400 });
}
// Defense in depth: re-validate immediately before the outbound fetch.
// Guards sessions persisted before callbackUrl validation existed, and
// narrows the window for a host that was public at create time but
// resolves private now.
const v = validateFetchUrl(session.callbackUrl, { allowedHosts: getCallbackAllowedHosts() });
if (!v.ok) {
return data({ error: "session callback URL is not allowed" }, { status: 400 });
}
let resp: Response;
try {
resp = await fetchWithTimeout(session.callbackUrl, {

View file

@ -4,6 +4,7 @@ import { createSession, listSessions } from "~/lib/sessions";
import { parseGpxAsync, extractWaypoints } from "@trails-cool/gpx";
import { withDb } from "@trails-cool/db";
import type { Waypoint } from "@trails-cool/types";
import { validateFetchUrl, getCallbackAllowedHosts } from "~/lib/url-validation.server";
export async function action({ request }: Route.ActionArgs) {
if (request.method !== "POST") {
@ -17,6 +18,20 @@ export async function action({ request }: Route.ActionArgs) {
gpx?: string;
};
// callbackUrl becomes a server-side fetch target on save-to-journal,
// so an unvalidated value here is an SSRF sink. The /new loader
// already validates the query-param form; this is the programmatic
// JSON entry point and must do the same.
if (callbackUrl !== undefined) {
if (typeof callbackUrl !== "string") {
return data({ error: "callbackUrl must be a string" }, { status: 400 });
}
const v = validateFetchUrl(callbackUrl, { allowedHosts: getCallbackAllowedHosts() });
if (!v.ok) {
return data({ error: `Invalid callback URL: ${v.reason}` }, { status: 400 });
}
}
return withDb(async () => {
const session = await createSession({ callbackUrl, callbackToken });

View file

@ -72,16 +72,16 @@
"linkedom": "^0.18.12",
"playwright": "^1.60.0",
"postgres": "catalog:",
"prettier": "^3.8.3",
"prettier": "^3.8.4",
"react": "catalog:",
"react-dom": "catalog:",
"react-i18next": "^17.0.8",
"react-leaflet": "^5.0.0",
"react-router": "catalog:",
"tailwindcss": "catalog:",
"turbo": "^2.9.16",
"turbo": "^2.9.17",
"typescript": "catalog:",
"typescript-eslint": "^8.60.1",
"typescript-eslint": "^8.61.0",
"vite": "catalog:",
"vitest": "^4.1.8"
},

356
pnpm-lock.yaml generated
View file

@ -132,7 +132,7 @@ importers:
version: 10.1.8(eslint@10.4.1(jiti@2.7.0))
eslint-plugin-import-x:
specifier: ^4.16.2
version: 4.16.2(@typescript-eslint/utils@8.60.1(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3))(eslint@10.4.1(jiti@2.7.0))
version: 4.16.2(@typescript-eslint/utils@8.61.0(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3))(eslint@10.4.1(jiti@2.7.0))
fit-file-parser:
specifier: ^3.0.2
version: 3.0.2
@ -158,8 +158,8 @@ importers:
specifier: 'catalog:'
version: 3.4.9
prettier:
specifier: ^3.8.3
version: 3.8.3
specifier: ^3.8.4
version: 3.8.4
react:
specifier: ^19.2.5
version: 19.2.7
@ -179,14 +179,14 @@ importers:
specifier: 'catalog:'
version: 4.3.0
turbo:
specifier: ^2.9.16
version: 2.9.16
specifier: ^2.9.17
version: 2.9.17
typescript:
specifier: 'catalog:'
version: 6.0.3
typescript-eslint:
specifier: ^8.60.1
version: 8.60.1(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3)
specifier: ^8.61.0
version: 8.61.0(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3)
vite:
specifier: 'catalog:'
version: 8.0.13(@types/node@25.9.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.48.0)(tsx@4.21.0)(yaml@2.9.0)
@ -382,7 +382,7 @@ importers:
version: 56.0.16(expo@56.0.9)(react-native@0.85.3(@babel/core@7.29.7)(@react-native/jest-preset@0.85.3(@babel/core@7.29.7)(react@19.2.7))(@react-native/metro-config@0.85.3(@babel/core@7.29.7))(@types/react@19.2.17)(react@19.2.7))(react@19.2.7)(typescript@6.0.3)
expo-router:
specifier: ~56.2.9
version: 56.2.9(0eba4098a5195e5629f2d05bdadf3fed)
version: 56.2.9(32ebb48fb3c89ce8dbed2a3aa0224111)
expo-secure-store:
specifier: ~56.0.4
version: 56.0.4(expo@56.0.9)
@ -430,8 +430,8 @@ importers:
version: 4.4.3
devDependencies:
'@testing-library/react-native':
specifier: ^13.3.3
version: 13.3.3(jest@29.7.0(@types/node@25.9.2))(react-native@0.85.3(@babel/core@7.29.7)(@react-native/jest-preset@0.85.3(@babel/core@7.29.7)(react@19.2.7))(@react-native/metro-config@0.85.3(@babel/core@7.29.7))(@types/react@19.2.17)(react@19.2.7))(react-test-renderer@19.2.7(react@19.2.7))(react@19.2.7)
specifier: ^14.0.0
version: 14.0.0(jest@29.7.0(@types/node@25.9.2))(react-native@0.85.3(@babel/core@7.29.7)(@react-native/jest-preset@0.85.3(@babel/core@7.29.7)(react@19.2.7))(@react-native/metro-config@0.85.3(@babel/core@7.29.7))(@types/react@19.2.17)(react@19.2.7))(react@19.2.7)(test-renderer@1.2.0(@types/react@19.2.17)(react@19.2.7))
'@types/jest':
specifier: ^29.5.14
version: 29.5.14
@ -2161,8 +2161,8 @@ packages:
resolution: {integrity: sha512-4QqS3LY5PBmTRHj9sAg1HLoPzqAI0uOX6wI/TRqHIcOxlFidy6YEmCQJk6FSZjNLGCeubDMfmkWL+qaLKhSGQA==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
'@jest/diff-sequences@30.3.0':
resolution: {integrity: sha512-cG51MVnLq1ecVUaQ3fr6YuuAOitHK1S4WUJHnsPFE/quQr33ADUx1FfrTCpMCRxvy0Yr9BThKpDjSlcTi91tMA==}
'@jest/diff-sequences@30.4.0':
resolution: {integrity: sha512-zOpzlfUs45l6u7jm39qr87JCHUDsaeCtvL+kQe/Vn9jSnRB4/5IPXISm0h9I1vZW/o00Kn4UTJ2MOlhnUGwv3g==}
engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0}
'@jest/environment@29.7.0':
@ -2202,8 +2202,8 @@ packages:
resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
'@jest/schemas@30.0.5':
resolution: {integrity: sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==}
'@jest/schemas@30.4.1':
resolution: {integrity: sha512-i6b4qw5qnP8c5FEeBJg/uZQ4ddrkN6Ca8qISJh0pr7a5hfn3h3v5x60BEbOC7OYAGZNMs1LfFLwnW2CuK8F57Q==}
engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0}
'@jest/source-map@29.6.3':
@ -3486,14 +3486,14 @@ packages:
resolution: {integrity: sha512-zIcONa+hVtVSSep9UT3jZ5rizo2BsxgyDYU7WFD5eICBE7no3881HGeb/QkGfsJs6JTkY1aQhT7rIPC7e+0nnA==}
engines: {node: '>=14', npm: '>=6', yarn: '>=1'}
'@testing-library/react-native@13.3.3':
resolution: {integrity: sha512-k6Mjsd9dbZgvY4Bl7P1NIpePQNi+dfYtlJ5voi9KQlynxSyQkfOgJmYGCYmw/aSgH/rUcFvG8u5gd4npzgRDyg==}
engines: {node: '>=18'}
'@testing-library/react-native@14.0.0':
resolution: {integrity: sha512-Ji+mmlvWp9kTOhqWIskVfCQ05LdmsS3NN6PtG8blYHyd5yLvghSsul5QS4ci01Fw65H9oa6slj9PEOyoogj1VQ==}
engines: {node: ^22.13.0 || >=24}
peerDependencies:
jest: '>=29.0.0'
react: ^19.2.5
react-native: '>=0.71'
react-test-renderer: '>=18.2.0'
react-native: '>=0.78'
test-renderer: ^1.0.0
peerDependenciesMeta:
jest:
optional: true
@ -3523,33 +3523,33 @@ packages:
resolution: {integrity: sha512-HqmEUIGRJ5fSXchkVgR5F7qn48bDBzv0kWj/Kfu5e6uci4UlEeng4331LnBkWffb++Ei3FOVLxo8JJWMFBDMeQ==}
engines: {node: '>= 10'}
'@turbo/darwin-64@2.9.16':
resolution: {integrity: sha512-jLjApWTSNd7JZ5JaLYfelW1ytnGQOvB7ivl+2RD1xQvJTbi8I9gBjzcga7tDZVPyaxpl10YTfJt3BrYXR18KDw==}
'@turbo/darwin-64@2.9.17':
resolution: {integrity: sha512-io5jn5RDeU+9YV78rWhwG++HD/OZ/Lxg1sg93+jDGKQNP3UDxY6RX2dmarbCILhNxNuAM8FH3WgGMY9E96Mf8w==}
cpu: [x64]
os: [darwin]
'@turbo/darwin-arm64@2.9.16':
resolution: {integrity: sha512-YPgrn+5HIGzrx0O2a631SV4MBQUe4W/DafMFUuBVgaU32PW9/OTT0ehviF0QSxTXuRJlHvW2eUTemddF5/spmw==}
'@turbo/darwin-arm64@2.9.17':
resolution: {integrity: sha512-83YZTYmN2sxFWf2LTMOwqbOvR3qZMa/TSFwnB6BHVBbIWyoPPe+TAdSTd8KevEx8ml8KkycJ/9A70DFVReyUww==}
cpu: [arm64]
os: [darwin]
'@turbo/linux-64@2.9.16':
resolution: {integrity: sha512-vAEf1H6l26lTpl9FJ/peQo1NUB8RC0sbEJJz5mPcUhHA2bPDup2x3CZPgo/bH8S4cUcBLm4FN3UHd5iUO2RAew==}
'@turbo/linux-64@2.9.17':
resolution: {integrity: sha512-teKfwJg0zSC+C2ZSOsX3VnAJGVgcN+pgKNmnGWzcpXQ9eIkAQtYP+getrQ2f1Tw/ePudnreQhq8tVP8S73Vy6Q==}
cpu: [x64]
os: [linux]
'@turbo/linux-arm64@2.9.16':
resolution: {integrity: sha512-xDBLR2PZg4BrQOchfG6svgpv5FCNJ2TOtT2psLdEJcdKo1BH+pnPs9Xj6pvUjgfkHbuvBOfeE4R6tvxMoQKDHQ==}
'@turbo/linux-arm64@2.9.17':
resolution: {integrity: sha512-mqO36x2CNtJ9CCbEf5xOqH662tVSc1wB0mxh7dopBpgXg0fEifdzwX0IEAUW1WUAaNH986L7iEUUgw3HNqUWgg==}
cpu: [arm64]
os: [linux]
'@turbo/windows-64@2.9.16':
resolution: {integrity: sha512-NBAJnaUiGdgkSzQwUIdOvkCkcpTSu58G/sBGa0mvBtzfvFOOgrQwepKOOQ8cp6sWM6OcKDNFj2p1dsZA1OWjPg==}
'@turbo/windows-64@2.9.17':
resolution: {integrity: sha512-jbyoNePufyMoSSrvVr+/mglcjmya/MOgoIrSHPr67iZ1VFgrlMQXHXtptR2lR48gi+86b1XBvsviJZ9A7zrydg==}
cpu: [x64]
os: [win32]
'@turbo/windows-arm64@2.9.16':
resolution: {integrity: sha512-Y7SJppD0Z8wjO3Ec0ZGd9KQ4Yv0BMnA8CIowj5Vp+OEVsosXDG2weK6/t1RRLfJmc2Ozrnd6y4DOgQys+mn3WQ==}
'@turbo/windows-arm64@2.9.17':
resolution: {integrity: sha512-+ql0wYc99Y2AMvyHCcC/P+xtyV4nz522L+C9HDnyi7ryHXBGM+ZjBP28M7SLBGMDImgpN8sk2szpgbvreMeXVA==}
cpu: [arm64]
os: [win32]
@ -3696,6 +3696,11 @@ packages:
peerDependencies:
'@types/react': ^19.2.0
'@types/react-reconciler@0.33.0':
resolution: {integrity: sha512-HZOXsKT0tGI9LlUw2LuedXsVeB88wFa536vVL0M6vE8zN63nI+sSr1ByxmPToP5K5bukaVscyeCJcF9guVNJ1g==}
peerDependencies:
'@types/react': '*'
'@types/react-test-renderer@19.1.0':
resolution: {integrity: sha512-XD0WZrHqjNrxA/MaR9O22w/RNidWR9YZmBdRGI7wcnWGrv/3dA8wKCJ8m63Sn+tLJhcjmuhOi629N66W6kgWzQ==}
@ -3717,63 +3722,63 @@ packages:
'@types/yargs@17.0.35':
resolution: {integrity: sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==}
'@typescript-eslint/eslint-plugin@8.60.1':
resolution: {integrity: sha512-JQ4S5GB0tfjO8BuJ4fcX+HodkzJjYBV+7OJ+wLygaX7OGQ7FudyHL4NSCA6ob+w3Yn+5MkKIozOwQhXeM7opVg==}
'@typescript-eslint/eslint-plugin@8.61.0':
resolution: {integrity: sha512-bFNvl9ZczlVb+wR2Akszf3gHfKVj/8WanXaGJ3UstTA7brNKg0cNdk6X1Psu5V7MZ2oQtzZKOEzIUehaoxbDGw==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
'@typescript-eslint/parser': ^8.60.1
'@typescript-eslint/parser': ^8.61.0
eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
typescript: '>=4.8.4 <6.1.0'
'@typescript-eslint/parser@8.60.1':
resolution: {integrity: sha512-A0M6ua6H252bVjPvvtSgl2QA4+ET9S5Mtkb2GDyTxIhH/C4qDItT7RQNO5PhMC6NXGYXOR9dIalcDDgBKT7oFA==}
'@typescript-eslint/parser@8.61.0':
resolution: {integrity: sha512-5B7PfA2e1NQGCnDHd/0lW7W3gvp3d59Ryw54FYO8Uswxo9f6ikw3AZV+Xj/TvpImmpsiYyUqAfhC6kJID1jF6w==}
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.60.1':
resolution: {integrity: sha512-eXkTH2bxmXlqD1RnOPmLZ9ZM9D3VwSx04JOwBnP9RQ+yUA5a2Mu7SfW8uaV2Aon53NJzZlZYuX7tn91Izf+xaw==}
'@typescript-eslint/project-service@8.61.0':
resolution: {integrity: sha512-DV42F7MLJO6Rax7SK1yg43tcnEfGUrurSpSxKuVX+a3RCTzBlH3fuxprrOJXKCJGAaw82xXocikJ0uQaqwXgGA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
typescript: '>=4.8.4 <6.1.0'
'@typescript-eslint/scope-manager@8.60.1':
resolution: {integrity: sha512-gvI5OQoptnxQnchOirukCuQ55svJSTuD/4k5+pC267xyBtYry748R9/c3tYUzb/iE6RZfllRz2lVulLCHkTm4w==}
'@typescript-eslint/scope-manager@8.61.0':
resolution: {integrity: sha512-IWdXFHFSb6mlC3HPc7QsLDm5zYEbUla6trDEHf32D3/dnuUyXd87plScSNXSbm0/RxMvObpI17sv/EDTGrGZkA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@typescript-eslint/tsconfig-utils@8.60.1':
resolution: {integrity: sha512-nh8w4qAteiKuZu3pSSzG/yGKpw0OlkrKnzFmbVRenKaD4qc+7i1GrmZaLVkr8rk4uipiPGMOW4YsM6WmKZ5CvA==}
'@typescript-eslint/tsconfig-utils@8.61.0':
resolution: {integrity: sha512-O5Amvdv9ztMpxpf+vmFULGG78IE6Qwdr3bCGvqwG4nwc9H2qXkOYJJnRbRHyMkQTjv1d03olqwwwzHLMqpFePQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
typescript: '>=4.8.4 <6.1.0'
'@typescript-eslint/type-utils@8.60.1':
resolution: {integrity: sha512-sdwTrpjosW7ANQYJ39ZBF1ZyEMEGVB2UsikrserVM/30a/F1dTLnu9bGxEdosugyu5caigjLrR2qiD11asjI1A==}
'@typescript-eslint/type-utils@8.61.0':
resolution: {integrity: sha512-TuBiQYIkd97yBfInHCTKVYMbX4kvEmpOEuixIuzCU9p8BGT1SfyyO0d0IfDMbPIHcjn/hWnusUX5e8v5Xg+X8A==}
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.60.1':
resolution: {integrity: sha512-4h0tY8ppCkdCzcrl2YM5M3my0xsE1Tf8om3owEu5oPWmXwkKRmk0j0LGDzYBGUcAlesEbxBhazqu/K4cu3Ug7w==}
'@typescript-eslint/types@8.61.0':
resolution: {integrity: sha512-9QTQpZ5Iin4CdIodfbDQFSeiSJKidgYJYug1P9CC2xWgUTvlmixViqDZNciMjwLBZyJnG4tGmPl97rVAFb1AJg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@typescript-eslint/typescript-estree@8.60.1':
resolution: {integrity: sha512-alpRkfG8hlVE5kdJW2GkfgDgXxold3e8e4l6EnmhRmRLbekgAPCCGDVD++sABy9FcgPFroq+uFcCSM1vR57Cew==}
'@typescript-eslint/typescript-estree@8.61.0':
resolution: {integrity: sha512-42zatd5qSvvcV1JdDBCLxYRznvP4eIHpPoZXdkPFnAmanA4FuZ5dibSnCBggY8hQnqajPpoGjXFdZ7fIJKQnlA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
typescript: '>=4.8.4 <6.1.0'
'@typescript-eslint/utils@8.60.1':
resolution: {integrity: sha512-h2MPBLoNtjc3qZWfY3Tl51yPorQ2McHn8pJfcMNTcIvrrZrr90Ykffit0yjrPFWQcRcUxzH20+6OcVdW4yHtUg==}
'@typescript-eslint/utils@8.61.0':
resolution: {integrity: sha512-3bzFt7ImFMW/jVYwJamDoe/dMOdFLSC6pom6rRjdh4SZJEYupyMzem8e7vKZLclLfpHjlwSAXOUxtKxGXUiLqA==}
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.60.1':
resolution: {integrity: sha512-EbGRQg4FhrmwLodl+t3JNAnXHWVr9Vp+Zl1QBZVPY4ByfkzIT8cX3K6QWODHtkIZqqJVEWvhHSx3v5PDHsaQag==}
'@typescript-eslint/visitor-keys@8.61.0':
resolution: {integrity: sha512-QVLZu3ZPQEE+HICQyAMZ2yLQhxf0meY/wx6Hx14YcTNj13JB3qHlX3lJ02L3fLGHgERRH71kvYDwiXIguT3AjQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@ungap/structured-clone@1.3.1':
@ -5700,8 +5705,8 @@ packages:
resolution: {integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
jest-diff@30.3.0:
resolution: {integrity: sha512-n3q4PDQjS4LrKxfWB3Z5KNk1XjXtZTBwQp71OP0Jo03Z6V60x++K5L8k6ZrW8MY8pOFylZvHM0zsjS1RqlHJZQ==}
jest-diff@30.4.1:
resolution: {integrity: sha512-CRpFK0RtLriVDGcPPAnR6HMVI8bSR2jnUIgralhauzYQZIb4RH9AtEInTuQr65LmmGggGcRT6HIASxwqsVsmlA==}
engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0}
jest-docblock@29.7.0:
@ -5755,8 +5760,8 @@ packages:
resolution: {integrity: sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
jest-matcher-utils@30.3.0:
resolution: {integrity: sha512-HEtc9uFQgaUHkC7nLSlQL3Tph4Pjxt/yiPvkIrrDCt9jhoLIgxaubo1G+CFOnmHYMxHwwdaSN7mkIFs6ZK8OhA==}
jest-matcher-utils@30.4.1:
resolution: {integrity: sha512-zvYfX5CaeEkFrrLS9suWe9rvJrm9J1Iv3ua8kIBv9GEPzcnsfBf0bob37la7s67fs0nlBC3EuvkOLnXQKxtx4A==}
engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0}
jest-message-util@29.7.0:
@ -6661,8 +6666,8 @@ packages:
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
engines: {node: '>= 0.8.0'}
prettier@3.8.3:
resolution: {integrity: sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==}
prettier@3.8.4:
resolution: {integrity: sha512-N2MylSdi48+5N/6S5j+maeHbUSIzzZ5uOcX5Hm4QpV8Dkb1HFjfAKTKX6yNPJQD9AhcT3ifHNB66tWTTJDi11Q==}
engines: {node: '>=14'}
hasBin: true
@ -6674,8 +6679,8 @@ packages:
resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
pretty-format@30.3.0:
resolution: {integrity: sha512-oG4T3wCbfeuvljnyAzhBvpN45E8iOTXCU/TD3zXW80HA3dQ4ahdqMkWGiPWZvjpQwlbyHrPTWUAqUzGzv4l1JQ==}
pretty-format@30.4.1:
resolution: {integrity: sha512-K6KiKMHTL4jjX4u3Kir2EW07nRfcqVTXIImx50wbjHQTcZPgg+gjVeNTIT3l3L1Rd4UefxfogquC9J37SoFyyw==}
engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0}
proc-log@4.2.0:
@ -6885,6 +6890,12 @@ packages:
'@types/react':
optional: true
react-reconciler@0.33.0:
resolution: {integrity: sha512-KetWRytFv1epdpJc3J4G75I4WrplZE5jOL7Yq0p34+OVOKF4Se7WrdIdVC45XsSSmUTlht2FM/fM1FZb1mfQeA==}
engines: {node: '>=0.10.0'}
peerDependencies:
react: ^19.2.5
react-refresh@0.14.2:
resolution: {integrity: sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==}
engines: {node: '>=0.10.0'}
@ -7083,8 +7094,8 @@ packages:
resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
hasBin: true
semver@7.8.2:
resolution: {integrity: sha512-c8jsqUZm3omBOI66G90z1Dyw5z622G8oLG+omfsHBJf3CWQTlOcwOjvOG6wtiNfW6anKm/eA39LMwMtMez2TiQ==}
semver@7.8.4:
resolution: {integrity: sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==}
engines: {node: '>=10'}
hasBin: true
@ -7405,6 +7416,11 @@ packages:
resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==}
engines: {node: '>=8'}
test-renderer@1.2.0:
resolution: {integrity: sha512-JYiEGbgBGtmHAWX8Kf99gGRL1HtjcRVHLrmJNTZL4vFs9XrnWcuL45Iszw/pO4094+JR7havSrN+ds6YTOpSQA==}
peerDependencies:
react: ^19.2.5
thread-stream@4.0.0:
resolution: {integrity: sha512-4iMVL6HAINXWf1ZKZjIPcz5wYaOdPhtO8ATvZ+Xqp3BTdaqtAwQkNmKORqcIo5YkQqGXq5cwfswDwMqqQNrpJA==}
engines: {node: '>=20'}
@ -7501,8 +7517,8 @@ packages:
tunnel-agent@0.6.0:
resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==}
turbo@2.9.16:
resolution: {integrity: sha512-NqgRQy6j6dPYcdSdv0q1g9QsZg7SWg87RERM8otw/1AtKU2yTFVClOM7cbwKzOonZr/Ek1blTBucw64L9H0Bwg==}
turbo@2.9.17:
resolution: {integrity: sha512-91Q3KxfHJn7esFu2Ic6j9pkvQqWjncQCOp7r1gCKChRSb/+T/yIjsavAmbGLmFRKAzSjmWW/FMrcknmJ4hEOPA==}
hasBin: true
type-check@0.4.0:
@ -7529,8 +7545,8 @@ packages:
resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==}
engines: {node: '>= 0.6'}
typescript-eslint@8.60.1:
resolution: {integrity: sha512-6m5hkkRAp8lKvhVpcprAIn5KkehQEh+47oHH2VGnExEh7dhNxXlg6GPAOIu6TxbVQxhebrJDvjl3020ooiWCMA==}
typescript-eslint@8.61.0:
resolution: {integrity: sha512-8y31Rd0eGTrDKqhy6vT0HtzhN+YLjQizwX3aA3hPXP/ynSfnrBXcQY5IzsP9/DM7+klX4IUncZZjkchP0z+rUw==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
@ -9028,7 +9044,7 @@ snapshots:
progress: 2.0.3
prompts: 2.4.2
resolve-from: 5.0.0
semver: 7.8.2
semver: 7.8.4
send: 0.19.2
slugify: 1.6.9
stacktrace-parser: 0.1.11
@ -9039,7 +9055,7 @@ snapshots:
ws: 8.21.0
zod: 3.25.76
optionalDependencies:
expo-router: 56.2.9(0eba4098a5195e5629f2d05bdadf3fed)
expo-router: 56.2.9(32ebb48fb3c89ce8dbed2a3aa0224111)
react-native: 0.85.3(@babel/core@7.29.7)(@react-native/jest-preset@0.85.3(@babel/core@7.29.7)(react@19.2.7))(@react-native/metro-config@0.85.3(@babel/core@7.29.7))(@types/react@19.2.17)(react@19.2.7)
transitivePeerDependencies:
- '@expo/dom-webview'
@ -9069,7 +9085,7 @@ snapshots:
debug: 4.4.3
getenv: 2.0.0
glob: 13.0.6
semver: 7.8.2
semver: 7.8.4
slugify: 1.6.9
xcode: 3.0.1
xml2js: 0.6.0
@ -9089,7 +9105,7 @@ snapshots:
getenv: 2.0.0
glob: 13.0.6
resolve-workspace-root: 2.0.1
semver: 7.8.2
semver: 7.8.4
slugify: 1.6.9
transitivePeerDependencies:
- supports-color
@ -9137,7 +9153,7 @@ snapshots:
ignore: 5.3.2
minimatch: 10.2.5
resolve-from: 5.0.0
semver: 7.8.2
semver: 7.8.4
transitivePeerDependencies:
- supports-color
@ -9149,7 +9165,7 @@ snapshots:
getenv: 2.0.0
jimp-compact: 0.16.1
parse-png: 2.1.0
semver: 7.8.2
semver: 7.8.4
transitivePeerDependencies:
- supports-color
- typescript
@ -9292,7 +9308,7 @@ snapshots:
debug: 4.4.3
expo-modules-autolinking: 56.0.15(typescript@6.0.3)
resolve-from: 5.0.0
semver: 7.8.2
semver: 7.8.4
transitivePeerDependencies:
- supports-color
- typescript
@ -9317,7 +9333,7 @@ snapshots:
react: 19.2.7
optionalDependencies:
'@expo/metro-runtime': 56.0.14(@expo/log-box@56.0.12)(expo@56.0.9)(react-dom@19.2.7(react@19.2.7))(react-native@0.85.3(@babel/core@7.29.7)(@react-native/jest-preset@0.85.3(@babel/core@7.29.7)(react@19.2.7))(@react-native/metro-config@0.85.3(@babel/core@7.29.7))(@types/react@19.2.17)(react@19.2.7))(react@19.2.7)
expo-router: 56.2.9(0eba4098a5195e5629f2d05bdadf3fed)
expo-router: 56.2.9(32ebb48fb3c89ce8dbed2a3aa0224111)
react-dom: 19.2.7(react@19.2.7)
transitivePeerDependencies:
- supports-color
@ -9663,7 +9679,7 @@ snapshots:
dependencies:
'@jest/types': 29.6.3
'@jest/diff-sequences@30.3.0': {}
'@jest/diff-sequences@30.4.0': {}
'@jest/environment@29.7.0':
dependencies:
@ -9736,7 +9752,7 @@ snapshots:
dependencies:
'@sinclair/typebox': 0.27.10
'@jest/schemas@30.0.5':
'@jest/schemas@30.4.1':
dependencies:
'@sinclair/typebox': 0.34.49
@ -10326,7 +10342,7 @@ snapshots:
metro: 0.84.4
metro-config: 0.84.4
metro-core: 0.84.4
semver: 7.8.2
semver: 7.8.4
optionalDependencies:
'@react-native/metro-config': 0.85.3(@babel/core@7.29.7)
transitivePeerDependencies:
@ -10433,10 +10449,10 @@ snapshots:
pathe: 1.1.2
picocolors: 1.1.1
pkg-types: 2.3.1
prettier: 3.8.3
prettier: 3.8.4
react-refresh: 0.14.2
react-router: 7.17.0(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
semver: 7.8.2
semver: 7.8.4
tinyglobby: 0.2.17
valibot: 1.4.1(typescript@6.0.3)
vite: 8.0.13(@types/node@25.9.2)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.48.0)(tsx@4.21.0)(yaml@2.9.0)
@ -11023,15 +11039,15 @@ snapshots:
picocolors: 1.1.1
redent: 3.0.0
'@testing-library/react-native@13.3.3(jest@29.7.0(@types/node@25.9.2))(react-native@0.85.3(@babel/core@7.29.7)(@react-native/jest-preset@0.85.3(@babel/core@7.29.7)(react@19.2.7))(@react-native/metro-config@0.85.3(@babel/core@7.29.7))(@types/react@19.2.17)(react@19.2.7))(react-test-renderer@19.2.7(react@19.2.7))(react@19.2.7)':
'@testing-library/react-native@14.0.0(jest@29.7.0(@types/node@25.9.2))(react-native@0.85.3(@babel/core@7.29.7)(@react-native/jest-preset@0.85.3(@babel/core@7.29.7)(react@19.2.7))(@react-native/metro-config@0.85.3(@babel/core@7.29.7))(@types/react@19.2.17)(react@19.2.7))(react@19.2.7)(test-renderer@1.2.0(@types/react@19.2.17)(react@19.2.7))':
dependencies:
jest-matcher-utils: 30.3.0
jest-matcher-utils: 30.4.1
picocolors: 1.1.1
pretty-format: 30.3.0
pretty-format: 30.4.1
react: 19.2.7
react-native: 0.85.3(@babel/core@7.29.7)(@react-native/jest-preset@0.85.3(@babel/core@7.29.7)(react@19.2.7))(@react-native/metro-config@0.85.3(@babel/core@7.29.7))(@types/react@19.2.17)(react@19.2.7)
react-test-renderer: 19.2.7(react@19.2.7)
redent: 3.0.0
test-renderer: 1.2.0(@types/react@19.2.17)(react@19.2.7)
optionalDependencies:
jest: 29.7.0(@types/node@25.9.2)
@ -11051,22 +11067,22 @@ snapshots:
'@tootallnate/once@2.0.1': {}
'@turbo/darwin-64@2.9.16':
'@turbo/darwin-64@2.9.17':
optional: true
'@turbo/darwin-arm64@2.9.16':
'@turbo/darwin-arm64@2.9.17':
optional: true
'@turbo/linux-64@2.9.16':
'@turbo/linux-64@2.9.17':
optional: true
'@turbo/linux-arm64@2.9.16':
'@turbo/linux-arm64@2.9.17':
optional: true
'@turbo/windows-64@2.9.16':
'@turbo/windows-64@2.9.17':
optional: true
'@turbo/windows-arm64@2.9.16':
'@turbo/windows-arm64@2.9.17':
optional: true
'@turf/bbox@7.3.4':
@ -11328,6 +11344,10 @@ snapshots:
dependencies:
'@types/react': 19.2.17
'@types/react-reconciler@0.33.0(@types/react@19.2.17)':
dependencies:
'@types/react': 19.2.17
'@types/react-test-renderer@19.1.0':
dependencies:
'@types/react': 19.2.17
@ -11350,14 +11370,14 @@ snapshots:
dependencies:
'@types/yargs-parser': 21.0.3
'@typescript-eslint/eslint-plugin@8.60.1(@typescript-eslint/parser@8.60.1(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3))(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3)':
'@typescript-eslint/eslint-plugin@8.61.0(@typescript-eslint/parser@8.61.0(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3))(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3)':
dependencies:
'@eslint-community/regexpp': 4.12.2
'@typescript-eslint/parser': 8.60.1(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3)
'@typescript-eslint/scope-manager': 8.60.1
'@typescript-eslint/type-utils': 8.60.1(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3)
'@typescript-eslint/utils': 8.60.1(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3)
'@typescript-eslint/visitor-keys': 8.60.1
'@typescript-eslint/parser': 8.61.0(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3)
'@typescript-eslint/scope-manager': 8.61.0
'@typescript-eslint/type-utils': 8.61.0(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3)
'@typescript-eslint/utils': 8.61.0(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3)
'@typescript-eslint/visitor-keys': 8.61.0
eslint: 10.4.1(jiti@2.7.0)
ignore: 7.0.5
natural-compare: 1.4.0
@ -11366,41 +11386,41 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@typescript-eslint/parser@8.60.1(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3)':
'@typescript-eslint/parser@8.61.0(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3)':
dependencies:
'@typescript-eslint/scope-manager': 8.60.1
'@typescript-eslint/types': 8.60.1
'@typescript-eslint/typescript-estree': 8.60.1(typescript@6.0.3)
'@typescript-eslint/visitor-keys': 8.60.1
'@typescript-eslint/scope-manager': 8.61.0
'@typescript-eslint/types': 8.61.0
'@typescript-eslint/typescript-estree': 8.61.0(typescript@6.0.3)
'@typescript-eslint/visitor-keys': 8.61.0
debug: 4.4.3
eslint: 10.4.1(jiti@2.7.0)
typescript: 6.0.3
transitivePeerDependencies:
- supports-color
'@typescript-eslint/project-service@8.60.1(typescript@6.0.3)':
'@typescript-eslint/project-service@8.61.0(typescript@6.0.3)':
dependencies:
'@typescript-eslint/tsconfig-utils': 8.60.1(typescript@6.0.3)
'@typescript-eslint/types': 8.60.1
'@typescript-eslint/tsconfig-utils': 8.61.0(typescript@6.0.3)
'@typescript-eslint/types': 8.61.0
debug: 4.4.3
typescript: 6.0.3
transitivePeerDependencies:
- supports-color
'@typescript-eslint/scope-manager@8.60.1':
'@typescript-eslint/scope-manager@8.61.0':
dependencies:
'@typescript-eslint/types': 8.60.1
'@typescript-eslint/visitor-keys': 8.60.1
'@typescript-eslint/types': 8.61.0
'@typescript-eslint/visitor-keys': 8.61.0
'@typescript-eslint/tsconfig-utils@8.60.1(typescript@6.0.3)':
'@typescript-eslint/tsconfig-utils@8.61.0(typescript@6.0.3)':
dependencies:
typescript: 6.0.3
'@typescript-eslint/type-utils@8.60.1(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3)':
'@typescript-eslint/type-utils@8.61.0(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3)':
dependencies:
'@typescript-eslint/types': 8.60.1
'@typescript-eslint/typescript-estree': 8.60.1(typescript@6.0.3)
'@typescript-eslint/utils': 8.60.1(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3)
'@typescript-eslint/types': 8.61.0
'@typescript-eslint/typescript-estree': 8.61.0(typescript@6.0.3)
'@typescript-eslint/utils': 8.61.0(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3)
debug: 4.4.3
eslint: 10.4.1(jiti@2.7.0)
ts-api-utils: 2.5.0(typescript@6.0.3)
@ -11408,37 +11428,37 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@typescript-eslint/types@8.60.1': {}
'@typescript-eslint/types@8.61.0': {}
'@typescript-eslint/typescript-estree@8.60.1(typescript@6.0.3)':
'@typescript-eslint/typescript-estree@8.61.0(typescript@6.0.3)':
dependencies:
'@typescript-eslint/project-service': 8.60.1(typescript@6.0.3)
'@typescript-eslint/tsconfig-utils': 8.60.1(typescript@6.0.3)
'@typescript-eslint/types': 8.60.1
'@typescript-eslint/visitor-keys': 8.60.1
'@typescript-eslint/project-service': 8.61.0(typescript@6.0.3)
'@typescript-eslint/tsconfig-utils': 8.61.0(typescript@6.0.3)
'@typescript-eslint/types': 8.61.0
'@typescript-eslint/visitor-keys': 8.61.0
debug: 4.4.3
minimatch: 10.2.5
semver: 7.8.2
semver: 7.8.4
tinyglobby: 0.2.17
ts-api-utils: 2.5.0(typescript@6.0.3)
typescript: 6.0.3
transitivePeerDependencies:
- supports-color
'@typescript-eslint/utils@8.60.1(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3)':
'@typescript-eslint/utils@8.61.0(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3)':
dependencies:
'@eslint-community/eslint-utils': 4.9.1(eslint@10.4.1(jiti@2.7.0))
'@typescript-eslint/scope-manager': 8.60.1
'@typescript-eslint/types': 8.60.1
'@typescript-eslint/typescript-estree': 8.60.1(typescript@6.0.3)
'@typescript-eslint/scope-manager': 8.61.0
'@typescript-eslint/types': 8.61.0
'@typescript-eslint/typescript-estree': 8.61.0(typescript@6.0.3)
eslint: 10.4.1(jiti@2.7.0)
typescript: 6.0.3
transitivePeerDependencies:
- supports-color
'@typescript-eslint/visitor-keys@8.60.1':
'@typescript-eslint/visitor-keys@8.61.0':
dependencies:
'@typescript-eslint/types': 8.60.1
'@typescript-eslint/types': 8.61.0
eslint-visitor-keys: 5.0.1
'@ungap/structured-clone@1.3.1': {}
@ -12524,21 +12544,21 @@ snapshots:
optionalDependencies:
unrs-resolver: 1.12.2
eslint-plugin-import-x@4.16.2(@typescript-eslint/utils@8.60.1(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3))(eslint@10.4.1(jiti@2.7.0)):
eslint-plugin-import-x@4.16.2(@typescript-eslint/utils@8.61.0(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3))(eslint@10.4.1(jiti@2.7.0)):
dependencies:
'@package-json/types': 0.0.12
'@typescript-eslint/types': 8.60.1
'@typescript-eslint/types': 8.61.0
comment-parser: 1.4.7
debug: 4.4.3
eslint: 10.4.1(jiti@2.7.0)
eslint-import-context: 0.1.9(unrs-resolver@1.12.2)
is-glob: 4.0.3
minimatch: 10.2.5
semver: 7.8.2
semver: 7.8.4
stable-hash-x: 0.2.0
unrs-resolver: 1.12.2
optionalDependencies:
'@typescript-eslint/utils': 8.60.1(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3)
'@typescript-eslint/utils': 8.61.0(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3)
transitivePeerDependencies:
- supports-color
@ -12809,7 +12829,7 @@ snapshots:
- supports-color
- typescript
expo-router@56.2.9(0eba4098a5195e5629f2d05bdadf3fed):
expo-router@56.2.9(32ebb48fb3c89ce8dbed2a3aa0224111):
dependencies:
'@expo/log-box': 56.0.12(@expo/dom-webview@55.0.5)(expo@56.0.9)(react-native@0.85.3(@babel/core@7.29.7)(@react-native/jest-preset@0.85.3(@babel/core@7.29.7)(react@19.2.7))(@react-native/metro-config@0.85.3(@babel/core@7.29.7))(@types/react@19.2.17)(react@19.2.7))(react@19.2.7)
'@expo/metro-runtime': 56.0.14(@expo/log-box@56.0.12)(expo@56.0.9)(react-dom@19.2.7(react@19.2.7))(react-native@0.85.3(@babel/core@7.29.7)(@react-native/jest-preset@0.85.3(@babel/core@7.29.7)(react@19.2.7))(@react-native/metro-config@0.85.3(@babel/core@7.29.7))(@types/react@19.2.17)(react@19.2.7))(react@19.2.7)
@ -12846,7 +12866,7 @@ snapshots:
shallowequal: 1.1.0
vaul: 1.1.2(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
optionalDependencies:
'@testing-library/react-native': 13.3.3(jest@29.7.0(@types/node@25.9.2))(react-native@0.85.3(@babel/core@7.29.7)(@react-native/jest-preset@0.85.3(@babel/core@7.29.7)(react@19.2.7))(@react-native/metro-config@0.85.3(@babel/core@7.29.7))(@types/react@19.2.17)(react@19.2.7))(react-test-renderer@19.2.7(react@19.2.7))(react@19.2.7)
'@testing-library/react-native': 14.0.0(jest@29.7.0(@types/node@25.9.2))(react-native@0.85.3(@babel/core@7.29.7)(@react-native/jest-preset@0.85.3(@babel/core@7.29.7)(react@19.2.7))(@react-native/metro-config@0.85.3(@babel/core@7.29.7))(@types/react@19.2.17)(react@19.2.7))(react@19.2.7)(test-renderer@1.2.0(@types/react@19.2.17)(react@19.2.7))
react-dom: 19.2.7(react@19.2.7)
react-native-gesture-handler: 2.31.2(react-native@0.85.3(@babel/core@7.29.7)(@react-native/jest-preset@0.85.3(@babel/core@7.29.7)(react@19.2.7))(@react-native/metro-config@0.85.3(@babel/core@7.29.7))(@types/react@19.2.17)(react@19.2.7))(react@19.2.7)
react-native-reanimated: 4.3.1(react-native-worklets@0.8.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.3(@babel/core@7.29.7))(react-native@0.85.3(@babel/core@7.29.7)(@react-native/jest-preset@0.85.3(@babel/core@7.29.7)(react@19.2.7))(@react-native/metro-config@0.85.3(@babel/core@7.29.7))(@types/react@19.2.17)(react@19.2.7))(react@19.2.7))(react-native@0.85.3(@babel/core@7.29.7)(@react-native/jest-preset@0.85.3(@babel/core@7.29.7)(react@19.2.7))(@react-native/metro-config@0.85.3(@babel/core@7.29.7))(@types/react@19.2.17)(react@19.2.7))(react@19.2.7)
@ -13399,7 +13419,7 @@ snapshots:
'@babel/parser': 7.29.7
'@istanbuljs/schema': 0.1.6
istanbul-lib-coverage: 3.2.2
semver: 7.8.2
semver: 7.8.4
transitivePeerDependencies:
- supports-color
@ -13510,12 +13530,12 @@ snapshots:
jest-get-type: 29.6.3
pretty-format: 29.7.0
jest-diff@30.3.0:
jest-diff@30.4.1:
dependencies:
'@jest/diff-sequences': 30.3.0
'@jest/diff-sequences': 30.4.0
'@jest/get-type': 30.1.0
chalk: 4.1.2
pretty-format: 30.3.0
pretty-format: 30.4.1
jest-docblock@29.7.0:
dependencies:
@ -13612,12 +13632,12 @@ snapshots:
jest-get-type: 29.6.3
pretty-format: 29.7.0
jest-matcher-utils@30.3.0:
jest-matcher-utils@30.4.1:
dependencies:
'@jest/get-type': 30.1.0
chalk: 4.1.2
jest-diff: 30.3.0
pretty-format: 30.3.0
jest-diff: 30.4.1
pretty-format: 30.4.1
jest-message-util@29.7.0:
dependencies:
@ -13736,7 +13756,7 @@ snapshots:
jest-util: 29.7.0
natural-compare: 1.4.0
pretty-format: 29.7.0
semver: 7.8.2
semver: 7.8.4
transitivePeerDependencies:
- supports-color
@ -14060,7 +14080,7 @@ snapshots:
make-dir@4.0.0:
dependencies:
semver: 7.8.2
semver: 7.8.4
makeerror@1.0.12:
dependencies:
@ -14360,7 +14380,7 @@ snapshots:
node-abi@3.92.0:
dependencies:
semver: 7.8.2
semver: 7.8.4
optional: true
node-addon-api@7.1.1:
@ -14391,7 +14411,7 @@ snapshots:
dependencies:
hosted-git-info: 7.0.2
proc-log: 4.2.0
semver: 7.8.2
semver: 7.8.4
validate-npm-package-name: 5.0.1
npm-run-path@4.0.1:
@ -14710,7 +14730,7 @@ snapshots:
prelude-ls@1.2.1: {}
prettier@3.8.3: {}
prettier@3.8.4: {}
pretty-format@27.5.1:
dependencies:
@ -14724,11 +14744,12 @@ snapshots:
ansi-styles: 5.2.0
react-is: 18.3.1
pretty-format@30.3.0:
pretty-format@30.4.1:
dependencies:
'@jest/schemas': 30.0.5
'@jest/schemas': 30.4.1
ansi-styles: 5.2.0
react-is: 18.3.1
react-is-18: react-is@18.3.1
react-is-19: react-is@19.2.7
proc-log@4.2.0: {}
@ -14901,7 +14922,7 @@ snapshots:
react-native: 0.85.3(@babel/core@7.29.7)(@react-native/jest-preset@0.85.3(@babel/core@7.29.7)(react@19.2.7))(@react-native/metro-config@0.85.3(@babel/core@7.29.7))(@types/react@19.2.17)(react@19.2.7)
react-native-is-edge-to-edge: 1.3.1(react-native@0.85.3(@babel/core@7.29.7)(@react-native/jest-preset@0.85.3(@babel/core@7.29.7)(react@19.2.7))(@react-native/metro-config@0.85.3(@babel/core@7.29.7))(@types/react@19.2.17)(react@19.2.7))(react@19.2.7)
react-native-worklets: 0.8.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.3(@babel/core@7.29.7))(react-native@0.85.3(@babel/core@7.29.7)(@react-native/jest-preset@0.85.3(@babel/core@7.29.7)(react@19.2.7))(@react-native/metro-config@0.85.3(@babel/core@7.29.7))(@types/react@19.2.17)(react@19.2.7))(react@19.2.7)
semver: 7.8.2
semver: 7.8.4
react-native-safe-area-context@5.7.0(react-native@0.85.3(@babel/core@7.29.7)(@react-native/jest-preset@0.85.3(@babel/core@7.29.7)(react@19.2.7))(@react-native/metro-config@0.85.3(@babel/core@7.29.7))(@types/react@19.2.17)(react@19.2.7))(react@19.2.7):
dependencies:
@ -14931,7 +14952,7 @@ snapshots:
convert-source-map: 2.0.0
react: 19.2.7
react-native: 0.85.3(@babel/core@7.29.7)(@react-native/jest-preset@0.85.3(@babel/core@7.29.7)(react@19.2.7))(@react-native/metro-config@0.85.3(@babel/core@7.29.7))(@types/react@19.2.17)(react@19.2.7)
semver: 7.8.2
semver: 7.8.4
transitivePeerDependencies:
- supports-color
@ -14964,7 +14985,7 @@ snapshots:
react-refresh: 0.14.2
regenerator-runtime: 0.13.11
scheduler: 0.27.0
semver: 7.8.2
semver: 7.8.4
stacktrace-parser: 0.1.11
tinyglobby: 0.2.17
whatwg-fetch: 3.6.20
@ -14981,6 +15002,11 @@ snapshots:
- supports-color
- utf-8-validate
react-reconciler@0.33.0(react@19.2.7):
dependencies:
react: 19.2.7
scheduler: 0.27.0
react-refresh@0.14.2: {}
react-remove-scroll-bar@2.3.8(@types/react@19.2.17)(react@19.2.7):
@ -15197,7 +15223,7 @@ snapshots:
semver@6.3.1: {}
semver@7.8.2: {}
semver@7.8.4: {}
send@0.19.2:
dependencies:
@ -15522,6 +15548,14 @@ snapshots:
glob: 7.2.3
minimatch: 3.1.5
test-renderer@1.2.0(@types/react@19.2.17)(react@19.2.7):
dependencies:
'@types/react-reconciler': 0.33.0(@types/react@19.2.17)
react: 19.2.7
react-reconciler: 0.33.0(react@19.2.7)
transitivePeerDependencies:
- '@types/react'
thread-stream@4.0.0:
dependencies:
real-require: 0.2.0
@ -15606,14 +15640,14 @@ snapshots:
safe-buffer: 5.2.1
optional: true
turbo@2.9.16:
turbo@2.9.17:
optionalDependencies:
'@turbo/darwin-64': 2.9.16
'@turbo/darwin-arm64': 2.9.16
'@turbo/linux-64': 2.9.16
'@turbo/linux-arm64': 2.9.16
'@turbo/windows-64': 2.9.16
'@turbo/windows-arm64': 2.9.16
'@turbo/darwin-64': 2.9.17
'@turbo/darwin-arm64': 2.9.17
'@turbo/linux-64': 2.9.17
'@turbo/linux-arm64': 2.9.17
'@turbo/windows-64': 2.9.17
'@turbo/windows-arm64': 2.9.17
type-check@0.4.0:
dependencies:
@ -15634,12 +15668,12 @@ snapshots:
media-typer: 0.3.0
mime-types: 2.1.35
typescript-eslint@8.60.1(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3):
typescript-eslint@8.61.0(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3):
dependencies:
'@typescript-eslint/eslint-plugin': 8.60.1(@typescript-eslint/parser@8.60.1(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3))(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3)
'@typescript-eslint/parser': 8.60.1(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3)
'@typescript-eslint/typescript-estree': 8.60.1(typescript@6.0.3)
'@typescript-eslint/utils': 8.60.1(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3)
'@typescript-eslint/eslint-plugin': 8.61.0(@typescript-eslint/parser@8.61.0(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3))(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3)
'@typescript-eslint/parser': 8.61.0(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3)
'@typescript-eslint/typescript-estree': 8.61.0(typescript@6.0.3)
'@typescript-eslint/utils': 8.61.0(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3)
eslint: 10.4.1(jiti@2.7.0)
typescript: 6.0.3
transitivePeerDependencies: