diff --git a/.agents/skills/ts-js-validation/SKILL.md b/.agents/skills/ts-js-validation/SKILL.md index 5d027553f4..2ae92d2abf 100644 --- a/.agents/skills/ts-js-validation/SKILL.md +++ b/.agents/skills/ts-js-validation/SKILL.md @@ -1,22 +1,22 @@ --- name: ts-js-validation -description: Validate TypeScript and JavaScript changes in React Native Firebase by running the root prepare, TypeScript compile, API reference, Jest, formatting, and compare-types scripts. Use when a developer updates TS/JS code and wants the standard RNFB validation pass before handing off or committing. +description: Validate React Native Firebase changes by running the CI-equivalent prepare, TypeScript, lint, Jest, formatting, and compare-types scripts. Use before handoff, commit, or push when package sources, native bridge code, or docs changed. metadata: owner_team: react-native-firebase maintainer: russell.wheatley status: draft tags: typescript,javascript,testing,validation,formatting,react-native-firebase - last_reviewed: "2026-05-08" - version: "0.1.0" + last_reviewed: "2026-07-06" + version: "0.2.0" --- # React Native Firebase TS/JS Validation ## Scope -Use this skill to validate changes to TypeScript or JavaScript code in the React Native Firebase monorepo. +Use this skill to validate changes in the React Native Firebase monorepo before handoff, commit, or push. -It is for developer-facing validation after editing package JS/TS sources, type tests, Jest tests, or shared TypeScript configuration. It runs the standard root validation commands that catch generated package setup issues, TypeScript errors, consumer type regressions, API reference regressions, Jest failures, formatting drift, and firebase-js-sdk type parity drift. +It runs the same static-analysis and compile/test commands CI uses for the Lint, TypeScript, Jest, docs, and compare-types jobs — not a narrowed JS-only subset. ## Triggers @@ -24,27 +24,23 @@ Use this skill when the user asks for: - testing TS or JS changes - validating TypeScript or JavaScript edits before commit or handoff -- running the standard JS validation pass for RNFB -- checking whether package JS/TS changes compile and pass Jest -- formatting package JS/TS code and then running validation +- running the standard validation pass for RNFB +- checking whether package changes compile and pass Jest +- formatting and linting before push +- CI-equivalent validation before publication ## Out-of-scope boundaries Do not use this skill for: -- Android Java/Kotlin formatting or build validation -- iOS Objective-C, Objective-C++, C++, Swift, or pod validation -- documentation-only changes that do not affect JS/TS behavior -- release validation that requires the full platform, emulator, Detox, or packaging matrix +- release validation that requires the full platform, emulator, Detox, or packaging matrix (see [validation checklist § e2e](../../../okf-bundle/testing/validation-checklist.md)) - migrating a package from JavaScript to TypeScript; use the TypeScript refactor or migration skills instead ## Defaults -Set one clear default path so the agent does not choose randomly between options. - - Default tool or method: run the canonical command sequence below from the repository root -- Fallback when default fails: if a command fails, stop the sequence, inspect the failure, fix issues only when the user asked for fixes or the fix is clearly in the current change set, then rerun the failed command and any later commands -- Why this default exists: `lerna:prepare`, both TypeScript compiles, API reference generation, Jest, formatting, and compare-types cover the JS/TS surfaces most likely to regress in this monorepo +- Fallback when default fails: stop, inspect the failure, fix issues in the current change set when authorized, then rerun the failed command and any later commands +- Why this default exists: the sequence mirrors CI Lint + TypeScript + Jest + docs + compare-types gates ## Command sequence @@ -54,43 +50,42 @@ Run these root `package.json` scripts in order. **Canonical checklist:** [valida 2. `yarn tsc:compile` 3. `yarn tsc:compile:consumer` 4. `yarn reference:api` -5. `yarn lint:js` (use `yarn lint:js --fix` then re-run until clean) -6. `yarn tests:jest` -7. `yarn format:js` -8. `yarn compare:types` +5. `yarn lint` — **CI Lint job** (`lint:js` + `lint:android` + `lint:ios:check`). When `lint:android` reformats Java, commit the formatter output and rerun until exit 0. +6. When `docs/**` changed: `yarn lint:markdown` then `yarn lint:spellcheck` — **CI docs job** +7. `yarn lint:js --fix` then `yarn lint:js` when step 5 reported ESLint issues only (optional shortcut before re-running full `yarn lint`) +8. `yarn tests:jest` +9. `yarn format:js` — inspect diff; rerun `yarn lint` if formatting touched files +10. `yarn compare:types` ## Gotchas - **Forbidden:** `yarn workspace … prepare`, `cd packages/ && yarn prepare/build`, `yarn jet`, `npx jet` — see [agent command policy](../../../okf-bundle/testing/agent-command-policy.md). On failure, fix product code and re-run the **same** canonical command. +- **`yarn lint` is not optional** when native Java or iOS sources are in the diff — `lint:js` alone does not match CI. +- **`yarn lint:spellcheck` is not optional** when `docs/**` is in the diff — `lint:markdown` alone does not match CI. - `yarn format:js` writes changes across `packages/**/*.{js,ts,tsx}`. Check the diff after formatting and do not revert user changes. - Run commands from the repository root so workspace resolution, root `tsconfig.json`, and Jest configuration are consistent. - `yarn lerna:prepare` may rebuild or refresh package artifacts needed before TypeScript or tests run. -- `yarn tsc:compile` checks the repository TypeScript project, while `yarn tsc:compile:consumer` checks the consumer-facing TypeScript project. Run both. -- `yarn reference:api` runs TypeDoc and should come after consumer TypeScript compilation. -- `yarn tests:jest` is the root Jest entrypoint. If it fails, report the failing test file or suite and the first actionable error rather than dumping the full output. - `yarn compare:types` installs dependencies under `.github/scripts/compare-types` before running the type parity comparison. Keep it last. -- If validation is slow, keep the command running rather than replacing it with a narrower command unless the user explicitly asks for targeted validation. +- If validation is slow, keep the command running rather than replacing it with a narrower command unless the user explicitly narrows validation. ## Workflow -1. Confirm the task is TS/JS validation and note any specific changed package or test files the user mentioned. +1. Confirm the task scope and note changed packages, native paths, or docs. 2. Check whether the worktree has unrelated dirty files if the current task includes code edits or commit preparation. 3. Run the command sequence from the repository root. -4. If `yarn format:js` changes files, include those formatting changes in the validation context and inspect the relevant diff before continuing. +4. If `yarn lint:android` or `yarn format:js` changes files, include those changes and rerun `yarn lint` before continuing. 5. If a command fails: - stop before running later commands - - identify whether the failure belongs to the current TS/JS changes, pre-existing repo state, or missing local setup + - identify whether the failure belongs to the current changes, pre-existing repo state, or missing local setup - fix current-change failures when authorized, then rerun the failed command and continue the remaining sequence 6. Return a concise result with the commands run, pass/fail status, and any remaining blockers. ## Validation loop -Use this loop before finalizing: - 1. Run the command sequence. -2. If validation fails because of current TS/JS changes and fixing is in scope, fix the issue and rerun the failed command plus all later commands. +2. If validation fails because of current changes and fixing is in scope, fix the issue and rerun the failed command plus all later commands. 3. If validation fails for unrelated or environment-specific reasons, stop and report the blocker with the command that failed and the shortest useful error summary. -4. Only report success when every command in the sequence completes successfully. +4. Only report success when every applicable command in the sequence completes successfully. ## Output format @@ -108,7 +103,9 @@ Use this template: - `yarn tsc:compile`: passed | failed | not run - `yarn tsc:compile:consumer`: passed | failed | not run - `yarn reference:api`: passed | failed | not run -- `yarn lint:js`: passed | failed | not run +- `yarn lint`: passed | failed | not run +- `yarn lint:markdown`: passed | failed | not run | n/a +- `yarn lint:spellcheck`: passed | failed | not run | n/a - `yarn tests:jest`: passed | failed | not run - `yarn format:js`: passed | failed | changed files - `yarn compare:types`: passed | failed | not run @@ -123,7 +120,7 @@ Use this template: ## Constraints - Keep responses factual and grounded in command output. -- Do not skip any command in the default sequence unless the user explicitly narrows validation. +- Do not skip `yarn lint` or docs lint rows when the diff requires them. - Do not claim validation passed unless `compare:types` ran after any formatting changes. - Do not revert unrelated local changes. - Avoid broad refactors while fixing validation failures. @@ -132,6 +129,6 @@ Use this template: Load files only when needed: -- **`okf-bundle/testing/validation-checklist.md`** — full validation command list including e2e, coverage, and doc lints +- **`okf-bundle/testing/validation-checklist.md`** — full validation command list including e2e, coverage, and CI job mapping - Read `package.json` if command names or script definitions need to be confirmed. -- Read affected package `package.json`, `type-test.ts`, or nearby `__tests__/` files only when a failure needs package-specific diagnosis. +- Read affected package `type-test.ts` or nearby `__tests__/` files only when a failure needs package-specific diagnosis. diff --git a/.github/scripts/compare-types/README.md b/.github/scripts/compare-types/README.md index fbe85e0106..4af0303ca6 100644 --- a/.github/scripts/compare-types/README.md +++ b/.github/scripts/compare-types/README.md @@ -15,6 +15,18 @@ Every difference must have an entry in the package's `configs/.ts` - A difference is **undocumented** — add it to `configs/.ts` with a reason, or fix the RN Firebase types to match. - A config entry is **stale** — the API now matches the firebase-js-sdk, so the entry should be removed from `configs/.ts`. + + +### Justification bar + +A documented difference is not a free pass. Every `missingInRN`, `extraInRN`, and `differentShape` entry must clear one of the OKF change-authoring [acceptable exceptions](../../../okf-bundle/testing/change-authoring-workflow.md#acceptable-exceptions): an evidence-backed **intractable technical reason** (platform SDK, native bridge, Hermes/Metro, or toolchain limitation), **or** a **user-accepted deferral** with a documented rationale (e.g. an alignment that needs architectural review). Both require the user's explicit acceptance — convenience, "harmless", or optional-parameter drift never qualifies on its own: + +- **`missingInRN`** — an export we simply have not built yet is a backlog item, not a documented difference; only keep it here when it clears an acceptable exception. +- **`extraInRN`** — an RN-only export, overload, or parameter is **drift, not a feature**. If firebase-js-sdk does not expose it and no acceptable exception applies, remove it rather than documenting it. +- **`differentShape`** — align the RN Firebase types to firebase-js-sdk and remove the entry unless the shape difference is forced by an intractable reason (e.g. a native module that can only resolve `Promise`) or a user-accepted deferral. + +When implementing a `missingInRN` export, do not introduce new `extraInRN` / `differentShape` drift that would not itself clear an acceptable exception. + ## Prerequisites The root repository dependencies must be installed because the script reads the Firebase JS SDK types from the installed root `node_modules/firebase` package. diff --git a/.github/scripts/compare-types/configs/analytics.ts b/.github/scripts/compare-types/configs/analytics.ts index a6d1069323..d03f0195fa 100644 --- a/.github/scripts/compare-types/configs/analytics.ts +++ b/.github/scripts/compare-types/configs/analytics.ts @@ -103,8 +103,9 @@ const config: PackageConfig = { { name: 'logEvent', reason: - 'RN Firebase `logEvent` returns `Promise` and RN overloads omit the web `[key: string]: any` index signature on event params. ' + - 'Phase S hint: **Promise that could maybe sync-void+queue** (ordered native fire-and-forget; see PS-S2-gap).', + 'Return type aligned to firebase-js-sdk sync `void` (Phase B). Remaining drift is ' + + 'cosmetic: firebase-js-sdk overloads include `[key: string]: any` index signatures and ' + + 'slightly different property ordering on typed event params; behaviour is equivalent.', }, { name: 'setAnalyticsCollectionEnabled', diff --git a/.github/scripts/compare-types/configs/app-check.ts b/.github/scripts/compare-types/configs/app-check.ts index 30f702ba3b..8e89adb1fc 100644 --- a/.github/scripts/compare-types/configs/app-check.ts +++ b/.github/scripts/compare-types/configs/app-check.ts @@ -12,11 +12,6 @@ import type { PackageConfig } from '../src/types'; const config: PackageConfig = { nameMapping: {}, missingInRN: [ - { - name: 'AppCheckTokenListener', - reason: - 'RN Firebase exposes token change listeners through the `onTokenChanged` overloads but does not export the standalone listener type alias from the firebase-js-sdk.', - }, { name: 'PartialObserver', reason: @@ -86,12 +81,6 @@ const config: PackageConfig = { }, ], differentShape: [ - { - name: 'initializeAppCheck', - reason: - 'RN Firebase returns `Promise` whereas the firebase-js-sdk returns `AppCheck` synchronously. ' + - 'Phase S hint: **Promise that could maybe sync-void+queue** after provider/refresh state is installed synchronously (see PS-S2-gap).', - }, { name: 'AppCheckOptions', reason: diff --git a/.github/scripts/compare-types/configs/firestore-pipelines.ts b/.github/scripts/compare-types/configs/firestore-pipelines.ts index 9e97c7bc91..b1e5448620 100644 --- a/.github/scripts/compare-types/configs/firestore-pipelines.ts +++ b/.github/scripts/compare-types/configs/firestore-pipelines.ts @@ -21,75 +21,9 @@ import type { PackageConfig } from '../src/types'; const config: PackageConfig = { nameMapping: {}, - missingInRN: [ - { - name: 'documentMatches', - reason: - 'Newer firebase-js-sdk document expression helper not yet exposed by RN Firebase pipelines.', - }, - { - name: 'geoDistance', - reason: - 'Newer firebase-js-sdk geospatial expression helper not yet exposed by RN Firebase pipelines.', - }, - { - name: 'score', - reason: - 'Newer firebase-js-sdk search score expression helper not yet exposed by RN Firebase pipelines.', - }, - { - name: 'DefineStageOptions', - reason: 'Newer firebase-js-sdk stage options type not yet exposed by RN Firebase pipelines.', - }, - { - name: 'parent', - reason: 'Newer firebase-js-sdk parent stage helper not yet exposed by RN Firebase pipelines.', - }, - { - name: 'SearchStageOptions', - reason: - 'Newer firebase-js-sdk search stage options type not yet exposed by RN Firebase pipelines.', - }, - ], - extraInRN: [ - { - name: 'Type', - reason: - 'RN Firebase exposes a local type discriminator alias for pipeline expression helpers.', - }, - ], - differentShape: [ - { - name: 'constant', - reason: - 'firebase-js-sdk added an optional `preferIntegers` option to pipeline constant expressions; not yet exposed by RN Firebase pipelines.', - }, - { - name: 'isType', - reason: - 'RN Firebase accepts its local `Type` alias where the firebase-js-sdk declaration accepts a string.', - }, - { - name: 'ExpressionType', - reason: - 'Declaration member ordering differs from the firebase-js-sdk file, but the same expression kinds are supported (including `PipelineValue`).', - }, - { - name: 'StageOptions', - reason: - 'Declaration formatting differs for the raw options object, but the public shape is equivalent.', - }, - { - name: 'TimeGranularity', - reason: - 'RN Firebase uses the existing `isoWeek` and `isoYear` casing while the firebase-js-sdk declaration includes lowercase variants.', - }, - { - name: 'timestampDiff', - reason: - 'Declaration overload ordering differs from the firebase-js-sdk file, but all four end/start field and expression combinations are supported.', - }, - ], + missingInRN: [], + extraInRN: [], + differentShape: [], }; export default config; diff --git a/.github/scripts/compare-types/configs/firestore.ts b/.github/scripts/compare-types/configs/firestore.ts index 9e365659c9..361c378230 100644 --- a/.github/scripts/compare-types/configs/firestore.ts +++ b/.github/scripts/compare-types/configs/firestore.ts @@ -26,23 +26,12 @@ const config: PackageConfig = { // --------------------------------------------------------------------------- missingInRN: [ // --- Functions --- - { - name: 'aggregateFieldEqual', - reason: - 'Equality comparison helper for AggregateField instances. Not yet ' + - 'implemented in RN Firebase.', - }, - { - name: 'aggregateQuerySnapshotEqual', - reason: - 'Equality comparison helper for AggregateQuerySnapshot instances. Not ' + - 'yet implemented in RN Firebase.', - }, { name: 'documentSnapshotFromJSON', reason: - 'Deserialises a DocumentSnapshot from a JSON representation. Part of ' + - 'the firebase-js-sdk serialization API not yet available in RN Firebase.', + 'firebase-js-sdk reconstructs web SDK snapshot wrappers from JSON. RN Firebase ' + + 'snapshots are native-backed wrappers, and the Android/iOS Firestore SDKs do not ' + + 'expose cross-platform DocumentSnapshot JSON constructors.', }, { name: 'enableIndexedDbPersistence', @@ -60,45 +49,54 @@ const config: PackageConfig = { { name: 'maximum', reason: - 'Aggregate field helper added in firebase-js-sdk; not yet implemented in RN Firebase.', + 'FieldValue set/update sentinel (`maximum(n: number)`) exported by firebase-js-sdk ' + + '12.15.0. Firebase Firestore iOS SDK 12.15.0 does not expose FIRFieldValue ' + + 'maximum/minimum factories (see Firebase iOS FIRFieldValue reference). Firebase ' + + 'Firestore Android SDK 34.15.0 (BOM) exposes FieldValue.maximum/minimum but RN ' + + 'Firebase native serialization does not wire them; cross-platform parity deferred ' + + 'until iOS SDK adds support. User-accepted gap (C1.2b).', }, { name: 'memoryEagerGarbageCollector', reason: - 'Factory for the memory eager garbage collector used with memoryLocalCache. ' + - 'The local cache configuration API is not yet implemented in RN Firebase; ' + - 'persistence is controlled via native platform settings.', + 'Web local-cache component factory for memoryLocalCache. RN Firebase delegates ' + + 'persistence to the native Firestore SDKs, which do not expose the firebase-js-sdk ' + + 'LocalCache/GarbageCollector component model.', }, { name: 'memoryLocalCache', reason: - 'Factory for an in-memory local cache instance. The local cache ' + - 'configuration API is not yet implemented in RN Firebase.', + 'Web local-cache factory. React Native targets use the native Firestore SDK cache ' + + 'configured through RN Firebase settings, not firebase-js-sdk LocalCache instances.', }, { name: 'memoryLruGarbageCollector', reason: - 'Factory for the memory LRU garbage collector used with memoryLocalCache. ' + - 'The local cache configuration API is not yet implemented in RN Firebase.', + 'Web local-cache component factory for memoryLocalCache. Native Firestore SDK cache ' + + 'configuration does not expose a firebase-js-sdk MemoryLruGarbageCollector object.', }, { name: 'minimum', reason: - 'Aggregate field helper added in firebase-js-sdk; not yet implemented in RN Firebase.', + 'FieldValue set/update sentinel (`minimum(n: number)`) exported by firebase-js-sdk ' + + '12.15.0. Firebase Firestore iOS SDK 12.15.0 does not expose FIRFieldValue ' + + 'maximum/minimum factories (see Firebase iOS FIRFieldValue reference). Firebase ' + + 'Firestore Android SDK 34.15.0 (BOM) exposes FieldValue.maximum/minimum but RN ' + + 'Firebase native serialization does not wire them; cross-platform parity deferred ' + + 'until iOS SDK adds support. User-accepted gap (C1.2b).', }, { name: 'onSnapshotResume', reason: - 'Resumes a snapshot listener from a previously-serialized resume token. ' + - 'Part of the firebase-js-sdk snapshot serialization API not yet available ' + - 'in RN Firebase.', + 'firebase-js-sdk web snapshot resume API depends on serialized web SDK listener ' + + 'state. RN Firebase listeners are backed by Android/iOS SDK listener state, and ' + + 'those SDKs do not expose a compatible public resume-token constructor.', }, { name: 'persistentLocalCache', reason: - 'Factory for a persistent local cache instance. The local cache ' + - 'configuration API is not yet implemented in RN Firebase; persistence ' + - 'is controlled via native platform settings.', + 'Web persistent local-cache factory. RN Firebase uses native Firestore persistence ' + + 'settings instead of firebase-js-sdk PersistentLocalCache component instances.', }, { name: 'persistentMultipleTabManager', @@ -109,20 +107,22 @@ const config: PackageConfig = { { name: 'persistentSingleTabManager', reason: - 'Factory for the persistent single-tab manager. The local cache ' + - 'configuration API is not yet implemented in RN Firebase.', + 'Web tab-manager factory for persistentLocalCache. React Native has no ' + + 'firebase-js-sdk tab-manager component path; native persistence is controlled by ' + + 'platform SDK settings.', }, { name: 'querySnapshotFromJSON', reason: - 'Deserialises a QuerySnapshot from a JSON representation. Part of ' + - 'the firebase-js-sdk serialization API not yet available in RN Firebase.', + 'firebase-js-sdk reconstructs web SDK query snapshot wrappers from JSON. RN Firebase ' + + 'query snapshots are native-backed wrappers, and the Android/iOS Firestore SDKs do ' + + 'not expose cross-platform QuerySnapshot JSON constructors.', }, { name: 'setIndexConfiguration', reason: - 'Configures Firestore indexes from a JSON or Protobuf configuration. ' + - 'Deprecated in the firebase-js-sdk. Not implemented in RN Firebase.', + 'Deprecated in firebase-js-sdk; React Native Firebase will not implement. Native ' + + 'Firestore SDKs do not expose the web JSON/Protobuf index configuration API.', }, // --- Types / Interfaces --- @@ -135,44 +135,44 @@ const config: PackageConfig = { { name: 'Index', reason: - 'Type used with setIndexConfiguration. Not implemented in RN Firebase ' + - 'as setIndexConfiguration is not supported.', + 'Deprecated firebase-js-sdk type used only by setIndexConfiguration. React Native ' + + 'Firebase will not implement that web index configuration API.', }, { name: 'IndexConfiguration', reason: - 'Type used with setIndexConfiguration. Not implemented in RN Firebase ' + - 'as setIndexConfiguration is not supported.', + 'Deprecated firebase-js-sdk type used only by setIndexConfiguration. React Native ' + + 'Firebase will not implement that web index configuration API.', }, { name: 'IndexField', reason: - 'Type used with setIndexConfiguration. Not implemented in RN Firebase ' + - 'as setIndexConfiguration is not supported.', + 'Deprecated firebase-js-sdk type used only by setIndexConfiguration. React Native ' + + 'Firebase will not implement that web index configuration API.', }, { name: 'MemoryCacheSettings', reason: - 'Configuration interface for the memory local cache. The local cache ' + - 'configuration API is not yet implemented in RN Firebase.', + 'Web memory local-cache configuration interface. RN Firebase exposes native ' + + 'Firestore persistence/cache settings rather than firebase-js-sdk LocalCache objects.', }, { name: 'MemoryEagerGarbageCollector', reason: - 'Interface for the memory eager garbage collector. The local cache ' + - 'configuration API is not yet implemented in RN Firebase.', + 'Web memory local-cache garbage-collector interface. Native Firestore SDK cache ' + + 'configuration does not expose this firebase-js-sdk component model.', }, { name: 'MemoryGarbageCollector', reason: - 'Base interface for memory garbage collector strategies. The local cache ' + - 'configuration API is not yet implemented in RN Firebase.', + 'Web memory local-cache garbage-collector base interface. Native Firestore SDK cache ' + + 'configuration does not expose this firebase-js-sdk component model.', }, { name: 'MemoryLruGarbageCollector', reason: - 'Interface for the memory LRU garbage collector. The local cache ' + - 'configuration API is not yet implemented in RN Firebase.', + 'Web memory local-cache LRU garbage-collector interface. Native Firestore SDK cache ' + + 'configuration does not expose this firebase-js-sdk component model.', }, { name: 'PersistentCacheIndexManager', @@ -183,8 +183,8 @@ const config: PackageConfig = { { name: 'PersistentCacheSettings', reason: - 'Configuration interface for the persistent local cache. The local cache ' + - 'configuration API is not yet implemented in RN Firebase.', + 'Web persistent local-cache configuration interface. RN Firebase uses native ' + + 'Firestore persistence settings instead of firebase-js-sdk PersistentLocalCache objects.', }, { name: 'PersistentMultipleTabManager', @@ -195,26 +195,21 @@ const config: PackageConfig = { { name: 'PersistentSingleTabManager', reason: - 'Interface for the persistent single-tab manager. The local cache ' + - 'configuration API is not yet implemented in RN Firebase.', + 'Web persistent-cache tab-manager interface. React Native has no firebase-js-sdk ' + + 'single-tab manager path; native persistence is controlled by platform SDK settings.', }, { name: 'PersistentSingleTabManagerSettings', reason: - 'Configuration interface for the persistent single-tab manager. The local ' + - 'cache configuration API is not yet implemented in RN Firebase.', + 'Web persistent-cache single-tab manager settings. React Native has no ' + + 'firebase-js-sdk tab-manager component path.', }, { name: 'PersistentTabManager', reason: - 'Base interface for persistent tab manager strategies. The local cache ' + - 'configuration API is not yet implemented in RN Firebase.', - }, - { - name: 'TransactionOptions', - reason: - 'Options object for runTransaction (e.g. maxAttempts). Not yet supported ' + - 'by the RN Firebase native transaction implementation.', + 'Web persistent-cache tab-manager base interface. React Native has no ' + + 'firebase-js-sdk tab-manager component path; native persistence is controlled by ' + + 'platform SDK settings.', }, ], @@ -273,40 +268,22 @@ const config: PackageConfig = { name: 'deleteAllPersistentCacheIndexes', reason: 'Returns `Promise` in RN Firebase vs `void` in the firebase-js-sdk. ' + - 'Phase S hint: **keep-async: deferred persistent-cache IO** (web void schedules disk/index work; see PS-S2-gap).', + 'RN Firebase delegates persistent-cache index deletion to native SDK IO and exposes ' + + 'completion/failure through the returned Promise; the web SDK starts the operation and returns void.', }, { name: 'disablePersistentCacheIndexAutoCreation', reason: 'Returns `Promise` in RN Firebase vs `void` in the firebase-js-sdk. ' + - 'Phase S hint: **keep-async: deferred persistent-cache IO** (see PS-S2-gap).', + 'RN Firebase delegates persistent-cache index state to native SDK IO and exposes ' + + 'completion/failure through the returned Promise; the web SDK starts the operation and returns void.', }, { name: 'enablePersistentCacheIndexAutoCreation', reason: 'Returns `Promise` in RN Firebase vs `void` in the firebase-js-sdk. ' + - 'Phase S hint: **keep-async: deferred persistent-cache IO** (see PS-S2-gap).', - }, - { - name: 'initializeFirestore', - reason: - 'Returns `Promise` in RN Firebase vs `Firestore` in the firebase-js-sdk. ' + - 'Phase S hint: **Promise that could maybe sync-void+gate** (in-memory settings visible before return; see PS-S2-gap).', - }, - { - name: 'onSnapshotsInSync', - reason: - 'The observer `next` callback has no parameter in RN Firebase vs ' + - '`(value: void) => void` in the firebase-js-sdk, and the `error` callback ' + - 'uses `Error` instead of `FirestoreError`. Both differences are cosmetic; ' + - 'the behaviour is equivalent.', - }, - { - name: 'runTransaction', - reason: - 'The firebase-js-sdk accepts an optional `TransactionOptions` parameter ' + - '(e.g. maxAttempts) which is not yet supported by the RN Firebase native ' + - 'transaction implementation.', + 'RN Firebase delegates persistent-cache index state to native SDK IO and exposes ' + + 'completion/failure through the returned Promise; the web SDK starts the operation and returns void.', }, { name: 'FirestoreSettings', diff --git a/.github/scripts/compare-types/configs/functions.ts b/.github/scripts/compare-types/configs/functions.ts index e879aac2eb..168eaf2516 100644 --- a/.github/scripts/compare-types/configs/functions.ts +++ b/.github/scripts/compare-types/configs/functions.ts @@ -1,8 +1,10 @@ /** - * Known differences between the firebase-js-sdk public API and - * the @react-native-firebase/functions modular API. + * Known differences between the firebase-js-sdk @firebase/functions public + * API and the @react-native-firebase/functions modular API. * - * Each entry must have a `name` and a `reason`. Undocumented drift fails CI. + * Each entry must have a `name` (the export name) and a `reason` explaining + * why the difference exists. Any difference NOT listed here will cause CI to + * fail so that new drift is caught and deliberately acknowledged. */ import type { PackageConfig } from '../src/types'; @@ -11,23 +13,57 @@ const config: PackageConfig = { nameMapping: { httpsCallableFromURL: 'httpsCallableFromUrl', }, - - missingInRN: [ - { name: 'FunctionsError', reason: 'RN Firebase surfaces callable failures through the `HttpsError` class instead of the firebase-js-sdk `FunctionsError` export.' }, - { name: 'FunctionsErrorCodeCore', reason: 'Internal firebase-js-sdk error-code helper not re-exported by RN Firebase. Callable errors use `HttpsErrorCode` constants instead.' }, - ], - + missingInRN: [], extraInRN: [ - { name: 'HttpsErrorCode', reason: 'RN Firebase exposes callable error code constants as a standalone export. The firebase-js-sdk surfaces these through the `FunctionsErrorCode` enum instead.' }, - { name: 'SDK_VERSION', reason: 'RN Firebase package version string exported from the modular entry point. The firebase-js-sdk does not export SDK_VERSION from @firebase/functions.' }, - { name: 'HttpsError', reason: 'RN Firebase re-exports the callable `HttpsError` class from its modular entry point for ergonomic imports.' }, - { name: 'FunctionsStatics', reason: 'RN Firebase statics namespace type used by the legacy namespaced API surface. Not part of the firebase-js-sdk modular public API.' }, - { name: 'FirebaseApp', reason: 'RN Firebase re-exports `FirebaseApp` from the modular entry point for convenience.' }, + { + name: 'SDK_VERSION', + reason: + 'RN Firebase package version string exported from the modular entry point. The firebase-js-sdk does not export SDK_VERSION from @firebase/functions.', + }, + { + name: 'HttpsError', + reason: + 'RN Firebase exports the runtime callable error class as `HttpsError` (also aliased as `FunctionsError`). ' + + 'The firebase-js-sdk exports the `FunctionsError` class name only.', + }, + { + name: 'HttpsErrorCode', + reason: + 'RN Firebase exports a const object of callable error code strings for backwards-compatible namespaced usage. ' + + 'The firebase-js-sdk does not export this helper from the modular entry point.', + }, + { + name: 'HttpsErrorCodeValue', + reason: + 'RN Firebase type for unprefixed error codes returned by `HttpsError`, including RN-specific codes. ' + + 'The firebase-js-sdk uses prefixed `FunctionsErrorCode` values at runtime.', + }, + { + name: 'FunctionsStatics', + reason: + 'Deprecated namespaced statics type retained for backwards compatibility. The firebase-js-sdk modular API does not export this helper type.', + }, + { + name: 'FirebaseApp', + reason: + 'Deprecated re-export of `@react-native-firebase/app` `FirebaseApp` from the functions types module. ' + + 'Prefer importing `FirebaseApp` from `@react-native-firebase/app`.', + }, ], - differentShape: [ - { name: 'Functions', reason: 'RN Firebase extends the Functions service interface with native region/custom-domain helpers and uses async callable factories.' }, - { name: 'FunctionsErrorCode', reason: 'RN Firebase `FunctionsErrorCode` enum includes additional native bridge error codes beyond the firebase-js-sdk set.' }, + { + name: 'FunctionsError', + reason: + 'RN Firebase `FunctionsError` is an alias for `HttpsError`, whose runtime `code` values are unprefixed ' + + 'strings from the native bridge. The firebase-js-sdk `FunctionsError` class extends `FirebaseError` with ' + + 'prefixed `functions/` error codes.', + }, + { + name: 'Functions', + reason: + 'RN Firebase `Functions` is a native module wrapper with `useEmulator` / deprecated `useFunctionsEmulator` ' + + 'methods. The firebase-js-sdk modular `Functions` service type has a different class shape.', + }, ], }; diff --git a/.github/scripts/compare-types/configs/remote-config.ts b/.github/scripts/compare-types/configs/remote-config.ts index f62440bc0b..ddb2f5c52e 100644 --- a/.github/scripts/compare-types/configs/remote-config.ts +++ b/.github/scripts/compare-types/configs/remote-config.ts @@ -17,36 +17,12 @@ import type { PackageConfig } from '../src/types'; const config: PackageConfig = { missingInRN: [ - { - name: 'FetchResponse', - reason: - 'Part of the firebase-js-sdk initialization options surface. RN Firebase ' + - 'does not expose `RemoteConfigOptions` or the web fetch-response bootstrap path.', - }, { name: 'FetchType', reason: 'Used by the firebase-js-sdk web fetch-response bootstrap path. RN Firebase ' + 'does not expose that initialization surface.', }, - { - name: 'FirebaseExperimentDescription', - reason: - 'Only used by the firebase-js-sdk fetch-response bootstrap types. RN Firebase ' + - 'does not expose that initialization surface.', - }, - { - name: 'FirebaseRemoteConfigObject', - reason: - 'Only used by the firebase-js-sdk fetch-response bootstrap types. RN Firebase ' + - 'does not expose that initialization surface.', - }, - { - name: 'RemoteConfigOptions', - reason: - 'The firebase-js-sdk supports optional initialization options when creating ' + - 'a Remote Config instance. RN Firebase does not expose this initialization API.', - }, ], // --------------------------------------------------------------------------- // Extra in RN Firebase @@ -81,26 +57,14 @@ const config: PackageConfig = { }, ], differentShape: [ - { - name: 'ConfigUpdateObserver', - reason: - 'The `error` callback parameter uses `ReactNativeFirebase.NativeFirebaseError` ' + - 'instead of `FirebaseError` from `@firebase/app`. Both represent Firebase ' + - 'errors but the RN type extends the native bridge error structure.', - }, { name: 'FetchStatus', reason: - 'RN Firebase preserves the long-standing native string literals ' + - '(`no_fetch_yet` / `throttled`) used by both the namespaced API and native bridge, ' + - 'instead of the firebase-js-sdk web literals (`no-fetch-yet` / `throttle`).', - }, - { - name: 'getRemoteConfig', - reason: - 'The firebase-js-sdk accepts an optional `RemoteConfigOptions` second argument. ' + - 'RN Firebase only accepts the optional app instance and does not expose the ' + - 'initialization-options surface.', + 'Intentional native bridge contract: RN Firebase preserves underscore literals ' + + '(`no_fetch_yet`, `throttled`) returned by the iOS/Android Remote Config SDKs and ' + + 'used by the long-standing namespaced API. Aligning to firebase-js-sdk hyphen literals ' + + '(`no-fetch-yet`, `throttle`) would be a breaking change for existing comparisons and ' + + 'cannot be normalized without native/bridge churn; not planned for compare-types parity.', }, { name: 'ValueSource', diff --git a/.github/scripts/compare-types/configs/storage.ts b/.github/scripts/compare-types/configs/storage.ts index 4b9f18bbd4..48a6db1e64 100644 --- a/.github/scripts/compare-types/configs/storage.ts +++ b/.github/scripts/compare-types/configs/storage.ts @@ -25,13 +25,6 @@ const config: PackageConfig = { // Missing in RN Firebase // --------------------------------------------------------------------------- missingInRN: [ - { - name: 'StorageError', - reason: - 'RN Firebase surfaces Storage failures as `NativeFirebaseError` instances from ' + - '`@react-native-firebase/app` rather than exporting the firebase-js-sdk web ' + - '`StorageError` subclass.', - }, { name: 'StorageErrorCode', reason: @@ -135,21 +128,6 @@ const config: PackageConfig = { 'in RN Firebase (they are set via dedicated modular functions) whereas the ' + 'firebase-js-sdk declares them as mutable properties.', }, - { - name: 'StorageObserver', - reason: - 'The `error` callback parameter uses `NativeFirebaseError` instead of ' + - '`StorageError`. Both represent Firebase Storage errors but the RN type ' + - 'extends the native bridge error structure.', - }, - { - name: 'UploadTask', - reason: - 'RN Firebase returns `Promise` from `cancel()`, `pause()`, and ' + - '`resume()` whereas the firebase-js-sdk returns a synchronous `boolean`. ' + - 'Error callback types also use `NativeFirebaseError` instead of `StorageError`. ' + - 'Phase S hint: **convert after native fix** (sync boolean from native task state; see PS-S2-gap).', - }, { name: 'EmulatorMockTokenOptions', reason: @@ -173,20 +151,6 @@ const config: PackageConfig = { '(the Web Streams API type). The Node.js stream type is used because the ' + 'React Native environment does not have the Web Streams API.', }, - { - name: 'uploadBytes', - reason: - 'Returns `Promise` in RN Firebase instead of `Promise`. ' + - '`TaskResult` is a type alias for `UploadResult`, so the runtime shape is identical; ' + - 'the different name is for consistency with the native task system.', - }, - { - name: 'uploadBytesResumable', - reason: - 'Returns `Task` in RN Firebase instead of `UploadTask`. `Task` is a type alias ' + - 'for `UploadTask`, so the runtime shape is identical; the different name is for ' + - 'consistency with the native task system.', - }, { name: 'uploadString', reason: @@ -211,6 +175,22 @@ const config: PackageConfig = { '`(typeof TaskState)[keyof typeof TaskState]`. The RN const additionally includes ' + "a `CANCELLED` alias (with double-L) for `'canceled'` for backwards compatibility.", }, + { + name: 'StorageObserver', + reason: + 'RN Firebase types `error` as `((error: StorageError) => unknown) | null`, placing ' + + '`| null` on the optional callback property. The firebase-js-sdk `.d.ts` parses as ' + + '`(error: StorageError) => void | null`, binding `| null` to the return type; RN aligns ' + + 'with other task callback signatures (`unknown` return) and correct optional-null placement.', + }, + { + name: 'UploadTask', + reason: + 'RN Firebase types the `on()` `complete` parameter as `CompleteFn | null`, matching ' + + 'observer callback semantics and the `Subscribe` helper. The firebase-js-sdk public ' + + '`.d.ts` compare surface shows `Unsubscribe | null` for that parameter — an extraction ' + + 'artifact, not the intended complete-handler type.', + }, ], }; diff --git a/.github/workflows/scripts/README-firestore.md b/.github/workflows/scripts/README-firestore.md index fb1c656340..e3f65a5514 100644 --- a/.github/workflows/scripts/README-firestore.md +++ b/.github/workflows/scripts/README-firestore.md @@ -48,6 +48,11 @@ firebase firestore:indexes --project react-native-firebase-testing --database pi There is no `firebase firestore:rules` pull command; edit the `.rules` files in-repo and deploy. + +## Index deploy verify cycle + +Canonical workflow (CLI ≥ 15.17.0 for search indexes): sync → edit JSON → `./deploy-firestore.sh` (runs `verify-firestore-indexes.sh`) → sync again → confirm cloud pull matches intent. Full policy and tooling surfaces: [okf-bundle Firebase testing project doc](../../../okf-bundle/testing/firebase-testing-project.md#index-change-workflow-sync--edit--deploy--verify). + ## Deploy to cloud ```bash diff --git a/.github/workflows/scripts/deploy-firestore.sh b/.github/workflows/scripts/deploy-firestore.sh index badd2d8993..f1d30f75d4 100755 --- a/.github/workflows/scripts/deploy-firestore.sh +++ b/.github/workflows/scripts/deploy-firestore.sh @@ -22,3 +22,7 @@ echo "" # Use full firestore target (not firestore:rules / firestore:indexes) — sub-targets can # silently no-op with multi-database config. "${FIREBASE_CMD[@]}" deploy --only firestore --config firebase.deploy.json + +echo "" +echo "Running post-deploy index verification..." +"$SCRIPT_DIR/verify-firestore-indexes.sh" diff --git a/.github/workflows/scripts/firestore.pipelines-e2e.indexes.json b/.github/workflows/scripts/firestore.pipelines-e2e.indexes.json index 7779225732..30f93ab34a 100644 --- a/.github/workflows/scripts/firestore.pipelines-e2e.indexes.json +++ b/.github/workflows/scripts/firestore.pipelines-e2e.indexes.json @@ -11,7 +11,28 @@ "flat": {} } } - ] + ], + "density": "DENSE" + }, + { + "collectionGroup": "search-text", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "menu", + "searchConfig": { + "textSpec": { + "indexSpecs": [ + { + "indexType": "TOKENIZED", + "matchType": "MATCH_GLOBALLY" + } + ] + } + } + } + ], + "density": "SPARSE_ANY" } ], "fieldOverrides": [] diff --git a/.github/workflows/scripts/functions/package.json b/.github/workflows/scripts/functions/package.json index c09b5131f5..d6aa6a8c7a 100644 --- a/.github/workflows/scripts/functions/package.json +++ b/.github/workflows/scripts/functions/package.json @@ -19,7 +19,7 @@ }, "devDependencies": { "firebase-functions-test": "^3.4.1", - "firebase-tools": "^15.16.0", + "firebase-tools": "^15.22.4", "typescript": "^6.0.3" }, "private": true, diff --git a/.github/workflows/scripts/functions/yarn.lock b/.github/workflows/scripts/functions/yarn.lock index 0aeb647b78..8102a387b1 100644 --- a/.github/workflows/scripts/functions/yarn.lock +++ b/.github/workflows/scripts/functions/yarn.lock @@ -17,22 +17,6 @@ __metadata: languageName: node linkType: hard -"@apphosting/build@npm:^0.1.7": - version: 0.1.7 - resolution: "@apphosting/build@npm:0.1.7" - dependencies: - "@apphosting/common": "npm:^0.0.9" - "@npmcli/promise-spawn": "npm:^3.0.0" - colorette: "npm:^2.0.20" - commander: "npm:^11.1.0" - npm-pick-manifest: "npm:^9.0.0" - ts-node: "npm:^10.9.1" - bin: - apphosting-local-build: dist/bin/localbuild.js - checksum: 10/2a38c1792943b1fb7f73168ff2a556c1fd60197113ac3f8ac1165341379d2ca772fe915ad8aa1b3cc95a0417a6407acf123331d5edb0f408dea8e289f87b6028 - languageName: node - linkType: hard - "@apphosting/common@npm:^0.0.8": version: 0.0.8 resolution: "@apphosting/common@npm:0.0.8" @@ -40,13 +24,6 @@ __metadata: languageName: node linkType: hard -"@apphosting/common@npm:^0.0.9": - version: 0.0.9 - resolution: "@apphosting/common@npm:0.0.9" - checksum: 10/117068ce2860a2ba481ec217ed29df782eeca244abe1fff86525e6a69d19ed3879e98889d46d9c87a70a1aa32cd79535b71bd4fd2405e849e861b873f58b34a4 - languageName: node - linkType: hard - "@colors/colors@npm:1.5.0": version: 1.5.0 resolution: "@colors/colors@npm:1.5.0" @@ -61,15 +38,6 @@ __metadata: languageName: node linkType: hard -"@cspotcode/source-map-support@npm:^0.8.0": - version: 0.8.1 - resolution: "@cspotcode/source-map-support@npm:0.8.1" - dependencies: - "@jridgewell/trace-mapping": "npm:0.3.9" - checksum: 10/b6e38a1712fab242c86a241c229cf562195aad985d0564bd352ac404be583029e89e93028ffd2c251d2c407ecac5fb0cbdca94a2d5c10f29ac806ede0508b3ff - languageName: node - linkType: hard - "@dabh/diagnostics@npm:^2.0.2": version: 2.0.3 resolution: "@dabh/diagnostics@npm:2.0.3" @@ -712,30 +680,6 @@ __metadata: languageName: node linkType: hard -"@jridgewell/resolve-uri@npm:^3.0.3": - version: 3.1.2 - resolution: "@jridgewell/resolve-uri@npm:3.1.2" - checksum: 10/97106439d750a409c22c8bff822d648f6a71f3aa9bc8e5129efdc36343cd3096ddc4eeb1c62d2fe48e9bdd4db37b05d4646a17114ecebd3bbcacfa2de51c3c1d - languageName: node - linkType: hard - -"@jridgewell/sourcemap-codec@npm:^1.4.10": - version: 1.5.5 - resolution: "@jridgewell/sourcemap-codec@npm:1.5.5" - checksum: 10/5d9d207b462c11e322d71911e55e21a4e2772f71ffe8d6f1221b8eb5ae6774458c1d242f897fb0814e8714ca9a6b498abfa74dfe4f434493342902b1a48b33a5 - languageName: node - linkType: hard - -"@jridgewell/trace-mapping@npm:0.3.9": - version: 0.3.9 - resolution: "@jridgewell/trace-mapping@npm:0.3.9" - dependencies: - "@jridgewell/resolve-uri": "npm:^3.0.3" - "@jridgewell/sourcemap-codec": "npm:^1.4.10" - checksum: 10/83deafb8e7a5ca98993c2c6eeaa93c270f6f647a4c0dc00deb38c9cf9b2d3b7bf15e8839540155247ef034a052c0ec4466f980bf0c9e2ab63b97d16c0cedd3ff - languageName: node - linkType: hard - "@js-sdsl/ordered-map@npm:^4.4.2": version: 4.4.2 resolution: "@js-sdsl/ordered-map@npm:4.4.2" @@ -812,15 +756,6 @@ __metadata: languageName: node linkType: hard -"@npmcli/promise-spawn@npm:^3.0.0": - version: 3.0.0 - resolution: "@npmcli/promise-spawn@npm:3.0.0" - dependencies: - infer-owner: "npm:^1.0.4" - checksum: 10/3454465a2731cea5875ba51f80873e2205e5bd878c31517286b0ede4ea931c7bf3de895382287e906d03710fff6f9e44186bd0eee068ce578901c5d3b58e7692 - languageName: node - linkType: hard - "@opentelemetry/api@npm:^1.3.0, @opentelemetry/api@npm:~1.9.0": version: 1.9.0 resolution: "@opentelemetry/api@npm:1.9.0" @@ -988,34 +923,6 @@ __metadata: languageName: node linkType: hard -"@tsconfig/node10@npm:^1.0.7": - version: 1.0.11 - resolution: "@tsconfig/node10@npm:1.0.11" - checksum: 10/51fe47d55fe1b80ec35e6e5ed30a13665fd3a531945350aa74a14a1e82875fb60b350c2f2a5e72a64831b1b6bc02acb6760c30b3738b54954ec2dea82db7a267 - languageName: node - linkType: hard - -"@tsconfig/node12@npm:^1.0.7": - version: 1.0.11 - resolution: "@tsconfig/node12@npm:1.0.11" - checksum: 10/5ce29a41b13e7897a58b8e2df11269c5395999e588b9a467386f99d1d26f6c77d1af2719e407621412520ea30517d718d5192a32403b8dfcc163bf33e40a338a - languageName: node - linkType: hard - -"@tsconfig/node14@npm:^1.0.0": - version: 1.0.3 - resolution: "@tsconfig/node14@npm:1.0.3" - checksum: 10/19275fe80c4c8d0ad0abed6a96dbf00642e88b220b090418609c4376e1cef81bf16237bf170ad1b341452feddb8115d8dd2e5acdfdea1b27422071163dc9ba9d - languageName: node - linkType: hard - -"@tsconfig/node16@npm:^1.0.2": - version: 1.0.4 - resolution: "@tsconfig/node16@npm:1.0.4" - checksum: 10/202319785901f942a6e1e476b872d421baec20cf09f4b266a1854060efbf78cde16a4d256e8bc949d31e6cd9a90f1e8ef8fb06af96a65e98338a2b6b0de0a0ff - languageName: node - linkType: hard - "@types/body-parser@npm:*": version: 1.19.6 resolution: "@types/body-parser@npm:1.19.6" @@ -1233,24 +1140,6 @@ __metadata: languageName: node linkType: hard -"acorn-walk@npm:^8.1.1": - version: 8.3.4 - resolution: "acorn-walk@npm:8.3.4" - dependencies: - acorn: "npm:^8.11.0" - checksum: 10/871386764e1451c637bb8ab9f76f4995d408057e9909be6fb5ad68537ae3375d85e6a6f170b98989f44ab3ff6c74ad120bc2779a3d577606e7a0cd2b4efcaf77 - languageName: node - linkType: hard - -"acorn@npm:^8.11.0, acorn@npm:^8.4.1": - version: 8.15.0 - resolution: "acorn@npm:8.15.0" - bin: - acorn: bin/acorn - checksum: 10/77f2de5051a631cf1729c090e5759148459cdb76b5f5c70f890503d629cf5052357b0ce783c0f976dd8a93c5150f59f6d18df1def3f502396a20f81282482fa4 - languageName: node - linkType: hard - "agent-base@npm:6": version: 6.0.2 resolution: "agent-base@npm:6.0.2" @@ -1402,22 +1291,6 @@ __metadata: languageName: node linkType: hard -"arg@npm:^4.1.0": - version: 4.1.3 - resolution: "arg@npm:4.1.3" - checksum: 10/969b491082f20cad166649fa4d2073ea9e974a4e5ac36247ca23d2e5a8b3cb12d60e9ff70a8acfe26d76566c71fd351ee5e6a9a6595157eb36f92b1fd64e1599 - languageName: node - linkType: hard - -"argparse@npm:^1.0.7": - version: 1.0.10 - resolution: "argparse@npm:1.0.10" - dependencies: - sprintf-js: "npm:~1.0.2" - checksum: 10/c6a621343a553ff3779390bb5ee9c2263d6643ebcd7843227bdde6cc7adbed796eb5540ca98db19e3fd7b4714e1faa51551f8849b268bb62df27ddb15cbcd91e - languageName: node - linkType: hard - "argparse@npm:^2.0.1": version: 2.0.1 resolution: "argparse@npm:2.0.1" @@ -1952,7 +1825,7 @@ __metadata: languageName: node linkType: hard -"colorette@npm:^2.0.19, colorette@npm:^2.0.20": +"colorette@npm:^2.0.19": version: 2.0.20 resolution: "colorette@npm:2.0.20" checksum: 10/0b8de48bfa5d10afc160b8eaa2b9938f34a892530b2f7d7897e0458d9535a066e3998b49da9d21161c78225b272df19ae3a64d6df28b4c9734c0e55bbd02406f @@ -1985,13 +1858,6 @@ __metadata: languageName: node linkType: hard -"commander@npm:^11.1.0": - version: 11.1.0 - resolution: "commander@npm:11.1.0" - checksum: 10/66bd2d8a0547f6cb1d34022efb25f348e433b0e04ad76a65279b1b09da108f59a4d3001ca539c60a7a46ea38bcf399fc17d91adad76a8cf43845d8dcbaf5cda1 - languageName: node - linkType: hard - "commander@npm:^2.19.0": version: 2.20.3 resolution: "commander@npm:2.20.3" @@ -2175,13 +2041,6 @@ __metadata: languageName: node linkType: hard -"create-require@npm:^1.1.0": - version: 1.1.1 - resolution: "create-require@npm:1.1.1" - checksum: 10/a9a1503d4390d8b59ad86f4607de7870b39cad43d929813599a23714831e81c520bddf61bcdd1f8e30f05fd3a2b71ae8538e946eb2786dc65c2bbc520f692eff - languageName: node - linkType: hard - "cross-env@npm:^7.0.3": version: 7.0.3 resolution: "cross-env@npm:7.0.3" @@ -2278,16 +2137,6 @@ __metadata: languageName: node linkType: hard -"deep-equal-in-any-order@npm:^2.0.6": - version: 2.0.6 - resolution: "deep-equal-in-any-order@npm:2.0.6" - dependencies: - lodash.mapvalues: "npm:^4.6.0" - sort-any: "npm:^2.0.0" - checksum: 10/c975530c2455a15c835306bf388e9c5f7a79b6a45ff0c9c9c5c3ba089c36613ffa7b5b63031ec666e5209f7c7b035155039575d6b7c9876b9cfb7b410af3de2f - languageName: node - linkType: hard - "deep-extend@npm:^0.6.0": version: 0.6.0 resolution: "deep-extend@npm:0.6.0" @@ -2350,13 +2199,6 @@ __metadata: languageName: node linkType: hard -"diff@npm:^4.0.1": - version: 4.0.2 - resolution: "diff@npm:4.0.2" - checksum: 10/ec09ec2101934ca5966355a229d77afcad5911c92e2a77413efda5455636c4cf2ce84057e2d7715227a2eeeda04255b849bd3ae3a4dd22eb22e86e76456df069 - languageName: node - linkType: hard - "discontinuous-range@npm:1.0.0": version: 1.0.0 resolution: "discontinuous-range@npm:1.0.0" @@ -2583,7 +2425,7 @@ __metadata: languageName: node linkType: hard -"esprima@npm:^4.0.0, esprima@npm:^4.0.1": +"esprima@npm:^4.0.1": version: 4.0.1 resolution: "esprima@npm:4.0.1" bin: @@ -2882,13 +2724,6 @@ __metadata: languageName: node linkType: hard -"filesize@npm:^6.1.0": - version: 6.4.0 - resolution: "filesize@npm:6.4.0" - checksum: 10/20ddfd66059aa4cdd0db34e36adb368696811d083bbc31952f64f33f5f7792d8351ab33cd47416ef478acfd869cf77eee47235749090ad9b1cac26d2c18a05e5 - languageName: node - linkType: hard - "fill-range@npm:^7.1.1": version: 7.1.1 resolution: "fill-range@npm:7.1.1" @@ -3009,11 +2844,10 @@ __metadata: languageName: node linkType: hard -"firebase-tools@npm:^15.16.0": - version: 15.16.0 - resolution: "firebase-tools@npm:15.16.0" +"firebase-tools@npm:^15.22.4": + version: 15.22.4 + resolution: "firebase-tools@npm:15.22.4" dependencies: - "@apphosting/build": "npm:^0.1.7" "@apphosting/common": "npm:^0.0.8" "@electric-sql/pglite": "npm:^0.3.3" "@electric-sql/pglite-tools": "npm:^0.2.8" @@ -3037,11 +2871,9 @@ __metadata: cross-env: "npm:^7.0.3" cross-spawn: "npm:^7.0.5" csv-parse: "npm:^5.0.4" - deep-equal-in-any-order: "npm:^2.0.6" exegesis: "npm:^4.2.0" exegesis-express: "npm:^4.0.0" express: "npm:^4.16.4" - filesize: "npm:^6.1.0" form-data: "npm:^4.0.1" fs-extra: "npm:^10.1.0" fuzzy: "npm:^0.1.3" @@ -3049,9 +2881,8 @@ __metadata: glob: "npm:^10.5.0" google-auth-library: "npm:^9.11.0" ignore: "npm:^7.0.4" - js-yaml: "npm:^3.14.2" + js-yaml: "npm:^4.2.0" jsonwebtoken: "npm:^9.0.2" - leven: "npm:^3.1.0" libsodium-wrappers: "npm:^0.7.10" lodash: "npm:^4.18.0" lsofi: "npm:^2.0.0" @@ -3063,7 +2894,6 @@ __metadata: node-fetch: "npm:^2.6.7" open: "npm:^6.3.0" ora: "npm:^5.4.1" - p-limit: "npm:^3.0.1" pg: "npm:^8.11.3" pg-gateway: "npm:^0.3.0-beta.4" pglite-2: "npm:@electric-sql/pglite@0.2.17" @@ -3082,16 +2912,14 @@ __metadata: triple-beam: "npm:^1.3.0" universal-analytics: "npm:^0.5.3" update-notifier-cjs: "npm:^5.1.6" - uuid: "npm:^8.3.2" winston: "npm:^3.0.0" winston-transport: "npm:^4.4.0" ws: "npm:^7.5.10" yaml: "npm:^2.8.3" - zod: "npm:^3.24.3" - zod-to-json-schema: "npm:^3.24.5" + zod: "npm:^4.0.0" bin: firebase: lib/bin/firebase.js - checksum: 10/beba86e13615609295f36462719092dae5d621aa6211fc4ccf39d73e4f5ee6fead14ab106fafc05ff8183bd402867f5719dc0729d9fbd2348100ebfd546e5b2e + checksum: 10/d8a907a2859e981aca73e06a04936b9d36ed0d7cee8139cb728f1ad721d00fa7c77a473fbf48a9b5857f5e189416d9c3ca18e354859c5220fddb8b5e2488f1a8 languageName: node linkType: hard @@ -3230,7 +3058,7 @@ __metadata: firebase-admin: "npm:^13.8.0" firebase-functions: "npm:^7.2.5" firebase-functions-test: "npm:^3.4.1" - firebase-tools: "npm:^15.16.0" + firebase-tools: "npm:^15.22.4" typescript: "npm:^6.0.3" dependenciesMeta: "@firebase/util": @@ -3670,15 +3498,6 @@ __metadata: languageName: node linkType: hard -"hosted-git-info@npm:^7.0.0": - version: 7.0.2 - resolution: "hosted-git-info@npm:7.0.2" - dependencies: - lru-cache: "npm:^10.0.1" - checksum: 10/8f085df8a4a637d995f357f48b1e3f6fc1f9f92e82b33fb406415b5741834ed431a510a09141071001e8deea2eee43ce72786463e2aa5e5a70db8648c0eedeab - languageName: node - linkType: hard - "html-entities@npm:^2.5.2": version: 2.6.0 resolution: "html-entities@npm:2.6.0" @@ -3822,13 +3641,6 @@ __metadata: languageName: node linkType: hard -"infer-owner@npm:^1.0.4": - version: 1.0.4 - resolution: "infer-owner@npm:1.0.4" - checksum: 10/181e732764e4a0611576466b4b87dac338972b839920b2a8cde43642e4ed6bd54dc1fb0b40874728f2a2df9a1b097b8ff83b56d5f8f8e3927f837fdcb47d8a89 - languageName: node - linkType: hard - "inherits@npm:2.0.4, inherits@npm:^2.0.3, inherits@npm:^2.0.4, inherits@npm:~2.0.3, inherits@npm:~2.0.4": version: 2.0.4 resolution: "inherits@npm:2.0.4" @@ -4133,26 +3945,25 @@ __metadata: languageName: node linkType: hard -"js-yaml@npm:^3.14.2": - version: 3.14.2 - resolution: "js-yaml@npm:3.14.2" +"js-yaml@npm:^4.1.0": + version: 4.1.0 + resolution: "js-yaml@npm:4.1.0" dependencies: - argparse: "npm:^1.0.7" - esprima: "npm:^4.0.0" + argparse: "npm:^2.0.1" bin: js-yaml: bin/js-yaml.js - checksum: 10/172e0b6007b0bf0fc8d2469c94424f7dd765c64a047d2b790831fecef2204a4054eabf4d911eb73ab8c9a3256ab8ba1ee8d655b789bf24bf059c772acc2075a1 + checksum: 10/c138a34a3fd0d08ebaf71273ad4465569a483b8a639e0b118ff65698d257c2791d3199e3f303631f2cb98213fa7b5f5d6a4621fd0fff819421b990d30d967140 languageName: node linkType: hard -"js-yaml@npm:^4.1.0": - version: 4.1.0 - resolution: "js-yaml@npm:4.1.0" +"js-yaml@npm:^4.2.0": + version: 4.3.0 + resolution: "js-yaml@npm:4.3.0" dependencies: argparse: "npm:^2.0.1" bin: js-yaml: bin/js-yaml.js - checksum: 10/c138a34a3fd0d08ebaf71273ad4465569a483b8a639e0b118ff65698d257c2791d3199e3f303631f2cb98213fa7b5f5d6a4621fd0fff819421b990d30d967140 + checksum: 10/2bcec3a8118d7f744badeb04e14366578d234a736f353d41fe35d2305e4ce2409a8e041d277f07cd6bbc8aaa12128d650a68ce43247072519bede20962d2126f languageName: node linkType: hard @@ -4326,13 +4137,6 @@ __metadata: languageName: node linkType: hard -"leven@npm:^3.1.0": - version: 3.1.0 - resolution: "leven@npm:3.1.0" - checksum: 10/638401d534585261b6003db9d99afd244dfe82d75ddb6db5c0df412842d5ab30b2ef18de471aaec70fe69a46f17b4ae3c7f01d8a4e6580ef7adb9f4273ad1e55 - languageName: node - linkType: hard - "libsodium-wrappers@npm:^0.7.10": version: 0.7.15 resolution: "libsodium-wrappers@npm:0.7.15" @@ -4428,13 +4232,6 @@ __metadata: languageName: node linkType: hard -"lodash.mapvalues@npm:^4.6.0": - version: 4.6.0 - resolution: "lodash.mapvalues@npm:4.6.0" - checksum: 10/566032abaacbc5dc7e74673e589830d2694ec03dc979ac134c93985b47409ac845cbd4eea3786cc0b4db4e80d726a32c1119af63d0151520e27789568aa76bd2 - languageName: node - linkType: hard - "lodash.once@npm:^4.0.0": version: 4.1.1 resolution: "lodash.once@npm:4.1.1" @@ -4449,7 +4246,7 @@ __metadata: languageName: node linkType: hard -"lodash@npm:^4.17.10, lodash@npm:^4.17.11, lodash@npm:^4.17.15, lodash@npm:^4.17.19, lodash@npm:^4.17.21, lodash@npm:^4.17.5": +"lodash@npm:^4.17.10, lodash@npm:^4.17.11, lodash@npm:^4.17.15, lodash@npm:^4.17.19, lodash@npm:^4.17.5": version: 4.17.21 resolution: "lodash@npm:4.17.21" checksum: 10/c08619c038846ea6ac754abd6dd29d2568aa705feb69339e836dfa8d8b09abbb2f859371e86863eda41848221f9af43714491467b5b0299122431e202bb0c532 @@ -4543,13 +4340,6 @@ __metadata: languageName: node linkType: hard -"make-error@npm:^1.1.1": - version: 1.3.6 - resolution: "make-error@npm:1.3.6" - checksum: 10/b86e5e0e25f7f777b77fabd8e2cbf15737972869d852a22b7e73c17623928fccb826d8e46b9951501d3f20e51ad74ba8c59ed584f610526a48f8ccf88aaec402 - languageName: node - linkType: hard - "make-fetch-happen@npm:^14.0.3": version: 14.0.3 resolution: "make-fetch-happen@npm:14.0.3" @@ -5042,46 +4832,6 @@ __metadata: languageName: node linkType: hard -"npm-install-checks@npm:^6.0.0": - version: 6.3.0 - resolution: "npm-install-checks@npm:6.3.0" - dependencies: - semver: "npm:^7.1.1" - checksum: 10/6c20dadb878a0d2f1f777405217b6b63af1299d0b43e556af9363ee6eefaa98a17dfb7b612a473a473e96faf7e789c58b221e0d8ffdc1d34903c4f71618df3b4 - languageName: node - linkType: hard - -"npm-normalize-package-bin@npm:^3.0.0": - version: 3.0.1 - resolution: "npm-normalize-package-bin@npm:3.0.1" - checksum: 10/de416d720ab22137a36292ff8a333af499ea0933ef2320a8c6f56a73b0f0448227fec4db5c890d702e26d21d04f271415eab6580b5546456861cc0c19498a4bf - languageName: node - linkType: hard - -"npm-package-arg@npm:^11.0.0": - version: 11.0.3 - resolution: "npm-package-arg@npm:11.0.3" - dependencies: - hosted-git-info: "npm:^7.0.0" - proc-log: "npm:^4.0.0" - semver: "npm:^7.3.5" - validate-npm-package-name: "npm:^5.0.0" - checksum: 10/bacc863907edf98940286edc2fd80327901c1e8b34426d538cdc708ed66bc6567f06d742d838eaf35db6804347bb4ba56ca9cef032c4b52743b33e7a22a2678e - languageName: node - linkType: hard - -"npm-pick-manifest@npm:^9.0.0": - version: 9.1.0 - resolution: "npm-pick-manifest@npm:9.1.0" - dependencies: - npm-install-checks: "npm:^6.0.0" - npm-normalize-package-bin: "npm:^3.0.0" - npm-package-arg: "npm:^11.0.0" - semver: "npm:^7.3.5" - checksum: 10/e759e4fe4076da9169cf522964a80bbc096d50cd24c8c44b50b44706c4479bd9d9d018fbdb76c6ea0c6037e012e07c6c917a1ecaa7ae1a1169cddfae1c0f24b6 - languageName: node - linkType: hard - "object-assign@npm:^4, object-assign@npm:^4.0.1": version: 4.1.1 resolution: "object-assign@npm:4.1.1" @@ -5486,13 +5236,6 @@ __metadata: languageName: node linkType: hard -"proc-log@npm:^4.0.0": - version: 4.2.0 - resolution: "proc-log@npm:4.2.0" - checksum: 10/4e1394491b717f6c1ade15c570ecd4c2b681698474d3ae2d303c1e4b6ab9455bd5a81566211e82890d5a5ae9859718cc6954d5150bb18b09b72ecb297beae90a - languageName: node - linkType: hard - "proc-log@npm:^5.0.0": version: 5.0.0 resolution: "proc-log@npm:5.0.0" @@ -5978,15 +5721,6 @@ __metadata: languageName: node linkType: hard -"semver@npm:^7.1.1": - version: 7.7.3 - resolution: "semver@npm:7.7.3" - bin: - semver: bin/semver.js - checksum: 10/8dbc3168e057a38fc322af909c7f5617483c50caddba135439ff09a754b20bdd6482a5123ff543dad4affa488ecf46ec5fb56d61312ad20bb140199b88dfaea9 - languageName: node - linkType: hard - "send@npm:0.19.0": version: 0.19.0 resolution: "send@npm:0.19.0" @@ -6182,15 +5916,6 @@ __metadata: languageName: node linkType: hard -"sort-any@npm:^2.0.0": - version: 2.0.0 - resolution: "sort-any@npm:2.0.0" - dependencies: - lodash: "npm:^4.17.21" - checksum: 10/d2dc6cc4f56298ce50b13ce6aafd8bf16010a8f8d0ae75345e8424118ac2cc017a8ffea0eedd136dd67751c09e7b0edb09c959d052ed7ed02afcfbab63c68277 - languageName: node - linkType: hard - "source-map@npm:~0.6.1": version: 0.6.1 resolution: "source-map@npm:0.6.1" @@ -6205,13 +5930,6 @@ __metadata: languageName: node linkType: hard -"sprintf-js@npm:~1.0.2": - version: 1.0.3 - resolution: "sprintf-js@npm:1.0.3" - checksum: 10/c34828732ab8509c2741e5fd1af6b767c3daf2c642f267788f933a65b1614943c282e74c4284f4fa749c264b18ee016a0d37a3e5b73aee446da46277d3a85daa - languageName: node - linkType: hard - "sql-formatter@npm:^15.3.0": version: 15.6.6 resolution: "sql-formatter@npm:15.6.6" @@ -6606,44 +6324,6 @@ __metadata: languageName: node linkType: hard -"ts-node@npm:^10.9.1": - version: 10.9.2 - resolution: "ts-node@npm:10.9.2" - dependencies: - "@cspotcode/source-map-support": "npm:^0.8.0" - "@tsconfig/node10": "npm:^1.0.7" - "@tsconfig/node12": "npm:^1.0.7" - "@tsconfig/node14": "npm:^1.0.0" - "@tsconfig/node16": "npm:^1.0.2" - acorn: "npm:^8.4.1" - acorn-walk: "npm:^8.1.1" - arg: "npm:^4.1.0" - create-require: "npm:^1.1.0" - diff: "npm:^4.0.1" - make-error: "npm:^1.1.1" - v8-compile-cache-lib: "npm:^3.0.1" - yn: "npm:3.1.1" - peerDependencies: - "@swc/core": ">=1.2.50" - "@swc/wasm": ">=1.2.50" - "@types/node": "*" - typescript: ">=2.7" - peerDependenciesMeta: - "@swc/core": - optional: true - "@swc/wasm": - optional: true - bin: - ts-node: dist/bin.js - ts-node-cwd: dist/bin-cwd.js - ts-node-esm: dist/bin-esm.js - ts-node-script: dist/bin-script.js - ts-node-transpile-only: dist/bin-transpile.js - ts-script: dist/bin-script-deprecated.js - checksum: 10/a91a15b3c9f76ac462f006fa88b6bfa528130dcfb849dd7ef7f9d640832ab681e235b8a2bc58ecde42f72851cc1d5d4e22c901b0c11aa51001ea1d395074b794 - languageName: node - linkType: hard - "tslib@npm:^2.0.1, tslib@npm:^2.1.0": version: 2.8.1 resolution: "tslib@npm:2.8.1" @@ -6841,7 +6521,7 @@ __metadata: languageName: node linkType: hard -"uuid@npm:^8.0.0, uuid@npm:^8.3.2": +"uuid@npm:^8.0.0": version: 8.3.2 resolution: "uuid@npm:8.3.2" bin: @@ -6859,13 +6539,6 @@ __metadata: languageName: node linkType: hard -"v8-compile-cache-lib@npm:^3.0.1": - version: 3.0.1 - resolution: "v8-compile-cache-lib@npm:3.0.1" - checksum: 10/88d3423a52b6aaf1836be779cab12f7016d47ad8430dffba6edf766695e6d90ad4adaa3d8eeb512cc05924f3e246c4a4ca51e089dccf4402caa536b5e5be8961 - languageName: node - linkType: hard - "valid-url@npm:^1": version: 1.0.9 resolution: "valid-url@npm:1.0.9" @@ -6873,13 +6546,6 @@ __metadata: languageName: node linkType: hard -"validate-npm-package-name@npm:^5.0.0": - version: 5.0.1 - resolution: "validate-npm-package-name@npm:5.0.1" - checksum: 10/0d583a1af23aeffea7748742cf22b6802458736fb8b60323ba5949763824d46f796474b0e1b9206beb716f9d75269e19dbd7795d6b038b29d561be95dd827381 - languageName: node - linkType: hard - "vary@npm:^1, vary@npm:^1.1.2, vary@npm:~1.1.2": version: 1.1.2 resolution: "vary@npm:1.1.2" @@ -7170,13 +6836,6 @@ __metadata: languageName: node linkType: hard -"yn@npm:3.1.1": - version: 3.1.1 - resolution: "yn@npm:3.1.1" - checksum: 10/2c487b0e149e746ef48cda9f8bad10fc83693cd69d7f9dcd8be4214e985de33a29c9e24f3c0d6bcf2288427040a8947406ab27f7af67ee9456e6b84854f02dd6 - languageName: node - linkType: hard - "yocto-queue@npm:^0.1.0": version: 0.1.0 resolution: "yocto-queue@npm:0.1.0" @@ -7202,15 +6861,6 @@ __metadata: languageName: node linkType: hard -"zod-to-json-schema@npm:^3.24.5": - version: 3.24.6 - resolution: "zod-to-json-schema@npm:3.24.6" - peerDependencies: - zod: ^3.24.1 - checksum: 10/a2c30cf1f250aa79a7f975e65b4236d1abafafd63b43c43475057f28ce6e13f4c882391553c656fb426fd09665e6ae293c2439b4ed8600863beda43fb1a56922 - languageName: node - linkType: hard - "zod-to-json-schema@npm:^3.25.1": version: 3.25.2 resolution: "zod-to-json-schema@npm:3.25.2" @@ -7220,16 +6870,16 @@ __metadata: languageName: node linkType: hard -"zod@npm:^3.24.3": - version: 3.25.76 - resolution: "zod@npm:3.25.76" - checksum: 10/f0c963ec40cd96858451d1690404d603d36507c1fc9682f2dae59ab38b578687d542708a7fdbf645f77926f78c9ed558f57c3d3aa226c285f798df0c4da16995 - languageName: node - linkType: hard - "zod@npm:^3.25 || ^4.0": version: 4.4.1 resolution: "zod@npm:4.4.1" checksum: 10/e9c62dc846ed4c6ab5b062ffdc9ac7d38eadc41a921b71015f3a9d9ef6d3448c72ac93beb0015bd33d774e68e804e65840834101296950f5cbd7e3d64973f64c languageName: node linkType: hard + +"zod@npm:^4.0.0": + version: 4.4.3 + resolution: "zod@npm:4.4.3" + checksum: 10/804b9a42aa8f35f2b3c5a8dff906291cb749115f83ee2afe3576d70b5b5c53c965365c7f4967690647a9c54af9838ff232a85ff9577a0a36c44b68bc6cdefe36 + languageName: node + linkType: hard diff --git a/.github/workflows/scripts/simulator-logging.sh b/.github/workflows/scripts/simulator-logging.sh index 4c5d3e217a..379713a212 100755 --- a/.github/workflows/scripts/simulator-logging.sh +++ b/.github/workflows/scripts/simulator-logging.sh @@ -9,7 +9,7 @@ restart_simulator_logging() { local sim_app_log="${log_dir}/sim-app.log" local resource_log="${log_dir}/resource-monitor.log" local repo_root="${RNFB_REPO_ROOT:-$(cd "$(dirname "${BASH_SOURCE[0]}")/../../.." && pwd)}" - local log_predicate='process == "testing" OR (process == "SpringBoard" AND eventMessage CONTAINS "invertase")' + local log_predicate='process == "testing" OR (process == "SpringBoard" AND eventMessage CONTAINS "invertase") OR eventMessage CONTAINS[c] "RNFBStorage" OR eventMessage CONTAINS[c] "FIRStorage" OR eventMessage CONTAINS[c] "StorageTask"' if ! xcrun simctl list devices booted 2>/dev/null | grep -q Booted; then echo "[boot-status] phase=log_streams skipped=no_booted_simulator" diff --git a/.github/workflows/scripts/verify-firestore-indexes.sh b/.github/workflows/scripts/verify-firestore-indexes.sh new file mode 100755 index 0000000000..cbff368719 --- /dev/null +++ b/.github/workflows/scripts/verify-firestore-indexes.sh @@ -0,0 +1,90 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Post-deploy verification for pipelines-e2e composite/search indexes. +# Fails non-zero when expected index definitions are absent from cloud export. + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +cd "$SCRIPT_DIR" + +# shellcheck source=firebase-cli.sh +source "$SCRIPT_DIR/firebase-cli.sh" + +PROJECT="${FIREBASE_PROJECT:-react-native-firebase-testing}" +DATABASE="${FIRESTORE_VERIFY_DATABASE:-pipelines-e2e}" +TMP_INDEXES="$(mktemp)" +trap 'rm -f "$TMP_INDEXES"' EXIT + +MIN_FIREBASE_TOOLS_VERSION="${MIN_FIREBASE_TOOLS_VERSION:-15.17.0}" + +version_ge() { + local installed="$1" + local required="$2" + if [ "$(printf '%s\n' "$required" "$installed" | sort -V | head -n1)" != "$required" ]; then + return 1 + fi + return 0 +} + +INSTALLED_VERSION="$("${FIREBASE_CMD[@]}" --version | tr -d '\r')" +if ! version_ge "$INSTALLED_VERSION" "$MIN_FIREBASE_TOOLS_VERSION"; then + echo "❌ firebase-tools ${INSTALLED_VERSION} is below required ${MIN_FIREBASE_TOOLS_VERSION} (search index deploy)." >&2 + exit 1 +fi + +echo "Verifying Firestore indexes for project=${PROJECT} database=${DATABASE} (firebase-tools ${INSTALLED_VERSION})" + +"${FIREBASE_CMD[@]}" use "$PROJECT" >/dev/null +"${FIREBASE_CMD[@]}" firestore:indexes --project "$PROJECT" --database "$DATABASE" >"$TMP_INDEXES" + +# B2: full-text search composite on search-text/menu (not find-nearest vector index). +if ! python3 - "$TMP_INDEXES" <<'PY' +import json, sys +path = sys.argv[1] +with open(path) as f: + data = json.load(f) +indexes = data.get("indexes") or [] + +def has_search_menu_index(indexes): + for entry in indexes: + if entry.get("collectionGroup") != "search-text": + continue + for field in entry.get("fields") or []: + if field.get("fieldPath") != "menu": + continue + sc = field.get("searchConfig") or {} + specs = ((sc.get("textSpec") or {}).get("indexSpecs") or []) + for spec in specs: + if spec.get("indexType") == "TOKENIZED" and spec.get("matchType") == "MATCH_GLOBALLY": + return True + return False + +if not has_search_menu_index(indexes): + print("Missing expected search-text/menu TOKENIZED MATCH_GLOBALLY searchConfig index in cloud export.", file=sys.stderr) + print("Triage: firebase-tools version, firestore.pipelines-e2e.indexes.json schema, index BUILDING state.", file=sys.stderr) + sys.exit(1) +print("OK: search-text/menu search index present in cloud export.") +PY +then + exit 1 +fi + +# Optional: warn when vector find-nearest index missing (separate from search spine). +if ! python3 - "$TMP_INDEXES" <<'PY' +import json, sys +path = sys.argv[1] +with open(path) as f: + data = json.load(f) +for entry in data.get("indexes") or []: + if entry.get("collectionGroup") == "find-nearest": + for field in entry.get("fields") or []: + if field.get("fieldPath") == "embedding" and field.get("vectorConfig"): + print("OK: find-nearest vector index present.") + sys.exit(0) +print("WARN: find-nearest vector index not found in cloud export (may still be BUILDING).", file=sys.stderr) +PY +then + : +fi + +echo "Firestore index verification passed." diff --git a/.github/workflows/tests_e2e_ios.yml b/.github/workflows/tests_e2e_ios.yml index b416f50275..1d3e04a482 100644 --- a/.github/workflows/tests_e2e_ios.yml +++ b/.github/workflows/tests_e2e_ios.yml @@ -357,11 +357,12 @@ jobs: command: RNFB_START_SIM_LOGS=0 ./.github/workflows/scripts/boot-simulator.sh - name: Start Simulator App Log - # One filtered sim log stream (testing + SpringBoard/invertase); optional sim video when record_screens. + # One filtered sim log stream (testing + SpringBoard/invertase + Storage); optional sim video when record_screens. + # RNFB_SIM_LOG_STDOUT=1 surfaces sim-app.log lines in the step log for iOS Storage diagnosis (B3.1). continue-on-error: true run: | chmod +x ./.github/workflows/scripts/boot-simulator.sh - RNFB_RECORD_SCREENS="${RNFB_RECORD_SCREENS}" RNFB_SIM_BOOT_MODE=logs ./.github/workflows/scripts/boot-simulator.sh + RNFB_RECORD_SCREENS="${RNFB_RECORD_SCREENS}" RNFB_SIM_BOOT_MODE=logs RNFB_SIM_LOG_STDOUT=1 ./.github/workflows/scripts/boot-simulator.sh - name: Wait for host load to settle continue-on-error: true diff --git a/.spellcheck.dict.txt b/.spellcheck.dict.txt index 4d7ed610e2..c07a72a573 100644 --- a/.spellcheck.dict.txt +++ b/.spellcheck.dict.txt @@ -5,6 +5,7 @@ AdMob AirPods analytics Analytics +args ANR APIs APIs. @@ -88,6 +89,7 @@ FirebaseApp FirebaseCore firestore Firestore +FieldValue geospatial Geospatial freeform @@ -138,6 +140,7 @@ macOS MDX mlkit MLKit +microtask mono-repo multidex Multidex diff --git a/.yarnrc.yml b/.yarnrc.yml index 894bf1ef8f..1cdf733628 100644 --- a/.yarnrc.yml +++ b/.yarnrc.yml @@ -48,3 +48,4 @@ npmPreapprovedPackages: - '@firebase/util@1.15.1' - '@react-native-firebase/*' - 'firebase@12.15.0' # If adopting recent firebase-js-sdk, specify directly here + - 'firebase-tools@15.22.4' diff --git a/AGENTS.md b/AGENTS.md index 66ab87c7a2..a2d05ab12b 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -12,7 +12,7 @@ - **Agent shell commands:** [agent-command-policy.md](okf-bundle/testing/agent-command-policy.md) only (allowlist). E2e additionally [running-e2e.md § agent rule](okf-bundle/testing/running-e2e.md#agent-rule-read-first). - Follow local package patterns; check `type-test.ts`, `__tests__/`, and plugin dirs before public API/platform changes. - Start with `okf-bundle/index.md` for repo-specific implementation/testing/maintenance knowledge. -- **Change authoring:** [change-authoring-workflow.md](okf-bundle/testing/change-authoring-workflow.md) — baseline → unit-focused implementation → area-focused review → commit. +- **Change authoring:** [change-authoring-workflow.md](okf-bundle/testing/change-authoring-workflow.md) — baseline → unit-focused implementation → area-focused review → commit; [**validation evidence**](okf-bundle/testing/change-authoring-workflow.md#validation-evidence-blocking) and [**coverage evidence**](okf-bundle/testing/coverage-design.md#coverage-evidence-package) required before gates close or push. - Use package indexes under `okf-bundle/packages/` for package-specific workflows and active work queues. - Follow `okf-bundle/documentation-policy.md`: durable knowledge in reference docs; ephemeral state only in explicit work queues; commits are documentation; single-commit PR titles must match the commit subject exactly. - Testing entry points: `okf-bundle/testing/index.md`; validation requirements: `okf-bundle/testing/validation-checklist.md`. diff --git a/docs/firestore/pipelines/sdk-compatibility.mdx b/docs/firestore/pipelines/sdk-compatibility.mdx index 555de99155..f8f424a08f 100644 --- a/docs/firestore/pipelines/sdk-compatibility.mdx +++ b/docs/firestore/pipelines/sdk-compatibility.mdx @@ -11,45 +11,25 @@ CI enforces parity through `yarn compare:types` and the `firestore-pipelines` al # Summary -| Category | Status | -| --------------------------------------------------------------------------- | --------------------------------------------------------------------- | -| Core pipeline builder (`pipeline()`, stages, `execute()`) | **Supported** on Android, iOS, and macOS | -| Expression helpers (aggregates, strings, arrays, maps, timestamps, vectors) | **Mostly supported** — see gaps below | -| Newer firebase-js-sdk helpers (2025–2026) | **Partial** — tracked in "Not yet available" | -| firebase-js-sdk `Type` export | **React Native Firebase only** — use `isType()` with our `Type` union | +| Category | Status | +| --------------------------------------------------------------------------- | ---------------------------------------- | +| Core pipeline builder (`pipeline()`, stages, `execute()`) | **Supported** on Android, iOS, and macOS | +| Expression helpers (aggregates, strings, arrays, maps, timestamps, vectors) | **Supported** on Android, iOS, and macOS | +| Current firebase-js-sdk pipeline exports | **Supported** through compare-types | # Not yet available in React Native Firebase -These firebase-js-sdk pipeline exports are **not** exposed yet. They are listed in the repository compare-types allowlist until implemented: +All pipeline exports currently tracked in the compare-types allowlist are supported. Check release notes when upgrading for newly added firebase-js-sdk pipeline APIs. -| Export | Kind | Notes | -| -------------------- | ---------- | -------------------------------------------------- | -| `documentMatches` | Expression | Document matching helper (requires `search` stage) | -| `geoDistance` | Expression | Geospatial distance (requires `search` stage) | -| `score` | Expression | Full-text search score | -| `parent` | Stage | Parent document stage | -| `DefineStageOptions` | Type | Options for define stage | -| `SearchStageOptions` | Type | Full-text search stage options | +## Platform notes -If you depend on one of these, follow [Firebase pipeline release notes](https://firebase.google.com/support/release-notes/js) and React Native Firebase changelogs, or open a feature request with your use case. - -# Same name, slightly different shape +Compare-types parity does not guarantee identical runtime behavior on every target. The `parent()` expression helper may be unavailable on web and on macOS when pipelines execute through the firebase-js-sdk interop path (**P-036**). Pipelines that use the search stage with text matching need a deployed composite search index on the Enterprise `pipelines-e2e` database used in CI (**P-035**); native iOS and Android e2e cover search after that index is deployed. The `geoDistance` helper is covered for types and serialization; dedicated runtime e2e is deferred because native platforms lower it through the generic function path. Maintainer drift IDs and e2e expectations are tracked in [`okf-bundle/packages/firestore/pipeline-platform-parity.md`](https://github.com/invertase/react-native-firebase/blob/main/okf-bundle/packages/firestore/pipeline-platform-parity.md). -These exports exist in both SDKs but differ in typing or optional parameters: - -| Export | Difference | -| ----------------- | --------------------------------------------------------------------- | -| `timestampDiff` | Declaration overload ordering differs; all four SDK shapes supported | -| `constant` | firebase-js-sdk added optional `preferIntegers`; not yet on RNFB | -| `isType` | RNFB accepts the local `Type` alias; JS SDK accepts a broader string | -| `StageOptions` | Equivalent runtime shape; declaration formatting differs | -| `TimeGranularity` | RNFB uses `isoWeek` / `isoYear`; JS SDK also lists lowercase variants | +If you depend on one of these, follow [Firebase pipeline release notes](https://firebase.google.com/support/release-notes/js) and React Native Firebase changelogs, or open a feature request with your use case. -# React Native Firebase only +# Type-shape parity -| Export | Notes | -| ------ | ----------------------------------------------------------------------- | -| `Type` | Local type discriminator union used with `isType()` and related helpers | +The current `firestore-pipelines` compare-types config has no `differentShape` entries. `StageOptions`, `TimeGranularity`, `isType`, and `timestampDiff` now match the firebase-js-sdk declarations, including the lowercase `isoweek` and `isoyear` time granularity literals. # Platform execution matrix diff --git a/docs/migrating-to-v26.mdx b/docs/migrating-to-v26.mdx index 67718dda7c..1d834a1b52 100644 --- a/docs/migrating-to-v26.mdx +++ b/docs/migrating-to-v26.mdx @@ -12,6 +12,8 @@ If you are upgrading from v24 or earlier, complete [Migrating to v25](/migrating ## Table of contents - [New Architecture requirement](/migrating-to-v26#new-architecture-requirement) +- [Platform behavior differences](/migrating-to-v26#platform-behavior-differences) +- [firebase-js-sdk API parity improvements](/migrating-to-v26#firebase-js-sdk-api-parity-improvements) - [General pattern](/migrating-to-v26#general-pattern) - [App](/migrating-to-v26#app) - [Machine Learning (ML)](/migrating-to-v26#machine-learning-ml) @@ -81,22 +83,90 @@ Native builds fail early with explicit guards: When migrating from firebase-js-sdk web examples, watch for these high-impact runtime divergences: -| Area | firebase-js-sdk (web) | React Native Firebase | -| ----------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| **Auth** | Browser persistence, redirects, reCAPTCHA, `revokeAccessToken`, `useDeviceLanguage`, `linkWithPhoneNumber` / `reauthenticateWithPhoneNumber` | Native iOS/Android SDKs manage persistence. Several web-only helpers **throw synchronously** on React Native (`setPersistence`, `getRedirectResult`, `revokeAccessToken`, `useDeviceLanguage`, `linkWithPhoneNumber`, `reauthenticateWithPhoneNumber`). Use native provider flows instead. | -| **Analytics** | Cross-platform modular API | On-device conversion measurement helpers (`initiateOnDeviceConversionMeasurement*`) are **iOS only**; on Android and web the JS layer resolves without calling native (no-op). `logTransaction` (verified iOS in-app purchase events) is **iOS only** and **rejects** on other platforms. | -| **Realtime Database** | `goOnline` / `goOffline` are synchronous; web transport toggles | `goOnline` / `goOffline` are **synchronous** through TurboModules, matching firebase-js-sdk. `getServerTime`, `setPersistenceEnabled`, and `setPersistenceCacheSizeBytes` are RN-specific. `forceLongPolling` / `forceWebSockets` **throw** — transport is native-controlled. | -| **Phone Number Verification** | N/A (Android SDK only) | **Android only** — all entry points throw on iOS and Web. | -| **Cloud Storage** | `uploadBytes` / `uploadString` from JS blobs | `putFile` and `writeToFile` are **native-only** file-path APIs with no firebase-js-sdk equivalent. Retry-time setters are modular functions on RN, not instance properties. | -| **Cloud Messaging** | Web push / service-worker surface | FCM token lifecycle, permissions, background handlers, and **APNs token APIs are iOS only**. Event delivery still uses the legacy native event proxy during the TurboModule migration; behavior matches pre-v26 releases but will change when Codegen events land in a future release. | -| **Remote Config** | `reset()` clears server and local state | `reset()` is **Android only** — iOS does not clear activated, fetched, or default Remote Config values. `setDefaultsFromResource` loads from native resource files (`.plist` / XML). | -| **Performance** | `initializePerformance` returns synchronously; trace `start`/`stop` are sync | `initializePerformance` is **synchronous** on RN (applies settings to the native instance). Trace, HTTP metric, and screen trace `start`/`stop` are **synchronous** through TurboModules, matching firebase-js-sdk. | -| **Firestore** | IndexedDB persistence, `memoryLocalCache`, `persistentLocalCache` | Local cache factories and IndexedDB APIs are **web only**. Persistence is controlled by the native Firestore SDK. `initializeFirestore` is **async** on RN. | -| **App Check** | reCAPTCHA version 3 / Enterprise web providers | Use `ReactNativeFirebaseAppCheckProvider` for Device Check, App Attest, Play Integrity, etc. Web reCAPTCHA provider classes have **no RN equivalent**. | -| **RN-native-only modules** | No web SDK | `crashlytics`, `in-app-messaging`, `app-distribution`, and `ml` are **React Native only** — no firebase-js-sdk modular surface. | +{/* prettier-ignore */} +| Area | firebase-js-sdk (web) | React Native Firebase | +| --- | --- | --- | +| **Auth** | Browser persistence, redirects, reCAPTCHA, `revokeAccessToken`, `useDeviceLanguage`, `linkWithPhoneNumber` / `reauthenticateWithPhoneNumber` | Native iOS/Android SDKs manage persistence. Several web-only helpers **throw synchronously** on React Native (`setPersistence`, `getRedirectResult`, `revokeAccessToken`, `useDeviceLanguage`, `linkWithPhoneNumber`, `reauthenticateWithPhoneNumber`). Use native provider flows instead. | +| **Analytics** | Cross-platform modular API | On-device conversion measurement helpers (`initiateOnDeviceConversionMeasurement*`) are **iOS only**; on Android and web the JS layer resolves without calling native (no-op). `logTransaction` (verified iOS in-app purchase events) is **iOS only** and **rejects** on other platforms. | +| **Realtime Database** | `goOnline` / `goOffline` are synchronous; web transport toggles | `goOnline` / `goOffline` are **synchronous** through TurboModules, matching firebase-js-sdk. `getServerTime`, `setPersistenceEnabled`, and `setPersistenceCacheSizeBytes` are RN-specific. `forceLongPolling` / `forceWebSockets` **throw** — transport is native-controlled. | +| **Phone Number Verification** | N/A (Android SDK only) | **Android only** — all entry points throw on iOS and Web. | +| **Cloud Storage** | `uploadBytes` / `uploadString` from JS blobs; upload task controls return sync `boolean` | `putFile` and `writeToFile` are **native-only** file-path APIs. `UploadTask.pause()` / `.resume()` / `.cancel()` also return sync `boolean` values through native TurboModules. | +| **Cloud Messaging** | Web push / service-worker surface | FCM token lifecycle, permissions, background handlers, and **APNs token APIs are iOS only**. Event delivery still uses the legacy native event proxy during the TurboModule migration; behavior matches pre-v26 releases but will change when Codegen events land in a future release. | +| **Remote Config** | `reset()` clears server and local state | `reset()` is **Android only** — iOS does not clear activated, fetched, or default Remote Config values. `setDefaultsFromResource` loads from native resource files (`.plist` / XML). | +| **Performance** | `initializePerformance` returns synchronously; trace `start`/`stop` are sync | `initializePerformance` is **synchronous** on RN (applies settings to the native instance). Trace, HTTP metric, and screen trace `start`/`stop` are **synchronous** through TurboModules, matching firebase-js-sdk. | +| **Firestore** | IndexedDB persistence, `memoryLocalCache`, `persistentLocalCache`, FieldValue `maximum()` / `minimum()` sentinels | Local cache factories and IndexedDB APIs are **web only**. Persistence is controlled by the native Firestore SDK. `initializeFirestore` returns **`Firestore` synchronously**. FieldValue `maximum()` / `minimum()` are not exported yet because iOS SDK 12.15.0 lacks matching native factories. | +| **App Check** | reCAPTCHA version 3 / Enterprise web providers | Use `ReactNativeFirebaseAppCheckProvider` for Device Check, App Attest, Play Integrity, etc. Web reCAPTCHA provider classes have **no RN equivalent**. | +| **RN-native-only modules** | No web SDK | `crashlytics`, `in-app-messaging`, `app-distribution`, and `ml` are **React Native only** — no firebase-js-sdk modular surface. | Per-package notes also appear in each module's [usage](/) page under **Platform support**. +## firebase-js-sdk API parity improvements + +v26 aligns React Native Firebase modular types and several runtime signatures with **firebase-js-sdk** where TurboModules removed bridge-forced `Promise` wrappers. Use this section when porting web SDK examples or when scripted upgrades hit TypeScript or runtime errors. + +**Migration rule:** If a method below is **sync**, remove `await` and any `.then()` / `.catch()` chain on its return value — sync APIs return `void` or a value directly; calling `.then()` on `void` throws at runtime. + +### Synchronous APIs enabled by TurboModules + +{/* prettier-ignore */} +| Method | Before (pre-v26 / legacy bridge) | After (v26) | Notes | +| ------ | -------------------------------- | ----------- | ----- | +| `registerVersion(library, version, variant?)` | `Promise` (web) | `void` — throws on RN | Web-only on RN; remove `await` if copied from web samples | +| `isSignInWithEmailLink(auth, emailLink)` | `Promise` | `boolean` | Remove `await` | +| `TotpSecret.generateQrCodeUrl(accountName?, issuer?)` | `Promise` | `string` | Remove `await`; omitted args default from current user / app name | +| `trace(…).start()` / `.stop()` | `Promise` | `void` | Remove `await` on perf trace lifecycle | +| `httpMetric(…).start()` / `.stop()` | `Promise` | `void` | Same as traces | +| `ScreenTrace.start()` / `.stop()` | `Promise` | `void` | Same as traces | +| `startScreenTrace(performance, screenName)` | `Promise` | `ScreenTrace` | Remove `await` | +| `goOnline(db)` / `goOffline(db)` | `Promise` | `void` | Remove `await` | +| `UploadTask.pause()` / `.resume()` / `.cancel()` | `Promise` | `boolean` | Remove `await`; use the returned boolean directly | + +### Type parity improvements + +{/* prettier-ignore */} +| Export / method | Before | After | Notes | +| --------------- | ------ | ----- | ----- | +| `onSnapshotsInSync(firestore, observer)` | `next?: () => void`; `error?: Error` | `next?: (value: void) => void`; `error?: FirestoreError` | Callback overload `onSnapshotsInSync(firestore, () => {})` unchanged | +| `uploadBytes(ref, data, metadata?)` | Return type `TaskResult` | `UploadResult` | Alias rename only | +| `uploadBytesResumable(ref, data, metadata?)` | Return type `Task` | `UploadTask` | Alias rename only | +| Storage / Remote Config error callbacks | `NativeFirebaseError` | `FirebaseError` / `StorageError` | `NativeFirebaseError` remains assignable to `FirebaseError` | +| `AppCheckTokenListener` | Not exported | Exported type alias | Matches firebase-js-sdk observer typing | +| `FunctionsError`, `FunctionsErrorCodeCore` | Missing or misaligned | Exported / aligned | Registry + compare-types config | +| `firestore/pipelines` (`StageOptions`, `TimeGranularity`, `isType`, …) | Declaration drift | Aligned to SDK `.d.ts` | Type-only; no call-shape change | + +### Synchronous modular return values + +{/* prettier-ignore */} +| Method | Before | After | Notes | +| ------ | ------ | ----- | ----- | +| `logEvent(analytics, …)` | `Promise` | `void` | Fire-and-forget; remove `await` / `.then()` | +| `initializeAppCheck(app?, options?)` | `Promise` | `AppCheck` | Returns handle immediately; provider setup continues natively | +| `initializeFirestore(app, settings, databaseId?)` | `Promise` | `Firestore` | Returns instance immediately; `settings()` runs on native bridge | +| `getRemoteConfig(app?, options?)` | `(app?)` only | `(app?, options?: RemoteConfigOptions)` | `options` accepted for parity; no-op on native | +| `aggregateFieldEqual()` | Not exported | Exported | Aggregate query helper | +| `LastFetchStatus` literals | — | — | **Unchanged** — native still uses `no_fetch_yet` / `throttled` (documented drift) | + +### Firestore parity additions + +{/* prettier-ignore */} +| Export / method | Before | After | Notes | +| --------------- | ------ | ----- | ----- | +| `TransactionOptions` | Not exported | Exported | Type for transaction retry options | +| `runTransaction(firestore, updateFunction, options?)` | No options argument | Accepts `options?: TransactionOptions` | `{ maxAttempts?: number }` on native iOS and Android; omitted options use the SDK default of **5** retries; explicit values **< 1** throw `Max attempts must be at least 1` (firebase-js-sdk parity) | +| `aggregateQuerySnapshotEqual()` | Not exported | Exported | Aggregate query snapshot equality helper, alongside `aggregateFieldEqual()` | +| `maximum(n)` / `minimum(n)` FieldValue sentinels | Exported by firebase-js-sdk 12.15.0 | Not exported by RNFB yet | Android SDK 34.15.0 has native factories, but iOS Firebase Firestore SDK 12.15.0 does not; RNFB waits for cross-platform parity | + +### Observer and Promise pitfalls + +{/* prettier-ignore */} +| Pitfall | Symptom | Fix | +| ------- | ------- | --- | +| `.then()` on sync API | `TypeError: … .then is not a function` | Use direct call: `logEvent(…)` not `logEvent(…).then(…)` | +| `await` on sync API | Unnecessary microtask delay; misleading types in strict TS | Drop `await` where the table above marks the API sync | +| `onConfigUpdate(remoteConfig, observer)` | Runtime throw: observer must include **both** `next` and `error` functions | Pass `{ next: (update) => {…}, error: (err) => {…} }` — do not omit `error` | +| `onSnapshotsInSync` observer form | Type error on `error` callback | Type `error` as `(error: FirestoreError) => void`, or use the `() => void` callback overload | +| `runTransaction(..., { maxAttempts: 0 })` or negative | Runtime throw: `Max attempts must be at least 1` | Omit `options` for the default **5** attempts, or pass `maxAttempts: 1` or higher | + ## General pattern For each package listed in this guide: @@ -420,6 +490,10 @@ The namespaced API for `@react-native-firebase/app-check` has been **removed**. | `FirebaseAppCheckTypes` | Import `AppCheck`, `AppCheckTokenResult`, etc. from package root | | `appCheck().getToken()` | `getToken(appCheck, forceRefresh?)` | +## Signature changes + +- `initializeAppCheck(app?, options?)` returns `AppCheck` synchronously (previously `Promise`). Native provider setup continues in the background — remove `await` and do not chain `.then()`. + # Analytics The namespaced API for `@react-native-firebase/analytics` has been **removed**. This package is **modular-only** — use `getAnalytics()` and root-level helper functions. @@ -437,6 +511,10 @@ Analytics supports only the **default Firebase app** (same as before). Calling ` | `analytics().setUserId(...)` etc. | `setUserId(analytics, ...)`, `setConsent(analytics, ...)`, etc. | | Deprecated helper events (`logScreenView`, `logPurchase`, …) | Still exported as modular helpers; prefer `logEvent(analytics, 'screen_view', params)` | +## Signature changes + +- `logEvent(analytics, …)` returns `void` synchronously (previously `Promise`). Remove `await` and `.then()` chains. + ## Example ```js @@ -453,7 +531,7 @@ await analytics().setUserId('user-123'); import { getAnalytics, logEvent, setUserId } from '@react-native-firebase/analytics'; const analytics = getAnalytics(); -await logEvent(analytics, 'screen_view', { screen_name: 'Home' }); +logEvent(analytics, 'screen_view', { screen_name: 'Home' }); await setUserId(analytics, 'user-123'); ``` @@ -552,6 +630,11 @@ The namespaced API for `@react-native-firebase/storage` has been **removed**. Th | `storage().ref()` | `ref(storage, path?)` | | `storageRef.put()` | `uploadBytesResumable(storageRef, data, metadata?)` | +## Signature changes + +- `UploadTask.pause()`, `UploadTask.resume()`, and `UploadTask.cancel()` now return `boolean` synchronously (previously `Promise`), matching firebase-js-sdk task semantics. Remove `await`, `.then()`, and `.catch()` from these control calls and use the returned boolean directly. +- `cancel()` delegates to the native SDK. Android cancels active uploads; iOS active-upload cancel follows the current Firebase Storage iOS SDK 12.15.0 behavior tracked in [firebase-ios-sdk#16353](https://github.com/firebase/firebase-ios-sdk/issues/16353). + # Authentication The namespaced API for `@react-native-firebase/auth` has been **removed**. This package is **modular-only** — use `getAuth()` / `initializeAuth()` and root-level helper functions. @@ -606,12 +689,19 @@ The namespaced API for `@react-native-firebase/firestore` has been **removed**. | `firestore().collection(...)` | `collection(getFirestore(), ...)` | | `firestore().doc(...)` | `doc(getFirestore(), ...)` | | `firestore().batch()` | `writeBatch(getFirestore())` | -| `firestore().runTransaction(...)` | `runTransaction(getFirestore(), ...)` | +| `firestore().runTransaction(...)` | `runTransaction(getFirestore(), updateFunction, options?)` | | `firestore().useEmulator(...)` | `connectFirestoreEmulator(getFirestore(), ...)` | | `firestore().settings(...)` | `initializeFirestore(app, settings, databaseId?)` | | `firestore.FieldValue` / `firestore.Timestamp` | `FieldValue`, `Timestamp`, `FieldPath`, `Bytes`, `GeoPoint`, `Filter` (named exports) | | `firestore.Blob` | `Bytes` | +## Signature changes + +- `initializeFirestore(app, settings, databaseId?)` returns `Firestore` synchronously (previously `Promise`). Remove `await` and `.then()`; settings apply on the native bridge after return. +- `TransactionOptions` is now exported. `runTransaction(firestore, updateFunction, options?)` accepts `{ maxAttempts?: number }` and passes the retry limit to the native iOS and Android Firestore SDKs. When `options` is omitted, the native default applies (**5** attempts, matching [firebase-js-sdk `runTransaction`](https://firebase.google.com/docs/reference/js/firestore_.md#runtransaction)). When `maxAttempts` is provided explicitly, values below **1** throw synchronously with `Max attempts must be at least 1` — the same validation as firebase-js-sdk. +- `aggregateFieldEqual()` and `aggregateQuerySnapshotEqual()` are now exported for aggregate query equality checks (firebase-js-sdk parity). +- FieldValue `maximum(n)` and `minimum(n)` sentinels from firebase-js-sdk 12.15.0 are not exported yet. Android Firebase Firestore SDK 34.15.0 supports them, but iOS Firebase Firestore SDK 12.15.0 does not expose matching `FIRFieldValue` factories, so React Native Firebase waits for cross-platform support. + ## Example ```js @@ -676,6 +766,8 @@ For each modular-only package you use: | `storage` | `firebase.storage()`, default `storage()`, `FirebaseStorageTypes`, instance/reference methods | `getStorage()`, `ref`, `uploadBytesResumable`, `getDownloadURL`, `connectStorageEmulator`, `StringFormat`, `TaskEvent`, `TaskState` | | `firestore` | `firebase.firestore()`, default `firestore()`, `FirebaseFirestoreTypes`, instance methods | `getFirestore()`, `doc`, `collection`, `setDoc`, `writeBatch`, `runTransaction`, `connectFirestoreEmulator`, `FieldValue`, `Timestamp`, `Bytes`, `SDK_VERSION` | +Also remove `await`, `.then()`, and `.catch()` from `UploadTask.pause()`, `UploadTask.resume()`, and `UploadTask.cancel()`. For Firestore transactions, import `TransactionOptions` when you pass `{ maxAttempts }` (omit `options` for the default **5** retries; do not pass `0` or negative values). Import `aggregateFieldEqual()` / `aggregateQuerySnapshotEqual()` for aggregate equality checks. + ## 3. Validate ```bash diff --git a/jest.setup.ts b/jest.setup.ts index 2d6c25fb4f..66d3ecea4f 100644 --- a/jest.setup.ts +++ b/jest.setup.ts @@ -608,7 +608,7 @@ jest.doMock('react-native', () => { updateMetadata: jest.fn(() => Promise.resolve({})), writeToFile: jest.fn(() => Promise.resolve()), putFile: jest.fn(() => Promise.resolve()), - setTaskStatus: jest.fn(() => Promise.resolve()), + setTaskStatus: jest.fn(() => true), list: jest.fn(() => Promise.resolve({ items: [], prefixes: [], pageToken: null })), listAll: jest.fn(() => Promise.resolve({ items: [], prefixes: [], pageToken: null })), }, @@ -627,7 +627,7 @@ jest.doMock('react-native', () => { updateMetadata: jest.fn(() => Promise.resolve({})), writeToFile: jest.fn(() => Promise.resolve()), putFile: jest.fn(() => Promise.resolve()), - setTaskStatus: jest.fn(() => Promise.resolve()), + setTaskStatus: jest.fn(() => true), list: jest.fn(() => Promise.resolve({ items: [], prefixes: [], pageToken: null })), listAll: jest.fn(() => Promise.resolve({ items: [], prefixes: [], pageToken: null })), }, diff --git a/okf-bundle/documentation-policy.md b/okf-bundle/documentation-policy.md index 72e2fb3654..88b65ca904 100644 --- a/okf-bundle/documentation-policy.md +++ b/okf-bundle/documentation-policy.md @@ -44,7 +44,7 @@ Confirm: | Check | Requirement | |-------|-------------| -| **Canonical location** | Each topic has one owning doc; others link to it ([agent command policy](testing/agent-command-policy.md) for **all** agent shell commands; [change authoring](testing/change-authoring-workflow.md) for workflow/gates/frozen tree; [running e2e](testing/running-e2e.md) for e2e `yarn tests:*` detail — [agent rule](testing/running-e2e.md#agent-rule-read-first); [platform coverage gate](testing/running-e2e.md#platform-coverage-gate-blocking); [iteration vocabulary](testing/iteration-vocabulary.md) for term ids only; [documentation site maintenance](documentation-site-maintenance.md) for `docs.json`, TypeDoc, and legacy redirect audits; this file for doc/commit policy, etc.) | +| **Canonical location** | Each topic has one owning doc; others link to it ([agent command policy](testing/agent-command-policy.md) for **all** agent shell commands; [change authoring](testing/change-authoring-workflow.md) for workflow/gates/frozen tree; [change authoring § validation evidence (blocking)](testing/change-authoring-workflow.md#validation-evidence-blocking); [running e2e](testing/running-e2e.md) for e2e `yarn tests:*` detail — [agent rule](testing/running-e2e.md#agent-rule-read-first); [platform coverage gate](testing/running-e2e.md#platform-coverage-gate-blocking); [iteration vocabulary](testing/iteration-vocabulary.md) for term ids only; [change authoring § quality standards](testing/change-authoring-workflow.md#quality-standards) for the review-findings resolution rule and the intractable-limitation bar; [compare-types README § justification bar](../.github/scripts/compare-types/README.md#justification-bar) for firebase-js-sdk type/API drift justification; [coverage design § expectations](testing/coverage-design.md#coverage-expectations-policy); [coverage design § evidence package](testing/coverage-design.md#coverage-evidence-package) for coverage completion evidence; [documentation site maintenance](documentation-site-maintenance.md) for `docs.json`, TypeDoc, and legacy redirect audits; this file for doc/commit policy, etc.) | | **DRY** | No duplicated procedures, policy paragraphs, or ephemeral snapshots outside work queues | | **Link hygiene** | Cross-links resolve; indexes list canonical entry points | | **Durability** | No ephemeral fields leaked into general reference docs | diff --git a/okf-bundle/index.md b/okf-bundle/index.md index 9ddff16c09..8dc72f5fd5 100644 --- a/okf-bundle/index.md +++ b/okf-bundle/index.md @@ -14,7 +14,7 @@ okf_version: "0.1" # Testing * [Agent command policy](/testing/agent-command-policy.md) — allowlisted shell commands for agents (install, prepare, validation, e2e) -* [Change authoring workflow](/testing/change-authoring-workflow.md) — verified product change loop (unit-focused → area-focused review → commit) +* [Change authoring workflow](/testing/change-authoring-workflow.md) — verified product change loop (unit-focused → area-focused review → commit); [§ validation evidence (blocking)](testing/change-authoring-workflow.md#validation-evidence-blocking); [coverage evidence package](testing/coverage-design.md#coverage-evidence-package) * [Iteration vocabulary](/testing/iteration-vocabulary.md) — work type, tier, and queue field identifiers * [Running e2e tests](/testing/running-e2e.md) — canonical e2e commands, narrowing, environment, diagnosis * [Validation checklist](/testing/validation-checklist.md) — compile, Jest, lint, `compare:types`, e2e, coverage diff --git a/okf-bundle/namespace-api-removal-work-queue.md b/okf-bundle/namespace-api-removal-work-queue.md index e468d7d6e2..e6768e8abc 100644 --- a/okf-bundle/namespace-api-removal-work-queue.md +++ b/okf-bundle/namespace-api-removal-work-queue.md @@ -56,7 +56,7 @@ Each module follows **one** serial loop. Work types: [change authoring workflow | **3** | `implementation` | `implementation` | [Workflow checklist](namespace-api-removal-workflow.md#per-module-implementation); **unit-focused** tier; `.only` OK locally; **no commit** | | **4** | `independent-review` | `review` | **Frozen tree**; **area-focused** tier; removal greps; minor/nit → remediation + delta re-review | | **5** | `documentation` | — | Migration guide + OKF if durable learnings | -| **6** | `commit` | `commit` | Set `commit_subject`, close gates in queue doc, stage queue **with** product commit; one focused commit | +| **6** | `commit` | `commit` | [Validation evidence package](testing/validation-checklist.md#validation-evidence-package) recorded; set `commit_subject`, close gates in queue doc, stage queue **with** product commit; one focused commit | --- diff --git a/okf-bundle/namespace-api-removal-workflow.md b/okf-bundle/namespace-api-removal-workflow.md index 95bd6d9ba4..a6c6388575 100644 --- a/okf-bundle/namespace-api-removal-workflow.md +++ b/okf-bundle/namespace-api-removal-workflow.md @@ -90,7 +90,7 @@ Complete modular-only checklist (one focused commit scope): ## Per-module `independent-review` -On a **frozen tree** — [change authoring § independent-review](testing/change-authoring-workflow.md#independent-review), plus removal greps and module-specific **area-focused** e2e on [**every required platform**](testing/running-e2e.md#platform-coverage-gate-blocking) (no `.only`; **no Android/macOS shortcuts**). Minor/nit findings: fix or defer-with-rationale, then delta re-review before `commit`. +On a **frozen tree** — [change authoring § independent-review](testing/change-authoring-workflow.md#independent-review), plus removal greps and module-specific **area-focused** e2e on [**every required platform**](testing/running-e2e.md#platform-coverage-gate-blocking) (no `.only`; **no Android/macOS shortcuts**). Resolve **every** finding, including minor/nit — fix it, or record a user-accepted [exception](testing/change-authoring-workflow.md#acceptable-exceptions) ([review findings](testing/change-authoring-workflow.md#review-findings--resolve-do-not-defer)); no self-authorized deferral — then delta re-review before `commit`. ## Module area harness @@ -112,9 +112,10 @@ refactor(): remove deprecated namespaced API Before `git commit`: -1. Set the queue row's `commit_subject` to that exact line (replace ``). -2. Close `commit_gate` and update the header/next-pickup line in [namespace API removal work queue](namespace-api-removal-work-queue.md). -3. Stage product, user docs, durable OKF learnings, **and** the queue doc together — one commit. +1. [Validation evidence package](testing/validation-checklist.md#validation-evidence-package) recorded; [coverage evidence package](testing/coverage-design.md#coverage-evidence-package) when lib/native bridge touched. +2. Set the queue row's `commit_subject` to that exact line (replace ``). +3. Close `commit_gate` and update the header/next-pickup line in [namespace API removal work queue](namespace-api-removal-work-queue.md). +4. Stage product, user docs, durable OKF learnings, **and** the queue doc together — one commit. **Never stage:** area narrowing, any `.only`, ad-hoc harness edits, or **`RNFBDebug = true`** in `tests/globals.js`. diff --git a/okf-bundle/new-architecture/migration-work-queue.md b/okf-bundle/new-architecture/migration-work-queue.md index 3995fa7f51..469d831023 100644 --- a/okf-bundle/new-architecture/migration-work-queue.md +++ b/okf-bundle/new-architecture/migration-work-queue.md @@ -355,7 +355,7 @@ Each package (or one legacy module within a multi-module package) follows **one* | **3** | `implementation` | `implementation` | Spec, codegen, native, JS; Jest + **unit-focused** tier on **every required platform** when native bridge touched ([platform coverage gate](../testing/running-e2e.md#platform-coverage-gate-blocking)); handoff includes e2e platform matrix or env blocker — Jest-only insufficient; `.only` / area narrowing OK locally; **no commit** | | **4** | `independent-review` | `review` | **Frozen tree**; **area-focused** tier; no `.only`; [area harness](turbomodule-implementation-workflow.md#turbomodule-area-harness); serial [host rule](../testing/change-authoring-workflow.md#host-rule) | | **5** | `documentation` | — | User docs + durable OKF when applicable | -| **6** | `commit` | `commit` | One focused commit only after `review_gate` closed | +| **6** | `commit` | `commit` | One focused commit only after `review_gate` closed **with** [validation/coverage evidence](../testing/validation-checklist.md#validation-evidence-package) recorded | Canonical commands: [validation checklist](../testing/validation-checklist.md), [serialized dispatch](../testing/running-e2e.md#serialized-e2e-dispatch). diff --git a/okf-bundle/new-architecture/turbomodule-implementation-workflow.md b/okf-bundle/new-architecture/turbomodule-implementation-workflow.md index 552696edff..00d38dc6a3 100644 --- a/okf-bundle/new-architecture/turbomodule-implementation-workflow.md +++ b/okf-bundle/new-architecture/turbomodule-implementation-workflow.md @@ -211,7 +211,7 @@ Runs **after** every native package is on TurboModules (Phases 0–5), **before* **Completion signal (per package):** the corresponding async-vs-sync entry is removed from the package's `compare:types` config and `yarn compare:types` is clean for that package ([validation checklist § type parity](../testing/validation-checklist.md#api-reference-and-type-parity)). -**Caution:** sync across JSI runs on the JS thread — never convert a method that does real I/O. When unsure, keep it async; over-converting is a perf/ANR risk, under-converting is harmless. +**Caution:** sync across JSI runs on the JS thread — never convert a method that does real I/O. When unsure, keep it async: over-converting is a perf/ANR risk; under-converting keeps the correct async signature but leaves a documented async→sync parity gap tracked in `compare:types` until resolved. ## TurboModule `documentation` @@ -237,6 +237,8 @@ Breaking change (`!`): TurboModule migration requires New Architecture; legacy b **Never stage:** `tests/harness.overrides.js`, any `.only`, temporary sub-suite edits in `tests/app.js`. +Before `git commit`: [validation evidence package](../../testing/validation-checklist.md#validation-evidence-package) recorded; [coverage evidence package](../../testing/coverage-design.md#coverage-evidence-package) when lib/native bridge touched ([change authoring § commit](../../testing/change-authoring-workflow.md#commit)). + ## Gotchas * **macOS / web turbo name registration** — [`nativeModuleWeb.ts`](../../../packages/app/lib/internal/nativeModuleWeb.ts) registers JS-SDK shims by module name in the **registry object initializer** (not deferred to bottom-of-file calls) so `NativeRNFBTurbo*` names exist before `RNFBNativeEventEmitter` instantiates during circular imports. When [`APP_NATIVE_MODULE`](../../../packages/app/lib/internal/constants.ts) changes ([NewArch-AD-2](architecture-decisions.md#newarch-ad-2--naming-nativernfbturbo--accepted)), register **both** legacy `RNFBAppModule` and turbo keys. Missing registration → macOS **blank window** / `Native module NativeRNFBTurboApp is not registered` in `com.facebook.react.log:javascript`. diff --git a/okf-bundle/packages/firestore/pipeline-coverage-work-queue.md b/okf-bundle/packages/firestore/pipeline-coverage-work-queue.md index 8c25a832de..00ae97cb0d 100644 --- a/okf-bundle/packages/firestore/pipeline-coverage-work-queue.md +++ b/okf-bundle/packages/firestore/pipeline-coverage-work-queue.md @@ -8,7 +8,7 @@ timestamp: 2026-06-25T12:00:00Z # Pipeline coverage and parity — work queue -> **COMPLETE:** **Merge gate** closed — static pre-merge green; **R** closed. Ready for PR [9086](https://github.com/invertase/react-native-firebase/pull/9086) force-push + CI. +> **COMPLETE:** **Merge gate** closed — static pre-merge green; **R** closed. Ready for PR [9086](https://github.com/invertase/react-native-firebase/pull/9086) force-push + CI **after** [validation evidence](../../testing/change-authoring-workflow.md#validation-evidence-blocking) still valid on published commits. > **Goal/order:** platform parity first; then TS/native coverage toward intractable limits. Links: [parity](pipeline-platform-parity.md), [SDK audit](pipeline-sdk-support-audit.md), [coverage](../../testing/coverage-design.md), [e2e](../../testing/running-e2e.md), [architecture](pipelines.md). --- @@ -78,7 +78,7 @@ Gate prerequisites before any `:test-cover` ([host rule](../../testing/change-au **Label:** `after-phase-r-final`; **harness:** full app (committed defaults) -**Next item:** force-push branch → PR 9086 CI → paste [PR post draft](#pr-post-draft-coverage-table--copy-for-merge-comment). +**Next item:** force-push branch → PR 9086 CI → paste [PR post draft](#pr-post-draft-coverage-table--copy-for-merge-comment) — only after [validation evidence](../../testing/change-authoring-workflow.md#validation-evidence-blocking) still valid on published commits. **Current gates:** **Merge gate** **closed** (2026-07-03). compare:types 19/19 documented; Jest 1146/1146; tsc + lint green. **K–R** complete. @@ -255,7 +255,7 @@ Each J0 probe / J1–J6 bridge step follows **one** serial loop. No overlap. Wor | ----- | -------------------- | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **1** | `implementation` | `implementation` | Code/e2e changes; Jest + **unit-focused** tier; `.only` / tight area narrowing OK locally; **no commit** | | **2** | `independent-review` | `review` | **Frozen tree**; **area-focused** tier; no `.only`; area narrowing only in `tests/app.js` + `tests/globals.js`; serial [host rule](../../testing/change-authoring-workflow.md#host-rule) | -| **3** | `commit` | `commit` | One focused commit only after `review_gate` closed | +| **3** | `commit` | `commit` | One focused commit only after `review_gate` closed **with** [validation/coverage evidence](../../testing/validation-checklist.md#validation-evidence-package) recorded | Canonical commands: [serialized dispatch](../../testing/running-e2e.md#serialized-e2e-dispatch), [one iteration](../../testing/running-e2e.md#running-one-iteration), [guard probes](pipeline-implementation-workflow.md#ios-guard-probe-iterations). diff --git a/okf-bundle/packages/firestore/pipeline-implementation-workflow.md b/okf-bundle/packages/firestore/pipeline-implementation-workflow.md index 5b86dd681f..ad7c17ac04 100644 --- a/okf-bundle/packages/firestore/pipeline-implementation-workflow.md +++ b/okf-bundle/packages/firestore/pipeline-implementation-workflow.md @@ -64,15 +64,9 @@ Primary backlog: **`missingInRN`** in `.github/scripts/compare-types/configs/fir `compare-types` config is backlog, not permission. -### Shape differences: `differentShape` +### Shape differences: `differentShape` / `extraInRN` -Each entry needs a strict, intractable RN technical reason (bridge, platform SDK, Hermes/Metro, etc.). - -- If indefensible, align RNFB to firebase-js-sdk and remove the entry. -- Do not use `differentShape` for avoidable drift (formatting, naming, optional params). -- When implementing a `missingInRN` export, do not introduce new `differentShape` drift without the same intractability bar. - -`extraInRN`: justify RN-specific surface or remove. +Every documented difference must clear the [compare-types justification bar](../../../.github/scripts/compare-types/README.md#justification-bar). Avoidable drift is aligned to firebase-js-sdk and the entry removed; do not introduce new `differentShape` / `extraInRN` drift when implementing a `missingInRN` export. ## Pipeline `implementation` @@ -123,6 +117,8 @@ feat(firestore): expose pipeline **Never stage:** area narrowing in `tests/app.js` / `tests/globals.js`, any `.only`. +Before `git commit`: [validation evidence package](../../testing/validation-checklist.md#validation-evidence-package) recorded; [coverage evidence package](../../testing/coverage-design.md#coverage-evidence-package) when lib/native bridge touched ([change authoring § commit](../../testing/change-authoring-workflow.md#commit)). + ## Gotchas - **macOS is first-class** — web SDK interop; parity bugs often appear there first. diff --git a/okf-bundle/packages/firestore/pipeline-platform-parity.md b/okf-bundle/packages/firestore/pipeline-platform-parity.md index aa64a7b764..cb2b068d9e 100644 --- a/okf-bundle/packages/firestore/pipeline-platform-parity.md +++ b/okf-bundle/packages/firestore/pipeline-platform-parity.md @@ -73,6 +73,8 @@ No permanent `Platform.android` / `Platform.ios` e2e workaround without registry | **P-026** | findNearest validation | L4011–4013 | Vacuous pass | | **P-027** | empty addFields/removeFields | L4047–4049 | Vacuous pass | | **P-028** | findNearest DOTPRODUCT alias | L4073–4075 | Vacuous pass | +| **P-035** | Search stage + text index | L3007–3036 | Vacuous pass on macOS-js; firebase-js-sdk path requires deployed composite search index on `pipelines-e2e` — native iOS/Android run full assertions after index deploy | +| **P-036** | `define` stage + `parent()` | L2975–3094 | Vacuous pass on macOS-js for define and parent; web SDK rejects `parent(...)` operand shapes (STRING/MAP vs Reference) — native iOS/Android only (define L2975–2996; parent probes L2998–3094) | **macOS count note:** lower macOS total is app `utils*` registration, not Pipeline drift. Pipeline tests register on every platform; some macOS passes are vacuous (table). @@ -85,6 +87,7 @@ No permanent `Platform.android` / `Platform.ios` e2e workaround without registry | **P-029** | Android receiver-chain / deferred-unary lowering vs iOS direct `coerceExpressionTree` — no known e2e split | | **P-030** | iOS-only builder features: `xor`/`nor`, `pipelinevalue` direct build, `.condition` boolean unwrap — low traffic | | **P-031** | iOS `rawStage` skip (L3981) + iOS index-hint skip (L3796) — align with P-014/P-015 SDK gaps | +| **P-037** | `coerceDocumentPathValue` `DocumentReference` branches (iOS L548, Android L2463) | **Wire-unreachable** from RN pipeline execute: JS `serializeValue` (`packages/firestore/lib/pipelines/pipeline_runtime.ts` L313–318) always sends document/collection refs as `{ path }` constant maps, never a live `DocumentReference` on the bridge. Native branches are defensive parity for non-JS callers. **Intractable** native coverage gap (not missing e2e): parent wire shapes exercised in `pipelines-serialization-matrix.test.ts` (DocumentReference → `{ path }` constant) and `Pipeline.e2e.js` L2998–3094 (ref, constant-wrapped path map, string, field `__name__` deferred path). | --- diff --git a/okf-bundle/packages/firestore/pipeline-sdk-support-audit.md b/okf-bundle/packages/firestore/pipeline-sdk-support-audit.md index 4099379157..b37643086c 100644 --- a/okf-bundle/packages/firestore/pipeline-sdk-support-audit.md +++ b/okf-bundle/packages/firestore/pipeline-sdk-support-audit.md @@ -131,7 +131,7 @@ Probe order/gates/live status: [work queue](pipeline-coverage-work-queue.md#j0-- 2. Implement or fix native lowering; unify matching `Pipeline.e2e.js` assertions cross-platform. 3. Run the implement/review gate defined in the [work queue runtime protocol](pipeline-coverage-work-queue.md#phase-j-iteration-protocol-strict). 4. Record outcome: - - **`independent-review` pass** → `sdk-supported-bridge-ok`; close parity row; `commit` after `review_gate` closed. + - **`independent-review` pass** → `sdk-supported-bridge-ok`; close parity row; `commit` after `review_gate` closed **with** [validation/coverage evidence](../../testing/validation-checklist.md#validation-evidence-package) recorded. - **`invalid-argument` / pipeline execute error** → capture exact message; classify `sdk-unsupported-confirmed` or `rnfb-bridge-gap` (compare native request in debug logs). Android already runs full pipelines; macOS uses JS SDK. Probes focus on **native iOS/Android** execute paths. diff --git a/okf-bundle/packages/firestore/pipelines.md b/okf-bundle/packages/firestore/pipelines.md index 6415bc346f..6c3a3b5331 100644 --- a/okf-bundle/packages/firestore/pipelines.md +++ b/okf-bundle/packages/firestore/pipelines.md @@ -163,16 +163,16 @@ Live-path holes concentrate in **expression lowering** and **stage coercion**, n Quantified tables/priorities: [work queue](pipeline-coverage-work-queue.md). Script: `bash scripts/map-pipeline-coverage-gaps.sh