diff --git a/.changeset/orange-spies-cry.md b/.changeset/orange-spies-cry.md new file mode 100644 index 000000000..52d583ffe --- /dev/null +++ b/.changeset/orange-spies-cry.md @@ -0,0 +1,5 @@ +--- +'@powersync/adapter-sql-js': patch +--- + +Introduced adapter-sql-js package. diff --git a/.changeset/rude-pears-fail.md b/.changeset/rude-pears-fail.md new file mode 100644 index 000000000..c9cc0837a --- /dev/null +++ b/.changeset/rude-pears-fail.md @@ -0,0 +1,5 @@ +--- +'@powersync/common': minor +--- + +Added ControlledExecutor utility to exports. diff --git a/packages/adapter-sql-js/README.md b/packages/adapter-sql-js/README.md new file mode 100644 index 000000000..a3d4dac00 --- /dev/null +++ b/packages/adapter-sql-js/README.md @@ -0,0 +1,92 @@ +# PowerSync SQL-JS Adapter + +A development package for PowerSync which uses [SQL.js](https://sql.js.org/#/) to provide a pure JavaScript SQLite implementation. +This eliminates the need for native dependencies and enables seamless development with Expo Go and other JavaScript-only environments. + +This adapter is specifically intended to streamline the development workflow and will be much slower than DB adapters that use native dependencies. +Every write operation triggers a complete rewrite of the entire database file to persistent storage, not just the changed data. +In addition to the perfomance overheads, this adapter doesn't provide any of the SQLite consistency guarantees - you may end up with missing data or a corrupted database file if the app is killed while writing to the database file. + +For production use, when building React Native apps we recommend switching to our [react-native-quick-sqlite](https://www.npmjs.com/package/@journeyapps/react-native-quick-sqlite) or [OP-SQLite](https://www.npmjs.com/package/@powersync/op-sqlite) adapters when making production builds as they give substantially better performance. + +## Note: Alpha Release + +This package is currently in an alpha release. + +## Usage + +By default the SQLJS adapter will be in-memory. Read further for persister examples. + +```tsx +import { SQLJSOpenFactory } from '@powersync/adapter-sql-js'; + +const powersync = new PowerSyncDatabase({ + schema: AppSchema, + database: new SQLJSOpenFactory({ + dbFilename: 'powersync.db' + }) +}); +``` + +## Persister examples + +### Expo + +We can use the [Expo File System](https://docs.expo.dev/versions/latest/sdk/filesystem/) to persist the database in an Expo app. + +```tsx +import { PowerSyncDatabase, SQLJSOpenFactory, SQLJSPersister } from '@powersync/react-native'; +import * as FileSystem from 'expo-file-system'; + +const powersync = new PowerSyncDatabase({ + schema: AppSchema, + database: new SQLJSOpenFactory({ + dbFilename: 'powersync.db', + persister: createSQLJSPersister('powersync.db') + }) +}); + +const createSQLJSPersister = (dbFilename: string): SQLJSPersister => { + const dbPath = `${FileSystem.documentDirectory}${dbFilename}`; + + return { + readFile: async (): Promise | Buffer | null> => { + try { + const fileInfo = await FileSystem.getInfoAsync(dbPath); + if (!fileInfo.exists) { + return null; + } + + const result = await FileSystem.readAsStringAsync(dbPath, { + encoding: FileSystem.EncodingType.Base64 + }); + + const binary = atob(result); + const bytes = new Uint8Array(binary.length); + for (let i = 0; i < binary.length; i++) { + bytes[i] = binary.charCodeAt(i); + } + return bytes; + } catch (error) { + console.error('Error reading database file:', error); + return null; + } + }, + + writeFile: async (data: ArrayLike | Buffer): Promise => { + try { + const uint8Array = new Uint8Array(data); + const binary = Array.from(uint8Array, (byte) => String.fromCharCode(byte)).join(''); + const base64 = btoa(binary); + + await FileSystem.writeAsStringAsync(dbPath, base64, { + encoding: FileSystem.EncodingType.Base64 + }); + } catch (error) { + console.error('Error writing database file:', error); + throw error; + } + } + }; +}; +``` diff --git a/packages/adapter-sql-js/package.json b/packages/adapter-sql-js/package.json new file mode 100644 index 000000000..4bf76e9e2 --- /dev/null +++ b/packages/adapter-sql-js/package.json @@ -0,0 +1,46 @@ +{ + "name": "@powersync/adapter-sql-js", + "version": "0.0.0", + "publishConfig": { + "registry": "https://registry.npmjs.org/", + "access": "public" + }, + "description": "A development db adapter based on SQL.js for JourneyApps PowerSync", + "type": "module", + "main": "dist/bundle.mjs", + "module": "dist/bundle.mjs", + "types": "lib/index.d.ts", + "author": "JOURNEYAPPS", + "license": "Apache-2.0", + "files": [ + "lib", + "dist" + ], + "repository": { + "type": "git", + "url": "git+https://github.com/powersync-ja/powersync-js.git" + }, + "bugs": { + "url": "https://github.com/powersync-ja/powersync-js/issues" + }, + "homepage": "https://docs.powersync.com", + "scripts": { + "build": "tsc -b && rollup -c rollup.config.mjs", + "build:prod": "tsc -b --sourceMap false && rollup -c rollup.config.mjs --sourceMap false", + "clean": "rm -rf lib dist tsconfig.tsbuildinfo", + "test": "vitest" + }, + "dependencies": { + "@powersync/common": "workspace:^", + "async-mutex": "^0.4.0" + }, + "devDependencies": { + "@powersync/sql-js": "0.0.1", + "@powersync/web": "workspace:*", + "@rollup/plugin-alias": "^5.1.0", + "@types/sql.js": "^1.4.9", + "chance": "^1.1.9", + "rollup": "4.14.3", + "uuid": "^11.1.0" + } +} diff --git a/packages/adapter-sql-js/rollup.config.mjs b/packages/adapter-sql-js/rollup.config.mjs new file mode 100644 index 000000000..47e65c673 --- /dev/null +++ b/packages/adapter-sql-js/rollup.config.mjs @@ -0,0 +1,41 @@ +import alias from '@rollup/plugin-alias'; +import commonjs from '@rollup/plugin-commonjs'; +import nodeResolve from '@rollup/plugin-node-resolve'; +import path from 'path'; +import { fileURLToPath } from 'url'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +/** + * @returns {import('rollup').RollupOptions} + */ +export default (commandLineArgs) => { + const sourceMap = (commandLineArgs.sourceMap || 'true') == 'true'; + + // Clears rollup CLI warning https://github.com/rollup/rollup/issues/2694 + delete commandLineArgs.sourceMap; + + return { + input: 'lib/index.js', + output: { + file: 'dist/bundle.mjs', + format: 'esm', + sourcemap: sourceMap + }, + plugins: [ + nodeResolve({ preferBuiltins: false, browser: true }), + commonjs({}), + alias({ + entries: [ + // The default Emscripten output contains code like `require("fs")`. This seems + // to be unreachable, but Metro complains when it detects it. + { find: 'fs', replacement: path.resolve(__dirname, 'vendored/empty.js') }, + { find: 'path', replacement: path.resolve(__dirname, 'vendored/empty.js') }, + { find: 'crypto', replacement: path.resolve(__dirname, 'vendored/empty.js') } + ] + }) + ], + external: ['@powersync/common'] + }; +}; diff --git a/packages/adapter-sql-js/src/SQLJSAdapter.ts b/packages/adapter-sql-js/src/SQLJSAdapter.ts new file mode 100644 index 000000000..edc3aa602 --- /dev/null +++ b/packages/adapter-sql-js/src/SQLJSAdapter.ts @@ -0,0 +1,335 @@ +import { + BaseListener, + BaseObserver, + BatchedUpdateNotification, + ControlledExecutor, + createLogger, + DBAdapter, + DBAdapterListener, + DBLockOptions, + ILogger, + LockContext, + QueryResult, + SQLOpenFactory, + SQLOpenOptions, + Transaction +} from '@powersync/common'; +import { Mutex } from 'async-mutex'; +// This uses a pure JS version which avoids the need for WebAssembly, which is not supported in React Native. +import SQLJs from '@powersync/sql-js/dist/sql-asm.js'; + +export interface SQLJSPersister { + readFile: () => Promise | Buffer | null>; + writeFile: (data: ArrayLike | Buffer) => Promise; +} + +export interface SQLJSOpenOptions extends SQLOpenOptions { + persister?: SQLJSPersister; + logger?: ILogger; +} + +export interface ResolvedSQLJSOpenOptions extends SQLJSOpenOptions { + persister: SQLJSPersister; + logger: ILogger; +} + +export class SQLJSOpenFactory implements SQLOpenFactory { + constructor(protected options: SQLJSOpenOptions) {} + + openDB(): DBAdapter { + return new SQLJSDBAdapter(this.options); + } +} + +(globalThis as any).onSqliteUpdate = ( + dbP: number, + operation: string, + database: string, + table: string, + rowId: number +) => { + SQLJSDBAdapter.sharedObserver.iterateListeners((l) => l.tablesUpdated?.(dbP, operation, database, table, rowId)); +}; + +interface TableObserverListener extends BaseListener { + tablesUpdated?: (dpP: number, operation: string, database: string, table: string, rowId: number) => void; +} +class TableObserver extends BaseObserver {} + +export class SQLJSDBAdapter extends BaseObserver implements DBAdapter { + protected initPromise: Promise; + protected _db: SQLJs.Database | null; + protected tableUpdateCache: Set; + protected dbP: number | null; + protected writeScheduler: ControlledExecutor; + protected options: ResolvedSQLJSOpenOptions; + + static sharedObserver = new TableObserver(); + protected disposeListener: () => void; + + protected mutex: Mutex; + + protected getDB(): Promise { + return this.initPromise; + } + + get name() { + return this.options.dbFilename; + } + + constructor(options: SQLJSOpenOptions) { + super(); + this.options = this.resolveOptions(options); + this.initPromise = this.init(); + this._db = null; + this.tableUpdateCache = new Set(); + this.mutex = new Mutex(); + this.dbP = null; + this.disposeListener = SQLJSDBAdapter.sharedObserver.registerListener({ + tablesUpdated: (dbP: number, operation: string, database: string, table: string, rowId: number) => { + if (this.dbP !== dbP) { + // Ignore updates from other databases. + return; + } + this.tableUpdateCache.add(table); + } + }); + + this.writeScheduler = new ControlledExecutor(async (db: SQLJs.Database) => { + await this.options.persister.writeFile(db.export()); + }); + } + + protected resolveOptions(options: SQLJSOpenOptions): ResolvedSQLJSOpenOptions { + const persister = options.persister ?? { + readFile: async () => null, + writeFile: async () => {} + }; + + const logger = options.logger ?? createLogger('SQLJSDBAdapter'); + + return { + ...options, + persister, + logger + }; + } + + protected async init(): Promise { + const SQL = await SQLJs({ + locateFile: (filename: any) => `../dist/${filename}`, + print: (text) => { + this.options.logger.info(text); + }, + printErr: (text) => { + this.options.logger.error('[stderr]', text); + } + }); + const existing = await this.options.persister.readFile(); + const db = new SQL.Database(existing); + this.dbP = db['db']; + this._db = db; + return db; + } + + async close() { + const db = await this.getDB(); + this.disposeListener(); + db.close(); + } + + protected generateLockContext(): LockContext { + const execute = async (query: string, params?: any[]): Promise => { + const db = await this.getDB(); + const statement = db.prepare(query); + const rawResults: any[][] = []; + let columnNames: string[] | null = null; + try { + if (params) { + statement.bind(params); + } + while (statement.step()) { + if (!columnNames) { + columnNames = statement.getColumnNames(); + } + rawResults.push(statement.get()); + } + + const rows = rawResults.map((row) => { + return Object.fromEntries(row.map((value, index) => [columnNames![index], value])); + }); + return { + // `lastInsertId` is not available in the original version of SQL.js or its types, but it's available in the fork we use. + insertId: (db as any).lastInsertId(), + rowsAffected: db.getRowsModified(), + rows: { + _array: rows, + length: rows.length, + item: (idx: number) => rows[idx] + } + }; + } finally { + statement.free(); + } + }; + + const getAll = async (query: string, params?: any[]): Promise => { + const result = await execute(query, params); + return result.rows?._array ?? ([] as T[]); + }; + + const getOptional = async (query: string, params?: any[]): Promise => { + const results = await getAll(query, params); + return results.length > 0 ? results[0] : null; + }; + + const get = async (query: string, params?: any[]): Promise => { + const result = await getOptional(query, params); + if (!result) { + throw new Error(`No results for query: ${query}`); + } + return result; + }; + + const executeRaw = async (query: string, params?: any[]): Promise => { + const db = await this.getDB(); + const statement = db.prepare(query); + const rawResults: any[][] = []; + try { + if (params) { + statement.bind(params); + } + while (statement.step()) { + rawResults.push(statement.get()); + } + return rawResults; + } finally { + statement.free(); + } + }; + + return { + getAll, + getOptional, + get, + executeRaw, + execute + }; + } + + execute(query: string, params?: any[]): Promise { + return this.writeLock((tx) => tx.execute(query, params)); + } + + executeRaw(query: string, params?: any[]): Promise { + return this.writeLock((tx) => tx.executeRaw(query, params)); + } + + async executeBatch(query: string, params: any[][] = []): Promise { + let totalRowsAffected = 0; + const db = await this.getDB(); + + const stmt = db.prepare(query); + try { + for (const paramSet of params) { + stmt.run(paramSet); + totalRowsAffected += db.getRowsModified(); + } + + return { + rowsAffected: totalRowsAffected + }; + } finally { + stmt.free(); + } + } + + /** + * We're not using separate read/write locks here because we can't implement connection pools on top of SQL.js. + */ + readLock(fn: (tx: LockContext) => Promise, options?: DBLockOptions): Promise { + return this.writeLock(fn, options); + } + + readTransaction(fn: (tx: Transaction) => Promise, options?: DBLockOptions): Promise { + return this.readLock(async (ctx) => { + return this.internalTransaction(ctx, fn); + }); + } + + writeLock(fn: (tx: LockContext) => Promise, options?: DBLockOptions): Promise { + return this.mutex.runExclusive(async () => { + const db = await this.getDB(); + const result = await fn(this.generateLockContext()); + + this.writeScheduler.schedule(db); + + const notification: BatchedUpdateNotification = { + rawUpdates: [], + tables: Array.from(this.tableUpdateCache), + groupedUpdates: {} + }; + this.tableUpdateCache.clear(); + this.iterateListeners((l) => l.tablesUpdated?.(notification)); + return result; + }); + } + + writeTransaction(fn: (tx: Transaction) => Promise, options?: DBLockOptions): Promise { + return this.writeLock(async (ctx) => { + return this.internalTransaction(ctx, fn); + }); + } + + refreshSchema(): Promise { + return this.get("PRAGMA table_info('sqlite_master')"); + } + + getAll(sql: string, parameters?: any[]): Promise { + return this.readLock((tx) => tx.getAll(sql, parameters)); + } + + getOptional(sql: string, parameters?: any[]): Promise { + return this.readLock((tx) => tx.getOptional(sql, parameters)); + } + + get(sql: string, parameters?: any[]): Promise { + return this.readLock((tx) => tx.get(sql, parameters)); + } + + protected async internalTransaction(ctx: LockContext, fn: (tx: Transaction) => Promise): Promise { + let finalized = false; + const commit = async (): Promise => { + if (finalized) { + return { rowsAffected: 0 }; + } + finalized = true; + return ctx.execute('COMMIT'); + }; + const rollback = async (): Promise => { + if (finalized) { + return { rowsAffected: 0 }; + } + finalized = true; + return ctx.execute('ROLLBACK'); + }; + try { + await ctx.execute('BEGIN'); + const result = await fn({ + ...ctx, + commit, + rollback + }); + await commit(); + return result; + } catch (ex) { + try { + await rollback(); + } catch (ex2) { + // In rare cases, a rollback may fail. + // Safe to ignore. + } + throw ex; + } + } +} diff --git a/packages/adapter-sql-js/src/index.ts b/packages/adapter-sql-js/src/index.ts new file mode 100644 index 000000000..ed5bee1cb --- /dev/null +++ b/packages/adapter-sql-js/src/index.ts @@ -0,0 +1 @@ +export * from './SQLJSAdapter.js'; diff --git a/packages/adapter-sql-js/src/types.d.ts b/packages/adapter-sql-js/src/types.d.ts new file mode 100644 index 000000000..479d0ebda --- /dev/null +++ b/packages/adapter-sql-js/src/types.d.ts @@ -0,0 +1,4 @@ +declare module '@powersync/sql-js/dist/sql-asm.js' { + import sqljs from 'sql.js/dist/sql-asm.js'; + export default sqljs; +} diff --git a/packages/adapter-sql-js/tests/setup/db.ts b/packages/adapter-sql-js/tests/setup/db.ts new file mode 100644 index 000000000..fd09b0be1 --- /dev/null +++ b/packages/adapter-sql-js/tests/setup/db.ts @@ -0,0 +1,32 @@ +import { AbstractPowerSyncDatabase, column, PowerSyncDatabase, Schema, Table } from '@powersync/web'; +import { SQLJSOpenFactory } from '../../src/SQLJSAdapter'; + +const AppSchema = new Schema({ + users: new Table({ + name: column.text, + age: column.integer, + networth: column.real + }), + t1: new Table({ + a: column.integer, + b: column.integer, + c: column.text + }) +}); + +export const getPowerSyncDb = () => { + const database = new PowerSyncDatabase({ + database: new SQLJSOpenFactory({ + dbFilename: 'powersync-test.db', + persister: { + // in-memory db + readFile: async () => null, + writeFile: async () => {} + } + }), + + schema: AppSchema + }); + + return database; +}; diff --git a/packages/adapter-sql-js/tests/sqlite/queries.test.ts b/packages/adapter-sql-js/tests/sqlite/queries.test.ts new file mode 100644 index 000000000..5fe004f79 --- /dev/null +++ b/packages/adapter-sql-js/tests/sqlite/queries.test.ts @@ -0,0 +1,445 @@ +import { AbstractPowerSyncDatabase, LockContext } from '@powersync/common'; +import { afterEach, beforeEach, describe, expect, it } from 'vitest'; +import { getPowerSyncDb } from '../setup/db'; +import Chance from 'chance'; +import { v4 } from 'uuid'; + +const chance = new Chance(); +function randomIntFromInterval(min: number, max: number) { + // min included and max excluded + return Math.random() * (max - min) + min; +} + +function generateUserInfo() { + return { + id: v4(), + name: chance.name(), + age: chance.integer({ min: 0, max: 100 }), + networth: chance.floating({ min: 0, max: 1000000 }) + }; +} + +function createTestUser(context: LockContext) { + const { name, age, networth } = generateUserInfo(); + return context.execute('INSERT INTO users (id, name, age, networth) VALUES(uuid(), ?, ?, ?)', [name, age, networth]); +} + +describe('Raw queries', () => { + let db: AbstractPowerSyncDatabase; + + beforeEach(async () => { + db = getPowerSyncDb(); + await db.init(); + }); + + afterEach(async () => { + await db.disconnectAndClear(); + }); + + it('Insert', async () => { + const res = await createTestUser(db); + expect(res.rows?._array).to.eql([]); + expect(res.rows?.length).to.equal(0); + expect(res.rows?.item).to.be.a('function'); + }); + + it('Query without params', async () => { + const { name, age, networth } = generateUserInfo(); + await db.execute('INSERT INTO users (id, name, age, networth) VALUES(uuid(), ?, ?, ?)', [name, age, networth]); + + const res = await db.execute('SELECT name, age, networth FROM users'); + + expect(res.rows?.length).to.equal(1); + + console.log( + JSON.stringify(res.rows?._array), + JSON.stringify([ + { + name, + age, + networth + } + ]) + ); + + expect(res.rows?._array).to.eql([ + { + name, + age, + networth + } + ]); + }); + + it('Query with params', async () => { + const { id, name, age, networth } = generateUserInfo(); + await db.execute('INSERT INTO users (id, name, age, networth) VALUES(?, ?, ?, ?)', [id, name, age, networth]); + + const res = await db.execute('SELECT name, age, networth FROM users WHERE id = ?', [id]); + + expect(res.rows?._array).to.eql([ + { + name, + age, + networth + } + ]); + }); + + it('Failed insert', async () => { + const { name, networth } = generateUserInfo(); + let errorThrown = false; + try { + await db.execute('INSERT INTO usersfail (id, name, age, networth) VALUES(uuid(), ?, ?, ?)', [ + name, + name, + networth + ]); + } catch (e: any) { + errorThrown = true; + expect(typeof e).to.equal('object'); + expect(e.message).to.include(`no such table`); + } + expect(errorThrown).to.equal(true); + }); + + it('Transaction, auto commit', async () => { + const { name, age, networth } = generateUserInfo(); + + await db.writeTransaction(async (tx) => { + const res = await tx.execute('INSERT INTO "users" (id, name, age, networth) VALUES(uuid(), ?, ?, ?)', [ + name, + age, + networth + ]); + + expect(res.rows?._array).to.eql([]); + expect(res.rows?.length).to.equal(0); + expect(res.rows?.item).to.be.a('function'); + }); + + const res = await db.execute('SELECT name, age, networth FROM users'); + expect(res.rows?._array).to.eql([ + { + name, + age, + networth + } + ]); + }); + + it('Transaction, auto rollback', async () => { + const { name, age, networth } = generateUserInfo(); + + try { + await db.writeTransaction(async (tx) => { + await tx.execute('INSERT INTO "users" (id, name, age, networth) VALUES(uuid(), ?, ?, ?)', [ + name, + age, + networth + ]); + }); + } catch (error) { + expect(error).to.be.instanceOf(Error); + expect((error as Error).message) + .to.include('SQL execution error') + .and.to.include('cannot store TEXT value in INT column users.id'); + + const res = await db.execute('SELECT * FROM users'); + expect(res.rows?._array).to.eql([]); + } + }); + + it('Transaction, manual commit', async () => { + const { name, age, networth } = generateUserInfo(); + + await db.writeTransaction(async (tx) => { + await tx.execute('INSERT INTO "users" (id, name, age, networth) VALUES(uuid(), ?, ?, ?)', [name, age, networth]); + await tx.commit(); + }); + + const res = await db.execute('SELECT name, age, networth FROM users'); + expect(res.rows?._array).to.eql([ + { + name, + age, + networth + } + ]); + }); + + it('Transaction, manual rollback', async () => { + const { name, age, networth } = generateUserInfo(); + + await db.writeTransaction(async (tx) => { + await tx.execute('INSERT INTO "users" (id, name, age, networth) VALUES(uuid(), ?, ?, ?)', [name, age, networth]); + await tx.rollback(); + }); + + const res = await db.execute('SELECT * FROM users'); + expect(res.rows?._array).to.eql([]); + }); + + /** + * The lock manager will attempt to free the connection lock + * as soon as the callback resolves, but it should also + * correctly await any queued work such as tx.rollback(); + */ + it('Transaction, manual rollback, forgot await', async () => { + const { name, age, networth } = generateUserInfo(); + + await db.writeTransaction(async (tx) => { + await tx.execute('INSERT INTO "users" (id, name, age, networth) VALUES(uuid(), ?, ?, ?)', [name, age, networth]); + // Purposely forget await to this. + tx.rollback(); + }); + + const res = await db.execute('SELECT * FROM users'); + expect(res.rows?._array).to.eql([]); + }); + + it('Transaction, executed in order', async () => { + // ARRANGE: Setup for multiple transactions + const iterations = 10; + const actual: unknown[] = []; + + // ARRANGE: Generate expected data + const id = v4(); + const name = chance.name(); + const age = chance.integer(); + + // ACT: Start multiple async transactions to upsert and select the same record + const promises = []; + for (let iteration = 1; iteration <= iterations; iteration++) { + const promised = db.writeTransaction(async (tx) => { + // ACT: Upsert statement to create record / increment the value + await tx.execute( + ` + INSERT OR REPLACE INTO [users] ([id], [name], [age], [networth]) + SELECT ?, ?, ?, + IFNULL(( + SELECT [networth] + 1000 + FROM [users] + WHERE [id] = ? + ), 0) + `, + [id, name, age, id] + ); + + // ACT: Select statement to get incremented value and store it for checking later + const results = await tx.execute('SELECT [networth] FROM [users] WHERE [id] = ?', [id]); + + actual.push(results.rows?._array[0].networth); + }); + + promises.push(promised); + } + + // ACT: Wait for all transactions to complete + await Promise.all(promises); + + // ASSERT: That the expected values where returned + const expected = Array(iterations) + .fill(0) + .map((_, index) => index * 1000); + expect(actual).to.eql(expected, 'Each transaction should read a different value'); + }); + + it('Write lock, rejects on callback error', async () => { + const promised = db.writeLock(async () => { + throw new Error('Error from callback'); + }); + + // ASSERT: should return a promise that eventually rejects + expect(promised).to.have.property('then').that.is.a('function'); + try { + await promised; + expect.fail('Should not resolve'); + } catch (e) { + expect(e).to.be.a.instanceof(Error); + expect((e as Error)?.message).to.equal('Error from callback'); + } + }); + + it('Transaction, rejects on callback error', async () => { + const promised = db.writeTransaction(async () => { + throw new Error('Error from callback'); + }); + + // ASSERT: should return a promise that eventually rejects + expect(promised).to.have.property('then').that.is.a('function'); + try { + await promised; + expect.fail('Should not resolve'); + } catch (e) { + expect(e).to.be.a.instanceof(Error); + expect((e as Error)?.message).to.equal('Error from callback'); + } + }); + + it('Transaction, rejects on invalid query', async () => { + const promised = db.writeTransaction(async (tx) => { + await tx.execute('SELECT * FROM [tableThatDoesNotExist];'); + }); + + // ASSERT: should return a promise that eventually rejects + expect(promised).to.have.property('then').that.is.a('function'); + try { + await promised; + expect.fail('Should not resolve'); + } catch (e) { + expect(e).to.be.a.instanceof(Error); + expect((e as Error)?.message).to.include('no such table: tableThatDoesNotExist'); + } + }); + + it('Batch execute', async () => { + const { id: id1, name: name1, age: age1, networth: networth1 } = generateUserInfo(); + const { id: id2, name: name2, age: age2, networth: networth2 } = generateUserInfo(); + + const sql = `INSERT INTO "users" (id, name, age, networth) VALUES(?, ?, ?, ?)`; + const params = [ + [id1, name1, age1, networth1], + [id2, name2, age2, networth2] + ]; + + await db.executeBatch(sql, params); + + const expected = [ + { id: id1, name: name1, age: age1, networth: networth1 }, + { + id: id2, + name: name2, + age: age2, + networth: networth2 + } + ].sort((a, b) => a.name.localeCompare(b.name)); + + const res = await db.execute('SELECT id, name, age, networth FROM users ORDER BY name'); + expect(res.rows?._array).to.eql(expected); + }); + + it('Should queue simultaneous executions', async () => { + let order: number[] = []; + + const operationCount = 5; + // This wont resolve or free until another connection free's it + await db.writeLock(async (context) => { + await Promise.all( + Array(operationCount) + .fill(0) + .map(async (x: number, index: number) => { + try { + await context.execute('SELECT * FROM users'); + order.push(index); + } catch (ex) { + console.error(ex); + } + }) + ); + }); + + expect(order).to.deep.equal( + Array(operationCount) + .fill(0) + .map((x, index) => index) + ); + }); + + it('Should call update hook on changes', async () => { + const controller = new AbortController(); + const result = new Promise((resolve) => + db.onChange( + { + onChange: () => { + resolve(); + controller.abort(); + } + }, + { + tables: ['users'], + signal: controller.signal + } + ) + ); + + const { id, name, age, networth } = generateUserInfo(); + + await db.execute('INSERT INTO "users" (id, name, age, networth) VALUES(?, ?, ?, ?)', [id, name, age, networth]); + + await result; + }); + + it('Should reflect writeTransaction updates on read connections', async () => { + const watched = new Promise((resolve) => { + const abort = new AbortController(); + db.watch( + 'SELECT COUNT(*) as count FROM users', + [], + { + onResult: (results) => { + if (results.rows?.item(0).count == 1) { + resolve(); + abort.abort(); + } + } + }, + { + signal: abort.signal + } + ); + }); + + await db.writeTransaction(async (tx) => { + return createTestUser(tx); + }); + + // The watched query should have updated + await watched; + }); + + it('Should reflect writeLock updates on read connections ', async () => { + const numberOfUsers = 1000; + + const watched = new Promise((resolve) => { + const abort = new AbortController(); + db.watch( + 'SELECT COUNT(*) as count FROM users', + [], + { + onResult: (results) => { + if (results.rows?.item(0).count == numberOfUsers) { + resolve(); + abort.abort(); + } + } + }, + { + signal: abort.signal + } + ); + }); + + await db.writeLock(async (tx) => { + for (let i = 0; i < numberOfUsers; i++) { + await tx.execute('INSERT INTO users (id, name, age, networth) VALUES(uuid(), ?, ?, ?)', ['steven', i, 0]); + } + }); + + // The query result length for 1 item should be returned for all connections + await watched; + }); + + it('500 INSERTs', async () => { + let start = performance.now(); + for (let i = 0; i < 500; ++i) { + const n = randomIntFromInterval(0, 100000); + await db.execute(`INSERT INTO t1(id, a, b, c) VALUES(uuid(), ?, ?, ?)`, [i + 1, n, n + 'label']); + } + await db.execute('PRAGMA wal_checkpoint(RESTART)'); + let end = performance.now(); + let duration = end - start; + + expect(duration).lessThan(2000); + }); +}); diff --git a/packages/adapter-sql-js/tsconfig.json b/packages/adapter-sql-js/tsconfig.json new file mode 100644 index 000000000..59adb5a5d --- /dev/null +++ b/packages/adapter-sql-js/tsconfig.json @@ -0,0 +1,19 @@ +{ + "extends": "../../tsconfig.base", + "compilerOptions": { + "baseUrl": "./", + "jsx": "react", + "types": ["node"], + "rootDir": "src", + "outDir": "./lib", + "lib": ["esnext"], + "declaration": true, + "module": "NodeNext", + "moduleResolution": "nodenext", + "preserveConstEnums": true, + "esModuleInterop": false, + "skipLibCheck": false, + "strictNullChecks": true + }, + "include": ["src/**/*"] +} diff --git a/packages/adapter-sql-js/vendored/empty.js b/packages/adapter-sql-js/vendored/empty.js new file mode 100644 index 000000000..ff8b4c563 --- /dev/null +++ b/packages/adapter-sql-js/vendored/empty.js @@ -0,0 +1 @@ +export default {}; diff --git a/packages/adapter-sql-js/vitest.config.ts b/packages/adapter-sql-js/vitest.config.ts new file mode 100644 index 000000000..e26633c68 --- /dev/null +++ b/packages/adapter-sql-js/vitest.config.ts @@ -0,0 +1,34 @@ +import topLevelAwait from 'vite-plugin-top-level-await'; +import wasm from 'vite-plugin-wasm'; +import { defineConfig, UserConfigExport } from 'vitest/config'; + +const config: UserConfigExport = { + worker: { + format: 'es', + plugins: () => [wasm(), topLevelAwait()] + }, + optimizeDeps: { + // Don't optimise these packages as they contain web workers and WASM files. + // https://github.com/vitejs/vite/issues/11672#issuecomment-1415820673 + exclude: ['@journeyapps/wa-sqlite', '@powersync/web'], + include: ['async-mutex', 'comlink', 'bson'] + }, + plugins: [wasm(), topLevelAwait()], + test: { + isolate: false, + globals: true, + include: ['tests/**/*.test.ts'], + browser: { + enabled: true, + headless: true, + provider: 'playwright', + instances: [ + { + browser: 'chromium' + } + ] + } + } +}; + +export default defineConfig(config); diff --git a/packages/common/src/index.ts b/packages/common/src/index.ts index 40d4f7330..1e839d69f 100644 --- a/packages/common/src/index.ts +++ b/packages/common/src/index.ts @@ -41,6 +41,7 @@ export * from './client/watched/WatchedQuery.js'; export * from './utils/AbortOperation.js'; export * from './utils/BaseObserver.js'; +export * from './utils/ControlledExecutor.js'; export * from './utils/DataStream.js'; export * from './utils/Logger.js'; export * from './utils/parseQuery.js'; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index dee2c0bfd..3b28fa3b3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -125,7 +125,7 @@ importers: version: 4.0.1(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1)) '@expo/vector-icons': specifier: ^14.0.0 - version: 14.1.0(fdc5ce3de8aabd6226c79743411018d7) + version: 14.1.0(kpdfmw6ivudhnfw6o4uluiluqi) '@journeyapps/react-native-quick-sqlite': specifier: ^2.4.6 version: 2.4.6(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) @@ -146,7 +146,7 @@ importers: version: 0.1.11(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) '@react-navigation/drawer': specifier: ^7.1.1 - version: 7.4.1(62bded36bd875de6ca3ee26c42c5ea03) + version: 7.4.1(xwon3p5r2ryxkrzljplculi3hm) '@react-navigation/native': specifier: ^7.0.14 version: 7.1.10(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) @@ -170,7 +170,7 @@ importers: version: 2.1.10 expo-router: specifier: 4.0.21 - version: 4.0.21(e374635bcb9f01385d354b70deac59d5) + version: 4.0.21(7pkmiwofdx5cbd6rrboya7mm6y) expo-splash-screen: specifier: ~0.29.22 version: 0.29.24(expo@52.0.46(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@expo/metro-runtime@4.0.1(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1)))(encoding@0.1.13)(graphql@16.8.1)(react-native-webview@13.12.5(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1)) @@ -218,7 +218,7 @@ importers: version: 10.2.0 react-navigation-stack: specifier: ^2.10.4 - version: 2.10.4(cc782526f6f527a9fd49628df4caf975) + version: 2.10.4(n5q7nzlozgkktehjjhku7iswqa) typed-async-storage: specifier: ^3.1.2 version: 3.1.2 @@ -871,7 +871,7 @@ importers: version: 7.0.5(expo@52.0.46(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@expo/metro-runtime@4.0.1(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1)))(encoding@0.1.13)(graphql@16.8.1)(react-native-webview@13.12.5(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) expo-router: specifier: 4.0.21 - version: 4.0.21(b0bddf53ba1689b30337428eee4dc275) + version: 4.0.21(cpo3xaw6yrjernjvkkkt7bisia) expo-splash-screen: specifier: ~0.29.22 version: 0.29.24(expo@52.0.46(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@expo/metro-runtime@4.0.1(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1)))(encoding@0.1.13)(graphql@16.8.1)(react-native-webview@13.12.5(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1)) @@ -944,7 +944,7 @@ importers: version: 1.0.2 '@expo/vector-icons': specifier: ^14.0.3 - version: 14.1.0(fdc5ce3de8aabd6226c79743411018d7) + version: 14.1.0(kpdfmw6ivudhnfw6o4uluiluqi) '@journeyapps/react-native-quick-sqlite': specifier: ^2.4.6 version: 2.4.6(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) @@ -965,7 +965,7 @@ importers: version: 0.1.11(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) '@react-navigation/drawer': specifier: ^7.1.1 - version: 7.4.1(62bded36bd875de6ca3ee26c42c5ea03) + version: 7.4.1(xwon3p5r2ryxkrzljplculi3hm) '@react-navigation/native': specifier: ^7.0.14 version: 7.1.10(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) @@ -989,7 +989,7 @@ importers: version: 0.13.3(expo@52.0.46(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@expo/metro-runtime@4.0.1(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1)))(encoding@0.1.13)(graphql@16.8.1)(react-native-webview@13.12.5(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1)) expo-camera: specifier: ~16.0.18 - version: 16.0.18(3cdcf7b8e47f65c9a4496cca30210857) + version: 16.0.18(iufejmpajqz4jjoldpycss6ycq) expo-constants: specifier: ~17.0.8 version: 17.0.8(expo@52.0.46(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@expo/metro-runtime@4.0.1(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1)))(encoding@0.1.13)(graphql@16.8.1)(react-native-webview@13.12.5(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1)) @@ -1004,7 +1004,7 @@ importers: version: 7.0.5(expo@52.0.46(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@expo/metro-runtime@4.0.1(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1)))(encoding@0.1.13)(graphql@16.8.1)(react-native-webview@13.12.5(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) expo-router: specifier: 4.0.21 - version: 4.0.21(e374635bcb9f01385d354b70deac59d5) + version: 4.0.21(7pkmiwofdx5cbd6rrboya7mm6y) expo-secure-store: specifier: ~14.0.1 version: 14.0.1(expo@52.0.46(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@expo/metro-runtime@4.0.1(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1)))(encoding@0.1.13)(graphql@16.8.1)(react-native-webview@13.12.5(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1)) @@ -1046,7 +1046,7 @@ importers: version: 4.4.0(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) react-navigation-stack: specifier: ^2.10.4 - version: 2.10.4(cc782526f6f527a9fd49628df4caf975) + version: 2.10.4(n5q7nzlozgkktehjjhku7iswqa) devDependencies: '@babel/core': specifier: ^7.26.10 @@ -1083,7 +1083,7 @@ importers: version: 4.0.1(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1)) '@expo/vector-icons': specifier: ^14.0.2 - version: 14.1.0(fdc5ce3de8aabd6226c79743411018d7) + version: 14.1.0(kpdfmw6ivudhnfw6o4uluiluqi) '@journeyapps/react-native-quick-sqlite': specifier: ^2.4.6 version: 2.4.6(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) @@ -1110,7 +1110,7 @@ importers: version: 7.3.14(@react-navigation/native@7.1.10(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native-safe-area-context@4.12.0(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native-screens@4.4.0(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) '@react-navigation/drawer': specifier: ^7.1.1 - version: 7.4.1(62bded36bd875de6ca3ee26c42c5ea03) + version: 7.4.1(xwon3p5r2ryxkrzljplculi3hm) '@react-navigation/native': specifier: ^7.0.14 version: 7.1.10(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) @@ -1131,7 +1131,7 @@ importers: version: 14.0.3(expo@52.0.46(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@expo/metro-runtime@4.0.1(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1)))(encoding@0.1.13)(graphql@16.8.1)(react-native-webview@13.12.5(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) expo-camera: specifier: ~16.0.18 - version: 16.0.18(3cdcf7b8e47f65c9a4496cca30210857) + version: 16.0.18(iufejmpajqz4jjoldpycss6ycq) expo-constants: specifier: ~17.0.5 version: 17.0.8(expo@52.0.46(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@expo/metro-runtime@4.0.1(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1)))(encoding@0.1.13)(graphql@16.8.1)(react-native-webview@13.12.5(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1)) @@ -1149,7 +1149,7 @@ importers: version: 7.0.5(expo@52.0.46(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@expo/metro-runtime@4.0.1(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1)))(encoding@0.1.13)(graphql@16.8.1)(react-native-webview@13.12.5(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) expo-router: specifier: 4.0.21 - version: 4.0.21(e374635bcb9f01385d354b70deac59d5) + version: 4.0.21(7pkmiwofdx5cbd6rrboya7mm6y) expo-secure-store: specifier: ^14.0.1 version: 14.0.1(expo@52.0.46(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@expo/metro-runtime@4.0.1(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1)))(encoding@0.1.13)(graphql@16.8.1)(react-native-webview@13.12.5(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1)) @@ -1164,7 +1164,7 @@ importers: version: 0.2.2(expo@52.0.46(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@expo/metro-runtime@4.0.1(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1)))(encoding@0.1.13)(graphql@16.8.1)(react-native-webview@13.12.5(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1)) expo-system-ui: specifier: ~4.0.8 - version: 4.0.9(c0a3f55e662f74e948e2bd58fcbec8f1) + version: 4.0.9(gkhgpojom75kfqjgntjbsh35pm) expo-web-browser: specifier: ~14.0.2 version: 14.0.2(expo@52.0.46(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@expo/metro-runtime@4.0.1(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1)))(encoding@0.1.13)(graphql@16.8.1)(react-native-webview@13.12.5(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1)) @@ -1225,7 +1225,7 @@ importers: version: 29.7.0(@types/node@20.17.57)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.11.29)(@types/node@20.17.57)(typescript@5.8.3)) jest-expo: specifier: ~52.0.3 - version: 52.0.6(5ecd6a454ab2aef14ba34b6a53fe2748) + version: 52.0.6(k3ezlcldv4g4k2inpgpppmt2uy) react-test-renderer: specifier: 18.3.1 version: 18.3.1(react@18.3.1) @@ -1637,6 +1637,37 @@ importers: specifier: ^5.5.3 version: 5.8.3 + packages/adapter-sql-js: + dependencies: + '@powersync/common': + specifier: workspace:^ + version: link:../common + async-mutex: + specifier: ^0.4.0 + version: 0.4.1 + devDependencies: + '@powersync/sql-js': + specifier: 0.0.1 + version: 0.0.1 + '@powersync/web': + specifier: workspace:* + version: link:../web + '@rollup/plugin-alias': + specifier: ^5.1.0 + version: 5.1.1(rollup@4.14.3) + '@types/sql.js': + specifier: ^1.4.9 + version: 1.4.9 + chance: + specifier: ^1.1.9 + version: 1.1.13 + rollup: + specifier: 4.14.3 + version: 4.14.3 + uuid: + specifier: ^11.1.0 + version: 11.1.0 + packages/attachments: devDependencies: '@powersync/common': @@ -1727,7 +1758,7 @@ importers: version: 20.17.57 drizzle-orm: specifier: ^0.35.2 - version: 0.35.3(@libsql/client-wasm@0.15.8)(@op-engineering/op-sqlite@14.0.2(react-native@0.78.0(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli-server-api@15.1.3)(@types/react@19.1.6)(react@19.0.0))(react@19.0.0))(@types/react@19.1.6)(kysely@0.28.2)(react@19.0.0) + version: 0.35.3(@libsql/client-wasm@0.15.8)(@op-engineering/op-sqlite@14.0.2(react-native@0.78.0(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli-server-api@15.1.3)(@types/react@19.1.6)(react@19.0.0))(react@19.0.0))(@types/react@19.1.6)(@types/sql.js@1.4.9)(kysely@0.28.2)(react@19.0.0)(sql.js@1.13.0) vite: specifier: ^6.1.0 version: 6.3.5(@types/node@20.17.57)(jiti@2.4.2)(less@4.2.2)(lightningcss@1.30.1)(sass@1.89.1)(terser@5.40.0)(tsx@4.19.4)(yaml@2.8.0) @@ -1795,7 +1826,7 @@ importers: version: 1.4.2 drizzle-orm: specifier: ^0.35.2 - version: 0.35.3(@libsql/client-wasm@0.15.8)(@op-engineering/op-sqlite@14.0.2(react-native@0.78.0(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli-server-api@15.1.3)(@types/react@19.1.6)(react@19.0.0))(react@19.0.0))(@types/react@19.1.6)(kysely@0.28.2)(react@19.0.0) + version: 0.35.3(@libsql/client-wasm@0.15.8)(@op-engineering/op-sqlite@14.0.2(react-native@0.78.0(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli-server-api@15.1.3)(@types/react@19.1.6)(react@19.0.0))(react@19.0.0))(@types/react@19.1.6)(@types/sql.js@1.4.9)(kysely@0.28.2)(react@19.0.0)(sql.js@1.13.0) rollup: specifier: 4.14.3 version: 4.14.3 @@ -6501,6 +6532,9 @@ packages: '@powersync/better-sqlite3@0.2.0': resolution: {integrity: sha512-8otwueqHJqwilUz/vLENlpMp2c4k/TV6hGX016XrZxSkizDAil99yRm7lAVwpbYYGuSgyzidyDh6vy6PY+m4kw==} + '@powersync/sql-js@0.0.1': + resolution: {integrity: sha512-f1ZOPN1e8UjKqz/eQNwqmfr2IZlRlYp0BrVHGCrKh1KK+hY0o5DtdmzlZamvWYK+F73FK/Jb/E6i2xfT5mwsZA==} + '@radix-ui/react-compose-refs@1.0.0': resolution: {integrity: sha512-0KaSv6sx787/hK3eF53iOkiSLwAGlFMx5lotrqD2pTjB18KbybKoEIgkNZTKC60YECDQTKGTRcDBILwZVqVKvA==} peerDependencies: @@ -8726,6 +8760,9 @@ packages: '@types/deep-eql@4.0.2': resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} + '@types/emscripten@1.40.1': + resolution: {integrity: sha512-sr53lnYkQNhjHNN0oJDdUm5564biioI5DuOpycufDVK7D3y+GR3oUswe2rlwY1nPNyusHbrJ9WoTyIHl4/Bpwg==} + '@types/eslint-scope@3.7.7': resolution: {integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==} @@ -8961,6 +8998,9 @@ packages: '@types/sockjs@0.3.36': resolution: {integrity: sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==} + '@types/sql.js@1.4.9': + resolution: {integrity: sha512-ep8b36RKHlgWPqjNG9ToUrPiwkhwh0AEzy883mO5Xnd+cL6VBH1EvSjBAAuxLUFF2Vn/moE3Me6v9E1Lo+48GQ==} + '@types/ssri@7.1.5': resolution: {integrity: sha512-odD/56S3B51liILSk5aXJlnYt99S6Rt9EFDDqGtJM26rKHApHcwyU/UoYHrzKkdkHMAIquGWCuHtQTbes+FRQw==} @@ -18636,6 +18676,9 @@ packages: resolution: {integrity: sha512-ZjqOfJGuB97UeHzTJoTbadlM0h9ynehtSTHNUbGfXR4HZ4rCIoD2oIW91W+A5oE76k8hl0Uz5GD8Sx3Pt9Xa3w==} hasBin: true + sql.js@1.13.0: + resolution: {integrity: sha512-RJbVP1HRDlUUXahJ7VMTcu9Rm1Nzw+EBpoPr94vnbD4LwR715F3CcxE2G2k45PewcaZ57pjetYa+LoSJLAASgA==} + srcset@4.0.0: resolution: {integrity: sha512-wvLeHgcVHKO8Sc/H/5lkGreJQVeYMm9rlmt8PuR1xE31rIuXhuzznUUqAt8MqLhB3MqJdFzlNAfpcWnxiFUcPw==} engines: {node: '>=12'} @@ -25108,13 +25151,13 @@ snapshots: '@expo/timeago.js@1.0.0': {} - '@expo/vector-icons@14.1.0(99f35dc9d27b76831378288730881035)': + '@expo/vector-icons@14.1.0(ka6rgkktlsuut5gotrymd2sdni)': dependencies: expo-font: 13.0.4(expo@52.0.46(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@expo/metro-runtime@4.0.1(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1)))(encoding@0.1.13)(graphql@16.8.1)(react-native-webview@13.12.5(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react@18.3.1) react: 18.3.1 react-native: 0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1) - '@expo/vector-icons@14.1.0(fdc5ce3de8aabd6226c79743411018d7)': + '@expo/vector-icons@14.1.0(kpdfmw6ivudhnfw6o4uluiluqi)': dependencies: expo-font: 13.0.4(expo@52.0.46(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@expo/metro-runtime@4.0.1(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1)))(encoding@0.1.13)(graphql@16.8.1)(react-native-webview@13.12.5(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react@18.3.1) react: 18.3.1 @@ -27140,6 +27183,8 @@ snapshots: dependencies: bindings: 1.5.0 + '@powersync/sql-js@0.0.1': {} + '@radix-ui/react-compose-refs@1.0.0(react@18.3.1)': dependencies: '@babel/runtime': 7.27.6 @@ -28583,23 +28628,7 @@ snapshots: use-latest-callback: 0.2.3(react@18.3.1) use-sync-external-store: 1.5.0(react@18.3.1) - '@react-navigation/drawer@7.4.1(62bded36bd875de6ca3ee26c42c5ea03)': - dependencies: - '@react-navigation/elements': 2.4.3(@react-navigation/native@7.1.10(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native-safe-area-context@4.12.0(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) - '@react-navigation/native': 7.1.10(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) - color: 4.2.3 - react: 18.3.1 - react-native: 0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1) - react-native-drawer-layout: 4.1.10(react-native-gesture-handler@2.20.2(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native-reanimated@3.16.7(@babel/core@7.26.10)(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) - react-native-gesture-handler: 2.20.2(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) - react-native-reanimated: 3.16.7(@babel/core@7.26.10)(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) - react-native-safe-area-context: 4.12.0(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) - react-native-screens: 4.4.0(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) - use-latest-callback: 0.2.3(react@18.3.1) - transitivePeerDependencies: - - '@react-native-masked-view/masked-view' - - '@react-navigation/drawer@7.4.1(f2502081aada8c22c3fd2dbf46b9d114)': + '@react-navigation/drawer@7.4.1(nyxmcqdttlojx3ihgax6eihdpu)': dependencies: '@react-navigation/elements': 2.4.3(@react-navigation/native@7.1.10(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native-safe-area-context@4.12.0(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) '@react-navigation/native': 7.1.10(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) @@ -28616,6 +28645,22 @@ snapshots: - '@react-native-masked-view/masked-view' optional: true + '@react-navigation/drawer@7.4.1(xwon3p5r2ryxkrzljplculi3hm)': + dependencies: + '@react-navigation/elements': 2.4.3(@react-navigation/native@7.1.10(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native-safe-area-context@4.12.0(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) + '@react-navigation/native': 7.1.10(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) + color: 4.2.3 + react: 18.3.1 + react-native: 0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1) + react-native-drawer-layout: 4.1.10(react-native-gesture-handler@2.20.2(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native-reanimated@3.16.7(@babel/core@7.26.10)(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) + react-native-gesture-handler: 2.20.2(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) + react-native-reanimated: 3.16.7(@babel/core@7.26.10)(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) + react-native-safe-area-context: 4.12.0(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) + react-native-screens: 4.4.0(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) + use-latest-callback: 0.2.3(react@18.3.1) + transitivePeerDependencies: + - '@react-native-masked-view/masked-view' + '@react-navigation/elements@2.4.3(@react-navigation/native@7.1.10(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native-safe-area-context@4.12.0(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1)': dependencies: '@react-navigation/native': 7.1.10(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) @@ -30660,6 +30705,8 @@ snapshots: '@types/deep-eql@4.0.2': {} + '@types/emscripten@1.40.1': {} + '@types/eslint-scope@3.7.7': dependencies: '@types/eslint': 9.6.1 @@ -30937,6 +30984,11 @@ snapshots: dependencies: '@types/node': 20.17.57 + '@types/sql.js@1.4.9': + dependencies: + '@types/emscripten': 1.40.1 + '@types/node': 20.17.57 + '@types/ssri@7.1.5': dependencies: '@types/node': 20.17.57 @@ -34325,14 +34377,16 @@ snapshots: dotenv@16.5.0: {} - drizzle-orm@0.35.3(@libsql/client-wasm@0.15.8)(@op-engineering/op-sqlite@14.0.2(react-native@0.78.0(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli-server-api@15.1.3)(@types/react@19.1.6)(react@19.0.0))(react@19.0.0))(@types/react@19.1.6)(kysely@0.28.2)(react@19.0.0): + drizzle-orm@0.35.3(@libsql/client-wasm@0.15.8)(@op-engineering/op-sqlite@14.0.2(react-native@0.78.0(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli-server-api@15.1.3)(@types/react@19.1.6)(react@19.0.0))(react@19.0.0))(@types/react@19.1.6)(@types/sql.js@1.4.9)(kysely@0.28.2)(react@19.0.0)(sql.js@1.13.0): dependencies: '@libsql/client-wasm': 0.15.8 optionalDependencies: '@op-engineering/op-sqlite': 14.0.2(react-native@0.78.0(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli-server-api@15.1.3)(@types/react@19.1.6)(react@19.0.0))(react@19.0.0) '@types/react': 19.1.6 + '@types/sql.js': 1.4.9 kysely: 0.28.2 react: 19.0.0 + sql.js: 1.13.0 dtrace-provider@0.8.8: dependencies: @@ -35549,7 +35603,7 @@ snapshots: expo: 52.0.46(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@expo/metro-runtime@4.0.1(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1)))(encoding@0.1.13)(graphql@16.8.1)(react-native-webview@13.12.5(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) semver: 7.7.2 - expo-camera@16.0.18(3cdcf7b8e47f65c9a4496cca30210857): + expo-camera@16.0.18(iufejmpajqz4jjoldpycss6ycq): dependencies: expo: 52.0.46(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@expo/metro-runtime@4.0.1(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1)))(encoding@0.1.13)(graphql@16.8.1)(react-native-webview@13.12.5(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) invariant: 2.2.4 @@ -35709,29 +35763,29 @@ snapshots: dependencies: invariant: 2.2.4 - expo-router@4.0.21(b0bddf53ba1689b30337428eee4dc275): + expo-router@4.0.21(7pkmiwofdx5cbd6rrboya7mm6y): dependencies: - '@expo/metro-runtime': 4.0.1(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1)) + '@expo/metro-runtime': 4.0.1(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1)) '@expo/server': 0.5.3 '@radix-ui/react-slot': 1.0.1(react@18.3.1) - '@react-navigation/bottom-tabs': 7.3.14(@react-navigation/native@7.1.10(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native-safe-area-context@4.12.0(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native-screens@4.4.0(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) - '@react-navigation/native': 7.1.10(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) - '@react-navigation/native-stack': 7.3.14(@react-navigation/native@7.1.10(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native-safe-area-context@4.12.0(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native-screens@4.4.0(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) + '@react-navigation/bottom-tabs': 7.3.14(@react-navigation/native@7.1.10(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native-safe-area-context@4.12.0(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native-screens@4.4.0(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) + '@react-navigation/native': 7.1.10(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) + '@react-navigation/native-stack': 7.3.14(@react-navigation/native@7.1.10(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native-safe-area-context@4.12.0(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native-screens@4.4.0(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) client-only: 0.0.1 - expo: 52.0.46(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@expo/metro-runtime@4.0.1(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1)))(encoding@0.1.13)(graphql@16.8.1)(react-native-webview@13.12.5(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) - expo-constants: 17.0.8(expo@52.0.46(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@expo/metro-runtime@4.0.1(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1)))(encoding@0.1.13)(graphql@16.8.1)(react-native-webview@13.12.5(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1)) - expo-linking: 7.0.5(expo@52.0.46(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@expo/metro-runtime@4.0.1(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1)))(encoding@0.1.13)(graphql@16.8.1)(react-native-webview@13.12.5(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) + expo: 52.0.46(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@expo/metro-runtime@4.0.1(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1)))(encoding@0.1.13)(graphql@16.8.1)(react-native-webview@13.12.5(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) + expo-constants: 17.0.8(expo@52.0.46(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@expo/metro-runtime@4.0.1(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1)))(encoding@0.1.13)(graphql@16.8.1)(react-native-webview@13.12.5(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1)) + expo-linking: 7.0.5(expo@52.0.46(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@expo/metro-runtime@4.0.1(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1)))(encoding@0.1.13)(graphql@16.8.1)(react-native-webview@13.12.5(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) react-helmet-async: 1.3.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react-native-helmet-async: 2.0.4(react@18.3.1) - react-native-is-edge-to-edge: 1.1.7(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) - react-native-safe-area-context: 4.12.0(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) - react-native-screens: 4.4.0(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) + react-native-is-edge-to-edge: 1.1.7(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) + react-native-safe-area-context: 4.12.0(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) + react-native-screens: 4.4.0(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) schema-utils: 4.3.2 semver: 7.6.3 server-only: 0.0.1 optionalDependencies: - '@react-navigation/drawer': 7.4.1(f2502081aada8c22c3fd2dbf46b9d114) - react-native-reanimated: 3.16.7(@babel/core@7.26.10)(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) + '@react-navigation/drawer': 7.4.1(xwon3p5r2ryxkrzljplculi3hm) + react-native-reanimated: 3.16.7(@babel/core@7.26.10)(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) transitivePeerDependencies: - '@react-native-masked-view/masked-view' - react @@ -35739,29 +35793,29 @@ snapshots: - react-native - supports-color - expo-router@4.0.21(e374635bcb9f01385d354b70deac59d5): + expo-router@4.0.21(cpo3xaw6yrjernjvkkkt7bisia): dependencies: - '@expo/metro-runtime': 4.0.1(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1)) + '@expo/metro-runtime': 4.0.1(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1)) '@expo/server': 0.5.3 '@radix-ui/react-slot': 1.0.1(react@18.3.1) - '@react-navigation/bottom-tabs': 7.3.14(@react-navigation/native@7.1.10(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native-safe-area-context@4.12.0(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native-screens@4.4.0(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) - '@react-navigation/native': 7.1.10(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) - '@react-navigation/native-stack': 7.3.14(@react-navigation/native@7.1.10(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native-safe-area-context@4.12.0(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native-screens@4.4.0(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) + '@react-navigation/bottom-tabs': 7.3.14(@react-navigation/native@7.1.10(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native-safe-area-context@4.12.0(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native-screens@4.4.0(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) + '@react-navigation/native': 7.1.10(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) + '@react-navigation/native-stack': 7.3.14(@react-navigation/native@7.1.10(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native-safe-area-context@4.12.0(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native-screens@4.4.0(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) client-only: 0.0.1 - expo: 52.0.46(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@expo/metro-runtime@4.0.1(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1)))(encoding@0.1.13)(graphql@16.8.1)(react-native-webview@13.12.5(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) - expo-constants: 17.0.8(expo@52.0.46(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@expo/metro-runtime@4.0.1(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1)))(encoding@0.1.13)(graphql@16.8.1)(react-native-webview@13.12.5(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1)) - expo-linking: 7.0.5(expo@52.0.46(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@expo/metro-runtime@4.0.1(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1)))(encoding@0.1.13)(graphql@16.8.1)(react-native-webview@13.12.5(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) + expo: 52.0.46(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@expo/metro-runtime@4.0.1(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1)))(encoding@0.1.13)(graphql@16.8.1)(react-native-webview@13.12.5(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) + expo-constants: 17.0.8(expo@52.0.46(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@expo/metro-runtime@4.0.1(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1)))(encoding@0.1.13)(graphql@16.8.1)(react-native-webview@13.12.5(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1)) + expo-linking: 7.0.5(expo@52.0.46(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@expo/metro-runtime@4.0.1(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1)))(encoding@0.1.13)(graphql@16.8.1)(react-native-webview@13.12.5(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) react-helmet-async: 1.3.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react-native-helmet-async: 2.0.4(react@18.3.1) - react-native-is-edge-to-edge: 1.1.7(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) - react-native-safe-area-context: 4.12.0(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) - react-native-screens: 4.4.0(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) + react-native-is-edge-to-edge: 1.1.7(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) + react-native-safe-area-context: 4.12.0(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) + react-native-screens: 4.4.0(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) schema-utils: 4.3.2 semver: 7.6.3 server-only: 0.0.1 optionalDependencies: - '@react-navigation/drawer': 7.4.1(62bded36bd875de6ca3ee26c42c5ea03) - react-native-reanimated: 3.16.7(@babel/core@7.26.10)(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) + '@react-navigation/drawer': 7.4.1(nyxmcqdttlojx3ihgax6eihdpu) + react-native-reanimated: 3.16.7(@babel/core@7.26.10)(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) transitivePeerDependencies: - '@react-native-masked-view/masked-view' - react @@ -35802,7 +35856,7 @@ snapshots: expo: 52.0.46(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@expo/metro-runtime@4.0.1(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1)))(encoding@0.1.13)(graphql@16.8.1)(react-native-webview@13.12.5(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) sf-symbols-typescript: 2.1.0 - expo-system-ui@4.0.9(c0a3f55e662f74e948e2bd58fcbec8f1): + expo-system-ui@4.0.9(gkhgpojom75kfqjgntjbsh35pm): dependencies: '@react-native/normalize-colors': 0.76.8 debug: 4.4.1(supports-color@8.1.1) @@ -35830,7 +35884,7 @@ snapshots: '@expo/config-plugins': 9.0.17 '@expo/fingerprint': 0.11.11 '@expo/metro-config': 0.19.12 - '@expo/vector-icons': 14.1.0(99f35dc9d27b76831378288730881035) + '@expo/vector-icons': 14.1.0(ka6rgkktlsuut5gotrymd2sdni) babel-preset-expo: 12.0.11(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10)) expo-asset: 11.0.5(expo@52.0.46(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@expo/metro-runtime@4.0.1(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1)))(encoding@0.1.13)(graphql@16.8.1)(react-native-webview@13.12.5(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) expo-constants: 17.0.8(expo@52.0.46(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@expo/metro-runtime@4.0.1(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1)))(encoding@0.1.13)(graphql@16.8.1)(react-native-webview@13.12.5(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1)) @@ -35866,7 +35920,7 @@ snapshots: '@expo/config-plugins': 9.0.17 '@expo/fingerprint': 0.11.11 '@expo/metro-config': 0.19.12 - '@expo/vector-icons': 14.1.0(fdc5ce3de8aabd6226c79743411018d7) + '@expo/vector-icons': 14.1.0(kpdfmw6ivudhnfw6o4uluiluqi) babel-preset-expo: 12.0.11(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10)) expo-asset: 11.0.5(expo@52.0.46(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@expo/metro-runtime@4.0.1(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1)))(encoding@0.1.13)(graphql@16.8.1)(react-native-webview@13.12.5(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) expo-constants: 17.0.8(expo@52.0.46(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@expo/metro-runtime@4.0.1(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1)))(encoding@0.1.13)(graphql@16.8.1)(react-native-webview@13.12.5(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1)) @@ -38053,7 +38107,7 @@ snapshots: jest-mock: 29.7.0 jest-util: 29.7.0 - jest-expo@52.0.6(5ecd6a454ab2aef14ba34b6a53fe2748): + jest-expo@52.0.6(k3ezlcldv4g4k2inpgpppmt2uy): dependencies: '@expo/config': 10.0.11 '@expo/json-file': 9.1.4 @@ -43136,7 +43190,7 @@ snapshots: - supports-color - utf-8-validate - react-navigation-stack@2.10.4(cc782526f6f527a9fd49628df4caf975): + react-navigation-stack@2.10.4(n5q7nzlozgkktehjjhku7iswqa): dependencies: '@react-native-community/masked-view': 0.1.11(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.27.2(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.3))(@types/react@18.3.23)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) color: 3.2.1 @@ -44469,6 +44523,9 @@ snapshots: argparse: 2.0.1 nearley: 2.20.1 + sql.js@1.13.0: + optional: true + srcset@4.0.0: {} ssri@10.0.6: @@ -46147,7 +46204,7 @@ snapshots: dependencies: esbuild: 0.25.4 postcss: 8.5.4 - rollup: 4.34.8 + rollup: 4.41.1 optionalDependencies: '@types/node': 22.15.29 fsevents: 2.3.3