diff --git a/README.md b/README.md index b5a8604..68129e6 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ Firebase integration for [Effect](https://effect.website). Provides schemas, mod | [effect-firebase](./packages/effect-firebase) | Core schemas, models, and query builder | | [@effect-firebase/admin](./packages/admin) | Firebase Admin SDK + Cloud Functions | | [@effect-firebase/client](./packages/client) | Firebase Client SDK | +| [@effect-firebase/react-native](./packages/react-native) | React Native Firebase SDK | | [@effect-firebase/mock](./packages/mock) | In-memory mock for testing | ## Guides diff --git a/packages/react-native/README.md b/packages/react-native/README.md new file mode 100644 index 0000000..f2d9498 --- /dev/null +++ b/packages/react-native/README.md @@ -0,0 +1,47 @@ +# @effect-firebase/react-native + +React Native Firebase integration for Effect Firebase. Provides a `FirestoreService` implementation backed by [`@react-native-firebase`](https://rnfirebase.io) for use in React Native applications. + +## Installation + +```bash +npm install @effect-firebase/react-native effect-firebase effect +npm install @react-native-firebase/app @react-native-firebase/firestore +``` + +Requires `@react-native-firebase/*` v24 or later (the modular API). The Firebase app is configured natively (via `google-services.json` / `GoogleService-Info.plist`) — no JavaScript `initializeApp` call is needed. + +## Usage + +```typescript +import { Effect } from 'effect'; +import { Client } from '@effect-firebase/react-native'; +import { PostRepository } from './repositories/post-repository'; +import { Query } from 'effect-firebase'; + +const program = Effect.gen(function* () { + const repo = yield* PostRepository; + const posts = yield* repo.query( + Query.and( + Query.where('status', '==', 'published'), + Query.orderBy('createdAt', 'desc'), + Query.limit(10), + ), + ); + return posts; +}).pipe(Effect.provide(PostRepository), Effect.provide(Client.layer())); + +Effect.runPromise(program).then(console.log); +``` + +## Layer options + +```typescript +Client.layer(); // uses the default (natively configured) Firebase app +Client.layer({ app }); // uses the provided app from getApp() +Client.layer({ firestore }); // uses a Firestore instance directly +``` + +## License + +MIT diff --git a/packages/react-native/eslint.config.mjs b/packages/react-native/eslint.config.mjs new file mode 100644 index 0000000..50874fb --- /dev/null +++ b/packages/react-native/eslint.config.mjs @@ -0,0 +1,10 @@ +import baseConfig from '../../eslint.config.mjs'; + +export default [ + ...baseConfig, + { + files: ['**/*.ts', '**/*.js'], + // Override or add rules here + rules: {}, + }, +]; diff --git a/packages/react-native/package.json b/packages/react-native/package.json new file mode 100644 index 0000000..9a7ddb4 --- /dev/null +++ b/packages/react-native/package.json @@ -0,0 +1,47 @@ +{ + "name": "@effect-firebase/react-native", + "version": "1.0.0-beta.5", + "type": "module", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/fwal/effect-firebase", + "directory": "packages/react-native" + }, + "private": false, + "main": "./dist/index.js", + "module": "./dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + "./package.json": "./package.json", + ".": { + "@effect-firebase/source": "./src/index.ts", + "types": "./dist/index.d.ts", + "import": "./dist/index.js", + "default": "./dist/index.js" + } + }, + "files": [ + "dist", + "!**/*.tsbuildinfo" + ], + "dependencies": { + "tslib": "^2.8.1" + }, + "devDependencies": { + "@react-native-firebase/app": "catalog:", + "@react-native-firebase/firestore": "catalog:", + "effect": "catalog:", + "effect-firebase": "workspace:*" + }, + "peerDependencies": { + "@react-native-firebase/app": ">=24.0.0", + "@react-native-firebase/firestore": ">=24.0.0", + "effect": "catalog:", + "effect-firebase": "workspace:*" + }, + "publishConfig": { + "access": "public", + "provenance": true + } +} diff --git a/packages/react-native/src/index.ts b/packages/react-native/src/index.ts new file mode 100644 index 0000000..e1b2862 --- /dev/null +++ b/packages/react-native/src/index.ts @@ -0,0 +1,3 @@ +export * as Firestore from './lib/firestore/firestore-service.js'; +export * as Client from './lib/client.js'; +export * as App from './lib/app.js'; diff --git a/packages/react-native/src/lib/app.ts b/packages/react-native/src/lib/app.ts new file mode 100644 index 0000000..360eb1f --- /dev/null +++ b/packages/react-native/src/lib/app.ts @@ -0,0 +1,15 @@ +import type { FirebaseApp } from '@react-native-firebase/app'; +import { Layer, Context } from 'effect'; + +export interface AppService { + readonly getApp: () => FirebaseApp; +} + +export class App extends Context.Service()( + '@effect-firebase/react-native/App', +) {} + +export const layer = (app: FirebaseApp): Layer.Layer => + Layer.succeed(App, { + getApp: () => app, + }); diff --git a/packages/react-native/src/lib/client.ts b/packages/react-native/src/lib/client.ts new file mode 100644 index 0000000..e722b81 --- /dev/null +++ b/packages/react-native/src/lib/client.ts @@ -0,0 +1,83 @@ +import { getApp, type FirebaseApp } from '@react-native-firebase/app'; +import type { Firestore } from '@react-native-firebase/firestore'; +import { Layer } from 'effect'; +import { + layer as firestoreLayerLive, + layerFromFirestore as firestoreLayerFromFirestore, +} from './firestore/firestore-service.js'; +import { type FirestoreService } from 'effect-firebase'; +import { layer as appLayer } from './app.js'; + +export interface LayerOptions { + /** + * Explicit Firebase app instance to use. + */ + readonly app?: FirebaseApp; + /** + * Explicit Firestore instance to use. + * When provided, the app option is ignored. + */ + readonly firestore?: Firestore; +} + +type ReadyLayer = Layer.Layer; + +const resolveApp = (app?: FirebaseApp): FirebaseApp => { + if (app) { + return app; + } + + try { + return getApp(); + } catch (error) { + throw new Error( + 'Client.layer: no Firebase app available. Pass { app } or ensure the default app is configured natively before calling Client.layer().', + { cause: error }, + ); + } +}; + +/** + * Creates the default client layer with Firestore service. + * + * Resolution order: + * 1. `options.firestore` + * 2. `options.app` + * 3. default app (`getApp()`) + * + * @throws If both `app` and `firestore` are provided. + * @throws If no app is available and no `firestore` is provided. + * + * @example + * ```ts + * import { Client } from '@effect-firebase/react-native'; + * + * const layer = Client.layer(); + * ``` + * + * @example + * ```ts + * import { getApp } from '@react-native-firebase/app'; + * import { Client } from '@effect-firebase/react-native'; + * + * const layer = Client.layer({ app: getApp() }); + * ``` + */ +export function layer(options: LayerOptions & { app: FirebaseApp }): ReadyLayer; +export function layer( + options: LayerOptions & { firestore: Firestore }, +): ReadyLayer; +export function layer(options?: LayerOptions): ReadyLayer; +export function layer(options: LayerOptions = {}): ReadyLayer { + if (options.app && options.firestore) { + throw new Error( + 'Client.layer: pass either { app } or { firestore }, not both.', + ); + } + + if (options.firestore) { + return firestoreLayerFromFirestore(options.firestore); + } + + return Layer.provide(firestoreLayerLive, appLayer(resolveApp(options.app))); +} diff --git a/packages/react-native/src/lib/firestore/converter.spec.ts b/packages/react-native/src/lib/firestore/converter.spec.ts new file mode 100644 index 0000000..ecbaaaf --- /dev/null +++ b/packages/react-native/src/lib/firestore/converter.spec.ts @@ -0,0 +1,305 @@ +import { DateTime } from 'effect'; +import { describe, expect, it, vi } from 'vitest'; +import { firestoreDecode, firestoreEncode } from './converter.js'; +import { FirestoreSchema, Firestore as FirestoreHelper } from 'effect-firebase'; + +// The real @react-native-firebase/firestore pulls in react-native native +// module glue that cannot load under vitest, so the SDK values used by the +// converter are replaced with structurally equivalent fakes. +vi.mock('@react-native-firebase/firestore', () => { + class Timestamp { + constructor( + readonly seconds: number, + readonly nanoseconds: number, + ) {} + static fromMillis(millis: number) { + return new Timestamp(Math.floor(millis / 1000), (millis % 1000) * 1e6); + } + toMillis() { + return this.seconds * 1000 + this.nanoseconds / 1e6; + } + } + class GeoPoint { + constructor( + readonly latitude: number, + readonly longitude: number, + ) {} + } + class FieldValue { + constructor( + readonly _type: string, + readonly _values: ReadonlyArray, + ) {} + } + return { + Timestamp, + GeoPoint, + FieldValue, + serverTimestamp: () => new FieldValue('serverTimestamp', []), + deleteField: () => new FieldValue('delete', []), + arrayUnion: (...values: unknown[]) => new FieldValue('arrayUnion', values), + arrayRemove: (...values: unknown[]) => + new FieldValue('arrayRemove', values), + doc: (_db: unknown, path: string) => ({ + id: path.split('/').pop(), + path, + firestore: {}, + get: async () => undefined, + }), + }; +}); + +// Imported after the mock so the spec and converter share the same fakes. +import { + arrayRemove, + arrayUnion, + deleteField, + GeoPoint as FirebaseGeoPoint, + serverTimestamp, + Timestamp as FirebaseTimestamp, + Firestore, +} from '@react-native-firebase/firestore'; + +describe('Firestore Converter', () => { + describe('firestoreDecode', () => { + it('should convert Firestore Timestamp to FirestoreSchema.Timestamp', () => { + const firebaseTimestamp = new FirebaseTimestamp(1705315800, 123000000); + + const result = firestoreDecode({ + title: 'Test Post', + createdAt: firebaseTimestamp, + }); + + expect(result.title).toBe('Test Post'); + expect(result.createdAt).toBeInstanceOf(FirestoreSchema.Timestamp); + expect(result.createdAt.seconds).toBe(1705315800); + expect(result.createdAt.nanoseconds).toBe(123000000); + }); + + it('should handle nested timestamps', () => { + const firebaseTimestamp = new FirebaseTimestamp(1705315800, 0); + + const result = firestoreDecode({ + post: { + createdAt: firebaseTimestamp, + title: 'Nested', + }, + }); + + expect(result.post.createdAt).toBeInstanceOf(FirestoreSchema.Timestamp); + }); + + it('should handle timestamps in arrays', () => { + const firebaseTimestamp = new FirebaseTimestamp(1705315800, 0); + + const result = firestoreDecode({ + timestamps: [firebaseTimestamp, firebaseTimestamp], + }); + + expect(result.timestamps[0]).toBeInstanceOf(FirestoreSchema.Timestamp); + expect(result.timestamps[1]).toBeInstanceOf(FirestoreSchema.Timestamp); + }); + + it('should preserve null and undefined values', () => { + const result = firestoreDecode({ + nullValue: null, + undefinedValue: undefined, + stringValue: 'test', + }); + + expect(result.nullValue).toBeNull(); + expect(result.undefinedValue).toBeUndefined(); + expect(result.stringValue).toBe('test'); + }); + + it('should NOT convert null to Timestamp', () => { + const result = firestoreDecode({ + createdAt: null, + }); + + // null should stay null, not be converted to Timestamp + expect(result.createdAt).toBeNull(); + }); + + it('should convert document references to FirestoreSchema.Reference', () => { + const result = firestoreDecode({ + author: { + id: '1', + path: 'users/1', + firestore: {}, + get: async () => undefined, + }, + }); + + expect(result.author).toBeInstanceOf(FirestoreSchema.Reference); + expect(result.author.path).toBe('users/1'); + }); + }); + + describe('firestoreEncode', () => { + const fakeFirestore = {} as unknown as Firestore; + + it('should convert FirestoreSchema.Timestamp to Firestore Timestamp', () => { + const result = firestoreEncode( + fakeFirestore, + FirestoreSchema.Timestamp.fromMillis(1705315800123), + ); + + expect(result).toBeInstanceOf(FirebaseTimestamp); + expect((result as FirebaseTimestamp).seconds).toBe(1705315800); + expect((result as FirebaseTimestamp).nanoseconds).toBe(123000000); + }); + + it('should convert Effect DateTime to Firestore Timestamp', () => { + const result = firestoreEncode( + fakeFirestore, + DateTime.makeUnsafe(1705315800123), + ); + + expect(result).toBeInstanceOf(FirebaseTimestamp); + expect((result as FirebaseTimestamp).toMillis()).toBe(1705315800123); + }); + + it('should convert Effect DateTime nested in objects and arrays', () => { + const result = firestoreEncode(fakeFirestore, { + createdAt: DateTime.makeUnsafe(1705315800123), + history: [DateTime.makeUnsafe(1705315800000)], + }) as Record; + + expect(result.createdAt).toBeInstanceOf(FirebaseTimestamp); + expect((result.history as unknown[])[0]).toBeInstanceOf( + FirebaseTimestamp, + ); + }); + + it('should convert FirestoreSchema.GeoPoint to Firestore GeoPoint', () => { + const result = firestoreEncode( + fakeFirestore, + new FirestoreSchema.GeoPoint({ + latitude: 55.6761, + longitude: 12.5683, + }), + ); + + expect(result).toBeInstanceOf(FirebaseGeoPoint); + expect((result as FirebaseGeoPoint).latitude).toBe(55.6761); + expect((result as FirebaseGeoPoint).longitude).toBe(12.5683); + }); + + it('should convert FirestoreSchema.Reference to a document reference', () => { + const result = firestoreEncode( + fakeFirestore, + FirestoreSchema.Reference.makeFromPath('users/1'), + ); + + expect((result as { path: string }).path).toBe('users/1'); + }); + + it('should convert ServerTimestamp to Firestore field value', () => { + const result = firestoreEncode( + fakeFirestore, + FirestoreSchema.ServerTimestamp.make(), + ); + expect(result).toStrictEqual(serverTimestamp()); + }); + + it('should convert Delete to Firestore field value', () => { + const result = firestoreEncode(fakeFirestore, FirestoreHelper.delete()); + expect(result).toStrictEqual(deleteField()); + }); + + it('should convert ArrayUnion to arrayUnion FieldValue', () => { + const result = firestoreEncode( + fakeFirestore, + FirestoreHelper.arrayUnion(['a', 'b']), + ); + expect(result).toStrictEqual(arrayUnion('a', 'b')); + }); + + it('should convert ArrayRemove to arrayRemove FieldValue', () => { + const result = firestoreEncode( + fakeFirestore, + FirestoreHelper.arrayRemove(['a']), + ); + expect(result).toStrictEqual(arrayRemove('a')); + }); + + it('should recursively encode values inside ArrayUnion', () => { + const ts = FirestoreSchema.Timestamp.fromMillis(1705315800000); + const result = firestoreEncode( + fakeFirestore, + FirestoreHelper.arrayUnion([ts]), + ); + expect(result).toStrictEqual( + arrayUnion(FirebaseTimestamp.fromMillis(1705315800000)), + ); + }); + + it('should recursively encode values inside ArrayRemove', () => { + const ts = FirestoreSchema.Timestamp.fromMillis(1705315800000); + const result = firestoreEncode( + fakeFirestore, + FirestoreHelper.arrayRemove([ts]), + ); + expect(result).toStrictEqual( + arrayRemove(FirebaseTimestamp.fromMillis(1705315800000)), + ); + }); + + it('should recursively convert nested objects and arrays', () => { + const result = firestoreEncode(fakeFirestore, { + createdAt: FirestoreSchema.Timestamp.fromMillis(1705315800000), + metadata: { + location: new FirestoreSchema.GeoPoint({ latitude: 1, longitude: 2 }), + }, + updates: [ + FirestoreSchema.Timestamp.fromMillis(1705315800123), + FirestoreHelper.delete(), + null, + ], + }); + + expect((result as Record).createdAt).toBeInstanceOf( + FirebaseTimestamp, + ); + expect( + ( + (result as Record).metadata as Record< + string, + unknown + > + ).location, + ).toBeInstanceOf(FirebaseGeoPoint); + expect((result as Record).updates).toHaveLength(3); + expect( + ((result as Record).updates as unknown[])[0], + ).toBeInstanceOf(FirebaseTimestamp); + expect( + ((result as Record).updates as unknown[])[1], + ).toStrictEqual(deleteField()); + expect( + ((result as Record).updates as unknown[])[2], + ).toBeNull(); + }); + + it('should preserve already-native Firestore values', () => { + const firebaseTimestamp = new FirebaseTimestamp(1705315800, 0); + const firebaseGeoPoint = new FirebaseGeoPoint(10, 20); + const firebaseDelete = deleteField(); + + const result = firestoreEncode(fakeFirestore, { + timestamp: firebaseTimestamp, + geoPoint: firebaseGeoPoint, + delete: firebaseDelete, + }); + + expect((result as Record).timestamp).toBe( + firebaseTimestamp, + ); + expect((result as Record).geoPoint).toBe( + firebaseGeoPoint, + ); + expect((result as Record).delete).toBe(firebaseDelete); + }); + }); +}); diff --git a/packages/react-native/src/lib/firestore/converter.ts b/packages/react-native/src/lib/firestore/converter.ts new file mode 100644 index 0000000..d4b7fd6 --- /dev/null +++ b/packages/react-native/src/lib/firestore/converter.ts @@ -0,0 +1,128 @@ +import { + arrayRemove, + arrayUnion, + deleteField, + doc, + DocumentData, + DocumentReference, + FieldValue, + Firestore as FirebaseFirestore, + FirestoreDataConverter, + GeoPoint, + serverTimestamp, + Timestamp, +} from '@react-native-firebase/firestore'; +import { DateTime } from 'effect'; +import { FirestoreSchema, Firestore } from 'effect-firebase'; + +/** + * React Native Firebase only exports DocumentReference as a type, so + * instanceof checks are impossible through the public API. Document + * references are identified structurally instead. + */ +const isDocumentReference = ( + value: object, +): value is DocumentReference => + 'firestore' in value && + typeof (value as { path?: unknown }).path === 'string' && + typeof (value as { get?: unknown }).get === 'function'; + +/** + * Encode a value to Firestore client sdk format. + * @param db The Firestore instance. + * @param data The value to encode. + * @returns The encoded value. + */ +export const firestoreEncode = ( + db: FirebaseFirestore, + data: unknown, +): unknown => { + if ( + data === null || + data instanceof Timestamp || + data instanceof GeoPoint || + data instanceof FieldValue + ) { + return data; + } + + if (typeof data === 'object' && isDocumentReference(data)) { + return data; + } + + if (data instanceof FirestoreSchema.Timestamp) { + return Timestamp.fromMillis(data.toMillis()); + } + // Decoded models expose timestamps as Effect DateTime values; without this + // they would fall through to the plain-object branch and encode to garbage + // (notably when used as query cursor values). + if (DateTime.isDateTime(data)) { + return Timestamp.fromMillis(DateTime.toEpochMillis(data)); + } + if (data instanceof FirestoreSchema.GeoPoint) { + return new GeoPoint(data.latitude, data.longitude); + } + if (data instanceof FirestoreSchema.Reference) { + return doc(db, data.path); + } + if (data instanceof FirestoreSchema.ServerTimestamp) { + return serverTimestamp(); + } + if (data instanceof Firestore.Delete) { + return deleteField(); + } + if (data instanceof Firestore.ArrayUnion) { + return arrayUnion(...data.values.map((v) => firestoreEncode(db, v))); + } + if (data instanceof Firestore.ArrayRemove) { + return arrayRemove(...data.values.map((v) => firestoreEncode(db, v))); + } + if (Array.isArray(data)) { + return data.map((item) => firestoreEncode(db, item)); + } + if (typeof data === 'object' && data !== null) { + // If it's already a Firebase type, leave it alone (optimization) + return Object.fromEntries( + Object.entries(data).map(([k, v]) => [k, firestoreEncode(db, v)]), + ); + } + + return data; +}; + +/** + * Decode a value from Firestore client sdk format. + * @param data The value to decode. + * @returns The decoded value. + */ +export const firestoreDecode = (data: DocumentData): DocumentData => { + if (data instanceof Timestamp) { + return FirestoreSchema.Timestamp.fromMillis(data.toMillis()); + } + if (data instanceof GeoPoint) { + return new FirestoreSchema.GeoPoint({ + latitude: data.latitude, + longitude: data.longitude, + }); + } + if (Array.isArray(data)) { + return data.map(firestoreDecode); + } + if (typeof data === 'object' && data !== null) { + if (isDocumentReference(data)) { + return FirestoreSchema.Reference.makeFromPath(data.path); + } + return Object.fromEntries( + Object.entries(data).map(([k, v]) => [k, firestoreDecode(v)]), + ); + } + return data; +}; + +export const makeConverter = ( + db: FirebaseFirestore, +): FirestoreDataConverter => ({ + toFirestore: (modelObject) => + firestoreEncode(db, modelObject) as DocumentData, + fromFirestore: (snapshot) => firestoreDecode(snapshot.data()), +}); diff --git a/packages/react-native/src/lib/firestore/firestore-service.spec.ts b/packages/react-native/src/lib/firestore/firestore-service.spec.ts new file mode 100644 index 0000000..0f3ee19 --- /dev/null +++ b/packages/react-native/src/lib/firestore/firestore-service.spec.ts @@ -0,0 +1,387 @@ +import { describe, expect, it, beforeEach, vi } from 'vitest'; +import { Cause, Data, Effect, Exit, Result } from 'effect'; +import { FirestoreService } from 'effect-firebase'; +import type { Firestore } from '@react-native-firebase/firestore'; + +class TestError extends Data.TaggedError('TestError')<{ reason: string }> {} + +type Op = readonly [name: string, ...args: unknown[]]; + +const h = vi.hoisted(() => { + const state = { + directOps: [] as Op[], + txOps: [] as Op[], + batchOps: [] as Op[], + runTransactionCalls: 0, + batchesCreated: 0, + commits: 0, + }; + + const reset = () => { + state.directOps = []; + state.txOps = []; + state.batchOps = []; + state.runTransactionCalls = 0; + state.batchesCreated = 0; + state.commits = 0; + }; + + const idOf = (path: string) => path.split('/').pop() as string; + + const fakeSnapshot = (path: string, data: Record) => ({ + id: idOf(path), + ref: { id: idOf(path), path }, + data: () => data, + }); + + const fakeDocRef = (path: string): Record => { + const ref: Record = { + id: idOf(path), + path, + type: 'document', + withConverter: () => ref, + }; + return ref; + }; + + const fakeCollection = (path: string): Record => { + const col: Record = { + path, + type: 'collection', + withConverter: () => col, + }; + return col; + }; + + const tx = { + get: async (ref: { path: string }) => { + state.txOps.push(['get', ref.path]); + return fakeSnapshot(ref.path, { title: 'tx' }); + }, + set: (ref: { path: string }, data: unknown, options?: unknown) => { + state.txOps.push(['set', ref.path, data, options]); + }, + update: (ref: { path: string }, data: unknown) => { + state.txOps.push(['update', ref.path, data]); + }, + delete: (ref: { path: string }) => { + state.txOps.push(['delete', ref.path]); + }, + }; + + const makeBatch = () => { + state.batchesCreated += 1; + return { + set: (ref: { path: string }, data: unknown, options?: unknown) => { + state.batchOps.push(['set', ref.path, data, options]); + }, + update: (ref: { path: string }, data: unknown) => { + state.batchOps.push(['update', ref.path, data]); + }, + delete: (ref: { path: string }) => { + state.batchOps.push(['delete', ref.path]); + }, + commit: async () => { + state.commits += 1; + }, + }; + }; + + return { + state, + reset, + fakeSnapshot, + fakeDocRef, + fakeCollection, + tx, + makeBatch, + }; +}); + +// The real @react-native-firebase/firestore pulls in react-native native +// module glue that cannot load under vitest, so the mock is fully +// self-contained instead of spreading the actual module. +vi.mock('@react-native-firebase/firestore', () => { + class Timestamp { + constructor( + readonly seconds: number, + readonly nanoseconds: number, + ) {} + static fromMillis(millis: number) { + return new Timestamp(Math.floor(millis / 1000), (millis % 1000) * 1e6); + } + toMillis() { + return this.seconds * 1000 + this.nanoseconds / 1e6; + } + } + class GeoPoint { + constructor( + readonly latitude: number, + readonly longitude: number, + ) {} + } + class FieldValue {} + const fieldValue = () => new FieldValue(); + const constraint = (type: string) => ({ type }); + return { + Timestamp, + GeoPoint, + FieldValue, + serverTimestamp: fieldValue, + deleteField: fieldValue, + arrayUnion: fieldValue, + arrayRemove: fieldValue, + where: () => constraint('where'), + orderBy: () => constraint('orderBy'), + limit: () => constraint('limit'), + limitToLast: () => constraint('limitToLast'), + startAt: () => constraint('startAt'), + startAfter: () => constraint('startAfter'), + endAt: () => constraint('endAt'), + endBefore: () => constraint('endBefore'), + and: () => constraint('and'), + or: () => constraint('or'), + getFirestore: () => ({}), + onSnapshot: () => () => undefined, + doc: (dbOrCollection: { path?: string }, path?: string) => + path !== undefined + ? h.fakeDocRef(path) + : h.fakeDocRef(`${dbOrCollection.path}/generated-id`), + collection: (_db: unknown, path: string) => h.fakeCollection(path), + query: (ref: unknown) => ref, + getDoc: async (ref: { path: string }) => { + h.state.directOps.push(['get', ref.path]); + return h.fakeSnapshot(ref.path, { title: 'direct' }); + }, + getDocs: async (q: { path: string }) => { + h.state.directOps.push(['query', q.path]); + return { docs: [h.fakeSnapshot(`${q.path}/1`, { title: 'direct' })] }; + }, + addDoc: async (col: { path: string }, data: unknown) => { + h.state.directOps.push(['add', col.path, data]); + return h.fakeDocRef(`${col.path}/added-id`); + }, + setDoc: async (ref: { path: string }, data: unknown, options?: unknown) => { + h.state.directOps.push(['set', ref.path, data, options]); + }, + updateDoc: async (ref: { path: string }, data: unknown) => { + h.state.directOps.push(['update', ref.path, data]); + }, + deleteDoc: async (ref: { path: string }) => { + h.state.directOps.push(['delete', ref.path]); + }, + runTransaction: async ( + _db: unknown, + fn: (tx: unknown) => Promise, + ) => { + h.state.runTransactionCalls += 1; + return fn(h.tx); + }, + writeBatch: () => h.makeBatch(), + }; +}); + +// Imported after the mock so the service uses the mocked SDK functions. +import { layerFromFirestore } from './firestore-service.js'; + +const db = {} as Firestore; + +const run = (effect: Effect.Effect) => + Effect.runPromise(effect.pipe(Effect.provide(layerFromFirestore(db)))); + +const runExit = (effect: Effect.Effect) => + Effect.runPromiseExit(effect.pipe(Effect.provide(layerFromFirestore(db)))); + +const withService = ( + f: (service: FirestoreService['Service']) => Effect.Effect, +) => Effect.flatMap(FirestoreService, f); + +beforeEach(() => { + h.reset(); +}); + +describe('FirestoreService (react-native)', () => { + describe('withTransaction', () => { + it('routes reads and writes through the transaction', async () => { + await run( + withService((fs) => + fs.withTransaction( + Effect.gen(function* () { + yield* fs.get('posts/1'); + yield* fs.set('posts/1', { title: 'a' }); + yield* fs.update('posts/2', { title: 'b' }); + yield* fs.delete('posts/3'); + }), + ), + ), + ); + + expect(h.state.runTransactionCalls).toBe(1); + expect(h.state.txOps.map((op) => op[0])).toEqual([ + 'get', + 'set', + 'update', + 'delete', + ]); + expect(h.state.directOps).toEqual([]); + }); + + it('routes add through transaction.set with a pre-allocated ref', async () => { + const result = await run( + withService((fs) => + fs.withTransaction(fs.add('posts', { title: 'a' })), + ), + ); + + expect(result).toEqual({ + id: 'generated-id', + path: 'posts/generated-id', + }); + expect(h.state.txOps).toEqual([ + ['set', 'posts/generated-id', { title: 'a' }, undefined], + ]); + }); + + it('propagates typed failures from the effect', async () => { + const exit = await runExit( + withService((fs) => + fs.withTransaction( + Effect.gen(function* () { + yield* fs.set('posts/1', { title: 'a' }); + yield* new TestError({ reason: 'boom' }); + }), + ), + ), + ); + + expect(Exit.isFailure(exit)).toBe(true); + if (Exit.isFailure(exit)) { + expect(Cause.hasFails(exit.cause)).toBe(true); + const failure = Cause.findFail(exit.cause); + expect(Result.getOrThrow(failure).error).toMatchObject({ + _tag: 'TestError', + reason: 'boom', + }); + } + }); + + it('joins the ambient transaction when nested', async () => { + await run( + withService((fs) => + fs.withTransaction( + Effect.gen(function* () { + yield* fs.set('posts/1', { title: 'a' }); + yield* fs.withTransaction(fs.set('posts/2', { title: 'b' })); + }), + ), + ), + ); + + expect(h.state.runTransactionCalls).toBe(1); + expect(h.state.txOps.map((op) => op[1])).toEqual(['posts/1', 'posts/2']); + }); + + it('dies when querying inside a transaction', async () => { + const exit = await runExit( + withService((fs) => fs.withTransaction(fs.query('posts', []))), + ); + + expect(Exit.isFailure(exit)).toBe(true); + if (Exit.isFailure(exit)) { + expect(Cause.hasDies(exit.cause)).toBe(true); + } + }); + }); + + describe('withBatch', () => { + it('stages writes on the batch and commits once', async () => { + await run( + withService((fs) => + fs.withBatch( + Effect.gen(function* () { + yield* fs.set('posts/1', { title: 'a' }); + yield* fs.update('posts/2', { title: 'b' }); + yield* fs.delete('posts/3'); + yield* fs.add('posts', { title: 'c' }); + }), + ), + ), + ); + + expect(h.state.batchesCreated).toBe(1); + expect(h.state.commits).toBe(1); + expect(h.state.batchOps.map((op) => op[0])).toEqual([ + 'set', + 'update', + 'delete', + 'set', + ]); + expect(h.state.directOps).toEqual([]); + }); + + it('reads bypass the batch and hit the database directly', async () => { + await run( + withService((fs) => + fs.withBatch( + Effect.gen(function* () { + yield* fs.get('posts/1'); + yield* fs.query('posts', []); + }), + ), + ), + ); + + expect(h.state.directOps.map((op) => op[0])).toEqual(['get', 'query']); + expect(h.state.batchOps).toEqual([]); + }); + + it('does not commit when the effect fails', async () => { + const exit = await runExit( + withService((fs) => + fs.withBatch( + Effect.gen(function* () { + yield* fs.set('posts/1', { title: 'a' }); + yield* new TestError({ reason: 'boom' }); + }), + ), + ), + ); + + expect(Exit.isFailure(exit)).toBe(true); + expect(h.state.commits).toBe(0); + }); + + it('routes writes to the transaction when used inside withTransaction', async () => { + await run( + withService((fs) => + fs.withTransaction(fs.withBatch(fs.set('posts/1', { title: 'a' }))), + ), + ); + + expect(h.state.batchesCreated).toBe(0); + expect(h.state.txOps.map((op) => op[0])).toEqual(['set']); + }); + }); + + describe('outside a transaction or batch', () => { + it('reads and writes go directly to the database', async () => { + await run( + withService((fs) => + Effect.gen(function* () { + yield* fs.get('posts/1'); + yield* fs.set('posts/1', { title: 'a' }); + yield* fs.delete('posts/2'); + }), + ), + ); + + expect(h.state.directOps.map((op) => op[0])).toEqual([ + 'get', + 'set', + 'delete', + ]); + expect(h.state.txOps).toEqual([]); + expect(h.state.batchOps).toEqual([]); + }); + }); +}); diff --git a/packages/react-native/src/lib/firestore/firestore-service.ts b/packages/react-native/src/lib/firestore/firestore-service.ts new file mode 100644 index 0000000..cff57a3 --- /dev/null +++ b/packages/react-native/src/lib/firestore/firestore-service.ts @@ -0,0 +1,386 @@ +import { + Cause, + Context, + Effect, + Exit, + Layer, + Array as Arr, + Option, + Queue, + Result, + Stream, +} from 'effect'; +import { FirestoreError, FirestoreService } from 'effect-firebase'; +import type { FirestoreDataOptions, Snapshot } from 'effect-firebase'; +import type { FirebaseApp } from '@react-native-firebase/app'; +import { + doc, + getFirestore, + type Firestore, + type Transaction, + type WriteBatch, + getDoc, + getDocs, + addDoc, + collection, + setDoc, + updateDoc, + deleteDoc, + onSnapshot, + runTransaction, + writeBatch, +} from '@react-native-firebase/firestore'; +import { App, layer as appLayer } from '../app.js'; +import { firestoreDecode, makeConverter } from './converter.js'; +import { buildQuery } from './query-builder.js'; + +const dataOptions = (options?: FirestoreDataOptions) => ({ + serverTimestamps: options?.serverTimestamps ?? 'estimate', +}); + +/** + * Fiber-local reference to the currently active transaction. Reads and + * writes issued while it is set are routed through the transaction, so + * repositories participate without changes. + */ +const CurrentTransaction = Context.Reference>( + '@effect-firebase/react-native/CurrentTransaction', + { defaultValue: () => Option.none() }, +); + +/** + * Fiber-local reference to the currently active write batch. Writes issued + * while it is set are staged on the batch; reads bypass it. + */ +const CurrentBatch = Context.Reference>( + '@effect-firebase/react-native/CurrentBatch', + { defaultValue: () => Option.none() }, +); + +/** + * Carries a typed Exit across the `runTransaction` promise boundary, so a + * failing effect rolls the transaction back without losing its error type. + */ +class EffectFailure { + constructor(readonly exit: Exit.Exit) {} +} + +/** + * The write-staging surface shared by `Transaction` and `WriteBatch`. + */ +type StagedWriter = Pick; + +const make = (db: Firestore) => { + const converter = makeConverter(db); + + // Writes route through the active transaction first, then the active + // batch. Both stage writes through the same set/update/delete surface; + // the Transaction is cast because TypeScript cannot resolve overloads + // through the Transaction | WriteBatch union. + const currentWriter: Effect.Effect> = Effect.gen( + function* () { + const tx = yield* CurrentTransaction; + if (Option.isSome(tx)) { + return Option.some(tx.value as unknown as StagedWriter); + } + return yield* CurrentBatch; + }, + ); + + const assertNoTransaction = (operation: string) => + Effect.flatMap(CurrentTransaction, (tx) => + Option.isSome(tx) + ? Effect.die( + new Error( + `FirestoreService.${operation} cannot be used inside withTransaction.`, + ), + ) + : Effect.void, + ); + + const packDocSnapshot = ( + snapshot: { + readonly id: string; + readonly ref: { readonly path: string }; + readonly data: (options?: { + readonly serverTimestamps?: 'estimate' | 'previous' | 'none'; + }) => Record | undefined; + }, + options?: FirestoreDataOptions, + ): Option.Option => { + const data = snapshot.data(dataOptions(options)); + if (!data) return Option.none(); + return Option.some([ + { id: snapshot.id, path: snapshot.ref.path }, + firestoreDecode(data), + ]); + }; + + const streamDoc = (path: string, options?: FirestoreDataOptions) => + Stream.callback, FirestoreError>((queue) => + Effect.acquireRelease( + Effect.sync(() => { + const docRef = doc(db, path); + return onSnapshot( + docRef, + (snapshot) => { + const data = snapshot.data(dataOptions(options)); + if (!data) { + Queue.offerUnsafe(queue, Option.none()); + } else { + Queue.offerUnsafe( + queue, + Option.some([ + { id: snapshot.id, path: snapshot.ref.path }, + firestoreDecode(data), + ] as const), + ); + } + }, + (error) => { + Queue.failCauseUnsafe( + queue, + Cause.fail(FirestoreError.fromError(error)), + ); + }, + ); + }), + (unsubscribe) => Effect.sync(() => unsubscribe()), + ), + ); + + const streamQuery = ( + collectionPath: string, + constraints: Parameters[2], + options?: FirestoreDataOptions, + ) => + Stream.callback, FirestoreError>((queue) => + Effect.acquireRelease( + Effect.sync(() => { + const q = buildQuery(db, collectionPath, constraints); + return onSnapshot( + q, + (snapshot) => { + const snapshots = Arr.filterMap(snapshot.docs, (queryDoc) => { + const data = queryDoc.data(dataOptions(options)); + if (!data) return Result.failVoid; + return Result.succeed([ + { id: queryDoc.id, path: queryDoc.ref.path }, + firestoreDecode(data), + ] as const); + }); + Queue.offerUnsafe(queue, snapshots); + }, + (error) => { + Queue.failCauseUnsafe( + queue, + Cause.fail(FirestoreError.fromError(error)), + ); + }, + ); + }), + (unsubscribe) => Effect.sync(() => unsubscribe()), + ), + ); + + return FirestoreService.of({ + get: (path, options) => + Effect.gen(function* () { + const tx = yield* CurrentTransaction; + const snapshot = yield* Effect.tryPromise({ + try: () => + Option.isSome(tx) + ? tx.value.get(doc(db, path)) + : getDoc(doc(db, path)), + catch: (error) => FirestoreError.fromError(error), + }); + return packDocSnapshot(snapshot, options); + }), + add: (path, data) => + Effect.gen(function* () { + const writer = yield* currentWriter; + if (Option.isSome(writer)) { + const ref = doc(collection(db, path).withConverter(converter)); + yield* Effect.try({ + try: () => void writer.value.set(ref, data), + catch: (error) => FirestoreError.fromError(error), + }); + return { id: ref.id, path: ref.path }; + } + return yield* Effect.tryPromise({ + try: () => + addDoc(collection(db, path).withConverter(converter), data), + catch: (error) => FirestoreError.fromError(error), + }).pipe(Effect.map((ref) => ({ id: ref.id, path: ref.path }))); + }), + set: (path, data, options) => + Effect.gen(function* () { + const writer = yield* currentWriter; + const ref = doc(db, path).withConverter(converter); + if (Option.isSome(writer)) { + yield* Effect.try({ + try: () => + void writer.value.set(ref, data, { merge: options?.merge }), + catch: (error) => FirestoreError.fromError(error), + }); + return; + } + yield* Effect.tryPromise({ + try: () => setDoc(ref, data, { merge: options?.merge }), + catch: (error) => FirestoreError.fromError(error), + }); + }), + update: (path, data) => + Effect.gen(function* () { + const writer = yield* currentWriter; + if (Option.isSome(writer)) { + yield* Effect.try({ + try: () => + void writer.value.update( + doc(db, path), + converter.toFirestore(data), + ), + catch: (error) => FirestoreError.fromError(error), + }); + return; + } + yield* Effect.tryPromise({ + try: () => updateDoc(doc(db, path), converter.toFirestore(data)), + catch: (error) => FirestoreError.fromError(error), + }); + }), + delete: (path) => + Effect.gen(function* () { + const writer = yield* currentWriter; + const ref = doc(db, path).withConverter(converter); + if (Option.isSome(writer)) { + yield* Effect.try({ + try: () => void writer.value.delete(ref), + catch: (error) => FirestoreError.fromError(error), + }); + return; + } + yield* Effect.tryPromise({ + try: () => deleteDoc(ref), + catch: (error) => FirestoreError.fromError(error), + }); + }), + deleteRecursive: (_path) => + Effect.die( + new Error( + 'deleteRecursive is not supported on the client SDK. Use the Admin SDK layer instead.', + ), + ), + query: (collectionPath, constraints) => + // The client SDK only supports document reads inside transactions. + assertNoTransaction('query').pipe( + Effect.flatMap(() => + Effect.tryPromise({ + try: async () => { + const q = buildQuery(db, collectionPath, constraints); + const snapshot = await getDocs(q); + return Arr.filterMap(snapshot.docs, (queryDoc) => { + const data = queryDoc.data(); + if (!data) return Result.failVoid; + return Result.succeed([ + { id: queryDoc.id, path: queryDoc.ref.path }, + firestoreDecode(data), + ] as const); + }); + }, + catch: (error) => FirestoreError.fromError(error), + }), + ), + ), + streamDoc: (path, options) => + Stream.unwrap( + assertNoTransaction('streamDoc').pipe( + Effect.map(() => streamDoc(path, options)), + ), + ), + streamQuery: (collectionPath, constraints, options) => + Stream.unwrap( + assertNoTransaction('streamQuery').pipe( + Effect.map(() => streamQuery(collectionPath, constraints, options)), + ), + ), + withTransaction: (self: Effect.Effect) => + Effect.gen(function* () { + const ambient = yield* CurrentTransaction; + // Nested transactions join the ambient one. + if (Option.isSome(ambient)) { + return yield* self; + } + const context = yield* Effect.context(); + const exit = yield* Effect.tryPromise({ + try: (signal) => + runTransaction(db, (tx) => + Effect.runPromiseExit( + self.pipe( + Effect.provideService(CurrentTransaction, Option.some(tx)), + Effect.provideContext(context), + ), + { signal }, + ).then((exit) => { + if (Exit.isFailure(exit)) { + // Reject so Firestore rolls the transaction back. + throw new EffectFailure(exit); + } + return exit; + }), + ), + catch: (error) => + error instanceof EffectFailure + ? error + : FirestoreError.fromError(error), + }).pipe( + Effect.catch((error) => + error instanceof EffectFailure + ? Effect.succeed(error.exit as Exit.Exit) + : Effect.fail(error), + ), + ); + return yield* exit; + }), + withBatch: (self: Effect.Effect) => + Effect.gen(function* () { + const tx = yield* CurrentTransaction; + const ambient = yield* CurrentBatch; + // Inside a transaction writes are already atomic; nested batches + // join the ambient one. + if (Option.isSome(tx) || Option.isSome(ambient)) { + return yield* self; + } + const batch = writeBatch(db); + const result = yield* self.pipe( + Effect.provideService(CurrentBatch, Option.some(batch)), + ); + yield* Effect.tryPromise({ + try: () => batch.commit(), + catch: (error) => FirestoreError.fromError(error), + }); + return result; + }), + }); +}; + +/** + * Live Firestore Service using the client SDK. + */ +export const layer = Layer.effect( + FirestoreService, + Effect.gen(function* () { + const app = yield* App; + return make(getFirestore(app.getApp())); + }), +); + +export const layerFromFirestore = ( + db: Firestore, +): Layer.Layer => + Layer.succeed(FirestoreService, make(db)); + +export const layerFromApp = ( + app: FirebaseApp, +): Layer.Layer => + Layer.provide(layer, appLayer(app)); diff --git a/packages/react-native/src/lib/firestore/query-builder.ts b/packages/react-native/src/lib/firestore/query-builder.ts new file mode 100644 index 0000000..1f9a781 --- /dev/null +++ b/packages/react-native/src/lib/firestore/query-builder.ts @@ -0,0 +1,123 @@ +import { + collection, + query, + where, + orderBy, + limit, + limitToLast, + startAt, + startAfter, + endAt, + endBefore, + and, + or, + Query, + QueryConstraint as FirebaseQueryConstraint, + QueryFilterConstraint, + QueryCompositeFilterConstraint, + DocumentData, + Firestore, +} from '@react-native-firebase/firestore'; +import type { QueryConstraint } from 'effect-firebase'; +import { firestoreEncode } from './converter.js'; + +/** + * Helper to convert unknown value to DocumentData for Firestore. + */ +const convertValue = (db: Firestore, value: unknown): unknown => + firestoreEncode(db, value as DocumentData); + +/** + * Convert a single query constraint to Firebase Client SDK query constraint. + */ +const toFirebaseConstraint = ( + db: Firestore, + constraint: QueryConstraint, +): FirebaseQueryConstraint | QueryCompositeFilterConstraint => { + switch (constraint._tag) { + case 'Where': + return where( + constraint.field, + constraint.op, + convertValue(db, constraint.value), + ); + case 'OrderBy': + return orderBy(constraint.field, constraint.direction); + case 'Limit': + return limit(constraint.count); + case 'LimitToLast': + return limitToLast(constraint.count); + case 'StartAt': + return startAt( + ...constraint.values.map((value) => convertValue(db, value)), + ); + case 'StartAfter': + return startAfter( + ...constraint.values.map((value) => convertValue(db, value)), + ); + case 'EndAt': + return endAt( + ...constraint.values.map((value) => convertValue(db, value)), + ); + case 'EndBefore': + return endBefore( + ...constraint.values.map((value) => convertValue(db, value)), + ); + case 'And': + return and( + ...constraint.constraints.map((child) => toFilterConstraint(db, child)), + ); + case 'Or': + return or( + ...constraint.constraints.map((child) => toFilterConstraint(db, child)), + ); + } +}; + +/** + * Convert a constraint to a filter constraint (for use in and/or). + */ +const toFilterConstraint = ( + db: Firestore, + constraint: QueryConstraint, +): QueryFilterConstraint => { + switch (constraint._tag) { + case 'Where': + return where( + constraint.field, + constraint.op, + convertValue(db, constraint.value), + ); + case 'And': + return and( + ...constraint.constraints.map((child) => toFilterConstraint(db, child)), + ); + case 'Or': + return or( + ...constraint.constraints.map((child) => toFilterConstraint(db, child)), + ); + default: + throw new Error( + `Cannot use ${constraint._tag} inside AND/OR composite filters`, + ); + } +}; + +/** + * Build a Firebase Client SDK query from a collection path and constraints. + */ +export const buildQuery = ( + db: Firestore, + collectionPath: string, + constraints: ReadonlyArray, +): Query => { + const collectionRef = collection(db, collectionPath); + const firebaseConstraints = constraints.map((constraint) => + toFirebaseConstraint(db, constraint), + ); + // Cast is safe - QueryCompositeFilterConstraint can be used in query() + return query( + collectionRef, + ...(firebaseConstraints as FirebaseQueryConstraint[]), + ); +}; diff --git a/packages/react-native/tsconfig.json b/packages/react-native/tsconfig.json new file mode 100644 index 0000000..c35c15c --- /dev/null +++ b/packages/react-native/tsconfig.json @@ -0,0 +1,16 @@ +{ + "extends": "../../tsconfig.base.json", + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + }, + { + "path": "./tsconfig.spec.json" + } + ], + "compilerOptions": { + "ignoreDeprecations": "6.0" + } +} diff --git a/packages/react-native/tsconfig.lib.json b/packages/react-native/tsconfig.lib.json new file mode 100644 index 0000000..ec25bd6 --- /dev/null +++ b/packages/react-native/tsconfig.lib.json @@ -0,0 +1,38 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "baseUrl": ".", + // React Native Firebase ships type declarations that only resolve under + // bundler-style resolution (extensionless relative imports), matching the + // Metro bundler React Native projects use. + "module": "preserve", + "moduleResolution": "bundler", + "rootDir": "src", + "outDir": "dist", + "tsBuildInfoFile": "dist/tsconfig.lib.tsbuildinfo", + "emitDeclarationOnly": false, + "forceConsistentCasingInFileNames": true, + "types": ["node"], + "ignoreDeprecations": "6.0" + }, + "include": ["src/**/*.ts"], + "exclude": [ + "vite.config.ts", + "vite.config.mts", + "vitest.config.ts", + "vitest.config.mts", + "src/**/*.test.ts", + "src/**/*.spec.ts", + "src/**/*.test.tsx", + "src/**/*.spec.tsx", + "src/**/*.test.js", + "src/**/*.spec.js", + "src/**/*.test.jsx", + "src/**/*.spec.jsx" + ], + "references": [ + { + "path": "../effect-firebase/tsconfig.lib.json" + } + ] +} diff --git a/packages/react-native/tsconfig.spec.json b/packages/react-native/tsconfig.spec.json new file mode 100644 index 0000000..1610d02 --- /dev/null +++ b/packages/react-native/tsconfig.spec.json @@ -0,0 +1,34 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "outDir": "./out-tsc/vitest", + // Match tsconfig.lib.json — React Native Firebase types require + // bundler-style resolution. + "module": "preserve", + "moduleResolution": "bundler", + "types": [ + "vitest/globals", + "vitest/importMeta", + "vite/client", + "node", + "vitest" + ], + "ignoreDeprecations": "6.0", + "rootDir": "." + }, + "include": [ + "vite.config.ts", + "vite.config.mts", + "vitest.config.ts", + "vitest.config.mts", + "src/**/*.test.ts", + "src/**/*.spec.ts", + "src/**/*.test.tsx", + "src/**/*.spec.tsx", + "src/**/*.test.js", + "src/**/*.spec.js", + "src/**/*.test.jsx", + "src/**/*.spec.jsx", + "src/**/*.d.ts" + ] +} diff --git a/packages/react-native/vitest.config.mts b/packages/react-native/vitest.config.mts new file mode 100644 index 0000000..17bc6d5 --- /dev/null +++ b/packages/react-native/vitest.config.mts @@ -0,0 +1,18 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig(() => ({ + root: __dirname, + cacheDir: '../../node_modules/.vite/packages/react-native', + test: { + name: '@effect-firebase/react-native', + watch: false, + globals: true, + environment: 'jsdom', + include: ['{src,tests}/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'], + reporters: ['default'], + coverage: { + reportsDirectory: './test-output/vitest/coverage', + provider: 'v8' as const, + }, + }, +})); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e4e5165..1f2a647 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -15,6 +15,12 @@ catalogs: '@effect/vitest': specifier: 4.0.0-rc.112 version: 4.0.0-rc.112 + '@react-native-firebase/app': + specifier: ^26.3.3 + version: 26.3.3 + '@react-native-firebase/firestore': + specifier: ^26.3.3 + version: 26.3.3 effect: specifier: 4.0.0-rc.112 version: 4.0.0-rc.112 @@ -404,6 +410,25 @@ importers: specifier: workspace:* version: link:../effect-firebase + packages/react-native: + dependencies: + tslib: + specifier: ^2.8.1 + version: 2.8.1 + devDependencies: + '@react-native-firebase/app': + specifier: 'catalog:' + version: 26.3.3(react-native@0.87.1(@babel/core@7.29.7)(@types/react@19.2.18)(react@19.2.8))(react@19.2.8) + '@react-native-firebase/firestore': + specifier: 'catalog:' + version: 26.3.3(@react-native-firebase/app@26.3.3(react-native@0.87.1(@babel/core@7.29.7)(@types/react@19.2.18)(react@19.2.8))(react@19.2.8))(react-native@0.87.1(@babel/core@7.29.7)(@types/react@19.2.18)(react@19.2.8)) + effect: + specifier: 'catalog:' + version: 4.0.0-rc.112 + effect-firebase: + specifier: workspace:* + version: link:../effect-firebase + packages: '@apidevtools/json-schema-ref-parser@9.1.2': @@ -1483,6 +1508,13 @@ packages: '@fastify/busboy@3.2.2': resolution: {integrity: sha512-yXSS27qPExaXeuLvMRMXOLtpipzfQYNjG3FkunDWKGfMYjKuhFXko9CVzqxm8jcF+lmtS9Fd89QNdh9XDjnbNg==} + '@firebase/ai@2.14.0': + resolution: {integrity: sha512-TYEQqCQUTyVHuG/HVi9vau6F9kvEaS49o/hmdn/yUuN6ZXQkwIml2nNJTIBfjNl/r9LOxwUNILgcOY16nxObug==} + engines: {node: '>=20.0.0'} + peerDependencies: + '@firebase/app': 0.x + '@firebase/app-types': 0.x + '@firebase/ai@2.15.0': resolution: {integrity: sha512-Aj7TbFdAIWZdkX8JfdDStERpR35g6WNs+7XhNPtFLFOizUotj6k4N/D8HJkR45165HhnMJBe4hjOeeaxnnn56Q==} engines: {node: '>=20.0.0'} @@ -1490,20 +1522,41 @@ packages: '@firebase/app': 0.x '@firebase/app-types': 0.x + '@firebase/analytics-compat@0.2.29': + resolution: {integrity: sha512-allztvCvCUlItZzD97TiRAtGoFJzR1FQFmLxbaLc6PvgscqD9cl5NdKPTtka6keShVYXvCZJpzWcRoH4TME8rw==} + peerDependencies: + '@firebase/app': 0.x + '@firebase/app-compat': 0.x + '@firebase/analytics-compat@0.2.30': resolution: {integrity: sha512-uVZEKlLaW4AHAhv8zoN9cTmveX6v86AVqcJ4LCaRCMTChTH8/NsjbisTq1lpBfWCLWS1spqwSHB4vol/YSCdMA==} peerDependencies: '@firebase/app': 0.x '@firebase/app-compat': 0.x + '@firebase/analytics-types@0.8.4': + resolution: {integrity: sha512-zQ+XTgkwH6CY/eUSHJRP7e4LxM30RCxlCmob5sy2axs25GE3Ny0XdgpDscMTHHQIGqWkxPXad4w2Mw9sCgT8zQ==} + '@firebase/analytics-types@0.8.5': resolution: {integrity: sha512-kdnooE7Bis2jEnsqcerRwn/UQpH5D3uvHpku7OdUM9TJN3omlu6iYtbyAQ6XkAJRgJtO0aNf9OOkW8J6D59oCA==} + '@firebase/analytics@0.10.23': + resolution: {integrity: sha512-34ALWXzWA6PTRUA5hipZmsm1RKzeecw5J1+qTCXsiMzwLqONC+GuTIQSdmm91MmTAEA+wG1Q5t0IFahcYQOqAA==} + peerDependencies: + '@firebase/app': 0.x + '@firebase/analytics@0.10.24': resolution: {integrity: sha512-OfIAcIIwoqXjBzS+DnUQpOZ7i3ePaNFg83KPpDWjBZUKJmqMwzzAtLJqmKZOkQnW8im6vFR6f2I3M/9hxVd+QA==} peerDependencies: '@firebase/app': 0.x + '@firebase/app-check-compat@0.4.6': + resolution: {integrity: sha512-2pzNEZEkX84jSqy6TH6FI1HSLA1lc7kakRUybBbKjg9YhIttPlW/XX3N9CDtChji2PTTPWVPZiWhB10exHfA+A==} + engines: {node: '>=20.0.0'} + peerDependencies: + '@firebase/app': 0.x + '@firebase/app-compat': 0.x + '@firebase/app-check-compat@0.4.7': resolution: {integrity: sha512-fBb/xSMyIKv1nDmccfzz3IAGBzx/cQOxmZai66rJzifb1hMMkztf824Xx7LhpTUe7HNUbXwY90IvJ66fi8q6yg==} engines: {node: '>=20.0.0'} @@ -1511,25 +1564,48 @@ packages: '@firebase/app': 0.x '@firebase/app-compat': 0.x + '@firebase/app-check-interop-types@0.3.4': + resolution: {integrity: sha512-zz3i6e13B8BfWiLy8MABtTh8aGIACgKbf9UVnyHcWs+yQzJXgQcl8A46b0zfaiJHdQ+niF0ouAfcpuf+3LMPQg==} + '@firebase/app-check-interop-types@0.3.5': resolution: {integrity: sha512-qId34pVZ2CXTmtu4ofW5leiI93DvnOvIcr/5GT7MZPw5WXAi6nZoU+g9cNRgl7K90UJSbK0cXxten4meYMPyZg==} + '@firebase/app-check-types@0.5.4': + resolution: {integrity: sha512-xV7JsIyzVr15aA7f3Pi0rB9gdBuVubs89FGA8VkRYA4g0l78poADgdfrScgf7NndSg9mm7cR7PJyY0+t22KaGw==} + '@firebase/app-check-types@0.5.5': resolution: {integrity: sha512-+DF4gzFrlwGFyky38o4T/YN/r51l70yCtJ2HTkwmRj8FCMwPjm4hLH4fQbj6BUvzkiFqliBkitFsRpf1/YZkWA==} + '@firebase/app-check@0.13.0': + resolution: {integrity: sha512-AbMttBKazQvGVXBZhQdVAdPzRhwHyJAY3Ghu5y2C7IZKIDIppzNYz0shTZ1mP4FBJa+28BuC4t+5h1Q6pT3Asg==} + engines: {node: '>=20.0.0'} + peerDependencies: + '@firebase/app': 0.x + '@firebase/app-check@0.13.1': resolution: {integrity: sha512-l8y3dmnhodXks/APAwx4tWqRl3tk8b9874KF1FJyKg1DIU+kMD0l52iz7S9/MW+eK8k6cjJg0G0iJ5KQAsQpow==} engines: {node: '>=20.0.0'} peerDependencies: '@firebase/app': 0.x + '@firebase/app-compat@0.5.16': + resolution: {integrity: sha512-shQq37O8qELDzvsVwYPlDXwD1zlcrZ0m2bpBF5ov2HSbY8x+AHsnL5TtJ2e1JAfkQN05qHao1AfabS69PN6GiA==} + engines: {node: '>=20.0.0'} + '@firebase/app-compat@0.5.17': resolution: {integrity: sha512-5GdJWobqs6jbNYOnaQiSa4Ng8gnFerhqr7nY+v5jlnT7o9QbEeIZRLPQpnLe0TxYSWfRV2lAMbyR0kbXeIos9Q==} engines: {node: '>=20.0.0'} + '@firebase/app-types@0.9.5': + resolution: {integrity: sha512-YevqTjvo7Iujsa9Dwowmd6dSoElhzmD63ZSrq6bzjvQ6POjYgNjOFHLmNIgJs48eNO093NCERibuFnxbfOvU7A==} + '@firebase/app-types@0.9.6': resolution: {integrity: sha512-yPLahy7Esfu2w/yme3msVK4xTkDXQqq6szfQn8yVOQpCKiT5GVFjqNpLbuz6NkX0WuTwUidkmPewW3r4xkvpeg==} + '@firebase/app@0.16.0': + resolution: {integrity: sha512-G+ZGEyVP8YTb3ay6A+XpcYgFH3sTESHcnHU/EyTktodqhz2BHkLq+QEP7IVwjiMX0cxYwpVKip0/wC0KZcn9vQ==} + engines: {node: '>=20.0.0'} + '@firebase/app@0.16.1': resolution: {integrity: sha512-tjUEorFyKrurH7PbLWv9zDHRuU4mLefgD/yY38D584ziorIRlQz/PVjx4c/SCGyCuUlmyzt72mK+Lh+COAywNQ==} engines: {node: '>=20.0.0'} @@ -1541,15 +1617,41 @@ packages: '@firebase/app': 0.x '@firebase/app-compat': 0.x + '@firebase/auth-compat@0.6.9': + resolution: {integrity: sha512-/hHeTBmQ61+N5J1RECls+WfskZTY78JXr7aO5EMOfUpqJvDqvoS+568k0rp6Ss/4UWwBjadILs+H+SGy1zCS3A==} + engines: {node: '>=20.0.0'} + peerDependencies: + '@firebase/app': 0.x + '@firebase/app-compat': 0.x + + '@firebase/auth-interop-types@0.2.5': + resolution: {integrity: sha512-1Li/YuBDBAXcKv7BzY4U28gontUmAaw53sYiqbaVOMCFb2lFKK/c3CGMUWqtwe7+TXrl3poWnTCL5umYBg85Eg==} + '@firebase/auth-interop-types@0.2.6': resolution: {integrity: sha512-FgwZqDrBqgK0BHI70QTv1v/5wmuDF9f8fsJFvKSxoRlK2PPfSQtZAk2jhXu4pe9BZzFi/e4UYusU/bEQHdf6Qg==} + '@firebase/auth-types@0.13.1': + resolution: {integrity: sha512-0c1Mnid0uMDfGJHeUS4zfvBa4/CedJXotGy/n/NZJnBjwiJawt0ZYU+wH2VAVLiRCEfG2ncCkAX3yd1/2nrB7g==} + peerDependencies: + '@firebase/app-types': 0.x + '@firebase/util': 1.x + '@firebase/auth-types@0.13.2': resolution: {integrity: sha512-OU+miuoSxIWYN7GT291d2ylVJBL3k/OePo7/JDSoQtkFQoEiGBc4AHuMjj/seqFIsHrqnjrAfRCk4pfufoJolQ==} peerDependencies: '@firebase/app-types': 0.x '@firebase/util': 1.x + '@firebase/auth@1.13.4': + resolution: {integrity: sha512-s+NS1aV0DDyyfoIMeSz53HXnVTv7ufJjJfrP63XyaWHweJ5vOoxKWrTm5tO7S7PDqvyOa/Wi3oP0dgAo6JTMMA==} + engines: {node: '>=20.0.0'} + peerDependencies: + '@firebase/app': 0.x + '@react-native-async-storage/async-storage': ^2.2.0 || ^3.0.0 + peerDependenciesMeta: + '@react-native-async-storage/async-storage': + optional: true + '@firebase/auth@1.13.5': resolution: {integrity: sha512-1AXoBJqBVD8WL8FZYo3S2GmJF9YUoom6Y6ngMxOSkzzhW5sT83pLchb6TGFgxes91dfXx8s/VYc5VrLDNqpLog==} engines: {node: '>=20.0.0'} @@ -1560,15 +1662,36 @@ packages: '@react-native-async-storage/async-storage': optional: true + '@firebase/component@0.7.4': + resolution: {integrity: sha512-tLpOaaCol9ugUIYp2R3CbWPPA8Ajg/papX/XHEy8U52b/QXH3BbX8tTJX9aShDCjp+9sMAxMLD94i7lresdugQ==} + engines: {node: '>=20.0.0'} + '@firebase/component@0.7.5': resolution: {integrity: sha512-vuFDcL91Q+2ZuBJkyOh86T4q0B4ffNTDjc/A38tybO56odQABxRTFLTIowCWqAKeIcgo37GowWMVgFF73gD8Qw==} engines: {node: '>=20.0.0'} + '@firebase/data-connect@0.7.3': + resolution: {integrity: sha512-nHBFk3Ntl+NZCRIUG2d5j7I69P0otjyQ/duhVKLbw4+5cNke/F6RK1pdE5Jnf831/QOTs2Bd00LlxlZ+jNsb9w==} + peerDependencies: + '@firebase/app': 0.x + '@firebase/data-connect@0.7.4': resolution: {integrity: sha512-su1aGWlzhxb+xtggCUSsufJn1FDa06SBDK71y+fpQ+g2zMhMExik6FUv/odkKzOF/xfWVjabCbWBcjJY3MceDA==} peerDependencies: '@firebase/app': 0.x + '@firebase/database-compat@2.1.6': + resolution: {integrity: sha512-mu7S/75UIajB1A5M9Vfojk69LttW55uABp9nHEtWrV/mIaSEwvoaIe9GySsEzS2EKFK5/3f5okcAuUbihhYeJg==} + engines: {node: '>=20.0.0'} + peerDependencies: + '@firebase/app': 0.x + '@firebase/app-compat': 0.x + peerDependenciesMeta: + '@firebase/app': + optional: true + '@firebase/app-compat': + optional: true + '@firebase/database-compat@2.1.7': resolution: {integrity: sha512-lBq9sJm8MnJINKJnkAKSOj2MbC66xGoSVCcGkPtstl+lkoKEBtD46qHLbuDgW/WbLPoKVm17RIN8BxHj+Z2F2w==} engines: {node: '>=20.0.0'} @@ -1581,13 +1704,27 @@ packages: '@firebase/app-compat': optional: true + '@firebase/database-types@1.0.21': + resolution: {integrity: sha512-SX1jUqhttKgg/m9dYRTvqU9QvucBooziWfA986r4cpsbi4zlsvewe424j3Vpduwd6DG1MSAMfBVT2VqA61FnkA==} + '@firebase/database-types@1.0.22': resolution: {integrity: sha512-YAZNXsjY9EQQ+pKw/3ax8n5FgolHC7Qew7EY5RceYdl0R2ZP+kCv1O0DkKlcceue8uQCOreHCNN7PWVFpY1Nug==} + '@firebase/database@1.1.4': + resolution: {integrity: sha512-D+j4+8uhGtNd1tVD+X+c8JrC4ppStGJKyujSQt2NPwdN26QcCk0BeIxue+UqspHkHiFHyQOimwlzjLewGq6S+A==} + engines: {node: '>=20.0.0'} + '@firebase/database@1.1.5': resolution: {integrity: sha512-/JGpvszLoNXNgzilRXocigGfFF4hbcPA9wN1i1kjJx6oKkXgkHteZYl3lQs1lJX3ETDf6bv7zI15lPMVUp4sAQ==} engines: {node: '>=20.0.0'} + '@firebase/firestore-compat@0.4.12': + resolution: {integrity: sha512-k2uX81Ao/S0jnFcWGPOQpKK1cPlJHvD9WIqh/RE1XBDP2yg5zhE4rHhSg1rtB11k39q3nKon9XLNDDrPjGclag==} + engines: {node: '>=20.0.0'} + peerDependencies: + '@firebase/app': 0.x + '@firebase/app-compat': 0.x + '@firebase/firestore-compat@0.4.13': resolution: {integrity: sha512-l9dCewxMzzLOIhcwTjERCKxrWOn1kZ9JvwOQq9zZNq4I/Nbvb/B9njT230V61uvQ9qZ3/qpUG758D8DDTEFXnw==} engines: {node: '>=20.0.0'} @@ -1595,18 +1732,37 @@ packages: '@firebase/app': 0.x '@firebase/app-compat': 0.x + '@firebase/firestore-types@3.0.4': + resolution: {integrity: sha512-jGn+JSS4X9zZsrfu7Yw66v5YRdOLD1oyQh4USR0xWl4CUqV/DA6bNIXRPpxH/cUl3iVTNiP6MN7g+EL42A4qfA==} + peerDependencies: + '@firebase/app-types': 0.x + '@firebase/util': 1.x + '@firebase/firestore-types@3.0.5': resolution: {integrity: sha512-dbdMAQkMd5dwWc48eupz/Y6/E9ruat3+gY5lhVKscvvT/HnDBEEMzJW38zdKhgdnglZHGk2vUsJMOHAphMHGMA==} peerDependencies: '@firebase/app-types': 0.x '@firebase/util': 1.x + '@firebase/firestore@4.17.0': + resolution: {integrity: sha512-P9tof6pyO1bnLlMWbux+5O7WFJqlb7OTPMKxxOiXKYiQl7mxykAvxr1BFCgWeEXUU7DZxQncyJ040B0IhFVZCg==} + engines: {node: '>=20.0.0'} + peerDependencies: + '@firebase/app': 0.x + '@firebase/firestore@4.17.1': resolution: {integrity: sha512-8lqPNf2w10CtYG+tayVjZO1pSyQpnhztQRudeD109VtXDzNbASTaYdO43sj5PMsDcWq0aOYY3RmJOUlXu9++jw==} engines: {node: '>=20.0.0'} peerDependencies: '@firebase/app': 0.x + '@firebase/functions-compat@0.4.6': + resolution: {integrity: sha512-dj9sOet+FIU91jeU4A3vGJoXHty7NqkSfjRLCwLgJXPDk1m72KFuxD3nlFgw/yXx/Fr7UjqzbxZ0LrIOdpx7+w==} + engines: {node: '>=20.0.0'} + peerDependencies: + '@firebase/app': 0.x + '@firebase/app-compat': 0.x + '@firebase/functions-compat@0.5.0': resolution: {integrity: sha512-T3BDIToESZUHt7438wyKYMkRjKg3m1xAIux5fVpNvTRQlDOFLukWniQWBDhJ2znpU9kxMTR6+e31TVo8P15PZw==} engines: {node: '>=20.0.0'} @@ -1614,77 +1770,155 @@ packages: '@firebase/app': 0.x '@firebase/app-compat': 0.x + '@firebase/functions-types@0.6.4': + resolution: {integrity: sha512-zV6kgqtduR4rUAdC/ilS7kmb93XD7bEZoJDlVBZqlOw2uGGGCNBQBuleww2rr0Ulr3L9o2TDjumEt68/l1f9DQ==} + '@firebase/functions-types@0.6.5': resolution: {integrity: sha512-Zc0pURjthHXzSj54ZivCkzKDSV1r/wIpnmHdhq82q2yFFPVoncG/ZJjnVMiANvQfeww/QnElhzODpfwUucVwdA==} + '@firebase/functions@0.13.6': + resolution: {integrity: sha512-9obLnzeQUivK5lmtGFOU2ucQ38BjTp+jpPtbfFp/mDsdVCvEpRqdWNvMMQ6aQwR4vcVc/utsvngm5BRkXbc7ZA==} + engines: {node: '>=20.0.0'} + peerDependencies: + '@firebase/app': 0.x + '@firebase/functions@0.14.0': resolution: {integrity: sha512-DhuYFr0eMhp+s/PNEk6SiMsYkc00+XVOUeKbrl8MOzQNZI3SKQpqoDR1d+keNDAutwmHRWTUAdXBoVPD+xxVUw==} engines: {node: '>=20.0.0'} peerDependencies: '@firebase/app': 0.x + '@firebase/installations-compat@0.2.23': + resolution: {integrity: sha512-isaXmjb9roM83eVeXAe+ZRNKYNsSo2s0aNM+cy04AAGEyVL/d8Aa11GwEXovRFeYjl9+1yRAOxRDTOukZRwTxA==} + peerDependencies: + '@firebase/app': 0.x + '@firebase/app-compat': 0.x + '@firebase/installations-compat@0.2.24': resolution: {integrity: sha512-8M5nlcWwYt881x83COP2odq5vgf+NgwJh+RMd4LRSv8JI1pxwDfgrDJOERrjTgfC9J5Z0vnQX4b1pdN914e0Zw==} peerDependencies: '@firebase/app': 0.x '@firebase/app-compat': 0.x + '@firebase/installations-types@0.5.4': + resolution: {integrity: sha512-U2eFapdHwjb43Vx9o+Pmj4dFfvcHEK1IirEFLqMtWrTHvmdrS3gBpBD1kmJk/9HjsOtoHZxJ2Paoe79e+L1ZPg==} + peerDependencies: + '@firebase/app-types': 0.x + '@firebase/installations-types@0.5.5': resolution: {integrity: sha512-e9UYcju3puDl1vdrcKIi5dExzHLameOT/Tc61Q48PYwxtsM1NzZh/ikGbdBQTsbRgg0EMZqdPr0/m5ODUBobrg==} peerDependencies: '@firebase/app-types': 0.x + '@firebase/installations@0.6.23': + resolution: {integrity: sha512-MBkbcQfd+3qHjW+slsH4s7jH5qTdGlYpwqmxEZ7QcIpgDxu1SKyU0f+mCZhCt1BCacLNiOWF5L0R06N0LtlfMg==} + peerDependencies: + '@firebase/app': 0.x + '@firebase/installations@0.6.24': resolution: {integrity: sha512-Ui52ey8wHoWqkBbXRKJEKYWylI0JZogZmoLS+o8Anh1bxWtK27ZYjLla1UJAAdC5DCKLJ2qAp0VpJOjg8VOX1g==} peerDependencies: '@firebase/app': 0.x + '@firebase/logger@0.5.1': + resolution: {integrity: sha512-vZKLsqE1ABOy8OjQiE7cUTFn4gvaqlk88yp8N94Pk/sDpq61YqZGqmVFZTvOyflTwuYFcWirBdYGoJgbDaXKYQ==} + engines: {node: '>=20.0.0'} + '@firebase/logger@0.5.2': resolution: {integrity: sha512-J2VO4NFTc0xQFrxV1B/lm5balicm9cwuX2acR9Yn41fN8KgUeQFo+VJV222IqW2FPSXKDu9uo5WdQFWf9TPbYg==} engines: {node: '>=20.0.0'} + '@firebase/messaging-compat@0.2.28': + resolution: {integrity: sha512-/AmMqHRnSQhPsdeED3ocs+s30/tpFvZDiiwIYY2uXFRvLujo1fnbPOeCFoe4Y+dRy1LCSjpvJf+dy5ZTsxi1yg==} + peerDependencies: + '@firebase/app': 0.x + '@firebase/app-compat': 0.x + '@firebase/messaging-compat@0.2.29': resolution: {integrity: sha512-8Twe4CeYvAx8AzjBxyyQFKzinaMGGt13hPQBqaARQ2QZjagrEaqSVBe+Zy6F4L/vT8DV168yRgRu7W/RK7p+4w==} peerDependencies: '@firebase/app': 0.x '@firebase/app-compat': 0.x + '@firebase/messaging-interop-types@0.2.5': + resolution: {integrity: sha512-tUEKnaAP2Y/MNIqgnriPpV6e5l13Vs/+p2yrd6NGlncPJT9O3a8muYZtdnWe+IJ4fgKLHJVC79n/asxk/N5Msw==} + '@firebase/messaging-interop-types@0.2.6': resolution: {integrity: sha512-MVzvkKe2V4H2dHu5oOxRfeKQcfTwWmCgnzsC4V1q3ixun5iiL8riCZ2qI35rDhCL4glPGiu0jHxDbpVNuTKfow==} + '@firebase/messaging@0.13.1': + resolution: {integrity: sha512-kL8fdjbNBI7hprlXJrUjktDWosrpT4JtfwXtVVevImPF/rBRAsC+LS/jIs+kgQVuotnvMhaBCgAFipBoY9YU9g==} + peerDependencies: + '@firebase/app': 0.x + '@firebase/messaging@0.13.2': resolution: {integrity: sha512-KcZoqUu2ih4sLH91dW9tmyHjCR0IQyNzSLZunX5uq7cLeImXb4uO2I0wq5FACduO2I+FoTeWa2BtUv7Jpowqdw==} peerDependencies: '@firebase/app': 0.x + '@firebase/performance-compat@0.2.26': + resolution: {integrity: sha512-jgoocXLN6ao26xWQ8pzosmzQ33uLzGBJQPNK0NTbVy1XvIHr5pfgBf9hWLOxsWe+R7sJq5bjD+8ybXprmt61mA==} + peerDependencies: + '@firebase/app': 0.x + '@firebase/app-compat': 0.x + '@firebase/performance-compat@0.2.27': resolution: {integrity: sha512-O/ozTf/EbChN94Pk7bd1eUC0PAC36726AwsaiJyC0bZzSBWfLGSWASGPH5pebUWXQPJtGxIJYRkkbX5l0Qa+Hw==} peerDependencies: '@firebase/app': 0.x '@firebase/app-compat': 0.x + '@firebase/performance-types@0.2.4': + resolution: {integrity: sha512-kJSEk7b0uhpcPRyL4SQ/GPujLqk52XNKcXlnsKDbWGAb9vugcLvOU3u6zfEdwd+d8hWJb5S5ZizV1JFFI0nkKg==} + '@firebase/performance-types@0.2.5': resolution: {integrity: sha512-PRzOgB+/M+6AKlEkY8a9xy5Ff5SfZPIh4iShXhn2WAcL/euSbK7bdLqWysHduunNJhGFsXa22Ag3ixqL6rQtYg==} + '@firebase/performance@0.7.13': + resolution: {integrity: sha512-1u6fuXP9cj0s+lkTFAspr/ttfPebPbEdpx+5Wdr4mPZbp8qH2KCMxOddEAR1ZMRa5GI0E7hDYSnolEmbqOFOAg==} + peerDependencies: + '@firebase/app': 0.x + '@firebase/performance@0.7.14': resolution: {integrity: sha512-9PH1XEZVHErxGdbXluvGz4Uyjw4W955H8v7Mv9rHIybRrg5F2Ac2tvf5+mSf5EtnxWNmxrD2WLnvMFaZP4sMrQ==} peerDependencies: '@firebase/app': 0.x + '@firebase/remote-config-compat@0.2.28': + resolution: {integrity: sha512-kEO9Gn6fbmVj7eNUtZ6d59mLgUDUD0qo7aCicGOWNfuRWTaUv3CF9DMYychO61zaEQ3cfA+CEny4V1E8A1gRGA==} + peerDependencies: + '@firebase/app': 0.x + '@firebase/app-compat': 0.x + '@firebase/remote-config-compat@0.2.29': resolution: {integrity: sha512-mY7JtTISK6F4g4T0x3kVepr5cp0NXL7f5yjIUXXGaTrg4qUlFBWRbENaHaqZ78dwmNcLm24h/yPsOVRlDXEXhA==} peerDependencies: '@firebase/app': 0.x '@firebase/app-compat': 0.x + '@firebase/remote-config-types@0.5.1': + resolution: {integrity: sha512-cX/1LT6KQwkXzck2eSzeKnuvXZCyr8qaPpDcikoJs7jmI+oBOXixpDLeDtWj1U6GNMkIoXrEDNoyT2Ypcyp5/A==} + '@firebase/remote-config-types@0.5.2': resolution: {integrity: sha512-i8k1omVfoAnaT1ZPv2FFjxMZrATYsO/GnFgHEj5+7fAJLzi8wLnGGv1WK06oEAD6ltrWXSO1HzeNyajn/NjMWw==} + '@firebase/remote-config@0.9.1': + resolution: {integrity: sha512-nzQUSJnk1zAZEl2Q5O3I7Z61cYLK5JI4H6wyyOiHkVZ+bmgy1YXNNMptNbVjixMQ/eCzgA6nZRaC+1eBcJGUFA==} + peerDependencies: + '@firebase/app': 0.x + '@firebase/remote-config@0.9.2': resolution: {integrity: sha512-Rii93DkXjM+RE/ytHdYa7EIiQLJbdBr+W8EEiqd/vbLCOC+1FdkDuRiumJBp6t3yewHGbdqbpjB3fk3z0cZ+8g==} peerDependencies: '@firebase/app': 0.x + '@firebase/storage-compat@0.4.4': + resolution: {integrity: sha512-qSRgCB9f2R/nCp8t/8OC101cIFBFeUazlRInOMdzbnLzvrQBzEfx19SrR4pvdj/0+M+P/y8AK/a2s+3EB+B1Pw==} + engines: {node: '>=20.0.0'} + peerDependencies: + '@firebase/app': 0.x + '@firebase/app-compat': 0.x + '@firebase/storage-compat@0.4.5': resolution: {integrity: sha512-vO0tFPxXbKDKdlTu8tYT08S9t9ezUTJYEdLCULpWxWq2aq6zojwN1QmAB+1a50AI/g47GlWUJn1XPncm/PDZsw==} engines: {node: '>=20.0.0'} @@ -1692,22 +1926,41 @@ packages: '@firebase/app': 0.x '@firebase/app-compat': 0.x + '@firebase/storage-types@0.8.4': + resolution: {integrity: sha512-BT7cwxJOx8SWwlQfrlC+bD/Sk3Cw+1odCi8UZNFNWTVZoPsBnA5W+mqtZzVnvsdJpXCFGSGQ7R7vOR6dtM/BRA==} + peerDependencies: + '@firebase/app-types': 0.x + '@firebase/util': 1.x + '@firebase/storage-types@0.8.5': resolution: {integrity: sha512-GEDs5P+rNUfNcS+wxIdOLAHficife2YXtvTJnyi3ssrX11AAtBg+nDUdbYh8vuBzWehVQZPmztGUUnud4L+4yg==} peerDependencies: '@firebase/app-types': 0.x '@firebase/util': 1.x + '@firebase/storage@0.14.4': + resolution: {integrity: sha512-jfzEWZb3Fpsq3FwAB2ifoc8mcSh935qXdDou3TpyjDWa45hhNcZUv8/w28/10njByhfK7snbakKN30nwnzQ3/w==} + engines: {node: '>=20.0.0'} + peerDependencies: + '@firebase/app': 0.x + '@firebase/storage@0.14.5': resolution: {integrity: sha512-r2tozN/BlEewLi70tJNUQPzWwbex9GM7NgXZsamHKQrjKEfcR0i4jGgHBKAKA4hbwiPE9eNMb3hcxWnDpeJZwg==} engines: {node: '>=20.0.0'} peerDependencies: '@firebase/app': 0.x + '@firebase/util@1.15.2': + resolution: {integrity: sha512-974pWIZVLDMc5GW5YAsj8y0XxULxIy/sPUy7tsxmWbF93KRIyh9xpuHlh0zDL+shUcf5nHDjFOg9YLiQ763eiA==} + engines: {node: '>=20.0.0'} + '@firebase/util@1.15.3': resolution: {integrity: sha512-c/z/gaIlaaLZEuGbE6sLUuJ61tskg1JghvhcNQzW948ASBinbVBBRnZTC4b4yt4LaEtJQkYlyzqLHcutFwEIvA==} engines: {node: '>=20.0.0'} + '@firebase/webchannel-wrapper@1.0.6': + resolution: {integrity: sha512-Vr/Mqu79dMwGRAyGbJ4uN4+BtXB3/mRTdzetD1daWNeG8QaWuzhhbG77GltO5c0yYmYls8i250iX73624GJd7Q==} + '@firebase/webchannel-wrapper@1.0.7': resolution: {integrity: sha512-phBFwieDLvkZGYN9CE9ZFNEIoBVksprzsnCzQejCmCHtgwCXReeuRpoEGN9C4EbhONztv8NRV1tau6Rb9pONwQ==} @@ -1950,10 +2203,22 @@ packages: resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==} engines: {node: '>=18.0.0'} + '@isaacs/ttlcache@1.4.1': + resolution: {integrity: sha512-RQgQ4uQ+pLbqXfOmieB91ejmLwvSgv9nLx6sT6sD83s7umBypgg+OIBOBbEUiJXrfpnp9j0mRhYYdzp9uqq3lA==} + engines: {node: '>=12'} + '@jest/diff-sequences@30.0.1': resolution: {integrity: sha512-n5H8QLDJ47QqbCNn5SuFjCRDrOLEZ0h8vAHCK5RL9Ls7Xa8AQLa/YxAc9UjFqoEDM48muwtBGjtMY5cr0PLDCw==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + '@jest/schemas@29.6.3': + resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/types@29.6.3': + resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jridgewell/gen-mapping@0.3.13': resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} @@ -2706,6 +2971,73 @@ packages: '@protobufjs/utf8@1.1.2': resolution: {integrity: sha512-b1UQwcEZ4yCnMCD8DAL1VlbvBJE9/IX4FTIp7BG1xYpf29SLazLSrqUkj4w7Y5y7cCVP6E5tcqqcI0xemPkHug==} + '@react-native-firebase/app@26.3.3': + resolution: {integrity: sha512-DmgSP+k7sB/KjaKYYk27n06+O3q4shO4LsDRYCSmE3axL59r93Zoh3qP62dyAi1BHXuLvuOv+3ooS1xTS4RtjQ==} + peerDependencies: + expo: '>=47.0.0' + react: '*' + react-native: '*' + peerDependenciesMeta: + expo: + optional: true + + '@react-native-firebase/firestore@26.3.3': + resolution: {integrity: sha512-aThSPouRDvxSVOu4uQGP59ehBeU9iDK642IWH4EnEhg+K2Yu3OCKVcpksecZhdjGP4Xc5En3R2OWmE8soyh+zg==} + peerDependencies: + '@react-native-firebase/app': 26.3.3 + + '@react-native/asset-utils@0.87.1': + resolution: {integrity: sha512-FeFnbn9ENPs7IVBzZt1bBWfiRGvT4q+CsWwXGFyKVW/1ol3ylBRuTtXBGHIAmcNN4fUR60nSXsCN19pzNHkPgA==} + engines: {node: ^22.13.0 || ^24.3.0 || >= 26.0.0} + + '@react-native/codegen@0.87.1': + resolution: {integrity: sha512-qbaqEdlUfj2vRgvWTpMoNgHnEqAhAYJLUrpGkb0WC9n0kdtqUvgigpz4bDktZwolM9BemXwgGFgyiAnbs3t0xw==} + engines: {node: ^22.13.0 || ^24.3.0 || >= 26.0.0} + peerDependencies: + '@babel/core': '*' + + '@react-native/community-cli-plugin@0.87.1': + resolution: {integrity: sha512-aGBae6v+ngy8fIpU1EOaVxn/8DOgmJNphEdn5Eb0wTchUCxr8bDjpTJYNdrptyn3qI/elk8r9agQ2OBaFvrRlw==} + engines: {node: ^22.13.0 || ^24.3.0 || >= 26.0.0} + peerDependencies: + '@react-native-community/cli': '*' + '@react-native/metro-config': 0.87.1 + peerDependenciesMeta: + '@react-native-community/cli': + optional: true + '@react-native/metro-config': + optional: true + + '@react-native/debugger-frontend@0.87.1': + resolution: {integrity: sha512-RNm7soJB+8YSauLnsCCylA1eVfT6JWaDTPUEF01uu9YwDyZ7remKlZbXtmVbtscbNGcp+hbI4iZUdVOpQWsHuA==} + engines: {node: ^22.13.0 || ^24.3.0 || >= 26.0.0} + + '@react-native/debugger-shell@0.87.1': + resolution: {integrity: sha512-eNbKjcnseJIjy5XCDwyhKOT1ngOg3Dv1fVxTDtnVFqdqjqsbfY4v9JuJG1RZJ7+mFoRRe05HE8GSQU8B7n5xwQ==} + engines: {node: ^22.13.0 || ^24.3.0 || >= 26.0.0} + + '@react-native/dev-middleware@0.87.1': + resolution: {integrity: sha512-KgvAGUaVl6/XrWFAPK8e0ojDRbsdBjr4bnwyn6PC3CwxPQc5iv+i7hMoUwYS8ORSkHKfjt+cV86/mBQ4lG8yfA==} + engines: {node: ^22.13.0 || ^24.3.0 || >= 26.0.0} + + '@react-native/gradle-plugin@0.87.1': + resolution: {integrity: sha512-bZ5X2BNxaSlfp2KlDtUM910QqW9G1yTIeZXghuv4ag8SAQLzm5Mf9j5GjJfT6ax2Qo2aRT15Vi3Tro/yLGJstA==} + engines: {node: ^22.13.0 || ^24.3.0 || >= 26.0.0} + + '@react-native/normalize-colors@0.87.1': + resolution: {integrity: sha512-8+AutemzX+a7cuKgTUyb7JUk3sFYgLyrSnlTLrL6LuW/LKDE+FYE8lJGWYhJPJcE51Ge1D8yRzxgQEdEFZtuIw==} + + '@react-native/virtualized-lists@0.87.1': + resolution: {integrity: sha512-qSZjeX3UJrDvyfjf7yc3E68rp1XnzE+5nu8ImklhkVC0+p/XiaHPb/KGkRqDdnQyWHN55BRYSsCMEwgVI6WRNQ==} + engines: {node: ^22.13.0 || ^24.3.0 || >= 26.0.0} + peerDependencies: + '@types/react': ^19.2.0 + react: '*' + react-native: 0.87.1 + peerDependenciesMeta: + '@types/react': + optional: true + '@rolldown/binding-android-arm-eabi@1.2.6': resolution: {integrity: sha512-b+jTcARdTiFLI6jB4a5XjTm0RWd6KcRfQj/I2356fxUZemiho9zQLxo0RtCuMDAyKcLo6cEltkgbQp6d1+sjjQ==} engines: {node: ^20.19.0 || >=22.12.0} @@ -3103,6 +3435,9 @@ packages: '@sec-ant/readable-stream@0.4.1': resolution: {integrity: sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==} + '@sinclair/typebox@0.27.12': + resolution: {integrity: sha512-hhyNJ+nbR6ZR7pToHvllEFun9TL0sbL+tk/ON75lo+Xas054uez98qRbsuNt7MBCyZKK4+8Yli/OAGZhmfBZ/g==} + '@sindresorhus/is@4.6.0': resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==} engines: {node: '>=10'} @@ -3713,6 +4048,15 @@ packages: '@types/http-proxy@1.17.17': resolution: {integrity: sha512-ED6LB+Z1AVylNTu7hdzuBqOgMnvG/ld6wGCG8wFnAzKX5uyW2K3WD52v0gnLCTK/VLpXtKckgWuyScYK6cSPaw==} + '@types/istanbul-lib-coverage@2.0.6': + resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} + + '@types/istanbul-lib-report@3.0.3': + resolution: {integrity: sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==} + + '@types/istanbul-reports@3.0.4': + resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==} + '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} @@ -3772,6 +4116,12 @@ packages: '@types/triple-beam@1.3.5': resolution: {integrity: sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==} + '@types/yargs-parser@21.0.3': + resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} + + '@types/yargs@17.0.35': + resolution: {integrity: sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==} + '@typescript-eslint/eslint-plugin@8.66.0': resolution: {integrity: sha512-p088eaGrzYz1s+7cov0aMOCkNGTJlVxF4jgubf28c8L0Cv9Rloj8YBHnv4hXLq6IIEE1AsjNWavO+k+8kP2Y0A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -4230,6 +4580,9 @@ packages: alien-signals@0.4.14: resolution: {integrity: sha512-itUAVzhczTmP2U5yX67xVpsbbOiquusbWVyA9N+sy6+r6YVbFkahXvNCeEPWEOMhwDYwbVbGHFkVL03N9I5g+Q==} + anser@1.4.10: + resolution: {integrity: sha512-hCv9AqTQ8ycjpSd3upOJd7vFwW1JaoYQ7tpham03GJ1ca8/65rqn0RpaWpItOAd6ylW9wAw6luXYPJIyPFVOww==} + ansi-align@3.0.1: resolution: {integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==} @@ -4349,6 +4702,9 @@ packages: as-array@2.0.0: resolution: {integrity: sha512-1Sd1LrodN0XYxYeZcN1J4xYZvmvTwD5tDWaPUGPIzH1mFsmzsPnVtd2exWhecMjtZk/wYWjNZJiD3b1SLCeJqg==} + asap@2.0.6: + resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==} + asn1@0.2.6: resolution: {integrity: sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==} @@ -4465,6 +4821,9 @@ packages: peerDependencies: '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + babel-plugin-syntax-hermes-parser@0.36.1: + resolution: {integrity: sha512-ycduwJbvdvIMmVvlAZqGggS+pm5Eu4Bk9pcV9Sm2Z4PJNRVsKkv0g7vHj+LeuC1gHTeF67sJXFOq61IlqCa2hA==} + babel-plugin-transform-typescript-metadata@0.3.2: resolution: {integrity: sha512-mWEvCQTgXQf48yDqgN7CH50waTyYBeP2Lpqx4nNWab9sxEpdXVeKgfj1qYI2/TgUPQtNFZ85i3PemRtnXVYYJg==} peerDependencies: @@ -4609,6 +4968,9 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true + bser@2.1.1: + resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} + btoa@1.2.1: resolution: {integrity: sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g==} engines: {node: '>= 0.4.0'} @@ -4714,10 +5076,18 @@ packages: resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==} engines: {node: '>=18'} + chrome-launcher@0.15.2: + resolution: {integrity: sha512-zdLEwNo3aUVzIhKhTtXfxhdvZhUghrnmkvcAq2NoDd+LeOHKf03H5jwZ8T/STsAlzyALkBVK552iaG1fGf1xVQ==} + engines: {node: '>=12.13.0'} + hasBin: true + chrome-trace-event@1.0.4: resolution: {integrity: sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==} engines: {node: '>=6.0'} + chromium-edge-launcher@0.3.0: + resolution: {integrity: sha512-p03azHlGjtyRvFEee3cyvtsRYdniSkwjkzmM/KmVnqT5d7QkkwpJBhis/zCLMYdQMVJ5tt140TBNqqrZPaWeFA==} + chunk-data@0.1.0: resolution: {integrity: sha512-zFyPtyC0SZ6Zu79b9sOYtXZcgrsXe0RpePrzRyj52hYVFG1+Rk6rBqjjOEk+GNQwc3PIX+86teQMok970pod1g==} engines: {node: '>=20'} @@ -4725,6 +5095,10 @@ packages: ci-info@2.0.0: resolution: {integrity: sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==} + ci-info@3.9.0: + resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} + engines: {node: '>=8'} + cjson@0.3.3: resolution: {integrity: sha512-yKNcXi/Mvi5kb1uK0sahubYiyfUO2EUgOp4NcY9+8NX5Xmc+4yeNogZuLFkpLBBj7/QI9MjRUIuXrV9XOw5kVg==} engines: {node: '>= 0.3.0'} @@ -4827,6 +5201,10 @@ packages: resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==} engines: {node: '>=16'} + commander@12.1.0: + resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==} + engines: {node: '>=18'} + commander@2.20.3: resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} @@ -5336,6 +5714,9 @@ packages: error-ex@1.3.4: resolution: {integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==} + error-stack-parser@2.1.4: + resolution: {integrity: sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==} + es-abstract-get@1.0.0: resolution: {integrity: sha512-6PMWXpdhshVvFp+FoWYs1EvG1Nj0tvk0dZM+XcK0xMEM1czRVcP6ohqPWHy6qPagSpC8j4+p89WXlT+xXJs/fg==} engines: {node: '>= 0.4'} @@ -5669,6 +6050,14 @@ packages: resolution: {integrity: sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==} engines: {node: '>=0.8.0'} + fb-dotslash@0.5.8: + resolution: {integrity: sha512-XHYLKk9J4BupDxi9bSEhkfss0m+Vr9ChTrjhf9l2iw3jB5C7BnY4GVPoMcqbrTutsKJso6yj2nAB6BI/F2oZaA==} + engines: {node: '>=20'} + hasBin: true + + fb-watchman@2.0.2: + resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} + fdir@6.5.0: resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} engines: {node: '>=12.0.0'} @@ -5774,6 +6163,9 @@ packages: engines: {node: '>=20.0.0 || >=22.0.0 || >=24.0.0'} hasBin: true + firebase@12.17.1: + resolution: {integrity: sha512-dhp41ye9jMQvhx5FwjMkf/hjDHJApl7gXmvzOZGvP0M7c/GZGUnQ4qvsvlOBkF0Pa7wAwHMdcpL0ON2pXCQ4Sw==} + firebase@12.18.0: resolution: {integrity: sha512-XaL6tlE5Xd20ZDhckqOMIw+JJTET+wTdeZPxQ7ihc42oxRb7kWUyn/j1LO5V9dH1xq8Rv5R71Pv1fBCdIkt9Rw==} @@ -5788,6 +6180,9 @@ packages: flatted@3.4.4: resolution: {integrity: sha512-5+ybhBZANEJxaH3X5evAFatUxLfEHSr7n6kYJ+1Qd0mUqr4eu9gIf6GDbWHf8RJijHrjjO8G+la14SlL2SeS1Q==} + flow-enums-runtime@0.0.6: + resolution: {integrity: sha512-3PYnM29RFXwvAN6Pc/scUfkI7RwhQ/xqyLUyPNlXUp9S40zI8nup9tUSrTLSVnWGBN38FNiGWbwZOB6uR4OGdw==} + fn.name@1.1.0: resolution: {integrity: sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==} @@ -6129,12 +6524,21 @@ packages: resolution: {integrity: sha512-EQfezRg0NCZGNlhlDR3Evrw1FVL2G3LhU7EgPoxufQKruNBSYA8MiRPHeWbU+36o+Fhel0wMwM+sLEiBAlNLJA==} engines: {node: '>=10.0.0'} + hermes-compiler@250829098.0.17: + resolution: {integrity: sha512-qG1PXzTEtriF6oQLZF3vyHhSMxOdW5h2TqqLri0rdpstPustd2fSvRZQMVAPdlhgFwBfYnj3OUZtiO6LjYsEFw==} + hermes-estree@0.25.1: resolution: {integrity: sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==} + hermes-estree@0.36.1: + resolution: {integrity: sha512-guv1nQ6IJ7S83NRFPWc3SA7IBZrdNC9kapwOq6uXvF4wP+sDCgjzQbKPCoyYmoyZRzztF/n/c36l/rccCZSiCw==} + hermes-parser@0.25.1: resolution: {integrity: sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==} + hermes-parser@0.36.1: + resolution: {integrity: sha512-GApNk4zLHi2UWoWZZkx7LNCOSzLSc5lB55pZ/PhK7ycFeg7u5LcF88p/WbpIi1XUDtE0MpHE3uRR3u3KB7TjSQ==} + highlight.js@10.7.3: resolution: {integrity: sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==} @@ -6266,6 +6670,11 @@ packages: resolution: {integrity: sha512-BAg6QkE8W+TuQLrrw0Ugr7HegXduRuuj8/ti2kSOc+jz1dmx8/WNcjr6XGnq5YpDWxFwwaavqD0+jIUOKelTsw==} engines: {node: '>= 4'} + image-size@1.2.1: + resolution: {integrity: sha512-rH+46sQJ2dlwfjfhCyNx5thzrv+dtmBIhPHk0zgRUukHzZ/kRueTJXoYYsclBaKcSMBWuGbOFXtioLpzTb5euw==} + engines: {node: '>=16.x'} + hasBin: true + import-fresh@3.3.1: resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} engines: {node: '>=6'} @@ -6312,6 +6721,9 @@ packages: resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} engines: {node: '>= 0.4'} + invariant@2.2.4: + resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==} + ip-address@10.5.0: resolution: {integrity: sha512-R5SnVLJmgYYvf2F2ZgwSBnelz5G4q5AxIC277GDfUaNbrZKNANcBC7RHqYYePlszf4kBolVkJauG0ZjHHFh55g==} engines: {node: '>= 12'} @@ -6374,6 +6786,11 @@ packages: is-deflate@1.0.0: resolution: {integrity: sha512-YDoFpuZWu1VRXlsnlYMzKyVRITXj7Ej/V9gXQ2/pAe7X1J7M/RNOqaIYi6qUn+B7nGyB9pDXrv02dsB58d2ZAQ==} + is-docker@2.2.1: + resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} + engines: {node: '>=8'} + hasBin: true + is-docker@3.0.0: resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -6551,6 +6968,10 @@ packages: resolution: {integrity: sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw==} engines: {node: '>=4'} + is-wsl@2.2.0: + resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} + engines: {node: '>=8'} + is-wsl@3.1.0: resolution: {integrity: sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==} engines: {node: '>=16'} @@ -6612,10 +7033,26 @@ packages: jackspeak@3.4.3: resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + jest-get-type@29.6.3: + resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-util@29.7.0: + resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-validate@29.7.0: + resolution: {integrity: sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-worker@27.5.1: resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==} engines: {node: '>= 10.13.0'} + jest-worker@29.7.0: + resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jiti@2.4.2: resolution: {integrity: sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==} hasBin: true @@ -6650,6 +7087,9 @@ packages: jsbn@0.1.1: resolution: {integrity: sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==} + jsc-safe-url@0.2.4: + resolution: {integrity: sha512-0wM3YBWtYePOjfyXQH5MWQ8H7sdk5EXSwZvmSLKk2RboVQ2Bu239jycHDz5J/8Blf3K0Qnoy2b6xD+z10MFB+Q==} + jsdom@30.0.1: resolution: {integrity: sha512-52v7mUVUfNQVYYqE1lcdaymWL0njO7lTLUog6ZvW2U5KsbiLk/GnZlVJ+qx0xfNJZ6Gn+KSpPNE52vurbxZwrA==} engines: {node: ^22.22.2 || ^24.15.0 || >=26.0.0} @@ -6788,6 +7228,10 @@ packages: resolution: {integrity: sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==} engines: {node: '>= 0.6.3'} + leven@3.1.0: + resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} + engines: {node: '>=6'} + levn@0.4.1: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} @@ -6798,6 +7242,9 @@ packages: libsodium@0.7.16: resolution: {integrity: sha512-3HrzSPuzm6Yt9aTYCDxYEG8x8/6C0+ag655Y7rhhWZM9PT4NpdnbqlzXhGZlDnkgR6MeSTnOt/VIyHLs9aSf+Q==} + lighthouse-logger@1.4.2: + resolution: {integrity: sha512-gPWxznF6TKmUHrOQjlVo2UbaL2EJ71mb2CCeRs/2qBpi4L/g4LUVc9+3lKQ6DTUZwJswfM7ainGrLO1+fOqa2g==} + lightningcss-android-arm64@1.32.0: resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} engines: {node: '>= 12.0.0'} @@ -7012,6 +7459,9 @@ packages: lodash.snakecase@4.1.1: resolution: {integrity: sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==} + lodash.throttle@4.1.1: + resolution: {integrity: sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==} + lodash@4.18.1: resolution: {integrity: sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==} @@ -7102,6 +7552,9 @@ packages: make-error@1.3.6: resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} + makeerror@1.0.12: + resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} + marked-terminal@7.3.0: resolution: {integrity: sha512-t4rBvPsHc57uE/2nJOLmMbZCQ4tgAccAED3ngXQqW6g+TxA488JzJ+FK3lQkzBQOI1mRV/r/Kq+1ZlJ4D0owQw==} engines: {node: '>=16.0.0'} @@ -7113,6 +7566,9 @@ packages: engines: {node: '>= 18'} hasBin: true + marky@1.3.0: + resolution: {integrity: sha512-ocnPZQLNpvbedwTy9kNrQEsknEfgvcLMvOtz3sFeWApDq1MXH1TqkCIx58xlpESsfwQOnuBO9beyQuNGzVvuhQ==} + math-intrinsics@1.1.0: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} @@ -7134,6 +7590,9 @@ packages: resolution: {integrity: sha512-yz3xRaG20c6/BOzvYoDaGtPmGscs7YivItZEEqe6GbwNfHuxu9YNmvnEkMzKldAGY4/80pRcQRZSEnhquk9XuQ==} engines: {node: '>= 0.8'} + memoize-one@5.2.1: + resolution: {integrity: sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==} + merge-descriptors@1.0.3: resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==} @@ -7152,6 +7611,64 @@ packages: resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} engines: {node: '>= 0.6'} + metro-babel-transformer@0.87.0: + resolution: {integrity: sha512-IEn1K1FyY4J1sA5y6zqDjf2OkfmpTEqhZOeP6MJX8HepSW0cuHGw1m8bYOdv2adkG3XUE9dtM0csUs0gP/Xa5w==} + engines: {node: ^22.13.0 || ^24.3.0 || >= 26.0.0} + + metro-cache-key@0.87.0: + resolution: {integrity: sha512-Q+MPt6jl0zQogr4Q02WaJK6HY+GtE5A0nzj8kIV1Owgrx6OMNvm6scPTr1SM/R4LpCE8EH/Y5qfbXQ84GHTr0Q==} + engines: {node: ^22.13.0 || ^24.3.0 || >= 26.0.0} + + metro-cache@0.87.0: + resolution: {integrity: sha512-146vS1BMSKcp99jddOhFBfHwzUEWN35NrsnSJDF2sQQ0ZT5OsBcOjd574PM233TWEZISRJ5DOK+vokD+1ubx+w==} + engines: {node: ^22.13.0 || ^24.3.0 || >= 26.0.0} + + metro-config@0.87.0: + resolution: {integrity: sha512-yZ9QAIzWH9MxwrzwRlX/CBGRWOT14l7klSDYg8hdtSdnoUs5A7MQRdHE2KB9iHVzGQW5wgWM5aXJswNeWbSQPA==} + engines: {node: ^22.13.0 || ^24.3.0 || >= 26.0.0} + + metro-core@0.87.0: + resolution: {integrity: sha512-yW57+pCOHRC/CJZ99GA2PTd+30dORwDAjUPRCokj91IWW5In9Jwtt2FB5wACrGO8P0GHTyVHdTwDNyZsNndUbA==} + engines: {node: ^22.13.0 || ^24.3.0 || >= 26.0.0} + + metro-file-map@0.87.0: + resolution: {integrity: sha512-Dc57t8jsINwA90bbVlqaeDlxf1rVGgj5SmOEnOMbaHNUM/HCYYTJxPV8SRdOBwh7qTz/biO9vaQvBTjRBgbbsg==} + engines: {node: ^22.13.0 || ^24.3.0 || >= 26.0.0} + + metro-minify-terser@0.87.0: + resolution: {integrity: sha512-tPa0O983PDutFu3LXbArRH5NduogcKrvW6fs9VHhksTKUA1iqDyoD1ZSj/Me52xJ6T9/9pOwIVyj9ulKc/zMkg==} + engines: {node: ^22.13.0 || ^24.3.0 || >= 26.0.0} + + metro-resolver@0.87.0: + resolution: {integrity: sha512-Xl3M9R3KToaHJvXlI2lSOxtYHitzxite+195DSi00HL9PcS7Xik5+3xlRjfkKb3FA86SZxYPj+WJwlcfgaZoxg==} + engines: {node: ^22.13.0 || ^24.3.0 || >= 26.0.0} + + metro-runtime@0.87.0: + resolution: {integrity: sha512-XsXZkgEwI0ZMYSBfvOMAbenzwa60XlObXJ27g6/Khgrz9ESbiBbAsd7hR62G2jRBYOhGAzG61Gk22dpRJj/mdw==} + engines: {node: ^22.13.0 || ^24.3.0 || >= 26.0.0} + + metro-source-map@0.87.0: + resolution: {integrity: sha512-31BrYqu1c2co93rF1LN9Pw+7g+BrfDyxJkNQWrYm+pfA/+eVYVumF7tFMHbXLePLmHfhvSgVvbK6su1Oyiw1ng==} + engines: {node: ^22.13.0 || ^24.3.0 || >= 26.0.0} + + metro-symbolicate@0.87.0: + resolution: {integrity: sha512-uOpTxAXu74N+RSujUZ78L6gjI6bDdnz6XuW+AIUNuubZDEQPIpaX0StzIb0GMeQWP6zfHOHwFrWPP5Iquu1GXw==} + engines: {node: ^22.13.0 || ^24.3.0 || >= 26.0.0} + hasBin: true + + metro-transform-plugins@0.87.0: + resolution: {integrity: sha512-i8keUe9+BaSwMuQM26DGheElCpTtflAKIrSwJAm8ZsgDb50RAUQus+e6zt2suaJXJ1OxZa7vqgtqoZxdniM6Fw==} + engines: {node: ^22.13.0 || ^24.3.0 || >= 26.0.0} + + metro-transform-worker@0.87.0: + resolution: {integrity: sha512-YftLzNJxCTYxEN5k4AzR8KYwiENTEuz30L+4QeoMrtDd+U8mDThZg/ArR3JVRd8LaikwPOjVAS5SP3xPJN0AaA==} + engines: {node: ^22.13.0 || ^24.3.0 || >= 26.0.0} + + metro@0.87.0: + resolution: {integrity: sha512-fRqFhSzQhLNQSCvJFeuRzBRXAOOKXf1O8d2cvmMtG6yFR0jCllQ7vBsXoLP18yuqtf+N1XwWXTPF11eWy9q6dQ==} + engines: {node: ^22.13.0 || ^24.3.0 || >= 26.0.0} + hasBin: true + micromatch@4.0.8: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} @@ -7367,6 +7884,9 @@ packages: engines: {node: ^22.22.2 || ^24.15.0 || >=26.0.0} hasBin: true + node-int64@0.4.0: + resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} + node-releases@2.0.53: resolution: {integrity: sha512-D9UOmYG3UH1V+ENW56t5QXBwJw1YEY18ruVeus89Rw+SyIgjPkCO84bRzO3uNIYosJbNwiabWVn48o3uJLjxFQ==} engines: {node: '>=18'} @@ -7407,6 +7927,9 @@ packages: nth-check@2.1.1: resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} + nullthrows@1.1.1: + resolution: {integrity: sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==} + nx@23.1.1: resolution: {integrity: sha512-oDdW2JgVllgfyyN6OqlRzeABw0QrlXdxyl9rtOUMMXQzlkpYA1RTs8jinJCe6QSo7aEn0dZ+Ar7dd09hMudBsg==} hasBin: true @@ -7419,6 +7942,10 @@ packages: '@swc/core': optional: true + ob1@0.87.0: + resolution: {integrity: sha512-8Q8sKCiUwsxgSmjDtVWyRgmxsgeJXXam3oQH6Id8ADfNaJMV6GZKyeAl8+pGVVdgwAZabfk5+aExle7AP/nZiA==} + engines: {node: ^22.13.0 || ^24.3.0 || >= 26.0.0} + object-assign@4.1.1: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} @@ -7497,6 +8024,10 @@ packages: resolution: {integrity: sha512-IFenVPgF70fSm1keSd2iDBIDIBZkroLeuffXq+wKTzTJlBpesFWojV9lb8mzOfaAzM1sr7HQHuO0vtV0zYekGg==} engines: {node: '>=8'} + open@7.4.2: + resolution: {integrity: sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==} + engines: {node: '>=8'} + openapi3-ts@3.2.0: resolution: {integrity: sha512-/ykNWRV5Qs0Nwq7Pc0nJ78fgILvOT/60OxEmB3v7yQ8a8Bwcm43D4diaYazG/KBn6czA+52XYy931WFLMCUeSg==} @@ -7811,6 +8342,10 @@ packages: resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + pretty-format@29.7.0: + resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + pretty-ms@9.3.0: resolution: {integrity: sha512-gjVS5hOP+M3wMm5nmNOucbIrqudzs9v/57bWRHQWLYklXqoXKrVfYW2W9+glfGsqtPgpiz5WwyEEB+ksXIx3gQ==} engines: {node: '>=18'} @@ -7839,6 +8374,9 @@ packages: promise-breaker@6.0.0: resolution: {integrity: sha512-BthzO9yTPswGf7etOBiHCVuugs2N01/Q/94dIPls48z2zCmrnDptUUZzfIb+41xq0MnYZ/BzmOd6ikDR4ibNZA==} + promise@8.3.0: + resolution: {integrity: sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==} + prop-types@15.8.1: resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} @@ -7895,6 +8433,9 @@ packages: queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + queue@6.0.2: + resolution: {integrity: sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==} + quick-format-unescaped@4.0.4: resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==} @@ -7940,6 +8481,9 @@ packages: resolution: {integrity: sha512-xLgQil4kIUCrAzVk9fRSkxkFNwmygLFjVxXrLc65aE1F0+Zsb8rxumFBy4XKyvgMCTL6kilDq3EZ0piE2dP/Dg==} engines: {node: '>=18.0.0'} + react-devtools-core@6.1.5: + resolution: {integrity: sha512-ePrwPfxAnB+7hgnEr8vpKxL9cmnp7F322t8oqcPshbIQQhDKgFDW4tjhF2wjVbdXF9O/nyuy3sQWd9JGpiLPvA==} + react-dom@19.2.8: resolution: {integrity: sha512-rVprimfGBG3DR+Tq0IQG2DT5PxKth1WIGDmj5yPmlzr4YBe7uyE+Du4oVqTDXZSHGGGXRtTJEGSSePyQCMBglQ==} peerDependencies: @@ -7951,6 +8495,29 @@ packages: react-is@17.0.2: resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} + react-is@18.3.1: + resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} + + react-native-url-polyfill@4.0.0: + resolution: {integrity: sha512-eqYM3wBAA0eL1sPYbBAoNfbES3+NkgcxUdelQ7QzmoVtqKB5qGG0U13MPTRUroAWK+y2EoJFS3MZUK0fwTf0pA==} + peerDependencies: + react-native: '*' + + react-native@0.87.1: + resolution: {integrity: sha512-DJKG6ANoD7BtrE4z9DewiSD7/RxCX73lK5Pu49aUr85P3333Dm2roTiP0rRjQNDZdVizHSOmstWfwF/o9EjCRA==} + engines: {node: ^22.13.0 || ^24.3.0 || >= 26.0.0} + hasBin: true + peerDependencies: + '@types/react': ^19.1.1 + react: ^19.2.3 + peerDependenciesMeta: + '@types/react': + optional: true + + react-refresh@0.14.2: + resolution: {integrity: sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==} + engines: {node: '>=0.10.0'} + react@19.2.8: resolution: {integrity: sha512-PWaYA1L/q9u2u7xYQi+Y3L3Yfnie7XyLeaJICV1MGD6LprsBxcAqGjYyr0eY3p+QdsA+x/Irkt4Qif8D63+Sbw==} engines: {node: '>=0.10.0'} @@ -8000,6 +8567,9 @@ packages: regenerate@1.4.2: resolution: {integrity: sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==} + regenerator-runtime@0.13.11: + resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==} + regexp.prototype.flags@1.5.4: resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} engines: {node: '>= 0.4'} @@ -8216,6 +8786,10 @@ packages: resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==} engines: {node: '>= 18'} + serialize-error@2.1.0: + resolution: {integrity: sha512-ghgmKt5o4Tly5yEG/UJp8qTd0AN7Xalw4XBtDEKP655B699qMEtra1WlXeE6WIvdEG481JvRxULKsInq/iNysw==} + engines: {node: '>=0.10.0'} + seroval-plugins@1.5.6: resolution: {integrity: sha512-HXuLAX2pu/UByPpaeo/TaMfvMIi+1QqIoPJYCcAtU8QkVNwgR6MPlGuCQTErV1JwraaMbYaWVIBX7mppzGLATQ==} engines: {node: '>=10'} @@ -8267,6 +8841,10 @@ packages: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} + shell-quote@1.10.0: + resolution: {integrity: sha512-w1aiOKwKuRgtwAReIIj89puqg+I7GvX4IbLrvmhXbzQsj1+Zwi4VO3+fa6ZF91TWSjIxoEkKnMeHcLEODK5ZXA==} + engines: {node: '>= 0.4'} + side-channel-list@1.0.1: resolution: {integrity: sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==} engines: {node: '>= 0.4'} @@ -8354,6 +8932,10 @@ packages: source-map-support@0.5.21: resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + source-map@0.5.7: + resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==} + engines: {node: '>=0.10.0'} + source-map@0.6.1: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} @@ -8396,6 +8978,13 @@ packages: stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + stackframe@1.3.4: + resolution: {integrity: sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==} + + stacktrace-parser@0.1.11: + resolution: {integrity: sha512-WjlahMgHmCJpqzU8bIBy4qtsZdU9lRlcZE3Lvyej6t4tuOuv1vk57OW3MBrj6hXBFx/nNoC9MPMTcr5YA7NQbg==} + engines: {node: '>=6'} + statuses@1.5.0: resolution: {integrity: sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==} engines: {node: '>= 0.6'} @@ -8668,6 +9257,9 @@ packages: thread-stream@3.2.0: resolution: {integrity: sha512-zLBvqpwr4Esa0kRjcrzGU6zL25lePWaCLMx0RQFrmteozIfeNdaMLpG5U7PeHzvlFkAWaRKA9/KVW4F60iB+qw==} + throat@5.0.0: + resolution: {integrity: sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==} + through2@2.0.5: resolution: {integrity: sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==} @@ -8711,6 +9303,9 @@ packages: resolution: {integrity: sha512-e0votIpp4Uo2AJYSzVHV6xCcawuiez3DzqDAbrTc3YxBkplN6e+dM13ZeIcZnDg/QpSuU2zfZ3rzwY8ukEnaXw==} engines: {node: '>=14.14'} + tmpl@1.0.5: + resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} + to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} @@ -8808,6 +9403,10 @@ packages: resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} engines: {node: '>=10'} + type-fest@0.7.1: + resolution: {integrity: sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==} + engines: {node: '>=8'} + type-fest@4.41.0: resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==} engines: {node: '>=16'} @@ -9170,6 +9769,9 @@ packages: jsdom: optional: true + vlq@1.0.1: + resolution: {integrity: sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w==} + vscode-uri@3.2.0: resolution: {integrity: sha512-m2gXo3bn0G1kT9InzMf07fTbqMbGtyckj3bH5ktLO+1Ssv+yiATZ4dhwaQv9UZWxJh6E9IFGnQyjgWVDWVBDrg==} @@ -9177,6 +9779,9 @@ packages: resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} engines: {node: '>=18'} + walker@1.0.8: + resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} + watchpack@2.5.2: resolution: {integrity: sha512-6i/00NBjP4yGPs+caKSyRfpTF/8Torsu0MOW3mMzIbhgISFder8i7xbqgHlLMwJrdiN8ndBV3UA1/AfzPSr+jg==} engines: {node: '>=10.13.0'} @@ -9326,6 +9931,18 @@ packages: write-file-atomic@3.0.3: resolution: {integrity: sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==} + ws@7.5.13: + resolution: {integrity: sha512-rsKI6xDBFVf4r/x8XyChGK04QR/XHroxs/jUcoWvtEZM8TPU/X/uIY9B1CsSzYws9ZJb/6bbBu7dPhFW00CAoA==} + engines: {node: '>=8.3.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ^5.0.2 + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + ws@8.18.0: resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} engines: {node: '>=10.0.0'} @@ -10581,6 +11198,16 @@ snapshots: '@fastify/busboy@3.2.2': {} + '@firebase/ai@2.14.0(@firebase/app-types@0.9.5)(@firebase/app@0.16.0)': + dependencies: + '@firebase/app': 0.16.0 + '@firebase/app-check-interop-types': 0.3.4 + '@firebase/app-types': 0.9.5 + '@firebase/component': 0.7.4 + '@firebase/logger': 0.5.1 + '@firebase/util': 1.15.2 + tslib: 2.8.1 + '@firebase/ai@2.15.0(@firebase/app-types@0.9.6)(@firebase/app@0.16.1)': dependencies: '@firebase/app': 0.16.1 @@ -10591,6 +11218,16 @@ snapshots: '@firebase/util': 1.15.3 tslib: 2.8.1 + '@firebase/analytics-compat@0.2.29(@firebase/app-compat@0.5.16)(@firebase/app@0.16.0)': + dependencies: + '@firebase/analytics': 0.10.23(@firebase/app@0.16.0) + '@firebase/analytics-types': 0.8.4 + '@firebase/app': 0.16.0 + '@firebase/app-compat': 0.5.16 + '@firebase/component': 0.7.4 + '@firebase/util': 1.15.2 + tslib: 2.8.1 + '@firebase/analytics-compat@0.2.30(@firebase/app-compat@0.5.17)(@firebase/app@0.16.1)': dependencies: '@firebase/analytics': 0.10.24(@firebase/app@0.16.1) @@ -10601,8 +11238,19 @@ snapshots: '@firebase/util': 1.15.3 tslib: 2.8.1 + '@firebase/analytics-types@0.8.4': {} + '@firebase/analytics-types@0.8.5': {} + '@firebase/analytics@0.10.23(@firebase/app@0.16.0)': + dependencies: + '@firebase/app': 0.16.0 + '@firebase/component': 0.7.4 + '@firebase/installations': 0.6.23(@firebase/app@0.16.0) + '@firebase/logger': 0.5.1 + '@firebase/util': 1.15.2 + tslib: 2.8.1 + '@firebase/analytics@0.10.24(@firebase/app@0.16.1)': dependencies: '@firebase/app': 0.16.1 @@ -10612,6 +11260,17 @@ snapshots: '@firebase/util': 1.15.3 tslib: 2.8.1 + '@firebase/app-check-compat@0.4.6(@firebase/app-compat@0.5.16)(@firebase/app@0.16.0)': + dependencies: + '@firebase/app': 0.16.0 + '@firebase/app-check': 0.13.0(@firebase/app@0.16.0) + '@firebase/app-check-types': 0.5.4 + '@firebase/app-compat': 0.5.16 + '@firebase/component': 0.7.4 + '@firebase/logger': 0.5.1 + '@firebase/util': 1.15.2 + tslib: 2.8.1 + '@firebase/app-check-compat@0.4.7(@firebase/app-compat@0.5.17)(@firebase/app@0.16.1)': dependencies: '@firebase/app': 0.16.1 @@ -10623,10 +11282,22 @@ snapshots: '@firebase/util': 1.15.3 tslib: 2.8.1 + '@firebase/app-check-interop-types@0.3.4': {} + '@firebase/app-check-interop-types@0.3.5': {} + '@firebase/app-check-types@0.5.4': {} + '@firebase/app-check-types@0.5.5': {} + '@firebase/app-check@0.13.0(@firebase/app@0.16.0)': + dependencies: + '@firebase/app': 0.16.0 + '@firebase/component': 0.7.4 + '@firebase/logger': 0.5.1 + '@firebase/util': 1.15.2 + tslib: 2.8.1 + '@firebase/app-check@0.13.1(@firebase/app@0.16.1)': dependencies: '@firebase/app': 0.16.1 @@ -10635,6 +11306,14 @@ snapshots: '@firebase/util': 1.15.3 tslib: 2.8.1 + '@firebase/app-compat@0.5.16': + dependencies: + '@firebase/app': 0.16.0 + '@firebase/component': 0.7.4 + '@firebase/logger': 0.5.1 + '@firebase/util': 1.15.2 + tslib: 2.8.1 + '@firebase/app-compat@0.5.17': dependencies: '@firebase/app': 0.16.1 @@ -10643,10 +11322,22 @@ snapshots: '@firebase/util': 1.15.3 tslib: 2.8.1 + '@firebase/app-types@0.9.5': + dependencies: + '@firebase/logger': 0.5.1 + '@firebase/app-types@0.9.6': dependencies: '@firebase/logger': 0.5.2 + '@firebase/app@0.16.0': + dependencies: + '@firebase/component': 0.7.4 + '@firebase/logger': 0.5.1 + '@firebase/util': 1.15.2 + idb: 7.1.1 + tslib: 2.8.1 + '@firebase/app@0.16.1': dependencies: '@firebase/component': 0.7.5 @@ -10668,13 +11359,41 @@ snapshots: - '@firebase/app-types' - '@react-native-async-storage/async-storage' + '@firebase/auth-compat@0.6.9(@firebase/app-compat@0.5.16)(@firebase/app-types@0.9.5)(@firebase/app@0.16.0)': + dependencies: + '@firebase/app': 0.16.0 + '@firebase/app-compat': 0.5.16 + '@firebase/auth': 1.13.4(@firebase/app@0.16.0) + '@firebase/auth-types': 0.13.1(@firebase/app-types@0.9.5)(@firebase/util@1.15.2) + '@firebase/component': 0.7.4 + '@firebase/util': 1.15.2 + tslib: 2.8.1 + transitivePeerDependencies: + - '@firebase/app-types' + - '@react-native-async-storage/async-storage' + + '@firebase/auth-interop-types@0.2.5': {} + '@firebase/auth-interop-types@0.2.6': {} + '@firebase/auth-types@0.13.1(@firebase/app-types@0.9.5)(@firebase/util@1.15.2)': + dependencies: + '@firebase/app-types': 0.9.5 + '@firebase/util': 1.15.2 + '@firebase/auth-types@0.13.2(@firebase/app-types@0.9.6)(@firebase/util@1.15.3)': dependencies: '@firebase/app-types': 0.9.6 '@firebase/util': 1.15.3 + '@firebase/auth@1.13.4(@firebase/app@0.16.0)': + dependencies: + '@firebase/app': 0.16.0 + '@firebase/component': 0.7.4 + '@firebase/logger': 0.5.1 + '@firebase/util': 1.15.2 + tslib: 2.8.1 + '@firebase/auth@1.13.5(@firebase/app@0.16.1)': dependencies: '@firebase/app': 0.16.1 @@ -10683,11 +11402,25 @@ snapshots: '@firebase/util': 1.15.3 tslib: 2.8.1 + '@firebase/component@0.7.4': + dependencies: + '@firebase/util': 1.15.2 + tslib: 2.8.1 + '@firebase/component@0.7.5': dependencies: '@firebase/util': 1.15.3 tslib: 2.8.1 + '@firebase/data-connect@0.7.3(@firebase/app@0.16.0)': + dependencies: + '@firebase/app': 0.16.0 + '@firebase/auth-interop-types': 0.2.5 + '@firebase/component': 0.7.4 + '@firebase/logger': 0.5.1 + '@firebase/util': 1.15.2 + tslib: 2.8.1 + '@firebase/data-connect@0.7.4(@firebase/app@0.16.1)': dependencies: '@firebase/app': 0.16.1 @@ -10697,6 +11430,18 @@ snapshots: '@firebase/util': 1.15.3 tslib: 2.8.1 + '@firebase/database-compat@2.1.6(@firebase/app-compat@0.5.16)(@firebase/app@0.16.0)': + dependencies: + '@firebase/component': 0.7.4 + '@firebase/database': 1.1.4 + '@firebase/database-types': 1.0.21 + '@firebase/logger': 0.5.1 + '@firebase/util': 1.15.2 + tslib: 2.8.1 + optionalDependencies: + '@firebase/app': 0.16.0 + '@firebase/app-compat': 0.5.16 + '@firebase/database-compat@2.1.7(@firebase/app-compat@0.5.17)(@firebase/app@0.16.1)': dependencies: '@firebase/component': 0.7.5 @@ -10709,11 +11454,26 @@ snapshots: '@firebase/app': 0.16.1 '@firebase/app-compat': 0.5.17 + '@firebase/database-types@1.0.21': + dependencies: + '@firebase/app-types': 0.9.5 + '@firebase/util': 1.15.2 + '@firebase/database-types@1.0.22': dependencies: '@firebase/app-types': 0.9.6 '@firebase/util': 1.15.3 + '@firebase/database@1.1.4': + dependencies: + '@firebase/app-check-interop-types': 0.3.4 + '@firebase/auth-interop-types': 0.2.5 + '@firebase/component': 0.7.4 + '@firebase/logger': 0.5.1 + '@firebase/util': 1.15.2 + faye-websocket: 0.11.4 + tslib: 2.8.1 + '@firebase/database@1.1.5': dependencies: '@firebase/app-check-interop-types': 0.3.5 @@ -10724,6 +11484,18 @@ snapshots: faye-websocket: 0.11.4 tslib: 2.8.1 + '@firebase/firestore-compat@0.4.12(@firebase/app-compat@0.5.16)(@firebase/app-types@0.9.5)(@firebase/app@0.16.0)': + dependencies: + '@firebase/app': 0.16.0 + '@firebase/app-compat': 0.5.16 + '@firebase/component': 0.7.4 + '@firebase/firestore': 4.17.0(@firebase/app@0.16.0) + '@firebase/firestore-types': 3.0.4(@firebase/app-types@0.9.5)(@firebase/util@1.15.2) + '@firebase/util': 1.15.2 + tslib: 2.8.1 + transitivePeerDependencies: + - '@firebase/app-types' + '@firebase/firestore-compat@0.4.13(@firebase/app-compat@0.5.17)(@firebase/app-types@0.9.6)(@firebase/app@0.16.1)': dependencies: '@firebase/app': 0.16.1 @@ -10736,11 +11508,28 @@ snapshots: transitivePeerDependencies: - '@firebase/app-types' + '@firebase/firestore-types@3.0.4(@firebase/app-types@0.9.5)(@firebase/util@1.15.2)': + dependencies: + '@firebase/app-types': 0.9.5 + '@firebase/util': 1.15.2 + '@firebase/firestore-types@3.0.5(@firebase/app-types@0.9.6)(@firebase/util@1.15.3)': dependencies: '@firebase/app-types': 0.9.6 '@firebase/util': 1.15.3 + '@firebase/firestore@4.17.0(@firebase/app@0.16.0)': + dependencies: + '@firebase/app': 0.16.0 + '@firebase/component': 0.7.4 + '@firebase/logger': 0.5.1 + '@firebase/util': 1.15.2 + '@firebase/webchannel-wrapper': 1.0.6 + '@grpc/grpc-js': 1.9.16 + '@grpc/proto-loader': 0.7.15 + re2js: 2.8.6 + tslib: 2.8.1 + '@firebase/firestore@4.17.1(@firebase/app@0.16.1)': dependencies: '@firebase/app': 0.16.1 @@ -10753,6 +11542,16 @@ snapshots: re2js: 2.8.6 tslib: 2.8.1 + '@firebase/functions-compat@0.4.6(@firebase/app-compat@0.5.16)(@firebase/app@0.16.0)': + dependencies: + '@firebase/app': 0.16.0 + '@firebase/app-compat': 0.5.16 + '@firebase/component': 0.7.4 + '@firebase/functions': 0.13.6(@firebase/app@0.16.0) + '@firebase/functions-types': 0.6.4 + '@firebase/util': 1.15.2 + tslib: 2.8.1 + '@firebase/functions-compat@0.5.0(@firebase/app-compat@0.5.17)(@firebase/app@0.16.1)': dependencies: '@firebase/app': 0.16.1 @@ -10763,8 +11562,20 @@ snapshots: '@firebase/util': 1.15.3 tslib: 2.8.1 + '@firebase/functions-types@0.6.4': {} + '@firebase/functions-types@0.6.5': {} + '@firebase/functions@0.13.6(@firebase/app@0.16.0)': + dependencies: + '@firebase/app': 0.16.0 + '@firebase/app-check-interop-types': 0.3.4 + '@firebase/auth-interop-types': 0.2.5 + '@firebase/component': 0.7.4 + '@firebase/messaging-interop-types': 0.2.5 + '@firebase/util': 1.15.2 + tslib: 2.8.1 + '@firebase/functions@0.14.0(@firebase/app@0.16.1)': dependencies: '@firebase/app': 0.16.1 @@ -10775,6 +11586,18 @@ snapshots: '@firebase/util': 1.15.3 tslib: 2.8.1 + '@firebase/installations-compat@0.2.23(@firebase/app-compat@0.5.16)(@firebase/app-types@0.9.5)(@firebase/app@0.16.0)': + dependencies: + '@firebase/app': 0.16.0 + '@firebase/app-compat': 0.5.16 + '@firebase/component': 0.7.4 + '@firebase/installations': 0.6.23(@firebase/app@0.16.0) + '@firebase/installations-types': 0.5.4(@firebase/app-types@0.9.5) + '@firebase/util': 1.15.2 + tslib: 2.8.1 + transitivePeerDependencies: + - '@firebase/app-types' + '@firebase/installations-compat@0.2.24(@firebase/app-compat@0.5.17)(@firebase/app-types@0.9.6)(@firebase/app@0.16.1)': dependencies: '@firebase/app': 0.16.1 @@ -10787,10 +11610,22 @@ snapshots: transitivePeerDependencies: - '@firebase/app-types' + '@firebase/installations-types@0.5.4(@firebase/app-types@0.9.5)': + dependencies: + '@firebase/app-types': 0.9.5 + '@firebase/installations-types@0.5.5(@firebase/app-types@0.9.6)': dependencies: '@firebase/app-types': 0.9.6 + '@firebase/installations@0.6.23(@firebase/app@0.16.0)': + dependencies: + '@firebase/app': 0.16.0 + '@firebase/component': 0.7.4 + '@firebase/util': 1.15.2 + idb: 7.1.1 + tslib: 2.8.1 + '@firebase/installations@0.6.24(@firebase/app@0.16.1)': dependencies: '@firebase/app': 0.16.1 @@ -10799,10 +11634,23 @@ snapshots: idb: 7.1.1 tslib: 2.8.1 + '@firebase/logger@0.5.1': + dependencies: + tslib: 2.8.1 + '@firebase/logger@0.5.2': dependencies: tslib: 2.8.1 + '@firebase/messaging-compat@0.2.28(@firebase/app-compat@0.5.16)(@firebase/app@0.16.0)': + dependencies: + '@firebase/app': 0.16.0 + '@firebase/app-compat': 0.5.16 + '@firebase/component': 0.7.4 + '@firebase/messaging': 0.13.1(@firebase/app@0.16.0) + '@firebase/util': 1.15.2 + tslib: 2.8.1 + '@firebase/messaging-compat@0.2.29(@firebase/app-compat@0.5.17)(@firebase/app@0.16.1)': dependencies: '@firebase/app': 0.16.1 @@ -10812,8 +11660,20 @@ snapshots: '@firebase/util': 1.15.3 tslib: 2.8.1 + '@firebase/messaging-interop-types@0.2.5': {} + '@firebase/messaging-interop-types@0.2.6': {} + '@firebase/messaging@0.13.1(@firebase/app@0.16.0)': + dependencies: + '@firebase/app': 0.16.0 + '@firebase/component': 0.7.4 + '@firebase/installations': 0.6.23(@firebase/app@0.16.0) + '@firebase/messaging-interop-types': 0.2.5 + '@firebase/util': 1.15.2 + idb: 7.1.1 + tslib: 2.8.1 + '@firebase/messaging@0.13.2(@firebase/app@0.16.1)': dependencies: '@firebase/app': 0.16.1 @@ -10824,6 +11684,17 @@ snapshots: idb: 7.1.1 tslib: 2.8.1 + '@firebase/performance-compat@0.2.26(@firebase/app-compat@0.5.16)(@firebase/app@0.16.0)': + dependencies: + '@firebase/app': 0.16.0 + '@firebase/app-compat': 0.5.16 + '@firebase/component': 0.7.4 + '@firebase/logger': 0.5.1 + '@firebase/performance': 0.7.13(@firebase/app@0.16.0) + '@firebase/performance-types': 0.2.4 + '@firebase/util': 1.15.2 + tslib: 2.8.1 + '@firebase/performance-compat@0.2.27(@firebase/app-compat@0.5.17)(@firebase/app@0.16.1)': dependencies: '@firebase/app': 0.16.1 @@ -10835,8 +11706,20 @@ snapshots: '@firebase/util': 1.15.3 tslib: 2.8.1 + '@firebase/performance-types@0.2.4': {} + '@firebase/performance-types@0.2.5': {} + '@firebase/performance@0.7.13(@firebase/app@0.16.0)': + dependencies: + '@firebase/app': 0.16.0 + '@firebase/component': 0.7.4 + '@firebase/installations': 0.6.23(@firebase/app@0.16.0) + '@firebase/logger': 0.5.1 + '@firebase/util': 1.15.2 + tslib: 2.8.1 + web-vitals: 4.2.4 + '@firebase/performance@0.7.14(@firebase/app@0.16.1)': dependencies: '@firebase/app': 0.16.1 @@ -10847,6 +11730,17 @@ snapshots: tslib: 2.8.1 web-vitals: 4.2.4 + '@firebase/remote-config-compat@0.2.28(@firebase/app-compat@0.5.16)(@firebase/app@0.16.0)': + dependencies: + '@firebase/app': 0.16.0 + '@firebase/app-compat': 0.5.16 + '@firebase/component': 0.7.4 + '@firebase/logger': 0.5.1 + '@firebase/remote-config': 0.9.1(@firebase/app@0.16.0) + '@firebase/remote-config-types': 0.5.1 + '@firebase/util': 1.15.2 + tslib: 2.8.1 + '@firebase/remote-config-compat@0.2.29(@firebase/app-compat@0.5.17)(@firebase/app@0.16.1)': dependencies: '@firebase/app': 0.16.1 @@ -10858,8 +11752,19 @@ snapshots: '@firebase/util': 1.15.3 tslib: 2.8.1 + '@firebase/remote-config-types@0.5.1': {} + '@firebase/remote-config-types@0.5.2': {} + '@firebase/remote-config@0.9.1(@firebase/app@0.16.0)': + dependencies: + '@firebase/app': 0.16.0 + '@firebase/component': 0.7.4 + '@firebase/installations': 0.6.23(@firebase/app@0.16.0) + '@firebase/logger': 0.5.1 + '@firebase/util': 1.15.2 + tslib: 2.8.1 + '@firebase/remote-config@0.9.2(@firebase/app@0.16.1)': dependencies: '@firebase/app': 0.16.1 @@ -10869,6 +11774,18 @@ snapshots: '@firebase/util': 1.15.3 tslib: 2.8.1 + '@firebase/storage-compat@0.4.4(@firebase/app-compat@0.5.16)(@firebase/app-types@0.9.5)(@firebase/app@0.16.0)': + dependencies: + '@firebase/app': 0.16.0 + '@firebase/app-compat': 0.5.16 + '@firebase/component': 0.7.4 + '@firebase/storage': 0.14.4(@firebase/app@0.16.0) + '@firebase/storage-types': 0.8.4(@firebase/app-types@0.9.5)(@firebase/util@1.15.2) + '@firebase/util': 1.15.2 + tslib: 2.8.1 + transitivePeerDependencies: + - '@firebase/app-types' + '@firebase/storage-compat@0.4.5(@firebase/app-compat@0.5.17)(@firebase/app-types@0.9.6)(@firebase/app@0.16.1)': dependencies: '@firebase/app': 0.16.1 @@ -10881,11 +11798,23 @@ snapshots: transitivePeerDependencies: - '@firebase/app-types' + '@firebase/storage-types@0.8.4(@firebase/app-types@0.9.5)(@firebase/util@1.15.2)': + dependencies: + '@firebase/app-types': 0.9.5 + '@firebase/util': 1.15.2 + '@firebase/storage-types@0.8.5(@firebase/app-types@0.9.6)(@firebase/util@1.15.3)': dependencies: '@firebase/app-types': 0.9.6 '@firebase/util': 1.15.3 + '@firebase/storage@0.14.4(@firebase/app@0.16.0)': + dependencies: + '@firebase/app': 0.16.0 + '@firebase/component': 0.7.4 + '@firebase/util': 1.15.2 + tslib: 2.8.1 + '@firebase/storage@0.14.5(@firebase/app@0.16.1)': dependencies: '@firebase/app': 0.16.1 @@ -10893,10 +11822,16 @@ snapshots: '@firebase/util': 1.15.3 tslib: 2.8.1 + '@firebase/util@1.15.2': + dependencies: + tslib: 2.8.1 + '@firebase/util@1.15.3': dependencies: tslib: 2.8.1 + '@firebase/webchannel-wrapper@1.0.6': {} + '@firebase/webchannel-wrapper@1.0.7': {} '@google-cloud/cloud-sql-connector@1.11.3': @@ -11184,8 +12119,23 @@ snapshots: dependencies: minipass: 7.1.3 + '@isaacs/ttlcache@1.4.1': {} + '@jest/diff-sequences@30.0.1': {} + '@jest/schemas@29.6.3': + dependencies: + '@sinclair/typebox': 0.27.12 + + '@jest/types@29.6.3': + dependencies: + '@jest/schemas': 29.6.3 + '@types/istanbul-lib-coverage': 2.0.6 + '@types/istanbul-reports': 3.0.4 + '@types/node': 24.13.3 + '@types/yargs': 17.0.35 + chalk: 4.1.2 + '@jridgewell/gen-mapping@0.3.13': dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -12169,21 +13119,103 @@ snapshots: '@protobufjs/base64@1.1.2': {} - '@protobufjs/codegen@2.0.5': {} + '@protobufjs/codegen@2.0.5': {} + + '@protobufjs/eventemitter@1.1.1': {} + + '@protobufjs/fetch@1.1.1': + dependencies: + '@protobufjs/aspromise': 1.1.2 + + '@protobufjs/float@1.0.2': {} + + '@protobufjs/path@1.1.2': {} + + '@protobufjs/pool@1.1.0': {} + + '@protobufjs/utf8@1.1.2': {} + + '@react-native-firebase/app@26.3.3(react-native@0.87.1(@babel/core@7.29.7)(@types/react@19.2.18)(react@19.2.8))(react@19.2.8)': + dependencies: + firebase: 12.17.1 + react: 19.2.8 + react-native: 0.87.1(@babel/core@7.29.7)(@types/react@19.2.18)(react@19.2.8) + transitivePeerDependencies: + - '@react-native-async-storage/async-storage' + + '@react-native-firebase/firestore@26.3.3(@react-native-firebase/app@26.3.3(react-native@0.87.1(@babel/core@7.29.7)(@types/react@19.2.18)(react@19.2.8))(react@19.2.8))(react-native@0.87.1(@babel/core@7.29.7)(@types/react@19.2.18)(react@19.2.8))': + dependencies: + '@react-native-firebase/app': 26.3.3(react-native@0.87.1(@babel/core@7.29.7)(@types/react@19.2.18)(react@19.2.8))(react@19.2.8) + react-native-url-polyfill: 4.0.0(react-native@0.87.1(@babel/core@7.29.7)(@types/react@19.2.18)(react@19.2.8)) + transitivePeerDependencies: + - react-native + + '@react-native/asset-utils@0.87.1': {} + + '@react-native/codegen@0.87.1(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/parser': 7.29.8 + hermes-parser: 0.36.1 + invariant: 2.2.4 + nullthrows: 1.1.1 + tinyglobby: 0.2.17 + yargs: 17.7.3 + + '@react-native/community-cli-plugin@0.87.1': + dependencies: + '@react-native/asset-utils': 0.87.1 + '@react-native/dev-middleware': 0.87.1 + debug: 4.4.3(supports-color@7.2.0) + invariant: 2.2.4 + metro: 0.87.0 + semver: 7.8.5 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate - '@protobufjs/eventemitter@1.1.1': {} + '@react-native/debugger-frontend@0.87.1': {} - '@protobufjs/fetch@1.1.1': + '@react-native/debugger-shell@0.87.1': dependencies: - '@protobufjs/aspromise': 1.1.2 + cross-spawn: 7.0.6 + debug: 4.4.3(supports-color@7.2.0) + fb-dotslash: 0.5.8 + transitivePeerDependencies: + - supports-color - '@protobufjs/float@1.0.2': {} + '@react-native/dev-middleware@0.87.1': + dependencies: + '@isaacs/ttlcache': 1.4.1 + '@react-native/debugger-frontend': 0.87.1 + '@react-native/debugger-shell': 0.87.1 + chrome-launcher: 0.15.2 + chromium-edge-launcher: 0.3.0 + connect: 3.7.0 + debug: 4.4.3(supports-color@7.2.0) + invariant: 2.2.4 + nullthrows: 1.1.1 + open: 7.4.2 + serve-static: 1.16.3 + ws: 7.5.13 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate - '@protobufjs/path@1.1.2': {} + '@react-native/gradle-plugin@0.87.1': {} - '@protobufjs/pool@1.1.0': {} + '@react-native/normalize-colors@0.87.1': {} - '@protobufjs/utf8@1.1.2': {} + '@react-native/virtualized-lists@0.87.1(@types/react@19.2.18)(react-native@0.87.1(@babel/core@7.29.7)(@types/react@19.2.18)(react@19.2.8))(react@19.2.8)': + dependencies: + invariant: 2.2.4 + nullthrows: 1.1.1 + react: 19.2.8 + react-native: 0.87.1(@babel/core@7.29.7)(@types/react@19.2.18)(react@19.2.8) + optionalDependencies: + '@types/react': 19.2.18 '@rolldown/binding-android-arm-eabi@1.2.6': optional: true @@ -12473,6 +13505,8 @@ snapshots: '@sec-ant/readable-stream@0.4.1': {} + '@sinclair/typebox@0.27.12': {} + '@sindresorhus/is@4.6.0': {} '@sindresorhus/is@7.2.0': {} @@ -13155,6 +14189,16 @@ snapshots: dependencies: '@types/node': 24.13.3 + '@types/istanbul-lib-coverage@2.0.6': {} + + '@types/istanbul-lib-report@3.0.3': + dependencies: + '@types/istanbul-lib-coverage': 2.0.6 + + '@types/istanbul-reports@3.0.4': + dependencies: + '@types/istanbul-lib-report': 3.0.3 + '@types/json-schema@7.0.15': {} '@types/json5@0.0.29': {} @@ -13217,6 +14261,12 @@ snapshots: '@types/triple-beam@1.3.5': {} + '@types/yargs-parser@21.0.3': {} + + '@types/yargs@17.0.35': + dependencies: + '@types/yargs-parser': 21.0.3 + '@typescript-eslint/eslint-plugin@8.66.0(@typescript-eslint/parser@8.66.0(eslint@9.39.5(jiti@2.7.0))(typescript@6.0.3))(eslint@9.39.5(jiti@2.7.0))(typescript@6.0.3)': dependencies: '@eslint-community/regexpp': 4.12.2 @@ -13931,6 +14981,8 @@ snapshots: alien-signals@0.4.14: {} + anser@1.4.10: {} + ansi-align@3.0.1: dependencies: string-width: 4.2.3 @@ -14080,6 +15132,8 @@ snapshots: as-array@2.0.0: {} + asap@2.0.6: {} + asn1@0.2.6: dependencies: safer-buffer: 2.1.2 @@ -14218,6 +15272,10 @@ snapshots: transitivePeerDependencies: - supports-color + babel-plugin-syntax-hermes-parser@0.36.1: + dependencies: + hermes-parser: 0.36.1 + babel-plugin-transform-typescript-metadata@0.3.2(@babel/core@7.29.7)(@babel/traverse@7.29.8): dependencies: '@babel/core': 7.29.7 @@ -14382,6 +15440,10 @@ snapshots: node-releases: 2.0.53 update-browserslist-db: 1.3.1(browserslist@4.28.8) + bser@2.1.1: + dependencies: + node-int64: 0.4.0 + btoa@1.2.1: optional: true @@ -14485,12 +15547,33 @@ snapshots: chownr@3.0.0: {} + chrome-launcher@0.15.2: + dependencies: + '@types/node': 24.13.3 + escape-string-regexp: 4.0.0 + is-wsl: 2.2.0 + lighthouse-logger: 1.4.2 + transitivePeerDependencies: + - supports-color + chrome-trace-event@1.0.4: {} + chromium-edge-launcher@0.3.0: + dependencies: + '@types/node': 24.13.3 + escape-string-regexp: 4.0.0 + is-wsl: 2.2.0 + lighthouse-logger: 1.4.2 + mkdirp: 1.0.4 + transitivePeerDependencies: + - supports-color + chunk-data@0.1.0: {} ci-info@2.0.0: {} + ci-info@3.9.0: {} + cjson@0.3.3: dependencies: json-parse-helpfulerror: 1.0.3 @@ -14592,6 +15675,8 @@ snapshots: commander@11.1.0: optional: true + commander@12.1.0: {} + commander@2.20.3: {} commander@5.1.0: {} @@ -15056,6 +16141,10 @@ snapshots: dependencies: is-arrayish: 0.2.1 + error-stack-parser@2.1.4: + dependencies: + stackframe: 1.3.4 + es-abstract-get@1.0.0: dependencies: es-errors: 1.3.0 @@ -15527,8 +16616,7 @@ snapshots: expect-type@1.4.0: {} - exponential-backoff@3.1.3: - optional: true + exponential-backoff@3.1.3: {} express-rate-limit@5.5.1: {} @@ -15670,6 +16758,12 @@ snapshots: dependencies: websocket-driver: 0.7.5 + fb-dotslash@0.5.8: {} + + fb-watchman@2.0.2: + dependencies: + bser: 2.1.1 + fdir@6.5.0(picomatch@4.0.7): optionalDependencies: picomatch: 4.0.7 @@ -15884,6 +16978,39 @@ snapshots: - supports-color - utf-8-validate + firebase@12.17.1: + dependencies: + '@firebase/ai': 2.14.0(@firebase/app-types@0.9.5)(@firebase/app@0.16.0) + '@firebase/analytics': 0.10.23(@firebase/app@0.16.0) + '@firebase/analytics-compat': 0.2.29(@firebase/app-compat@0.5.16)(@firebase/app@0.16.0) + '@firebase/app': 0.16.0 + '@firebase/app-check': 0.13.0(@firebase/app@0.16.0) + '@firebase/app-check-compat': 0.4.6(@firebase/app-compat@0.5.16)(@firebase/app@0.16.0) + '@firebase/app-compat': 0.5.16 + '@firebase/app-types': 0.9.5 + '@firebase/auth': 1.13.4(@firebase/app@0.16.0) + '@firebase/auth-compat': 0.6.9(@firebase/app-compat@0.5.16)(@firebase/app-types@0.9.5)(@firebase/app@0.16.0) + '@firebase/data-connect': 0.7.3(@firebase/app@0.16.0) + '@firebase/database': 1.1.4 + '@firebase/database-compat': 2.1.6(@firebase/app-compat@0.5.16)(@firebase/app@0.16.0) + '@firebase/firestore': 4.17.0(@firebase/app@0.16.0) + '@firebase/firestore-compat': 0.4.12(@firebase/app-compat@0.5.16)(@firebase/app-types@0.9.5)(@firebase/app@0.16.0) + '@firebase/functions': 0.13.6(@firebase/app@0.16.0) + '@firebase/functions-compat': 0.4.6(@firebase/app-compat@0.5.16)(@firebase/app@0.16.0) + '@firebase/installations': 0.6.23(@firebase/app@0.16.0) + '@firebase/installations-compat': 0.2.23(@firebase/app-compat@0.5.16)(@firebase/app-types@0.9.5)(@firebase/app@0.16.0) + '@firebase/messaging': 0.13.1(@firebase/app@0.16.0) + '@firebase/messaging-compat': 0.2.28(@firebase/app-compat@0.5.16)(@firebase/app@0.16.0) + '@firebase/performance': 0.7.13(@firebase/app@0.16.0) + '@firebase/performance-compat': 0.2.26(@firebase/app-compat@0.5.16)(@firebase/app@0.16.0) + '@firebase/remote-config': 0.9.1(@firebase/app@0.16.0) + '@firebase/remote-config-compat': 0.2.28(@firebase/app-compat@0.5.16)(@firebase/app@0.16.0) + '@firebase/storage': 0.14.4(@firebase/app@0.16.0) + '@firebase/storage-compat': 0.4.4(@firebase/app-compat@0.5.16)(@firebase/app-types@0.9.5)(@firebase/app@0.16.0) + '@firebase/util': 1.15.2 + transitivePeerDependencies: + - '@react-native-async-storage/async-storage' + firebase@12.18.0: dependencies: '@firebase/ai': 2.15.0(@firebase/app-types@0.9.6)(@firebase/app@0.16.1) @@ -15926,6 +17053,8 @@ snapshots: flatted@3.4.4: {} + flow-enums-runtime@0.0.6: {} + fn.name@1.1.0: {} follow-redirects@1.16.0(debug@4.4.3(supports-color@7.2.0)): @@ -16391,12 +17520,20 @@ snapshots: heap-js@2.7.1: {} + hermes-compiler@250829098.0.17: {} + hermes-estree@0.25.1: {} + hermes-estree@0.36.1: {} + hermes-parser@0.25.1: dependencies: hermes-estree: 0.25.1 + hermes-parser@0.36.1: + dependencies: + hermes-estree: 0.36.1 + highlight.js@10.7.3: {} homedir-polyfill@1.0.3: @@ -16563,6 +17700,10 @@ snapshots: ignore@7.0.6: {} + image-size@1.2.1: + dependencies: + queue: 6.0.2 + import-fresh@3.3.1: dependencies: parent-module: 1.0.1 @@ -16600,6 +17741,10 @@ snapshots: hasown: 2.0.4 side-channel: 1.1.1 + invariant@2.2.4: + dependencies: + loose-envify: 1.4.0 + ip-address@10.5.0: {} ip-regex@2.1.0: {} @@ -16663,6 +17808,8 @@ snapshots: is-deflate@1.0.0: {} + is-docker@2.2.1: {} + is-docker@3.0.0: {} is-document.all@1.0.0: @@ -16800,6 +17947,10 @@ snapshots: is-wsl@1.1.0: {} + is-wsl@2.2.0: + dependencies: + is-docker: 2.2.1 + is-wsl@3.1.0: dependencies: is-inside-container: 1.0.0 @@ -16866,12 +18017,39 @@ snapshots: optionalDependencies: '@pkgjs/parseargs': 0.11.0 + jest-get-type@29.6.3: {} + + jest-util@29.7.0: + dependencies: + '@jest/types': 29.6.3 + '@types/node': 24.13.3 + chalk: 4.1.2 + ci-info: 3.9.0 + graceful-fs: 4.2.11 + picomatch: 2.3.2 + + jest-validate@29.7.0: + dependencies: + '@jest/types': 29.6.3 + camelcase: 6.3.0 + chalk: 4.1.2 + jest-get-type: 29.6.3 + leven: 3.1.0 + pretty-format: 29.7.0 + jest-worker@27.5.1: dependencies: '@types/node': 24.13.3 merge-stream: 2.0.0 supports-color: 8.1.1 + jest-worker@29.7.0: + dependencies: + '@types/node': 24.13.3 + jest-util: 29.7.0 + merge-stream: 2.0.0 + supports-color: 8.1.1 + jiti@2.4.2: optional: true @@ -16901,6 +18079,8 @@ snapshots: jsbn@0.1.1: {} + jsc-safe-url@0.2.4: {} + jsdom@30.0.1: dependencies: '@asamuzakjp/css-color': 6.0.7 @@ -17092,6 +18272,8 @@ snapshots: dependencies: readable-stream: 2.3.8 + leven@3.1.0: {} + levn@0.4.1: dependencies: prelude-ls: 1.2.1 @@ -17103,6 +18285,13 @@ snapshots: libsodium@0.7.16: {} + lighthouse-logger@1.4.2: + dependencies: + debug: 2.6.9 + marky: 1.3.0 + transitivePeerDependencies: + - supports-color + lightningcss-android-arm64@1.32.0: optional: true @@ -17258,6 +18447,8 @@ snapshots: lodash.snakecase@4.1.1: {} + lodash.throttle@4.1.1: {} + lodash@4.18.1: {} log-symbols@4.1.0: @@ -17358,6 +18549,10 @@ snapshots: make-error@1.3.6: {} + makeerror@1.0.12: + dependencies: + tmpl: 1.0.5 + marked-terminal@7.3.0(marked@13.0.3): dependencies: ansi-escapes: 7.3.0 @@ -17371,6 +18566,8 @@ snapshots: marked@13.0.3: {} + marky@1.3.0: {} + math-intrinsics@1.1.0: {} mdn-data@2.0.28: {} @@ -17383,6 +18580,8 @@ snapshots: media-typer@1.1.1: {} + memoize-one@5.2.1: {} + merge-descriptors@1.0.3: {} merge-descriptors@2.0.0: {} @@ -17393,6 +18592,179 @@ snapshots: methods@1.1.2: {} + metro-babel-transformer@0.87.0: + dependencies: + '@babel/core': 7.29.7 + flow-enums-runtime: 0.0.6 + hermes-parser: 0.36.1 + metro-cache-key: 0.87.0 + nullthrows: 1.1.1 + transitivePeerDependencies: + - supports-color + + metro-cache-key@0.87.0: + dependencies: + flow-enums-runtime: 0.0.6 + + metro-cache@0.87.0: + dependencies: + exponential-backoff: 3.1.3 + flow-enums-runtime: 0.0.6 + https-proxy-agent: 7.0.6 + metro-core: 0.87.0 + transitivePeerDependencies: + - supports-color + + metro-config@0.87.0: + dependencies: + connect: 3.7.0 + flow-enums-runtime: 0.0.6 + jest-validate: 29.7.0 + metro: 0.87.0 + metro-cache: 0.87.0 + metro-core: 0.87.0 + metro-runtime: 0.87.0 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + metro-core@0.87.0: + dependencies: + flow-enums-runtime: 0.0.6 + lodash.throttle: 4.1.1 + metro-resolver: 0.87.0 + + metro-file-map@0.87.0: + dependencies: + debug: 4.4.3(supports-color@7.2.0) + fb-watchman: 2.0.2 + flow-enums-runtime: 0.0.6 + graceful-fs: 4.2.11 + invariant: 2.2.4 + jest-worker: 29.7.0 + micromatch: 4.0.8 + nullthrows: 1.1.1 + walker: 1.0.8 + transitivePeerDependencies: + - supports-color + + metro-minify-terser@0.87.0: + dependencies: + flow-enums-runtime: 0.0.6 + terser: 5.51.0 + + metro-resolver@0.87.0: + dependencies: + flow-enums-runtime: 0.0.6 + + metro-runtime@0.87.0: + dependencies: + '@babel/runtime': 7.29.7 + flow-enums-runtime: 0.0.6 + + metro-source-map@0.87.0: + dependencies: + '@babel/traverse': 7.29.8 + '@babel/types': 7.29.8 + flow-enums-runtime: 0.0.6 + invariant: 2.2.4 + metro-symbolicate: 0.87.0 + nullthrows: 1.1.1 + ob1: 0.87.0 + source-map: 0.5.7 + vlq: 1.0.1 + transitivePeerDependencies: + - supports-color + + metro-symbolicate@0.87.0: + dependencies: + flow-enums-runtime: 0.0.6 + invariant: 2.2.4 + metro-source-map: 0.87.0 + nullthrows: 1.1.1 + source-map: 0.5.7 + vlq: 1.0.1 + transitivePeerDependencies: + - supports-color + + metro-transform-plugins@0.87.0: + dependencies: + '@babel/core': 7.29.7 + '@babel/generator': 7.29.8 + '@babel/template': 7.29.7 + '@babel/traverse': 7.29.8 + flow-enums-runtime: 0.0.6 + nullthrows: 1.1.1 + transitivePeerDependencies: + - supports-color + + metro-transform-worker@0.87.0: + dependencies: + '@babel/core': 7.29.7 + '@babel/generator': 7.29.8 + '@babel/parser': 7.29.8 + '@babel/types': 7.29.8 + flow-enums-runtime: 0.0.6 + metro: 0.87.0 + metro-babel-transformer: 0.87.0 + metro-cache: 0.87.0 + metro-cache-key: 0.87.0 + metro-minify-terser: 0.87.0 + metro-source-map: 0.87.0 + metro-transform-plugins: 0.87.0 + nullthrows: 1.1.1 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + metro@0.87.0: + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/core': 7.29.7 + '@babel/generator': 7.29.8 + '@babel/parser': 7.29.8 + '@babel/template': 7.29.7 + '@babel/traverse': 7.29.8 + '@babel/types': 7.29.8 + accepts: 2.0.0 + ci-info: 2.0.0 + connect: 3.7.0 + debug: 4.4.3(supports-color@7.2.0) + error-stack-parser: 2.1.4 + flow-enums-runtime: 0.0.6 + graceful-fs: 4.2.11 + hermes-parser: 0.36.1 + image-size: 1.2.1 + invariant: 2.2.4 + jest-worker: 29.7.0 + jsc-safe-url: 0.2.4 + lodash.throttle: 4.1.1 + metro-babel-transformer: 0.87.0 + metro-cache: 0.87.0 + metro-cache-key: 0.87.0 + metro-config: 0.87.0 + metro-core: 0.87.0 + metro-file-map: 0.87.0 + metro-resolver: 0.87.0 + metro-runtime: 0.87.0 + metro-source-map: 0.87.0 + metro-symbolicate: 0.87.0 + metro-transform-plugins: 0.87.0 + metro-transform-worker: 0.87.0 + mime-types: 3.0.2 + nullthrows: 1.1.1 + serialize-error: 2.1.0 + source-map: 0.5.7 + throat: 5.0.0 + ws: 7.5.13 + yargs: 17.7.3 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + micromatch@4.0.8: dependencies: braces: 3.0.3 @@ -17599,6 +18971,8 @@ snapshots: which: 7.0.0 optional: true + node-int64@0.4.0: {} + node-releases@2.0.53: {} node-schedule@2.1.1: @@ -17640,6 +19014,8 @@ snapshots: dependencies: boolbase: 1.0.0 + nullthrows@1.1.1: {} + nx@23.1.1(@swc-node/register@1.12.1(@swc/core@1.15.47(@swc/helpers@0.5.23))(@swc/types@0.1.28)(typescript@6.0.3))(@swc/core@1.15.47(@swc/helpers@0.5.23)): dependencies: '@emnapi/core': 1.4.5 @@ -17776,6 +19152,10 @@ snapshots: '@swc-node/register': 1.12.1(@swc/core@1.15.47(@swc/helpers@0.5.23))(@swc/types@0.1.28)(typescript@6.0.3) '@swc/core': 1.15.47(@swc/helpers@0.5.23) + ob1@0.87.0: + dependencies: + flow-enums-runtime: 0.0.6 + object-assign@4.1.1: {} object-hash@3.0.0: {} @@ -17861,6 +19241,11 @@ snapshots: dependencies: is-wsl: 1.1.0 + open@7.4.2: + dependencies: + is-docker: 2.2.1 + is-wsl: 2.2.0 + openapi3-ts@3.2.0: dependencies: yaml: 2.9.0 @@ -18202,6 +19587,12 @@ snapshots: ansi-styles: 5.2.0 react-is: 17.0.2 + pretty-format@29.7.0: + dependencies: + '@jest/schemas': 29.6.3 + ansi-styles: 5.2.0 + react-is: 18.3.1 + pretty-ms@9.3.0: dependencies: parse-ms: 4.0.0 @@ -18221,6 +19612,10 @@ snapshots: promise-breaker@6.0.0: {} + promise@8.3.0: + dependencies: + asap: 2.0.6 + prop-types@15.8.1: dependencies: loose-envify: 1.4.0 @@ -18297,6 +19692,10 @@ snapshots: queue-microtask@1.2.3: {} + queue@6.0.2: + dependencies: + inherits: 2.0.4 + quick-format-unescaped@4.0.4: {} quick-lru@5.1.1: {} @@ -18345,6 +19744,14 @@ snapshots: re2js@2.8.6: {} + react-devtools-core@6.1.5: + dependencies: + shell-quote: 1.10.0 + ws: 7.5.13 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + react-dom@19.2.8(react@19.2.8): dependencies: react: 19.2.8 @@ -18354,6 +19761,57 @@ snapshots: react-is@17.0.2: {} + react-is@18.3.1: {} + + react-native-url-polyfill@4.0.0(react-native@0.87.1(@babel/core@7.29.7)(@types/react@19.2.18)(react@19.2.8)): + dependencies: + react-native: 0.87.1(@babel/core@7.29.7)(@types/react@19.2.18)(react@19.2.8) + + react-native@0.87.1(@babel/core@7.29.7)(@types/react@19.2.18)(react@19.2.8): + dependencies: + '@react-native/asset-utils': 0.87.1 + '@react-native/codegen': 0.87.1(@babel/core@7.29.7) + '@react-native/community-cli-plugin': 0.87.1 + '@react-native/gradle-plugin': 0.87.1 + '@react-native/normalize-colors': 0.87.1 + '@react-native/virtualized-lists': 0.87.1(@types/react@19.2.18)(react-native@0.87.1(@babel/core@7.29.7)(@types/react@19.2.18)(react@19.2.8))(react@19.2.8) + anser: 1.4.10 + ansi-regex: 5.0.1 + babel-plugin-syntax-hermes-parser: 0.36.1 + base64-js: 1.5.1 + commander: 12.1.0 + flow-enums-runtime: 0.0.6 + hermes-compiler: 250829098.0.17 + invariant: 2.2.4 + memoize-one: 5.2.1 + metro-runtime: 0.87.0 + metro-source-map: 0.87.0 + nullthrows: 1.1.1 + pretty-format: 29.7.0 + promise: 8.3.0 + react: 19.2.8 + react-devtools-core: 6.1.5 + react-refresh: 0.14.2 + regenerator-runtime: 0.13.11 + scheduler: 0.27.0 + semver: 7.8.5 + stacktrace-parser: 0.1.11 + tinyglobby: 0.2.17 + whatwg-fetch: 3.6.20 + ws: 7.5.13 + yargs: 17.7.3 + optionalDependencies: + '@types/react': 19.2.18 + transitivePeerDependencies: + - '@babel/core' + - '@react-native-community/cli' + - '@react-native/metro-config' + - bufferutil + - supports-color + - utf-8-validate + + react-refresh@0.14.2: {} + react@19.2.8: {} read-package-up@11.0.0: @@ -18423,6 +19881,8 @@ snapshots: regenerate@1.4.2: {} + regenerator-runtime@0.13.11: {} + regexp.prototype.flags@1.5.4: dependencies: call-bind: 1.0.9 @@ -18711,6 +20171,8 @@ snapshots: transitivePeerDependencies: - supports-color + serialize-error@2.1.0: {} + seroval-plugins@1.5.6(seroval@1.5.6): dependencies: seroval: 1.5.6 @@ -18771,6 +20233,8 @@ snapshots: shebang-regex@3.0.0: {} + shell-quote@1.10.0: {} + side-channel-list@1.0.1: dependencies: es-errors: 1.3.0 @@ -18876,6 +20340,8 @@ snapshots: buffer-from: 1.1.2 source-map: 0.6.1 + source-map@0.5.7: {} + source-map@0.6.1: {} source-map@0.7.6: {} @@ -18919,6 +20385,12 @@ snapshots: stackback@0.0.2: {} + stackframe@1.3.4: {} + + stacktrace-parser@0.1.11: + dependencies: + type-fest: 0.7.1 + statuses@1.5.0: {} statuses@2.0.2: {} @@ -19264,6 +20736,8 @@ snapshots: dependencies: real-require: 0.2.0 + throat@5.0.0: {} + through2@2.0.5: dependencies: readable-stream: 2.3.8 @@ -19300,6 +20774,8 @@ snapshots: tmp@0.2.7: {} + tmpl@1.0.5: {} + to-regex-range@5.0.1: dependencies: is-number: 7.0.0 @@ -19401,6 +20877,8 @@ snapshots: type-fest@0.20.2: {} + type-fest@0.7.1: {} + type-fest@4.41.0: {} type-fest@5.8.0: @@ -19826,12 +21304,18 @@ snapshots: transitivePeerDependencies: - msw + vlq@1.0.1: {} + vscode-uri@3.2.0: {} w3c-xmlserializer@5.0.0: dependencies: xml-name-validator: 5.0.0 + walker@1.0.8: + dependencies: + makeerror: 1.0.12 + watchpack@2.5.2: dependencies: graceful-fs: 4.2.11 @@ -20051,6 +21535,8 @@ snapshots: signal-exit: 3.0.7 typedarray-to-buffer: 3.1.5 + ws@7.5.13: {} + ws@8.18.0: optional: true diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 9caba5b..ae9cc61 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -5,6 +5,8 @@ packages: catalog: '@effect/atom-react': 4.0.0-rc.112 + '@react-native-firebase/app': ^26.3.3 + '@react-native-firebase/firestore': ^26.3.3 '@effect/platform-browser': 4.0.0-rc.112 '@effect/vitest': 4.0.0-rc.112 effect: 4.0.0-rc.112 diff --git a/tsconfig.json b/tsconfig.json index d216779..8aac728 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -24,6 +24,9 @@ { "path": "./packages/devtools" }, + { + "path": "./packages/react-native" + }, { "path": "./example/app" }