diff --git a/packages/db-expo-sqlite-persisted-collection/README.md b/packages/db-expo-sqlite-persisted-collection/README.md new file mode 100644 index 000000000..51edff9d6 --- /dev/null +++ b/packages/db-expo-sqlite-persisted-collection/README.md @@ -0,0 +1,61 @@ +# @tanstack/db-expo-sqlite-persisted-collection + +Thin SQLite persistence for Expo apps using the official `expo-sqlite` adapter. + +## Public API + +- `createExpoSQLitePersistence(...)` +- `persistedCollectionOptions(...)` (re-exported from core) + +## Quick start + +```ts +import * as SQLite from 'expo-sqlite' +import { createCollection } from '@tanstack/db' +import { + createExpoSQLitePersistence, + persistedCollectionOptions, +} from '@tanstack/db-expo-sqlite-persisted-collection' + +type Todo = { + id: string + title: string + completed: boolean +} + +const database = await SQLite.openDatabaseAsync(`tanstack-db.sqlite`) + +// One shared persistence instance for the whole database. +const persistence = createExpoSQLitePersistence({ + database, +}) + +export const todosCollection = createCollection( + persistedCollectionOptions({ + id: `todos`, + getKey: (todo) => todo.id, + persistence, + schemaVersion: 1, // Per-collection schema version + }), +) +``` + +## Notes + +- This package targets the official `expo-sqlite` async database API. +- `createExpoSQLitePersistence` is shared across collections. +- Mode defaults (`sync-present` vs `sync-absent`) are inferred from whether a + `sync` config is present in `persistedCollectionOptions`. +- The React Native `op-sqlite` wrapper remains available in + `@tanstack/db-react-native-sqlite-persisted-collection`. +- Expo web is not part of the emulator-backed E2E path in this package. Use the + browser SQLite package for browser-focused persistence coverage. + +## E2E + +- `pnpm --filter @tanstack/db-expo-sqlite-persisted-collection test:e2e` + runs the shared Node-backed conformance suite. +- `pnpm --filter @tanstack/db-expo-sqlite-persisted-collection test:e2e:expo:ios` + runs the real Expo iOS Simulator path. +- `pnpm --filter @tanstack/db-expo-sqlite-persisted-collection test:e2e:expo:android` + runs the real Expo Android Emulator path. diff --git a/packages/db-expo-sqlite-persisted-collection/e2e/expo-emulator-smoke.e2e.test.ts b/packages/db-expo-sqlite-persisted-collection/e2e/expo-emulator-smoke.e2e.test.ts new file mode 100644 index 000000000..35943d6e2 --- /dev/null +++ b/packages/db-expo-sqlite-persisted-collection/e2e/expo-emulator-smoke.e2e.test.ts @@ -0,0 +1,20 @@ +import { expect, it } from 'vitest' +import { ensureExpoEmulatorRuntime } from '../tests/helpers/expo-emulator-runtime' + +const runtimePlatform = process.env.TANSTACK_DB_EXPO_RUNTIME_PLATFORM?.trim() +const shouldRun = runtimePlatform === `ios` || runtimePlatform === `android` + +it.runIf(shouldRun)( + `runs a persistence smoke test inside a real Expo runtime`, + async () => { + const runtime = await ensureExpoEmulatorRuntime( + runtimePlatform === `android` ? `android` : `ios`, + ) + const smokeResult = await runtime.runPersistenceSmokeTest( + `expo-runtime-smoke.sqlite`, + ) + + expect(smokeResult.insertedTitle).toBe(`Persisted from Expo runtime`) + expect(smokeResult.reloadedCount).toBe(1) + }, +) diff --git a/packages/db-expo-sqlite-persisted-collection/e2e/expo-persisted-collection.e2e.test.ts b/packages/db-expo-sqlite-persisted-collection/e2e/expo-persisted-collection.e2e.test.ts new file mode 100644 index 000000000..d371c418c --- /dev/null +++ b/packages/db-expo-sqlite-persisted-collection/e2e/expo-persisted-collection.e2e.test.ts @@ -0,0 +1,14 @@ +import { it } from 'vitest' +import { createExpoSQLitePersistence } from '../src' +import { runMobilePersistedCollectionConformanceSuite } from './mobile-persisted-collection-conformance-suite' + +const runtimePlatform = process.env.TANSTACK_DB_EXPO_RUNTIME_PLATFORM?.trim() + +if (!runtimePlatform) { + runMobilePersistedCollectionConformanceSuite( + `expo persisted collection conformance`, + (database) => createExpoSQLitePersistence({ database }), + ) +} else { + it.skip(`runs the conformance suite in shimmed e2e mode only`, () => {}) +} diff --git a/packages/db-expo-sqlite-persisted-collection/e2e/expo-runtime-app/App.tsx b/packages/db-expo-sqlite-persisted-collection/e2e/expo-runtime-app/App.tsx new file mode 100644 index 000000000..a1cac71a5 --- /dev/null +++ b/packages/db-expo-sqlite-persisted-collection/e2e/expo-runtime-app/App.tsx @@ -0,0 +1,411 @@ +import React, { useEffect, useMemo, useState } from 'react' +import { ScrollView, Text, View } from 'react-native' +import * as SQLite from 'expo-sqlite' +import { createCollection } from '@tanstack/db' +import { + createExpoSQLitePersistence, + persistedCollectionOptions, +} from '@tanstack/db-expo-sqlite-persisted-collection' +import type { + ExpoRuntimeCommand, + ExpoRuntimeCommandResult, + ExpoRuntimeRegistration, + ExpoRuntimeSmokeTestResult, +} from '../runtime-protocol' + +type DatabaseHandle = Awaited> +type TransactionHandleLike = { + execAsync: (sql: string) => Promise + getAllAsync: ( + sql: string, + params?: ReadonlyArray | Record, + ) => Promise> + runAsync: ( + sql: string, + params?: ReadonlyArray | Record, + ) => Promise +} + +type ActiveTransaction = { + transaction: TransactionHandleLike + complete: { + resolve: () => void + reject: (error?: unknown) => void + promise: Promise + } + taskPromise: Promise +} + +function createDeferred() { + let resolve!: () => void + let reject!: (error?: unknown) => void + const promise = new Promise((innerResolve, innerReject) => { + resolve = innerResolve + reject = innerReject + }) + return { resolve, reject, promise } +} + +async function postJson( + url: string, + body: TBody, +): Promise { + const response = await fetch(url, { + method: `POST`, + headers: { + 'content-type': `application/json`, + }, + body: JSON.stringify(body), + }) + + if (!response.ok) { + throw new Error(`POST ${url} failed with status ${response.status}`) + } +} + +function normalizeSqliteParams( + params?: ReadonlyArray | Record, +): ReadonlyArray | Record | undefined { + return params === undefined ? undefined : params +} + +async function closeDatabaseHandle(database: DatabaseHandle): Promise { + const closableDatabase = database as DatabaseHandle & { + closeAsync?: () => Promise + } + + if (typeof closableDatabase.closeAsync === `function`) { + await closableDatabase.closeAsync() + } +} + +export default function App() { + const bridgeUrl = process.env.EXPO_PUBLIC_TSDB_BRIDGE_URL + const sessionId = process.env.EXPO_PUBLIC_TSDB_SESSION_ID + const [statusLines, setStatusLines] = useState>([ + `booting Expo SQLite runtime bridge`, + ]) + + const log = (message: string) => { + setStatusLines((currentLines) => [...currentLines, message]) + } + + const databaseHandles = useMemo(() => new Map(), []) + const activeTransactions = useMemo( + () => new Map(), + [], + ) + + useEffect(() => { + if (!bridgeUrl || !sessionId) { + log(`missing bridge env vars`) + return + } + + let disposed = false + + const getDatabase = async ( + databaseId: string, + databaseName: string, + ): Promise => { + const existingDatabase = databaseHandles.get(databaseId) + if (existingDatabase) { + return existingDatabase + } + + const database = await SQLite.openDatabaseAsync(databaseName) + databaseHandles.set(databaseId, database) + return database + } + + const reportResult = async ( + result: ExpoRuntimeCommandResult, + ): Promise => { + await postJson(`${bridgeUrl}/command-result`, result) + } + + const executeSmokeTest = async ( + databaseName: string, + ): Promise => { + const database = await SQLite.openDatabaseAsync(databaseName) + const collectionId = `expo-runtime-smoke-${Date.now().toString(36)}` + const persistence = createExpoSQLitePersistence< + { + id: string + title: string + score: number + }, + string + >({ + database, + }) + const collection = createCollection( + persistedCollectionOptions< + { + id: string + title: string + score: number + }, + string + >({ + id: collectionId, + getKey: (todo) => todo.id, + persistence, + syncMode: `eager`, + }), + ) + + try { + await collection.stateWhenReady() + const insertTx = collection.insert({ + id: `1`, + title: `Persisted from Expo runtime`, + score: 7, + }) + await insertTx.isPersisted.promise + await collection.cleanup() + collection.startSyncImmediate() + await collection.stateWhenReady() + + const reloadedRows = await persistence.adapter.loadSubset( + collectionId, + {}, + ) + return { + insertedTitle: `Persisted from Expo runtime`, + reloadedCount: reloadedRows.length, + } + } finally { + await collection.cleanup() + await closeDatabaseHandle(database) + } + } + + const handleCommand = async ( + command: ExpoRuntimeCommand, + ): Promise => { + switch (command.type) { + case `db:exec`: { + const database = await getDatabase( + command.databaseId, + command.databaseName, + ) + await database.execAsync(command.sql) + return undefined + } + case `db:getAll`: { + const database = await getDatabase( + command.databaseId, + command.databaseName, + ) + const params = normalizeSqliteParams(command.params) + return params === undefined + ? database.getAllAsync(command.sql) + : database.getAllAsync(command.sql, params) + } + case `db:run`: { + const database = await getDatabase( + command.databaseId, + command.databaseName, + ) + const params = normalizeSqliteParams(command.params) + return params === undefined + ? database.runAsync(command.sql) + : database.runAsync(command.sql, params) + } + case `db:close`: { + const database = databaseHandles.get(command.databaseId) + databaseHandles.delete(command.databaseId) + if (database) { + await closeDatabaseHandle(database) + } + return undefined + } + case `tx:start`: { + const database = await getDatabase( + command.databaseId, + command.databaseName, + ) + const complete = createDeferred() + let readyResolve!: () => void + let readyReject!: (error?: unknown) => void + const readyPromise = new Promise((resolve, reject) => { + readyResolve = resolve + readyReject = reject + }) + const activeTransaction: ActiveTransaction = { + transaction: undefined as never, + complete, + taskPromise: Promise.resolve(), + } + activeTransaction.taskPromise = database + .withExclusiveTransactionAsync(async (transaction) => { + activeTransaction.transaction = transaction + activeTransactions.set(command.transactionId, activeTransaction) + readyResolve() + try { + await complete.promise + } finally { + activeTransactions.delete(command.transactionId) + } + }) + .catch((error) => { + readyReject(error) + throw error + }) + + await readyPromise + return undefined + } + case `tx:exec`: { + const transaction = activeTransactions.get(command.transactionId) + if (!transaction) { + throw new Error(`Unknown transaction id`) + } + await transaction.transaction.execAsync(command.sql) + return undefined + } + case `tx:getAll`: { + const transaction = activeTransactions.get(command.transactionId) + if (!transaction) { + throw new Error(`Unknown transaction id`) + } + const params = normalizeSqliteParams(command.params) + return params === undefined + ? transaction.transaction.getAllAsync(command.sql) + : transaction.transaction.getAllAsync(command.sql, params) + } + case `tx:run`: { + const transaction = activeTransactions.get(command.transactionId) + if (!transaction) { + throw new Error(`Unknown transaction id`) + } + const params = normalizeSqliteParams(command.params) + return params === undefined + ? transaction.transaction.runAsync(command.sql) + : transaction.transaction.runAsync(command.sql, params) + } + case `tx:commit`: { + const transaction = activeTransactions.get(command.transactionId) + if (!transaction) { + throw new Error(`Unknown transaction id`) + } + transaction.complete.resolve() + await transaction.taskPromise + return undefined + } + case `tx:rollback`: { + const transaction = activeTransactions.get(command.transactionId) + if (!transaction) { + throw new Error(`Unknown transaction id`) + } + transaction.complete.reject(new Error(`Host requested rollback`)) + await transaction.taskPromise.catch(() => undefined) + return undefined + } + case `app:runPersistenceSmokeTest`: + return executeSmokeTest(command.databaseName) + default: + throw new Error(`Unsupported command type`) + } + } + + const register = async (): Promise => { + const registration: ExpoRuntimeRegistration = { + sessionId, + platform: process.env.EXPO_PUBLIC_TSDB_RUNTIME_PLATFORM ?? `unknown`, + } + await postJson(`${bridgeUrl}/register`, registration) + log(`registered with host bridge`) + } + + const pollCommands = async (): Promise => { + while (!disposed) { + const response = await fetch(`${bridgeUrl}/next-command`) + if (response.status === 204) { + await new Promise((resolve) => setTimeout(resolve, 200)) + continue + } + + if (!response.ok) { + throw new Error( + `Host bridge command poll failed with status ${response.status}`, + ) + } + + const command = (await response.json()) as ExpoRuntimeCommand + try { + const result = await handleCommand(command) + await reportResult({ + commandId: command.id, + ok: true, + result, + }) + } catch (error) { + await reportResult({ + commandId: command.id, + ok: false, + error: error instanceof Error ? error.message : String(error), + }) + } + } + } + + void (async () => { + try { + await register() + await pollCommands() + } catch (error) { + log( + `runtime bridge failed: ${ + error instanceof Error ? error.message : String(error) + }`, + ) + } + })() + + return () => { + disposed = true + } + }, [activeTransactions, bridgeUrl, databaseHandles, sessionId]) + + return ( + + + Expo SQLite Runtime Bridge + + + {statusLines.map((line, index) => ( + + {line} + + ))} + + + ) +} diff --git a/packages/db-expo-sqlite-persisted-collection/e2e/expo-runtime-app/app.json b/packages/db-expo-sqlite-persisted-collection/e2e/expo-runtime-app/app.json new file mode 100644 index 000000000..c16905647 --- /dev/null +++ b/packages/db-expo-sqlite-persisted-collection/e2e/expo-runtime-app/app.json @@ -0,0 +1,8 @@ +{ + "expo": { + "name": "TanStack DB Expo SQLite E2E", + "slug": "tanstack-db-expo-sqlite-e2e", + "scheme": "tanstack-db-expo-sqlite-e2e", + "platforms": ["ios", "android"] + } +} diff --git a/packages/db-expo-sqlite-persisted-collection/e2e/expo-runtime-app/index.js b/packages/db-expo-sqlite-persisted-collection/e2e/expo-runtime-app/index.js new file mode 100644 index 000000000..8d831528b --- /dev/null +++ b/packages/db-expo-sqlite-persisted-collection/e2e/expo-runtime-app/index.js @@ -0,0 +1,6 @@ +import './polyfills' +import { registerRootComponent } from 'expo' + +import App from './App' + +registerRootComponent(App) diff --git a/packages/db-expo-sqlite-persisted-collection/e2e/expo-runtime-app/metro.config.js b/packages/db-expo-sqlite-persisted-collection/e2e/expo-runtime-app/metro.config.js new file mode 100644 index 000000000..9d65d9939 --- /dev/null +++ b/packages/db-expo-sqlite-persisted-collection/e2e/expo-runtime-app/metro.config.js @@ -0,0 +1,15 @@ +const path = require('node:path') +const { getDefaultConfig } = require('expo/metro-config') + +const projectRoot = __dirname +const workspaceRoot = path.resolve(projectRoot, '../../../../') + +const config = getDefaultConfig(projectRoot) + +config.watchFolders = [workspaceRoot] +config.resolver.nodeModulesPaths = [ + path.resolve(projectRoot, 'node_modules'), + path.resolve(workspaceRoot, 'node_modules'), +] + +module.exports = config diff --git a/packages/db-expo-sqlite-persisted-collection/e2e/expo-runtime-app/package.json b/packages/db-expo-sqlite-persisted-collection/e2e/expo-runtime-app/package.json new file mode 100644 index 000000000..89d937dbb --- /dev/null +++ b/packages/db-expo-sqlite-persisted-collection/e2e/expo-runtime-app/package.json @@ -0,0 +1,19 @@ +{ + "name": "@tanstack/db-expo-sqlite-persisted-collection-e2e-app", + "private": true, + "version": "0.0.0", + "main": "index.js", + "scripts": { + "start": "expo start", + "ios": "expo start --ios", + "android": "expo start --android" + }, + "dependencies": { + "@tanstack/db": "workspace:*", + "@tanstack/db-expo-sqlite-persisted-collection": "workspace:*", + "expo": "~55.0.6", + "expo-sqlite": "^55.0.10", + "react": "19.2.0", + "react-native": "0.83.2" + } +} diff --git a/packages/db-expo-sqlite-persisted-collection/e2e/expo-runtime-app/polyfills.js b/packages/db-expo-sqlite-persisted-collection/e2e/expo-runtime-app/polyfills.js new file mode 100644 index 000000000..4b5fb03bf --- /dev/null +++ b/packages/db-expo-sqlite-persisted-collection/e2e/expo-runtime-app/polyfills.js @@ -0,0 +1,21 @@ +function createPseudoRandomUuid() { + return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (char) => { + const randomNibble = Math.floor(Math.random() * 16) + const value = char === 'x' ? randomNibble : (randomNibble & 0x3) | 0x8 + return value.toString(16) + }) +} + +if (typeof globalThis.crypto === 'undefined') { + Object.defineProperty(globalThis, 'crypto', { + configurable: true, + value: { + randomUUID: createPseudoRandomUuid, + }, + }) +} else if (typeof globalThis.crypto.randomUUID !== 'function') { + Object.defineProperty(globalThis.crypto, 'randomUUID', { + configurable: true, + value: createPseudoRandomUuid, + }) +} diff --git a/packages/db-expo-sqlite-persisted-collection/e2e/expo-runtime-app/tsconfig.json b/packages/db-expo-sqlite-persisted-collection/e2e/expo-runtime-app/tsconfig.json new file mode 100644 index 000000000..00e4c9422 --- /dev/null +++ b/packages/db-expo-sqlite-persisted-collection/e2e/expo-runtime-app/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../../../../tsconfig.json", + "compilerOptions": { + "jsx": "react-jsx", + "moduleResolution": "Bundler", + "allowJs": true, + "types": ["react", "react-native"] + }, + "include": ["./**/*"] +} diff --git a/packages/db-expo-sqlite-persisted-collection/e2e/mobile-persisted-collection-conformance-suite.ts b/packages/db-expo-sqlite-persisted-collection/e2e/mobile-persisted-collection-conformance-suite.ts new file mode 100644 index 000000000..ca2cf3f72 --- /dev/null +++ b/packages/db-expo-sqlite-persisted-collection/e2e/mobile-persisted-collection-conformance-suite.ts @@ -0,0 +1,284 @@ +import { mkdtempSync, rmSync } from 'node:fs' +import { tmpdir } from 'node:os' +import { join } from 'node:path' +import { afterAll, afterEach, beforeAll } from 'vitest' +import { createCollection } from '@tanstack/db' +import { persistedCollectionOptions } from '../src' +import { generateSeedData } from '../../db-collection-e2e/src/fixtures/seed-data' +import { runPersistedCollectionConformanceSuite } from '../../db-sqlite-persisted-collection-core/tests/contracts/persisted-collection-conformance-contract' +import { createExpoSQLiteTestDatabase } from '../tests/helpers/expo-sqlite-test-db' +import type { Collection } from '@tanstack/db' +import type { PersistedCollectionPersistence } from '@tanstack/db-sqlite-persisted-collection-core' +import type { + Comment, + E2ETestConfig, + Post, + User, +} from '../../db-collection-e2e/src/types' + +type PersistableRow = { + id: string +} + +type MobilePersistedCollectionTestConfig = E2ETestConfig +type PersistedCollectionHarness = { + collection: Collection + seedPersisted: (rows: Array) => Promise +} + +type MobilePersistenceFactory = ( + database: ReturnType, +) => PersistedCollectionPersistence + +function createPersistedCollection( + database: ReturnType, + id: string, + syncMode: `eager` | `on-demand`, + createPersistence: MobilePersistenceFactory, +): PersistedCollectionHarness { + const persistence = createPersistence(database) + let seedTxSequence = 0 + const seedPersisted = async (rows: Array): Promise => { + if (rows.length === 0) { + return + } + seedTxSequence++ + await persistence.adapter.applyCommittedTx(id, { + txId: `seed-${id}-${seedTxSequence}`, + term: 1, + seq: seedTxSequence, + rowVersion: seedTxSequence, + mutations: rows.map((row) => ({ + type: `insert` as const, + key: row.id, + value: row, + })), + }) + } + + const collection = createCollection( + persistedCollectionOptions({ + id, + syncMode, + getKey: (item) => item.id, + persistence, + }), + ) + + return { + collection, + seedPersisted, + } +} + +type PersistedTransactionHandle = { + isPersisted: { + promise: Promise + } +} + +async function waitForPersisted( + transaction: PersistedTransactionHandle, +): Promise { + await transaction.isPersisted.promise +} + +async function seedCollection( + collection: Collection, + rows: Array, +): Promise { + const tx = collection.insert(rows) + await waitForPersisted(tx) +} + +async function insertRowIntoCollections( + collections: ReadonlyArray>, + row: T, +): Promise { + for (const collection of collections) { + const tx = collection.insert(row) + await waitForPersisted(tx) + } +} + +async function updateRowAcrossCollections( + collections: ReadonlyArray>, + id: string, + updates: Partial, +): Promise { + for (const collection of collections) { + if (!collection.has(id)) { + continue + } + const tx = collection.update(id, (draft) => { + Object.assign(draft, updates) + }) + await waitForPersisted(tx) + } +} + +async function deleteRowAcrossCollections( + collections: ReadonlyArray>, + id: string, +): Promise { + for (const collection of collections) { + if (!collection.has(id)) { + continue + } + const tx = collection.delete(id) + await waitForPersisted(tx) + } +} + +export function runMobilePersistedCollectionConformanceSuite( + suiteName: string, + createPersistence: MobilePersistenceFactory, +): void { + let config: MobilePersistedCollectionTestConfig | undefined + + beforeAll(async () => { + const tempDirectory = mkdtempSync( + join(tmpdir(), `db-expo-persisted-conformance-`), + ) + const dbPath = join(tempDirectory, `state.sqlite`) + const suiteId = Date.now().toString(36) + const database = createExpoSQLiteTestDatabase({ + filename: dbPath, + }) + const seedData = generateSeedData() + + const eagerUsers = createPersistedCollection( + database, + `expo-persisted-users-eager-${suiteId}`, + `eager`, + createPersistence, + ) + const eagerPosts = createPersistedCollection( + database, + `expo-persisted-posts-eager-${suiteId}`, + `eager`, + createPersistence, + ) + const eagerComments = createPersistedCollection( + database, + `expo-persisted-comments-eager-${suiteId}`, + `eager`, + createPersistence, + ) + + const onDemandUsers = createPersistedCollection( + database, + `expo-persisted-users-ondemand-${suiteId}`, + `on-demand`, + createPersistence, + ) + const onDemandPosts = createPersistedCollection( + database, + `expo-persisted-posts-ondemand-${suiteId}`, + `on-demand`, + createPersistence, + ) + const onDemandComments = createPersistedCollection( + database, + `expo-persisted-comments-ondemand-${suiteId}`, + `on-demand`, + createPersistence, + ) + + await Promise.all([ + eagerUsers.collection.preload(), + eagerPosts.collection.preload(), + eagerComments.collection.preload(), + ]) + + await seedCollection(eagerUsers.collection, seedData.users) + await seedCollection(eagerPosts.collection, seedData.posts) + await seedCollection(eagerComments.collection, seedData.comments) + await onDemandUsers.seedPersisted(seedData.users) + await onDemandPosts.seedPersisted(seedData.posts) + await onDemandComments.seedPersisted(seedData.comments) + + config = { + collections: { + eager: { + users: eagerUsers.collection, + posts: eagerPosts.collection, + comments: eagerComments.collection, + }, + onDemand: { + users: onDemandUsers.collection, + posts: onDemandPosts.collection, + comments: onDemandComments.collection, + }, + }, + mutations: { + insertUser: async (user) => + insertRowIntoCollections( + [eagerUsers.collection, onDemandUsers.collection], + user, + ), + updateUser: async (id, updates) => + updateRowAcrossCollections( + [eagerUsers.collection, onDemandUsers.collection], + id, + updates, + ), + deleteUser: async (id) => + deleteRowAcrossCollections( + [eagerUsers.collection, onDemandUsers.collection], + id, + ), + insertPost: async (post) => + insertRowIntoCollections( + [eagerPosts.collection, onDemandPosts.collection], + post, + ), + }, + setup: async () => {}, + afterEach: async () => { + await Promise.all([ + onDemandUsers.collection.cleanup(), + onDemandPosts.collection.cleanup(), + onDemandComments.collection.cleanup(), + ]) + + onDemandUsers.collection.startSyncImmediate() + onDemandPosts.collection.startSyncImmediate() + onDemandComments.collection.startSyncImmediate() + }, + teardown: async () => { + await Promise.all([ + eagerUsers.collection.cleanup(), + eagerPosts.collection.cleanup(), + eagerComments.collection.cleanup(), + onDemandUsers.collection.cleanup(), + onDemandPosts.collection.cleanup(), + onDemandComments.collection.cleanup(), + ]) + await database.closeAsync() + rmSync(tempDirectory, { recursive: true, force: true }) + }, + } + }) + + afterEach(async () => { + if (config?.afterEach) { + await config.afterEach() + } + }) + + afterAll(async () => { + if (config) { + await config.teardown() + } + }) + + function getConfig(): Promise { + if (!config) { + throw new Error(`${suiteName} config is not initialized`) + } + return Promise.resolve(config) + } + + runPersistedCollectionConformanceSuite(suiteName, getConfig) +} diff --git a/packages/db-expo-sqlite-persisted-collection/e2e/runtime-protocol.ts b/packages/db-expo-sqlite-persisted-collection/e2e/runtime-protocol.ts new file mode 100644 index 000000000..21f672e5c --- /dev/null +++ b/packages/db-expo-sqlite-persisted-collection/e2e/runtime-protocol.ts @@ -0,0 +1,94 @@ +export type ExpoRuntimeCommand = + | { + id: string + type: `db:exec` + databaseId: string + databaseName: string + sql: string + } + | { + id: string + type: `db:getAll` + databaseId: string + databaseName: string + sql: string + params?: ReadonlyArray | Record + } + | { + id: string + type: `db:run` + databaseId: string + databaseName: string + sql: string + params?: ReadonlyArray | Record + } + | { + id: string + type: `db:close` + databaseId: string + databaseName: string + } + | { + id: string + type: `tx:start` + databaseId: string + databaseName: string + transactionId: string + } + | { + id: string + type: `tx:exec` + transactionId: string + sql: string + } + | { + id: string + type: `tx:getAll` + transactionId: string + sql: string + params?: ReadonlyArray | Record + } + | { + id: string + type: `tx:run` + transactionId: string + sql: string + params?: ReadonlyArray | Record + } + | { + id: string + type: `tx:commit` + transactionId: string + } + | { + id: string + type: `tx:rollback` + transactionId: string + } + | { + id: string + type: `app:runPersistenceSmokeTest` + databaseName: string + } + +export type ExpoRuntimeCommandResult = + | { + commandId: string + ok: true + result?: unknown + } + | { + commandId: string + ok: false + error: string + } + +export type ExpoRuntimeRegistration = { + sessionId: string + platform: string +} + +export type ExpoRuntimeSmokeTestResult = { + insertedTitle: string + reloadedCount: number +} diff --git a/packages/db-expo-sqlite-persisted-collection/package.json b/packages/db-expo-sqlite-persisted-collection/package.json new file mode 100644 index 000000000..8f9260190 --- /dev/null +++ b/packages/db-expo-sqlite-persisted-collection/package.json @@ -0,0 +1,65 @@ +{ + "name": "@tanstack/db-expo-sqlite-persisted-collection", + "version": "0.1.0", + "description": "Expo SQLite persisted collection adapter for TanStack DB", + "author": "TanStack Team", + "license": "MIT", + "repository": { + "type": "git", + "url": "git+https://github.com/TanStack/db.git", + "directory": "packages/db-expo-sqlite-persisted-collection" + }, + "homepage": "https://tanstack.com/db", + "keywords": [ + "sqlite", + "expo", + "expo-sqlite", + "persistence", + "typescript" + ], + "scripts": { + "build": "vite build", + "dev": "vite build --watch", + "lint": "eslint . --fix", + "test": "vitest --run", + "test:e2e": "pnpm --filter @tanstack/db-ivm build && pnpm --filter @tanstack/db build && pnpm --filter @tanstack/db-sqlite-persisted-collection-core build && pnpm --filter @tanstack/db-expo-sqlite-persisted-collection build && vitest --config vitest.e2e.config.ts --run", + "test:e2e:runtime": "pnpm --filter @tanstack/db-ivm build && pnpm --filter @tanstack/db build && pnpm --filter @tanstack/db-sqlite-persisted-collection-core build && pnpm --filter @tanstack/db-expo-sqlite-persisted-collection build && TANSTACK_DB_MOBILE_REQUIRE_RUNTIME_FACTORY=1 vitest --config vitest.e2e.config.ts --run", + "test:e2e:expo:ios": "pnpm --filter @tanstack/db-ivm build && pnpm --filter @tanstack/db build && pnpm --filter @tanstack/db-sqlite-persisted-collection-core build && pnpm --filter @tanstack/db-expo-sqlite-persisted-collection build && TANSTACK_DB_MOBILE_REQUIRE_RUNTIME_FACTORY=1 TANSTACK_DB_MOBILE_SQLITE_FACTORY_MODULE=./tests/helpers/expo-emulator-database-factory.ts TANSTACK_DB_EXPO_RUNTIME_PLATFORM=ios vitest --config vitest.e2e.config.ts --run", + "test:e2e:expo:android": "pnpm --filter @tanstack/db-ivm build && pnpm --filter @tanstack/db build && pnpm --filter @tanstack/db-sqlite-persisted-collection-core build && pnpm --filter @tanstack/db-expo-sqlite-persisted-collection build && TANSTACK_DB_MOBILE_REQUIRE_RUNTIME_FACTORY=1 TANSTACK_DB_MOBILE_SQLITE_FACTORY_MODULE=./tests/helpers/expo-emulator-database-factory.ts TANSTACK_DB_EXPO_RUNTIME_PLATFORM=android vitest --config vitest.e2e.config.ts --run" + }, + "type": "module", + "main": "dist/cjs/index.cjs", + "module": "dist/esm/index.js", + "types": "dist/esm/index.d.ts", + "exports": { + ".": { + "import": { + "types": "./dist/esm/index.d.ts", + "default": "./dist/esm/index.js" + }, + "require": { + "types": "./dist/cjs/index.d.cts", + "default": "./dist/cjs/index.cjs" + } + }, + "./package.json": "./package.json" + }, + "sideEffects": false, + "files": [ + "dist", + "src", + "e2e" + ], + "dependencies": { + "@tanstack/db-sqlite-persisted-collection-core": "workspace:*" + }, + "peerDependencies": { + "expo-sqlite": "^55.0.10", + "typescript": ">=4.7" + }, + "devDependencies": { + "@types/better-sqlite3": "^7.6.13", + "@vitest/coverage-istanbul": "^3.2.4", + "better-sqlite3": "^12.6.2" + } +} diff --git a/packages/db-expo-sqlite-persisted-collection/src/expo-sqlite-driver.ts b/packages/db-expo-sqlite-persisted-collection/src/expo-sqlite-driver.ts new file mode 100644 index 000000000..ea84d6a28 --- /dev/null +++ b/packages/db-expo-sqlite-persisted-collection/src/expo-sqlite-driver.ts @@ -0,0 +1,238 @@ +import { InvalidPersistedCollectionConfigError } from '@tanstack/db-sqlite-persisted-collection-core' +import type { SQLiteDriver } from '@tanstack/db-sqlite-persisted-collection-core' + +export type ExpoSQLiteBindParams = + | ReadonlyArray + | Record + +export type ExpoSQLiteRunResult = { + changes: number + lastInsertRowId: number +} + +export type ExpoSQLiteQueryable = { + execAsync: (sql: string) => Promise + getAllAsync: ( + sql: string, + params?: ExpoSQLiteBindParams, + ) => Promise> + runAsync: ( + sql: string, + params?: ExpoSQLiteBindParams, + ) => Promise +} + +export type ExpoSQLiteTransaction = ExpoSQLiteQueryable + +export type ExpoSQLiteDatabaseLike = ExpoSQLiteQueryable & { + withExclusiveTransactionAsync: ( + task: (transaction: ExpoSQLiteTransaction) => Promise, + ) => Promise + closeAsync?: () => Promise +} + +type ExpoSQLiteExistingDatabaseOptions = { + database: ExpoSQLiteDatabaseLike +} + +type ExpoSQLiteOpenDatabaseOptions = { + openDatabase: () => Promise | ExpoSQLiteDatabaseLike +} + +export type ExpoSQLiteDriverOptions = + | ExpoSQLiteExistingDatabaseOptions + | ExpoSQLiteOpenDatabaseOptions + +function hasExistingDatabase( + options: ExpoSQLiteDriverOptions, +): options is ExpoSQLiteExistingDatabaseOptions { + return `database` in options +} + +function assertTransactionCallbackHasDriverArg( + fn: (transactionDriver: SQLiteDriver) => Promise, +): void { + if (fn.length > 0) { + return + } + + throw new InvalidPersistedCollectionConfigError( + `SQLiteDriver.transaction callback must accept the transaction driver argument`, + ) +} + +function isExpoSQLiteDatabaseLike( + value: unknown, +): value is ExpoSQLiteDatabaseLike { + return ( + typeof value === `object` && + value !== null && + typeof (value as ExpoSQLiteDatabaseLike).execAsync === `function` && + typeof (value as ExpoSQLiteDatabaseLike).getAllAsync === `function` && + typeof (value as ExpoSQLiteDatabaseLike).runAsync === `function` && + typeof (value as ExpoSQLiteDatabaseLike).withExclusiveTransactionAsync === + `function` + ) +} + +export class ExpoSQLiteDriver implements SQLiteDriver { + private readonly databasePromise: Promise + private readonly ownsDatabase: boolean + private queue: Promise = Promise.resolve() + private nextSavepointId = 1 + + constructor(options: ExpoSQLiteDriverOptions) { + if (hasExistingDatabase(options)) { + if (!isExpoSQLiteDatabaseLike(options.database)) { + throw new InvalidPersistedCollectionConfigError( + `Expo SQLite database must provide execAsync/getAllAsync/runAsync/withExclusiveTransactionAsync`, + ) + } + + this.databasePromise = Promise.resolve(options.database) + this.ownsDatabase = false + return + } + + this.databasePromise = Promise.resolve(options.openDatabase()).then( + (database) => { + if (!isExpoSQLiteDatabaseLike(database)) { + throw new InvalidPersistedCollectionConfigError( + `Expo SQLite openDatabase() must resolve a database with execAsync/getAllAsync/runAsync/withExclusiveTransactionAsync`, + ) + } + + return database + }, + ) + this.ownsDatabase = true + } + + async exec(sql: string): Promise { + await this.enqueue(async () => { + const database = await this.getDatabase() + await database.execAsync(sql) + }) + } + + async query( + sql: string, + params: ReadonlyArray = [], + ): Promise> { + return this.enqueue(async () => { + const database = await this.getDatabase() + return database.getAllAsync(sql, normalizeParams(params)) + }) + } + + async run(sql: string, params: ReadonlyArray = []): Promise { + await this.enqueue(async () => { + const database = await this.getDatabase() + await database.runAsync(sql, normalizeParams(params)) + }) + } + + async transaction( + fn: (transactionDriver: SQLiteDriver) => Promise, + ): Promise { + assertTransactionCallbackHasDriverArg(fn) + return this.transactionWithDriver(fn) + } + + async transactionWithDriver( + fn: (transactionDriver: SQLiteDriver) => Promise, + ): Promise { + return this.enqueue(async () => { + const database = await this.getDatabase() + return database.withExclusiveTransactionAsync(async (transaction) => { + const transactionDriver = this.createTransactionDriver(transaction) + return fn(transactionDriver) + }) + }) + } + + async close(): Promise { + const database = await this.getDatabase() + if (!this.ownsDatabase || typeof database.closeAsync !== `function`) { + return + } + + await database.closeAsync() + } + + async getDatabase(): Promise { + return this.databasePromise + } + + private enqueue(operation: () => Promise): Promise { + const queuedOperation = this.queue.then(operation, operation) + this.queue = queuedOperation.then( + () => undefined, + () => undefined, + ) + return queuedOperation + } + + private createTransactionDriver( + transaction: ExpoSQLiteTransaction, + ): SQLiteDriver { + const transactionDriver: SQLiteDriver = { + exec: async (sql) => { + await transaction.execAsync(sql) + }, + query: async ( + sql: string, + params: ReadonlyArray = [], + ): Promise> => { + return transaction.getAllAsync(sql, normalizeParams(params)) + }, + run: async (sql: string, params: ReadonlyArray = []) => { + await transaction.runAsync(sql, normalizeParams(params)) + }, + transaction: async ( + fn: (nestedTransactionDriver: SQLiteDriver) => Promise, + ): Promise => { + assertTransactionCallbackHasDriverArg(fn) + return this.runNestedTransaction(transaction, transactionDriver, fn) + }, + transactionWithDriver: async ( + fn: (nestedTransactionDriver: SQLiteDriver) => Promise, + ): Promise => + this.runNestedTransaction(transaction, transactionDriver, fn), + } + + return transactionDriver + } + + private async runNestedTransaction( + transaction: ExpoSQLiteTransaction, + transactionDriver: SQLiteDriver, + fn: (transactionDriver: SQLiteDriver) => Promise, + ): Promise { + const savepointName = `tsdb_sp_${this.nextSavepointId}` + this.nextSavepointId++ + await transaction.execAsync(`SAVEPOINT ${savepointName}`) + + try { + const result = await fn(transactionDriver) + await transaction.execAsync(`RELEASE SAVEPOINT ${savepointName}`) + return result + } catch (error) { + await transaction.execAsync(`ROLLBACK TO SAVEPOINT ${savepointName}`) + await transaction.execAsync(`RELEASE SAVEPOINT ${savepointName}`) + throw error + } + } +} + +function normalizeParams( + params: ReadonlyArray, +): ExpoSQLiteBindParams | undefined { + return params.length > 0 ? [...params] : undefined +} + +export function createExpoSQLiteDriver( + options: ExpoSQLiteDriverOptions, +): ExpoSQLiteDriver { + return new ExpoSQLiteDriver(options) +} diff --git a/packages/db-expo-sqlite-persisted-collection/src/expo.ts b/packages/db-expo-sqlite-persisted-collection/src/expo.ts new file mode 100644 index 000000000..daf4bce39 --- /dev/null +++ b/packages/db-expo-sqlite-persisted-collection/src/expo.ts @@ -0,0 +1,159 @@ +import { + SingleProcessCoordinator, + createSQLiteCorePersistenceAdapter, +} from '@tanstack/db-sqlite-persisted-collection-core' +import { ExpoSQLiteDriver } from './expo-sqlite-driver' +import type { + PersistedCollectionCoordinator, + PersistedCollectionMode, + PersistedCollectionPersistence, + SQLiteCoreAdapterOptions, + SQLiteDriver, +} from '@tanstack/db-sqlite-persisted-collection-core' +import type { ExpoSQLiteDatabaseLike } from './expo-sqlite-driver' + +export type { ExpoSQLiteDatabaseLike } from './expo-sqlite-driver' + +type ExpoSQLiteCoreSchemaMismatchPolicy = + | `sync-present-reset` + | `sync-absent-error` + | `reset` + +export type ExpoSQLiteSchemaMismatchPolicy = + | ExpoSQLiteCoreSchemaMismatchPolicy + | `throw` + +export type ExpoSQLitePersistenceOptions = Omit< + SQLiteCoreAdapterOptions, + `driver` | `schemaVersion` | `schemaMismatchPolicy` +> & { + database: ExpoSQLiteDatabaseLike + coordinator?: PersistedCollectionCoordinator + schemaMismatchPolicy?: ExpoSQLiteSchemaMismatchPolicy +} + +function normalizeSchemaMismatchPolicy( + policy: ExpoSQLiteSchemaMismatchPolicy, +): ExpoSQLiteCoreSchemaMismatchPolicy { + if (policy === `throw`) { + return `sync-absent-error` + } + + return policy +} + +function resolveSchemaMismatchPolicy( + explicitPolicy: ExpoSQLiteSchemaMismatchPolicy | undefined, + mode: PersistedCollectionMode, +): ExpoSQLiteCoreSchemaMismatchPolicy { + if (explicitPolicy) { + return normalizeSchemaMismatchPolicy(explicitPolicy) + } + + return mode === `sync-present` ? `sync-present-reset` : `sync-absent-error` +} + +function createAdapterCacheKey( + schemaMismatchPolicy: ExpoSQLiteCoreSchemaMismatchPolicy, + schemaVersion: number | undefined, +): string { + const schemaVersionKey = + schemaVersion === undefined ? `schema:default` : `schema:${schemaVersion}` + return `${schemaMismatchPolicy}|${schemaVersionKey}` +} + +function createInternalSQLiteDriver( + options: ExpoSQLitePersistenceOptions, +): SQLiteDriver { + return new ExpoSQLiteDriver({ + database: options.database, + }) +} + +function resolveAdapterBaseOptions( + options: ExpoSQLitePersistenceOptions, +): Omit< + SQLiteCoreAdapterOptions, + `driver` | `schemaVersion` | `schemaMismatchPolicy` +> { + return { + appliedTxPruneMaxRows: options.appliedTxPruneMaxRows, + appliedTxPruneMaxAgeSeconds: options.appliedTxPruneMaxAgeSeconds, + pullSinceReloadThreshold: options.pullSinceReloadThreshold, + } +} + +export function createExpoSQLitePersistence< + T extends object, + TKey extends string | number = string | number, +>( + options: ExpoSQLitePersistenceOptions, +): PersistedCollectionPersistence { + const { coordinator, schemaMismatchPolicy } = options + const driver = createInternalSQLiteDriver(options) + const adapterBaseOptions = resolveAdapterBaseOptions(options) + const resolvedCoordinator = coordinator ?? new SingleProcessCoordinator() + const adapterCache = new Map< + string, + ReturnType< + typeof createSQLiteCorePersistenceAdapter< + Record, + string | number + > + > + >() + + const getAdapterForCollection = ( + mode: PersistedCollectionMode, + schemaVersion: number | undefined, + ) => { + const resolvedSchemaMismatchPolicy = resolveSchemaMismatchPolicy( + schemaMismatchPolicy, + mode, + ) + const cacheKey = createAdapterCacheKey( + resolvedSchemaMismatchPolicy, + schemaVersion, + ) + const cachedAdapter = adapterCache.get(cacheKey) + if (cachedAdapter) { + return cachedAdapter + } + + const adapter = createSQLiteCorePersistenceAdapter< + Record, + string | number + >({ + ...adapterBaseOptions, + driver, + schemaMismatchPolicy: resolvedSchemaMismatchPolicy, + ...(schemaVersion === undefined ? {} : { schemaVersion }), + }) + adapterCache.set(cacheKey, adapter) + return adapter + } + + const createCollectionPersistence = ( + mode: PersistedCollectionMode, + schemaVersion: number | undefined, + ): PersistedCollectionPersistence => ({ + adapter: getAdapterForCollection( + mode, + schemaVersion, + ) as unknown as PersistedCollectionPersistence[`adapter`], + coordinator: resolvedCoordinator, + }) + + const defaultPersistence = createCollectionPersistence( + `sync-absent`, + undefined, + ) + + return { + ...defaultPersistence, + resolvePersistenceForCollection: ({ mode, schemaVersion }) => + createCollectionPersistence(mode, schemaVersion), + resolvePersistenceForMode: (mode) => + createCollectionPersistence(mode, undefined), + } +} diff --git a/packages/db-expo-sqlite-persisted-collection/src/index.ts b/packages/db-expo-sqlite-persisted-collection/src/index.ts new file mode 100644 index 000000000..e30d9ed05 --- /dev/null +++ b/packages/db-expo-sqlite-persisted-collection/src/index.ts @@ -0,0 +1,17 @@ +export { createExpoSQLitePersistence } from './expo' +export type { + ExpoSQLiteDatabaseLike, + ExpoSQLitePersistenceOptions, + ExpoSQLiteSchemaMismatchPolicy, +} from './expo' +export { ExpoSQLiteDriver, createExpoSQLiteDriver } from './expo-sqlite-driver' +export type { + ExpoSQLiteBindParams, + ExpoSQLiteRunResult, + ExpoSQLiteTransaction, +} from './expo-sqlite-driver' +export { persistedCollectionOptions } from '@tanstack/db-sqlite-persisted-collection-core' +export type { + PersistedCollectionCoordinator, + PersistedCollectionPersistence, +} from '@tanstack/db-sqlite-persisted-collection-core' diff --git a/packages/db-expo-sqlite-persisted-collection/tests/expo-persistence.test.ts b/packages/db-expo-sqlite-persisted-collection/tests/expo-persistence.test.ts new file mode 100644 index 000000000..b22938157 --- /dev/null +++ b/packages/db-expo-sqlite-persisted-collection/tests/expo-persistence.test.ts @@ -0,0 +1,171 @@ +import { mkdtempSync, rmSync } from 'node:fs' +import { tmpdir } from 'node:os' +import { join } from 'node:path' +import { afterEach, expect, it } from 'vitest' +import { createCollection } from '@tanstack/db' +import { createExpoSQLitePersistence, persistedCollectionOptions } from '../src' +import { createExpoSQLiteTestDatabase } from './helpers/expo-sqlite-test-db' + +type Todo = { + id: string + title: string + score: number +} + +const activeCleanupFns: Array<() => void | Promise> = [] + +afterEach(async () => { + while (activeCleanupFns.length > 0) { + const cleanupFn = activeCleanupFns.pop() + await Promise.resolve(cleanupFn?.()) + } +}) + +function createTempSqlitePath(): string { + const tempDirectory = mkdtempSync(join(tmpdir(), `db-expo-persistence-test-`)) + const dbPath = join(tempDirectory, `state.sqlite`) + activeCleanupFns.push(() => { + rmSync(tempDirectory, { recursive: true, force: true }) + }) + return dbPath +} + +it(`persists data across app restart (close and reopen)`, async () => { + const dbPath = createTempSqlitePath() + const collectionId = `todos-restart` + + const firstDatabase = createExpoSQLiteTestDatabase({ filename: dbPath }) + const firstPersistence = createExpoSQLitePersistence({ + database: firstDatabase, + }) + const firstAdapter = firstPersistence.adapter + + await firstAdapter.applyCommittedTx(collectionId, { + txId: `tx-restart-1`, + term: 1, + seq: 1, + rowVersion: 1, + mutations: [ + { + type: `insert`, + key: `1`, + value: { + id: `1`, + title: `Survives restart`, + score: 10, + }, + }, + ], + }) + await firstDatabase.closeAsync() + + const secondDatabase = createExpoSQLiteTestDatabase({ filename: dbPath }) + activeCleanupFns.push(() => secondDatabase.closeAsync()) + const secondPersistence = createExpoSQLitePersistence({ + database: secondDatabase, + }) + const secondAdapter = secondPersistence.adapter + + const rows = await secondAdapter.loadSubset(collectionId, {}) + expect(rows).toEqual([ + { + key: `1`, + value: { + id: `1`, + title: `Survives restart`, + score: 10, + }, + }, + ]) +}) + +it(`keeps all committed rows under rapid mutation bursts`, async () => { + const dbPath = createTempSqlitePath() + const collectionId = `todos-burst` + const database = createExpoSQLiteTestDatabase({ filename: dbPath }) + activeCleanupFns.push(() => database.closeAsync()) + + const persistence = createExpoSQLitePersistence({ + database, + }) + const adapter = persistence.adapter + + const burstSize = 50 + for (let index = 0; index < burstSize; index++) { + const rowId = String(index + 1) + await adapter.applyCommittedTx(collectionId, { + txId: `tx-burst-${rowId}`, + term: 1, + seq: index + 1, + rowVersion: index + 1, + mutations: [ + { + type: `insert`, + key: rowId, + value: { + id: rowId, + title: `Todo ${rowId}`, + score: index, + }, + }, + ], + }) + } + + const rows = await adapter.loadSubset(collectionId, {}) + expect(rows).toHaveLength(burstSize) +}) + +it(`resumes persisted sync after simulated background/foreground transitions`, async () => { + const dbPath = createTempSqlitePath() + const collectionId = `todos-lifecycle` + const database = createExpoSQLiteTestDatabase({ filename: dbPath }) + activeCleanupFns.push(() => database.closeAsync()) + + const persistence = createExpoSQLitePersistence({ + database, + }) + const collection = createCollection( + persistedCollectionOptions({ + id: collectionId, + getKey: (todo) => todo.id, + persistence, + syncMode: `eager`, + }), + ) + activeCleanupFns.push(() => collection.cleanup()) + + await collection.stateWhenReady() + + const initialInsert = collection.insert({ + id: `1`, + title: `Before background`, + score: 1, + }) + await initialInsert.isPersisted.promise + expect(collection.get(`1`)?.title).toBe(`Before background`) + + await collection.cleanup() + collection.startSyncImmediate() + await collection.stateWhenReady() + + const postResumeInsert = collection.insert({ + id: `2`, + title: `Post resume write`, + score: 2, + }) + await postResumeInsert.isPersisted.promise + expect(collection.get(`2`)?.title).toBe(`Post resume write`) + + const persistedRows = await persistence.adapter.loadSubset(collectionId, {}) + expect(persistedRows).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + key: `1`, + }), + expect.objectContaining({ + key: `2`, + }), + ]), + ) +}) diff --git a/packages/db-expo-sqlite-persisted-collection/tests/expo-runtime-persistence-contract.test.ts b/packages/db-expo-sqlite-persisted-collection/tests/expo-runtime-persistence-contract.test.ts new file mode 100644 index 000000000..8caefee09 --- /dev/null +++ b/packages/db-expo-sqlite-persisted-collection/tests/expo-runtime-persistence-contract.test.ts @@ -0,0 +1,211 @@ +import { mkdtempSync, rmSync } from 'node:fs' +import { tmpdir } from 'node:os' +import { join } from 'node:path' +import { describe, expect, it } from 'vitest' +import { + createExpoSQLiteDriver, + createExpoSQLitePersistence, + persistedCollectionOptions, +} from '../src' +import { runRuntimePersistenceContractSuite } from '../../db-sqlite-persisted-collection-core/tests/contracts/runtime-persistence-contract' +import { SingleProcessCoordinator } from '../../db-sqlite-persisted-collection-core/src' +import { createExpoSQLiteTestDatabase } from './helpers/expo-sqlite-test-db' +import type { + PersistedCollectionCoordinator, + PersistedCollectionPersistence, +} from '@tanstack/db-sqlite-persisted-collection-core' +import type { ExpoSQLiteDatabaseLike } from '../src' +import type { + RuntimePersistenceContractTodo, + RuntimePersistenceDatabaseHarness, +} from '../../db-sqlite-persisted-collection-core/tests/contracts/runtime-persistence-contract' + +type RuntimePersistenceFactory = (options: { + database: ExpoSQLiteDatabaseLike + coordinator?: PersistedCollectionCoordinator +}) => PersistedCollectionPersistence + +type SQLiteDriverWithDatabase = ReturnType & { + __tanstackDbDatabase: ExpoSQLiteDatabaseLike +} + +function createRuntimeDatabaseHarness(): RuntimePersistenceDatabaseHarness { + const tempDirectory = mkdtempSync(join(tmpdir(), `db-expo-persistence-`)) + const dbPath = join(tempDirectory, `state.sqlite`) + const drivers = new Set() + const databases = new Set>() + + return { + createDriver: () => { + const database = createExpoSQLiteTestDatabase({ + filename: dbPath, + }) + const driver = Object.assign(createExpoSQLiteDriver({ database }), { + __tanstackDbDatabase: database, + }) + databases.add(database) + drivers.add(driver) + return driver + }, + cleanup: async () => { + for (const database of databases) { + try { + await database.closeAsync() + } catch { + // ignore cleanup errors from already-closed handles + } + } + databases.clear() + drivers.clear() + rmSync(tempDirectory, { recursive: true, force: true }) + }, + } +} + +const createPersistence: RuntimePersistenceFactory = (options) => + createExpoSQLitePersistence(options) + +runRuntimePersistenceContractSuite(`expo runtime persistence helpers`, { + createDatabaseHarness: createRuntimeDatabaseHarness, + createAdapter: (driver) => + createPersistence({ + database: (driver as SQLiteDriverWithDatabase).__tanstackDbDatabase, + }).adapter, + createPersistence: (driver, coordinator) => + createPersistence({ + database: (driver as SQLiteDriverWithDatabase).__tanstackDbDatabase, + coordinator, + }), + createCoordinator: () => new SingleProcessCoordinator(), +}) + +describe(`expo runtime persistence helper parity`, () => { + it(`defaults coordinator to SingleProcessCoordinator`, async () => { + const runtimeHarness = createRuntimeDatabaseHarness() + const driver = runtimeHarness.createDriver() as ReturnType< + typeof createExpoSQLiteDriver + > + try { + const persistence = createExpoSQLitePersistence({ + database: await driver.getDatabase(), + }) + expect(persistence.coordinator).toBeInstanceOf(SingleProcessCoordinator) + } finally { + await runtimeHarness.cleanup() + } + }) + + it(`allows overriding the default coordinator`, async () => { + const runtimeHarness = createRuntimeDatabaseHarness() + const driver = runtimeHarness.createDriver() as ReturnType< + typeof createExpoSQLiteDriver + > + try { + const coordinator = new SingleProcessCoordinator() + const persistence = createExpoSQLitePersistence({ + database: await driver.getDatabase(), + coordinator, + }) + expect(persistence.coordinator).toBe(coordinator) + } finally { + await runtimeHarness.cleanup() + } + }) + + it(`infers schema policy from sync mode`, async () => { + const tempDirectory = mkdtempSync(join(tmpdir(), `db-expo-schema-infer-`)) + const dbPath = join(tempDirectory, `state.sqlite`) + const collectionId = `todos` + const firstDatabase = createExpoSQLiteTestDatabase({ + filename: dbPath, + }) + + try { + const firstPersistence = createExpoSQLitePersistence< + RuntimePersistenceContractTodo, + string + >({ + database: firstDatabase, + }) + const firstCollectionOptions = persistedCollectionOptions< + RuntimePersistenceContractTodo, + string + >({ + id: collectionId, + schemaVersion: 1, + getKey: (todo) => todo.id, + persistence: firstPersistence, + }) + await firstCollectionOptions.persistence.adapter.applyCommittedTx( + collectionId, + { + txId: `tx-1`, + term: 1, + seq: 1, + rowVersion: 1, + mutations: [ + { + type: `insert`, + key: `1`, + value: { + id: `1`, + title: `before mismatch`, + score: 1, + }, + }, + ], + }, + ) + } finally { + await firstDatabase.closeAsync() + } + + const secondDatabase = createExpoSQLiteTestDatabase({ + filename: dbPath, + }) + try { + const secondPersistence = createExpoSQLitePersistence< + RuntimePersistenceContractTodo, + string + >({ + database: secondDatabase, + }) + + const syncAbsentOptions = persistedCollectionOptions< + RuntimePersistenceContractTodo, + string + >({ + id: collectionId, + schemaVersion: 2, + getKey: (todo) => todo.id, + persistence: secondPersistence, + }) + await expect( + syncAbsentOptions.persistence.adapter.loadSubset(collectionId, {}), + ).rejects.toThrow(`Schema version mismatch`) + + const syncPresentOptions = persistedCollectionOptions< + RuntimePersistenceContractTodo, + string + >({ + id: collectionId, + schemaVersion: 2, + getKey: (todo) => todo.id, + sync: { + sync: ({ markReady }) => { + markReady() + }, + }, + persistence: secondPersistence, + }) + const rows = await syncPresentOptions.persistence.adapter.loadSubset( + collectionId, + {}, + ) + expect(rows).toEqual([]) + } finally { + await secondDatabase.closeAsync() + rmSync(tempDirectory, { recursive: true, force: true }) + } + }) +}) diff --git a/packages/db-expo-sqlite-persisted-collection/tests/expo-sqlite-core-adapter-contract.test.ts b/packages/db-expo-sqlite-persisted-collection/tests/expo-sqlite-core-adapter-contract.test.ts new file mode 100644 index 000000000..5abcbaebc --- /dev/null +++ b/packages/db-expo-sqlite-persisted-collection/tests/expo-sqlite-core-adapter-contract.test.ts @@ -0,0 +1,42 @@ +import { mkdtempSync, rmSync } from 'node:fs' +import { tmpdir } from 'node:os' +import { join } from 'node:path' +import { runSQLiteCoreAdapterContractSuite } from '../../db-sqlite-persisted-collection-core/tests/contracts/sqlite-core-adapter-contract' +import { ExpoSQLiteDriver } from '../src' +import { SQLiteCorePersistenceAdapter } from '../../db-sqlite-persisted-collection-core/src' +import { createExpoSQLiteTestDatabase } from './helpers/expo-sqlite-test-db' +import type { + SQLiteCoreAdapterContractTodo, + SQLiteCoreAdapterHarnessFactory, +} from '../../db-sqlite-persisted-collection-core/tests/contracts/sqlite-core-adapter-contract' + +const createHarness: SQLiteCoreAdapterHarnessFactory = (options) => { + const tempDirectory = mkdtempSync(join(tmpdir(), `db-expo-core-`)) + const dbPath = join(tempDirectory, `state.sqlite`) + const database = createExpoSQLiteTestDatabase({ + filename: dbPath, + }) + const driver = new ExpoSQLiteDriver({ database }) + + const adapter = new SQLiteCorePersistenceAdapter< + SQLiteCoreAdapterContractTodo, + string + >({ + driver, + ...options, + }) + + return { + adapter, + driver, + cleanup: async () => { + await database.closeAsync() + rmSync(tempDirectory, { recursive: true, force: true }) + }, + } +} + +runSQLiteCoreAdapterContractSuite( + `SQLiteCorePersistenceAdapter (expo-sqlite driver harness)`, + createHarness, +) diff --git a/packages/db-expo-sqlite-persisted-collection/tests/expo-sqlite-driver.test.ts b/packages/db-expo-sqlite-persisted-collection/tests/expo-sqlite-driver.test.ts new file mode 100644 index 000000000..8c1a4ef5e --- /dev/null +++ b/packages/db-expo-sqlite-persisted-collection/tests/expo-sqlite-driver.test.ts @@ -0,0 +1,200 @@ +import { mkdtempSync, rmSync } from 'node:fs' +import { tmpdir } from 'node:os' +import { join } from 'node:path' +import { afterEach, expect, it } from 'vitest' +import { ExpoSQLiteDriver } from '../src' +import { InvalidPersistedCollectionConfigError } from '../../db-sqlite-persisted-collection-core/src' +import { createExpoSQLiteTestDatabase } from './helpers/expo-sqlite-test-db' + +const activeCleanupFns: Array<() => void | Promise> = [] + +afterEach(async () => { + while (activeCleanupFns.length > 0) { + const cleanupFn = activeCleanupFns.pop() + await Promise.resolve(cleanupFn?.()) + } +}) + +function createTempSqlitePath(): string { + const tempDirectory = mkdtempSync(join(tmpdir(), `db-expo-sqlite-test-`)) + const dbPath = join(tempDirectory, `state.sqlite`) + activeCleanupFns.push(() => { + rmSync(tempDirectory, { recursive: true, force: true }) + }) + return dbPath +} + +it(`reads query rows through getAllAsync`, async () => { + const dbPath = createTempSqlitePath() + const database = createExpoSQLiteTestDatabase({ filename: dbPath }) + activeCleanupFns.push(() => database.closeAsync()) + + const driver = new ExpoSQLiteDriver({ database }) + await driver.exec( + `CREATE TABLE todos (id TEXT PRIMARY KEY, title TEXT NOT NULL, score INTEGER NOT NULL)`, + ) + await driver.run(`INSERT INTO todos (id, title, score) VALUES (?, ?, ?)`, [ + `1`, + `From expo test`, + 7, + ]) + + const rows = await driver.query<{ + id: string + title: string + score: number + }>(`SELECT id, title, score FROM todos ORDER BY id ASC`) + expect(rows).toEqual([ + { + id: `1`, + title: `From expo test`, + score: 7, + }, + ]) +}) + +it(`rolls back exclusive transaction on failure`, async () => { + const dbPath = createTempSqlitePath() + const database = createExpoSQLiteTestDatabase({ filename: dbPath }) + activeCleanupFns.push(() => database.closeAsync()) + + const driver = new ExpoSQLiteDriver({ database }) + await driver.exec( + `CREATE TABLE tx_test (id TEXT PRIMARY KEY, title TEXT NOT NULL)`, + ) + + await expect( + driver.transactionWithDriver(async (transactionDriver) => { + await transactionDriver.run( + `INSERT INTO tx_test (id, title) VALUES (?, ?)`, + [`1`, `First`], + ) + await transactionDriver.run( + `INSERT INTO tx_test (missing_column) VALUES (?)`, + [`x`], + ) + }), + ).rejects.toThrow() + + const rows = await driver.query<{ count: number }>( + `SELECT COUNT(*) AS count FROM tx_test`, + ) + expect(rows[0]?.count).toBe(0) +}) + +it(`supports nested savepoint rollback without losing outer transaction`, async () => { + const dbPath = createTempSqlitePath() + const database = createExpoSQLiteTestDatabase({ filename: dbPath }) + activeCleanupFns.push(() => database.closeAsync()) + + const driver = new ExpoSQLiteDriver({ database }) + await driver.exec( + `CREATE TABLE nested_tx_test (id TEXT PRIMARY KEY, title TEXT NOT NULL)`, + ) + + await driver.transactionWithDriver(async (outerTransactionDriver) => { + await outerTransactionDriver.run( + `INSERT INTO nested_tx_test (id, title) VALUES (?, ?)`, + [`1`, `Outer before`], + ) + + await expect( + outerTransactionDriver.transaction(async (innerTransactionDriver) => { + await innerTransactionDriver.run( + `INSERT INTO nested_tx_test (id, title) VALUES (?, ?)`, + [`2`, `Inner failing`], + ) + throw new Error(`nested-failure`) + }), + ).rejects.toThrow(`nested-failure`) + + await outerTransactionDriver.run( + `INSERT INTO nested_tx_test (id, title) VALUES (?, ?)`, + [`3`, `Outer after`], + ) + }) + + const rows = await driver.query<{ id: string; title: string }>( + `SELECT id, title FROM nested_tx_test ORDER BY id ASC`, + ) + expect(rows).toEqual([ + { id: `1`, title: `Outer before` }, + { id: `3`, title: `Outer after` }, + ]) +}) + +it(`supports transaction callbacks that use provided transaction driver`, async () => { + const dbPath = createTempSqlitePath() + const database = createExpoSQLiteTestDatabase({ filename: dbPath }) + activeCleanupFns.push(() => database.closeAsync()) + + const driver = new ExpoSQLiteDriver({ database }) + await driver.exec(`CREATE TABLE closure_tx_test (value INTEGER NOT NULL)`) + + let resolveHold: (() => void) | undefined + const hold = new Promise((resolve) => { + resolveHold = resolve + }) + let resolveEntered: (() => void) | undefined + const entered = new Promise((resolve) => { + resolveEntered = resolve + }) + + const txPromise = driver.transaction(async (transactionDriver) => { + if (!resolveEntered) { + throw new Error(`transaction entry signal missing`) + } + resolveEntered() + await transactionDriver.run( + `INSERT INTO closure_tx_test (value) VALUES (?)`, + [1], + ) + await hold + await transactionDriver.run( + `INSERT INTO closure_tx_test (value) VALUES (?)`, + [2], + ) + }) + + await entered + + let outsideResolved = false + const outsidePromise = driver + .run(`INSERT INTO closure_tx_test (value) VALUES (?)`, [3]) + .then(() => { + outsideResolved = true + }) + + await Promise.resolve() + expect(outsideResolved).toBe(false) + + if (!resolveHold) { + throw new Error(`transaction hold signal missing`) + } + resolveHold() + + await Promise.all([txPromise, outsidePromise]) + + const rows = await driver.query<{ value: number }>( + `SELECT value FROM closure_tx_test ORDER BY value ASC`, + ) + expect(rows.map((row) => row.value)).toEqual([1, 2, 3]) +}) + +it(`throws when transaction callback omits transaction driver argument`, async () => { + const dbPath = createTempSqlitePath() + const database = createExpoSQLiteTestDatabase({ filename: dbPath }) + activeCleanupFns.push(() => database.closeAsync()) + + const driver = new ExpoSQLiteDriver({ database }) + + await expect( + driver.transaction((() => Promise.resolve(undefined)) as never), + ).rejects.toThrow(`transaction driver argument`) +}) + +it(`throws config error when expo database methods are missing`, () => { + expect(() => new ExpoSQLiteDriver({ database: {} as never })).toThrowError( + InvalidPersistedCollectionConfigError, + ) +}) diff --git a/packages/db-expo-sqlite-persisted-collection/tests/helpers/expo-emulator-database-factory.ts b/packages/db-expo-sqlite-persisted-collection/tests/helpers/expo-emulator-database-factory.ts new file mode 100644 index 000000000..72c255fdb --- /dev/null +++ b/packages/db-expo-sqlite-persisted-collection/tests/helpers/expo-emulator-database-factory.ts @@ -0,0 +1,62 @@ +import { ensureExpoEmulatorRuntime } from './expo-emulator-runtime' +import type { + ExpoSQLiteTestDatabase, + ExpoSQLiteTestDatabaseFactory, +} from './expo-sqlite-test-db' + +function resolvePlatform(): `ios` | `android` { + const platform = process.env.TANSTACK_DB_EXPO_RUNTIME_PLATFORM?.trim() + return platform === `android` ? `android` : `ios` +} + +export function createMobileSQLiteTestDatabaseFactory(): ExpoSQLiteTestDatabaseFactory { + const platform = resolvePlatform() + let runtimePromise: + | Promise>> + | undefined + + const getRuntime = () => { + runtimePromise ??= ensureExpoEmulatorRuntime(platform) + return runtimePromise + } + + return (options): ExpoSQLiteTestDatabase => { + let databasePromise: + | Promise< + ReturnType< + Awaited< + ReturnType + >[`createDatabase`] + > + > + | undefined + + const getDatabase = () => { + databasePromise ??= getRuntime().then((runtime) => + runtime.createDatabase(options), + ) + return databasePromise + } + + return { + execAsync: async (sql) => { + await (await getDatabase()).execAsync(sql) + }, + getAllAsync: async (sql, params) => + (await getDatabase()).getAllAsync(sql, params), + runAsync: async (sql, params) => + (await getDatabase()).runAsync(sql, params), + withExclusiveTransactionAsync: async (task): Promise => + (await getDatabase()).withExclusiveTransactionAsync(task), + closeAsync: async () => { + if (!databasePromise) { + return + } + + await (await databasePromise).closeAsync() + }, + } + } +} + +export default createMobileSQLiteTestDatabaseFactory diff --git a/packages/db-expo-sqlite-persisted-collection/tests/helpers/expo-emulator-runtime.ts b/packages/db-expo-sqlite-persisted-collection/tests/helpers/expo-emulator-runtime.ts new file mode 100644 index 000000000..f3d710519 --- /dev/null +++ b/packages/db-expo-sqlite-persisted-collection/tests/helpers/expo-emulator-runtime.ts @@ -0,0 +1,516 @@ +import { existsSync } from 'node:fs' +import { createServer } from 'node:http' +import { randomUUID } from 'node:crypto' +import { createServer as createNetServer } from 'node:net' +import { basename, delimiter, resolve } from 'node:path' +import { spawn } from 'node:child_process' +import type { IncomingMessage, ServerResponse } from 'node:http' +import type { ChildProcessWithoutNullStreams } from 'node:child_process' +import type { + ExpoSQLiteBindParams, + ExpoSQLiteDatabaseLike, + ExpoSQLiteRunResult, + ExpoSQLiteTransaction, +} from '../../src' +import type { + ExpoRuntimeCommand, + ExpoRuntimeCommandResult, + ExpoRuntimeRegistration, + ExpoRuntimeSmokeTestResult, +} from '../../e2e/runtime-protocol' + +type RuntimePlatform = `ios` | `android` + +type Deferred = { + promise: Promise + resolve: (value: T | PromiseLike) => void + reject: (error?: unknown) => void +} + +type PendingCommand = { + command: ExpoRuntimeCommand + deferred: Deferred +} + +type ExpoRuntimeCommandInput = ExpoRuntimeCommand extends infer TCommand + ? TCommand extends { id: string } + ? Omit + : never + : never + +function createDeferred(): Deferred { + let resolveDeferred!: Deferred[`resolve`] + let reject!: Deferred[`reject`] + const promise = new Promise((innerResolve, innerReject) => { + resolveDeferred = innerResolve + reject = innerReject + }) + return { promise, resolve: resolveDeferred, reject } +} + +function jsonResponse( + response: ServerResponse, + statusCode: number, + body: unknown, +): void { + response.statusCode = statusCode + response.setHeader(`content-type`, `application/json`) + response.end(JSON.stringify(body)) +} + +async function readJsonBody( + request: IncomingMessage, +): Promise { + const chunks: Array = [] + for await (const chunk of request) { + chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)) + } + + if (chunks.length === 0) { + return undefined + } + + return JSON.parse(Buffer.concat(chunks).toString(`utf8`)) as T +} + +function getRuntimeAppDirectory(): string { + return resolve(process.cwd(), `e2e/expo-runtime-app`) +} + +function getHostBridgeUrl(platform: RuntimePlatform, port: number): string { + const hostname = platform === `android` ? `10.0.2.2` : `127.0.0.1` + return `http://${hostname}:${port}` +} + +function getProjectName(platform: RuntimePlatform): string { + return platform === `android` ? `expo-emulator-android` : `expo-emulator-ios` +} + +function getAndroidSdkDirectory(): string | undefined { + const configuredSdkDirectory = + process.env.ANDROID_HOME?.trim() || process.env.ANDROID_SDK_ROOT?.trim() + + if (configuredSdkDirectory && existsSync(configuredSdkDirectory)) { + return configuredSdkDirectory + } + + const homeDirectory = process.env.HOME?.trim() + if (!homeDirectory) { + return undefined + } + + const defaultSdkDirectory = resolve(homeDirectory, `Library/Android/sdk`) + return existsSync(defaultSdkDirectory) ? defaultSdkDirectory : undefined +} + +function createRuntimeEnvironment(options: { + platform: RuntimePlatform + bridgeUrl: string + sessionId: string +}): NodeJS.ProcessEnv { + const environment: NodeJS.ProcessEnv = { + ...process.env, + EXPO_PUBLIC_TSDB_BRIDGE_URL: options.bridgeUrl, + EXPO_PUBLIC_TSDB_SESSION_ID: options.sessionId, + EXPO_PUBLIC_TSDB_RUNTIME_PLATFORM: options.platform, + CI: process.env.CI ?? `1`, + } + + if (options.platform !== `android`) { + return environment + } + + const sdkDirectory = getAndroidSdkDirectory() + if (!sdkDirectory) { + return environment + } + + const pathEntries = [ + resolve(sdkDirectory, `platform-tools`), + resolve(sdkDirectory, `emulator`), + resolve(sdkDirectory, `tools`), + resolve(sdkDirectory, `tools/bin`), + environment.PATH ?? ``, + ].filter((entry) => entry.length > 0) + + environment.PATH = pathEntries.join(delimiter) + environment.ANDROID_HOME ??= sdkDirectory + environment.ANDROID_SDK_ROOT ??= sdkDirectory + + return environment +} + +async function getAvailablePort(): Promise { + return new Promise((resolvePort, rejectPort) => { + const server = createNetServer() + server.once(`error`, rejectPort) + server.listen(0, `127.0.0.1`, () => { + const address = server.address() + if (!address || typeof address === `string`) { + server.close(() => { + rejectPort(new Error(`Unable to allocate an Expo dev server port`)) + }) + return + } + + server.close((closeError) => { + if (closeError) { + rejectPort(closeError) + return + } + + resolvePort(address.port) + }) + }) + }) +} + +function createDefaultLaunchCommand( + platform: RuntimePlatform, + devServerPort: number, +): Array { + const platformFlag = platform === `android` ? `--android` : `--ios` + return [ + `pnpm`, + `exec`, + `expo`, + `start`, + platformFlag, + `--port`, + String(devServerPort), + `--clear`, + ] +} + +function parseCommandOverride(rawCommand: string): Array { + return rawCommand + .split(/\s+/) + .map((part) => part.trim()) + .filter((part) => part.length > 0) +} + +class ExpoEmulatorRuntime { + private static readonly instances = new Map< + RuntimePlatform, + ExpoEmulatorRuntime + >() + + static async get(platform: RuntimePlatform): Promise { + let existing = this.instances.get(platform) + if (!existing) { + existing = new ExpoEmulatorRuntime(platform) + this.instances.set(platform, existing) + } + + await existing.start() + return existing + } + + private readonly pendingCommands: Array = [] + private readonly pendingByCommandId = new Map() + private readonly sessionReady = createDeferred() + private readonly portReady = createDeferred() + private readonly platform: RuntimePlatform + private readonly sessionId = randomUUID() + private serverStarted = false + private childProcess: ChildProcessWithoutNullStreams | null = null + + private constructor(platform: RuntimePlatform) { + this.platform = platform + process.once(`exit`, () => { + this.dispose() + }) + } + + createDatabase(options: { filename: string }): ExpoSQLiteDatabaseLike & { + closeAsync: () => Promise + } { + const databaseName = basename(options.filename) + const databaseId = `${databaseName}:${randomUUID()}` + + return { + execAsync: async (sql: string) => { + await this.sendCommand({ + type: `db:exec`, + databaseId, + databaseName, + sql, + }) + }, + getAllAsync: async ( + sql: string, + params?: ExpoSQLiteBindParams, + ): Promise> => + (await this.sendCommand({ + type: `db:getAll`, + databaseId, + databaseName, + sql, + params, + })) as ReadonlyArray, + runAsync: async ( + sql: string, + params?: ExpoSQLiteBindParams, + ): Promise => + (await this.sendCommand({ + type: `db:run`, + databaseId, + databaseName, + sql, + params, + })) as ExpoSQLiteRunResult, + withExclusiveTransactionAsync: async ( + task: (transaction: ExpoSQLiteTransaction) => Promise, + ): Promise => { + const transactionId = randomUUID() + await this.sendCommand({ + type: `tx:start`, + databaseId, + databaseName, + transactionId, + }) + const transaction: ExpoSQLiteTransaction = { + execAsync: async (sql: string) => { + await this.sendCommand({ + type: `tx:exec`, + transactionId, + sql, + }) + }, + getAllAsync: async ( + sql: string, + params?: ExpoSQLiteBindParams, + ): Promise> => + (await this.sendCommand({ + type: `tx:getAll`, + transactionId, + sql, + params, + })) as ReadonlyArray, + runAsync: async ( + sql: string, + params?: ExpoSQLiteBindParams, + ): Promise => + (await this.sendCommand({ + type: `tx:run`, + transactionId, + sql, + params, + })) as ExpoSQLiteRunResult, + } + + try { + const result = await task(transaction) + await this.sendCommand({ + type: `tx:commit`, + transactionId, + }) + return result + } catch (error) { + await this.sendCommand({ + type: `tx:rollback`, + transactionId, + }) + throw error + } + }, + closeAsync: async () => { + await this.sendCommand({ + type: `db:close`, + databaseId, + databaseName, + }) + }, + } + } + + async runPersistenceSmokeTest( + databaseName: string, + ): Promise { + return (await this.sendCommand({ + type: `app:runPersistenceSmokeTest`, + databaseName, + })) as ExpoRuntimeSmokeTestResult + } + + private async start(): Promise { + if (this.serverStarted) { + await this.portReady.promise + await this.sessionReady.promise + return + } + + this.serverStarted = true + const server = createServer(async (request, response) => { + try { + await this.handleRequest(request, response) + } catch (error) { + jsonResponse(response, 500, { + error: error instanceof Error ? error.message : String(error), + }) + } + }) + + await new Promise((resolveServer, rejectServer) => { + server.once(`error`, rejectServer) + server.listen(0, `0.0.0.0`, () => { + const address = server.address() + if (!address || typeof address === `string`) { + rejectServer(new Error(`Unable to resolve bridge server address`)) + return + } + this.portReady.resolve(address.port) + resolveServer() + }) + }) + + const port = await this.portReady.promise + const bridgeUrl = getHostBridgeUrl(this.platform, port) + const devServerPort = await getAvailablePort() + const launchCommandOverride = + process.env.TANSTACK_DB_EXPO_RUNTIME_APP_COMMAND?.trim() + const launchCommand = launchCommandOverride + ? parseCommandOverride(launchCommandOverride) + : createDefaultLaunchCommand(this.platform, devServerPort) + + const [command, ...args] = launchCommand + if (!command) { + throw new Error(`Expo runtime launch command is empty`) + } + + this.childProcess = spawn(command, args, { + cwd: getRuntimeAppDirectory(), + stdio: `pipe`, + env: createRuntimeEnvironment({ + platform: this.platform, + bridgeUrl, + sessionId: this.sessionId, + }), + }) + + this.childProcess.stdout.on(`data`, (chunk) => { + process.stdout.write( + `[${getProjectName(this.platform)}] ${String(chunk)}`, + ) + }) + this.childProcess.stderr.on(`data`, (chunk) => { + process.stderr.write( + `[${getProjectName(this.platform)}] ${String(chunk)}`, + ) + }) + this.childProcess.once(`exit`, (code) => { + if (code !== 0) { + this.sessionReady.reject( + new Error( + `Expo emulator app exited before registering (code ${code})`, + ), + ) + } + }) + + await Promise.race([ + this.sessionReady.promise, + new Promise((_, reject) => { + setTimeout(() => { + reject( + new Error( + `Timed out waiting for Expo emulator app to register with the host bridge`, + ), + ) + }, 120_000) + }), + ]) + } + + private async sendCommand( + commandInput: ExpoRuntimeCommandInput, + ): Promise { + await this.start() + const command = { + id: randomUUID(), + ...commandInput, + } as ExpoRuntimeCommand + const deferred = createDeferred() + const pending: PendingCommand = { + command, + deferred, + } + this.pendingCommands.push(pending) + this.pendingByCommandId.set(command.id, pending) + return deferred.promise + } + + private async handleRequest( + request: IncomingMessage, + response: ServerResponse, + ): Promise { + const requestUrl = new URL(request.url ?? `/`, `http://127.0.0.1`) + + if (request.method === `POST` && requestUrl.pathname === `/register`) { + const body = await readJsonBody(request) + if (body?.sessionId !== this.sessionId) { + jsonResponse(response, 400, { + error: `Unexpected Expo runtime session id`, + }) + return + } + + this.sessionReady.resolve() + jsonResponse(response, 200, { ok: true }) + return + } + + if (request.method === `GET` && requestUrl.pathname === `/next-command`) { + const pending = this.pendingCommands.shift() + if (!pending) { + response.statusCode = 204 + response.end() + return + } + + jsonResponse(response, 200, pending.command) + return + } + + if ( + request.method === `POST` && + requestUrl.pathname === `/command-result` + ) { + const body = await readJsonBody(request) + if (!body) { + jsonResponse(response, 400, { error: `Missing command result payload` }) + return + } + + const pending = this.pendingByCommandId.get(body.commandId) + if (!pending) { + jsonResponse(response, 404, { error: `Unknown command id` }) + return + } + + this.pendingByCommandId.delete(body.commandId) + if (body.ok) { + pending.deferred.resolve(body.result) + } else { + pending.deferred.reject(new Error(body.error)) + } + + jsonResponse(response, 200, { ok: true }) + return + } + + jsonResponse(response, 404, { error: `Unknown bridge route` }) + } + + private dispose(): void { + if (this.childProcess && !this.childProcess.killed) { + this.childProcess.kill(`SIGTERM`) + } + } +} + +export async function ensureExpoEmulatorRuntime( + platform: RuntimePlatform, +): Promise { + return ExpoEmulatorRuntime.get(platform) +} diff --git a/packages/db-expo-sqlite-persisted-collection/tests/helpers/expo-sqlite-test-db.ts b/packages/db-expo-sqlite-persisted-collection/tests/helpers/expo-sqlite-test-db.ts new file mode 100644 index 000000000..ee31587aa --- /dev/null +++ b/packages/db-expo-sqlite-persisted-collection/tests/helpers/expo-sqlite-test-db.ts @@ -0,0 +1,159 @@ +import BetterSqlite3 from 'better-sqlite3' +import type { + ExpoSQLiteBindParams, + ExpoSQLiteDatabaseLike, + ExpoSQLiteRunResult, + ExpoSQLiteTransaction, +} from '../../src' + +export type ExpoSQLiteTestDatabase = ExpoSQLiteDatabaseLike & { + closeAsync: () => Promise + getNativeDatabase?: () => InstanceType +} + +export type ExpoSQLiteTestDatabaseFactory = (options: { + filename: string +}) => ExpoSQLiteTestDatabase + +declare global { + var __tanstackDbCreateMobileSQLiteTestDatabase: + | ExpoSQLiteTestDatabaseFactory + | undefined +} + +function normalizeRunResult( + result: BetterSqlite3.RunResult, +): ExpoSQLiteRunResult { + return { + changes: result.changes, + lastInsertRowId: + typeof result.lastInsertRowid === `bigint` + ? Number(result.lastInsertRowid) + : result.lastInsertRowid, + } +} + +function hasNamedParameters( + params: ExpoSQLiteBindParams | undefined, +): params is Record { + return params !== undefined && !Array.isArray(params) +} + +function executeAll( + database: InstanceType, + sql: string, + params?: ExpoSQLiteBindParams, +): ReadonlyArray { + const statement = database.prepare(sql) + + if (params === undefined) { + return statement.all() as ReadonlyArray + } + + if (hasNamedParameters(params)) { + return statement.all(params) as ReadonlyArray + } + + return statement.all(...params) as ReadonlyArray +} + +function executeRun( + database: InstanceType, + sql: string, + params?: ExpoSQLiteBindParams, +): ExpoSQLiteRunResult { + const statement = database.prepare(sql) + const result = + params === undefined + ? statement.run() + : hasNamedParameters(params) + ? statement.run(params) + : statement.run(...params) + + return normalizeRunResult(result) +} + +function createTransactionHandle( + database: InstanceType, +): ExpoSQLiteTransaction { + return { + execAsync: (sql: string) => { + database.exec(sql) + return Promise.resolve() + }, + getAllAsync: ( + sql: string, + params?: ExpoSQLiteBindParams, + ): Promise> => + Promise.resolve(executeAll(database, sql, params)), + runAsync: ( + sql: string, + params?: ExpoSQLiteBindParams, + ): Promise => + Promise.resolve(executeRun(database, sql, params)), + } +} + +export function createExpoSQLiteTestDatabase(options: { + filename: string +}): ExpoSQLiteTestDatabase { + if ( + typeof globalThis.__tanstackDbCreateMobileSQLiteTestDatabase === `function` + ) { + return globalThis.__tanstackDbCreateMobileSQLiteTestDatabase(options) + } + + const nativeDatabase = new BetterSqlite3(options.filename) + let queue: Promise = Promise.resolve() + + const enqueue = (operation: () => Promise | T): Promise => { + const queuedOperation = queue.then(operation, operation) + queue = queuedOperation.then( + () => undefined, + () => undefined, + ) + return queuedOperation + } + + return { + execAsync: async (sql: string) => { + await enqueue(() => { + nativeDatabase.exec(sql) + }) + }, + getAllAsync: async ( + sql: string, + params?: ExpoSQLiteBindParams, + ): Promise> => + enqueue(() => executeAll(nativeDatabase, sql, params)), + runAsync: async ( + sql: string, + params?: ExpoSQLiteBindParams, + ): Promise => + enqueue(() => executeRun(nativeDatabase, sql, params)), + withExclusiveTransactionAsync: async ( + task: (transaction: ExpoSQLiteTransaction) => Promise, + ): Promise => + enqueue(async () => { + nativeDatabase.exec(`BEGIN IMMEDIATE`) + const transaction = createTransactionHandle(nativeDatabase) + try { + const result = await task(transaction) + nativeDatabase.exec(`COMMIT`) + return result + } catch (error) { + try { + nativeDatabase.exec(`ROLLBACK`) + } catch { + // Keep the original failure as the primary error. + } + throw error + } + }), + closeAsync: () => { + nativeDatabase.close() + return Promise.resolve() + }, + getNativeDatabase: () => nativeDatabase, + } +} diff --git a/packages/db-expo-sqlite-persisted-collection/tests/helpers/mobile-runtime-test-setup.ts b/packages/db-expo-sqlite-persisted-collection/tests/helpers/mobile-runtime-test-setup.ts new file mode 100644 index 000000000..16609e1c9 --- /dev/null +++ b/packages/db-expo-sqlite-persisted-collection/tests/helpers/mobile-runtime-test-setup.ts @@ -0,0 +1,81 @@ +import { isAbsolute, resolve } from 'node:path' +import { pathToFileURL } from 'node:url' +import type { ExpoSQLiteTestDatabaseFactory } from './expo-sqlite-test-db' + +const FACTORY_MODULE_ENV_VAR = `TANSTACK_DB_MOBILE_SQLITE_FACTORY_MODULE` +const FACTORY_EXPORT_ENV_VAR = `TANSTACK_DB_MOBILE_SQLITE_FACTORY_EXPORT` +const REQUIRE_FACTORY_ENV_VAR = `TANSTACK_DB_MOBILE_REQUIRE_RUNTIME_FACTORY` +const DEFAULT_FACTORY_EXPORT_NAME = `createMobileSQLiteTestDatabaseFactory` + +type MobileSQLiteFactoryExport = + | ExpoSQLiteTestDatabaseFactory + | (() => ExpoSQLiteTestDatabaseFactory) + | (() => Promise) + +function toImportSpecifier(rawSpecifier: string): string { + if (rawSpecifier.startsWith(`.`) || isAbsolute(rawSpecifier)) { + const absolutePath = isAbsolute(rawSpecifier) + ? rawSpecifier + : resolve(process.cwd(), rawSpecifier) + return pathToFileURL(absolutePath).href + } + + return rawSpecifier +} + +async function resolveFactoryFromExport( + exportedFactory: unknown, +): Promise { + if (typeof exportedFactory !== `function`) { + return null + } + + const candidate = exportedFactory as MobileSQLiteFactoryExport + if (candidate.length === 0) { + const resolvedFactory = await ( + candidate as + | (() => ExpoSQLiteTestDatabaseFactory) + | (() => Promise) + )() + if (typeof resolvedFactory === `function`) { + return resolvedFactory + } + } + + return candidate as ExpoSQLiteTestDatabaseFactory +} + +globalThis.__tanstackDbCreateMobileSQLiteTestDatabase = undefined + +const runtimeFactoryModule = process.env[FACTORY_MODULE_ENV_VAR]?.trim() +const requireRuntimeFactory = + process.env[REQUIRE_FACTORY_ENV_VAR]?.trim() === `1` + +if (requireRuntimeFactory && !runtimeFactoryModule) { + throw new Error( + `Missing ${FACTORY_MODULE_ENV_VAR}. ` + + `Set it to a module exporting a runtime mobile SQLite test database factory ` + + `when ${REQUIRE_FACTORY_ENV_VAR}=1.`, + ) +} + +if (runtimeFactoryModule) { + const runtimeModule = (await import( + toImportSpecifier(runtimeFactoryModule) + )) as Record + const factoryExportName = + process.env[FACTORY_EXPORT_ENV_VAR]?.trim() || DEFAULT_FACTORY_EXPORT_NAME + const selectedExport = + runtimeModule[factoryExportName] ?? runtimeModule.default + const resolvedFactory = await resolveFactoryFromExport(selectedExport) + + if (!resolvedFactory) { + throw new Error( + `Unable to resolve a mobile SQLite test database factory from "${runtimeFactoryModule}". ` + + `Expected export "${factoryExportName}" (or default export) to be a database factory ` + + `or a zero-argument function that returns one.`, + ) + } + + globalThis.__tanstackDbCreateMobileSQLiteTestDatabase = resolvedFactory +} diff --git a/packages/db-expo-sqlite-persisted-collection/tsconfig.docs.json b/packages/db-expo-sqlite-persisted-collection/tsconfig.docs.json new file mode 100644 index 000000000..5fddb4598 --- /dev/null +++ b/packages/db-expo-sqlite-persisted-collection/tsconfig.docs.json @@ -0,0 +1,12 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "paths": { + "@tanstack/db": ["../db/src"], + "@tanstack/db-sqlite-persisted-collection-core": [ + "../db-sqlite-persisted-collection-core/src" + ] + } + }, + "include": ["src"] +} diff --git a/packages/db-expo-sqlite-persisted-collection/tsconfig.json b/packages/db-expo-sqlite-persisted-collection/tsconfig.json new file mode 100644 index 000000000..c51df7306 --- /dev/null +++ b/packages/db-expo-sqlite-persisted-collection/tsconfig.json @@ -0,0 +1,24 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "target": "ES2020", + "module": "ESNext", + "moduleResolution": "Bundler", + "declaration": true, + "outDir": "dist", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "jsx": "react", + "paths": { + "@tanstack/db": ["../db/src"], + "@tanstack/db-ivm": ["../db-ivm/src"], + "@tanstack/db-sqlite-persisted-collection-core": [ + "../db-sqlite-persisted-collection-core/src" + ] + } + }, + "include": ["src", "tests", "e2e", "vite.config.ts", "vitest.e2e.config.ts"], + "exclude": ["node_modules", "dist", "e2e/expo-runtime-app"] +} diff --git a/packages/db-expo-sqlite-persisted-collection/vite.config.ts b/packages/db-expo-sqlite-persisted-collection/vite.config.ts new file mode 100644 index 000000000..a2139c9eb --- /dev/null +++ b/packages/db-expo-sqlite-persisted-collection/vite.config.ts @@ -0,0 +1,26 @@ +import { defineConfig, mergeConfig } from 'vitest/config' +import { tanstackViteConfig } from '@tanstack/vite-config' +import packageJson from './package.json' + +const config = defineConfig({ + test: { + name: packageJson.name, + include: [`tests/**/*.test.ts`], + exclude: [`e2e/**/*.e2e.test.ts`], + environment: `node`, + setupFiles: [`./tests/helpers/mobile-runtime-test-setup.ts`], + coverage: { enabled: true, provider: `istanbul`, include: [`src/**/*`] }, + typecheck: { + enabled: true, + include: [`tests/**/*.test.ts`], + }, + }, +}) + +export default mergeConfig( + config, + tanstackViteConfig({ + entry: `./src/index.ts`, + srcDir: `./src`, + }), +) diff --git a/packages/db-expo-sqlite-persisted-collection/vitest.e2e.config.ts b/packages/db-expo-sqlite-persisted-collection/vitest.e2e.config.ts new file mode 100644 index 000000000..cc5e6d535 --- /dev/null +++ b/packages/db-expo-sqlite-persisted-collection/vitest.e2e.config.ts @@ -0,0 +1,32 @@ +import { dirname, resolve } from 'node:path' +import { fileURLToPath } from 'node:url' +import { defineConfig } from 'vitest/config' + +const packageDirectory = dirname(fileURLToPath(import.meta.url)) + +export default defineConfig({ + resolve: { + alias: { + '@tanstack/db': resolve(packageDirectory, `../db/src`), + '@tanstack/db-ivm': resolve(packageDirectory, `../db-ivm/src`), + '@tanstack/db-sqlite-persisted-collection-core': resolve( + packageDirectory, + `../db-sqlite-persisted-collection-core/src`, + ), + }, + }, + test: { + include: [`e2e/**/*.e2e.test.ts`], + fileParallelism: false, + hookTimeout: 60_000, + testTimeout: 60_000, + environment: `jsdom`, + setupFiles: [`./tests/helpers/mobile-runtime-test-setup.ts`], + typecheck: { + enabled: false, + }, + coverage: { + enabled: false, + }, + }, +}) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index beb589e68..fd0b92175 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -218,16 +218,16 @@ importers: version: 5.90.21(react@19.2.4) expo: specifier: ~53.0.26 - version: 53.0.27(@babel/core@7.29.0)(@expo/metro-runtime@5.0.5(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4)))(graphql@16.12.0)(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) + version: 53.0.27(@babel/core@7.29.0)(@expo/dom-webview@55.0.3)(@expo/metro-runtime@5.0.5(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4)))(graphql@16.12.0)(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) expo-constants: specifier: ~17.1.0 - version: 17.1.8(expo@53.0.27(@babel/core@7.29.0)(@expo/metro-runtime@5.0.5(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4)))(graphql@16.12.0)(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4)) + version: 17.1.8(expo@53.0.27)(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4)) expo-linking: specifier: ~7.1.0 - version: 7.1.7(expo@53.0.27(@babel/core@7.29.0)(@expo/metro-runtime@5.0.5(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4)))(graphql@16.12.0)(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) + version: 7.1.7(expo@53.0.27)(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) expo-router: specifier: ~5.1.11 - version: 5.1.11(eab00a62f9f3891b852b0c18e99a25ac) + version: 5.1.11(@types/react@19.2.14)(expo-constants@17.1.8(expo@53.0.27)(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4)))(expo-linking@7.1.7(expo@53.0.27)(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(expo@53.0.27)(react-native-safe-area-context@5.4.0(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(react-native-screens@4.11.1(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) expo-status-bar: specifier: ~2.2.0 version: 2.2.3(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) @@ -413,16 +413,16 @@ importers: version: 11.10.0(typescript@5.9.3) better-auth: specifier: ^1.4.18 - version: 1.4.18(f906072589a91c79df666d45593ff2aa) + version: 1.4.18(1b793ba0314cea31a9e4f726e7b3a675) dotenv: specifier: ^17.2.4 version: 17.3.1 drizzle-orm: specifier: ^0.45.1 - version: 0.45.1(@op-engineering/op-sqlite@15.2.5(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.18.0)(better-sqlite3@12.6.2)(gel@2.1.1)(kysely@0.28.11)(pg@8.19.0)(postgres@3.4.8) + version: 0.45.1(@op-engineering/op-sqlite@15.2.5(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.18.0)(better-sqlite3@12.6.2)(expo-sqlite@55.0.10(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(gel@2.1.1)(kysely@0.28.11)(pg@8.19.0)(postgres@3.4.8) drizzle-zod: specifier: ^0.8.3 - version: 0.8.3(drizzle-orm@0.45.1(@op-engineering/op-sqlite@15.2.5(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.18.0)(better-sqlite3@12.6.2)(gel@2.1.1)(kysely@0.28.11)(pg@8.19.0)(postgres@3.4.8))(zod@4.3.6) + version: 0.8.3(drizzle-orm@0.45.1(@op-engineering/op-sqlite@15.2.5(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.18.0)(better-sqlite3@12.6.2)(expo-sqlite@55.0.10(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(gel@2.1.1)(kysely@0.28.11)(pg@8.19.0)(postgres@3.4.8))(zod@4.3.6) pg: specifier: ^8.18.0 version: 8.19.0 @@ -543,10 +543,10 @@ importers: version: 2.8.6 drizzle-orm: specifier: ^0.45.1 - version: 0.45.1(@op-engineering/op-sqlite@15.2.5(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.18.0)(better-sqlite3@12.6.2)(gel@2.1.1)(kysely@0.28.11)(pg@8.19.0)(postgres@3.4.8) + version: 0.45.1(@op-engineering/op-sqlite@15.2.5(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.18.0)(better-sqlite3@12.6.2)(expo-sqlite@55.0.10(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(gel@2.1.1)(kysely@0.28.11)(pg@8.19.0)(postgres@3.4.8) drizzle-zod: specifier: ^0.8.3 - version: 0.8.3(drizzle-orm@0.45.1(@op-engineering/op-sqlite@15.2.5(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.18.0)(better-sqlite3@12.6.2)(gel@2.1.1)(kysely@0.28.11)(pg@8.19.0)(postgres@3.4.8))(zod@4.3.6) + version: 0.8.3(drizzle-orm@0.45.1(@op-engineering/op-sqlite@15.2.5(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.18.0)(better-sqlite3@12.6.2)(expo-sqlite@55.0.10(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(gel@2.1.1)(kysely@0.28.11)(pg@8.19.0)(postgres@3.4.8))(zod@4.3.6) express: specifier: ^5.2.1 version: 5.2.1 @@ -664,10 +664,10 @@ importers: version: 2.8.6 drizzle-orm: specifier: ^0.45.1 - version: 0.45.1(@op-engineering/op-sqlite@15.2.5(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.18.0)(better-sqlite3@12.6.2)(gel@2.1.1)(kysely@0.28.11)(pg@8.19.0)(postgres@3.4.8) + version: 0.45.1(@op-engineering/op-sqlite@15.2.5(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.18.0)(better-sqlite3@12.6.2)(expo-sqlite@55.0.10(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(gel@2.1.1)(kysely@0.28.11)(pg@8.19.0)(postgres@3.4.8) drizzle-zod: specifier: ^0.8.3 - version: 0.8.3(drizzle-orm@0.45.1(@op-engineering/op-sqlite@15.2.5(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.18.0)(better-sqlite3@12.6.2)(gel@2.1.1)(kysely@0.28.11)(pg@8.19.0)(postgres@3.4.8))(zod@4.3.6) + version: 0.8.3(drizzle-orm@0.45.1(@op-engineering/op-sqlite@15.2.5(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.18.0)(better-sqlite3@12.6.2)(expo-sqlite@55.0.10(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(gel@2.1.1)(kysely@0.28.11)(pg@8.19.0)(postgres@3.4.8))(zod@4.3.6) express: specifier: ^5.2.1 version: 5.2.1 @@ -862,6 +862,49 @@ importers: packages/db-collections: {} + packages/db-expo-sqlite-persisted-collection: + dependencies: + '@tanstack/db-sqlite-persisted-collection-core': + specifier: workspace:* + version: link:../db-sqlite-persisted-collection-core + expo-sqlite: + specifier: ^55.0.10 + version: 55.0.10(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) + typescript: + specifier: '>=4.7' + version: 5.9.3 + devDependencies: + '@types/better-sqlite3': + specifier: ^7.6.13 + version: 7.6.13 + '@vitest/coverage-istanbul': + specifier: ^3.2.4 + version: 3.2.4(vitest@3.2.4) + better-sqlite3: + specifier: ^12.6.2 + version: 12.6.2 + + packages/db-expo-sqlite-persisted-collection/e2e/expo-runtime-app: + dependencies: + '@tanstack/db': + specifier: workspace:* + version: link:../../../db + '@tanstack/db-expo-sqlite-persisted-collection': + specifier: workspace:* + version: link:../.. + expo: + specifier: ~55.0.6 + version: 55.0.6(@babel/core@7.29.0)(@expo/dom-webview@55.0.3)(expo-router@5.1.11)(react-dom@19.2.4(react@19.2.0))(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3) + expo-sqlite: + specifier: ^55.0.10 + version: 55.0.10(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0) + react: + specifier: 19.2.0 + version: 19.2.0 + react-native: + specifier: 0.83.2 + version: 0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0) + packages/db-ivm: dependencies: fractional-indexing: @@ -885,7 +928,7 @@ importers: dependencies: '@op-engineering/op-sqlite': specifier: ^15.2.5 - version: 15.2.5(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) + version: 15.2.5(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) '@tanstack/db-sqlite-persisted-collection-core': specifier: workspace:* version: link:../db-sqlite-persisted-collection-core @@ -1716,6 +1759,12 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-class-static-block@7.28.6': + resolution: {integrity: sha512-rfQ++ghVwTWTqQ7w8qyDxL1XGihjBss4CmTgGRCTAC9RIbhVpyp4fOeZtta0Lbf+dTNIVJer6ych2ibHwkZqsQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.12.0 + '@babel/plugin-transform-classes@7.28.6': resolution: {integrity: sha512-EF5KONAqC5zAqT783iMGuM2ZtmEBy+mJMOKl2BCvPZ2lVrwvXnB6o+OBWCS+CoeCCpVRF2sA2RBKUxvT8tQT5Q==} engines: {node: '>=6.9.0'} @@ -2742,61 +2791,185 @@ packages: resolution: {integrity: sha512-XybHfF2QNPJNnHoUKHcG796iEkX5126UuTAs6MSpZuvZRRQRj/sGCLX+driCOVHbDOpcCOusMuHrhxHbtTApyg==} hasBin: true + '@expo/cli@55.0.16': + resolution: {integrity: sha512-rp1mBnA5msGDPTfFuqVl+9RsJOtuA0cXsWSJpHdvsIxcSVg0oJyF/rgvrwsFrNQCLXzkMXm+o3CsY9iL1D/CDA==} + hasBin: true + peerDependencies: + expo: '*' + expo-router: '*' + react-native: '*' + peerDependenciesMeta: + expo-router: + optional: true + react-native: + optional: true + '@expo/code-signing-certificates@0.0.6': resolution: {integrity: sha512-iNe0puxwBNEcuua9gmTGzq+SuMDa0iATai1FlFTMHJ/vUmKvN/V//drXoLJkVb5i5H3iE/n/qIJxyoBnXouD0w==} '@expo/config-plugins@10.1.2': resolution: {integrity: sha512-IMYCxBOcnuFStuK0Ay+FzEIBKrwW8OVUMc65+v0+i7YFIIe8aL342l7T4F8lR4oCfhXn7d6M5QPgXvjtc/gAcw==} + '@expo/config-plugins@55.0.6': + resolution: {integrity: sha512-cIox6FjZlFaaX40rbQ3DvP9e87S5X85H9uw+BAxJE5timkMhuByy3GAlOsj1h96EyzSiol7Q6YIGgY1Jiz4M+A==} + '@expo/config-types@53.0.5': resolution: {integrity: sha512-kqZ0w44E+HEGBjy+Lpyn0BVL5UANg/tmNixxaRMLS6nf37YsDrLk2VMAmeKMMk5CKG0NmOdVv3ngeUjRQMsy9g==} + '@expo/config-types@55.0.5': + resolution: {integrity: sha512-sCmSUZG4mZ/ySXvfyyBdhjivz8Q539X1NondwDdYG7s3SBsk+wsgPJzYsqgAG/P9+l0xWjUD2F+kQ1cAJ6NNLg==} + '@expo/config@11.0.13': resolution: {integrity: sha512-TnGb4u/zUZetpav9sx/3fWK71oCPaOjZHoVED9NaEncktAd0Eonhq5NUghiJmkUGt3gGSjRAEBXiBbbY9/B1LA==} + '@expo/config@55.0.8': + resolution: {integrity: sha512-D7RYYHfErCgEllGxNwdYdkgzLna7zkzUECBV3snbUpf7RvIpB5l1LpCgzuVoc5KVew5h7N1Tn4LnT/tBSUZsQg==} + '@expo/devcert@1.2.1': resolution: {integrity: sha512-qC4eaxmKMTmJC2ahwyui6ud8f3W60Ss7pMkpBq40Hu3zyiAaugPXnZ24145U7K36qO9UHdZUVxsCvIpz2RYYCA==} + '@expo/devtools@55.0.2': + resolution: {integrity: sha512-4VsFn9MUriocyuhyA+ycJP3TJhUsOFHDc270l9h3LhNpXMf6wvIdGcA0QzXkZtORXmlDybWXRP2KT1k36HcQkA==} + peerDependencies: + react: '*' + react-native: '*' + peerDependenciesMeta: + react: + optional: true + react-native: + optional: true + + '@expo/dom-webview@55.0.3': + resolution: {integrity: sha512-bY4/rfcZ0f43DvOtMn8/kmPlmo01tex5hRoc5hKbwBwQjqWQuQt0ACwu7akR9IHI4j0WNG48eL6cZB6dZUFrzg==} + peerDependencies: + expo: '*' + react: '*' + react-native: '*' + '@expo/env@1.0.7': resolution: {integrity: sha512-qSTEnwvuYJ3umapO9XJtrb1fAqiPlmUUg78N0IZXXGwQRt+bkp0OBls+Y5Mxw/Owj8waAM0Z3huKKskRADR5ow==} + '@expo/env@2.1.1': + resolution: {integrity: sha512-rVvHC4I6xlPcg+mAO09ydUi2Wjv1ZytpLmHOSzvXzBAz9mMrJggqCe4s4dubjJvi/Ino/xQCLhbaLCnTtLpikg==} + engines: {node: '>=20.12.0'} + '@expo/fingerprint@0.13.4': resolution: {integrity: sha512-MYfPYBTMfrrNr07DALuLhG6EaLVNVrY/PXjEzsjWdWE4ZFn0yqI0IdHNkJG7t1gePT8iztHc7qnsx+oo/rDo6w==} hasBin: true + '@expo/fingerprint@0.16.6': + resolution: {integrity: sha512-nRITNbnu3RKSHPvKVehrSU4KG2VY9V8nvULOHBw98ukHCAU4bGrU5APvcblOkX3JAap+xEHsg/mZvqlvkLInmQ==} + hasBin: true + '@expo/image-utils@0.7.6': resolution: {integrity: sha512-GKnMqC79+mo/1AFrmAcUcGfbsXXTRqOMNS1umebuevl3aaw+ztsYEFEiuNhHZW7PQ3Xs3URNT513ZxKhznDscw==} + '@expo/image-utils@0.8.12': + resolution: {integrity: sha512-3KguH7kyKqq7pNwLb9j6BBdD/bjmNwXZG/HPWT6GWIXbwrvAJt2JNyYTP5agWJ8jbbuys1yuCzmkX+TU6rmI7A==} + + '@expo/json-file@10.0.12': + resolution: {integrity: sha512-inbDycp1rMAelAofg7h/mMzIe+Owx6F7pur3XdQ3EPTy00tme+4P6FWgHKUcjN8dBSrnbRNpSyh5/shzHyVCyQ==} + '@expo/json-file@10.0.8': resolution: {integrity: sha512-9LOTh1PgKizD1VXfGQ88LtDH0lRwq9lsTb4aichWTWSWqy3Ugfkhfm3BhzBIkJJfQQ5iJu3m/BoRlEIjoCGcnQ==} '@expo/json-file@9.1.5': resolution: {integrity: sha512-prWBhLUlmcQtvN6Y7BpW2k9zXGd3ySa3R6rAguMJkp1z22nunLN64KYTUWfijFlprFoxm9r2VNnGkcbndAlgKA==} + '@expo/local-build-cache-provider@55.0.6': + resolution: {integrity: sha512-4kfdv48sKzokijMqi07fINYA9/XprshmPgSLf8i69XgzIv2YdRyBbb70SzrufB7PDneFoltz8N83icW8gOOj1g==} + + '@expo/log-box@55.0.7': + resolution: {integrity: sha512-m7V1k2vlMp4NOj3fopjOg4zl/ANXyTRF3HMTMep2GZAKsPiDzgOQ41nm8CaU50/HlDIGXlCObss07gOn20UpHQ==} + peerDependencies: + '@expo/dom-webview': ^55.0.3 + expo: '*' + react: '*' + react-native: '*' + '@expo/metro-config@0.20.18': resolution: {integrity: sha512-qPYq3Cq61KQO1CppqtmxA1NGKpzFOmdiL7WxwLhEVnz73LPSgneW7dV/3RZwVFkjThzjA41qB4a9pxDqtpepPg==} + '@expo/metro-config@55.0.9': + resolution: {integrity: sha512-ZJFEfat/+dLUhFyFFWrzMjAqAwwUaJ3RD42QNqR7jh+RVYkAf6XYLynb5qrKJTHI1EcOx4KoO1717yXYYRFDBA==} + peerDependencies: + expo: '*' + peerDependenciesMeta: + expo: + optional: true + '@expo/metro-runtime@5.0.5': resolution: {integrity: sha512-P8UFTi+YsmiD1BmdTdiIQITzDMcZgronsA3RTQ4QKJjHM3bas11oGzLQOnFaIZnlEV8Rrr3m1m+RHxvnpL+t/A==} peerDependencies: react-native: '*' + '@expo/metro@54.2.0': + resolution: {integrity: sha512-h68TNZPGsk6swMmLm9nRSnE2UXm48rWwgcbtAHVMikXvbxdS41NDHHeqg1rcQ9AbznDRp6SQVC2MVpDnsRKU1w==} + '@expo/osascript@2.3.8': resolution: {integrity: sha512-/TuOZvSG7Nn0I8c+FcEaoHeBO07yu6vwDgk7rZVvAXoeAK5rkA09jRyjYsZo+0tMEFaToBeywA6pj50Mb3ny9w==} engines: {node: '>=12'} + '@expo/osascript@2.4.2': + resolution: {integrity: sha512-/XP7PSYF2hzOZzqfjgkoWtllyeTN8dW3aM4P6YgKcmmPikKL5FdoyQhti4eh6RK5a5VrUXJTOlTNIpIHsfB5Iw==} + engines: {node: '>=12'} + + '@expo/package-manager@1.10.3': + resolution: {integrity: sha512-ZuXiK/9fCrIuLjPSe1VYmfp0Sa85kCMwd8QQpgyi5ufppYKRtLBg14QOgUqj8ZMbJTxE0xqzd0XR7kOs3vAK9A==} + '@expo/package-manager@1.9.10': resolution: {integrity: sha512-axJm+NOj3jVxep49va/+L3KkF3YW/dkV+RwzqUJedZrv4LeTqOG4rhrCaCPXHTvLqCTDKu6j0Xyd28N7mnxsGA==} '@expo/plist@0.3.5': resolution: {integrity: sha512-9RYVU1iGyCJ7vWfg3e7c/NVyMFs8wbl+dMWZphtFtsqyN9zppGREU3ctlD3i8KUE0sCUTVnLjCWr+VeUIDep2g==} + '@expo/plist@0.5.2': + resolution: {integrity: sha512-o4xdVdBpe4aTl3sPMZ2u3fJH4iG1I768EIRk1xRZP+GaFI93MaR3JvoFibYqxeTmLQ1p1kNEVqylfUjezxx45g==} + + '@expo/prebuild-config@55.0.8': + resolution: {integrity: sha512-VJNJiOmmZgyDnR7JMmc3B8Z0ZepZ17I8Wtw+wAH/2+UCUsFg588XU+bwgYcFGw+is28kwGjY46z43kfufpxOnA==} + peerDependencies: + expo: '*' + '@expo/prebuild-config@9.0.12': resolution: {integrity: sha512-AKH5Scf+gEMgGxZZaimrJI2wlUJlRoqzDNn7/rkhZa5gUTnO4l6slKak2YdaH+nXlOWCNfAQWa76NnpQIfmv6Q==} + '@expo/require-utils@55.0.2': + resolution: {integrity: sha512-dV5oCShQ1umKBKagMMT4B/N+SREsQe3lU4Zgmko5AO0rxKV0tynZT6xXs+e2JxuqT4Rz997atg7pki0BnZb4uw==} + peerDependencies: + typescript: ^5.0.0 || ^5.0.0-0 + peerDependenciesMeta: + typescript: + optional: true + + '@expo/router-server@55.0.10': + resolution: {integrity: sha512-NZQzHwkaedufNPayVfPxsZGEMngOD3gDvYx9lld4sitRexrKDx5sHmmNHi6IByGbmCb4jwLXub5sIyWh6z1xPQ==} + peerDependencies: + '@expo/metro-runtime': ^55.0.6 + expo: '*' + expo-constants: ^55.0.7 + expo-font: ^55.0.4 + expo-router: '*' + expo-server: ^55.0.6 + react: '*' + react-dom: '*' + react-server-dom-webpack: ~19.0.1 || ~19.1.2 || ~19.2.1 + peerDependenciesMeta: + '@expo/metro-runtime': + optional: true + expo-router: + optional: true + react-dom: + optional: true + react-server-dom-webpack: + optional: true + '@expo/schema-utils@0.1.8': resolution: {integrity: sha512-9I6ZqvnAvKKDiO+ZF8BpQQFYWXOJvTAL5L/227RUbWG1OVZDInFifzCBiqAZ3b67NRfeAgpgvbA7rejsqhY62A==} + '@expo/schema-utils@55.0.2': + resolution: {integrity: sha512-QZ5WKbJOWkCrMq0/kfhV9ry8te/OaS34YgLVpG8u9y2gix96TlpRTbxM/YATjNcUR2s4fiQmPCOxkGtog4i37g==} + '@expo/sdk-runtime-versions@1.0.0': resolution: {integrity: sha512-Doz2bfiPndXYFPMRwPyGa1k5QaKDVpY806UJj570epIiMzWaYyCtobasyfC++qfIXVb5Ocy7r3tP9d62hAQ7IQ==} @@ -2817,6 +2990,13 @@ packages: react: '*' react-native: '*' + '@expo/vector-icons@15.1.1': + resolution: {integrity: sha512-Iu2VkcoI5vygbtYngm7jb4ifxElNVXQYdDrYkT7UCEIiKLeWnQY0wf2ZhHZ+Wro6Sc5TaumpKUOqDRpLi5rkvw==} + peerDependencies: + expo-font: '>=14.0.4' + react: '*' + react-native: '*' + '@expo/ws-tunnel@1.0.6': resolution: {integrity: sha512-nDRbLmSrJar7abvUjp3smDwH8HcbZcoOEa5jVPUv9/9CajgmWw20JNRwTuBRzWIWIkEJDkz20GoNA+tSwUqk0Q==} @@ -3863,22 +4043,42 @@ packages: resolution: {integrity: sha512-UVSP1224PWg0X+mRlZNftV5xQwZGfawhivuW8fGgxNK9MS/U84xZ+16lkqcPh1ank6MOt239lIWHQ1S33CHgqA==} engines: {node: '>=18'} + '@react-native/assets-registry@0.83.2': + resolution: {integrity: sha512-9I5l3pGAKnlpQ15uVkeB9Mgjvt3cZEaEc8EDtdexvdtZvLSjtwBzgourrOW4yZUijbjJr8h3YO2Y0q+THwUHTA==} + engines: {node: '>= 20.19.4'} + '@react-native/babel-plugin-codegen@0.79.6': resolution: {integrity: sha512-CS5OrgcMPixOyUJ/Sk/HSsKsKgyKT5P7y3CojimOQzWqRZBmoQfxdST4ugj7n1H+ebM2IKqbgovApFbqXsoX0g==} engines: {node: '>=18'} + '@react-native/babel-plugin-codegen@0.83.2': + resolution: {integrity: sha512-XbcN/BEa64pVlb0Hb/E/Ph2SepjVN/FcNKrJcQvtaKZA6mBSO8pW8Eircdlr61/KBH94LihHbQoQDzkQFpeaTg==} + engines: {node: '>= 20.19.4'} + '@react-native/babel-preset@0.79.6': resolution: {integrity: sha512-H+FRO+r2Ql6b5IwfE0E7D52JhkxjeGSBSUpCXAI5zQ60zSBJ54Hwh2bBJOohXWl4J+C7gKYSAd2JHMUETu+c/A==} engines: {node: '>=18'} peerDependencies: '@babel/core': '*' + '@react-native/babel-preset@0.83.2': + resolution: {integrity: sha512-X/RAXDfe6W+om/Fw1i6htTxQXFhBJ2jgNOWx3WpI3KbjeIWbq7ib6vrpTeIAW2NUMg+K3mML1NzgD4dpZeqdjA==} + engines: {node: '>= 20.19.4'} + peerDependencies: + '@babel/core': '*' + '@react-native/codegen@0.79.6': resolution: {integrity: sha512-iRBX8Lgbqypwnfba7s6opeUwVyaR23mowh9ILw7EcT2oLz3RqMmjJdrbVpWhGSMGq2qkPfqAH7bhO8C7O+xfjQ==} engines: {node: '>=18'} peerDependencies: '@babel/core': '*' + '@react-native/codegen@0.83.2': + resolution: {integrity: sha512-9uK6X1miCXqtL4c759l74N/XbQeneWeQVjoV7SD2CGJuW7ZefxaoYenwGPs7rMoCdtS6wuIyR3hXQ+uWEBGYXA==} + engines: {node: '>= 20.19.4'} + peerDependencies: + '@babel/core': '*' + '@react-native/community-cli-plugin@0.79.6': resolution: {integrity: sha512-ZHVst9vByGsegeaddkD2YbZ6NvYb4n3pD9H7Pit94u+NlByq2uBJghoOjT6EKqg+UVl8tLRdi88cU2pDPwdHqA==} engines: {node: '>=18'} @@ -3888,25 +4088,60 @@ packages: '@react-native-community/cli': optional: true + '@react-native/community-cli-plugin@0.83.2': + resolution: {integrity: sha512-sTEF0eiUKtmImEP07Qo5c3Khvm1LIVX1Qyb6zWUqPL6W3MqFiXutZvKBjqLz6p49Szx8cplQLoXfLHT0bcDXKg==} + engines: {node: '>= 20.19.4'} + peerDependencies: + '@react-native-community/cli': '*' + '@react-native/metro-config': '*' + peerDependenciesMeta: + '@react-native-community/cli': + optional: true + '@react-native/metro-config': + optional: true + '@react-native/debugger-frontend@0.79.6': resolution: {integrity: sha512-lIK/KkaH7ueM22bLO0YNaQwZbT/oeqhaghOvmZacaNVbJR1Cdh/XAqjT8FgCS+7PUnbxA8B55NYNKGZG3O2pYw==} engines: {node: '>=18'} + '@react-native/debugger-frontend@0.83.2': + resolution: {integrity: sha512-t4fYfa7xopbUF5S4+ihNEwgaq4wLZLKLY0Ms8z72lkMteVd3bOX2Foxa8E2wTfRvdhPOkSpOsTeNDmD8ON4DoQ==} + engines: {node: '>= 20.19.4'} + + '@react-native/debugger-shell@0.83.2': + resolution: {integrity: sha512-z9go6NJMsLSDJT5MW6VGugRsZHjYvUTwxtsVc3uLt4U9W6T3J6FWI2wHpXIzd2dUkXRfAiRQ3Zi8ZQQ8fRFg9A==} + engines: {node: '>= 20.19.4'} + '@react-native/dev-middleware@0.79.6': resolution: {integrity: sha512-BK3GZBa9c7XSNR27EDRtxrgyyA3/mf1j3/y+mPk7Ac0Myu85YNrXnC9g3mL5Ytwo0g58TKrAIgs1fF2Q5Mn6mQ==} engines: {node: '>=18'} + '@react-native/dev-middleware@0.83.2': + resolution: {integrity: sha512-Zi4EVaAm28+icD19NN07Gh8Pqg/84QQu+jn4patfWKNkcToRFP5vPEbbp0eLOGWS+BVB1d1Fn5lvMrJsBbFcOg==} + engines: {node: '>= 20.19.4'} + '@react-native/gradle-plugin@0.79.6': resolution: {integrity: sha512-C5odetI6py3CSELeZEVz+i00M+OJuFZXYnjVD4JyvpLn462GesHRh+Se8mSkU5QSaz9cnpMnyFLJAx05dokWbA==} engines: {node: '>=18'} + '@react-native/gradle-plugin@0.83.2': + resolution: {integrity: sha512-PqN11fXRAU+uJ0inZY1HWYlwJOXHOhF4SPyeHBBxjajKpm2PGunmvFWwkmBjmmUkP/CNO0ezTUudV0oj+2wiHQ==} + engines: {node: '>= 20.19.4'} + '@react-native/js-polyfills@0.79.6': resolution: {integrity: sha512-6wOaBh1namYj9JlCNgX2ILeGUIwc6OP6MWe3Y5jge7Xz9fVpRqWQk88Q5Y9VrAtTMTcxoX3CvhrfRr3tGtSfQw==} engines: {node: '>=18'} + '@react-native/js-polyfills@0.83.2': + resolution: {integrity: sha512-dk6fIY2OrKW/2Nk2HydfYNrQau8g6LOtd7NVBrgaqa+lvuRyIML5iimShP5qPqQnx2ofHuzjFw+Ya0b5Q7nDbA==} + engines: {node: '>= 20.19.4'} + '@react-native/normalize-colors@0.79.6': resolution: {integrity: sha512-0v2/ruY7eeKun4BeKu+GcfO+SHBdl0LJn4ZFzTzjHdWES0Cn+ONqKljYaIv8p9MV2Hx/kcdEvbY4lWI34jC/mQ==} + '@react-native/normalize-colors@0.83.2': + resolution: {integrity: sha512-gkZAb9LoVVzNuYzzOviH7DiPTXQoZPHuiTH2+O2+VWNtOkiznjgvqpwYAhg58a5zfRq5GXlbBdf5mzRj5+3Y5Q==} + '@react-native/virtualized-lists@0.79.6': resolution: {integrity: sha512-khA/Hrbb+rB68YUHrLubfLgMOD9up0glJhw25UE3Kntj32YDyuO0Tqc81ryNTcCekFKJ8XrAaEjcfPg81zBGPw==} engines: {node: '>=18'} @@ -3918,6 +4153,17 @@ packages: '@types/react': optional: true + '@react-native/virtualized-lists@0.83.2': + resolution: {integrity: sha512-N7mRjHLW/+KWxMp9IHRWyE3VIkeG1m3PnZJAGEFLCN8VFb7e4VfI567o7tE/HYcdcXCylw+Eqhlciz8gDeQ71g==} + engines: {node: '>= 20.19.4'} + peerDependencies: + '@types/react': ^19.2.0 + react: '*' + react-native: '*' + peerDependenciesMeta: + '@types/react': + optional: true + '@react-navigation/bottom-tabs@7.9.1': resolution: {integrity: sha512-1MHn1b5tWFa8t8LXUvaNtlg5WGVXcNTsiV00ygQDBFDusMcu0ZPOU1exqELZwHf6kDntmTQE96/NRM+Cd2QR+A==} peerDependencies: @@ -4887,6 +5133,9 @@ packages: '@ungap/raw-json@0.4.4': resolution: {integrity: sha512-mUDobz3DeEItDmI34Hg+eL9hTTJSZbIvsvGAr42YoK4IyS7SWKmF5Xa0pI8RWFZSijL8QmfvCNH3s8HYJNxKaw==} + '@ungap/structured-clone@1.3.0': + resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} + '@unrs/resolver-binding-android-arm-eabi@1.11.1': resolution: {integrity: sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==} cpu: [arm] @@ -5319,6 +5568,9 @@ packages: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} + await-lock@2.2.2: + resolution: {integrity: sha512-aDczADvlvTGajTDjcjpJMqRkOF6Qdz3YbPZm/PyW6tKPkx2hlYBzxMhEywM/tU72HrVZjgl5VCdRuMlA7pZ8Gw==} + axobject-query@4.1.0: resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} engines: {node: '>= 0.4'} @@ -5360,12 +5612,24 @@ packages: peerDependencies: '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + babel-plugin-react-compiler@1.0.0: + resolution: {integrity: sha512-Ixm8tFfoKKIPYdCCKYTsqv+Fd4IJ0DQqMyEimo+pxUOMUR9cVPlwTrFt9Avu+3cb6Zp3mAzl+t1MrG2fxxKsxw==} + babel-plugin-react-native-web@0.19.13: resolution: {integrity: sha512-4hHoto6xaN23LCyZgL9LJZc3olmAxd7b6jDzlZnKXAh4rRAbZRKNBJoOOdp46OBqgy+K0t0guTj5/mhA8inymQ==} + babel-plugin-react-native-web@0.21.2: + resolution: {integrity: sha512-SPD0J6qjJn8231i0HZhlAGH6NORe+QvRSQM2mwQEzJ2Fb3E4ruWTiiicPlHjmeWShDXLcvoorOCXjeR7k/lyWA==} + babel-plugin-syntax-hermes-parser@0.25.1: resolution: {integrity: sha512-IVNpGzboFLfXZUAwkLFcI/bnqVbwky0jP3eBno4HKtqvQJAHBLdgxiG6lQ4to0+Q/YCN3PO0od5NZwIKyY4REQ==} + babel-plugin-syntax-hermes-parser@0.32.0: + resolution: {integrity: sha512-m5HthL++AbyeEA2FcdwOLfVFvWYECOBObLHNqdR8ceY4TsEdn4LdX2oTvbB2QJSSElE2AWA/b2MXZ/PF/CqLZg==} + + babel-plugin-syntax-hermes-parser@0.32.1: + resolution: {integrity: sha512-HgErPZTghW76Rkq9uqn5ESeiD97FbqpZ1V170T1RG2RDp+7pJVQV2pQJs7y5YzN0/gcT6GM5ci9apRnIwuyPdQ==} + babel-plugin-transform-flow-enums@0.0.2: resolution: {integrity: sha512-g4aaCrDDOsWjbm0PUUeVnkcVd6AKJsVc/MbnPhEotEpkeJQP6b8nzewohQi7+QS8UyPehOhGWn0nOwjvWpmMvQ==} @@ -5382,6 +5646,21 @@ packages: babel-plugin-react-compiler: optional: true + babel-preset-expo@55.0.11: + resolution: {integrity: sha512-ti8t4xufD6gUQQh+qY+b+VT/1zyA0n1PBnwOzCkPUyEDiIVBpaOixR+BzVH68hqu9mH2wDfzoFuGgv+2LfRdqw==} + peerDependencies: + '@babel/runtime': ^7.20.0 + expo: '*' + expo-widgets: ^55.0.4 + react-refresh: '>=0.14.0 <1.0.0' + peerDependenciesMeta: + '@babel/runtime': + optional: true + expo: + optional: true + expo-widgets: + optional: true + babel-preset-jest@29.6.3: resolution: {integrity: sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -6079,6 +6358,9 @@ packages: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} + dnssd-advertise@1.1.3: + resolution: {integrity: sha512-XENsHi3MBzWOCAXif3yZvU1Ah0l+nhJj1sjWL6TnOAYKvGiFhbTx32xHN7+wLMLUOCj7Nr0evADWG4R8JtqCDA==} + doctrine@2.1.0: resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} engines: {node: '>=0.10.0'} @@ -6620,30 +6902,62 @@ packages: react: '*' react-native: '*' + expo-asset@55.0.8: + resolution: {integrity: sha512-yEz2svDX67R0yiW2skx6dJmcE0q7sj9ECpGMcxBExMCbctc+nMoZCnjUuhzPl5vhClUsO5HFFXS5vIGmf1bgHQ==} + peerDependencies: + expo: '*' + react: '*' + react-native: '*' + expo-constants@17.1.8: resolution: {integrity: sha512-sOCeMN/BWLA7hBP6lMwoEQzFNgTopk6YY03sBAmwT216IHyL54TjNseg8CRU1IQQ/+qinJ2fYWCl7blx2TiNcA==} peerDependencies: expo: '*' react-native: '*' + expo-constants@55.0.7: + resolution: {integrity: sha512-kdcO4TsQRRqt0USvjaY5vgQMO9H52K3kBZ/ejC7F6rz70mv08GoowrZ1CYOr5O4JpPDRlIpQfZJUucaS/c+KWQ==} + peerDependencies: + expo: '*' + react-native: '*' + expo-file-system@18.1.11: resolution: {integrity: sha512-HJw/m0nVOKeqeRjPjGdvm+zBi5/NxcdPf8M8P3G2JFvH5Z8vBWqVDic2O58jnT1OFEy0XXzoH9UqFu7cHg9DTQ==} peerDependencies: expo: '*' react-native: '*' + expo-file-system@55.0.10: + resolution: {integrity: sha512-ysFdVdUgtfj2ApY0Cn+pBg+yK4xp+SNwcaH8j2B91JJQ4OXJmnyCSmrNZYz7J4mdYVuv2GzxIP+N/IGlHQG3Yw==} + peerDependencies: + expo: '*' + react-native: '*' + expo-font@13.3.2: resolution: {integrity: sha512-wUlMdpqURmQ/CNKK/+BIHkDA5nGjMqNlYmW0pJFXY/KE/OG80Qcavdu2sHsL4efAIiNGvYdBS10WztuQYU4X0A==} peerDependencies: expo: '*' react: '*' + expo-font@55.0.4: + resolution: {integrity: sha512-ZKeGTFffPygvY5dM/9ATM2p7QDkhsaHopH7wFAWgP2lKzqUMS9B/RxCvw5CaObr9Ro7x9YptyeRKX2HmgmMfrg==} + peerDependencies: + expo: '*' + react: '*' + react-native: '*' + expo-keep-awake@14.1.4: resolution: {integrity: sha512-wU9qOnosy4+U4z/o4h8W9PjPvcFMfZXrlUoKTMBW7F4pLqhkkP/5G4EviPZixv4XWFMjn1ExQ5rV6BX8GwJsWA==} peerDependencies: expo: '*' react: '*' + expo-keep-awake@55.0.4: + resolution: {integrity: sha512-vwfdMtMS5Fxaon8gC0AiE70SpxTsHJ+rjeoVJl8kdfdbxczF7OIaVmfjFJ5Gfigd/WZiLqxhfZk34VAkXF4PNg==} + peerDependencies: + expo: '*' + react: '*' + expo-linking@7.1.7: resolution: {integrity: sha512-ZJaH1RIch2G/M3hx2QJdlrKbYFUTOjVVW4g39hfxrE5bPX9xhZUYXqxqQtzMNl1ylAevw9JkgEfWbBWddbZ3UA==} peerDependencies: @@ -6654,9 +6968,19 @@ packages: resolution: {integrity: sha512-IUITUERdkgooXjr9bXsX0PmhrZUIGTMyP6NtmQpAxN5+qtf/I7ewbwLx1/rX7tgiAOzaYme+PZOp/o6yqIhFsw==} hasBin: true + expo-modules-autolinking@55.0.9: + resolution: {integrity: sha512-OXIrxSYKlT/1Av1AMyUWeSTW1GChGofWV14sB73o5eFbfuz6ocv18fnKx+Ji67ZC7a0RztDctcZTuEQK84S4iw==} + hasBin: true + expo-modules-core@2.5.0: resolution: {integrity: sha512-aIbQxZE2vdCKsolQUl6Q9Farlf8tjh/ROR4hfN1qT7QBGPl1XrJGnaOKkcgYaGrlzCPg/7IBe0Np67GzKMZKKQ==} + expo-modules-core@55.0.15: + resolution: {integrity: sha512-MAGz1SYSVgQbwVeUysWgPtLh8ozbBwORatXoA4w0NZqZBZzEyBgUQNhuwaroaIi9W8Ir3wy1McmZcDYDJNGmVw==} + peerDependencies: + react: '*' + react-native: '*' + expo-router@5.1.11: resolution: {integrity: sha512-6YQGqQM2rviVSiU6++hrJDPMByHZ7Oiux4XmgoSaGdaHku5QOn9911f2puEUZh2H9ALKBipw5v3ZkrECBd6Zbw==} peerDependencies: @@ -6679,6 +7003,17 @@ packages: react-server-dom-webpack: optional: true + expo-server@55.0.6: + resolution: {integrity: sha512-xI72FTm469FfuuBL2R5aNtthgH+GR7ygOpsx/KcPS0K8AZaZd7VjtEExbzn9/qyyYkWW3T+3dAmCDKOMX8gdmQ==} + engines: {node: '>=20.16.0'} + + expo-sqlite@55.0.10: + resolution: {integrity: sha512-yLQXkwcA0OVSKuL4t+a6vv+H/Klh8147n7hH75AN0MkC48p3Go7+6GM+3SFENeaBUsmOnOS3XSFxMxxj6PIg4g==} + peerDependencies: + expo: '*' + react: '*' + react-native: '*' + expo-status-bar@2.2.3: resolution: {integrity: sha512-+c8R3AESBoduunxTJ8353SqKAKpxL6DvcD8VKBuh81zzJyUUbfB4CVjr1GufSJEKsMzNPXZU+HJwXx7Xh7lx8Q==} peerDependencies: @@ -6702,6 +7037,23 @@ packages: react-native-webview: optional: true + expo@55.0.6: + resolution: {integrity: sha512-gaF8bh5beWmrptz3d4Gr138CiPoLJtzjNbqNSOQ8kdQm3wMW8lJGT1dsY5NPJTZ7MNJBTN+pcRwshr4BMK4OiA==} + hasBin: true + peerDependencies: + '@expo/dom-webview': '*' + '@expo/metro-runtime': '*' + react: '*' + react-native: '*' + react-native-webview: '*' + peerDependenciesMeta: + '@expo/dom-webview': + optional: true + '@expo/metro-runtime': + optional: true + react-native-webview: + optional: true + exponential-backoff@3.1.3: resolution: {integrity: sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==} @@ -6754,6 +7106,11 @@ packages: resolution: {integrity: sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==} engines: {node: '>=0.8.0'} + fb-dotslash@0.5.8: + resolution: {integrity: sha512-XHYLKk9J4BupDxi9bSEhkfss0m+Vr9ChTrjhf9l2iw3jB5C7BnY4GVPoMcqbrTutsKJso6yj2nAB6BI/F2oZaA==} + engines: {node: '>=20'} + hasBin: true + fb-watchman@2.0.2: resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} @@ -6769,6 +7126,9 @@ packages: picomatch: optional: true + fetch-nodeshim@0.4.9: + resolution: {integrity: sha512-XIQWlB2A4RZ7NebXWGxS0uDMdvRHkiUDTghBVJKFg9yEOd45w/PP8cZANuPf2H08W6Cor3+2n7Q6TTZgAS3Fkw==} + fflate@0.8.2: resolution: {integrity: sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==} @@ -7072,18 +7432,33 @@ packages: resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} hasBin: true + hermes-compiler@0.14.1: + resolution: {integrity: sha512-+RPPQlayoZ9n6/KXKt5SFILWXCGJ/LV5d24L5smXrvTDrPS4L6dSctPczXauuvzFP3QEJbD1YO7Z3Ra4a+4IhA==} + hermes-estree@0.25.1: resolution: {integrity: sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==} hermes-estree@0.29.1: resolution: {integrity: sha512-jl+x31n4/w+wEqm0I2r4CMimukLbLQEYpisys5oCre611CI5fc9TxhqkBBCJ1edDG4Kza0f7CgNz8xVMLZQOmQ==} + hermes-estree@0.32.0: + resolution: {integrity: sha512-KWn3BqnlDOl97Xe1Yviur6NbgIZ+IP+UVSpshlZWkq+EtoHg6/cwiDj/osP9PCEgFE15KBm1O55JRwbMEm5ejQ==} + + hermes-estree@0.32.1: + resolution: {integrity: sha512-ne5hkuDxheNBAikDjqvCZCwihnz0vVu9YsBzAEO1puiyFR4F1+PAz/SiPHSsNTuOveCYGRMX8Xbx4LOubeC0Qg==} + hermes-parser@0.25.1: resolution: {integrity: sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==} hermes-parser@0.29.1: resolution: {integrity: sha512-xBHWmUtRC5e/UL0tI7Ivt2riA/YBq9+SiYFU7C1oBa/j2jYGlIF9043oak1F47ihuDIxQ5nbsKueYJDRY02UgA==} + hermes-parser@0.32.0: + resolution: {integrity: sha512-g4nBOWFpuiTqjR3LZdRxKUkij9iyveWeuks7INEsMX741f3r9xxrOe8TeQfUxtda0eXmiIFiMQzoeSQEno33Hw==} + + hermes-parser@0.32.1: + resolution: {integrity: sha512-175dz634X/W5AiwrpLdoMl/MOb17poLHyIqgyExlE8D9zQ1OPnoORnGMB5ltRKnpvQzBjMYvT2rN/sHeIfZW5Q==} + hono@4.11.9: resolution: {integrity: sha512-Eaw2YTGM6WOxA6CXbckaEvslr2Ne4NFsKrvc0v97JD5awbmeBLO5w9Ho9L9kmKonrwF9RJlW6BxT1PVv/agBHQ==} engines: {node: '>=16.9.0'} @@ -7732,6 +8107,10 @@ packages: resolution: {integrity: sha512-mnIlAEMu4OyEvUNdzco9xpuB9YVcPkQec+QsgycBCtPZvEqWPCDPfbAE4OJMdBBWpZWtpCn1xw9jJYlwjWI5zQ==} hasBin: true + lan-network@0.2.0: + resolution: {integrity: sha512-EZgbsXMrGS+oK+Ta12mCjzBFse+SIewGdwrSTr5g+MSymnjpox2x05ceI20PQejJOFvOgzcXrfDk/SdY7dSCtw==} + hasBin: true + leven@3.1.0: resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} engines: {node: '>=6'} @@ -8081,55 +8460,137 @@ packages: resolution: {integrity: sha512-W/scFDnwJXSccJYnOFdGiYr9srhbHPdxX9TvvACOFsIXdLilh3XuxQl/wXW6jEJfgIb0jTvoTlwwrqvuwymr6Q==} engines: {node: '>=18.18'} + metro-babel-transformer@0.83.3: + resolution: {integrity: sha512-1vxlvj2yY24ES1O5RsSIvg4a4WeL7PFXgKOHvXTXiW0deLvQr28ExXj6LjwCCDZ4YZLhq6HddLpZnX4dEdSq5g==} + engines: {node: '>=20.19.4'} + metro-cache-key@0.82.5: resolution: {integrity: sha512-qpVmPbDJuRLrT4kcGlUouyqLGssJnbTllVtvIgXfR7ZuzMKf0mGS+8WzcqzNK8+kCyakombQWR0uDd8qhWGJcA==} engines: {node: '>=18.18'} + metro-cache-key@0.83.3: + resolution: {integrity: sha512-59ZO049jKzSmvBmG/B5bZ6/dztP0ilp0o988nc6dpaDsU05Cl1c/lRf+yx8m9WW/JVgbmfO5MziBU559XjI5Zw==} + engines: {node: '>=20.19.4'} + metro-cache@0.82.5: resolution: {integrity: sha512-AwHV9607xZpedu1NQcjUkua8v7HfOTKfftl6Vc9OGr/jbpiJX6Gpy8E/V9jo/U9UuVYX2PqSUcVNZmu+LTm71Q==} engines: {node: '>=18.18'} + metro-cache@0.83.3: + resolution: {integrity: sha512-3jo65X515mQJvKqK3vWRblxDEcgY55Sk3w4xa6LlfEXgQ9g1WgMh9m4qVZVwgcHoLy0a2HENTPCCX4Pk6s8c8Q==} + engines: {node: '>=20.19.4'} + + metro-cache@0.83.5: + resolution: {integrity: sha512-oH+s4U+IfZyg8J42bne2Skc90rcuESIYf86dYittcdWQtPfcaFXWpByPyTuWk3rR1Zz3Eh5HOrcVImfEhhJLng==} + engines: {node: '>=20.19.4'} + metro-config@0.82.5: resolution: {integrity: sha512-/r83VqE55l0WsBf8IhNmc/3z71y2zIPe5kRSuqA5tY/SL/ULzlHUJEMd1szztd0G45JozLwjvrhAzhDPJ/Qo/g==} engines: {node: '>=18.18'} + metro-config@0.83.3: + resolution: {integrity: sha512-mTel7ipT0yNjKILIan04bkJkuCzUUkm2SeEaTads8VfEecCh+ltXchdq6DovXJqzQAXuR2P9cxZB47Lg4klriA==} + engines: {node: '>=20.19.4'} + + metro-config@0.83.5: + resolution: {integrity: sha512-JQ/PAASXH7yczgV6OCUSRhZYME+NU8NYjI2RcaG5ga4QfQ3T/XdiLzpSb3awWZYlDCcQb36l4Vl7i0Zw7/Tf9w==} + engines: {node: '>=20.19.4'} + metro-core@0.82.5: resolution: {integrity: sha512-OJL18VbSw2RgtBm1f2P3J5kb892LCVJqMvslXxuxjAPex8OH7Eb8RBfgEo7VZSjgb/LOf4jhC4UFk5l5tAOHHA==} engines: {node: '>=18.18'} + metro-core@0.83.3: + resolution: {integrity: sha512-M+X59lm7oBmJZamc96usuF1kusd5YimqG/q97g4Ac7slnJ3YiGglW5CsOlicTR5EWf8MQFxxjDoB6ytTqRe8Hw==} + engines: {node: '>=20.19.4'} + + metro-core@0.83.5: + resolution: {integrity: sha512-YcVcLCrf0ed4mdLa82Qob0VxYqfhmlRxUS8+TO4gosZo/gLwSvtdeOjc/Vt0pe/lvMNrBap9LlmvZM8FIsMgJQ==} + engines: {node: '>=20.19.4'} + metro-file-map@0.82.5: resolution: {integrity: sha512-vpMDxkGIB+MTN8Af5hvSAanc6zXQipsAUO+XUx3PCQieKUfLwdoa8qaZ1WAQYRpaU+CJ8vhBcxtzzo3d9IsCIQ==} engines: {node: '>=18.18'} + metro-file-map@0.83.3: + resolution: {integrity: sha512-jg5AcyE0Q9Xbbu/4NAwwZkmQn7doJCKGW0SLeSJmzNB9Z24jBe0AL2PHNMy4eu0JiKtNWHz9IiONGZWq7hjVTA==} + engines: {node: '>=20.19.4'} + metro-minify-terser@0.82.5: resolution: {integrity: sha512-v6Nx7A4We6PqPu/ta1oGTqJ4Usz0P7c+3XNeBxW9kp8zayS3lHUKR0sY0wsCHInxZlNAEICx791x+uXytFUuwg==} engines: {node: '>=18.18'} + metro-minify-terser@0.83.3: + resolution: {integrity: sha512-O2BmfWj6FSfzBLrNCXt/rr2VYZdX5i6444QJU0fFoc7Ljg+Q+iqebwE3K0eTvkI6TRjELsXk1cjU+fXwAR4OjQ==} + engines: {node: '>=20.19.4'} + metro-resolver@0.82.5: resolution: {integrity: sha512-kFowLnWACt3bEsuVsaRNgwplT8U7kETnaFHaZePlARz4Fg8tZtmRDUmjaD68CGAwc0rwdwNCkWizLYpnyVcs2g==} engines: {node: '>=18.18'} + metro-resolver@0.83.3: + resolution: {integrity: sha512-0js+zwI5flFxb1ktmR///bxHYg7OLpRpWZlBBruYG8OKYxeMP7SV0xQ/o/hUelrEMdK4LJzqVtHAhBm25LVfAQ==} + engines: {node: '>=20.19.4'} + + metro-resolver@0.83.5: + resolution: {integrity: sha512-7p3GtzVUpbAweJeCcUJihJeOQl1bDuimO5ueo1K0BUpUtR41q5EilbQ3klt16UTPPMpA+tISWBtsrqU556mY1A==} + engines: {node: '>=20.19.4'} + metro-runtime@0.82.5: resolution: {integrity: sha512-rQZDoCUf7k4Broyw3Ixxlq5ieIPiR1ULONdpcYpbJQ6yQ5GGEyYjtkztGD+OhHlw81LCR2SUAoPvtTus2WDK5g==} engines: {node: '>=18.18'} + metro-runtime@0.83.3: + resolution: {integrity: sha512-JHCJb9ebr9rfJ+LcssFYA2x1qPYuSD/bbePupIGhpMrsla7RCwC/VL3yJ9cSU+nUhU4c9Ixxy8tBta+JbDeZWw==} + engines: {node: '>=20.19.4'} + + metro-runtime@0.83.5: + resolution: {integrity: sha512-f+b3ue9AWTVlZe2Xrki6TAoFtKIqw30jwfk7GQ1rDUBQaE0ZQ+NkiMEtb9uwH7uAjJ87U7Tdx1Jg1OJqUfEVlA==} + engines: {node: '>=20.19.4'} + metro-source-map@0.82.5: resolution: {integrity: sha512-wH+awTOQJVkbhn2SKyaw+0cd+RVSCZ3sHVgyqJFQXIee/yLs3dZqKjjeKKhhVeudgjXo7aE/vSu/zVfcQEcUfw==} engines: {node: '>=18.18'} + metro-source-map@0.83.3: + resolution: {integrity: sha512-xkC3qwUBh2psVZgVavo8+r2C9Igkk3DibiOXSAht1aYRRcztEZNFtAMtfSB7sdO2iFMx2Mlyu++cBxz/fhdzQg==} + engines: {node: '>=20.19.4'} + + metro-source-map@0.83.5: + resolution: {integrity: sha512-VT9bb2KO2/4tWY9Z2yeZqTUao7CicKAOps9LUg2aQzsz+04QyuXL3qgf1cLUVRjA/D6G5u1RJAlN1w9VNHtODQ==} + engines: {node: '>=20.19.4'} + metro-symbolicate@0.82.5: resolution: {integrity: sha512-1u+07gzrvYDJ/oNXuOG1EXSvXZka/0JSW1q2EYBWerVKMOhvv9JzDGyzmuV7hHbF2Hg3T3S2uiM36sLz1qKsiw==} engines: {node: '>=18.18'} hasBin: true + metro-symbolicate@0.83.3: + resolution: {integrity: sha512-F/YChgKd6KbFK3eUR5HdUsfBqVsanf5lNTwFd4Ca7uuxnHgBC3kR/Hba/RGkenR3pZaGNp5Bu9ZqqP52Wyhomw==} + engines: {node: '>=20.19.4'} + hasBin: true + + metro-symbolicate@0.83.5: + resolution: {integrity: sha512-EMIkrjNRz/hF+p0RDdxoE60+dkaTLPN3vaaGkFmX5lvFdO6HPfHA/Ywznzkev+za0VhPQ5KSdz49/MALBRteHA==} + engines: {node: '>=20.19.4'} + hasBin: true + metro-transform-plugins@0.82.5: resolution: {integrity: sha512-57Bqf3rgq9nPqLrT2d9kf/2WVieTFqsQ6qWHpEng5naIUtc/Iiw9+0bfLLWSAw0GH40iJ4yMjFcFJDtNSYynMA==} engines: {node: '>=18.18'} + metro-transform-plugins@0.83.3: + resolution: {integrity: sha512-eRGoKJU6jmqOakBMH5kUB7VitEWiNrDzBHpYbkBXW7C5fUGeOd2CyqrosEzbMK5VMiZYyOcNFEphvxk3OXey2A==} + engines: {node: '>=20.19.4'} + metro-transform-worker@0.82.5: resolution: {integrity: sha512-mx0grhAX7xe+XUQH6qoHHlWedI8fhSpDGsfga7CpkO9Lk9W+aPitNtJWNGrW8PfjKEWbT9Uz9O50dkI8bJqigw==} engines: {node: '>=18.18'} + metro-transform-worker@0.83.3: + resolution: {integrity: sha512-Ztekew9t/gOIMZX1tvJOgX7KlSLL5kWykl0Iwu2cL2vKMKVALRl1hysyhUw0vjpAvLFx+Kfq9VLjnHIkW32fPA==} + engines: {node: '>=20.19.4'} + metro@0.82.5: resolution: {integrity: sha512-8oAXxL7do8QckID/WZEKaIFuQJFUTLzfVcC48ghkHhNK2RGuQq8Xvf4AVd+TUA0SZtX0q8TGNXZ/eba1ckeGCg==} engines: {node: '>=18.18'} @@ -8309,6 +8770,9 @@ packages: muggle-string@0.4.1: resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==} + multitars@0.2.4: + resolution: {integrity: sha512-XgLbg1HHchFauMCQPRwMj6MSyDd5koPlTA1hM3rUFkeXzGpjU/I9fP3to7yrObE9jcN8ChIOQGrM0tV0kUZaKg==} + mute-stream@2.0.0: resolution: {integrity: sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==} engines: {node: ^18.17.0 || >=20.5.0} @@ -8462,6 +8926,14 @@ packages: resolution: {integrity: sha512-QyQQ6e66f+Ut/qUVjEce0E/wux5nAGLXYZDn1jr15JWstHsCH3l6VVrg8NKDptW9NEiBXKOJeGF/ydxeSDF3IQ==} engines: {node: '>=18.18'} + ob1@0.83.3: + resolution: {integrity: sha512-egUxXCDwoWG06NGCS5s5AdcpnumHKJlfd3HH06P3m9TEMwwScfcY35wpQxbm9oHof+dM/lVH9Rfyu1elTVelSA==} + engines: {node: '>=20.19.4'} + + ob1@0.83.5: + resolution: {integrity: sha512-vNKPYC8L5ycVANANpF/S+WZHpfnRWKx/F3AYP4QMn6ZJTh+l2HOrId0clNkEmua58NB9vmI9Qh7YOoV/4folYg==} + engines: {node: '>=20.19.4'} + object-assign@4.1.1: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} @@ -9032,6 +9504,17 @@ packages: '@types/react': optional: true + react-native@0.83.2: + resolution: {integrity: sha512-ZDma3SLkRN2U2dg0/EZqxNBAx4of/oTnPjXAQi299VLq2gdnbZowGy9hzqv+O7sTA62g+lM1v+2FM5DUnJ/6hg==} + engines: {node: '>= 20.19.4'} + hasBin: true + peerDependencies: + '@types/react': ^19.1.1 + react: ^19.2.0 + peerDependenciesMeta: + '@types/react': + optional: true + react-refresh@0.14.2: resolution: {integrity: sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==} engines: {node: '>=0.10.0'} @@ -9040,6 +9523,10 @@ packages: resolution: {integrity: sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==} engines: {node: '>=0.10.0'} + react@19.2.0: + resolution: {integrity: sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==} + engines: {node: '>=0.10.0'} + react@19.2.4: resolution: {integrity: sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==} engines: {node: '>=0.10.0'} @@ -9907,6 +10394,9 @@ packages: resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} engines: {node: '>=0.6'} + 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'} @@ -10430,6 +10920,9 @@ packages: resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} engines: {node: '>=18'} + whatwg-url-minimum@0.1.1: + resolution: {integrity: sha512-u2FNVjFVFZhdjb502KzXy1gKn1mEisQRJssmSJT8CPhZdZa0AP6VCbWlXERKyGu0l09t0k50FiDiralpGhBxgA==} + whatwg-url-without-unicode@8.0.0-3: resolution: {integrity: sha512-HoKuzZrUlgpz35YO27XgD28uh/WJH4B0+3ttFqRo//lmq+9T/mIOJ6kqmINI9HpUpz1imRC/nR/lxKpJiv0uig==} engines: {node: '>=10'} @@ -11344,6 +11837,14 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/plugin-transform-class-static-block@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + transitivePeerDependencies: + - supports-color + '@babel/plugin-transform-classes@7.28.6(@babel/core@7.29.0)': dependencies: '@babel/core': 7.29.0 @@ -12282,10 +12783,162 @@ snapshots: - supports-color - utf-8-validate - '@expo/code-signing-certificates@0.0.6': + '@expo/cli@55.0.16(@expo/dom-webview@55.0.3)(expo-constants@55.0.7)(expo-font@55.0.4(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(expo-router@5.1.11)(expo@55.0.6)(react-dom@19.2.4(react@19.2.0))(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3)': dependencies: - node-forge: 1.3.3 - + '@expo/code-signing-certificates': 0.0.6 + '@expo/config': 55.0.8(typescript@5.9.3) + '@expo/config-plugins': 55.0.6 + '@expo/devcert': 1.2.1 + '@expo/env': 2.1.1 + '@expo/image-utils': 0.8.12 + '@expo/json-file': 10.0.12 + '@expo/log-box': 55.0.7(@expo/dom-webview@55.0.3)(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0) + '@expo/metro': 54.2.0 + '@expo/metro-config': 55.0.9(expo@55.0.6)(typescript@5.9.3) + '@expo/osascript': 2.4.2 + '@expo/package-manager': 1.10.3 + '@expo/plist': 0.5.2 + '@expo/prebuild-config': 55.0.8(expo@55.0.6)(typescript@5.9.3) + '@expo/require-utils': 55.0.2(typescript@5.9.3) + '@expo/router-server': 55.0.10(expo-constants@55.0.7)(expo-font@55.0.4(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(expo-router@5.1.11)(expo-server@55.0.6)(expo@55.0.6)(react-dom@19.2.4(react@19.2.0))(react@19.2.0) + '@expo/schema-utils': 55.0.2 + '@expo/spawn-async': 1.7.2 + '@expo/ws-tunnel': 1.0.6 + '@expo/xcpretty': 4.4.0 + '@react-native/dev-middleware': 0.83.2 + 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.3 + expo: 55.0.6(@babel/core@7.29.0)(@expo/dom-webview@55.0.3)(expo-router@5.1.11)(react-dom@19.2.4(react@19.2.0))(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3) + expo-server: 55.0.6 + fetch-nodeshim: 0.4.9 + getenv: 2.0.0 + glob: 13.0.1 + lan-network: 0.2.0 + multitars: 0.2.4 + node-forge: 1.3.3 + npm-package-arg: 11.0.3 + ora: 3.4.0 + picomatch: 4.0.3 + pretty-format: 29.7.0 + progress: 2.0.3 + prompts: 2.4.2 + resolve-from: 5.0.0 + semver: 7.7.4 + send: 0.19.2 + slugify: 1.6.6 + 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.19.0 + zod: 3.25.76 + optionalDependencies: + expo-router: 5.1.11(@types/react@19.2.14)(expo-constants@55.0.7)(expo-linking@7.1.7)(expo@55.0.6)(react-native-safe-area-context@5.4.0(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native-screens@4.11.1(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0) + react-native: 0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0) + 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.16(@expo/dom-webview@55.0.3)(expo-constants@55.0.7)(expo-font@55.0.4(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(expo-router@5.1.11)(expo@55.0.6)(react-dom@19.2.4(react@19.2.4))(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4)(typescript@5.9.3)': + dependencies: + '@expo/code-signing-certificates': 0.0.6 + '@expo/config': 55.0.8(typescript@5.9.3) + '@expo/config-plugins': 55.0.6 + '@expo/devcert': 1.2.1 + '@expo/env': 2.1.1 + '@expo/image-utils': 0.8.12 + '@expo/json-file': 10.0.12 + '@expo/log-box': 55.0.7(@expo/dom-webview@55.0.3)(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) + '@expo/metro': 54.2.0 + '@expo/metro-config': 55.0.9(expo@55.0.6)(typescript@5.9.3) + '@expo/osascript': 2.4.2 + '@expo/package-manager': 1.10.3 + '@expo/plist': 0.5.2 + '@expo/prebuild-config': 55.0.8(expo@55.0.6)(typescript@5.9.3) + '@expo/require-utils': 55.0.2(typescript@5.9.3) + '@expo/router-server': 55.0.10(expo-constants@55.0.7)(expo-font@55.0.4(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(expo-router@5.1.11)(expo-server@55.0.6)(expo@55.0.6)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@expo/schema-utils': 55.0.2 + '@expo/spawn-async': 1.7.2 + '@expo/ws-tunnel': 1.0.6 + '@expo/xcpretty': 4.4.0 + '@react-native/dev-middleware': 0.83.2 + 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.3 + expo: 55.0.6(@babel/core@7.29.0)(@expo/dom-webview@55.0.3)(expo-router@5.1.11)(react-dom@19.2.4(react@19.2.4))(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4)(typescript@5.9.3) + expo-server: 55.0.6 + fetch-nodeshim: 0.4.9 + getenv: 2.0.0 + glob: 13.0.1 + lan-network: 0.2.0 + multitars: 0.2.4 + node-forge: 1.3.3 + npm-package-arg: 11.0.3 + ora: 3.4.0 + picomatch: 4.0.3 + pretty-format: 29.7.0 + progress: 2.0.3 + prompts: 2.4.2 + resolve-from: 5.0.0 + semver: 7.7.4 + send: 0.19.2 + slugify: 1.6.6 + 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.19.0 + zod: 3.25.76 + optionalDependencies: + expo-router: 5.1.11(@types/react@19.2.14)(expo-constants@55.0.7)(expo-linking@7.1.7)(expo@55.0.6)(react-native-safe-area-context@5.4.0(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(react-native-screens@4.11.1(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) + react-native: 0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4) + 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/code-signing-certificates@0.0.6': + dependencies: + node-forge: 1.3.3 + '@expo/config-plugins@10.1.2': dependencies: '@expo/config-types': 53.0.5 @@ -12305,8 +12958,28 @@ snapshots: transitivePeerDependencies: - supports-color + '@expo/config-plugins@55.0.6': + dependencies: + '@expo/config-types': 55.0.5 + '@expo/json-file': 10.0.12 + '@expo/plist': 0.5.2 + '@expo/sdk-runtime-versions': 1.0.0 + chalk: 4.1.2 + debug: 4.4.3 + getenv: 2.0.0 + glob: 13.0.1 + resolve-from: 5.0.0 + semver: 7.7.4 + slugify: 1.6.6 + xcode: 3.0.1 + xml2js: 0.6.0 + transitivePeerDependencies: + - supports-color + '@expo/config-types@53.0.5': {} + '@expo/config-types@55.0.5': {} + '@expo/config@11.0.13': dependencies: '@babel/code-frame': 7.10.4 @@ -12325,6 +12998,23 @@ snapshots: transitivePeerDependencies: - supports-color + '@expo/config@55.0.8(typescript@5.9.3)': + dependencies: + '@expo/config-plugins': 55.0.6 + '@expo/config-types': 55.0.5 + '@expo/json-file': 10.0.12 + '@expo/require-utils': 55.0.2(typescript@5.9.3) + deepmerge: 4.3.1 + getenv: 2.0.0 + glob: 13.0.1 + resolve-from: 5.0.0 + resolve-workspace-root: 2.0.1 + semver: 7.7.4 + slugify: 1.6.6 + transitivePeerDependencies: + - supports-color + - typescript + '@expo/devcert@1.2.1': dependencies: '@expo/sudo-prompt': 9.3.2 @@ -12332,6 +13022,39 @@ snapshots: transitivePeerDependencies: - supports-color + '@expo/devtools@55.0.2(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)': + dependencies: + chalk: 4.1.2 + optionalDependencies: + react: 19.2.0 + react-native: 0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0) + + '@expo/devtools@55.0.2(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4)': + dependencies: + chalk: 4.1.2 + optionalDependencies: + react: 19.2.4 + react-native: 0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4) + + '@expo/dom-webview@55.0.3(expo@53.0.27)(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4)': + dependencies: + expo: 53.0.27(@babel/core@7.29.0)(@expo/dom-webview@55.0.3)(@expo/metro-runtime@5.0.5(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4)))(graphql@16.12.0)(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) + react: 19.2.4 + react-native: 0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4) + optional: true + + '@expo/dom-webview@55.0.3(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)': + dependencies: + expo: 55.0.6(@babel/core@7.29.0)(@expo/dom-webview@55.0.3)(expo-router@5.1.11)(react-dom@19.2.4(react@19.2.0))(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3) + react: 19.2.0 + react-native: 0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0) + + '@expo/dom-webview@55.0.3(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4)': + dependencies: + expo: 55.0.6(@babel/core@7.29.0)(@expo/dom-webview@55.0.3)(expo-router@5.1.11)(react-dom@19.2.4(react@19.2.4))(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4)(typescript@5.9.3) + react: 19.2.4 + react-native: 0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4) + '@expo/env@1.0.7': dependencies: chalk: 4.1.2 @@ -12342,6 +13065,14 @@ snapshots: transitivePeerDependencies: - supports-color + '@expo/env@2.1.1': + dependencies: + chalk: 4.1.2 + debug: 4.4.3 + getenv: 2.0.0 + transitivePeerDependencies: + - supports-color + '@expo/fingerprint@0.13.4': dependencies: '@expo/spawn-async': 1.7.2 @@ -12359,6 +13090,22 @@ snapshots: transitivePeerDependencies: - supports-color + '@expo/fingerprint@0.16.6': + dependencies: + '@expo/env': 2.1.1 + '@expo/spawn-async': 1.7.2 + arg: 5.0.2 + chalk: 4.1.2 + debug: 4.4.3 + getenv: 2.0.0 + glob: 13.0.1 + ignore: 5.3.2 + minimatch: 10.2.4 + resolve-from: 5.0.0 + semver: 7.7.4 + transitivePeerDependencies: + - supports-color + '@expo/image-utils@0.7.6': dependencies: '@expo/spawn-async': 1.7.2 @@ -12371,6 +13118,21 @@ snapshots: temp-dir: 2.0.0 unique-string: 2.0.0 + '@expo/image-utils@0.8.12': + dependencies: + '@expo/spawn-async': 1.7.2 + chalk: 4.1.2 + getenv: 2.0.0 + jimp-compact: 0.16.1 + parse-png: 2.1.0 + resolve-from: 5.0.0 + semver: 7.7.4 + + '@expo/json-file@10.0.12': + dependencies: + '@babel/code-frame': 7.29.0 + json5: 2.2.3 + '@expo/json-file@10.0.8': dependencies: '@babel/code-frame': 7.10.4 @@ -12381,6 +13143,32 @@ snapshots: '@babel/code-frame': 7.10.4 json5: 2.2.3 + '@expo/local-build-cache-provider@55.0.6(typescript@5.9.3)': + dependencies: + '@expo/config': 55.0.8(typescript@5.9.3) + chalk: 4.1.2 + transitivePeerDependencies: + - supports-color + - typescript + + '@expo/log-box@55.0.7(@expo/dom-webview@55.0.3)(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)': + dependencies: + '@expo/dom-webview': 55.0.3(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0) + anser: 1.4.10 + expo: 55.0.6(@babel/core@7.29.0)(@expo/dom-webview@55.0.3)(expo-router@5.1.11)(react-dom@19.2.4(react@19.2.0))(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3) + react: 19.2.0 + react-native: 0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0) + stacktrace-parser: 0.1.11 + + '@expo/log-box@55.0.7(@expo/dom-webview@55.0.3)(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4)': + dependencies: + '@expo/dom-webview': 55.0.3(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) + anser: 1.4.10 + expo: 55.0.6(@babel/core@7.29.0)(@expo/dom-webview@55.0.3)(expo-router@5.1.11)(react-dom@19.2.4(react@19.2.4))(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4)(typescript@5.9.3) + react: 19.2.4 + react-native: 0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4) + stacktrace-parser: 0.1.11 + '@expo/metro-config@0.20.18': dependencies: '@babel/core': 7.29.0 @@ -12405,15 +13193,88 @@ snapshots: transitivePeerDependencies: - supports-color + '@expo/metro-config@55.0.9(expo@55.0.6)(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.8(typescript@5.9.3) + '@expo/env': 2.1.1 + '@expo/json-file': 10.0.12 + '@expo/metro': 54.2.0 + '@expo/spawn-async': 1.7.2 + browserslist: 4.28.1 + chalk: 4.1.2 + debug: 4.4.3 + getenv: 2.0.0 + glob: 13.0.1 + hermes-parser: 0.32.1 + jsc-safe-url: 0.2.4 + lightningcss: 1.31.1 + picomatch: 4.0.3 + postcss: 8.4.49 + resolve-from: 5.0.0 + optionalDependencies: + expo: 55.0.6(@babel/core@7.29.0)(@expo/dom-webview@55.0.3)(expo-router@5.1.11)(react-dom@19.2.4(react@19.2.4))(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4)(typescript@5.9.3) + transitivePeerDependencies: + - bufferutil + - supports-color + - typescript + - utf-8-validate + '@expo/metro-runtime@5.0.5(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))': dependencies: react-native: 0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4) + '@expo/metro-runtime@5.0.5(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))': + dependencies: + react-native: 0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0) + optional: true + + '@expo/metro-runtime@5.0.5(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))': + dependencies: + react-native: 0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4) + optional: true + + '@expo/metro@54.2.0': + dependencies: + metro: 0.82.5 + metro-babel-transformer: 0.83.3 + metro-cache: 0.83.3 + metro-cache-key: 0.83.3 + metro-config: 0.83.3 + metro-core: 0.83.3 + metro-file-map: 0.83.3 + metro-minify-terser: 0.83.3 + metro-resolver: 0.83.3 + metro-runtime: 0.83.3 + metro-source-map: 0.83.3 + metro-symbolicate: 0.83.3 + metro-transform-plugins: 0.83.3 + metro-transform-worker: 0.83.3 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + '@expo/osascript@2.3.8': dependencies: '@expo/spawn-async': 1.7.2 exec-async: 2.2.0 + '@expo/osascript@2.4.2': + dependencies: + '@expo/spawn-async': 1.7.2 + + '@expo/package-manager@1.10.3': + dependencies: + '@expo/json-file': 10.0.12 + '@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/package-manager@1.9.10': dependencies: '@expo/json-file': 10.0.8 @@ -12429,6 +13290,29 @@ snapshots: base64-js: 1.5.1 xmlbuilder: 15.1.1 + '@expo/plist@0.5.2': + dependencies: + '@xmldom/xmldom': 0.8.11 + base64-js: 1.5.1 + xmlbuilder: 15.1.1 + + '@expo/prebuild-config@55.0.8(expo@55.0.6)(typescript@5.9.3)': + dependencies: + '@expo/config': 55.0.8(typescript@5.9.3) + '@expo/config-plugins': 55.0.6 + '@expo/config-types': 55.0.5 + '@expo/image-utils': 0.8.12 + '@expo/json-file': 10.0.12 + '@react-native/normalize-colors': 0.83.2 + debug: 4.4.3 + expo: 55.0.6(@babel/core@7.29.0)(@expo/dom-webview@55.0.3)(expo-router@5.1.11)(react-dom@19.2.4(react@19.2.4))(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4)(typescript@5.9.3) + resolve-from: 5.0.0 + semver: 7.7.4 + xml2js: 0.6.0 + transitivePeerDependencies: + - supports-color + - typescript + '@expo/prebuild-config@9.0.12': dependencies: '@expo/config': 11.0.13 @@ -12444,8 +13328,48 @@ snapshots: transitivePeerDependencies: - supports-color + '@expo/require-utils@55.0.2(typescript@5.9.3)': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/core': 7.29.0 + '@babel/plugin-transform-modules-commonjs': 7.28.6(@babel/core@7.29.0) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@expo/router-server@55.0.10(expo-constants@55.0.7)(expo-font@55.0.4(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(expo-router@5.1.11)(expo-server@55.0.6)(expo@55.0.6)(react-dom@19.2.4(react@19.2.0))(react@19.2.0)': + dependencies: + debug: 4.4.3 + expo: 55.0.6(@babel/core@7.29.0)(@expo/dom-webview@55.0.3)(expo-router@5.1.11)(react-dom@19.2.4(react@19.2.0))(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3) + expo-constants: 55.0.7(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(typescript@5.9.3) + expo-font: 55.0.4(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0) + expo-server: 55.0.6 + react: 19.2.0 + optionalDependencies: + expo-router: 5.1.11(@types/react@19.2.14)(expo-constants@55.0.7)(expo-linking@7.1.7)(expo@55.0.6)(react-native-safe-area-context@5.4.0(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native-screens@4.11.1(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0) + react-dom: 19.2.4(react@19.2.0) + transitivePeerDependencies: + - supports-color + + '@expo/router-server@55.0.10(expo-constants@55.0.7)(expo-font@55.0.4(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(expo-router@5.1.11)(expo-server@55.0.6)(expo@55.0.6)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + debug: 4.4.3 + expo: 55.0.6(@babel/core@7.29.0)(@expo/dom-webview@55.0.3)(expo-router@5.1.11)(react-dom@19.2.4(react@19.2.4))(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4)(typescript@5.9.3) + expo-constants: 55.0.7(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(typescript@5.9.3) + expo-font: 55.0.4(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) + expo-server: 55.0.6 + react: 19.2.4 + optionalDependencies: + expo-router: 5.1.11(@types/react@19.2.14)(expo-constants@55.0.7)(expo-linking@7.1.7)(expo@55.0.6)(react-native-safe-area-context@5.4.0(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(react-native-screens@4.11.1(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) + react-dom: 19.2.4(react@19.2.4) + transitivePeerDependencies: + - supports-color + '@expo/schema-utils@0.1.8': {} + '@expo/schema-utils@55.0.2': {} + '@expo/sdk-runtime-versions@1.0.0': {} '@expo/server@0.6.3': @@ -12463,12 +13387,24 @@ snapshots: '@expo/sudo-prompt@9.3.2': {} - '@expo/vector-icons@14.1.0(expo-font@13.3.2(expo@53.0.27(@babel/core@7.29.0)(@expo/metro-runtime@5.0.5(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4)))(graphql@16.12.0)(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(react@19.2.4))(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4)': + '@expo/vector-icons@14.1.0(expo-font@13.3.2(expo@53.0.27)(react@19.2.4))(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4)': dependencies: - expo-font: 13.3.2(expo@53.0.27(@babel/core@7.29.0)(@expo/metro-runtime@5.0.5(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4)))(graphql@16.12.0)(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(react@19.2.4) + expo-font: 13.3.2(expo@53.0.27)(react@19.2.4) react: 19.2.4 react-native: 0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4) + '@expo/vector-icons@15.1.1(expo-font@55.0.4(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)': + dependencies: + expo-font: 55.0.4(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0) + react: 19.2.0 + react-native: 0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0) + + '@expo/vector-icons@15.1.1(expo-font@55.0.4(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4)': + dependencies: + expo-font: 55.0.4(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) + react: 19.2.4 + react-native: 0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4) + '@expo/ws-tunnel@1.0.6': {} '@expo/xcpretty@4.4.0': @@ -13383,10 +14319,10 @@ snapshots: '@oozcitak/util@10.0.0': {} - '@op-engineering/op-sqlite@15.2.5(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4)': + '@op-engineering/op-sqlite@15.2.5(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4)': dependencies: react: 19.2.4 - react-native: 0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4) + react-native: 0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4) '@opentelemetry/api@1.9.0': optional: true @@ -13564,12 +14500,27 @@ snapshots: '@publint/pack@0.1.4': {} + '@radix-ui/react-compose-refs@1.1.2(@types/react@19.2.14)(react@19.2.0)': + dependencies: + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.14 + optional: true + '@radix-ui/react-compose-refs@1.1.2(@types/react@19.2.14)(react@19.2.4)': dependencies: react: 19.2.4 optionalDependencies: '@types/react': 19.2.14 + '@radix-ui/react-slot@1.2.0(@types/react@19.2.14)(react@19.2.0)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.0) + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.14 + optional: true + '@radix-ui/react-slot@1.2.0(@types/react@19.2.14)(react@19.2.4)': dependencies: '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) @@ -13588,6 +14539,8 @@ snapshots: '@react-native/assets-registry@0.79.6': {} + '@react-native/assets-registry@0.83.2': {} + '@react-native/babel-plugin-codegen@0.79.6(@babel/core@7.29.0)': dependencies: '@babel/traverse': 7.29.0 @@ -13596,6 +14549,14 @@ snapshots: - '@babel/core' - supports-color + '@react-native/babel-plugin-codegen@0.83.2(@babel/core@7.29.0)': + dependencies: + '@babel/traverse': 7.29.0 + '@react-native/codegen': 0.83.2(@babel/core@7.29.0) + transitivePeerDependencies: + - '@babel/core' + - supports-color + '@react-native/babel-preset@0.79.6(@babel/core@7.29.0)': dependencies: '@babel/core': 7.29.0 @@ -13646,6 +14607,56 @@ snapshots: transitivePeerDependencies: - supports-color + '@react-native/babel-preset@0.83.2(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/plugin-proposal-export-default-from': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.29.0) + '@babel/plugin-syntax-export-default-from': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.29.0) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.29.0) + '@babel/plugin-transform-arrow-functions': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-async-generator-functions': 7.29.0(@babel/core@7.29.0) + '@babel/plugin-transform-async-to-generator': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-block-scoping': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-class-properties': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-classes': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-computed-properties': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.29.0) + '@babel/plugin-transform-flow-strip-types': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-for-of': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-function-name': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-literals': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-logical-assignment-operators': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-modules-commonjs': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-named-capturing-groups-regex': 7.29.0(@babel/core@7.29.0) + '@babel/plugin-transform-nullish-coalescing-operator': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-numeric-separator': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-object-rest-spread': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-optional-catch-binding': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-optional-chaining': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.29.0) + '@babel/plugin-transform-private-methods': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-private-property-in-object': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-react-display-name': 7.28.0(@babel/core@7.29.0) + '@babel/plugin-transform-react-jsx': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-regenerator': 7.29.0(@babel/core@7.29.0) + '@babel/plugin-transform-runtime': 7.29.0(@babel/core@7.29.0) + '@babel/plugin-transform-shorthand-properties': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-spread': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-sticky-regex': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-typescript': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-unicode-regex': 7.27.1(@babel/core@7.29.0) + '@babel/template': 7.28.6 + '@react-native/babel-plugin-codegen': 0.83.2(@babel/core@7.29.0) + babel-plugin-syntax-hermes-parser: 0.32.0 + babel-plugin-transform-flow-enums: 0.0.2(@babel/core@7.29.0) + react-refresh: 0.14.2 + transitivePeerDependencies: + - supports-color + '@react-native/codegen@0.79.6(@babel/core@7.29.0)': dependencies: '@babel/core': 7.29.0 @@ -13656,6 +14667,16 @@ snapshots: nullthrows: 1.1.1 yargs: 17.7.2 + '@react-native/codegen@0.83.2(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/parser': 7.29.0 + glob: 7.2.3 + hermes-parser: 0.32.0 + invariant: 2.2.4 + nullthrows: 1.1.1 + yargs: 17.7.2 + '@react-native/community-cli-plugin@0.79.6': dependencies: '@react-native/dev-middleware': 0.79.6 @@ -13671,8 +14692,29 @@ snapshots: - supports-color - utf-8-validate + '@react-native/community-cli-plugin@0.83.2': + dependencies: + '@react-native/dev-middleware': 0.83.2 + debug: 4.4.3 + invariant: 2.2.4 + metro: 0.82.5 + metro-config: 0.83.5 + metro-core: 0.83.5 + semver: 7.7.4 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + '@react-native/debugger-frontend@0.79.6': {} + '@react-native/debugger-frontend@0.83.2': {} + + '@react-native/debugger-shell@0.83.2': + dependencies: + cross-spawn: 7.0.6 + fb-dotslash: 0.5.8 + '@react-native/dev-middleware@0.79.6': dependencies: '@isaacs/ttlcache': 1.4.1 @@ -13691,12 +14733,37 @@ snapshots: - supports-color - utf-8-validate + '@react-native/dev-middleware@0.83.2': + dependencies: + '@isaacs/ttlcache': 1.4.1 + '@react-native/debugger-frontend': 0.83.2 + '@react-native/debugger-shell': 0.83.2 + chrome-launcher: 0.15.2 + chromium-edge-launcher: 0.2.0 + connect: 3.7.0 + debug: 4.4.3 + invariant: 2.2.4 + nullthrows: 1.1.1 + open: 7.4.2 + serve-static: 1.16.2 + ws: 7.5.10 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + '@react-native/gradle-plugin@0.79.6': {} + '@react-native/gradle-plugin@0.83.2': {} + '@react-native/js-polyfills@0.79.6': {} + '@react-native/js-polyfills@0.83.2': {} + '@react-native/normalize-colors@0.79.6': {} + '@react-native/normalize-colors@0.83.2': {} + '@react-native/virtualized-lists@0.79.6(@types/react@19.2.14)(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4)': dependencies: invariant: 2.2.4 @@ -13706,6 +14773,24 @@ snapshots: optionalDependencies: '@types/react': 19.2.14 + '@react-native/virtualized-lists@0.83.2(@types/react@19.2.14)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)': + dependencies: + invariant: 2.2.4 + nullthrows: 1.1.1 + react: 19.2.0 + react-native: 0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.14 + + '@react-native/virtualized-lists@0.83.2(@types/react@19.2.14)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4)': + dependencies: + invariant: 2.2.4 + nullthrows: 1.1.1 + react: 19.2.4 + react-native: 0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.14 + '@react-navigation/bottom-tabs@7.9.1(@react-navigation/native@7.1.27(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(react-native-safe-area-context@5.4.0(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(react-native-screens@4.11.1(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4)': dependencies: '@react-navigation/elements': 2.9.4(@react-navigation/native@7.1.27(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(react-native-safe-area-context@5.4.0(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) @@ -13719,6 +14804,47 @@ snapshots: transitivePeerDependencies: - '@react-native-masked-view/masked-view' + '@react-navigation/bottom-tabs@7.9.1(@react-navigation/native@7.1.27(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native-safe-area-context@5.4.0(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native-screens@4.11.1(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)': + dependencies: + '@react-navigation/elements': 2.9.4(@react-navigation/native@7.1.27(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native-safe-area-context@5.4.0(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0) + '@react-navigation/native': 7.1.27(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0) + color: 4.2.3 + react: 19.2.0 + react-native: 0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0) + react-native-safe-area-context: 5.4.0(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0) + react-native-screens: 4.11.1(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0) + sf-symbols-typescript: 2.2.0 + transitivePeerDependencies: + - '@react-native-masked-view/masked-view' + optional: true + + '@react-navigation/bottom-tabs@7.9.1(@react-navigation/native@7.1.27(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(react-native-safe-area-context@5.4.0(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(react-native-screens@4.11.1(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4)': + dependencies: + '@react-navigation/elements': 2.9.4(@react-navigation/native@7.1.27(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(react-native-safe-area-context@5.4.0(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) + '@react-navigation/native': 7.1.27(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) + color: 4.2.3 + react: 19.2.4 + react-native: 0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4) + react-native-safe-area-context: 5.4.0(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) + react-native-screens: 4.11.1(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) + sf-symbols-typescript: 2.2.0 + transitivePeerDependencies: + - '@react-native-masked-view/masked-view' + optional: true + + '@react-navigation/core@7.13.7(react@19.2.0)': + dependencies: + '@react-navigation/routers': 7.5.3 + escape-string-regexp: 4.0.0 + fast-deep-equal: 3.1.3 + nanoid: 3.3.11 + query-string: 7.1.3 + react: 19.2.0 + react-is: 19.2.3 + use-latest-callback: 0.2.6(react@19.2.0) + use-sync-external-store: 1.6.0(react@19.2.0) + optional: true + '@react-navigation/core@7.13.7(react@19.2.4)': dependencies: '@react-navigation/routers': 7.5.3 @@ -13731,15 +14857,37 @@ snapshots: use-latest-callback: 0.2.6(react@19.2.4) use-sync-external-store: 1.6.0(react@19.2.4) - '@react-navigation/elements@2.9.4(@react-navigation/native@7.1.27(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(react-native-safe-area-context@5.4.0(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4)': + '@react-navigation/elements@2.9.4(@react-navigation/native@7.1.27(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(react-native-safe-area-context@5.4.0(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4)': + dependencies: + '@react-navigation/native': 7.1.27(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) + color: 4.2.3 + react: 19.2.4 + react-native: 0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4) + react-native-safe-area-context: 5.4.0(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) + use-latest-callback: 0.2.6(react@19.2.4) + use-sync-external-store: 1.6.0(react@19.2.4) + + '@react-navigation/elements@2.9.4(@react-navigation/native@7.1.27(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native-safe-area-context@5.4.0(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)': + dependencies: + '@react-navigation/native': 7.1.27(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0) + color: 4.2.3 + react: 19.2.0 + react-native: 0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0) + react-native-safe-area-context: 5.4.0(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0) + use-latest-callback: 0.2.6(react@19.2.0) + use-sync-external-store: 1.6.0(react@19.2.0) + optional: true + + '@react-navigation/elements@2.9.4(@react-navigation/native@7.1.27(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(react-native-safe-area-context@5.4.0(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4)': dependencies: - '@react-navigation/native': 7.1.27(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) + '@react-navigation/native': 7.1.27(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) color: 4.2.3 react: 19.2.4 - react-native: 0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4) - react-native-safe-area-context: 5.4.0(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) + react-native: 0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4) + react-native-safe-area-context: 5.4.0(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) use-latest-callback: 0.2.6(react@19.2.4) use-sync-external-store: 1.6.0(react@19.2.4) + optional: true '@react-navigation/native-stack@7.9.1(@react-navigation/native@7.1.27(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(react-native-safe-area-context@5.4.0(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(react-native-screens@4.11.1(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4)': dependencies: @@ -13755,6 +14903,36 @@ snapshots: transitivePeerDependencies: - '@react-native-masked-view/masked-view' + '@react-navigation/native-stack@7.9.1(@react-navigation/native@7.1.27(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native-safe-area-context@5.4.0(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native-screens@4.11.1(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)': + dependencies: + '@react-navigation/elements': 2.9.4(@react-navigation/native@7.1.27(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native-safe-area-context@5.4.0(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0) + '@react-navigation/native': 7.1.27(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0) + color: 4.2.3 + react: 19.2.0 + react-native: 0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0) + react-native-safe-area-context: 5.4.0(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0) + react-native-screens: 4.11.1(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0) + sf-symbols-typescript: 2.2.0 + warn-once: 0.1.1 + transitivePeerDependencies: + - '@react-native-masked-view/masked-view' + optional: true + + '@react-navigation/native-stack@7.9.1(@react-navigation/native@7.1.27(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(react-native-safe-area-context@5.4.0(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(react-native-screens@4.11.1(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4)': + dependencies: + '@react-navigation/elements': 2.9.4(@react-navigation/native@7.1.27(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(react-native-safe-area-context@5.4.0(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) + '@react-navigation/native': 7.1.27(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) + color: 4.2.3 + react: 19.2.4 + react-native: 0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4) + react-native-safe-area-context: 5.4.0(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) + react-native-screens: 4.11.1(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) + sf-symbols-typescript: 2.2.0 + warn-once: 0.1.1 + transitivePeerDependencies: + - '@react-native-masked-view/masked-view' + optional: true + '@react-navigation/native@7.1.27(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4)': dependencies: '@react-navigation/core': 7.13.7(react@19.2.4) @@ -13765,6 +14943,28 @@ snapshots: react-native: 0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4) use-latest-callback: 0.2.6(react@19.2.4) + '@react-navigation/native@7.1.27(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)': + dependencies: + '@react-navigation/core': 7.13.7(react@19.2.0) + escape-string-regexp: 4.0.0 + fast-deep-equal: 3.1.3 + nanoid: 3.3.11 + react: 19.2.0 + react-native: 0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0) + use-latest-callback: 0.2.6(react@19.2.0) + optional: true + + '@react-navigation/native@7.1.27(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4)': + dependencies: + '@react-navigation/core': 7.13.7(react@19.2.4) + escape-string-regexp: 4.0.0 + fast-deep-equal: 3.1.3 + nanoid: 3.3.11 + react: 19.2.4 + react-native: 0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4) + use-latest-callback: 0.2.6(react@19.2.4) + optional: true + '@react-navigation/routers@7.5.3': dependencies: nanoid: 3.3.11 @@ -14916,6 +16116,8 @@ snapshots: '@ungap/raw-json@0.4.4': {} + '@ungap/structured-clone@1.3.0': {} + '@unrs/resolver-binding-android-arm-eabi@1.11.1': optional: true @@ -15413,6 +16615,8 @@ snapshots: dependencies: possible-typed-array-names: 1.1.0 + await-lock@2.2.2: {} + axobject-query@4.1.0: {} babel-dead-code-elimination@1.0.12: @@ -15488,12 +16692,26 @@ snapshots: transitivePeerDependencies: - supports-color + babel-plugin-react-compiler@1.0.0: + dependencies: + '@babel/types': 7.29.0 + babel-plugin-react-native-web@0.19.13: {} + babel-plugin-react-native-web@0.21.2: {} + babel-plugin-syntax-hermes-parser@0.25.1: dependencies: hermes-parser: 0.25.1 + babel-plugin-syntax-hermes-parser@0.32.0: + dependencies: + hermes-parser: 0.32.0 + + babel-plugin-syntax-hermes-parser@0.32.1: + dependencies: + hermes-parser: 0.32.1 + babel-plugin-transform-flow-enums@0.0.2(@babel/core@7.29.0): dependencies: '@babel/plugin-syntax-flow': 7.28.6(@babel/core@7.29.0) @@ -15546,6 +16764,39 @@ snapshots: - '@babel/core' - supports-color + babel-preset-expo@55.0.11(@babel/core@7.29.0)(@babel/runtime@7.28.4)(expo@55.0.6)(react-refresh@0.14.2): + dependencies: + '@babel/generator': 7.29.1 + '@babel/helper-module-imports': 7.28.6 + '@babel/plugin-proposal-decorators': 7.29.0(@babel/core@7.29.0) + '@babel/plugin-proposal-export-default-from': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-syntax-export-default-from': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-class-static-block': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-export-namespace-from': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-flow-strip-types': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-modules-commonjs': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-object-rest-spread': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.29.0) + '@babel/plugin-transform-private-methods': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-private-property-in-object': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-runtime': 7.29.0(@babel/core@7.29.0) + '@babel/preset-react': 7.28.5(@babel/core@7.29.0) + '@babel/preset-typescript': 7.28.5(@babel/core@7.29.0) + '@react-native/babel-preset': 0.83.2(@babel/core@7.29.0) + babel-plugin-react-compiler: 1.0.0 + babel-plugin-react-native-web: 0.21.2 + babel-plugin-syntax-hermes-parser: 0.32.1 + babel-plugin-transform-flow-enums: 0.0.2(@babel/core@7.29.0) + debug: 4.4.3 + react-refresh: 0.14.2 + resolve-from: 5.0.0 + optionalDependencies: + '@babel/runtime': 7.28.4 + expo: 55.0.6(@babel/core@7.29.0)(@expo/dom-webview@55.0.3)(expo-router@5.1.11)(react-dom@19.2.4(react@19.2.4))(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4)(typescript@5.9.3) + transitivePeerDependencies: + - '@babel/core' + - supports-color + babel-preset-jest@29.6.3(@babel/core@7.29.0): dependencies: '@babel/core': 7.29.0 @@ -15580,7 +16831,7 @@ snapshots: postcss: 8.5.6 postcss-media-query-parser: 0.2.3 - better-auth@1.4.18(f906072589a91c79df666d45593ff2aa): + better-auth@1.4.18(1b793ba0314cea31a9e4f726e7b3a675): dependencies: '@better-auth/core': 1.4.18(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@1.1.8(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.0) '@better-auth/telemetry': 1.4.18(@better-auth/core@1.4.18(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@1.1.8(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.0)) @@ -15599,7 +16850,7 @@ snapshots: '@tanstack/solid-start': 1.163.5(@tanstack/react-router@1.163.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(solid-js@1.9.11)(vite-plugin-solid@2.11.10(@testing-library/jest-dom@6.9.1)(solid-js@1.9.11)(vite@7.3.1(@types/node@25.2.2)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.90.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)))(vite@7.3.1(@types/node@25.2.2)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.90.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.1)) better-sqlite3: 12.6.2 drizzle-kit: 0.31.9 - drizzle-orm: 0.45.1(@op-engineering/op-sqlite@15.2.5(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.18.0)(better-sqlite3@12.6.2)(gel@2.1.1)(kysely@0.28.11)(pg@8.19.0)(postgres@3.4.8) + drizzle-orm: 0.45.1(@op-engineering/op-sqlite@15.2.5(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.18.0)(better-sqlite3@12.6.2)(expo-sqlite@55.0.10(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(gel@2.1.1)(kysely@0.28.11)(pg@8.19.0)(postgres@3.4.8) mongodb: 6.21.0(socks@2.8.7) pg: 8.19.0 react: 19.2.4 @@ -16239,6 +17490,8 @@ snapshots: dependencies: path-type: 4.0.0 + dnssd-advertise@1.1.3: {} + doctrine@2.1.0: dependencies: esutils: 2.0.3 @@ -16295,21 +17548,22 @@ snapshots: transitivePeerDependencies: - supports-color - drizzle-orm@0.45.1(@op-engineering/op-sqlite@15.2.5(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.18.0)(better-sqlite3@12.6.2)(gel@2.1.1)(kysely@0.28.11)(pg@8.19.0)(postgres@3.4.8): + drizzle-orm@0.45.1(@op-engineering/op-sqlite@15.2.5(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.18.0)(better-sqlite3@12.6.2)(expo-sqlite@55.0.10(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(gel@2.1.1)(kysely@0.28.11)(pg@8.19.0)(postgres@3.4.8): optionalDependencies: - '@op-engineering/op-sqlite': 15.2.5(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) + '@op-engineering/op-sqlite': 15.2.5(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) '@opentelemetry/api': 1.9.0 '@types/better-sqlite3': 7.6.13 '@types/pg': 8.18.0 better-sqlite3: 12.6.2 + expo-sqlite: 55.0.10(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) gel: 2.1.1 kysely: 0.28.11 pg: 8.19.0 postgres: 3.4.8 - drizzle-zod@0.8.3(drizzle-orm@0.45.1(@op-engineering/op-sqlite@15.2.5(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.18.0)(better-sqlite3@12.6.2)(gel@2.1.1)(kysely@0.28.11)(pg@8.19.0)(postgres@3.4.8))(zod@4.3.6): + drizzle-zod@0.8.3(drizzle-orm@0.45.1(@op-engineering/op-sqlite@15.2.5(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.18.0)(better-sqlite3@12.6.2)(expo-sqlite@55.0.10(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(gel@2.1.1)(kysely@0.28.11)(pg@8.19.0)(postgres@3.4.8))(zod@4.3.6): dependencies: - drizzle-orm: 0.45.1(@op-engineering/op-sqlite@15.2.5(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.18.0)(better-sqlite3@12.6.2)(gel@2.1.1)(kysely@0.28.11)(pg@8.19.0)(postgres@3.4.8) + drizzle-orm: 0.45.1(@op-engineering/op-sqlite@15.2.5(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.18.0)(better-sqlite3@12.6.2)(expo-sqlite@55.0.10(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(gel@2.1.1)(kysely@0.28.11)(pg@8.19.0)(postgres@3.4.8) zod: 4.3.6 dunder-proto@1.0.1: @@ -16897,44 +18151,140 @@ snapshots: expect-type@1.2.2: {} - expo-asset@11.1.7(expo@53.0.27(@babel/core@7.29.0)(@expo/metro-runtime@5.0.5(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4)))(graphql@16.12.0)(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4): + expo-asset@11.1.7(expo@53.0.27)(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4): dependencies: '@expo/image-utils': 0.7.6 - expo: 53.0.27(@babel/core@7.29.0)(@expo/metro-runtime@5.0.5(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4)))(graphql@16.12.0)(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) - expo-constants: 17.1.8(expo@53.0.27(@babel/core@7.29.0)(@expo/metro-runtime@5.0.5(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4)))(graphql@16.12.0)(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4)) + expo: 53.0.27(@babel/core@7.29.0)(@expo/dom-webview@55.0.3)(@expo/metro-runtime@5.0.5(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4)))(graphql@16.12.0)(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) + expo-constants: 17.1.8(expo@53.0.27)(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4)) react: 19.2.4 react-native: 0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4) transitivePeerDependencies: - supports-color - expo-constants@17.1.8(expo@53.0.27(@babel/core@7.29.0)(@expo/metro-runtime@5.0.5(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4)))(graphql@16.12.0)(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4)): + expo-asset@55.0.8(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3): + dependencies: + '@expo/image-utils': 0.8.12 + expo: 55.0.6(@babel/core@7.29.0)(@expo/dom-webview@55.0.3)(expo-router@5.1.11)(react-dom@19.2.4(react@19.2.0))(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3) + expo-constants: 55.0.7(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(typescript@5.9.3) + react: 19.2.0 + react-native: 0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0) + transitivePeerDependencies: + - supports-color + - typescript + + expo-asset@55.0.8(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4)(typescript@5.9.3): + dependencies: + '@expo/image-utils': 0.8.12 + expo: 55.0.6(@babel/core@7.29.0)(@expo/dom-webview@55.0.3)(expo-router@5.1.11)(react-dom@19.2.4(react@19.2.4))(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4)(typescript@5.9.3) + expo-constants: 55.0.7(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(typescript@5.9.3) + react: 19.2.4 + react-native: 0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4) + transitivePeerDependencies: + - supports-color + - typescript + + expo-constants@17.1.8(expo@53.0.27)(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4)): dependencies: '@expo/config': 11.0.13 '@expo/env': 1.0.7 - expo: 53.0.27(@babel/core@7.29.0)(@expo/metro-runtime@5.0.5(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4)))(graphql@16.12.0)(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) + expo: 53.0.27(@babel/core@7.29.0)(@expo/dom-webview@55.0.3)(@expo/metro-runtime@5.0.5(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4)))(graphql@16.12.0)(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) react-native: 0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4) transitivePeerDependencies: - supports-color - expo-file-system@18.1.11(expo@53.0.27(@babel/core@7.29.0)(@expo/metro-runtime@5.0.5(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4)))(graphql@16.12.0)(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4)): + expo-constants@17.1.8(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0)): + dependencies: + '@expo/config': 11.0.13 + '@expo/env': 1.0.7 + expo: 55.0.6(@babel/core@7.29.0)(@expo/dom-webview@55.0.3)(expo-router@5.1.11)(react-dom@19.2.4(react@19.2.0))(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3) + react-native: 0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0) + transitivePeerDependencies: + - supports-color + optional: true + + expo-constants@17.1.8(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4)): + dependencies: + '@expo/config': 11.0.13 + '@expo/env': 1.0.7 + expo: 55.0.6(@babel/core@7.29.0)(@expo/dom-webview@55.0.3)(expo-router@5.1.11)(react-dom@19.2.4(react@19.2.4))(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4)(typescript@5.9.3) + react-native: 0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4) + transitivePeerDependencies: + - supports-color + optional: true + + expo-constants@55.0.7(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(typescript@5.9.3): + dependencies: + '@expo/config': 55.0.8(typescript@5.9.3) + '@expo/env': 2.1.1 + expo: 55.0.6(@babel/core@7.29.0)(@expo/dom-webview@55.0.3)(expo-router@5.1.11)(react-dom@19.2.4(react@19.2.0))(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3) + react-native: 0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0) + transitivePeerDependencies: + - supports-color + - typescript + + expo-constants@55.0.7(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(typescript@5.9.3): + dependencies: + '@expo/config': 55.0.8(typescript@5.9.3) + '@expo/env': 2.1.1 + expo: 55.0.6(@babel/core@7.29.0)(@expo/dom-webview@55.0.3)(expo-router@5.1.11)(react-dom@19.2.4(react@19.2.4))(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4)(typescript@5.9.3) + react-native: 0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4) + transitivePeerDependencies: + - supports-color + - typescript + + expo-file-system@18.1.11(expo@53.0.27)(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4)): dependencies: - expo: 53.0.27(@babel/core@7.29.0)(@expo/metro-runtime@5.0.5(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4)))(graphql@16.12.0)(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) + expo: 53.0.27(@babel/core@7.29.0)(@expo/dom-webview@55.0.3)(@expo/metro-runtime@5.0.5(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4)))(graphql@16.12.0)(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) react-native: 0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4) - expo-font@13.3.2(expo@53.0.27(@babel/core@7.29.0)(@expo/metro-runtime@5.0.5(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4)))(graphql@16.12.0)(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(react@19.2.4): + expo-file-system@55.0.10(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0)): + dependencies: + expo: 55.0.6(@babel/core@7.29.0)(@expo/dom-webview@55.0.3)(expo-router@5.1.11)(react-dom@19.2.4(react@19.2.0))(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3) + react-native: 0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0) + + expo-file-system@55.0.10(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4)): + dependencies: + expo: 55.0.6(@babel/core@7.29.0)(@expo/dom-webview@55.0.3)(expo-router@5.1.11)(react-dom@19.2.4(react@19.2.4))(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4)(typescript@5.9.3) + react-native: 0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4) + + expo-font@13.3.2(expo@53.0.27)(react@19.2.4): + dependencies: + expo: 53.0.27(@babel/core@7.29.0)(@expo/dom-webview@55.0.3)(@expo/metro-runtime@5.0.5(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4)))(graphql@16.12.0)(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) + fontfaceobserver: 2.3.0 + react: 19.2.4 + + expo-font@55.0.4(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0): + dependencies: + expo: 55.0.6(@babel/core@7.29.0)(@expo/dom-webview@55.0.3)(expo-router@5.1.11)(react-dom@19.2.4(react@19.2.0))(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3) + fontfaceobserver: 2.3.0 + react: 19.2.0 + react-native: 0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0) + + expo-font@55.0.4(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4): dependencies: - expo: 53.0.27(@babel/core@7.29.0)(@expo/metro-runtime@5.0.5(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4)))(graphql@16.12.0)(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) + expo: 55.0.6(@babel/core@7.29.0)(@expo/dom-webview@55.0.3)(expo-router@5.1.11)(react-dom@19.2.4(react@19.2.4))(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4)(typescript@5.9.3) fontfaceobserver: 2.3.0 react: 19.2.4 + react-native: 0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4) + + expo-keep-awake@14.1.4(expo@53.0.27)(react@19.2.4): + dependencies: + expo: 53.0.27(@babel/core@7.29.0)(@expo/dom-webview@55.0.3)(@expo/metro-runtime@5.0.5(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4)))(graphql@16.12.0)(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) + react: 19.2.4 + + expo-keep-awake@55.0.4(expo@55.0.6)(react@19.2.0): + dependencies: + expo: 55.0.6(@babel/core@7.29.0)(@expo/dom-webview@55.0.3)(expo-router@5.1.11)(react-dom@19.2.4(react@19.2.0))(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3) + react: 19.2.0 - expo-keep-awake@14.1.4(expo@53.0.27(@babel/core@7.29.0)(@expo/metro-runtime@5.0.5(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4)))(graphql@16.12.0)(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(react@19.2.4): + expo-keep-awake@55.0.4(expo@55.0.6)(react@19.2.4): dependencies: - expo: 53.0.27(@babel/core@7.29.0)(@expo/metro-runtime@5.0.5(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4)))(graphql@16.12.0)(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) + expo: 55.0.6(@babel/core@7.29.0)(@expo/dom-webview@55.0.3)(expo-router@5.1.11)(react-dom@19.2.4(react@19.2.4))(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4)(typescript@5.9.3) react: 19.2.4 - expo-linking@7.1.7(expo@53.0.27(@babel/core@7.29.0)(@expo/metro-runtime@5.0.5(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4)))(graphql@16.12.0)(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4): + expo-linking@7.1.7(expo@53.0.27)(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4): dependencies: - expo-constants: 17.1.8(expo@53.0.27(@babel/core@7.29.0)(@expo/metro-runtime@5.0.5(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4)))(graphql@16.12.0)(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4)) + expo-constants: 17.1.8(expo@53.0.27)(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4)) invariant: 2.2.4 react: 19.2.4 react-native: 0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4) @@ -16942,6 +18292,28 @@ snapshots: - expo - supports-color + expo-linking@7.1.7(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0): + dependencies: + expo-constants: 17.1.8(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0)) + invariant: 2.2.4 + react: 19.2.0 + react-native: 0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0) + transitivePeerDependencies: + - expo + - supports-color + optional: true + + expo-linking@7.1.7(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4): + dependencies: + expo-constants: 17.1.8(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4)) + invariant: 2.2.4 + react: 19.2.4 + react-native: 0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4) + transitivePeerDependencies: + - expo + - supports-color + optional: true + expo-modules-autolinking@2.1.15: dependencies: '@expo/spawn-async': 1.7.2 @@ -16952,11 +18324,33 @@ snapshots: require-from-string: 2.0.2 resolve-from: 5.0.0 + expo-modules-autolinking@55.0.9(typescript@5.9.3): + dependencies: + '@expo/require-utils': 55.0.2(typescript@5.9.3) + '@expo/spawn-async': 1.7.2 + chalk: 4.1.2 + commander: 7.2.0 + transitivePeerDependencies: + - supports-color + - typescript + expo-modules-core@2.5.0: dependencies: invariant: 2.2.4 - expo-router@5.1.11(eab00a62f9f3891b852b0c18e99a25ac): + expo-modules-core@55.0.15(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0): + dependencies: + invariant: 2.2.4 + react: 19.2.0 + react-native: 0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0) + + expo-modules-core@55.0.15(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4): + dependencies: + invariant: 2.2.4 + react: 19.2.4 + react-native: 0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4) + + expo-router@5.1.11(@types/react@19.2.14)(expo-constants@17.1.8(expo@53.0.27)(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4)))(expo-linking@7.1.7(expo@53.0.27)(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(expo@53.0.27)(react-native-safe-area-context@5.4.0(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(react-native-screens@4.11.1(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4): dependencies: '@expo/metro-runtime': 5.0.5(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4)) '@expo/schema-utils': 0.1.8 @@ -16966,9 +18360,9 @@ snapshots: '@react-navigation/native': 7.1.27(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) '@react-navigation/native-stack': 7.9.1(@react-navigation/native@7.1.27(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(react-native-safe-area-context@5.4.0(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(react-native-screens@4.11.1(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) client-only: 0.0.1 - expo: 53.0.27(@babel/core@7.29.0)(@expo/metro-runtime@5.0.5(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4)))(graphql@16.12.0)(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) - expo-constants: 17.1.8(expo@53.0.27(@babel/core@7.29.0)(@expo/metro-runtime@5.0.5(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4)))(graphql@16.12.0)(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4)) - expo-linking: 7.1.7(expo@53.0.27(@babel/core@7.29.0)(@expo/metro-runtime@5.0.5(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4)))(graphql@16.12.0)(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) + expo: 53.0.27(@babel/core@7.29.0)(@expo/dom-webview@55.0.3)(@expo/metro-runtime@5.0.5(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4)))(graphql@16.12.0)(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) + expo-constants: 17.1.8(expo@53.0.27)(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4)) + expo-linking: 7.1.7(expo@53.0.27)(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) invariant: 2.2.4 react-fast-compare: 3.2.2 react-native-is-edge-to-edge: 1.2.1(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) @@ -16984,6 +18378,80 @@ snapshots: - react-native - supports-color + expo-router@5.1.11(@types/react@19.2.14)(expo-constants@55.0.7)(expo-linking@7.1.7)(expo@55.0.6)(react-native-safe-area-context@5.4.0(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native-screens@4.11.1(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0): + dependencies: + '@expo/metro-runtime': 5.0.5(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0)) + '@expo/schema-utils': 0.1.8 + '@expo/server': 0.6.3 + '@radix-ui/react-slot': 1.2.0(@types/react@19.2.14)(react@19.2.0) + '@react-navigation/bottom-tabs': 7.9.1(@react-navigation/native@7.1.27(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native-safe-area-context@5.4.0(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native-screens@4.11.1(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0) + '@react-navigation/native': 7.1.27(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0) + '@react-navigation/native-stack': 7.9.1(@react-navigation/native@7.1.27(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native-safe-area-context@5.4.0(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native-screens@4.11.1(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0) + client-only: 0.0.1 + expo: 55.0.6(@babel/core@7.29.0)(@expo/dom-webview@55.0.3)(expo-router@5.1.11)(react-dom@19.2.4(react@19.2.0))(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3) + expo-constants: 55.0.7(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(typescript@5.9.3) + expo-linking: 7.1.7(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0) + invariant: 2.2.4 + react-fast-compare: 3.2.2 + react-native-is-edge-to-edge: 1.2.1(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0) + react-native-safe-area-context: 5.4.0(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0) + react-native-screens: 4.11.1(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0) + semver: 7.6.3 + server-only: 0.0.1 + shallowequal: 1.1.0 + transitivePeerDependencies: + - '@react-native-masked-view/masked-view' + - '@types/react' + - react + - react-native + - supports-color + optional: true + + expo-router@5.1.11(@types/react@19.2.14)(expo-constants@55.0.7)(expo-linking@7.1.7)(expo@55.0.6)(react-native-safe-area-context@5.4.0(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(react-native-screens@4.11.1(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4): + dependencies: + '@expo/metro-runtime': 5.0.5(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4)) + '@expo/schema-utils': 0.1.8 + '@expo/server': 0.6.3 + '@radix-ui/react-slot': 1.2.0(@types/react@19.2.14)(react@19.2.4) + '@react-navigation/bottom-tabs': 7.9.1(@react-navigation/native@7.1.27(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(react-native-safe-area-context@5.4.0(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(react-native-screens@4.11.1(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) + '@react-navigation/native': 7.1.27(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) + '@react-navigation/native-stack': 7.9.1(@react-navigation/native@7.1.27(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(react-native-safe-area-context@5.4.0(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(react-native-screens@4.11.1(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) + client-only: 0.0.1 + expo: 55.0.6(@babel/core@7.29.0)(@expo/dom-webview@55.0.3)(expo-router@5.1.11)(react-dom@19.2.4(react@19.2.4))(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4)(typescript@5.9.3) + expo-constants: 55.0.7(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(typescript@5.9.3) + expo-linking: 7.1.7(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) + invariant: 2.2.4 + react-fast-compare: 3.2.2 + react-native-is-edge-to-edge: 1.2.1(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) + react-native-safe-area-context: 5.4.0(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) + react-native-screens: 4.11.1(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) + semver: 7.6.3 + server-only: 0.0.1 + shallowequal: 1.1.0 + transitivePeerDependencies: + - '@react-native-masked-view/masked-view' + - '@types/react' + - react + - react-native + - supports-color + optional: true + + expo-server@55.0.6: {} + + expo-sqlite@55.0.10(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0): + dependencies: + await-lock: 2.2.2 + expo: 55.0.6(@babel/core@7.29.0)(@expo/dom-webview@55.0.3)(expo-router@5.1.11)(react-dom@19.2.4(react@19.2.0))(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3) + react: 19.2.0 + react-native: 0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0) + + expo-sqlite@55.0.10(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4): + dependencies: + await-lock: 2.2.2 + expo: 55.0.6(@babel/core@7.29.0)(@expo/dom-webview@55.0.3)(expo-router@5.1.11)(react-dom@19.2.4(react@19.2.4))(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4)(typescript@5.9.3) + react: 19.2.4 + react-native: 0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4) + expo-status-bar@2.2.3(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4): dependencies: react: 19.2.4 @@ -16991,7 +18459,7 @@ snapshots: react-native-edge-to-edge: 1.6.0(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) react-native-is-edge-to-edge: 1.2.1(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) - expo@53.0.27(@babel/core@7.29.0)(@expo/metro-runtime@5.0.5(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4)))(graphql@16.12.0)(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4): + expo@53.0.27(@babel/core@7.29.0)(@expo/dom-webview@55.0.3)(@expo/metro-runtime@5.0.5(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4)))(graphql@16.12.0)(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4): dependencies: '@babel/runtime': 7.28.4 '@expo/cli': 0.24.24(graphql@16.12.0) @@ -16999,13 +18467,13 @@ snapshots: '@expo/config-plugins': 10.1.2 '@expo/fingerprint': 0.13.4 '@expo/metro-config': 0.20.18 - '@expo/vector-icons': 14.1.0(expo-font@13.3.2(expo@53.0.27(@babel/core@7.29.0)(@expo/metro-runtime@5.0.5(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4)))(graphql@16.12.0)(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(react@19.2.4))(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) + '@expo/vector-icons': 14.1.0(expo-font@13.3.2(expo@53.0.27)(react@19.2.4))(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) babel-preset-expo: 13.2.5(@babel/core@7.29.0) - expo-asset: 11.1.7(expo@53.0.27(@babel/core@7.29.0)(@expo/metro-runtime@5.0.5(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4)))(graphql@16.12.0)(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) - expo-constants: 17.1.8(expo@53.0.27(@babel/core@7.29.0)(@expo/metro-runtime@5.0.5(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4)))(graphql@16.12.0)(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4)) - expo-file-system: 18.1.11(expo@53.0.27(@babel/core@7.29.0)(@expo/metro-runtime@5.0.5(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4)))(graphql@16.12.0)(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4)) - expo-font: 13.3.2(expo@53.0.27(@babel/core@7.29.0)(@expo/metro-runtime@5.0.5(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4)))(graphql@16.12.0)(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(react@19.2.4) - expo-keep-awake: 14.1.4(expo@53.0.27(@babel/core@7.29.0)(@expo/metro-runtime@5.0.5(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4)))(graphql@16.12.0)(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(react@19.2.4) + expo-asset: 11.1.7(expo@53.0.27)(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) + expo-constants: 17.1.8(expo@53.0.27)(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4)) + expo-file-system: 18.1.11(expo@53.0.27)(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4)) + expo-font: 13.3.2(expo@53.0.27)(react@19.2.4) + expo-keep-awake: 14.1.4(expo@53.0.27)(react@19.2.4) expo-modules-autolinking: 2.1.15 expo-modules-core: 2.5.0 react: 19.2.4 @@ -17013,6 +18481,7 @@ snapshots: react-native-edge-to-edge: 1.6.0(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) whatwg-url-without-unicode: 8.0.0-3 optionalDependencies: + '@expo/dom-webview': 55.0.3(expo@53.0.27)(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) '@expo/metro-runtime': 5.0.5(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4)) transitivePeerDependencies: - '@babel/core' @@ -17022,6 +18491,86 @@ snapshots: - supports-color - utf-8-validate + expo@55.0.6(@babel/core@7.29.0)(@expo/dom-webview@55.0.3)(expo-router@5.1.11)(react-dom@19.2.4(react@19.2.0))(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3): + dependencies: + '@babel/runtime': 7.28.4 + '@expo/cli': 55.0.16(@expo/dom-webview@55.0.3)(expo-constants@55.0.7)(expo-font@55.0.4(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(expo-router@5.1.11)(expo@55.0.6)(react-dom@19.2.4(react@19.2.0))(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3) + '@expo/config': 55.0.8(typescript@5.9.3) + '@expo/config-plugins': 55.0.6 + '@expo/devtools': 55.0.2(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0) + '@expo/fingerprint': 0.16.6 + '@expo/local-build-cache-provider': 55.0.6(typescript@5.9.3) + '@expo/log-box': 55.0.7(@expo/dom-webview@55.0.3)(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0) + '@expo/metro': 54.2.0 + '@expo/metro-config': 55.0.9(expo@55.0.6)(typescript@5.9.3) + '@expo/vector-icons': 15.1.1(expo-font@55.0.4(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0) + '@ungap/structured-clone': 1.3.0 + babel-preset-expo: 55.0.11(@babel/core@7.29.0)(@babel/runtime@7.28.4)(expo@55.0.6)(react-refresh@0.14.2) + expo-asset: 55.0.8(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3) + expo-constants: 55.0.7(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(typescript@5.9.3) + expo-file-system: 55.0.10(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0)) + expo-font: 55.0.4(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0) + expo-keep-awake: 55.0.4(expo@55.0.6)(react@19.2.0) + expo-modules-autolinking: 55.0.9(typescript@5.9.3) + expo-modules-core: 55.0.15(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0) + pretty-format: 29.7.0 + react: 19.2.0 + react-native: 0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0) + react-refresh: 0.14.2 + whatwg-url-minimum: 0.1.1 + optionalDependencies: + '@expo/dom-webview': 55.0.3(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0) + transitivePeerDependencies: + - '@babel/core' + - bufferutil + - expo-router + - expo-widgets + - react-dom + - react-server-dom-webpack + - supports-color + - typescript + - utf-8-validate + + expo@55.0.6(@babel/core@7.29.0)(@expo/dom-webview@55.0.3)(expo-router@5.1.11)(react-dom@19.2.4(react@19.2.4))(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4)(typescript@5.9.3): + dependencies: + '@babel/runtime': 7.28.4 + '@expo/cli': 55.0.16(@expo/dom-webview@55.0.3)(expo-constants@55.0.7)(expo-font@55.0.4(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(expo-router@5.1.11)(expo@55.0.6)(react-dom@19.2.4(react@19.2.4))(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4)(typescript@5.9.3) + '@expo/config': 55.0.8(typescript@5.9.3) + '@expo/config-plugins': 55.0.6 + '@expo/devtools': 55.0.2(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) + '@expo/fingerprint': 0.16.6 + '@expo/local-build-cache-provider': 55.0.6(typescript@5.9.3) + '@expo/log-box': 55.0.7(@expo/dom-webview@55.0.3)(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) + '@expo/metro': 54.2.0 + '@expo/metro-config': 55.0.9(expo@55.0.6)(typescript@5.9.3) + '@expo/vector-icons': 15.1.1(expo-font@55.0.4(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) + '@ungap/structured-clone': 1.3.0 + babel-preset-expo: 55.0.11(@babel/core@7.29.0)(@babel/runtime@7.28.4)(expo@55.0.6)(react-refresh@0.14.2) + expo-asset: 55.0.8(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4)(typescript@5.9.3) + expo-constants: 55.0.7(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(typescript@5.9.3) + expo-file-system: 55.0.10(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4)) + expo-font: 55.0.4(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) + expo-keep-awake: 55.0.4(expo@55.0.6)(react@19.2.4) + expo-modules-autolinking: 55.0.9(typescript@5.9.3) + expo-modules-core: 55.0.15(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) + pretty-format: 29.7.0 + react: 19.2.4 + react-native: 0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4) + react-refresh: 0.14.2 + whatwg-url-minimum: 0.1.1 + optionalDependencies: + '@expo/dom-webview': 55.0.3(expo@55.0.6)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) + transitivePeerDependencies: + - '@babel/core' + - bufferutil + - expo-router + - expo-widgets + - react-dom + - react-server-dom-webpack + - supports-color + - typescript + - utf-8-validate + exponential-backoff@3.1.3: {} express-rate-limit@8.2.1(express@5.2.1): @@ -17098,6 +18647,8 @@ snapshots: dependencies: websocket-driver: 0.7.4 + fb-dotslash@0.5.8: {} + fb-watchman@2.0.2: dependencies: bser: 2.1.1 @@ -17110,6 +18661,8 @@ snapshots: optionalDependencies: picomatch: 4.0.3 + fetch-nodeshim@0.4.9: {} + fflate@0.8.2: {} file-entry-cache@8.0.0: @@ -17438,10 +18991,16 @@ snapshots: he@1.2.0: {} + hermes-compiler@0.14.1: {} + hermes-estree@0.25.1: {} hermes-estree@0.29.1: {} + hermes-estree@0.32.0: {} + + hermes-estree@0.32.1: {} + hermes-parser@0.25.1: dependencies: hermes-estree: 0.25.1 @@ -17450,6 +19009,14 @@ snapshots: dependencies: hermes-estree: 0.29.1 + hermes-parser@0.32.0: + dependencies: + hermes-estree: 0.32.0 + + hermes-parser@0.32.1: + dependencies: + hermes-estree: 0.32.1 + hono@4.11.9: {} hosted-git-info@7.0.2: @@ -18147,6 +19714,8 @@ snapshots: lan-network@0.1.7: {} + lan-network@0.2.0: {} + leven@3.1.0: {} levn@0.4.1: @@ -18485,25 +20054,56 @@ snapshots: merge2@1.4.1: {} - metro-babel-transformer@0.82.5: + metro-babel-transformer@0.82.5: + dependencies: + '@babel/core': 7.29.0 + flow-enums-runtime: 0.0.6 + hermes-parser: 0.29.1 + nullthrows: 1.1.1 + transitivePeerDependencies: + - supports-color + + metro-babel-transformer@0.83.3: + dependencies: + '@babel/core': 7.29.0 + flow-enums-runtime: 0.0.6 + hermes-parser: 0.32.0 + nullthrows: 1.1.1 + transitivePeerDependencies: + - supports-color + + metro-cache-key@0.82.5: + dependencies: + flow-enums-runtime: 0.0.6 + + metro-cache-key@0.83.3: + dependencies: + flow-enums-runtime: 0.0.6 + + metro-cache@0.82.5: dependencies: - '@babel/core': 7.29.0 + exponential-backoff: 3.1.3 flow-enums-runtime: 0.0.6 - hermes-parser: 0.29.1 - nullthrows: 1.1.1 + https-proxy-agent: 7.0.6 + metro-core: 0.82.5 transitivePeerDependencies: - supports-color - metro-cache-key@0.82.5: + metro-cache@0.83.3: dependencies: + exponential-backoff: 3.1.3 flow-enums-runtime: 0.0.6 + https-proxy-agent: 7.0.6 + metro-core: 0.83.3 + transitivePeerDependencies: + - supports-color - metro-cache@0.82.5: + metro-cache@0.83.5: dependencies: exponential-backoff: 3.1.3 flow-enums-runtime: 0.0.6 https-proxy-agent: 7.0.6 - metro-core: 0.82.5 + metro-core: 0.83.5 transitivePeerDependencies: - supports-color @@ -18522,12 +20122,54 @@ snapshots: - supports-color - utf-8-validate + metro-config@0.83.3: + dependencies: + connect: 3.7.0 + flow-enums-runtime: 0.0.6 + jest-validate: 29.7.0 + metro: 0.82.5 + metro-cache: 0.83.3 + metro-core: 0.83.3 + metro-runtime: 0.83.3 + yaml: 2.8.1 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + metro-config@0.83.5: + dependencies: + connect: 3.7.0 + flow-enums-runtime: 0.0.6 + jest-validate: 29.7.0 + metro: 0.82.5 + metro-cache: 0.83.5 + metro-core: 0.83.5 + metro-runtime: 0.83.5 + yaml: 2.8.1 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + metro-core@0.82.5: dependencies: flow-enums-runtime: 0.0.6 lodash.throttle: 4.1.1 metro-resolver: 0.82.5 + metro-core@0.83.3: + dependencies: + flow-enums-runtime: 0.0.6 + lodash.throttle: 4.1.1 + metro-resolver: 0.83.3 + + metro-core@0.83.5: + dependencies: + flow-enums-runtime: 0.0.6 + lodash.throttle: 4.1.1 + metro-resolver: 0.83.5 + metro-file-map@0.82.5: dependencies: debug: 4.4.3 @@ -18542,20 +20184,57 @@ snapshots: transitivePeerDependencies: - supports-color + metro-file-map@0.83.3: + dependencies: + debug: 4.4.3 + fb-watchman: 2.0.2 + flow-enums-runtime: 0.0.6 + graceful-fs: 4.2.11 + invariant: 2.2.4 + jest-worker: 29.7.0 + micromatch: 4.0.8 + nullthrows: 1.1.1 + walker: 1.0.8 + transitivePeerDependencies: + - supports-color + metro-minify-terser@0.82.5: dependencies: flow-enums-runtime: 0.0.6 terser: 5.44.0 + metro-minify-terser@0.83.3: + dependencies: + flow-enums-runtime: 0.0.6 + terser: 5.44.0 + metro-resolver@0.82.5: dependencies: flow-enums-runtime: 0.0.6 + metro-resolver@0.83.3: + dependencies: + flow-enums-runtime: 0.0.6 + + metro-resolver@0.83.5: + dependencies: + flow-enums-runtime: 0.0.6 + metro-runtime@0.82.5: dependencies: '@babel/runtime': 7.28.4 flow-enums-runtime: 0.0.6 + metro-runtime@0.83.3: + dependencies: + '@babel/runtime': 7.28.4 + flow-enums-runtime: 0.0.6 + + metro-runtime@0.83.5: + dependencies: + '@babel/runtime': 7.28.4 + flow-enums-runtime: 0.0.6 + metro-source-map@0.82.5: dependencies: '@babel/traverse': 7.29.0 @@ -18571,6 +20250,35 @@ snapshots: transitivePeerDependencies: - supports-color + metro-source-map@0.83.3: + dependencies: + '@babel/traverse': 7.29.0 + '@babel/traverse--for-generate-function-map': '@babel/traverse@7.29.0' + '@babel/types': 7.29.0 + flow-enums-runtime: 0.0.6 + invariant: 2.2.4 + metro-symbolicate: 0.83.3 + nullthrows: 1.1.1 + ob1: 0.83.3 + source-map: 0.5.7 + vlq: 1.0.1 + transitivePeerDependencies: + - supports-color + + metro-source-map@0.83.5: + dependencies: + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + flow-enums-runtime: 0.0.6 + invariant: 2.2.4 + metro-symbolicate: 0.83.5 + nullthrows: 1.1.1 + ob1: 0.83.5 + source-map: 0.5.7 + vlq: 1.0.1 + transitivePeerDependencies: + - supports-color + metro-symbolicate@0.82.5: dependencies: flow-enums-runtime: 0.0.6 @@ -18582,6 +20290,28 @@ snapshots: transitivePeerDependencies: - supports-color + metro-symbolicate@0.83.3: + dependencies: + flow-enums-runtime: 0.0.6 + invariant: 2.2.4 + metro-source-map: 0.83.3 + nullthrows: 1.1.1 + source-map: 0.5.7 + vlq: 1.0.1 + transitivePeerDependencies: + - supports-color + + metro-symbolicate@0.83.5: + dependencies: + flow-enums-runtime: 0.0.6 + invariant: 2.2.4 + metro-source-map: 0.83.5 + nullthrows: 1.1.1 + source-map: 0.5.7 + vlq: 1.0.1 + transitivePeerDependencies: + - supports-color + metro-transform-plugins@0.82.5: dependencies: '@babel/core': 7.29.0 @@ -18593,6 +20323,17 @@ snapshots: transitivePeerDependencies: - supports-color + metro-transform-plugins@0.83.3: + dependencies: + '@babel/core': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/template': 7.28.6 + '@babel/traverse': 7.29.0 + flow-enums-runtime: 0.0.6 + nullthrows: 1.1.1 + transitivePeerDependencies: + - supports-color + metro-transform-worker@0.82.5: dependencies: '@babel/core': 7.29.0 @@ -18613,6 +20354,26 @@ snapshots: - supports-color - utf-8-validate + metro-transform-worker@0.83.3: + dependencies: + '@babel/core': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 + flow-enums-runtime: 0.0.6 + metro: 0.82.5 + metro-babel-transformer: 0.83.3 + metro-cache: 0.83.3 + metro-cache-key: 0.83.3 + metro-minify-terser: 0.83.3 + metro-source-map: 0.83.3 + metro-transform-plugins: 0.83.3 + nullthrows: 1.1.1 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + metro@0.82.5: dependencies: '@babel/code-frame': 7.29.0 @@ -18802,6 +20563,8 @@ snapshots: muggle-string@0.4.1: {} + multitars@0.2.4: {} + mute-stream@2.0.0: {} mz@2.7.0: @@ -18958,6 +20721,14 @@ snapshots: dependencies: flow-enums-runtime: 0.0.6 + ob1@0.83.3: + dependencies: + flow-enums-runtime: 0.0.6 + + ob1@0.83.5: + dependencies: + flow-enums-runtime: 0.0.6 + object-assign@4.1.1: {} object-inspect@1.13.4: {} @@ -19515,6 +21286,12 @@ snapshots: - bufferutil - utf-8-validate + react-dom@19.2.4(react@19.2.0): + dependencies: + react: 19.2.0 + scheduler: 0.27.0 + optional: true + react-dom@19.2.4(react@19.2.4): dependencies: react: 19.2.4 @@ -19522,6 +21299,11 @@ snapshots: react-fast-compare@3.2.2: {} + react-freeze@1.0.4(react@19.2.0): + dependencies: + react: 19.2.0 + optional: true + react-freeze@1.0.4(react@19.2.4): dependencies: react: 19.2.4 @@ -19544,11 +21326,35 @@ snapshots: react: 19.2.4 react-native: 0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4) + react-native-is-edge-to-edge@1.2.1(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0): + dependencies: + react: 19.2.0 + react-native: 0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0) + optional: true + + react-native-is-edge-to-edge@1.2.1(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4): + dependencies: + react: 19.2.4 + react-native: 0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4) + optional: true + react-native-safe-area-context@5.4.0(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4): dependencies: react: 19.2.4 react-native: 0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4) + react-native-safe-area-context@5.4.0(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0): + dependencies: + react: 19.2.0 + react-native: 0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0) + optional: true + + react-native-safe-area-context@5.4.0(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4): + dependencies: + react: 19.2.4 + react-native: 0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4) + optional: true + react-native-screens@4.11.1(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4): dependencies: react: 19.2.4 @@ -19557,6 +21363,24 @@ snapshots: react-native-is-edge-to-edge: 1.2.1(react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) warn-once: 0.1.1 + react-native-screens@4.11.1(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0): + dependencies: + react: 19.2.0 + react-freeze: 1.0.4(react@19.2.0) + react-native: 0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0) + react-native-is-edge-to-edge: 1.2.1(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0) + warn-once: 0.1.1 + optional: true + + react-native-screens@4.11.1(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4): + dependencies: + react: 19.2.4 + react-freeze: 1.0.4(react@19.2.4) + react-native: 0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4) + react-native-is-edge-to-edge: 1.2.1(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) + warn-once: 0.1.1 + optional: true + react-native@0.79.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4): dependencies: '@jest/create-cache-key-function': 29.7.0 @@ -19605,10 +21429,108 @@ snapshots: - supports-color - utf-8-validate + react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0): + dependencies: + '@jest/create-cache-key-function': 29.7.0 + '@react-native/assets-registry': 0.83.2 + '@react-native/codegen': 0.83.2(@babel/core@7.29.0) + '@react-native/community-cli-plugin': 0.83.2 + '@react-native/gradle-plugin': 0.83.2 + '@react-native/js-polyfills': 0.83.2 + '@react-native/normalize-colors': 0.83.2 + '@react-native/virtualized-lists': 0.83.2(@types/react@19.2.14)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0) + 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.5 + metro-source-map: 0.83.5 + nullthrows: 1.1.1 + pretty-format: 29.7.0 + promise: 8.3.0 + react: 19.2.0 + 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.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4): + dependencies: + '@jest/create-cache-key-function': 29.7.0 + '@react-native/assets-registry': 0.83.2 + '@react-native/codegen': 0.83.2(@babel/core@7.29.0) + '@react-native/community-cli-plugin': 0.83.2 + '@react-native/gradle-plugin': 0.83.2 + '@react-native/js-polyfills': 0.83.2 + '@react-native/normalize-colors': 0.83.2 + '@react-native/virtualized-lists': 0.83.2(@types/react@19.2.14)(react-native@0.83.2(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) + 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.5 + metro-source-map: 0.83.5 + nullthrows: 1.1.1 + pretty-format: 29.7.0 + promise: 8.3.0 + react: 19.2.4 + 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-refresh@0.14.2: {} react-refresh@0.18.0: {} + react@19.2.0: {} + react@19.2.4: {} read-yaml-file@1.1.0: @@ -20655,6 +22577,8 @@ snapshots: toidentifier@1.0.1: {} + toqr@0.1.1: {} + totalist@3.0.1: {} tough-cookie@6.0.0: @@ -20895,10 +22819,20 @@ snapshots: dependencies: punycode: 2.3.1 + use-latest-callback@0.2.6(react@19.2.0): + dependencies: + react: 19.2.0 + optional: true + use-latest-callback@0.2.6(react@19.2.4): dependencies: react: 19.2.4 + use-sync-external-store@1.6.0(react@19.2.0): + dependencies: + react: 19.2.0 + optional: true + use-sync-external-store@1.6.0(react@19.2.4): dependencies: react: 19.2.4 @@ -21170,6 +23104,8 @@ snapshots: whatwg-mimetype@4.0.0: {} + whatwg-url-minimum@0.1.1: {} + whatwg-url-without-unicode@8.0.0-3: dependencies: buffer: 5.7.1