From 5d79c5b5049fea0ec0d3e747096970f6cef74858 Mon Sep 17 00:00:00 2001 From: Mike Hardy Date: Thu, 25 Jun 2026 18:02:27 -0500 Subject: [PATCH 01/10] docs: new architecture migration work queue Add TurboModule migration OKF bundle with work queue, implementation workflow extending change authoring, and package-extensions cross-link. --- okf-bundle/index.md | 1 + okf-bundle/new-architecture/index.md | 21 ++ .../new-architecture/migration-work-queue.md | 220 ++++++++++++++++++ .../turbomodule-implementation-workflow.md | 130 +++++++++++ .../testing/change-authoring-workflow.md | 1 + 5 files changed, 373 insertions(+) create mode 100644 okf-bundle/new-architecture/index.md create mode 100644 okf-bundle/new-architecture/migration-work-queue.md create mode 100644 okf-bundle/new-architecture/turbomodule-implementation-workflow.md diff --git a/okf-bundle/index.md b/okf-bundle/index.md index aa84bd6532..6f529d6647 100644 --- a/okf-bundle/index.md +++ b/okf-bundle/index.md @@ -24,6 +24,7 @@ okf_version: "0.1" * [Namespace API removal workflow](/namespace-api-removal-workflow.md) — modular-only migration checklist, factory design, removal greps * [Namespace API removal work queue](/namespace-api-removal-work-queue.md) — phase tracker and gate snapshots (ephemeral) +* [TurboModule migration](/new-architecture/index.md) — Codegen TurboModules, coordinated New Architecture break, phase queue # Packages diff --git a/okf-bundle/new-architecture/index.md b/okf-bundle/new-architecture/index.md new file mode 100644 index 0000000000..85e0b287b1 --- /dev/null +++ b/okf-bundle/new-architecture/index.md @@ -0,0 +1,21 @@ +# New Architecture (TurboModules) + +TurboModule migration for React Native Firebase native bridge packages. + +**Policy:** [OKF documentation and commit policy](../documentation-policy.md). + +## Documents + +* [Migration work queue](migration-work-queue.md) — ephemeral gates, phase ordering, package inventory +* [TurboModule implementation workflow](turbomodule-implementation-workflow.md) — spec/codegen/native conversion, area harness; extends [change authoring](../testing/change-authoring-workflow.md) + +## Reference implementation + +* [`packages/functions`](../../../packages/functions/) — only package migrated to TurboModules today ([PR #8603](https://github.com/invertase/react-native-firebase/pull/8603); new-arch-only from v24) + +## Related repository files + +* [`packages/app/lib/internal/registry/nativeModule.ts`](../../../packages/app/lib/internal/registry/nativeModule.ts) — `turboModule` flag, null encoding, module wrapping +* [`packages/app/lib/internal/nullSerialization.ts`](../../../packages/app/lib/internal/nullSerialization.ts) — iOS null sentinel for TurboModule object args +* [`packages/functions/specs/NativeRNFBTurboFunctions.ts`](../../../packages/functions/specs/NativeRNFBTurboFunctions.ts) — Codegen spec pattern +* [`packages/functions/package.json`](../../../packages/functions/package.json) — `codegenConfig`, committed generated output diff --git a/okf-bundle/new-architecture/migration-work-queue.md b/okf-bundle/new-architecture/migration-work-queue.md new file mode 100644 index 0000000000..69c893f391 --- /dev/null +++ b/okf-bundle/new-architecture/migration-work-queue.md @@ -0,0 +1,220 @@ +--- +type: Reference +title: TurboModule migration work queue +description: Phase tracker for migrating React Native Firebase packages from legacy NativeModules to Codegen TurboModules under a coordinated New Architecture break. +tags: [new-architecture, turbomodule, codegen, migration, work-queue] +timestamp: 2026-06-26T00:00:00Z +--- + +# TurboModule migration — work queue + +> **QUEUED (2026-06-26):** Planning document — awaiting maintainer review before implementation pickup. +> **Goal/order:** app foundation → hard probe → easy wins → remaining complex → coordinated break → EventEmitter cleanup. Links: [implementation workflow](turbomodule-implementation-workflow.md), [change authoring](../testing/change-authoring-workflow.md), [functions reference](../../../packages/functions/) ([PR #8603](https://github.com/invertase/react-native-firebase/pull/8603)). + +Ephemeral tracker; see [OKF policy](../documentation-policy.md). + +--- + +## Locked decisions + +| # | Decision | Detail | +|---|----------|--------| +| 1 | **New Architecture only** | One coordinated semver break across the monorepo. No dual old/new bridge support per package (`functions` precedent: v24). | +| 2 | **Naming** | Codegen module names use `NativeRNFBTurbo*` prefix (e.g. `NativeRNFBTurboAuth`, `NativeRNFBTurboFirestore`). | +| 3 | **Typing** | Strong Codegen types wherever the API allows. Source of truth: `packages/*/lib/types/internal.ts`, native method inventories, firebase-js-sdk shapes. Use `Object` / open maps only where payloads are genuinely dynamic. | +| 4 | **Events** | **Defer** Codegen EventEmitter cutover to [Phase C cleanup](#deferred-cleanup-phase-eventemitter) unless testing proves deferral impossible. | +| 5 | **Generated code** | Commit codegen output (`includesGeneratedCode: true`); mirror `packages/functions` layout. | +| 6 | **Module resolution** | Unified resolver in `packages/app` — `TurboModuleRegistry.get(name)` with `NativeModules` fallback during transition. | + +Implementation steps, harness, and commit rules: [turbomodule implementation workflow](turbomodule-implementation-workflow.md) — do not restate here. + +--- + +## Resume checklist + +Gate prerequisites before any `:test-cover` ([host rule](../testing/change-authoring-workflow.md#host-rule)): + +1. [Pre-flight](../testing/running-e2e.md#pre-flight-is-the-host-clear-to-start): [host-clear probes](../testing/running-e2e.md#host-clear-probes), [services ready](../testing/running-e2e.md#2-services-ready), [harness matches validation tier](../testing/running-e2e.md#3-harness-matches-validation-tier) ([narrowing gate](../testing/running-e2e.md#harness-narrowing-gate-blocking) — required for **unit-focused** and **area-focused**; not [push harness](#harness)); [serial `:test-cover`](../testing/running-e2e.md#serialized-e2e-dispatch); [frozen tree](../testing/change-authoring-workflow.md#frozen-tree) for `independent-review`. +2. New Architecture enabled on dev host / emulator for native bridge work. +3. Per-package protocol: [Phase iteration protocol](#phase-iteration-protocol) below. + +--- + +## What changes vs what stays + +| Layer | Stays | Changes | +|-------|-------|---------| +| JS product API | `namespaced.ts`, `modular.ts`, web shims, `FirebaseModule` subclasses, arg prepending | `nativeModuleName` → `NativeRNFBTurbo*`; `turboModule: true` | +| Events (Phases 0–5) | Compile-time event names, `SharedEventEmitter` fan-out, `nativeEvents` | Native emitters unchanged — see [Phase C](#deferred-cleanup-phase-eventemitter) | +| Native | Firebase SDK integration, business logic | Extend generated `*Spec`; iOS `getTurboModule()`; podspec new-arch guard | +| Release | Per-package semver today | **One coordinated major** when Phases 0–5 complete | + +--- + +## Reference pattern (`functions`) + +Brief index — full checklist: [turbomodule implementation workflow](turbomodule-implementation-workflow.md). + +Each migrated package repeats the [`functions`](../../../packages/functions/) shape: `specs/NativeRNFBTurbo*.ts` → `codegenConfig` + committed generated output → Android `NativeRNFBTurbo*` / iOS spec + `getTurboModule()` → JS `turboModule: true`. + +**Phase 0 still required:** unified module resolver; flip `getAppModule()` turbo TODO in [`nativeModule.ts`](../../../packages/app/lib/internal/registry/nativeModule.ts). + +--- + +## Deferred cleanup phase (EventEmitter) + +Follow-on **after** Phases 0–5 and coordinated break. Not in scope unless testing blocks deferral. + +| Topic | Current | Cleanup target | +|-------|---------|----------------| +| Event subscription | `RNFBNativeEventEmitter` + `RNFBAppModule` proxy | Codegen TurboModule events or RN New Architecture event emitters | +| Native emit | `RNFBRCTEventEmitter` / `ReactNativeFirebaseEventEmitter` | Align with chosen Codegen event pattern | +| JS fan-out | Fixed `nativeEvents` + `SharedEventEmitter` prefixes | Re-evaluate once native side supports typed events | + +**Deferral discriminator:** if **area-focused** e2e or device testing shows TurboModule migration **cannot** work with the legacy event proxy, escalate that package's event path into the active migration PR — do not wait for Phase C. + +--- + +## Package inventory + +### No native bridge (out of scope) + +| Package | Notes | +|---------|-------| +| `@react-native-firebase/ai` | Pure JS | +| `@react-native-firebase/vertexai` | Re-export over `ai` | + +### Already migrated + +| Package | TurboModule(s) | Status | +|---------|----------------|--------| +| `@react-native-firebase/functions` | `NativeRNFBTurboFunctions` | ✅ reference | + +### Native packages — complexity summary + +Android `@ReactMethod` counts approximate spec surface area. Multi-module: **one spec per legacy module** ([workflow § multi-module](turbomodule-implementation-workflow.md#multi-module-packages)). + +#### Multi-module (Tier A) + +| Package | Legacy modules | Events | Methods ≈ | Notes | +|---------|----------------|--------|-----------|-------| +| **database** | 5 modules (`RNFBDatabase*`) | 2 | ~22 | Transaction + sync listeners | +| **firestore** | 4 modules (`RNFBFirestore*`) | 4 | ~31 | Pipelines via `pipelineExecute`; listener IDs | + +#### Single-module, high complexity (Tier B) + +| Package | Legacy module | Events | Methods ≈ | Notes | +|---------|---------------|--------|-----------|-------| +| **auth** | `RNFBAuthModule` | 3 | **59** | Largest single spec | +| **messaging** | `RNFBMessagingModule` | 5–7 | 11 | Platform-conditional events; background iOS | + +#### Single-module, moderate (Tier C) + +| Package | Legacy module | Events | Methods ≈ | +|---------|---------------|--------|-----------| +| **storage** | `RNFBStorageModule` | 1 | 14 | +| **crashlytics** | `RNFBCrashlyticsModule` | 0 | 14 | +| **analytics** | `RNFBAnalyticsModule` | 0 | 11 | +| **remote-config** | `RNFBConfigModule` | 1 | 11 | +| **app-check** | `RNFBAppCheckModule` | 1 | 7 | +| **perf** | `RNFBPerfModule` | 0 | 7 | + +#### Single-module, simple (Tier D) + +| Package | Legacy module | Events | Methods ≈ | Notes | +|---------|---------------|--------|-----------|-------| +| **installations** | `RNFBInstallationsModule` | 0 | 3 | Smallest | +| **in-app-messaging** | `RNFBFiamModule` | 0 | 3 | | +| **app-distribution** | `RNFBAppDistributionModule` | 0 | 4 | | +| **ml** | `RNFBMLModule` | 0 | ~0 | Stub | +| **phone-number-verification** | `RNFBPnvModule` | 0 | 6 | Android-only; direct resolver | + +#### Foundation (Phase 0) + +| Package | Legacy modules | Notes | +|---------|----------------|-------| +| **app** | `RNFBAppModule`, `RNFBUtilsModule` (+ Android utils) | Event proxy; **blocker** for migration complete | + +--- + +## Phase ordering + +Strategy: **foundation → hard probe → easy wins → remaining complex → coordinated break → cleanup**. + +Pick **one** of `firestore` or `auth` in Phase 1 (firestore = multi-module + pipelines; auth = max single-module spec). + +### Phase table + +| Phase | Focus | Status | Packages | +|-------|--------|--------|----------| +| **0** | App foundation + unified resolver | queued | `app` | +| **1** | Hard probe | queued | `firestore` **or** `auth` — pick one | +| **2** | Easy wins | queued | `installations`, `perf`, `in-app-messaging`, `app-distribution`, `ml` | +| **3** | Moderate | queued | `app-check`, `remote-config`, `analytics`, `crashlytics`, `storage` | +| **4** | Remaining complex | queued | other Tier A/B + `messaging`, `database` | +| **5** | Android-only / misc | queued | `phone-number-verification` | +| **R** | Pre-merge full validation | queued | Revert harness narrowing; [full tier](../testing/running-e2e.md#e2e-validation-tiers-unit-focused-area-focused-full) 3-platform before coordinated major | +| **C** | EventEmitter cleanup | deferred | All — [§ deferred cleanup](#deferred-cleanup-phase-eventemitter) | + +**Coordinated break:** consumer-facing major when Phases 0–5 + **R** complete (`functions` already new-arch-only). + +--- + +## Phase iteration protocol + +Each package (or one legacy module within a multi-module package) follows **one** serial loop. No overlap. Work types: [change authoring workflow § work types](../testing/change-authoring-workflow.md#work-types). + +| Step | Work type | Closes gate | Rules | +|------|-----------|-------------|-------| +| **1** | `gap-analysis` | — | Spec inventory + feasibility; read-only when export shape unclear | +| **2** | `baseline-capture` | — | Optional area-focused e2e baseline before large packages | +| **3** | `implementation` | `implementation` | Spec, codegen, native, JS; Jest + **unit-focused** tier; `.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 | + +Canonical commands: [validation checklist](../testing/validation-checklist.md), [serialized dispatch](../testing/running-e2e.md#serialized-e2e-dispatch). + +Skip steps 1–2 when spec shape is known (most Tier D packages). + +--- + +## Current snapshot + +**Label:** `planning`; **harness:** not started + +**Next item:** Maintainer review of this queue + [implementation workflow](turbomodule-implementation-workflow.md) → Phase **0** pickup. + +**Arbiter gate:** + + +| Item | Code | `implementation_gate` | `review_gate` | `next_work_type` | `validation_tier` | Notes | +|------|------|----------------------|---------------|------------------|-------------------|-------| +| Phase 0 `app` | — | — | — | — | — | blocked on queue approval | + +--- + +## Harness + +- **Push state (committed):** full test app — all `platformSupportedModules` + `require.context` in `tests/app.js`. For CI / Phase **R** only. +- **Local `:test-cover`:** must match arbiter `validation_tier` — [running e2e § harness + narrowing gate](../testing/running-e2e.md#harness-narrowing-gate-blocking). **`implementation` → unit-focused** and **`independent-review` → area-focused:** both require [area narrowing](turbomodule-implementation-workflow.md#turbomodule-area-harness) locally **before** first run even when git has full harness. Revert before **R** (full tier). + +--- + +## Workflow (each phase) + +1. Pick package(s) for the phase from [phase table](#phase-table). +2. Follow [Phase iteration protocol](#phase-iteration-protocol) — never commit before `review_gate` closed; never overlap `:test-cover` ([host rule](../testing/change-authoring-workflow.md#host-rule)). +3. Update arbiter gate row when item closes. +4. Phase **R:** `pre-merge-validation` at **full** tier before coordinated major. + +**Pitfalls:** iOS null-in-object on option maps ([workflow § gotchas](turbomodule-implementation-workflow.md#gotchas)); New Architecture must be enabled; do not combine language modernization (Kotlin/Swift) with bridge migration in the same PR. + +--- + +## Related links + +* [New Architecture index](index.md) +* [TurboModule implementation workflow](turbomodule-implementation-workflow.md) +* [Change authoring workflow](../testing/change-authoring-workflow.md) +* [Documentation policy](../documentation-policy.md) diff --git a/okf-bundle/new-architecture/turbomodule-implementation-workflow.md b/okf-bundle/new-architecture/turbomodule-implementation-workflow.md new file mode 100644 index 0000000000..ccda2608e3 --- /dev/null +++ b/okf-bundle/new-architecture/turbomodule-implementation-workflow.md @@ -0,0 +1,130 @@ +--- +type: Reference +title: TurboModule migration implementation workflow +description: New Architecture–specific artifacts for Codegen specs, native module conversion, area harness setup, and coordinated break validation — extends the cross-package change authoring workflow. +tags: [new-architecture, turbomodule, codegen, workflow, migration] +timestamp: 2026-06-26T00:00:00Z +--- + +# TurboModule migration implementation workflow + +Requirements for migrating **one package** (or one legacy native module within a multi-module package) from legacy `NativeModules` to Codegen TurboModules. **Shared loop:** [change authoring workflow](../testing/change-authoring-workflow.md). + +**Policy:** [OKF documentation and commit policy](../documentation-policy.md). + +## Read first + +| Topic | Document | +|-------|----------| +| **Change authoring loop** | [change-authoring-workflow.md](../testing/change-authoring-workflow.md) | +| Live phase/gate snapshots | [migration-work-queue.md](migration-work-queue.md) | +| Locked decisions, inventory, phase order | [migration-work-queue.md](migration-work-queue.md) | +| Work types, tiers, gates | [change-authoring-workflow.md](../testing/change-authoring-workflow.md); term ids: [iteration-vocabulary.md](../testing/iteration-vocabulary.md) | +| E2e commands | [running-e2e.md](../testing/running-e2e.md) | +| Validation commands | [validation-checklist.md](../testing/validation-checklist.md) | +| Reference implementation | [`packages/functions`](../../../packages/functions/) ([PR #8603](https://github.com/invertase/react-native-firebase/pull/8603)) | + +## TurboModule hard gates + +In addition to [change authoring gates](../testing/change-authoring-workflow.md#gates): + +| Gate | Requirement | +|------|-------------| +| Spec inventory | Native methods inventoried from Java/ObjC; mapped to typed spec using `packages//lib/types/internal.ts` where available | +| Codegen | `specs/NativeRNFBTurbo*.ts` + `codegenConfig`; generated android/ios artifacts **committed** (`includesGeneratedCode: true`) | +| Native shell | Android `NativeRNFBTurbo*` extends generated `*Spec`; iOS spec protocol + `getTurboModule()` | +| JS wiring | `nativeModuleName` → `NativeRNFBTurbo*`; `turboModule: true`; web shims via `setReactNativeModule` unchanged | +| Podspec / package | New-arch guard; exclude duplicate RN generated providers (see [`RNFBFunctions.podspec`](../../../packages/functions/RNFBFunctions.podspec)) | +| Implementation | Package Jest + **unit-focused** e2e on New Architecture build | +| Review | Package e2e **area-focused** tier on frozen tree; no `.only`; native lint rows from [validation checklist](../testing/validation-checklist.md) where touched | +| Event deferral | Legacy event proxy retained unless [queue deferral discriminator](migration-work-queue.md#deferred-cleanup-phase-eventemitter) triggers escalation | + +### Multi-module packages + +One TurboModule spec **per legacy native module** — do not consolidate in the first pass (database ×5, firestore ×4). One focused commit per spec/module when gates close, or one commit per package when the whole package converts in a single PR — follow queue phase boundaries. + +## Spec authoring (`gap-analysis` / pre-`implementation`) + +1. Inventory `@ReactMethod` / `RCT_EXPORT_METHOD` from existing Java/ObjC sources. +2. Draft `specs/NativeRNFBTurbo*.ts` — strong types from `lib/types/internal.ts` and firebase-js-sdk shapes; `Object` / open maps only for genuinely dynamic payloads. +3. Naming: `NativeRNFBTurbo*` prefix (locked decision — [migration work queue § locked decisions](migration-work-queue.md#locked-decisions)). +4. Run `yarn codegen` in the package; commit generated output under `android/.../generated` and `ios/generated`. +5. For Phase 0 (`app`): include unified module resolver work in `packages/app` ([queue § reference pattern](migration-work-queue.md#reference-pattern-functions)). + +## TurboModule `implementation` + +Per package, repeat the [`functions`](../../../packages/functions/) shape: + +1. **`specs/NativeRNFBTurbo*.ts`** — extends `TurboModule`. +2. **`package.json` `codegenConfig`** — `jsSrcsDir: "specs"`, android `javaPackageName`, ios `modulesProvider`. +3. **Android** — `NativeRNFBTurbo*` extends generated `*Spec`; register in package class. +4. **iOS** — `.mm` implements spec; `- (std::shared_ptr)getTurboModule:` returns generated JSI class. +5. **JS** — update namespace config; no public API changes unless unavoidable. +6. **Native business logic** — prefer keeping ObjC++/Java shell + existing Swift helpers; language modernization is out of scope ([queue rationale](migration-work-queue.md#reference-pattern-functions)). + +**Unit-focused** tier per [change authoring § implementation inner loop](../testing/change-authoring-workflow.md#implementation-inner-loop) and [TurboModule area harness](#turbomodule-area-harness) below. + +Shared infrastructure (already landed for `functions`): + +* [`packages/app/lib/internal/registry/nativeModule.ts`](../../../packages/app/lib/internal/registry/nativeModule.ts) — `turboModule` flag, iOS null encoding +* [`packages/app/lib/internal/nullSerialization.ts`](../../../packages/app/lib/internal/nullSerialization.ts) + native interceptor + +## TurboModule `independent-review` + +On a **frozen tree** — full [change authoring § independent-review](../testing/change-authoring-workflow.md#independent-review), plus: + +* New Architecture build on each touched platform (native bridge change). +* Package e2e at **area-focused** tier with [area harness](#turbomodule-area-harness) applied locally before first `:test-cover`. +* iOS: exercise null-in-object payloads where the package passes option maps ([RN #52802](https://github.com/facebook/react-native/issues/52802)) — highest risk: `auth`, `firestore`, `database`, `storage`. + +## TurboModule area harness + +Extends [change authoring § harness narrowing](../testing/change-authoring-workflow.md#harness-narrowing). + +**Area setup (required for `unit-focused` and `area-focused` tiers):** narrow `tests/app.js` / `tests/globals.js` to the package under migration — load only that package's `platformSupportedModules` entry and its `packages//e2e/*.e2e.js` specs. + +| Package | Typical e2e entry | +|---------|-------------------| +| `app` | `packages/app/e2e/` | +| `auth` | `packages/auth/e2e/` | +| `firestore` | `packages/firestore/e2e/` (may coexist with Pipeline specs — load package module only) | +| `functions` | `packages/functions/e2e/` (reference; already migrated) | +| Others | `packages//e2e/` | + +**Sanity check:** pass counts must match loaded scope — not full-app totals ([running e2e § gate](../testing/running-e2e.md#harness-narrowing-gate-blocking)). + +**Push state (committed):** full test app remains default for CI. Local `:test-cover` during migration uses area narrowing even when git has full harness. + +**Phase R / coordinated break:** revert all narrowing; **full** tier 3-platform run before monorepo major ships ([change authoring § pre-merge-validation](../testing/change-authoring-workflow.md#work-types)). + +## TurboModule `documentation` + +Per package (or per phase batch), same commit when user-facing: + +**User docs** + +* Migration guide update for coordinated New Architecture break (final phase only unless package already ships new-arch-only like `functions`) +* Package install notes if podspec/build requirements change + +**OKF bundle maintenance** + +* Update [migration work queue](migration-work-queue.md) gate rows when items close +* Record non-obvious codegen or null-serialization choices here or in queue historical notes — not only commit messages + +## TurboModule `commit` + +```text +feat(): migrate to TurboModules +``` + +**Never stage:** area narrowing in `tests/app.js` / `tests/globals.js`, any `.only`. + +## Gotchas + +* **New Architecture only** — no dual old/new bridge; podspec old-arch guard like [`RNFBFunctions.podspec`](../../../packages/functions/RNFBFunctions.podspec). +* **Events deferred** — keep `RNFBRCTEventEmitter` / `nativeEvents` fan-out unless testing forces escalation ([queue § deferred cleanup](migration-work-queue.md#deferred-cleanup-phase-eventemitter)). +* **Swift / ObjC interop** — TurboModule shell stays ObjC++; follow functions podspec patterns for `use_frameworks!` and non-framework builds. +* **Unified resolver** — Phase 0 adds `TurboModuleRegistry.get` with `NativeModules` fallback in `packages/app`; turbo-only packages drop fallback once migrated. +* **phone-number-verification** — bypasses `createModuleNamespace`; wire spec + resolver directly in `modular.ts`. + +Live phase status and arbiter gates: [migration work queue](migration-work-queue.md) (ephemeral). diff --git a/okf-bundle/testing/change-authoring-workflow.md b/okf-bundle/testing/change-authoring-workflow.md index 3314913b42..14d957493a 100644 --- a/okf-bundle/testing/change-authoring-workflow.md +++ b/okf-bundle/testing/change-authoring-workflow.md @@ -203,6 +203,7 @@ rg '\.only\(' packages/ | Package / area | Adds to this loop | |----------------|-------------------| | Firestore Pipelines | Compare-types gap pick, serialization matrix, `Pipeline.e2e.js` setup, coverage snapshots — [pipeline implementation workflow](../packages/firestore/pipeline-implementation-workflow.md) | +| TurboModule migration | Spec inventory, codegen commit, New Architecture harness, multi-module spec split — [turbomodule implementation workflow](../new-architecture/turbomodule-implementation-workflow.md) | | Other packages | `okf-bundle/packages//` index when a workflow exists | Ephemeral coordination (gate rows, `next_work_type`, `commit_subject`): **work queues only** — not part of this workflow. From e6f008da9d154839306d9d7050bd1f6c2727271e Mon Sep 17 00:00:00 2001 From: Mike Hardy Date: Tue, 30 Jun 2026 12:05:41 -0500 Subject: [PATCH 02/10] feat(app)!: migrate app modules to TurboModules incl general migration infra BREAKING CHANGE: App/Core modules native bridge requires New Architecture. Migrate RNFBAppModule and RNFBUtilsModule to Codegen TurboModules with unified resolver, lazy Proxy wrapper, and committed generated artifacts. Includes functions codegenConfig rename (NewArch-AD-7), test harness overrides, architecture decisions, and validation workflow hardening. --- .gitignore | 2 + jest.setup.ts | 73 +++ okf-bundle/ci-workflows/ios.md | 2 + .../namespace-api-removal-work-queue.md | 2 +- okf-bundle/namespace-api-removal-workflow.md | 2 +- .../architecture-decisions.md | 290 +++++++++ okf-bundle/new-architecture/index.md | 4 +- .../new-architecture/migration-work-queue.md | 137 +++- .../turbomodule-implementation-workflow.md | 84 ++- .../pipeline-implementation-workflow.md | 2 +- okf-bundle/testing/agent-command-policy.md | 4 +- .../testing/change-authoring-workflow.md | 12 +- okf-bundle/testing/running-e2e.md | 187 +++--- okf-bundle/testing/validation-checklist.md | 5 +- package.json | 1 + packages/app/RNFBApp.podspec | 20 +- .../__tests__/nativeModuleContract.test.ts | 112 ++++ packages/app/android/build.gradle | 17 +- .../firebase/app/NativeRNFBTurboApp.java | 188 ++++++ .../app/ReactNativeFirebaseAppModule.java | 10 +- .../app/ReactNativeFirebaseAppPackage.java | 6 +- .../fbreact/specs/NativeRNFBTurboAppSpec.java | 136 ++++ .../specs/NativeRNFBTurboUtilsSpec.java | 94 +++ .../firebase/app/generated/jni/CMakeLists.txt | 36 ++ .../jni/RNFBAppTurboModules-generated.cpp | 170 +++++ .../app/generated/jni/RNFBAppTurboModules.h | 39 ++ .../RNFBAppTurboModulesJSI-generated.cpp | 187 ++++++ .../RNFBAppTurboModulesJSI.h | 606 ++++++++++++++++++ .../firebase/common/RCTConvertFirebase.java | 6 +- .../firebase/utils/NativeRNFBTurboUtils.java | 184 ++++++ packages/app/e2e/events.e2e.js | 8 +- .../app/ios/RNFBApp.xcodeproj/project.pbxproj | 16 +- packages/app/ios/RNFBApp/RNFBAppModule.h | 4 +- .../{RNFBAppModule.m => RNFBAppModule.mm} | 151 +++-- packages/app/ios/RNFBApp/RNFBUtilsModule.h | 4 +- .../{RNFBUtilsModule.m => RNFBUtilsModule.mm} | 93 ++- .../ios/generated/RCTAppDependencyProvider.h | 25 + .../ios/generated/RCTAppDependencyProvider.mm | 40 ++ .../app/ios/generated/RCTModuleProviders.h | 16 + .../app/ios/generated/RCTModuleProviders.mm | 52 ++ .../RCTModulesConformingToProtocolsProvider.h | 18 + ...RCTModulesConformingToProtocolsProvider.mm | 54 ++ .../RCTThirdPartyComponentsProvider.h | 16 + .../RCTThirdPartyComponentsProvider.mm | 30 + ...leModulesRequiringMainQueueSetupProvider.h | 14 + ...eModulesRequiringMainQueueSetupProvider.mm | 19 + .../RNFBAppTurboModules-generated.mm | 210 ++++++ .../RNFBAppTurboModules/RNFBAppTurboModules.h | 384 +++++++++++ .../RNFBAppTurboModulesJSI-generated.cpp | 187 ++++++ .../ios/generated/RNFBAppTurboModulesJSI.h | 606 ++++++++++++++++++ .../ReactAppDependencyProvider.podspec | 34 + .../app/ios/generated/ReactCodegen.podspec | 111 ++++ .../lib/internal/RNFBNativeEventEmitter.ts | 18 +- packages/app/lib/internal/constants.ts | 4 +- .../lib/internal/nativeModuleAndroidIos.ts | 66 +- packages/app/lib/internal/nativeModuleWeb.ts | 16 +- packages/app/lib/internal/registry/app.ts | 21 +- .../app/lib/internal/registry/nativeModule.ts | 213 +++--- packages/app/lib/modular.ts | 34 +- packages/app/lib/utils/UtilsStatics.ts | 4 +- packages/app/lib/utils/index.ts | 7 +- packages/app/package.json | 18 + packages/app/react-native.config.js | 2 + packages/app/specs/NativeRNFBTurboApp.ts | 57 ++ packages/app/specs/NativeRNFBTurboUtils.ts | 34 + packages/app/type-test.ts | 9 +- .../auth/ReactNativeFirebaseAuthModule.java | 4 +- .../functions/generated/jni/CMakeLists.txt | 10 +- ...> RNFBFunctionsTurboModules-generated.cpp} | 4 +- ...unctions.h => RNFBFunctionsTurboModules.h} | 2 +- ...NFBFunctionsTurboModulesJSI-generated.cpp} | 2 +- .../RNFBFunctionsTurboModulesJSI.h} | 0 .../ios/RNFBFunctions/RNFBFunctionsModule.h | 2 +- .../ios/RNFBFunctions/RNFBFunctionsModule.mm | 2 +- .../RNFBFunctionsTurboModules-generated.mm} | 8 +- .../RNFBFunctionsTurboModules.h} | 40 +- ...NFBFunctionsTurboModulesJSI-generated.cpp} | 2 +- ...nsJSI.h => RNFBFunctionsTurboModulesJSI.h} | 0 packages/functions/package.json | 2 +- packages/messaging/lib/index.ts | 11 +- packages/messaging/type-test.ts | 22 +- tests/app.js | 12 + tests/e2e/firebase.test.js | 83 ++- tests/globals.js | 12 +- tests/harness.overrides.example.js | 24 + tests/ios/Podfile.lock | 84 +-- 86 files changed, 4979 insertions(+), 560 deletions(-) create mode 100644 okf-bundle/new-architecture/architecture-decisions.md create mode 100644 packages/app/__tests__/nativeModuleContract.test.ts create mode 100644 packages/app/android/src/reactnative/java/io/invertase/firebase/app/NativeRNFBTurboApp.java create mode 100644 packages/app/android/src/reactnative/java/io/invertase/firebase/app/generated/java/com/facebook/fbreact/specs/NativeRNFBTurboAppSpec.java create mode 100644 packages/app/android/src/reactnative/java/io/invertase/firebase/app/generated/java/com/facebook/fbreact/specs/NativeRNFBTurboUtilsSpec.java create mode 100644 packages/app/android/src/reactnative/java/io/invertase/firebase/app/generated/jni/CMakeLists.txt create mode 100644 packages/app/android/src/reactnative/java/io/invertase/firebase/app/generated/jni/RNFBAppTurboModules-generated.cpp create mode 100644 packages/app/android/src/reactnative/java/io/invertase/firebase/app/generated/jni/RNFBAppTurboModules.h create mode 100644 packages/app/android/src/reactnative/java/io/invertase/firebase/app/generated/jni/react/renderer/components/RNFBAppTurboModules/RNFBAppTurboModulesJSI-generated.cpp create mode 100644 packages/app/android/src/reactnative/java/io/invertase/firebase/app/generated/jni/react/renderer/components/RNFBAppTurboModules/RNFBAppTurboModulesJSI.h create mode 100644 packages/app/android/src/reactnative/java/io/invertase/firebase/utils/NativeRNFBTurboUtils.java rename packages/app/ios/RNFBApp/{RNFBAppModule.m => RNFBAppModule.mm} (68%) rename packages/app/ios/RNFBApp/{RNFBUtilsModule.m => RNFBUtilsModule.mm} (66%) create mode 100644 packages/app/ios/generated/RCTAppDependencyProvider.h create mode 100644 packages/app/ios/generated/RCTAppDependencyProvider.mm create mode 100644 packages/app/ios/generated/RCTModuleProviders.h create mode 100644 packages/app/ios/generated/RCTModuleProviders.mm create mode 100644 packages/app/ios/generated/RCTModulesConformingToProtocolsProvider.h create mode 100644 packages/app/ios/generated/RCTModulesConformingToProtocolsProvider.mm create mode 100644 packages/app/ios/generated/RCTThirdPartyComponentsProvider.h create mode 100644 packages/app/ios/generated/RCTThirdPartyComponentsProvider.mm create mode 100644 packages/app/ios/generated/RCTUnstableModulesRequiringMainQueueSetupProvider.h create mode 100644 packages/app/ios/generated/RCTUnstableModulesRequiringMainQueueSetupProvider.mm create mode 100644 packages/app/ios/generated/RNFBAppTurboModules/RNFBAppTurboModules-generated.mm create mode 100644 packages/app/ios/generated/RNFBAppTurboModules/RNFBAppTurboModules.h create mode 100644 packages/app/ios/generated/RNFBAppTurboModulesJSI-generated.cpp create mode 100644 packages/app/ios/generated/RNFBAppTurboModulesJSI.h create mode 100644 packages/app/ios/generated/ReactAppDependencyProvider.podspec create mode 100644 packages/app/ios/generated/ReactCodegen.podspec create mode 100644 packages/app/specs/NativeRNFBTurboApp.ts create mode 100644 packages/app/specs/NativeRNFBTurboUtils.ts rename packages/functions/android/src/main/java/io/invertase/firebase/functions/generated/jni/{NativeRNFBTurboFunctions-generated.cpp => RNFBFunctionsTurboModules-generated.cpp} (95%) rename packages/functions/android/src/main/java/io/invertase/firebase/functions/generated/jni/{NativeRNFBTurboFunctions.h => RNFBFunctionsTurboModules.h} (83%) rename packages/functions/{ios/generated/NativeRNFBTurboFunctionsJSI-generated.cpp => android/src/main/java/io/invertase/firebase/functions/generated/jni/react/renderer/components/RNFBFunctionsTurboModules/RNFBFunctionsTurboModulesJSI-generated.cpp} (99%) rename packages/functions/android/src/main/java/io/invertase/firebase/functions/generated/jni/react/renderer/components/{NativeRNFBTurboFunctions/NativeRNFBTurboFunctionsJSI.h => RNFBFunctionsTurboModules/RNFBFunctionsTurboModulesJSI.h} (100%) rename packages/functions/ios/generated/{NativeRNFBTurboFunctions/NativeRNFBTurboFunctions-generated.mm => RNFBFunctionsTurboModules/RNFBFunctionsTurboModules-generated.mm} (94%) rename packages/functions/ios/generated/{NativeRNFBTurboFunctions/NativeRNFBTurboFunctions.h => RNFBFunctionsTurboModules/RNFBFunctionsTurboModules.h} (87%) rename packages/functions/{android/src/main/java/io/invertase/firebase/functions/generated/jni/react/renderer/components/NativeRNFBTurboFunctions/NativeRNFBTurboFunctionsJSI-generated.cpp => ios/generated/RNFBFunctionsTurboModulesJSI-generated.cpp} (99%) rename packages/functions/ios/generated/{NativeRNFBTurboFunctionsJSI.h => RNFBFunctionsTurboModulesJSI.h} (100%) create mode 100644 tests/harness.overrides.example.js diff --git a/.gitignore b/.gitignore index c405f67dec..c02aed9a24 100644 --- a/.gitignore +++ b/.gitignore @@ -547,6 +547,8 @@ tests/ios/resetXcode.sh google-services.json GoogleService-Info.plist +tests/harness.overrides.js + # generated files RNFBVersion.m ReactNativeFirebaseVersion.java diff --git a/jest.setup.ts b/jest.setup.ts index 42f68e2e86..1c5370b83f 100644 --- a/jest.setup.ts +++ b/jest.setup.ts @@ -32,6 +32,12 @@ jest.doMock('react-native', () => { OS: 'android', select: () => {}, }, + TurboModuleRegistry: { + get: jest.fn(() => undefined), + getEnforcing: jest.fn(() => { + throw new Error('TurboModuleRegistry.getEnforcing: module not found'); + }), + }, AppRegistry: { registerHeadlessTask: jest.fn(), }, @@ -54,6 +60,73 @@ jest.doMock('react-native', () => { initiateOnDeviceConversionMeasurementWithPhoneNumber: jest.fn(), initiateOnDeviceConversionMeasurementWithHashedPhoneNumber: jest.fn(), }, + NativeRNFBTurboApp: { + getConstants: () => ({ + NATIVE_FIREBASE_APPS: [ + { + appConfig: { + name: '[DEFAULT]', + }, + options: {}, + }, + { + appConfig: { + name: 'secondaryFromNative', + }, + options: {}, + }, + ], + FIREBASE_RAW_JSON: '{}', + }), + NATIVE_FIREBASE_APPS: [ + { + appConfig: { + name: '[DEFAULT]', + }, + options: {}, + }, + + { + appConfig: { + name: 'secondaryFromNative', + }, + options: {}, + }, + ], + FIREBASE_RAW_JSON: '{}', + addListener: jest.fn(), + eventsAddListener: jest.fn(), + eventsNotifyReady: jest.fn(), + removeListeners: jest.fn(), + }, + NativeRNFBTurboUtils: { + getConstants: () => ({ + isRunningInTestLab: false, + MAIN_BUNDLE: '/', + CACHES_DIRECTORY: '/cache', + DOCUMENT_DIRECTORY: '/documents', + TEMP_DIRECTORY: '/tmp', + LIBRARY_DIRECTORY: '/library', + PICTURES_DIRECTORY: '/pictures', + MOVIES_DIRECTORY: '/movies', + }), + isRunningInTestLab: false, + MAIN_BUNDLE: '/', + CACHES_DIRECTORY: '/cache', + DOCUMENT_DIRECTORY: '/documents', + TEMP_DIRECTORY: '/tmp', + LIBRARY_DIRECTORY: '/library', + PICTURES_DIRECTORY: '/pictures', + MOVIES_DIRECTORY: '/movies', + androidGetPlayServicesStatus: jest.fn(() => + Promise.resolve({ + isAvailable: true, + status: 0, + hasResolution: false, + isUserResolvableError: false, + }), + ), + }, RNFBAppModule: { NATIVE_FIREBASE_APPS: [ { diff --git a/okf-bundle/ci-workflows/ios.md b/okf-bundle/ci-workflows/ios.md index 4b308a84cd..ffbc581e73 100644 --- a/okf-bundle/ci-workflows/ios.md +++ b/okf-bundle/ci-workflows/ios.md @@ -150,6 +150,8 @@ Long `datamigrator` activity with no `com.invertase.testing` means migration/pre Device type comes from `tests/.detoxrc.js`; boot script and Detox use it. No hard-coded UDID. +**Missing Detox framework cache** — if iOS `:test-cover` fails before tests with `Detox.framework could not be found`, rebuild the local cache: [running e2e § iOS Detox framework cache](../testing/running-e2e.md#ios-detox-framework-cache-blocking) (`yarn tests:ios:detox-framework-cache:rebuild`). CI restores `~/Library/Detox/ios` from Actions cache keyed by Xcode version. + ### Codecov (debug matrix only) Debug leg: `yarn tests:ios:test:process-coverage` + Codecov flags `e2e-ts-ios`, `ios-native`; `codecov/project/ios-native` blocks on missing native upload. Release skips coverage. diff --git a/okf-bundle/namespace-api-removal-work-queue.md b/okf-bundle/namespace-api-removal-work-queue.md index 986b260f3b..e468d7d6e2 100644 --- a/okf-bundle/namespace-api-removal-work-queue.md +++ b/okf-bundle/namespace-api-removal-work-queue.md @@ -40,7 +40,7 @@ Ephemeral tracker; see [OKF policy](documentation-policy.md). Work types / tiers Gate prerequisites before any `:test-cover` ([host rule](testing/change-authoring-workflow.md#host-rule)): -1. [Pre-flight](testing/running-e2e.md#pre-flight-is-the-host-clear-to-start): [host-clear probes](testing/running-e2e.md#host-clear-probes), [services ready](testing/running-e2e.md#2-services-ready), [harness matches validation tier](testing/running-e2e.md#3-harness-matches-validation-tier) — [area harness: both platform blocks](testing/running-e2e.md#tests-app-js-area-harness); [narrowing gate](testing/running-e2e.md#harness-narrowing-gate-blocking) — **unit-focused** and **area-focused** only); [serial `:test-cover`](testing/running-e2e.md#serialized-e2e-dispatch); [frozen tree](testing/change-authoring-workflow.md#frozen-tree) for `independent-review`. +1. [Pre-flight](testing/running-e2e.md#pre-flight-is-the-host-clear-to-start): [host-clear probes](testing/running-e2e.md#host-clear-probes), [services ready](testing/running-e2e.md#2-services-ready), [harness matches validation tier](testing/running-e2e.md#3-harness-matches-validation-tier) — [local harness overrides](testing/running-e2e.md#local-harness-overrides-harnessoverridesjs); [narrowing gate](testing/running-e2e.md#harness-narrowing-gate-blocking) — **unit-focused** and **area-focused** only); [serial `:test-cover`](testing/running-e2e.md#serialized-e2e-dispatch); [frozen tree](testing/change-authoring-workflow.md#frozen-tree) for `independent-review`. 2. Per-module checklist and removal greps: [namespace-api-removal-workflow.md](namespace-api-removal-workflow.md). User-facing namespace removal: [Migrating to v26](/migrating-to-v26). --- diff --git a/okf-bundle/namespace-api-removal-workflow.md b/okf-bundle/namespace-api-removal-workflow.md index 66ec79aadb..95bd6d9ba4 100644 --- a/okf-bundle/namespace-api-removal-workflow.md +++ b/okf-bundle/namespace-api-removal-workflow.md @@ -94,7 +94,7 @@ On a **frozen tree** — [change authoring § independent-review](testing/change ## Module area harness -Extends [change authoring § harness narrowing](testing/change-authoring-workflow.md#harness-narrowing). **Mechanics:** [running e2e § area harness — two platform blocks](testing/running-e2e.md#tests-app-js-area-harness). +Extends [change authoring § harness narrowing](testing/change-authoring-workflow.md#harness-narrowing). **Mechanics:** [running e2e § local harness overrides](testing/running-e2e.md#local-harness-overrides-harnessoverridesjs). When native e2e runs: load **only** the target package's e2e spec(s) in `tests/app.js`. Narrow **`platformSupportedModules` on both** `if (Platform.other)` and `if (!Platform.other)` (recommended: Pattern A — initial array + `if (false && …)` on **both** blocks). Set **`RNFBDebug = true`** locally per [running e2e § fail-fast](testing/running-e2e.md#fail-fast-rnfbdebug-and-sub-suite-narrowing) — **never commit** (`false` is the committed default). Revert **both** blocks before `commit` or **full** tier. Pass counts must match loaded scope — not full-app totals ([running e2e § gate](testing/running-e2e.md#harness-narrowing-gate-blocking), [platform coverage gate](testing/running-e2e.md#platform-coverage-gate-blocking)). diff --git a/okf-bundle/new-architecture/architecture-decisions.md b/okf-bundle/new-architecture/architecture-decisions.md new file mode 100644 index 0000000000..09bfaa7542 --- /dev/null +++ b/okf-bundle/new-architecture/architecture-decisions.md @@ -0,0 +1,290 @@ +--- +type: Reference +title: New Architecture decisions (ADR) +description: Canonical owner of durable architectural decisions for the React Native Firebase TurboModule migration — the "what we decided and why". Other new-architecture docs reference this; they do not restate decisions. +tags: [new-architecture, turbomodule, architecture, decisions, adr] +timestamp: 2026-06-29T00:00:00Z +--- + +# New Architecture decisions (ADR) + +**Canonical owner of durable architectural decisions** for the TurboModule migration. Each entry is a decision plus a brief rationale. Procedure lives in [implementation workflow](turbomodule-implementation-workflow.md); ephemeral phase/gate state lives in the [migration work queue](migration-work-queue.md). Those docs **link here** for the "why" — they do not copy decisions. + +**Policy:** [OKF documentation and commit policy](../documentation-policy.md). Durable decisions belong here; never in the ephemeral work queue. + +## Decision ID convention + +All decisions in this document use the **`NewArch-AD-`** prefix (e.g. `NewArch-AD-7`, `NewArch-AD-14a`, `NewArch-AD-17.1`) so TurboModule migration ADRs are unambiguous from other architectural decision records elsewhere in the monorepo. Use this prefix in durable code comments and docs that cite these decisions — not bare `AD-`. + +## Status legend + +| Status | Meaning | +|--------|---------| +| **Accepted** | Decided; implement to this. | +| **Proposed** | Recommended, awaiting maintainer sign-off; safe to plan around. | +| **Open** | Under analysis; do not lock in code until resolved. | + +--- + +## NewArch-AD-1 — New Architecture only — **Accepted** + +One coordinated semver major across the monorepo. No dual old/new bridge per package (`functions` precedent: v24). The legacy bridge interop layer remains available to consumers via RN itself, but RNFB ships TurboModule-only. + +**Why:** A per-package dual-bridge would multiply native surface and testing. A single coordinated break is cheaper to build and reason about. + +--- + +## NewArch-AD-2 — Naming: `NativeRNFBTurbo*` — **Accepted** + +Codegen spec/module names use the `NativeRNFBTurbo*` prefix (`NativeRNFBTurboAuth`, `NativeRNFBTurboFirestore`, …). Spec files must be prefixed `Native` per RN Codegen. + +**Why:** Disambiguates from legacy `RNFB*` module names during transition; satisfies Codegen's `Native*` spec-file requirement. + +--- + +## NewArch-AD-3 — Strong Codegen typing — **Accepted** + +Strong Codegen types wherever the API allows. Source of truth: `packages/*/lib/types/internal.ts`, native method inventories, firebase-js-sdk shapes. Use `Object` / open maps only where payloads are genuinely dynamic. + +--- + +## NewArch-AD-4 — Events deferred to Phase C — **Accepted** + +Keep the legacy event path (`RNFBNativeEventEmitter` → app-module proxy → `RNFBRCTEventEmitter` / `ReactNativeFirebaseEventEmitter` → `SharedEventEmitter` fan-out) under TurboModules. Defer Codegen EventEmitter cutover to [Phase C](migration-work-queue.md#deferred-cleanup-phase-eventemitter). + +**Deferral discriminator:** if area-focused e2e or device testing shows a package's events cannot work over the legacy proxy under TurboModules, escalate that package's event path into its own migration PR rather than waiting for Phase C. **Highest risk:** `messaging` (background/iOS AppDelegate, headless JS task). + +--- + +## NewArch-AD-5 — Commit generated code — **Accepted** + +`includesGeneratedCode: true`; commit Codegen output under `android/.../generated` and `ios/generated`, mirroring `packages/functions`. + +**Guard (Proposed, see NewArch-AD-17):** a CI check that re-running `yarn codegen` yields no diff, so committed artifacts can't go stale. + +--- + +## NewArch-AD-6 — Unified native module resolver — **Accepted** + +`packages/app/lib/internal/nativeModuleAndroidIos.ts` resolves `TurboModuleRegistry.get(name) ?? NativeModules[name]`. + +**Why / semantics (researched, scope-limited):** In **bridgeless** mode with the **unified native-module proxy** (RN ≥ 0.74 New Architecture default; the repo's test app is RN 0.78 + `newArchEnabled`), both `TurboModuleRegistry.get(name)` and `NativeModules[name]` route through one unified, **cached** `nativeModuleProxy` (`BridgelessNativeModuleProxy` backing `global.nativeModuleProxy`, which *is* `NativeModules`) — so they return the **same instance** for a migrated module; the `??` cannot hand back two divergent wrappers. **Scope caveat (verified by design review):** this identity is confirmed for **bridgeless + unified proxy**; the bridged-New-Architecture path (`__turboModuleProxy` set without bridgeless) is a *different* lookup from bridged `NativeModules` lazy config and is **not verified** to share identity — RNFB targets bridgeless NA, so this is an untested edge, not a supported config. The `NativeModules` fallback is **load-bearing during Phases 1–5**: an unmigrated package's legacy module is null in `TurboModuleRegistry.get` and resolves via the interop-backed `NativeModules` (`legacyBinding_`). + +**Phase R action:** remove the `NativeModules` fallback once all packages are migrated, so a missing module throws instead of returning soft-undefined. + +--- + +## NewArch-AD-7 — `codegenConfig.name` = aggregate library name; one `codegenConfig` per package — **Accepted** + +Each package has **one** `codegenConfig` whose `name` is an **aggregate library name** of the form `RNFBTurboModules` (e.g. `RNFBAppTurboModules`, `RNFBFunctionsTurboModules`, `RNFBFirestoreTurboModules`), **not** a module name. Multiple TurboModules in a package are listed under iOS `modulesProvider` (spec name → ObjC class) and live in the `specs/` dir; Android registers each shell in the package class. **One rule for every package**, single- and multi-spec alike — no degenerate exceptions. + +**Why:** Multi-module packages (database ×5, firestore ×4) cannot name the library after one module, so the aggregate-library shape is mandatory for them; applying it everywhere gives a single rule reviewers can apply without thinking about spec count. The aggregate-library shape is the one RN documents and the one that generalizes. + +**`functions` correction (one-time):** `functions` shipped with `codegenConfig.name: "NativeRNFBTurboFunctions"` (the *module* name). Rename to `RNFBFunctionsTurboModules` for consistency. **Downside: effectively none.** `codegenConfig.name` is the *generated-library* identifier (drives generated file/JNI/CMake target names) — it is **internal**, not a public/consumer symbol, and is **distinct from the module name** `NativeRNFBTurboFunctions` (the `RCT_EXPORT_MODULE` / `TurboModuleRegistry.get('NativeRNFBTurboFunctions')` key), which **stays unchanged**. The rename is mechanical: change `name`, re-run `yarn codegen`, delete the old generated files, update `react-native.config.js` `cmakeListsPath` if it embeds the old name, commit. Only risk is a build-wiring reference to the old library name; a clean codegen + build catches it. Track as a small standalone follow-up (low risk, no consumer impact). + +**Gate:** every spec name appears as a `modulesProvider` key (iOS) and is registered in the package class (Android); `codegenConfig.name` matches `RNFBTurboModules`. + +Reference: [`packages/app/package.json`](../../../packages/app/package.json) `codegenConfig`. + +--- + +## NewArch-AD-8 — TurboModule JS enumeration: `for...in` + `Object.create` — **Accepted** + +When wrapping or extending a native module, enumerate methods with **`for...in`** (not `Object.keys`) and extend with **`Object.create(host, descriptors)`** (never copy the host into a plain `{}` / spread / `Object.assign({}, host)`). + +**Why:** TurboModules expose methods lazily on the **prototype**, which are non-own; `Object.keys`/spread see nothing and produce `XYZ is not a function`. Codegen methods **are** enumerable via `for...in` (confirmed), so `for...in` + `Object.create` both finds them and preserves the prototype. Reference: [RN enable-libraries § "XYZ is not a function"](https://github.com/reactwg/react-native-new-architecture/blob/main/docs/enable-libraries.md#javascript-xyz--is-not-a-function-it-is-undefined), [facebook/react-native#43221](https://github.com/facebook/react-native/issues/43221). + +Code: [`registry/nativeModule.ts`](../../../packages/app/lib/internal/registry/nativeModule.ts), [`nativeModuleAndroidIos.ts`](../../../packages/app/lib/internal/nativeModuleAndroidIos.ts). + +--- + +## NewArch-AD-9 — `requiresMainQueueSetup` returns `NO` — **Accepted** + +iOS TurboModule shells return `NO` from `+ requiresMainQueueSetup`. Any genuinely main-thread/UIKit work in `getConstants`/init is dispatched explicitly to the main queue, not by forcing whole-module main-queue setup. + +**Why:** Under TurboModules, `requiresMainQueueSetup = YES` makes the lazy module load run setup **synchronously on the main thread** — the JS thread blocks on main (deadlock risk under fling) **and synchronous methods are blocked** (which would block [NewArch-AD-16 Phase S](#newarch-ad-16--phase-s-asyncsync-conversion--open)). Reference: [RN #49957](https://github.com/facebook/react-native/pull/49957), [RN commit d7ac21c](https://github.com/facebook/react-native/commit/d7ac21cec5492e180fbf3817af7be64ab121cb75) (under TurboModules `getConstants` runs on the JS thread, not the main queue). + +**Per-package audit (part of gap-analysis):** inventory each shell's `getConstants`/init and any `methodQueue` override for genuine main-thread/UIKit dependencies; default to `NO`; dispatch only the specific main-thread work that needs it. + +**Phase 0 status — implemented (2026-06-29 re-implementation pass).** Both shells return `NO`; legacy `methodQueue = dispatch_get_main_queue()` overrides removed per [NewArch-AD-19](#newarch-ad-19--turbomodule-methodqueue-policy--accepted). Validate on-device during area-focused e2e if any method regresses. + +--- + +## NewArch-AD-10 — Cross-package native state is centralized in `app`, with testable APIs — **Accepted** + +`packages/app` is the home of cross-package native APIs and shared state (it always has been). This is acceptable; the goal is to **formalize** it: prefer explicit, testable accessors over bare `public static` fields, and ensure any inter-module state really is routed through `app` rather than duplicated per package. + +**Known shared state to keep centralized:** `authDomains` / iOS `customAuthDomains` (read by `auth` + `RCTConvertFirebase`); `ReactNativeFirebaseJSON` / `Meta` / `Preferences` / `UniversalFirebasePreferences` (read by database, firestore, messaging, crashlytics, app-check); the event emitters (NewArch-AD-4 / Phase C). When a package migrates, it must keep reaching these `app`-owned singletons; do not fork a second copy. + +**Direction:** treat the current `public static` maps as tolerated legacy carryover; a new cross-package channel should be an explicit app-owned API/singleton with tests, not a new public static. + +**Encapsulation cleanup ([Phase E](migration-work-queue.md#phase-e-shared-state-encapsulation-optional), optional):** a post-migration pass that refactors the un-encapsulated shared-state items (bare `public static` maps such as `authDomains`) behind explicit, testable `app`-owned accessor methods, and audits that all inter-module state is genuinely centralized in `app`. Optional and deferrable — it does not block the coordinated break — but the canonical home for that work. + +--- + +## NewArch-AD-11 — Multi-module method names are merged; uniqueness enforced by test — **Accepted** + +Multiple specs/modules in one package are **merged flat** into a single resolved native object (so JS keeps calling `native.documentGet(...)` etc.). Method names must therefore be **globally unique across a package's specs**. Follow the existing `` naming already in use (`documentGet`, `collectionGet`, `transactionBegin`, `aggregateQuery`, …) — which is why there are zero collisions today. + +**Enforcement:** a build/test-time uniqueness assertion (part of NewArch-AD-17's contract test) asserts the union of method names across a package's specs has no duplicates. Optional `__DEV__` runtime guard in the merge loop warns on overwrite. We do **not** namespace sub-modules on the wire (would churn every call site). + +--- + +## NewArch-AD-12 — One commit per package — **Accepted** + +Convert a whole package (all its legacy modules → all its specs) in one `implementation → independent-review → commit` loop; land it as one `feat(): migrate to TurboModules`. Multiple specs ≠ multiple commits — they share `codegenConfig`, generated artifacts, podspec/gradle guards, and JS wiring that only build and pass e2e together. + +--- + +## NewArch-AD-13 — Test harness: committed defaults + gitignored local overrides — **Accepted** + +`tests/globals.js` and `tests/app.js` keep the **committed defaults** (`RNFBDebug = false`, full `platformSupportedModules`, durable product wiring such as the `NativeRNFBTurbo*` resolver routing). Local per-run choices (`RNFBDebug = true`, a focused module list) live in a small **gitignored overrides file** that the harness reads if present. + +**Why:** Durable product wiring (e.g. routing `NativeRNFBTurbo*` through the resolver) currently shares files with ephemeral narrowing, so a `git checkout` revert of narrowing also drops product wiring — this already happened once. It also bites human developers who narrow locally and then lose or accidentally commit it. Separating committed defaults from a gitignored overrides file makes the durable wiring un-revertable and the local narrowing impossible to commit. + +**Mechanism:** + +- Committed **`tests/harness.overrides.example.js`** — the shape demonstrator. Heavily commented for a human or agent: what each field means, valid values, and exactly what to paste to narrow modules / enable `RNFBDebug`. Exports an empty/no-op override so copying it changes nothing until edited. +- Gitignored **`tests/harness.overrides.js`** — the real local file; developers/agents copy the example to this name and edit it. +- `tests/globals.js` / `tests/app.js` read `harness.overrides.js` if present, else fall back to committed defaults. Because `tests/app.js` uses `require.context` (Metro static analysis), the override must express module narrowing as a **filter list the harness applies to the static set**, not a dynamic `require`. + +**Ordering caution (do this in order):** add `tests/harness.overrides.js` to `.gitignore` **first** and verify it is ignored (`git check-ignore`), **then** create the local file — so the real overrides file can never be accidentally tracked. The committed example file (`harness.overrides.example.js`) must **not** be ignored. + +--- + +## NewArch-AD-14 — Native-module wrapper: memoizing lazy `Proxy` — **Accepted** + +The wrapper gives every native method: (1) **arg prepending** (`appName`, region/databaseId — the native bridge argument injection that lets product code call `firestore().collection(...)` without passing `appName`), (2) **error mapping** (native rejections → `NativeFirebaseError`), (3) **iOS null-encoding** for TurboModule object args. These responsibilities are mandatory product behavior. + +**Decision:** wrap via a **memoizing lazy `Proxy`** — each method is wrapped+bound **on first call** and cached, instead of eagerly materializing every method at first touch. + +**Why over eager:** eager builds all closures up front (auth ≈ 59, firestore ≈ 31 per cache key) and **defeats TurboModule prototype lazy loading**; the lazy Proxy preserves laziness (only pay for methods actually called), removes the eager `getConstants` rebuild on hot paths ([NewArch-AD-15](#newarch-ad-15--constant-memoization-scope-static-only--accepted)), and lets the `app`-path and `FirebaseModule`-path wrapping converge on one shape. The Proxy must enumerate via `for...in` and preserve the host prototype ([NewArch-AD-8](#newarch-ad-8--turbomodule-js-enumeration-forin--objectcreate--accepted)) — it must **not** flatten onto a frozen `{}` (that is the eager pattern being replaced). + +**Coupling note:** the current `initialiseNativeModule` flatten-onto-`{}` + `Object.freeze` only works because eager wrapping pre-materializes own-enumerable methods. Moving to the Proxy means returning the Proxy (or a Proxy-backed object), **not** an `Object.assign`-ed frozen plain object. Update both the multi-module merge and the single-module path together. + +### NewArch-AD-14a — Multi-host merge: routing composite Proxy (required for multi-module) + +A single `Proxy` has **one** target/`[[Prototype]]`, so it cannot represent N independent TurboModule hosts (firestore ×4, database ×5) whose lazy methods live on **separate** prototype chains. The single-host Proxy is insufficient for multi-module packages, which **Phase 1 hits immediately** (`FirestoreStatics`, `DatabaseSyncTree`). Design the merge as a **routing composite Proxy**, not a flattened object: + +1. **At init (metadata only, cheap):** `for...in` each raw host to build a `methodName → { host, key }` routing map. No wrapping/binding yet — just discover which host owns each name. (Method names are unique across a package's specs by [NewArch-AD-11](#newarch-ad-11--multi-module-method-names-are-merged-uniqueness-enforced-by-test--accepted), so the map has no collisions.) +2. **`get(name)` trap:** on first access, look up `{ host, key }`, wrap+bind from the **correct** host (arg-prepend + error-map + iOS null-encode), memoize the wrapped fn, return it. Preserves per-host prototype/laziness. +3. **`has` / `ownKeys` / `getOwnPropertyDescriptor`:** answer from the routing map (so `in`, `for...in`, and `Object.keys` over the merged surface behave). +4. **Drop the dead `multiModuleRoot[moduleName] = !!nativeModule` boolean flags** — they are written but never read in product code; if optional-module presence is ever needed, keep it in a side table, not on the callable surface. +5. **No `Object.freeze`** on the composite — immutability is provided by the Proxy traps (no `set`), not by freezing. + +The single-module path is the degenerate N=1 case of the same composite (one host in the routing map). Implement both through the one mechanism. **NewArch-AD-17.1's contract test must include a 2-host merge fixture** even before firestore ships, since Phase 0 (`app`/`utils` are resolved as *separate* single-host surfaces) does **not** exercise this path. + +--- + +## NewArch-AD-15 — Constant memoization scope: static only — **Accepted** + +Memoize constants that are **static after init** (e.g. app `NATIVE_FIREBASE_APPS`, `FIREBASE_RAW_JSON`; iOS/file-path constants). Do **not** memoize constants that can change at runtime; expose those as **methods**, not cached constants. + +**Why / coherency:** Memoization is JS-layer caching. For static native state a cached snapshot can't drift; for **dynamic** native state it can, with no native→JS invalidation signal. + +**Constant taxonomy (classify each before caching):** + +| Class | Examples | Caching rule | +|-------|----------|--------------| +| **bootstrap-only** | `NATIVE_FIREBASE_APPS` | Snapshot at bootstrap. JS never re-reads it today, so memoizing preserves current semantics — but document it as a bootstrap snapshot; runtime `initializeApp`/`deleteApp` will **not** be reflected (already true). | +| **build-time static** | `FIREBASE_RAW_JSON`, path constants (`DOCUMENT_DIRECTORY`, …) | Safe to memoize indefinitely. | +| **session-static** | `isRunningInTestLab` | Safe to memoize. | +| **dynamic** | `androidPlayServices` | **Never cache as a constant.** Expose as a method (`androidGetPlayServicesStatus()`); remove from the spec's `getConstants` typing when converted. | + +**Hot-path bug to fix in the same pass:** `withTurboConstants` calls `getConstants()` on **every** `getReactNativeModule()` resolve — the exact rebuild NewArch-AD-14/NewArch-AD-15 target. And `messaging.isSupported()` currently reads the Play Services value via the **legacy** module name `RNFBUtilsModule` and the static constant — under turbo-only resolution that name returns nothing, so `isSupported()` breaks. Fix it to resolve `NativeRNFBTurboUtils` **and** read via the dynamic method, not the constant. + +--- + +## NewArch-AD-16 — Phase S (async→sync conversion) — **Open** + +Some RNFB methods are `Promise` only because the legacy bridge forced async, while firebase-js-sdk is synchronous. TurboModules support sync JSI methods, so those can return to sync parity. Scope, discriminator, and the required gap-analysis live in [migration work queue § Phase S](migration-work-queue.md#phase-s-sync-conversion-forced-async--sync) and [implementation workflow § Phase S](turbomodule-implementation-workflow.md#phase-s-sync-conversion-forced-async--sync). + +**Open question driving the gap-analysis:** the "keep async if it does network/IO/disk" rule assumes firebase-js-sdk's sync methods do **not** do blocking IO for the same functionality. That must be verified per method (does the web SDK do the work in-memory, or defer it?), because if web is genuinely sync-and-non-blocking, RNFB may be able to be sync too. Do not lock the conversion list until that inventory exists. Blocked by NewArch-AD-9 (`requiresMainQueueSetup = NO`) — sync methods require it. + +--- + +## NewArch-AD-17 — Spec contract + parity tests — **Accepted (1); Proposed (2, 3)** + +Jest-level tests, reused across packages: + +1. **Resolution/enumeration contract** — **Accepted.** A fixture that models a TurboModule (methods **non-own on the prototype**, constants own; `Object.keys(raw) === []`) and asserts every spec method is callable through the **real wrapper** (`getNativeModule`/`getAppModule`). Catches the NewArch-AD-8 enumeration class — and now the NewArch-AD-14 Proxy behavior — in sub-second Jest instead of 30-minute e2e. Build alongside the Phase 0 re-implementation. **Must include a 2-host merge fixture** (two mock TurboModule hosts, disjoint method sets) that exercises the [NewArch-AD-14a routing composite Proxy](#newarch-ad-14a--multi-host-merge-routing-composite-proxy-required-for-multi-module) — because Phase 0 (`app`/`utils` resolved as separate single-host surfaces) does not, yet Phase 1 (firestore/database) depends on it. + + + +### NewArch-AD-17.1 — Jest TurboModule contract test — **Accepted** + +**Canonical file:** [`packages/app/__tests__/nativeModuleContract.test.ts`](../../../packages/app/__tests__/nativeModuleContract.test.ts) + +**Describe block (grep anchor):** `TurboModule wrapper contract (NewArch-AD-17.1)` + +**Scoped Jest command (review / implementer handoff):** + +```bash +yarn tests:jest -- packages/app/__tests__/nativeModuleContract.test.ts +``` + +**Full suite** (`yarn tests:jest`) must also stay green — the contract test is part of the global Jest run, not a separate harness. + +**Fixtures required in that file:** + +| Case | Asserts | +|------|---------| +| TurboModule host shape | Methods non-own on prototype; `Object.keys(raw) === []` | +| Single-host wrapper | Every spec method callable via `getNativeModule()` | +| 2-host merge (NewArch-AD-14a) | Routing composite Proxy dispatches to the correct host per method name | + +**When required:** any change to [`nativeModule.ts`](../../../packages/app/lib/internal/registry/nativeModule.ts), `withTurboConstants`, or TurboModule wrapper behavior — re-run the scoped command above before closing `implementation_gate` or `review_gate`. +2. **Spec↔native parity** — **Proposed.** Assert each package's spec method-name set equals the platform `@ReactMethod` / `RCT_EXPORT_METHOD` set, and (NewArch-AD-11) the union across a package's specs has no duplicate names. +3. **Codegen-up-to-date CI** — **Proposed.** `yarn codegen` + `git diff --exit-code` on generated dirs (NewArch-AD-5 guard). + +**Why:** The current Jest mocks are plain enumerable objects and structurally cannot reproduce the enumeration bug that already cost an iteration; these tests close that blind spot and make iterations faster and higher quality. + +--- + +## NewArch-AD-18 — Raw vs wrapped resolver policy — **Accepted** + +Two resolution surfaces exist and must be used deliberately: + +- **Wrapped** (`getNativeModule(module)` / `getAppModule()` → the [NewArch-AD-14](#newarch-ad-14--native-module-wrapper-memoizing-lazy-proxy--accepted) Proxy): the **default** for all product calls. Gives arg-prepend, error mapping, iOS null-encoding. +- **Raw** (`getReactNativeModule(name)`): the **bare** native object from the unified resolver — no wrapping. + +**Default rule:** new product code uses the **wrapped** surface. Raw access is allowed **only** when listed in the canonical exception table below (or after a gap-analysis finds a new legitimate case, documents it here, and adds an in-code rationale comment). Raw callers must use the **turbo** module name ([NewArch-AD-2](#newarch-ad-2--naming-nativernfbturbo--accepted)). Raw callers do **not** get error mapping — they must handle native errors themselves. + +**Gap-analysis gate (every package):** as part of spec authoring, `grep` the repo for `getReactNativeModule(` in product code. For each hit: (1) is it already in the table below? (2) if not, is it a bug (legacy module name, should be wrapped)? (3) if genuinely new, add a row here with policy rationale **before** landing the PR. See [workflow § gap-analysis](turbomodule-implementation-workflow.md#spec-authoring-gap-analysis--pre-implementation). + +### Canonical exception table + +| # | Call site | Module name | Category | Why raw (policy) | Action | +|---|-----------|---------------|----------|------------------|--------| +| E1 | [`RNFBNativeEventEmitter.ts`](../../../packages/app/lib/internal/RNFBNativeEventEmitter.ts) (constructor, `addListener`, `removeAllListeners`, `removeSubscription`) | `NativeRNFBTurboApp` | **Permanent** | React Native's `NativeEventEmitter` must receive the **same raw host object** that implements `addListener` / `removeListeners` on the native side. Wrapping would break event subscription identity and the RN event-bridge contract. Deferred to [Phase C](migration-work-queue.md#deferred-cleanup-phase-eventemitter) for a typed Codegen event path. | Keep raw; turbo name. | +| E2 | [`nativeModule.ts`](../../../packages/app/lib/internal/registry/nativeModule.ts) `initialiseNativeModule` / `getAppModule` bootstrap | any | **Infrastructure** | The wrapper factory itself must read the bare host to build the [NewArch-AD-14](#newarch-ad-14--native-module-wrapper-memoizing-lazy-proxy--accepted) Proxy/composite. Not a product bypass. | N/A | +| E3 | [`nativeModuleAndroidIos.ts`](../../../packages/app/lib/internal/nativeModuleAndroidIos.ts) unified resolver | any | **Infrastructure** | Defines `getReactNativeModule`; applies `withTurboConstants` before returning. Not a product bypass. | N/A | +| E4 | [`tests/globals.js`](../../../tests/globals.js) `NativeModules` proxy getter | `RNF*` / `NativeRNFBTurbo*` | **Infrastructure** | E2e harness routes RNFB module names through the real unified resolver so specs that read `NativeModules.NativeRNFBTurboApp` (e.g. [`events.e2e.js`](../../../packages/app/e2e/events.e2e.js)) get a live module, not a stub. Durable product wiring — not harness narrowing. | Keep; part of Phase 0. | +| E5 | [`UtilsStatics.ts`](../../../packages/app/lib/utils/UtilsStatics.ts) `FilePath` getter | `NativeRNFBTurboUtils` | **Phase 0 fix** | Reads path **constants** synchronously from the utils host without a `FirebaseModule` instance (static getter on `Utils.Statics`). Raw was acceptable pre-turbo; under [NewArch-AD-15](#newarch-ad-15--constant-memoization-scope-static-only--accepted) migrate to a dedicated wrapped utils accessor (or memoized static read via resolver) so constants are not rebuilt per access. Turbo name is already correct. | Fix in Phase 0 re-implementation. | +| E6 | [`messaging/lib/index.ts`](../../../packages/messaging/lib/index.ts) `isSupported()` | ~~`RNFBUtilsModule`~~ → `NativeRNFBTurboUtils` | **Phase 0 fix (bug)** | Cross-package read of Play Services availability. Was using **legacy module name** (returns `undefined` under turbo-only) and a **dynamic constant** (`androidPlayServices`) that can go stale. Must use turbo name + **dynamic method** `androidGetPlayServicesStatus()` per [NewArch-AD-15](#newarch-ad-15--constant-memoization-scope-static-only--accepted). | **Must-fix** in Phase 0. | +| E7 | [`app/lib/modular.ts`](../../../packages/app/lib/modular.ts) `metaGetAll`, `jsonGetAll`, `preferences*` | `NativeRNFBTurboApp` | **Not an exception — migrate** | No policy reason for raw; these are app-module method calls with no arg-prepend skip. Should use **`getAppModule()`** (wrapped) for error mapping consistency. Listed here so gap-analysis catches them. | Migrate to `getAppModule()` in Phase 0. | +| E8 | [`FirestoreStatics.ts`](../../../packages/firestore/lib/FirestoreStatics.ts) `setLogLevel` | `RNFBFirestoreModule` | **Deferred — Phase 1** | Cross-package static helper bypasses `FirebaseModule`/`getNativeModule`. Acceptable until firestore migrates; then switch to turbo name + wrapped surface (or firestore-owned static that uses `getNativeModule`). | Fix when `firestore` migrates. | +| E9 | [`DatabaseSyncTree.ts`](../../../packages/database/lib/DatabaseSyncTree.ts) `native` getter | `RNFBDatabaseQueryModule` | **Deferred — Phase 4** | Internal sync listener tree calls query module directly for low-latency sync ops, bypassing the merged multi-module surface. Acceptable until database migrates; then turbo name + evaluate whether wrapped merge surface suffices. | Fix when `database` migrates. | +| E10 | [`phone-number-verification/lib/index.ts`](../../../packages/phone-number-verification/lib/index.ts) `getNativeModule()` | `RNFBPnvModule` | **Deferred — Phase 5** | Package bypasses `createModuleNamespace` by design ([workflow § gotchas](turbomodule-implementation-workflow.md#gotchas)). Direct resolver is intentional; update to `NativeRNFBTurboPnv` on migration. | Fix when `phone-number-verification` migrates. | + +**Adding a new exception:** gap-analysis must justify why wrapping breaks (not merely "it's convenient"). Update this table and add a one-line `// NewArch-AD-18 E: ` comment at the call site. + +--- + +## NewArch-AD-19 — TurboModule `methodQueue` policy — **Accepted** + +Default: **do not override `methodQueue`.** Remove legacy `- (dispatch_queue_t)methodQueue { return dispatch_get_main_queue(); }` overrides (present on `RNFBAppModule` and `RNFBUtilsModule`) unless a specific method genuinely needs the main thread — in which case dispatch *that method's* main-thread work explicitly (the `RCTUnsafeExecuteOnMainQueueSync` pattern already used in `initializeApp`), rather than forcing the whole module onto main. + +**Why:** A module-wide `methodQueue = main_queue` couples every async method to the main thread (jank/contention) and is inconsistent with [NewArch-AD-9](#newarch-ad-9--requiresmainqueuesetup-returns-no--accepted) (`requiresMainQueueSetup = NO`). **Caveat (unverified):** how TurboModule JSI honors `methodQueue` for sync vs async methods is not documented; treat removal as a native change to validate on-device during Phase 0 re-implementation, not a blind delete. Keep explicit main dispatch only where UI (e.g. Play Services resolution dialogs) requires it. + +--- + +## Related docs + +| Topic | Document | +|-------|----------| +| Procedure / how-to | [turbomodule-implementation-workflow.md](turbomodule-implementation-workflow.md) | +| Phase/gate/ephemeral state | [migration-work-queue.md](migration-work-queue.md) | +| Index | [index.md](index.md) | +| Change loop, gates, tiers | [change-authoring-workflow.md](../testing/change-authoring-workflow.md) | +| Doc/commit policy | [documentation-policy.md](../documentation-policy.md) | diff --git a/okf-bundle/new-architecture/index.md b/okf-bundle/new-architecture/index.md index 85e0b287b1..142d357a6a 100644 --- a/okf-bundle/new-architecture/index.md +++ b/okf-bundle/new-architecture/index.md @@ -6,12 +6,14 @@ TurboModule migration for React Native Firebase native bridge packages. ## Documents +* [Architecture decisions (ADR)](architecture-decisions.md) — **canonical owner** of durable decisions (the "what + why"); other docs reference it * [Migration work queue](migration-work-queue.md) — ephemeral gates, phase ordering, package inventory * [TurboModule implementation workflow](turbomodule-implementation-workflow.md) — spec/codegen/native conversion, area harness; extends [change authoring](../testing/change-authoring-workflow.md) ## Reference implementation -* [`packages/functions`](../../../packages/functions/) — only package migrated to TurboModules today ([PR #8603](https://github.com/invertase/react-native-firebase/pull/8603); new-arch-only from v24) +* [`packages/functions`](../../../packages/functions/) — first TurboModule package ([PR #8603](https://github.com/invertase/react-native-firebase/pull/8603); new-arch-only from v24) +* [`packages/app`](../../../packages/app/) — Phase 0 foundation; first [multi-spec package](migration-work-queue.md#package-inventory) (`NativeRNFBTurboApp` + `NativeRNFBTurboUtils`); see [workflow § multi-spec / gotchas](turbomodule-implementation-workflow.md#multi-spec-packages-app-precedent) ## Related repository files diff --git a/okf-bundle/new-architecture/migration-work-queue.md b/okf-bundle/new-architecture/migration-work-queue.md index 69c893f391..01907811cd 100644 --- a/okf-bundle/new-architecture/migration-work-queue.md +++ b/okf-bundle/new-architecture/migration-work-queue.md @@ -8,8 +8,8 @@ timestamp: 2026-06-26T00:00:00Z # TurboModule migration — work queue -> **QUEUED (2026-06-26):** Planning document — awaiting maintainer review before implementation pickup. -> **Goal/order:** app foundation → hard probe → easy wins → remaining complex → coordinated break → EventEmitter cleanup. Links: [implementation workflow](turbomodule-implementation-workflow.md), [change authoring](../testing/change-authoring-workflow.md), [functions reference](../../../packages/functions/) ([PR #8603](https://github.com/invertase/react-native-firebase/pull/8603)). +> **IN PROGRESS (2026-06-30):** Phase **0** (`app` TurboModules) — **done**. Phase **0.1** (`app` compare:types) — **queued**. Decisions: [architecture-decisions.md](architecture-decisions.md). +> **Goal/order:** app foundation → hard probe → easy wins → remaining complex → sync conversion → coordinated break → cleanup (events, shared-state encapsulation). Decisions: [architecture-decisions.md](architecture-decisions.md). Links: [implementation workflow](turbomodule-implementation-workflow.md), [change authoring](../testing/change-authoring-workflow.md), [functions reference](../../../packages/functions/) ([PR #8603](https://github.com/invertase/react-native-firebase/pull/8603)). Ephemeral tracker; see [OKF policy](../documentation-policy.md). @@ -17,14 +17,27 @@ Ephemeral tracker; see [OKF policy](../documentation-policy.md). ## Locked decisions -| # | Decision | Detail | -|---|----------|--------| -| 1 | **New Architecture only** | One coordinated semver break across the monorepo. No dual old/new bridge support per package (`functions` precedent: v24). | -| 2 | **Naming** | Codegen module names use `NativeRNFBTurbo*` prefix (e.g. `NativeRNFBTurboAuth`, `NativeRNFBTurboFirestore`). | -| 3 | **Typing** | Strong Codegen types wherever the API allows. Source of truth: `packages/*/lib/types/internal.ts`, native method inventories, firebase-js-sdk shapes. Use `Object` / open maps only where payloads are genuinely dynamic. | -| 4 | **Events** | **Defer** Codegen EventEmitter cutover to [Phase C cleanup](#deferred-cleanup-phase-eventemitter) unless testing proves deferral impossible. | -| 5 | **Generated code** | Commit codegen output (`includesGeneratedCode: true`); mirror `packages/functions` layout. | -| 6 | **Module resolution** | Unified resolver in `packages/app` — `TurboModuleRegistry.get(name)` with `NativeModules` fallback during transition. | +Durable architectural decisions are owned by **[architecture-decisions.md](architecture-decisions.md)** (canonical, with rationale). Quick index of the *Accepted* ones: + +| ADR | Decision | +|-----|----------| +| [NewArch-AD-1](architecture-decisions.md#newarch-ad-1--new-architecture-only--accepted) | New Architecture only — one coordinated semver major | +| [NewArch-AD-2](architecture-decisions.md#newarch-ad-2--naming-nativernfbturbo--accepted) | Naming: `NativeRNFBTurbo*` prefix | +| [NewArch-AD-3](architecture-decisions.md#newarch-ad-3--strong-codegen-typing--accepted) | Strong Codegen typing | +| [NewArch-AD-4](architecture-decisions.md#newarch-ad-4--events-deferred-to-phase-c--accepted) | Events deferred to [Phase C](#deferred-cleanup-phase-eventemitter) | +| [NewArch-AD-5](architecture-decisions.md#newarch-ad-5--commit-generated-code--accepted) | Commit generated code | +| [NewArch-AD-6](architecture-decisions.md#newarch-ad-6--unified-native-module-resolver--accepted) | Unified resolver (`TurboModuleRegistry.get ?? NativeModules`) | +| [NewArch-AD-7](architecture-decisions.md#newarch-ad-7--codegenconfigname--aggregate-library-name-one-codegenconfig-per-package--accepted) | `codegenConfig.name` = `RNFBTurboModules` (all packages) | +| [NewArch-AD-8](architecture-decisions.md#newarch-ad-8--turbomodule-js-enumeration-forin--objectcreate--accepted) | Enumerate with `for...in` + `Object.create` | +| [NewArch-AD-9](architecture-decisions.md#newarch-ad-9--requiresmainqueuesetup-returns-no--accepted) | `requiresMainQueueSetup` returns `NO` | +| [NewArch-AD-10](architecture-decisions.md#newarch-ad-10--cross-package-native-state-is-centralized-in-app-with-testable-apis--accepted) | Cross-package state centralized in `app` | +| [NewArch-AD-11](architecture-decisions.md#newarch-ad-11--multi-module-method-names-are-merged-uniqueness-enforced-by-test--accepted) | Multi-module method names unique (test-enforced) | +| [NewArch-AD-12](architecture-decisions.md#newarch-ad-12--one-commit-per-package--accepted) | One commit per package | +| [NewArch-AD-13](architecture-decisions.md#newarch-ad-13--test-harness-committed-defaults--gitignored-local-overrides--accepted) | Harness: committed defaults + gitignored overrides | +| [NewArch-AD-14](architecture-decisions.md#newarch-ad-14--native-module-wrapper-memoizing-lazy-proxy--accepted) | Memoizing lazy Proxy wrapper (+ NewArch-AD-14a composite) | +| [NewArch-AD-15](architecture-decisions.md#newarch-ad-15--constant-memoization-scope-static-only--accepted) | Memoize static constants only; dynamic → method | +| [NewArch-AD-18](architecture-decisions.md#newarch-ad-18--raw-vs-wrapped-resolver-policy--accepted) | Raw vs wrapped resolver policy | +| [NewArch-AD-19](architecture-decisions.md#newarch-ad-19--turbomodule-methodqueue-policy--accepted) | No `methodQueue` override by default | Implementation steps, harness, and commit rules: [turbomodule implementation workflow](turbomodule-implementation-workflow.md) — do not restate here. @@ -44,7 +57,7 @@ Gate prerequisites before any `:test-cover` ([host rule](../testing/change-autho | Layer | Stays | Changes | |-------|-------|---------| -| JS product API | `namespaced.ts`, `modular.ts`, web shims, `FirebaseModule` subclasses, arg prepending | `nativeModuleName` → `NativeRNFBTurbo*`; `turboModule: true` | +| JS product API | `modular.ts`, web shims, `FirebaseModule` subclasses, arg prepending | `nativeModuleName` → `NativeRNFBTurbo*`; `turboModule: true` | | Events (Phases 0–5) | Compile-time event names, `SharedEventEmitter` fan-out, `nativeEvents` | Native emitters unchanged — see [Phase C](#deferred-cleanup-phase-eventemitter) | | Native | Firebase SDK integration, business logic | Extend generated `*Spec`; iOS `getTurboModule()`; podspec new-arch guard | | Release | Per-package semver today | **One coordinated major** when Phases 0–5 complete | @@ -88,7 +101,7 @@ Follow-on **after** Phases 0–5 and coordinated break. Not in scope unless test | Package | TurboModule(s) | Status | |---------|----------------|--------| -| `@react-native-firebase/functions` | `NativeRNFBTurboFunctions` | ✅ reference | +| `@react-native-firebase/functions` | `NativeRNFBTurboFunctions` | ✅ reference (`codegenConfig.name`: `RNFBFunctionsTurboModules` per [NewArch-AD-7](architecture-decisions.md#newarch-ad-7--codegenconfigname--aggregate-library-name-one-codegenconfig-per-package--accepted)) | ### Native packages — complexity summary @@ -133,13 +146,13 @@ Android `@ReactMethod` counts approximate spec surface area. Multi-module: **one | Package | Legacy modules | Notes | |---------|----------------|-------| -| **app** | `RNFBAppModule`, `RNFBUtilsModule` (+ Android utils) | Event proxy; **blocker** for migration complete | +| **app** | `RNFBAppModule`, `RNFBUtilsModule` (+ Android utils) | Event proxy; **blocker** for migration complete; first [multi-spec package](turbomodule-implementation-workflow.md#multi-spec-packages-app-precedent) | --- ## Phase ordering -Strategy: **foundation → hard probe → easy wins → remaining complex → coordinated break → cleanup**. +Strategy: **foundation → hard probe → easy wins → remaining complex → sync conversion → coordinated break → cleanup (events, shared-state encapsulation)**. Pick **one** of `firestore` or `auth` in Phase 1 (firestore = multi-module + pipelines; auth = max single-module spec). @@ -147,16 +160,89 @@ Pick **one** of `firestore` or `auth` in Phase 1 (firestore = multi-module + pip | Phase | Focus | Status | Packages | |-------|--------|--------|----------| -| **0** | App foundation + unified resolver | queued | `app` | +| **0** | App foundation + unified resolver | **done** | `app` | +| **0.1** | App modular type parity (`compare:types`) | **queued** | `app` — [§ Phase 0.1](#phase-01-app-comparetypes) | | **1** | Hard probe | queued | `firestore` **or** `auth` — pick one | | **2** | Easy wins | queued | `installations`, `perf`, `in-app-messaging`, `app-distribution`, `ml` | | **3** | Moderate | queued | `app-check`, `remote-config`, `analytics`, `crashlytics`, `storage` | | **4** | Remaining complex | queued | other Tier A/B + `messaging`, `database` | | **5** | Android-only / misc | queued | `phone-number-verification` | +| **S** | Sync conversion (forced-async → sync) | queued (scope open — [NewArch-AD-16](architecture-decisions.md#newarch-ad-16--phase-s-asyncsync-conversion--open)) | All migrated packages — [§ sync conversion](#phase-s-sync-conversion-forced-async--sync) | | **R** | Pre-merge full validation | queued | Revert harness narrowing; [full tier](../testing/running-e2e.md#e2e-validation-tiers-unit-focused-area-focused-full) 3-platform before coordinated major | | **C** | EventEmitter cleanup | deferred | All — [§ deferred cleanup](#deferred-cleanup-phase-eventemitter) | +| **E** | Shared-state encapsulation | deferred (optional) | `app` + readers — [§ Phase E](#phase-e-shared-state-encapsulation-optional) | -**Coordinated break:** consumer-facing major when Phases 0–5 + **R** complete (`functions` already new-arch-only). +**Coordinated break:** consumer-facing major when Phases 0–5, **S**, and **R** complete (`functions` already new-arch-only). Phases **C** and **E** are optional post-break cleanup and do not gate the major. + +--- + +## Phase S: sync conversion (forced-async → sync) + +**Runs after Phases 0–5** (every native package on TurboModules), **before R**. Owner doc for procedure/discriminator: [implementation workflow § Phase S](turbomodule-implementation-workflow.md#phase-s-sync-conversion-forced-async--sync). + +**Rationale:** Under the legacy bridge, *all* native calls were asynchronous. Some RNFB methods were therefore typed `Promise` purely because the bridge forced it — even though the corresponding **firebase-js-sdk** API is **synchronous**. These show up in `compare:types` configs as documented async-vs-sync differences. TurboModules support **synchronous** methods across the JSI boundary, so those forced-async APIs can return to sync parity with firebase-js-sdk. + +**Scope discriminator (only convert when ALL hold):** + +1. The difference exists **solely** because the legacy bridge forced async — not because the native work is genuinely asynchronous (I/O, network, disk). +2. firebase-js-sdk's equivalent is synchronous (the `compare:types` config records the async-vs-sync delta). +3. The TurboModule spec method can be declared sync (no `Promise`) and the native shell can return synchronously on the JS thread without blocking on real I/O. + +**Out of scope:** anything with real native latency (token fetches, network, disk, keychain). Forcing those sync would block JS — keep them `Promise`. + +**Per-package gate:** removing the corresponding `compare:types` config entry (the async-vs-sync difference is gone) is the completion signal for that package's Phase S item. + +This is a **coordinated public-API change** (async→sync is observable to consumers) and ships in the same major as the migration — see [implementation workflow § Phase S](turbomodule-implementation-workflow.md#phase-s-sync-conversion-forced-async--sync). + +### Gap-analysis (deferred — capture only, do not size yet) + +The "keep async if it does network/IO/disk" rule in the discriminator **assumes** that where firebase-js-sdk is synchronous, the work is genuinely in-memory and non-blocking. That assumption is **unverified** and is the core thing the gap-analysis must establish. Open question to resolve: + +> If firebase-js-sdk decided a method can be sync, why can't RNFB? Is it that the web SDK's sync method does **not** do blocking IO for that functionality (it works on in-memory/cached state, e.g. parsing a URL, returning a cached getter), whereas our native path would do real IO for the *same* result? Or could RNFB legitimately be sync too? + +**Why sync-blocking-on-IO is still bad even if a sync API "looks" fine:** a synchronous JSI method runs **on the JS thread**. If it blocks on network/disk/keychain, it freezes JS (UI jank / ANR) — the web SDK's sync getters do not do that because they return in-memory state. So the test is not "is the web API sync" alone; it is "is the underlying work in-memory on **both** sides". + +**The gap-analysis should produce, per candidate method, a table:** + +| Column | What to record | +|--------|----------------| +| Method | RNFB API + package | +| compare:types signal | Is it currently recorded as an async-vs-sync delta? (note: `app` registers in Phase **0.1**; other packages may still be unregistered — do not treat the config list as the full candidate set) | +| firebase-js-sdk behavior | What the web SDK actually does under the hood — **in-memory/cached** vs **deferred IO**. Cite the SDK source. | +| RNFB native behavior | What our native shell does for the same result — pure in-memory (SDK getter, parse, cached field) vs real IO (network, disk, keychain, Play Services). | +| Verdict | `convert` (both in-memory) / `keep-async` (either side does real IO) / `needs-native-change` (web is in-memory but our native is needlessly IO and could be made in-memory) | + +**Candidate sources:** the `compare:types` async-vs-sync entries **plus** a manual sweep of `Promise`-returning methods whose firebase-js-sdk equivalent is sync but which `compare:types` does not flag (e.g. unregistered packages or utils-only exports). The third verdict (`needs-native-change`) is the interesting one the user raised: cases where we are async only because our native implementation chose IO, not because the operation requires it. + +**Defer the actual inventory** — this section is the brief for it. + +--- + +## Phase E: shared-state encapsulation (optional) + +**Optional post-break cleanup.** Decision owner: [NewArch-AD-10](architecture-decisions.md#newarch-ad-10--cross-package-native-state-is-centralized-in-app-with-testable-apis--accepted). Does **not** gate the coordinated major. + +**Goal:** refactor the un-encapsulated cross-package shared-state items — bare `public static` fields read across packages — behind explicit, testable `app`-owned accessor methods, and audit that all inter-module state is genuinely centralized in `app` (not duplicated per package). + +**Candidate state (from NewArch-AD-10):** `authDomains` / iOS `customAuthDomains`; and a survey of `ReactNativeFirebaseJSON` / `Meta` / `Preferences` / `UniversalFirebasePreferences` access patterns for anything that is a bare cross-package static rather than a method. + +**Per-item loop:** standard [phase iteration protocol](#phase-iteration-protocol) (gap-analysis to inventory the statics + their readers → implementation to add accessors and migrate readers → independent-review → commit). Pure native refactor with no public API change; **area-focused** tier on the affected packages (`app` + each reader, e.g. `auth`). One commit per encapsulated item or per package, maintainer discretion. + +**Completion signal:** no bare cross-package `public static` mutable shared state remains; every cross-package read goes through an `app`-owned accessor with a unit test. + +--- + +## Phase 0.1: app compare:types + +**Scope:** Register `@react-native-firebase/app` in [compare:types](../../../.github/scripts/compare-types/src/registry.ts); document all modular API deltas in [configs/app.ts](../../../.github/scripts/compare-types/configs/app.ts); fix reasonably fixable type drift in product code. + +**Not in scope:** Phase S async→sync conversion (`registerVersion`, etc.) — document only unless trivial. + +**Loop:** standard [phase iteration protocol](#phase-iteration-protocol) — `gap-analysis` (compare output) → `implementation` (config + type fixes) → `independent-review` (`yarn compare:types` green for `app`) → `commit`. + +**Completion signal:** `yarn compare:types` reports zero undocumented differences for package `app`. + +**Planned commit subject:** `test(app): add app module type comparison config` --- @@ -168,7 +254,7 @@ Each package (or one legacy module within a multi-module package) follows **one* |------|-----------|-------------|-------| | **1** | `gap-analysis` | — | Spec inventory + feasibility; read-only when export shape unclear | | **2** | `baseline-capture` | — | Optional area-focused e2e baseline before large packages | -| **3** | `implementation` | `implementation` | Spec, codegen, native, JS; Jest + **unit-focused** tier; `.only` / area narrowing OK locally; **no commit** | +| **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 | @@ -181,23 +267,26 @@ Skip steps 1–2 when spec shape is known (most Tier D packages). ## Current snapshot -**Label:** `planning`; **harness:** not started +**Label:** `phase-0-committed`; **harness:** full (committed defaults) + +**Next item:** Phase **0.1** `app` compare:types — **implementation** -**Next item:** Maintainer review of this queue + [implementation workflow](turbomodule-implementation-workflow.md) → Phase **0** pickup. +**Current gates:** Phase 0 all **closed** · Phase 0.1 all **open** **Arbiter gate:** -| Item | Code | `implementation_gate` | `review_gate` | `next_work_type` | `validation_tier` | Notes | -|------|------|----------------------|---------------|------------------|-------------------|-------| -| Phase 0 `app` | — | — | — | — | — | blocked on queue approval | +| Item | Code | `implementation_gate` | `review_gate` | `commit_gate` | `next_work_type` | `validation_tier` | `commit_subject` | Notes | +|------|------|----------------------|---------------|---------------|------------------|-------------------|------------------|-------| +| Design review | DR | n/a | n/a | n/a | done | none | none | ✅ Adversarial review complete. | +| Phase 0 `app` TurboModules | P0 | **closed** | **closed** | **closed** | done | `full` | `feat(app): migrate app modules to TurboModules incl general migration infra` | Committed 2026-06-30. | +| Phase 0.1 `app` compare:types | P0.1 | **open** | **open** | **open** | `implementation` | `none` | `test(app): add app module type comparison config` | Queued after P0. | --- ## Harness -- **Push state (committed):** full test app — all `platformSupportedModules` + `require.context` in `tests/app.js`. For CI / Phase **R** only. -- **Local `:test-cover`:** must match arbiter `validation_tier` — [running e2e § harness + narrowing gate](../testing/running-e2e.md#harness-narrowing-gate-blocking). **`implementation` → unit-focused** and **`independent-review` → area-focused:** both require [area narrowing](turbomodule-implementation-workflow.md#turbomodule-area-harness) locally **before** first run even when git has full harness. Revert before **R** (full tier). +Local `:test-cover` harness rules: [running e2e § harness + narrowing gate](../testing/running-e2e.md#harness-narrowing-gate-blocking). Push state stays full until Phase **R**. --- diff --git a/okf-bundle/new-architecture/turbomodule-implementation-workflow.md b/okf-bundle/new-architecture/turbomodule-implementation-workflow.md index ccda2608e3..4430bcb8ec 100644 --- a/okf-bundle/new-architecture/turbomodule-implementation-workflow.md +++ b/okf-bundle/new-architecture/turbomodule-implementation-workflow.md @@ -17,8 +17,9 @@ Requirements for migrating **one package** (or one legacy native module within a | Topic | Document | |-------|----------| | **Change authoring loop** | [change-authoring-workflow.md](../testing/change-authoring-workflow.md) | +| **Architectural decisions (why)** | [architecture-decisions.md](architecture-decisions.md) — canonical owner; this doc is the *how* | | Live phase/gate snapshots | [migration-work-queue.md](migration-work-queue.md) | -| Locked decisions, inventory, phase order | [migration-work-queue.md](migration-work-queue.md) | +| Inventory, phase order | [migration-work-queue.md](migration-work-queue.md) | | Work types, tiers, gates | [change-authoring-workflow.md](../testing/change-authoring-workflow.md); term ids: [iteration-vocabulary.md](../testing/iteration-vocabulary.md) | | E2e commands | [running-e2e.md](../testing/running-e2e.md) | | Validation commands | [validation-checklist.md](../testing/validation-checklist.md) | @@ -35,32 +36,61 @@ In addition to [change authoring gates](../testing/change-authoring-workflow.md# | Native shell | Android `NativeRNFBTurbo*` extends generated `*Spec`; iOS spec protocol + `getTurboModule()` | | JS wiring | `nativeModuleName` → `NativeRNFBTurbo*`; `turboModule: true`; web shims via `setReactNativeModule` unchanged | | Podspec / package | New-arch guard; exclude duplicate RN generated providers (see [`RNFBFunctions.podspec`](../../../packages/functions/RNFBFunctions.podspec)) | -| Implementation | Package Jest + **unit-focused** e2e on New Architecture build | +| Implementation | Package Jest + **unit-focused** e2e on New Architecture build on **every required platform** ([platform coverage gate](../testing/running-e2e.md#platform-coverage-gate-blocking)). Native bridge / codegen / podspec / `build.gradle` touched → **blocking** before handoff; Jest-only does not close `implementation_gate`. Build or env failure keeps the gate open — handoff must include a platform matrix (exit code + pass counts + log path) or an explicit env blocker, not “Jest green”. | | Review | Package e2e **area-focused** tier on frozen tree; no `.only`; native lint rows from [validation checklist](../testing/validation-checklist.md) where touched | | Event deferral | Legacy event proxy retained unless [queue deferral discriminator](migration-work-queue.md#deferred-cleanup-phase-eventemitter) triggers escalation | ### Multi-module packages -One TurboModule spec **per legacy native module** — do not consolidate in the first pass (database ×5, firestore ×4). One focused commit per spec/module when gates close, or one commit per package when the whole package converts in a single PR — follow queue phase boundaries. +One TurboModule spec **per legacy native module** — do not consolidate the *specs* in the first pass (database ×5, firestore ×4); each legacy module keeps its own `NativeRNFBTurbo*` spec and shell. + +**Commit granularity: one commit per package, not per spec.** Splitting a multi-module package across several commits adds little value and is often impractical — the specs share `codegenConfig`, generated artifacts, podspec/`build.gradle` guards, and JS wiring that only compile and pass e2e together. Convert the whole package (all its legacy modules → all its specs) in a single `implementation` → `independent-review` → `commit` loop and land it as **one** `feat(): migrate to TurboModules` commit. Per-spec commits are only warranted if a single legacy module is genuinely independently shippable and reviewable, which is rare. Multiple specs ≠ multiple commits. + +### Multi-spec packages (`app` precedent) + +Phase 0 `app` is the first package with **two TurboModule specs in one `codegenConfig`**: `NativeRNFBTurboApp` + `NativeRNFBTurboUtils`. Modular type parity is tracked separately in [Phase 0.1](migration-work-queue.md#phase-01-app-comparetypes) (`configs/app.ts`). Single `codegenConfig.name` = the **aggregate library name** `RNFBAppTurboModules` (not a module name; decision [NewArch-AD-7](architecture-decisions.md#newarch-ad-7--codegenconfigname--aggregate-library-name-one-codegenconfig-per-package--accepted)); iOS **`modulesProvider`** maps each spec name to its ObjC shell (`RNFBAppModule`, `RNFBUtilsModule`). Android registers both shells in the package class. Method names must be unique across the package's specs ([NewArch-AD-11](architecture-decisions.md#newarch-ad-11--multi-module-method-names-are-merged-uniqueness-enforced-by-test--accepted)). Reference: [`packages/app/package.json`](../../../packages/app/package.json), [`ReactNativeFirebaseAppPackage.java`](../../../packages/app/android/src/reactnative/java/io/invertase/firebase/app/ReactNativeFirebaseAppPackage.java). ## Spec authoring (`gap-analysis` / pre-`implementation`) 1. Inventory `@ReactMethod` / `RCT_EXPORT_METHOD` from existing Java/ObjC sources. 2. Draft `specs/NativeRNFBTurbo*.ts` — strong types from `lib/types/internal.ts` and firebase-js-sdk shapes; `Object` / open maps only for genuinely dynamic payloads. -3. Naming: `NativeRNFBTurbo*` prefix (locked decision — [migration work queue § locked decisions](migration-work-queue.md#locked-decisions)). +3. Naming: `NativeRNFBTurbo*` prefix (decision [NewArch-AD-2](architecture-decisions.md#newarch-ad-2--naming-nativernfbturbo--accepted)). 4. Run `yarn codegen` in the package; commit generated output under `android/.../generated` and `ios/generated`. 5. For Phase 0 (`app`): include unified module resolver work in `packages/app` ([queue § reference pattern](migration-work-queue.md#reference-pattern-functions)). +6. **NewArch-AD-18 raw-resolver audit:** `grep` product code for `getReactNativeModule(` (exclude `packages/app/lib/internal/nativeModule*.ts` infrastructure). For each hit, compare against the [NewArch-AD-18 canonical exception table](architecture-decisions.md#canonical-exception-table): existing row → confirm turbo module name + in-code `// NewArch-AD-18 E:` comment; unlisted → bug (legacy name / should be wrapped) or new exception (add ADR row + rationale **before** merge). Every package migration PR must leave no unlisted raw call sites in that package's scope. + +### Phase 0 re-implementation must-fix checklist + +Phase 0 is a **re-implementation pass** under the matured ADRs — light in line count but necessary for correctness. Full checklist (also in [queue P0 row](migration-work-queue.md#current-snapshot)): + +| # | ADR / item | Work | +|---|------------|------| +| 1 | **NewArch-AD-7** | Rename `functions` `codegenConfig.name` → `RNFBFunctionsTurboModules`; regen + commit generated artifacts (do **first** — prevents wrong precedent for single-spec packages). Module name `NativeRNFBTurboFunctions` unchanged. | +| 2 | **NewArch-AD-9** | iOS `RNFBAppModule` + `RNFBUtilsModule`: `requiresMainQueueSetup` → `NO`. | +| 3 | **NewArch-AD-19** | Remove `methodQueue = dispatch_get_main_queue()` from both shells unless on-device validation proves a specific method needs it. | +| 4 | **NewArch-AD-14 / NewArch-AD-14a** | Replace eager wrap + flatten-onto-`{}`+`Object.freeze` with memoizing lazy Proxy + routing composite Proxy in [`nativeModule.ts`](../../../packages/app/lib/internal/registry/nativeModule.ts). Drop dead `multiModuleRoot[moduleName]` boolean flags. | +| 5 | **NewArch-AD-15** | Stop calling `getConstants()` on every resolve in `withTurboConstants`; memoize static constants only; Play Services → dynamic method (remove from utils constants typing when converted). | +| 6 | **NewArch-AD-18 E6** | Fix `messaging.isSupported()`: `NativeRNFBTurboUtils` + `androidGetPlayServicesStatus()`. | +| 7 | **NewArch-AD-18 E5, E7** | `UtilsStatics.FilePath`: memoized static utils accessor; `app/lib/modular.ts` meta/json/preferences → `getAppModule()`. | +| 8 | **NewArch-AD-13** | Harness overrides: `.gitignore` `tests/harness.overrides.js` first, then `harness.overrides.example.js` + read hook in `tests/app.js` / `tests/globals.js`. | +| 9 | **NewArch-AD-17.1** | Jest TurboModule enumeration/Proxy contract test **including 2-host merge fixture** — file [`packages/app/__tests__/nativeModuleContract.test.ts`](../../../packages/app/__tests__/nativeModuleContract.test.ts); scoped run: `yarn tests:jest -- packages/app/__tests__/nativeModuleContract.test.ts` ([ADR §17.1](architecture-decisions.md#newarch-ad-171--jest-turbomodule-contract-test--accepted)). | +| 10 | **Keep** | NewArch-AD-8 `for...in`/`Object.create`, NewArch-AD-10 `authDomains` centralization, `tests/globals.js` `NativeRNFBTurbo*` proxy (E4). | + +**Out of scope for Phase 0 (deferred):** NewArch-AD-18 E8–E10 (firestore/database/pnv until those packages migrate); dead legacy Java shells; iOS `customAuthDomains` rename. ## TurboModule `implementation` Per package, repeat the [`functions`](../../../packages/functions/) shape: 1. **`specs/NativeRNFBTurbo*.ts`** — extends `TurboModule`. -2. **`package.json` `codegenConfig`** — `jsSrcsDir: "specs"`, android `javaPackageName`, ios `modulesProvider`. -3. **Android** — `NativeRNFBTurbo*` extends generated `*Spec`; register in package class. -4. **iOS** — `.mm` implements spec; `- (std::shared_ptr)getTurboModule:` returns generated JSI class. -5. **JS** — update namespace config; no public API changes unless unavoidable. -6. **Native business logic** — prefer keeping ObjC++/Java shell + existing Swift helpers; language modernization is out of scope ([queue rationale](migration-work-queue.md#reference-pattern-functions)). +2. **`package.json` `codegenConfig`** — `jsSrcsDir: "specs"`, android `javaPackageName`, ios `modulesProvider` (one entry per spec; see [multi-spec packages](#multi-spec-packages-app-precedent)). +3. **Android codegen wiring** — `react-native.config.js` → `platforms.android.cmakeListsPath` pointing at the **committed** generated JNI `CMakeLists.txt` (app package path differs from [`functions`](../../../packages/functions/react-native.config.js): under `src/reactnative/java/.../generated/jni/`). After `yarn codegen`, verify CMake uses the compile macro for the monorepo React Native version: **`target_compile_options`** on RN **0.78** (current test app), **`target_compile_reactnative_options`** on RN **0.81+** (current `@react-native/codegen` default). + + **Forward compatibility:** this is **not** a permanent fork. The committed generated `CMakeLists.txt` is reproduced by `yarn codegen` against whatever `@react-native/codegen` the monorepo resolves — when the test app moves to RN 0.81+, re-running codegen emits `target_compile_reactnative_options` and the artifact updates with it. There is no hand-maintained macro choice: the macro only has to match the RN version that generated it, and `functions` already proves the same pipeline regenerates cleanly across versions. Treat a macro mismatch as a *stale committed artifact* (re-run codegen), not as a code change to maintain. +4. **Android** — `NativeRNFBTurbo*` extends generated `*Spec`; register in package class. +5. **iOS** — `.mm` implements spec; `- (std::shared_ptr)getTurboModule:` returns generated JSI class. +6. **JS** — update namespace config; no public API changes unless unavoidable. +7. **Native business logic** — prefer keeping ObjC++/Java shell + existing Swift helpers; language modernization is out of scope ([queue rationale](migration-work-queue.md#reference-pattern-functions)). **Unit-focused** tier per [change authoring § implementation inner loop](../testing/change-authoring-workflow.md#implementation-inner-loop) and [TurboModule area harness](#turbomodule-area-harness) below. @@ -81,7 +111,7 @@ On a **frozen tree** — full [change authoring § independent-review](../testin Extends [change authoring § harness narrowing](../testing/change-authoring-workflow.md#harness-narrowing). -**Area setup (required for `unit-focused` and `area-focused` tiers):** narrow `tests/app.js` / `tests/globals.js` to the package under migration — load only that package's `platformSupportedModules` entry and its `packages//e2e/*.e2e.js` specs. +**Area setup (required for `unit-focused` and `area-focused` tiers):** copy [`tests/harness.overrides.example.js`](../../../tests/harness.overrides.example.js) to gitignored `tests/harness.overrides.js` — set `modules` to the package under migration and `RNFBDebug: true`. Load that package's full `packages//e2e/*.e2e.js` specs via committed `require.context` ([running e2e § local overrides](../testing/running-e2e.md#local-harness-overrides-harnessoverridesjs)). | Package | Typical e2e entry | |---------|-------------------| @@ -93,10 +123,30 @@ Extends [change authoring § harness narrowing](../testing/change-authoring-work **Sanity check:** pass counts must match loaded scope — not full-app totals ([running e2e § gate](../testing/running-e2e.md#harness-narrowing-gate-blocking)). +**TurboModule `NativeModules` proxy:** package e2e that reads turbo shells directly (e.g. [`events.e2e.js`](../../../packages/app/e2e/events.e2e.js) → `NativeModules.NativeRNFBTurboApp`) requires the harness proxy in [`tests/globals.js`](../../../tests/globals.js) to route **`NativeRNFBTurbo*`** names through [`getReactNativeModule()`](../../../packages/app/lib/internal/nativeModuleAndroidIos.ts), not only the legacy `RNF*` prefix. Without that, the proxy returns a no-op stub and event tests hang. Durable committed wiring — not part of overrides narrowing ([NewArch-AD-13](architecture-decisions.md#newarch-ad-13)). + **Push state (committed):** full test app remains default for CI. Local `:test-cover` during migration uses area narrowing even when git has full harness. **Phase R / coordinated break:** revert all narrowing; **full** tier 3-platform run before monorepo major ships ([change authoring § pre-merge-validation](../testing/change-authoring-workflow.md#work-types)). +## Phase S: sync conversion (forced-async → sync) + +Runs **after** every native package is on TurboModules (Phases 0–5), **before** [Phase R](migration-work-queue.md#phase-table). Queue rationale and scope discriminator: [migration work queue § Phase S](migration-work-queue.md#phase-s-sync-conversion-forced-async--sync). This section owns the **procedure**. + +**What it fixes:** Some RNFB methods are typed `Promise` only because the legacy bridge made every call async — firebase-js-sdk's equivalent is synchronous. TurboModules support sync JSI methods, so those return to sync parity. These deltas are visible in `compare:types` configs as async-vs-sync differences. + +**Per-package loop** (same [change authoring](../testing/change-authoring-workflow.md) work types; one focused commit per package): + +1. **`gap-analysis`** — Read the package's `compare:types` config (`.github/scripts/compare-types/configs/.ts`) for documented async-vs-sync differences. For each, apply the [scope discriminator](migration-work-queue.md#phase-s-sync-conversion-forced-async--sync): keep `Promise` if the native work has real latency (network/disk/keychain/token); only convert pure bridge-forced async. +2. **`implementation`** — Declare the spec method sync (drop `Promise`) in `specs/NativeRNFBTurbo*.ts`; re-run `yarn codegen`; update the native shell to return synchronously (no resolver); update JS (`modular.ts`) to call sync; update types in `lib/`. **Unit-focused** tier. +3. **`independent-review`** — **area-focused** tier on a frozen tree; verify no consumer-visible behavior regressions beyond the intended async→sync change. +4. **`documentation`** — Remove the now-resolved entry from the package's `compare:types` config (the difference is gone); note the API change in the migration guide for the coordinated major. +5. **`commit`** — `refactor(): return sync parity for bridge-forced async APIs` (or `feat():` if the public type change is the headline). One commit per package. + +**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. + ## TurboModule `documentation` Per package (or per phase batch), same commit when user-facing: @@ -117,14 +167,20 @@ Per package (or per phase batch), same commit when user-facing: feat(): migrate to TurboModules ``` -**Never stage:** area narrowing in `tests/app.js` / `tests/globals.js`, any `.only`. +**Never stage:** `tests/harness.overrides.js`, any `.only`, temporary sub-suite edits in `tests/app.js`. ## Gotchas -* **New Architecture only** — no dual old/new bridge; podspec old-arch guard like [`RNFBFunctions.podspec`](../../../packages/functions/RNFBFunctions.podspec). -* **Events deferred** — keep `RNFBRCTEventEmitter` / `nativeEvents` fan-out unless testing forces escalation ([queue § deferred cleanup](migration-work-queue.md#deferred-cleanup-phase-eventemitter)). +* **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`. +* **Events deferred** ([NewArch-AD-4](architecture-decisions.md#newarch-ad-4--events-deferred-to-phase-c--accepted)) — keep `RNFBRCTEventEmitter` / `nativeEvents` fan-out unless testing forces escalation. * **Swift / ObjC interop** — TurboModule shell stays ObjC++; follow functions podspec patterns for `use_frameworks!` and non-framework builds. -* **Unified resolver** — Phase 0 adds `TurboModuleRegistry.get` with `NativeModules` fallback in `packages/app`; turbo-only packages drop fallback once migrated. +* **Unified resolver** ([NewArch-AD-6](architecture-decisions.md#newarch-ad-6--unified-native-module-resolver--accepted)) — `TurboModuleRegistry.get` with `NativeModules` fallback in `packages/app`; fallback removed at Phase R. +* **`requiresMainQueueSetup` = `NO`** ([NewArch-AD-9](architecture-decisions.md#newarch-ad-9--requiresmainqueuesetup-returns-no--accepted)) — iOS shells must return `NO`; `YES` blocks sync methods and risks main-thread deadlock under TurboModules. Audit `getConstants`/init/`methodQueue` for genuine main-thread work as part of gap-analysis; dispatch only that work explicitly. +* **TurboModule JS enumeration & wrapping** ([NewArch-AD-8](architecture-decisions.md#newarch-ad-8--turbomodule-js-enumeration-forin--objectcreate--accepted) + [NewArch-AD-14](architecture-decisions.md#newarch-ad-14--native-module-wrapper-memoizing-lazy-proxy--accepted)) — prototype lazy loading means **`Object.keys` / spread / `Object.assign({}, host)` break method access** (`XYZ is not a function`). Enumerate with **`for...in`**; the module surface is a **memoizing lazy `Proxy`** (NewArch-AD-14), and multi-module packages use the **routing composite Proxy** ([NewArch-AD-14a](architecture-decisions.md#newarch-ad-14a--multi-host-merge-routing-composite-proxy-required-for-multi-module)) — **not** a flattened-onto-`{}` + `Object.freeze` object. Do not copy TurboModule hosts into `{}`. Use the wrapped surface by default; raw `getReactNativeModule` only per [NewArch-AD-18](architecture-decisions.md#newarch-ad-18--raw-vs-wrapped-resolver-policy--accepted). +* **Android cross-module native shared state** ([NewArch-AD-10](architecture-decisions.md#newarch-ad-10--cross-package-native-state-is-centralized-in-app-with-testable-apis--accepted)) — turbo shells may expose **`public static` fields** read by other packages' native code. Phase 0: **`NativeRNFBTurboApp.authDomains`** (populated on `initializeApp`; read by [`RCTConvertFirebase`](../../../packages/app/android/src/reactnative/java/io/invertase/firebase/common/RCTConvertFirebase.java) and [`ReactNativeFirebaseAuthModule`](../../../packages/auth/android/src/main/java/io/invertase/firebase/auth/ReactNativeFirebaseAuthModule.java)). Unregistered legacy bridge classes may **delegate** to the turbo shell — do not duplicate the map on legacy classes. +* **iOS auth-domain naming** — iOS keeps historical **`customAuthDomains`** + `getCustomDomain:` on the turbo shell ([`RNFBAppModule.mm`](../../../packages/app/ios/RNFBApp/RNFBAppModule.mm)); Android uses **`authDomains`** on [`NativeRNFBTurboApp`](../../../packages/app/android/src/reactnative/java/io/invertase/firebase/app/NativeRNFBTurboApp.java). Same semantics; intentional cross-platform naming carry-over. +* **Spec Promise typing (Android)** — Codegen Android methods take **`Promise` args** even when the legacy bridge was sync void. Example: Play Services helpers in [`NativeRNFBTurboUtils`](../../../packages/app/specs/NativeRNFBTurboUtils.ts) — declare `Promise` / `Promise`; native resolves the promise. +* **Dead legacy shells** — unregistered legacy Java modules (e.g. [`ReactNativeFirebaseAppModule`](../../../packages/app/android/src/reactnative/java/io/invertase/firebase/app/ReactNativeFirebaseAppModule.java)) may remain temporarily when the package registers turbo shells only. **Not a Phase 0 blocker** — track deletion as follow-on cleanup once the turbo path is verified. * **phone-number-verification** — bypasses `createModuleNamespace`; wire spec + resolver directly in `modular.ts`. Live phase status and arbiter gates: [migration work queue](migration-work-queue.md) (ephemeral). diff --git a/okf-bundle/packages/firestore/pipeline-implementation-workflow.md b/okf-bundle/packages/firestore/pipeline-implementation-workflow.md index 8b51684a2f..5b86dd681f 100644 --- a/okf-bundle/packages/firestore/pipeline-implementation-workflow.md +++ b/okf-bundle/packages/firestore/pipeline-implementation-workflow.md @@ -92,7 +92,7 @@ On a **frozen tree** — full [change authoring § independent-review](../../tes ## Pipeline area harness -Extends [change authoring § harness narrowing](../../testing/change-authoring-workflow.md#harness-narrowing). **Mechanics:** [running e2e § area harness — two platform blocks](../../testing/running-e2e.md#tests-app-js-area-harness). +Extends [change authoring § harness narrowing](../../testing/change-authoring-workflow.md#harness-narrowing). **Mechanics:** [running e2e § local harness overrides](../../testing/running-e2e.md#local-harness-overrides-harnessoverridesjs). **Area setup (required for `unit-focused` and `area-focused` tiers):** firestore-only `platformSupportedModules` with **both** `if (Platform.other)` and `if (!Platform.other)` disabled (`if (false && …)` on each) or trimmed inside each block; load `require('../packages/firestore/e2e/Pipeline.e2e.js')` or full firestore `require.context` per scope; **`RNFBDebug = true`** locally per [running e2e § fail-fast](../../testing/running-e2e.md#fail-fast-rnfbdebug-and-sub-suite-narrowing) — **never commit**. Revert **both** platform blocks before **full** tier or `commit`. diff --git a/okf-bundle/testing/agent-command-policy.md b/okf-bundle/testing/agent-command-policy.md index 63909c6a5e..63710d1e56 100644 --- a/okf-bundle/testing/agent-command-policy.md +++ b/okf-bundle/testing/agent-command-policy.md @@ -34,6 +34,7 @@ Single source for **which shell commands agents may run** in this repo. E2e is a | JS lint (implementation / review gate) | `yarn lint:js`, `yarn lint:js --fix` | package-scoped `eslint`, `npx eslint` | | Docs lint (when docs in diff) | `yarn lint:markdown`, `yarn lint:spellcheck` | ad-hoc prettier/eslint on single files | | E2e + coverage | [running e2e](running-e2e.md) — **only** `yarn tests:*` | `jet`, `npx jet`, `yarn jet`, `detox test`, `cd tests && …`, direct Metro/emulator starts | +| iOS Detox framework cache rebuild | `yarn tests:ios:detox-framework-cache:rebuild` | `cd tests && yarn detox clean-framework-cache`, `cd tests && yarn detox build-framework-cache`, bare `detox …` | | Host pre-flight (before each `:test-cover`) | [running e2e § host-clear probes](running-e2e.md#host-clear-probes) | `pgrep`, polling `:8090`, spawn probes of Jet/Detox | ### Prepare / transpile (detail) @@ -103,7 +104,8 @@ RNFB agent command policy: okf-bundle/testing/agent-command-policy.md ONLY. E2e: okf-bundle/testing/running-e2e.md yarn tests:* ONLY. Never: yarn workspace prepare, yarn jet, npx jet, cd packages/* && yarn prepare/build for diagnostics. Prepare/install: yarn or yarn lerna:prepare must exit 0 before ANY other command — never parallelize with e2e/Metro/build. -Area harness: okf-bundle/testing/running-e2e.md#tests-app-js-area-harness — edit BOTH Platform.other and !Platform.other blocks; revert both before commit. +Area harness: okf-bundle/testing/running-e2e.md#local-harness-overrides-harnessoverridesjs — copy harness.overrides.example.js to gitignored harness.overrides.js; set modules + RNFBDebug; delete overrides after run. +TurboModule contract test (NewArch-AD-17.1): packages/app/__tests__/nativeModuleContract.test.ts — yarn tests:jest -- packages/app/__tests__/nativeModuleContract.test.ts On failure: fix product code, re-run the same canonical command. ``` diff --git a/okf-bundle/testing/change-authoring-workflow.md b/okf-bundle/testing/change-authoring-workflow.md index 14d957493a..d988f8e7be 100644 --- a/okf-bundle/testing/change-authoring-workflow.md +++ b/okf-bundle/testing/change-authoring-workflow.md @@ -97,7 +97,7 @@ E2e scope, pre-flight, and harness gate: [running e2e § agent rule](running-e2e | Gate | Closes when | |------|-------------| -| `implementation` | `implementation` work type complete — code plus **unit-focused**-tier checks green; [static analysis](validation-checklist.md#lint-and-formatting) green on the diff | +| `implementation` | `implementation` work type complete — code plus **unit-focused**-tier checks green on **every required platform** when native bridge or embed path changed ([platform coverage gate](running-e2e.md#platform-coverage-gate-blocking)); [static analysis](validation-checklist.md#lint-and-formatting) green on the diff | | `review` | `independent-review` complete — **area-focused**-tier checks green on frozen tree; applicable [validation checklist](validation-checklist.md) rows green (including static analysis) | | `commit` | Durable commit exists for the item | @@ -152,7 +152,7 @@ Step detail: [running e2e § unit-focused iteration loop](running-e2e.md#unit-fo When **`unit-focused`** e2e fails and product cause is unclear: -1. Confirm [pre-flight](running-e2e.md#pre-flight-is-the-host-clear-to-start) was complete ([prepare completion gate](running-e2e.md#prepare-completion-gate-blocking) when `lib/**` changed, host-clear probes, services, area narrowing, **`RNFBDebug = true`**). +1. Confirm [pre-flight](running-e2e.md#pre-flight-is-the-host-clear-to-start) was complete ([prepare completion gate](running-e2e.md#prepare-completion-gate-blocking) when `lib/**` changed, host-clear probes, services, harness overrides, **`RNFBDebug: true`** via overrides). 2. If the **same failure repeats** on back-to-back runs with no assertion progress and the host is known clean → **sub-suite narrow** ([running e2e § fail-fast](running-e2e.md#fail-fast-rnfbdebug-and-sub-suite-narrowing)): one spec file or `describe.only` on the failing band (e.g. aggregate `count()` / `average()` / `sum()` only). Still **unit-focused**; never commit narrowing. 3. If sub-suite runs still fail without actionable assertion text → add **temporary native instrumentation** (NSLog, `adb logcat` tags, etc.) on the code path under test; use [running e2e § diagnosing hangs](running-e2e.md#diagnosing-hangs) for log commands. **Remove instrumentation before `commit`** and before **`area-focused`** gate closure on a frozen tree. 4. Do not treat Jet WS disconnect / orchestration timeout alone as product failure — [stalled run detection](running-e2e.md#stalled-run-detection) and pre-flight recovery first. @@ -173,12 +173,12 @@ Keep **`implementation`** and **`independent-review`** in separate passes ([§ f ## Harness narrowing -**Before the first `:test-cover` at `unit-focused` or `area-focused` tier:** apply package area narrowing in `tests/app.js` / `tests/globals.js` even when the branch commit has full harness. **`tests/app.js` has two platform populate blocks** — [running e2e § area harness (two platform blocks)](running-e2e.md#tests-app-js-area-harness): edit **both** `if (Platform.other)` and `if (!Platform.other)` (or disable both with Pattern A). Set **`RNFBDebug = true`** locally in `tests/globals.js` ([running e2e § fail-fast](running-e2e.md#fail-fast-rnfbdebug-and-sub-suite-narrowing)). Full app load is **`full`** tier only. +**Before the first `:test-cover` at `unit-focused` or `area-focused` tier:** create local [`tests/harness.overrides.js`](../../tests/harness.overrides.example.js) even when the branch commit has full harness — [running e2e § local harness overrides](running-e2e.md#local-harness-overrides-harnessoverridesjs). Set `modules` to the package area and **`RNFBDebug: true`**. Full app load is **`full`** tier only (delete overrides file). | Kind | `implementation` (**unit-focused**) | `independent-review` (**area-focused**) | `pre-merge-validation` (**full**) | `commit` | |------|-------------------------------------|------------------------------------------|-----------------------------------|----------| -| **Area narrowing** | Required before `:test-cover` | Required before `:test-cover` | Revert — all modules | Never | -| **`RNFBDebug = true`** | Required locally before `:test-cover` | Required locally before `:test-cover` | Revert — `false` | Never | +| **Area narrowing** | Required before `:test-cover` (overrides file) | Required before `:test-cover` | Delete overrides — all modules | Never commit overrides | +| **`RNFBDebug: true`** | Required in overrides before `:test-cover` | Required in overrides before `:test-cover` | Delete overrides / `false` | Never | | **Single-test** (`.only`) | Allowed (diagnosis) | Revert | Revert | Never | | **Single-suite** (`describe.only` / one spec file) | Allowed (diagnosis only — [escalation](#e2e-diagnosis-escalation)) | Revert | Revert | Never | @@ -189,7 +189,7 @@ Package workflows define **which module/spec** to load (e.g. Firestore → [pipe ## `commit` - One focused commit per item when gates close. -- **Never stage:** area narrowing, any `.only`, ad-hoc harness edits, or **`RNFBDebug = true`** in `tests/globals.js` ([running e2e § before merge](running-e2e.md#before-merge-pr-handoff), [platform coverage gate](running-e2e.md#platform-coverage-gate-blocking)). +- **Never stage:** `tests/harness.overrides.js`, any `.only`, temporary sub-suite edits in `tests/app.js`, or native instrumentation ([running e2e § before merge](running-e2e.md#before-merge-pr-handoff), [platform coverage gate](running-e2e.md#platform-coverage-gate-blocking)). - **Work queue:** before `git commit`, set the row's `commit_subject` to the commit's subject line, close `commit_gate`, and stage the queue doc **in the same commit** as the product change ([documentation policy § work queues](../documentation-policy.md#work-queue-documents)). Do not record SHAs in queue docs. ```bash diff --git a/okf-bundle/testing/running-e2e.md b/okf-bundle/testing/running-e2e.md index 7e075c209a..84f97d145d 100644 --- a/okf-bundle/testing/running-e2e.md +++ b/okf-bundle/testing/running-e2e.md @@ -219,15 +219,15 @@ A listener on `:8081` or `:8080` is **not** sufficient — HTTP checks must succ #### 3. Harness matches validation tier -Confirm `tests/app.js` / `tests/globals.js` match the item's **`validation_tier`** ([iteration vocabulary](iteration-vocabulary.md#work-queue-fields)), **not** the branch's committed harness. +Confirm local harness overrides (or committed files for **full** tier only) match the item's **`validation_tier`** ([iteration vocabulary](iteration-vocabulary.md#work-queue-fields)), **not** the branch's committed harness alone. | Tier | Harness before `:test-cover` | |------|------------------------------| -| **Unit-focused** (`implementation`) | **Area narrowing required** — trim modules + load only the spec under change (e.g. firestore + `Pipeline.e2e.js`); `.only` OK locally. Set **`RNFBDebug = true`** locally in `tests/globals.js` ([§ fail-fast](#fail-fast-rnfbdebug-and-sub-suite-narrowing)). | -| **Area-focused** (`independent-review`, `baseline-capture`) | **Area narrowing required** — same module/spec trim as unit-focused; load **full** spec file(s) for the package area; **no** `.only`. Set **`RNFBDebug = true`** locally ([§ fail-fast](#fail-fast-rnfbdebug-and-sub-suite-narrowing)). | -| **Full** (`pre-merge-validation`) | Revert all narrowing — full app (`require.context`, all modules); **`RNFBDebug = false`** (committed default). | +| **Unit-focused** (`implementation`) | **Area narrowing required** — [`tests/harness.overrides.js`](#local-harness-overrides-harnessoverridesjs) with `modules` + `RNFBDebug: true`; `.only` OK locally. | +| **Area-focused** (`independent-review`, `baseline-capture`) | **Area narrowing required** — same overrides file; load **full** spec file(s) for the package area; **no** `.only`; `RNFBDebug: true`. | +| **Full** (`pre-merge-validation`) | **No** `harness.overrides.js` (delete or `{}`); full app in committed `tests/app.js`; `RNFBDebug: false`. | -Committed full harness on the branch does **not** override **unit-focused** or **area-focused** tier for local runs. Package workflows define area setup (e.g. [pipelines § area harness](../packages/firestore/pipeline-implementation-workflow.md#pipeline-area-harness)). **How to edit `tests/app.js`:** [two platform blocks](#tests-app-js-area-harness). Never commit narrowing until **full** tier. +Committed full harness on the branch does **not** override **unit-focused** or **area-focused** tier for local runs. Package workflows define **which module/spec** (e.g. [pipelines § area harness](../packages/firestore/pipeline-implementation-workflow.md#pipeline-area-harness)). **How:** [local harness overrides](#local-harness-overrides-harnessoverridesjs). Never commit `harness.overrides.js`. See [Harness narrowing gate (blocking)](#harness-narrowing-gate-blocking) — a run that skips step 3 does **not** close `implementation_gate` or `review_gate`. @@ -249,17 +249,19 @@ Do not poll `pgrep`, process names, or `:8090` for *completion* ([above](#how-a- ### Harness narrowing gate (blocking) -**Both `unit-focused` and `area-focused` tiers require area narrowing in `tests/app.js` / `tests/globals.js` before the first `:test-cover`.** The only difference between those tiers is whether `.only` is allowed and whether the full package-area spec loads — not whether the harness stays at full app load. +**Both `unit-focused` and `area-focused` tiers require area narrowing before the first `:test-cover`.** The only difference between those tiers is whether `.only` is allowed and whether the full package-area spec loads — not whether the harness stays at full app load. + +**Primary mechanism:** create a local **`tests/harness.overrides.js`** (gitignored) from [`tests/harness.overrides.example.js`](../../tests/harness.overrides.example.js). Committed `tests/app.js` and `tests/globals.js` stay at full harness — do **not** edit them for module narrowing or `RNFBDebug`. See [local harness overrides](#local-harness-overrides-harnessoverridesjs). | Mistake | Symptom | Gate impact | |---------|---------|-------------| -| Run `:test-cover` on committed full harness during `implementation` or `independent-review` | macOS/iOS/Android pass counts in the **hundreds or thousands** (all modules via `require.context`) | Run is **invalid** — does not close `implementation_gate` or `review_gate` | -| Narrow **only** `if (Platform.other)` or only set initial `platformSupportedModules` while **`if (!Platform.other)`** still pushes full native list | macOS ~700 firestore tests pass; iOS/Android logs show `database`, `crashlytics`, etc.; thousands of tests / Jet WS 1006 under load | Run is **invalid** on iOS/Android — see [two platform blocks](#tests-app-js-area-harness) | -| Correct pipeline area harness | ~**100** passing per platform for `Pipeline.e2e.js` only ([pipeline workflow](../packages/firestore/pipeline-implementation-workflow.md#pipeline-area-harness)) | Expected for pipeline area runs | +| Run `:test-cover` with no overrides (full harness) during `implementation` or `independent-review` | macOS/iOS/Android pass counts in the **hundreds or thousands** (all modules via `require.context`) | Run is **invalid** — does not close `implementation_gate` or `review_gate` | +| Edit only one platform block in `tests/app.js` (legacy pattern) while the other still pushes full list | macOS ~700 firestore tests pass; iOS/Android logs show `database`, `crashlytics`, etc. | Run is **invalid** on iOS/Android — use [overrides file](#local-harness-overrides-harnessoverridesjs) instead | +| Correct area harness via overrides | Pass counts match loaded module/spec scope ([sanity table](#sanity-check-by-platform)) | Expected | -**Apply locally before every `:test-cover` at unit-focused or area-focused tier** — even when git shows the full push harness. Revert `tests/app.js` / `tests/globals.js` after the run if the branch commit keeps full harness (typical until phase **R**). +**Apply locally before every `:test-cover` at unit-focused or area-focused tier** — even when git shows the full push harness. **Remove** `tests/harness.overrides.js` (or export `{}`) after the run when the branch keeps full harness (typical until phase **R**). Never commit `harness.overrides.js`. -**Validation report must state:** harness narrowed (yes/no), which module/spec loads, whether pass counts match area scope, and **which platforms ran** with exit codes. A green full-app run is not a substitute. +**Validation report must state:** harness narrowed (yes/no), override file used (yes/no), which module/spec loads, whether pass counts match area scope, and **which platforms ran** with exit codes. A green full-app run is not a substitute. @@ -267,12 +269,12 @@ Do not poll `pgrep`, process names, or `:8090` for *completion* ([above](#how-a- **Both `unit-focused` (implementation) and `area-focused` (baseline-capture, independent-review) require e2e on every platform where the changed module loads in the committed harness** — not a subset for convenience. -Determine required platforms from `tests/app.js` ([two platform blocks](#tests-app-js-area-harness) — use **committed** lists when deciding macOS vs native requirement, not a narrowed local harness): +Determine required platforms from committed [`tests/app.js`](../../tests/app.js) platform blocks (use **committed** lists when deciding macOS vs native requirement, not a narrowed local harness): | Platform class | When required | |----------------|---------------| -| **macOS** (`Platform.other`) | Module appears in the committed `if (Platform.other)` list (or your narrowed list includes it on macOS) | -| **iOS** and **Android** | Module appears in the committed `if (!Platform.other)` list (or your narrowed list includes it on native) | +| **macOS** (`Platform.other`) | Module appears in the committed `if (Platform.other)` list (or overrides `modules` includes it) | +| **iOS** and **Android** | Module appears in the committed `if (!Platform.other)` list (or overrides `modules` includes it) | **Area-focused (`baseline-capture`, `independent-review`) — closes `review_gate` / baseline only when:** @@ -295,8 +297,8 @@ See also: [coverage design § platform parity](coverage-design.md#coverage-expec **Checklist (copy before first run):** -1. [Both platform blocks](#tests-app-js-area-harness) narrowed or disabled — not just macOS / not just initial array. -2. `platformSupportedModules` lists only the package under change (e.g. `firestore` + `app`). +1. `tests/harness.overrides.js` exists with correct `modules` (almost always include `'app'`) and `RNFBDebug: true`. +2. Overrides `modules` lists only the package under change (e.g. `['app', 'firestore']`). 3. Spec load uses direct `require` of the area spec — not `require.context` for all packages — when sub-suite narrowing applies; otherwise full package `require.context` is OK when the module list is narrowed. 4. No `.only` when tier is **area-focused**; `.only` optional when tier is **unit-focused**. 5. Grep log: pass count consistent with area scope (~100 for pipeline-only, ~700 for full firestore package on macOS), not full app (~141+ macOS baseline with full load per [work queue](../packages/firestore/pipeline-coverage-work-queue.md)). @@ -305,8 +307,8 @@ See also: [coverage design § platform parity](coverage-design.md#coverage-expec For `implementation` work type — validation tier **unit-focused** ([change authoring workflow](change-authoring-workflow.md#implementation-inner-loop)): -1. [Pre-flight](#pre-flight-is-the-host-clear-to-start) — [prepare completion gate](#prepare-completion-gate-blocking) when `lib/**` changed, [host-clear probes](#host-clear-probes), services ready, **harness narrowed** (step 3), **`RNFBDebug = true`** locally; if probes fail, [pre-flight recovery](#pre-flight-recovery) first. -2. Edit e2e/spec; add `.only` if needed; never commit narrowing. +1. [Pre-flight](#pre-flight-is-the-host-clear-to-start) — [prepare completion gate](#prepare-completion-gate-blocking) when `lib/**` changed, [host-clear probes](#host-clear-probes), services ready, **harness overrides in place** (step 3), **`RNFBDebug: true`** via overrides; if probes fail, [pre-flight recovery](#pre-flight-recovery) first. +2. Edit e2e/spec; add `.only` if needed; never commit overrides or `.only`. 3. macOS first when TS-only: `yarn tests:macos:test-cover 2>&1 | tee /tmp/rnfb-e2e-macos.log` — wait for exit code ([stalled run](#stalled-run-detection) if markers stop). 4. If macOS green and native touched: `yarn tests::build && yarn tests::test-cover 2>&1 | tee /tmp/rnfb-e2e-.log`; one platform at a time. 5. Grep log tail → fix → repeat from step 1. @@ -323,11 +325,7 @@ Never overlap runs that use `:test-cover`. See [host rule](change-authoring-work | **Clean pre-flight every run** | [Pre-flight](#pre-flight-is-the-host-clear-to-start) — [host-clear probes](#host-clear-probes), services, harness tier | | **Phase J loop** | `implementation` (Jest + **unit-focused**) → `independent-review` (**area-focused**, frozen tree) → `commit` — [work queue protocol](../packages/firestore/pipeline-coverage-work-queue.md#phase-j-iteration-protocol-strict) | -| Validation tier | E2e scope | Narrowing allowed | Typical work type | -|-----------------|-----------|-------------------|-------------------| -| **Unit-focused** | Backpressure while product code is changing | `it.only` / `describe.only` / tight area narrowing in `tests/app.js` — **never commit** | `implementation` | -| **Area-focused** | Full loaded spec(s) for the package/area under change | **Area narrowing required** in `tests/app.js` / `tests/globals.js`; **no** `.only` | `baseline-capture`, `independent-review` | -| **Full** | All modules, all platforms | None — revert all narrowing | `pre-merge-validation` | +Tier scope table: [E2e validation tiers](#e2e-validation-tiers-unit-focused-area-focused-full). Each run owns its blocking `:test-cover` and returns summaries only. @@ -367,85 +365,63 @@ Full e2e loads every package. Narrow locally; **never commit** narrowing. | Kind | Mechanism | Scope | |------|-----------|--------| -| **Area narrowing** | `tests/app.js` + `tests/globals.js` | Which modules/specs load (e.g. trim `platformSupportedModules`; `require` one spec file instead of `require.context`) | +| **Area narrowing** | [`tests/harness.overrides.js`](#local-harness-overrides-harnessoverridesjs) | Which modules load (filter `platformSupportedModules` on all platforms) | +| **Sub-suite narrowing** | Temporary edit to `tests/app.js` (`require` one spec instead of `require.context`) | Which spec files load within a module — **unit-focused diagnosis only** | | **Single-test narrowing** | `it.only(...)` | One case in a loaded file | | **Single-suite narrowing** | `describe.only(...)` | One block in a loaded file | -**Area narrowing** = `tests/app.js` / `tests/globals.js` only; not test-runner `--grep` or packager `--target`. - - - -### Area harness in `tests/app.js` (two platform blocks) +**Area narrowing** = overrides file for modules + `RNFBDebug`; not test-runner `--grep` or packager `--target`. -**Canonical owner** for how to narrow the test app. Package workflows name **which module/spec**; this section defines **how** to edit `tests/app.js` so narrowing works on **every** platform. + -#### Why two blocks +### Local harness overrides (`harness.overrides.js`) -Committed `tests/app.js` builds `platformSupportedModules` from **two separate blocks** — only one runs per platform at bundle time: +**Canonical owner** for module narrowing and fail-fast debug. Package workflows name **which module/spec**; this section defines **how** to focus the harness without editing committed files. -| Block | Runs on | Committed role | -|-------|---------|----------------| -| `if (Platform.other) { … push … }` | **macOS / Other** | Full macOS module list | -| `if (!Platform.other) { … push … }` | **iOS / Android** | Full native module list | +#### Setup -Committed shape: `const platformSupportedModules = []`, then **both** blocks push their full lists. - -**Common agent mistake:** set a narrowed initial array (e.g. `['app', 'firestore']`) but leave **`if (!Platform.other)`** pushing every native module → macOS looks narrowed (~700 firestore tests) while iOS/Android still run the **full app** (thousands of tests, unrelated modules like `database` appear in logs). That invalidates [harness narrowing gate](#harness-narrowing-gate-blocking) on native platforms. +```bash +cp tests/harness.overrides.example.js tests/harness.overrides.js +``` -#### Apply narrowing (pick one pattern) +Edit `tests/harness.overrides.js` (gitignored — never commit). Shape: -**Pattern A — initial array + disable both blocks (recommended for one area on all platforms):** +| Field | Purpose | +|-------|---------| +| `modules?: string[]` | After each platform block builds its list, filter to only these module names (works on macOS **and** iOS/Android — no dual-block edits) | +| `RNFBDebug?: boolean` | `true` = verbose RNFB logging + disabled test retries ([§ fail-fast](#fail-fast-rnfbdebug-and-sub-suite-narrowing)) | -1. Replace `const platformSupportedModules = []` with the narrowed list (almost always include `'app'`). -2. Change **both** populate blocks to `if (false && Platform.other)` and `if (false && !Platform.other)` so neither block re-expands the list. -3. Add `// TEMP: area harness — never commit` above your edits. +**Example — app package only, debug on:** ```javascript -// TEMP: firestore area harness — never commit -const platformSupportedModules = ['app', 'firestore']; - -if (false && Platform.other) { - // committed macOS list — disabled while narrowed - platformSupportedModules.push('app'); - // … -} - -if (false && !Platform.other) { - // committed iOS/Android list — disabled while narrowed - platformSupportedModules.push('app'); - // … -} +module.exports = { + RNFBDebug: true, + modules: ['app'], +}; ``` -**Pattern B — trim inside each block (when macOS and native lists must differ):** +Omit a field or export `{}` to keep committed defaults for that field. -1. Keep `const platformSupportedModules = []`. -2. Edit **`if (Platform.other)`** pushes to only the modules needed on macOS. -3. Edit **`if (!Platform.other)`** pushes to only the modules needed on iOS/Android. -4. **Both blocks must be edited** before `:test-cover` when the work item requires native platforms — editing only one block is invalid. +#### How it works -Do **not** use `if (false && Platform.other)` on one block while leaving the other block active unless that asymmetry is intentional. +Committed [`tests/app.js`](../../tests/app.js) still builds full `platformSupportedModules` per platform block. If `harness.overrides.js` exists, [`tests/globals.js`](../../tests/globals.js) reads `RNFBDebug` and `tests/app.js` filters the module list **after** the platform block runs — so one overrides file applies on every platform. #### Spec loading (optional second narrowing) -Module specs load later in `loadTests()` via `platformSupportedModules.includes('')` — usually `require.context('../packages//e2e', …)`. +Module specs load in `loadTests()` via `platformSupportedModules.includes('')` — usually `require.context('../packages//e2e', …)`. | Goal | Change | |------|--------| -| Full package area | Leave `require.context` as-is; narrowing the module list is enough | -| Single spec file | Replace `require.context` for that module with `require('../packages//e2e/.e2e.js')` ([sub-suite](#fail-fast-rnfbdebug-and-sub-suite-narrowing) — unit-focused diagnosis only unless package workflow says otherwise) | - -#### Revert before `full` tier or `commit` +| Full package area | Overrides `modules` only — leave `require.context` as-is | +| Single spec file | **Temporarily** replace `require.context` for that module with `require('../packages//e2e/.e2e.js')` in `tests/app.js` — **never commit** ([sub-suite](#fail-fast-rnfbdebug-and-sub-suite-narrowing); unit-focused diagnosis only unless package workflow says otherwise) | -Restore committed harness on **both** blocks: +#### Revert before `full` tier or commit -1. `const platformSupportedModules = []` -2. `if (Platform.other) { … }` — full macOS list, **no** `false &&` -3. `if (!Platform.other) { … }` — full native list, **no** `false &&` -4. Restore any `require.context` edits; remove `// TEMP` comments -5. Revert `tests/globals.js` (`RNFBDebug = false`) per [before merge](#before-merge-pr-handoff) +1. Delete `tests/harness.overrides.js` or set `module.exports = {}`. +2. Revert any temporary `require.context` → single `require` edits in `tests/app.js`. +3. Remove all `.only` and native instrumentation. -**Pre-flight check:** grep `tests/app.js` — if either block is `if (Platform.other)` / `if (!Platform.other)` **without** `false &&` and pushes modules outside your area, native or macOS runs are not narrowed. +Do **not** revert durable product wiring in committed `tests/globals.js` (e.g. `NativeRNFBTurbo*` proxy routing — [NewArch-AD-13](../new-architecture/architecture-decisions.md#newarch-ad-13)). #### Sanity check by platform @@ -454,9 +430,9 @@ Restore committed harness on **both** blocks: | macOS | ~**700** passing | ~**100** passing | | iOS / Android | Same order of magnitude as macOS for the same spec scope | ~**100** passing | -Pass counts in the **thousands** or unrelated suites (`database`, `crashlytics`, …) in the log → re-apply [both blocks](#tests-app-js-area-harness) and re-run. +Pass counts in the **thousands** or unrelated suites (`database`, `crashlytics`, …) in the log → confirm overrides file exists with correct `modules` and re-run. -**Area example (Pattern A):** firestore-only `platformSupportedModules` + both blocks disabled; full firestore specs via existing `require.context` in `loadTests`. +**Area example:** `modules: ['app', 'firestore']` + full firestore specs via existing `require.context`. Package-specific spec names: [Firestore pipeline harness](../packages/firestore/pipeline-implementation-workflow.md#pipeline-area-harness), [namespace removal § module area harness](../namespace-api-removal-workflow.md#module-area-harness). @@ -464,7 +440,7 @@ Package-specific spec names: [Firestore pipeline harness](../packages/firestore/ ### Fail-fast (`RNFBDebug`) and sub-suite narrowing -**`RNFBDebug`** (`tests/globals.js`): for **`unit-focused`** and **`area-focused`** tiers, set `globalThis.RNFBDebug = true` **locally before the first `:test-cover`** — not optional. It prints per-case start/finish and **disables Mocha retry/backoff**, so failures surface immediately instead of burning time on retries. **Committed default must stay `false`.** Revert to `false` with other harness edits before **`full`** tier or commit ([§ before merge](#before-merge-pr-handoff)). +**`RNFBDebug`:** for **`unit-focused`** and **`area-focused`** tiers, set **`RNFBDebug: true`** in `tests/harness.overrides.js` **before the first `:test-cover`** — not optional. It prints per-case start/finish and **disables Mocha retry/backoff**, so failures surface immediately instead of burning time on retries. Committed `tests/globals.js` default stays `false`. Remove overrides (or set `RNFBDebug: false`) before **`full`** tier or commit ([§ before merge](#before-merge-pr-handoff)). | Kind | Mechanism | When | |------|-----------|------| @@ -483,9 +459,9 @@ All tiers use [canonical commands](#rules), [host rule](change-authoring-workflo | Validation tier | E2e scope | Narrowing allowed | Typical work type | |-----------------|-----------|-------------------|-------------------| -| **Unit-focused** | Fast loop while product code is changing | `it.only` / `describe.only` / tight area narrowing in `tests/app.js` — **never commit** | `implementation` | -| **Area-focused** | Full loaded spec(s) for the package/area under change | **Area narrowing required** in `tests/app.js` / `tests/globals.js`; **no** `.only` | `baseline-capture`, `independent-review` | -| **Full** | Unfocused — all modules, all platforms | None — revert all narrowing | `pre-merge-validation` | +| **Unit-focused** | Fast loop while product code is changing | `harness.overrides.js` + optional `.only` / sub-suite `require` in `tests/app.js` — **never commit** | `implementation` | +| **Area-focused** | Full loaded spec(s) for the package/area under change | **`harness.overrides.js`** required; **no** `.only` | `baseline-capture`, `independent-review` | +| **Full** | Unfocused — all modules, all platforms | Delete overrides file — committed full harness only | `pre-merge-validation` | **Universal rules:** @@ -502,13 +478,56 @@ See also: [unit-focused-tier loop](#unit-focused-tier-iteration-loop), [dispatch - **adb empty** — `adb kill-server && adb start-server && adb devices` - **Stale processes** — one Metro (`:8081`), one emulator set (`:8080`, `:9099`, `:9000`, `:4400`, …). Stray listener on `:8090` after a run → [pre-flight recovery](#pre-flight-recovery), then restart background services with [Rules §1–2](#rules) (`yarn tests:packager:jet`, `yarn tests:emulator:start`). +### iOS Detox framework cache (blocking) + +Detox injects a prebuilt **`Detox.framework`** and XCUITest runner from a versioned cache under **`~/Library/Detox/ios/`** (hashed by Xcode version). iOS `:test-cover` / `:build` **fail before any test runs** if that cache is missing or stale (common after Xcode upgrade, first checkout, or a failed Detox postinstall). + +**Detect (from a failed iOS run log):** + +```bash +rg 'Detox\.framework could not be found' /tmp/rnfb-e2e-ios.log +``` + +Typical error (Detox prints the fix inline): + +```text +DetoxRuntimeError: .../Library/Detox/ios/framework//Detox.framework could not be found, +this means either you changed a version of Xcode or Detox postinstall script was unsuccessful. +To attempt a fix try running 'detox clean-framework-cache && detox build-framework-cache' +``` + +**Detect (proactive, before `:test-cover`):** + +```bash +test -d ~/Library/Detox/ios/framework/*/Detox.framework && echo "Detox framework cache: OK" || echo "Detox framework cache: MISSING" +``` + +**Fix (canonical — repo root):** + +```bash +yarn tests:ios:detox-framework-cache:rebuild +``` + +This runs Detox's `rebuild-framework-cache` (clean + build of both the injected Detox library and the XCUITest runner) from the `tests/` workspace. Expect ~10–30s on a warm machine; first build after Xcode change may take longer. + +**Verify cache present after rebuild:** + +```bash +ls ~/Library/Detox/ios/framework/*/Detox.framework +ls ~/Library/Detox/ios/xcuitest-runner/*/ +``` + +Then resume the normal iOS loop: [pre-flight](#pre-flight-is-the-host-clear-to-start) → `yarn tests:ios:build` (if native/JS changed) → `yarn tests:ios:test-cover`. + +CI restores the same tree from `~/Library/Detox/ios` keyed by Xcode version ([iOS workflow § Detox Framework Cache Restore](../ci-workflows/ios.md)). Local developers must rebuild when the cache is missing — it is not committed to git. + ## Diagnosing hangs **Local stalls** — see [stalled run detection](#stalled-run-detection) first (Metro `/status`, `Jet client connected` markers). **Native / device logs** (remove instrumentation before merge): -- **macOS** — `log show --predicate 'process == "io.invertase.testing"' --last 10m --style compact`; bundle errors → [other.md](../ci-workflows/other.md) +- **macOS** — `log show --predicate 'process == "io.invertase.testing"' --last 10m --style compact`; filter `com.facebook.react.log:javascript` for bundle errors. **Blank window / Jet never connects:** often `Native module NativeRNFBTurboApp is not registered` — see [TurboModule workflow § gotchas — macOS web registration](../new-architecture/turbomodule-implementation-workflow.md#gotchas). Other bundle errors → [other.md](../ci-workflows/other.md) - **iOS** — `xcrun simctl spawn booted log stream --level debug --style compact --predicate 'process == "testing"'`; silent hangs: `sample ` on `testing` - **Android** — `adb logcat` (filter your tags) @@ -520,7 +539,7 @@ See also: [unit-focused-tier loop](#unit-focused-tier-iteration-loop), [dispatch Pre-merge applies once to the branch commit stream before merge/push intended for merge, not after every commit. -1. Revert all narrowing ([full tier](#e2e-validation-tiers-unit-focused-area-focused-full)): restore `tests/app.js` (`platformSupportedModules` + `require.context`), default `RNFBDebug` in `tests/globals.js`, remove all `.only`, remove native instrumentation. +1. Remove all narrowing ([full tier](#e2e-validation-tiers-unit-focused-area-focused-full)): delete `tests/harness.overrides.js` (or `{}`), revert any temporary `require.context` → single `require` edits in `tests/app.js`, remove all `.only`, remove native instrumentation. Committed `tests/globals.js` / `tests/app.js` stay at full harness defaults — do not revert durable product wiring (e.g. `NativeRNFBTurbo*` proxy). 2. [Pre-flight](#pre-flight-is-the-host-clear-to-start) — [host-clear probes](#host-clear-probes) pass before each platform run. 3. Rebuild if needed (`tests::build`; `yarn lerna:prepare` for `lib/**`). 4. Full unfocused suite with coverage on **iOS, Android, macOS** — one platform at a time, all green. diff --git a/okf-bundle/testing/validation-checklist.md b/okf-bundle/testing/validation-checklist.md index 8a4a45cb5f..7c473aa23d 100644 --- a/okf-bundle/testing/validation-checklist.md +++ b/okf-bundle/testing/validation-checklist.md @@ -20,8 +20,8 @@ Work types and tiers: [change authoring workflow](change-authoring-workflow.md). |-----------|--------|-----------| | `gap-analysis` | `compare:types`, config read, SDK declarations | n/a | | `baseline-capture` | Full loaded spec(s) + e2e on [**every required platform**](running-e2e.md#platform-coverage-gate-blocking) | **area-focused** tier; [area narrowing required](running-e2e.md#harness-narrowing-gate-blocking); no `.only`, no `:test-cover-reuse`; **no platform shortcuts** | -| `implementation` | Unit-focused Jest + e2e on required platforms when native/TS path needs it | **unit-focused** tier; [area narrowing + RNFBDebug=true locally](running-e2e.md#fail-fast-rnfbdebug-and-sub-suite-narrowing) before `:test-cover`; optional `.only` / sub-suite for diagnosis; [platform coverage gate](running-e2e.md#platform-coverage-gate-blocking) when module loads on iOS and Android | -| `independent-review` | Full checklist; e2e on **every required platform** (macOS / iOS / Android per harness) | **area-focused** tier; [platform coverage gate](running-e2e.md#platform-coverage-gate-blocking) — **no shortcuts**; [frozen tree](change-authoring-workflow.md#frozen-tree); never commit narrowing, sub-suite `.only`, or `RNFBDebug = true` ([fail-fast §](running-e2e.md#fail-fast-rnfbdebug-and-sub-suite-narrowing)) | +| `implementation` | Unit-focused Jest + e2e on **every required platform** when native bridge, iOS/Android embed, or macOS TS/runtime path changed — **Jest-only does not close `implementation_gate`** | **unit-focused** tier; [harness overrides + RNFBDebug](running-e2e.md#local-harness-overrides-harnessoverridesjs) before `:test-cover`; optional `.only` / sub-suite for diagnosis; [platform coverage gate](running-e2e.md#platform-coverage-gate-blocking) — no platform shortcuts | +| `independent-review` | Full checklist; e2e on **every required platform** (macOS / iOS / Android per harness) | **area-focused** tier; [platform coverage gate](running-e2e.md#platform-coverage-gate-blocking) — **no shortcuts**; [frozen tree](change-authoring-workflow.md#frozen-tree); never commit overrides, sub-suite `.only`, or temporary `tests/app.js` edits ([fail-fast §](running-e2e.md#fail-fast-rnfbdebug-and-sub-suite-narrowing)) | | `pre-merge-validation` | Full unfocused suite | **full** tier — [running-e2e § merge](running-e2e.md#before-merge-pr-handoff); entire PR branch, once | ## Prepare and compile @@ -118,6 +118,7 @@ Goal: each iteration improves OKF and removes conflicting guidance. - [ ] `yarn tsc:compile`, `yarn tsc:compile:consumer` - [ ] `yarn reference:api` - [ ] `yarn tests:jest` +- [ ] TurboModule wrapper contract ([NewArch-AD-17.1](../new-architecture/architecture-decisions.md#newarch-ad-171--jest-turbomodule-contract-test--accepted)) when `packages/app/lib/internal/registry/nativeModule.ts`, `nativeModuleAndroidIos.ts`, or TurboModule wrapper behavior changed: `yarn tests:jest -- packages/app/__tests__/nativeModuleContract.test.ts` - [ ] `yarn compare:types` (stale config entries removed) - [ ] `yarn lint:js` (+ markdown/spellcheck if docs; + platform lint if native) - [ ] E2e green on **every required platform** for the changed module ([platform coverage gate](running-e2e.md#platform-coverage-gate-blocking); [harness narrowing gate](running-e2e.md#harness-narrowing-gate-blocking); no `.only`; committed `RNFBDebug` remains `false`) diff --git a/package.json b/package.json index 9589baa225..00262f967a 100644 --- a/package.json +++ b/package.json @@ -54,6 +54,7 @@ "tests:android:test:jacoco-report": "cd tests/android && ./gradlew jacocoAndroidTestReport", "tests:ios:build": "cd tests && yarn detox build --configuration ios.sim.debug", "tests:ios:build:release": "cd tests && yarn detox build --configuration ios.sim.release", + "tests:ios:detox-framework-cache:rebuild": "cd tests && yarn detox rebuild-framework-cache", "tests:ios:manual": "cd tests && SIMCTL_CHILD_GULGeneratedClassDisposeDisabled=1 CC=clang CPLUSPLUS=clang++ LD=clang LDPLUSPLUS=clang++ yarn react-native run-ios", "tests:ios:test": "cd tests && SIMCTL_CHILD_GULGeneratedClassDisposeDisabled=1 yarn detox test --configuration ios.sim.debug --loglevel warn", "tests:ios:test:release": "cd tests && SIMCTL_CHILD_GULGeneratedClassDisposeDisabled=1 yarn detox test --configuration ios.sim.release --loglevel warn", diff --git a/packages/app/RNFBApp.podspec b/packages/app/RNFBApp.podspec index 0f8ca1d42c..7794b7eee4 100644 --- a/packages/app/RNFBApp.podspec +++ b/packages/app/RNFBApp.podspec @@ -22,20 +22,14 @@ Pod::Spec.new do |s| s.macos.deployment_target = firebase_macos_target s.tvos.deployment_target = firebase_tvos_target s.cocoapods_version = '>= 1.12.0' - s.source_files = "ios/**/*.{h,m}" + s.source_files = "ios/**/*.{h,m,mm,cpp}" + s.private_header_files = "ios/**/*.h" + s.exclude_files = 'ios/generated/RCTThirdPartyComponentsProvider.*', 'ios/generated/RCTAppDependencyProvider.*', 'ios/generated/RCTModuleProviders.*', 'ios/generated/RCTModulesConformingToProtocolsProvider.*', 'ios/generated/RCTUnstableModulesRequiringMainQueueSetupProvider.*' - # Deprecation message for old architecture users - # - safely in case the variable goes away completely in future react-native versions - # - suppressable in case people need to - if ( - defined?(ENV["RCT_NEW_ARCH_ENABLED"]) != nil && - ENV["RCT_NEW_ARCH_ENABLED"] == '0' && - ENV["RNFB_SUPPRESS_NEW_ARCHITECTURE_WARNING"] != '1' - ) - Pod::UI.puts '[react-native-firebase] '.yellow + "Legacy Architecture support is deprecated for all modules" - Pod::UI.puts '[react-native-firebase] '.yellow + "New Architecture support is already required for some modules" - Pod::UI.puts '[react-native-firebase] '.yellow + "all modules will require it in the future." - Pod::UI.puts '[react-native-firebase] '.yellow + "Suppress this with environment variable RNFB_SUPPRESS_NEW_ARCHITECTURE_WARNING=1" + # Fail fast for old architecture users, but safely in case the variable goes away + # completely in future react-native versions + if defined?(ENV["RCT_NEW_ARCH_ENABLED"]) != nil && (ENV["RCT_NEW_ARCH_ENABLED"] == '0') + raise "#{s.name} requires New Architecture. Enable New Architecture to use this module" end # App must define modules for static framework integration of other packages to work diff --git a/packages/app/__tests__/nativeModuleContract.test.ts b/packages/app/__tests__/nativeModuleContract.test.ts new file mode 100644 index 0000000000..a1f938f637 --- /dev/null +++ b/packages/app/__tests__/nativeModuleContract.test.ts @@ -0,0 +1,112 @@ +import { describe, expect, it, jest } from '@jest/globals'; +import { TurboModuleRegistry } from 'react-native'; +import FirebaseModule from '../lib/internal/FirebaseModule'; +import type { ModuleConfig } from '../lib/internal'; +import { getNativeModule } from '../lib/internal/registry/nativeModule'; +import type { WrappedNativeModule } from '../lib/internal/NativeModules'; + +function createTurboModuleFixture( + methods: Record, + constants: Record = {}, +): Record { + const proto = Object.create(Object.prototype, { + getConstants: { + value: () => constants, + enumerable: true, + }, + }); + + for (const [name, fn] of Object.entries(methods)) { + Object.defineProperty(proto, name, { + value: fn, + enumerable: true, + configurable: true, + }); + } + + return Object.create(proto); +} + +describe('TurboModule wrapper contract (NewArch-AD-17.1)', function () { + it('models TurboModule host: methods non-own on prototype, Object.keys(raw) === []', function () { + const methodA = jest.fn(() => 'a'); + const raw = createTurboModuleFixture({ methodA }, { CONSTANT: 'x' }); + + expect(Object.keys(raw)).toEqual([]); + expect(typeof raw.methodA).toBe('function'); + expect(Object.prototype.hasOwnProperty.call(raw, 'methodA')).toBe(false); + expect((raw.getConstants as () => Record)().CONSTANT).toBe('x'); + }); + + it('exposes every spec method callable through the real wrapper', function () { + const methodA = jest.fn(() => 'ok-a'); + const methodB = jest.fn(() => 'ok-b'); + const raw = createTurboModuleFixture({ methodA, methodB }); + + jest.mocked(TurboModuleRegistry.get).mockReturnValueOnce(raw); + + const config: ModuleConfig = { + namespace: 'contractSingle', + nativeModuleName: 'NativeRNFBTurboContractSingle', + nativeEvents: false, + hasMultiAppSupport: false, + hasCustomUrlOrRegionSupport: false, + turboModule: true, + }; + + class ContractModule extends FirebaseModule { + constructor() { + super({ name: '[DEFAULT]' } as any, config); + } + } + + const wrapped = getNativeModule(new ContractModule()) as WrappedNativeModule & { + methodA: () => string; + methodB: () => string; + }; + + expect(wrapped.methodA()).toBe('ok-a'); + expect(wrapped.methodB()).toBe('ok-b'); + expect(methodA).toHaveBeenCalledTimes(1); + expect(methodB).toHaveBeenCalledTimes(1); + expect(Object.keys(wrapped)).toContain('methodA'); + expect(Object.keys(wrapped)).toContain('methodB'); + }); + + it('routes methods through a 2-host merge composite Proxy (NewArch-AD-14a)', function () { + const hostAMethod = jest.fn(() => 'from-a'); + const hostBMethod = jest.fn(() => 'from-b'); + const hostA = createTurboModuleFixture({ methodFromA: hostAMethod }); + const hostB = createTurboModuleFixture({ methodFromB: hostBMethod }); + + jest.mocked(TurboModuleRegistry.get).mockReturnValueOnce(hostA).mockReturnValueOnce(hostB); + + const config: ModuleConfig = { + namespace: 'contractMerge', + nativeModuleName: ['NativeRNFBTurboContractA', 'NativeRNFBTurboContractB'], + nativeEvents: false, + hasMultiAppSupport: false, + hasCustomUrlOrRegionSupport: false, + turboModule: true, + }; + + class MergeModule extends FirebaseModule { + constructor() { + super({ name: '[DEFAULT]' } as any, config); + } + } + + const wrapped = getNativeModule(new MergeModule()) as WrappedNativeModule & { + methodFromA: () => string; + methodFromB: () => string; + }; + + expect(wrapped.methodFromA()).toBe('from-a'); + expect(wrapped.methodFromB()).toBe('from-b'); + expect(hostAMethod).toHaveBeenCalledTimes(1); + expect(hostBMethod).toHaveBeenCalledTimes(1); + expect('methodFromA' in wrapped).toBe(true); + expect('methodFromB' in wrapped).toBe(true); + expect(Object.keys(wrapped).sort()).toEqual(['methodFromA', 'methodFromB']); + }); +}); diff --git a/packages/app/android/build.gradle b/packages/app/android/build.gradle index 1f1e8a06fb..5b8e2eefa5 100644 --- a/packages/app/android/build.gradle +++ b/packages/app/android/build.gradle @@ -92,6 +92,7 @@ android { sourceSets { main { java.srcDirs = ['src/main/java', 'src/reactnative/java'] + java.excludes = ['**/generated/jni/**'] } } } @@ -132,12 +133,16 @@ def isNewArchitectureDisabled() { return project.hasProperty("newArchEnabled") && project.newArchEnabled != "true" } -if (isNewArchitectureDisabled() && System.getenv('RNFB_SUPPRESS_NEW_ARCHITECTURE_WARNING') != 1) { - def ANSI_YELLOW = "\u001B[33m"; +if (isNewArchitectureDisabled()) { + def ANSI_RED = "\u001B[31m"; def ANSI_RESET = "\u001B[0m"; - println(ANSI_YELLOW + " [react-native-firebase] Legacy Architecture support is deprecated for all modules") - println(ANSI_YELLOW + " [react-native-firebase] New Architecture support is already required for some modules") - println(ANSI_YELLOW + " [react-native-firebase] all modules will require it in the future.") - println(ANSI_YELLOW + " [react-native-firebase] Suppress this with environment variable RNFB_SUPPRESS_NEW_ARCHITECTURE_WARNING=1" + ANSI_RESET) + println("\n\n\n") + println(ANSI_RED + "**************************************************************************************************************") + println("\n\n\n") + println("New Architecture support is required for @react-native-firebase/app") + println("\n\n\n") + println("**************************************************************************************************************" + ANSI_RESET) + println("\n\n\n") + System.exit(1) } diff --git a/packages/app/android/src/reactnative/java/io/invertase/firebase/app/NativeRNFBTurboApp.java b/packages/app/android/src/reactnative/java/io/invertase/firebase/app/NativeRNFBTurboApp.java new file mode 100644 index 0000000000..af52527362 --- /dev/null +++ b/packages/app/android/src/reactnative/java/io/invertase/firebase/app/NativeRNFBTurboApp.java @@ -0,0 +1,188 @@ +package io.invertase.firebase.app; + +/* + * Copyright (c) 2016-present Invertase Limited & Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this library except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import android.util.Log; +import com.facebook.fbreact.specs.NativeRNFBTurboAppSpec; +import com.facebook.react.bridge.Promise; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReadableMap; +import com.facebook.react.bridge.WritableMap; +import com.google.firebase.FirebaseApp; +import io.invertase.firebase.common.RCTConvertFirebase; +import io.invertase.firebase.common.ReactNativeFirebaseEvent; +import io.invertase.firebase.common.ReactNativeFirebaseEventEmitter; +import io.invertase.firebase.common.ReactNativeFirebaseJSON; +import io.invertase.firebase.common.ReactNativeFirebaseMeta; +import io.invertase.firebase.common.ReactNativeFirebasePreferences; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class NativeRNFBTurboApp extends NativeRNFBTurboAppSpec { + private static final String TAG = "App"; + + public static Map authDomains = new HashMap<>(); + + NativeRNFBTurboApp(ReactApplicationContext reactContext) { + super(reactContext); + } + + @Override + public void initialize() { + super.initialize(); + ReactNativeFirebaseEventEmitter.getSharedInstance() + .attachReactContext(getReactApplicationContext()); + } + + @Override + protected Map getTypedExportedConstants() { + Map constants = new HashMap<>(); + List> appsList = new ArrayList<>(); + List firebaseApps = FirebaseApp.getApps(getReactApplicationContext()); + + for (FirebaseApp app : firebaseApps) { + appsList.add(RCTConvertFirebase.firebaseAppToMap(app)); + } + + constants.put("NATIVE_FIREBASE_APPS", appsList); + constants.put("FIREBASE_RAW_JSON", ReactNativeFirebaseJSON.getSharedInstance().getRawJSON()); + + return constants; + } + + @Override + public void initializeApp(ReadableMap options, ReadableMap appConfig, Promise promise) { + FirebaseApp firebaseApp = + RCTConvertFirebase.readableMapToFirebaseApp( + options, appConfig, getReactApplicationContext()); + NativeRNFBTurboApp.configureAuthDomain( + appConfig.getString("name"), options.getString("authDomain")); + + WritableMap firebaseAppMap = RCTConvertFirebase.firebaseAppToWritableMap(firebaseApp); + promise.resolve(firebaseAppMap); + } + + public static void configureAuthDomain(String name, String authDomain) { + if (authDomain != null) { + Log.d(TAG, name + " custom authDomain " + authDomain); + authDomains.put(name, authDomain); + } else { + authDomains.remove(name); + } + } + + @Override + public void setAutomaticDataCollectionEnabled(String appName, boolean enabled) { + FirebaseApp firebaseApp = FirebaseApp.getInstance(appName); + firebaseApp.setDataCollectionDefaultEnabled(enabled); + } + + @Override + public void deleteApp(String appName, Promise promise) { + FirebaseApp firebaseApp = FirebaseApp.getInstance(appName); + + if (firebaseApp != null) { + firebaseApp.delete(); + } + + promise.resolve(null); + } + + @Override + public void eventsNotifyReady(boolean ready) { + ReactNativeFirebaseEventEmitter emitter = ReactNativeFirebaseEventEmitter.getSharedInstance(); + emitter.notifyJsReady(ready); + } + + @Override + public void eventsGetListeners(Promise promise) { + ReactNativeFirebaseEventEmitter emitter = ReactNativeFirebaseEventEmitter.getSharedInstance(); + promise.resolve(emitter.getListenersMap()); + } + + @Override + public void eventsPing(String eventName, ReadableMap eventBody, Promise promise) { + ReactNativeFirebaseEventEmitter emitter = ReactNativeFirebaseEventEmitter.getSharedInstance(); + emitter.sendEvent( + new ReactNativeFirebaseEvent( + eventName, RCTConvertFirebase.readableMapToWritableMap(eventBody))); + promise.resolve(RCTConvertFirebase.readableMapToWritableMap(eventBody)); + } + + @Override + public void eventsAddListener(String eventName) { + ReactNativeFirebaseEventEmitter emitter = ReactNativeFirebaseEventEmitter.getSharedInstance(); + emitter.addListener(eventName); + } + + @Override + public void eventsRemoveListener(String eventName, boolean all) { + ReactNativeFirebaseEventEmitter emitter = ReactNativeFirebaseEventEmitter.getSharedInstance(); + emitter.removeListener(eventName, all); + } + + @Override + public void addListener(String eventName) { + // Keep: Required for RN built in Event Emitter Calls. + } + + @Override + public void removeListeners(double count) { + // Keep: Required for RN built in Event Emitter Calls. + } + + @Override + public void metaGetAll(Promise promise) { + promise.resolve(ReactNativeFirebaseMeta.getSharedInstance().getAll()); + } + + @Override + public void jsonGetAll(Promise promise) { + promise.resolve(ReactNativeFirebaseJSON.getSharedInstance().getAll()); + } + + @Override + public void preferencesSetBool(String key, boolean value, Promise promise) { + ReactNativeFirebasePreferences.getSharedInstance().setBooleanValue(key, value); + promise.resolve(null); + } + + @Override + public void preferencesSetString(String key, String value, Promise promise) { + ReactNativeFirebasePreferences.getSharedInstance().setStringValue(key, value); + promise.resolve(null); + } + + @Override + public void preferencesGetAll(Promise promise) { + promise.resolve(ReactNativeFirebasePreferences.getSharedInstance().getAll()); + } + + @Override + public void preferencesClearAll(Promise promise) { + ReactNativeFirebasePreferences.getSharedInstance().clearAll(); + promise.resolve(null); + } + + @Override + public void setLogLevel(String logLevel) { + // Android uses Firebase SDK log level via manifest; no-op at runtime. + } +} diff --git a/packages/app/android/src/reactnative/java/io/invertase/firebase/app/ReactNativeFirebaseAppModule.java b/packages/app/android/src/reactnative/java/io/invertase/firebase/app/ReactNativeFirebaseAppModule.java index bc9918f8dc..7efc7cfef7 100644 --- a/packages/app/android/src/reactnative/java/io/invertase/firebase/app/ReactNativeFirebaseAppModule.java +++ b/packages/app/android/src/reactnative/java/io/invertase/firebase/app/ReactNativeFirebaseAppModule.java @@ -17,7 +17,6 @@ * */ -import android.util.Log; import com.facebook.react.bridge.Promise; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactMethod; @@ -39,8 +38,6 @@ public class ReactNativeFirebaseAppModule extends ReactNativeFirebaseModule { private static final String TAG = "App"; - public static Map authDomains = new HashMap<>(); - ReactNativeFirebaseAppModule(ReactApplicationContext reactContext) { super(reactContext, TAG); } @@ -63,12 +60,7 @@ public void initializeApp(ReadableMap options, ReadableMap appConfig, Promise pr } public static void configureAuthDomain(String name, String authDomain) { - if (authDomain != null) { - Log.d(TAG, name + " custom authDomain " + authDomain); - authDomains.put(name, authDomain); - } else { - authDomains.remove(name); - } + NativeRNFBTurboApp.configureAuthDomain(name, authDomain); } @ReactMethod diff --git a/packages/app/android/src/reactnative/java/io/invertase/firebase/app/ReactNativeFirebaseAppPackage.java b/packages/app/android/src/reactnative/java/io/invertase/firebase/app/ReactNativeFirebaseAppPackage.java index fe7245f39a..03b0b822ba 100644 --- a/packages/app/android/src/reactnative/java/io/invertase/firebase/app/ReactNativeFirebaseAppPackage.java +++ b/packages/app/android/src/reactnative/java/io/invertase/firebase/app/ReactNativeFirebaseAppPackage.java @@ -21,7 +21,7 @@ import com.facebook.react.bridge.NativeModule; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.uimanager.ViewManager; -import io.invertase.firebase.utils.ReactNativeFirebaseUtilsModule; +import io.invertase.firebase.utils.NativeRNFBTurboUtils; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -36,8 +36,8 @@ public List createNativeModules(@Nonnull ReactApplicationContext r ReactNativeFirebaseApp.setApplicationContext(reactContext.getApplicationContext()); } List modules = new ArrayList<>(); - modules.add(new ReactNativeFirebaseAppModule(reactContext)); - modules.add(new ReactNativeFirebaseUtilsModule(reactContext)); + modules.add(new NativeRNFBTurboApp(reactContext)); + modules.add(new NativeRNFBTurboUtils(reactContext)); return modules; } diff --git a/packages/app/android/src/reactnative/java/io/invertase/firebase/app/generated/java/com/facebook/fbreact/specs/NativeRNFBTurboAppSpec.java b/packages/app/android/src/reactnative/java/io/invertase/firebase/app/generated/java/com/facebook/fbreact/specs/NativeRNFBTurboAppSpec.java new file mode 100644 index 0000000000..a13ee58e77 --- /dev/null +++ b/packages/app/android/src/reactnative/java/io/invertase/firebase/app/generated/java/com/facebook/fbreact/specs/NativeRNFBTurboAppSpec.java @@ -0,0 +1,136 @@ + +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleJavaSpec.js + * + * @nolint + */ + +package com.facebook.fbreact.specs; + +import com.facebook.proguard.annotations.DoNotStrip; +import com.facebook.react.bridge.Promise; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReactContextBaseJavaModule; +import com.facebook.react.bridge.ReactMethod; +import com.facebook.react.bridge.ReadableMap; +import com.facebook.react.common.build.ReactBuildConfig; +import com.facebook.react.turbomodule.core.interfaces.TurboModule; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public abstract class NativeRNFBTurboAppSpec extends ReactContextBaseJavaModule implements TurboModule { + public static final String NAME = "NativeRNFBTurboApp"; + + public NativeRNFBTurboAppSpec(ReactApplicationContext reactContext) { + super(reactContext); + } + + @Override + public @Nonnull String getName() { + return NAME; + } + + protected abstract Map getTypedExportedConstants(); + + @Override + @DoNotStrip + public final @Nullable Map getConstants() { + Map constants = getTypedExportedConstants(); + if (ReactBuildConfig.DEBUG || ReactBuildConfig.IS_INTERNAL_BUILD) { + Set obligatoryFlowConstants = new HashSet<>(Arrays.asList( + "FIREBASE_RAW_JSON", + "NATIVE_FIREBASE_APPS" + )); + Set optionalFlowConstants = new HashSet<>(); + Set undeclaredConstants = new HashSet<>(constants.keySet()); + undeclaredConstants.removeAll(obligatoryFlowConstants); + undeclaredConstants.removeAll(optionalFlowConstants); + if (!undeclaredConstants.isEmpty()) { + throw new IllegalStateException(String.format("Native Module Flow doesn't declare constants: %s", undeclaredConstants)); + } + undeclaredConstants = obligatoryFlowConstants; + undeclaredConstants.removeAll(constants.keySet()); + if (!undeclaredConstants.isEmpty()) { + throw new IllegalStateException(String.format("Native Module doesn't fill in constants: %s", undeclaredConstants)); + } + } + return constants; + } + + @ReactMethod + @DoNotStrip + public abstract void initializeApp(ReadableMap options, ReadableMap appConfig, Promise promise); + + @ReactMethod + @DoNotStrip + public abstract void setAutomaticDataCollectionEnabled(String appName, boolean enabled); + + @ReactMethod + @DoNotStrip + public abstract void deleteApp(String appName, Promise promise); + + @ReactMethod + @DoNotStrip + public abstract void eventsNotifyReady(boolean ready); + + @ReactMethod + @DoNotStrip + public abstract void eventsGetListeners(Promise promise); + + @ReactMethod + @DoNotStrip + public abstract void eventsPing(String eventName, ReadableMap eventBody, Promise promise); + + @ReactMethod + @DoNotStrip + public abstract void eventsAddListener(String eventName); + + @ReactMethod + @DoNotStrip + public abstract void eventsRemoveListener(String eventName, boolean all); + + @ReactMethod + @DoNotStrip + public abstract void addListener(String eventName); + + @ReactMethod + @DoNotStrip + public abstract void removeListeners(double count); + + @ReactMethod + @DoNotStrip + public abstract void metaGetAll(Promise promise); + + @ReactMethod + @DoNotStrip + public abstract void jsonGetAll(Promise promise); + + @ReactMethod + @DoNotStrip + public abstract void preferencesSetBool(String key, boolean value, Promise promise); + + @ReactMethod + @DoNotStrip + public abstract void preferencesSetString(String key, String value, Promise promise); + + @ReactMethod + @DoNotStrip + public abstract void preferencesGetAll(Promise promise); + + @ReactMethod + @DoNotStrip + public abstract void preferencesClearAll(Promise promise); + + @ReactMethod + @DoNotStrip + public abstract void setLogLevel(String logLevel); +} diff --git a/packages/app/android/src/reactnative/java/io/invertase/firebase/app/generated/java/com/facebook/fbreact/specs/NativeRNFBTurboUtilsSpec.java b/packages/app/android/src/reactnative/java/io/invertase/firebase/app/generated/java/com/facebook/fbreact/specs/NativeRNFBTurboUtilsSpec.java new file mode 100644 index 0000000000..1f6cb833bf --- /dev/null +++ b/packages/app/android/src/reactnative/java/io/invertase/firebase/app/generated/java/com/facebook/fbreact/specs/NativeRNFBTurboUtilsSpec.java @@ -0,0 +1,94 @@ + +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleJavaSpec.js + * + * @nolint + */ + +package com.facebook.fbreact.specs; + +import com.facebook.proguard.annotations.DoNotStrip; +import com.facebook.react.bridge.Promise; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReactContextBaseJavaModule; +import com.facebook.react.bridge.ReactMethod; +import com.facebook.react.common.build.ReactBuildConfig; +import com.facebook.react.turbomodule.core.interfaces.TurboModule; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public abstract class NativeRNFBTurboUtilsSpec extends ReactContextBaseJavaModule implements TurboModule { + public static final String NAME = "NativeRNFBTurboUtils"; + + public NativeRNFBTurboUtilsSpec(ReactApplicationContext reactContext) { + super(reactContext); + } + + @Override + public @Nonnull String getName() { + return NAME; + } + + protected abstract Map getTypedExportedConstants(); + + @Override + @DoNotStrip + public final @Nullable Map getConstants() { + Map constants = getTypedExportedConstants(); + if (ReactBuildConfig.DEBUG || ReactBuildConfig.IS_INTERNAL_BUILD) { + Set obligatoryFlowConstants = new HashSet<>(Arrays.asList( + "CACHES_DIRECTORY", + "DOCUMENT_DIRECTORY", + "LIBRARY_DIRECTORY", + "MAIN_BUNDLE", + "MOVIES_DIRECTORY", + "PICTURES_DIRECTORY", + "TEMP_DIRECTORY", + "isRunningInTestLab" + )); + Set optionalFlowConstants = new HashSet<>(Arrays.asList( + "EXTERNAL_DIRECTORY", + "EXTERNAL_STORAGE_DIRECTORY", + "FILE_TYPE_DIRECTORY", + "FILE_TYPE_REGULAR" + )); + Set undeclaredConstants = new HashSet<>(constants.keySet()); + undeclaredConstants.removeAll(obligatoryFlowConstants); + undeclaredConstants.removeAll(optionalFlowConstants); + if (!undeclaredConstants.isEmpty()) { + throw new IllegalStateException(String.format("Native Module Flow doesn't declare constants: %s", undeclaredConstants)); + } + undeclaredConstants = obligatoryFlowConstants; + undeclaredConstants.removeAll(constants.keySet()); + if (!undeclaredConstants.isEmpty()) { + throw new IllegalStateException(String.format("Native Module doesn't fill in constants: %s", undeclaredConstants)); + } + } + return constants; + } + + @ReactMethod + @DoNotStrip + public abstract void androidGetPlayServicesStatus(Promise promise); + + @ReactMethod + @DoNotStrip + public abstract void androidPromptForPlayServices(Promise promise); + + @ReactMethod + @DoNotStrip + public abstract void androidResolutionForPlayServices(Promise promise); + + @ReactMethod + @DoNotStrip + public abstract void androidMakePlayServicesAvailable(Promise promise); +} diff --git a/packages/app/android/src/reactnative/java/io/invertase/firebase/app/generated/jni/CMakeLists.txt b/packages/app/android/src/reactnative/java/io/invertase/firebase/app/generated/jni/CMakeLists.txt new file mode 100644 index 0000000000..f9c2aa3646 --- /dev/null +++ b/packages/app/android/src/reactnative/java/io/invertase/firebase/app/generated/jni/CMakeLists.txt @@ -0,0 +1,36 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +cmake_minimum_required(VERSION 3.13) +set(CMAKE_VERBOSE_MAKEFILE on) + +file(GLOB react_codegen_SRCS CONFIGURE_DEPENDS *.cpp react/renderer/components/RNFBAppTurboModules/*.cpp) + +add_library( + react_codegen_RNFBAppTurboModules + OBJECT + ${react_codegen_SRCS} +) + +target_include_directories(react_codegen_RNFBAppTurboModules PUBLIC . react/renderer/components/RNFBAppTurboModules) + +target_link_libraries( + react_codegen_RNFBAppTurboModules + fbjni + jsi + # We need to link different libraries based on whether we are building rncore or not, that's necessary + # because we want to break a circular dependency between react_codegen_rncore and reactnative + reactnative +) + +target_compile_options( + react_codegen_RNFBAppTurboModules + PRIVATE + -DLOG_TAG=\"ReactNative\" + -fexceptions + -frtti + -std=c++20 + -Wall +) diff --git a/packages/app/android/src/reactnative/java/io/invertase/firebase/app/generated/jni/RNFBAppTurboModules-generated.cpp b/packages/app/android/src/reactnative/java/io/invertase/firebase/app/generated/jni/RNFBAppTurboModules-generated.cpp new file mode 100644 index 0000000000..763f2c8625 --- /dev/null +++ b/packages/app/android/src/reactnative/java/io/invertase/firebase/app/generated/jni/RNFBAppTurboModules-generated.cpp @@ -0,0 +1,170 @@ + +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleJniCpp.js + */ + +#include "RNFBAppTurboModules.h" + +namespace facebook::react { + +static facebook::jsi::Value __hostFunction_NativeRNFBTurboAppSpecJSI_getConstants(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, ObjectKind, "getConstants", "()Ljava/util/Map;", args, count, cachedMethodId); +} + +static facebook::jsi::Value __hostFunction_NativeRNFBTurboAppSpecJSI_initializeApp(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, PromiseKind, "initializeApp", "(Lcom/facebook/react/bridge/ReadableMap;Lcom/facebook/react/bridge/ReadableMap;Lcom/facebook/react/bridge/Promise;)V", args, count, cachedMethodId); +} + +static facebook::jsi::Value __hostFunction_NativeRNFBTurboAppSpecJSI_setAutomaticDataCollectionEnabled(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, VoidKind, "setAutomaticDataCollectionEnabled", "(Ljava/lang/String;Z)V", args, count, cachedMethodId); +} + +static facebook::jsi::Value __hostFunction_NativeRNFBTurboAppSpecJSI_deleteApp(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, PromiseKind, "deleteApp", "(Ljava/lang/String;Lcom/facebook/react/bridge/Promise;)V", args, count, cachedMethodId); +} + +static facebook::jsi::Value __hostFunction_NativeRNFBTurboAppSpecJSI_eventsNotifyReady(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, VoidKind, "eventsNotifyReady", "(Z)V", args, count, cachedMethodId); +} + +static facebook::jsi::Value __hostFunction_NativeRNFBTurboAppSpecJSI_eventsGetListeners(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, PromiseKind, "eventsGetListeners", "(Lcom/facebook/react/bridge/Promise;)V", args, count, cachedMethodId); +} + +static facebook::jsi::Value __hostFunction_NativeRNFBTurboAppSpecJSI_eventsPing(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, PromiseKind, "eventsPing", "(Ljava/lang/String;Lcom/facebook/react/bridge/ReadableMap;Lcom/facebook/react/bridge/Promise;)V", args, count, cachedMethodId); +} + +static facebook::jsi::Value __hostFunction_NativeRNFBTurboAppSpecJSI_eventsAddListener(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, VoidKind, "eventsAddListener", "(Ljava/lang/String;)V", args, count, cachedMethodId); +} + +static facebook::jsi::Value __hostFunction_NativeRNFBTurboAppSpecJSI_eventsRemoveListener(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, VoidKind, "eventsRemoveListener", "(Ljava/lang/String;Z)V", args, count, cachedMethodId); +} + +static facebook::jsi::Value __hostFunction_NativeRNFBTurboAppSpecJSI_addListener(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, VoidKind, "addListener", "(Ljava/lang/String;)V", args, count, cachedMethodId); +} + +static facebook::jsi::Value __hostFunction_NativeRNFBTurboAppSpecJSI_removeListeners(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, VoidKind, "removeListeners", "(D)V", args, count, cachedMethodId); +} + +static facebook::jsi::Value __hostFunction_NativeRNFBTurboAppSpecJSI_metaGetAll(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, PromiseKind, "metaGetAll", "(Lcom/facebook/react/bridge/Promise;)V", args, count, cachedMethodId); +} + +static facebook::jsi::Value __hostFunction_NativeRNFBTurboAppSpecJSI_jsonGetAll(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, PromiseKind, "jsonGetAll", "(Lcom/facebook/react/bridge/Promise;)V", args, count, cachedMethodId); +} + +static facebook::jsi::Value __hostFunction_NativeRNFBTurboAppSpecJSI_preferencesSetBool(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, PromiseKind, "preferencesSetBool", "(Ljava/lang/String;ZLcom/facebook/react/bridge/Promise;)V", args, count, cachedMethodId); +} + +static facebook::jsi::Value __hostFunction_NativeRNFBTurboAppSpecJSI_preferencesSetString(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, PromiseKind, "preferencesSetString", "(Ljava/lang/String;Ljava/lang/String;Lcom/facebook/react/bridge/Promise;)V", args, count, cachedMethodId); +} + +static facebook::jsi::Value __hostFunction_NativeRNFBTurboAppSpecJSI_preferencesGetAll(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, PromiseKind, "preferencesGetAll", "(Lcom/facebook/react/bridge/Promise;)V", args, count, cachedMethodId); +} + +static facebook::jsi::Value __hostFunction_NativeRNFBTurboAppSpecJSI_preferencesClearAll(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, PromiseKind, "preferencesClearAll", "(Lcom/facebook/react/bridge/Promise;)V", args, count, cachedMethodId); +} + +static facebook::jsi::Value __hostFunction_NativeRNFBTurboAppSpecJSI_setLogLevel(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, VoidKind, "setLogLevel", "(Ljava/lang/String;)V", args, count, cachedMethodId); +} + +NativeRNFBTurboAppSpecJSI::NativeRNFBTurboAppSpecJSI(const JavaTurboModule::InitParams ¶ms) + : JavaTurboModule(params) { + methodMap_["getConstants"] = MethodMetadata {0, __hostFunction_NativeRNFBTurboAppSpecJSI_getConstants}; + methodMap_["initializeApp"] = MethodMetadata {2, __hostFunction_NativeRNFBTurboAppSpecJSI_initializeApp}; + methodMap_["setAutomaticDataCollectionEnabled"] = MethodMetadata {2, __hostFunction_NativeRNFBTurboAppSpecJSI_setAutomaticDataCollectionEnabled}; + methodMap_["deleteApp"] = MethodMetadata {1, __hostFunction_NativeRNFBTurboAppSpecJSI_deleteApp}; + methodMap_["eventsNotifyReady"] = MethodMetadata {1, __hostFunction_NativeRNFBTurboAppSpecJSI_eventsNotifyReady}; + methodMap_["eventsGetListeners"] = MethodMetadata {0, __hostFunction_NativeRNFBTurboAppSpecJSI_eventsGetListeners}; + methodMap_["eventsPing"] = MethodMetadata {2, __hostFunction_NativeRNFBTurboAppSpecJSI_eventsPing}; + methodMap_["eventsAddListener"] = MethodMetadata {1, __hostFunction_NativeRNFBTurboAppSpecJSI_eventsAddListener}; + methodMap_["eventsRemoveListener"] = MethodMetadata {2, __hostFunction_NativeRNFBTurboAppSpecJSI_eventsRemoveListener}; + methodMap_["addListener"] = MethodMetadata {1, __hostFunction_NativeRNFBTurboAppSpecJSI_addListener}; + methodMap_["removeListeners"] = MethodMetadata {1, __hostFunction_NativeRNFBTurboAppSpecJSI_removeListeners}; + methodMap_["metaGetAll"] = MethodMetadata {0, __hostFunction_NativeRNFBTurboAppSpecJSI_metaGetAll}; + methodMap_["jsonGetAll"] = MethodMetadata {0, __hostFunction_NativeRNFBTurboAppSpecJSI_jsonGetAll}; + methodMap_["preferencesSetBool"] = MethodMetadata {2, __hostFunction_NativeRNFBTurboAppSpecJSI_preferencesSetBool}; + methodMap_["preferencesSetString"] = MethodMetadata {2, __hostFunction_NativeRNFBTurboAppSpecJSI_preferencesSetString}; + methodMap_["preferencesGetAll"] = MethodMetadata {0, __hostFunction_NativeRNFBTurboAppSpecJSI_preferencesGetAll}; + methodMap_["preferencesClearAll"] = MethodMetadata {0, __hostFunction_NativeRNFBTurboAppSpecJSI_preferencesClearAll}; + methodMap_["setLogLevel"] = MethodMetadata {1, __hostFunction_NativeRNFBTurboAppSpecJSI_setLogLevel}; +} +static facebook::jsi::Value __hostFunction_NativeRNFBTurboUtilsSpecJSI_getConstants(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, ObjectKind, "getConstants", "()Ljava/util/Map;", args, count, cachedMethodId); +} + +static facebook::jsi::Value __hostFunction_NativeRNFBTurboUtilsSpecJSI_androidGetPlayServicesStatus(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, PromiseKind, "androidGetPlayServicesStatus", "(Lcom/facebook/react/bridge/Promise;)V", args, count, cachedMethodId); +} + +static facebook::jsi::Value __hostFunction_NativeRNFBTurboUtilsSpecJSI_androidPromptForPlayServices(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, PromiseKind, "androidPromptForPlayServices", "(Lcom/facebook/react/bridge/Promise;)V", args, count, cachedMethodId); +} + +static facebook::jsi::Value __hostFunction_NativeRNFBTurboUtilsSpecJSI_androidResolutionForPlayServices(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, PromiseKind, "androidResolutionForPlayServices", "(Lcom/facebook/react/bridge/Promise;)V", args, count, cachedMethodId); +} + +static facebook::jsi::Value __hostFunction_NativeRNFBTurboUtilsSpecJSI_androidMakePlayServicesAvailable(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, PromiseKind, "androidMakePlayServicesAvailable", "(Lcom/facebook/react/bridge/Promise;)V", args, count, cachedMethodId); +} + +NativeRNFBTurboUtilsSpecJSI::NativeRNFBTurboUtilsSpecJSI(const JavaTurboModule::InitParams ¶ms) + : JavaTurboModule(params) { + methodMap_["getConstants"] = MethodMetadata {0, __hostFunction_NativeRNFBTurboUtilsSpecJSI_getConstants}; + methodMap_["androidGetPlayServicesStatus"] = MethodMetadata {0, __hostFunction_NativeRNFBTurboUtilsSpecJSI_androidGetPlayServicesStatus}; + methodMap_["androidPromptForPlayServices"] = MethodMetadata {0, __hostFunction_NativeRNFBTurboUtilsSpecJSI_androidPromptForPlayServices}; + methodMap_["androidResolutionForPlayServices"] = MethodMetadata {0, __hostFunction_NativeRNFBTurboUtilsSpecJSI_androidResolutionForPlayServices}; + methodMap_["androidMakePlayServicesAvailable"] = MethodMetadata {0, __hostFunction_NativeRNFBTurboUtilsSpecJSI_androidMakePlayServicesAvailable}; +} + +std::shared_ptr RNFBAppTurboModules_ModuleProvider(const std::string &moduleName, const JavaTurboModule::InitParams ¶ms) { + if (moduleName == "NativeRNFBTurboApp") { + return std::make_shared(params); + } + if (moduleName == "NativeRNFBTurboUtils") { + return std::make_shared(params); + } + return nullptr; +} + +} // namespace facebook::react diff --git a/packages/app/android/src/reactnative/java/io/invertase/firebase/app/generated/jni/RNFBAppTurboModules.h b/packages/app/android/src/reactnative/java/io/invertase/firebase/app/generated/jni/RNFBAppTurboModules.h new file mode 100644 index 0000000000..8f4b523751 --- /dev/null +++ b/packages/app/android/src/reactnative/java/io/invertase/firebase/app/generated/jni/RNFBAppTurboModules.h @@ -0,0 +1,39 @@ + +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleJniH.js + */ + +#pragma once + +#include +#include +#include + +namespace facebook::react { + +/** + * JNI C++ class for module 'NativeRNFBTurboApp' + */ +class JSI_EXPORT NativeRNFBTurboAppSpecJSI : public JavaTurboModule { +public: + NativeRNFBTurboAppSpecJSI(const JavaTurboModule::InitParams ¶ms); +}; + +/** + * JNI C++ class for module 'NativeRNFBTurboUtils' + */ +class JSI_EXPORT NativeRNFBTurboUtilsSpecJSI : public JavaTurboModule { +public: + NativeRNFBTurboUtilsSpecJSI(const JavaTurboModule::InitParams ¶ms); +}; + + +JSI_EXPORT +std::shared_ptr RNFBAppTurboModules_ModuleProvider(const std::string &moduleName, const JavaTurboModule::InitParams ¶ms); + +} // namespace facebook::react diff --git a/packages/app/android/src/reactnative/java/io/invertase/firebase/app/generated/jni/react/renderer/components/RNFBAppTurboModules/RNFBAppTurboModulesJSI-generated.cpp b/packages/app/android/src/reactnative/java/io/invertase/firebase/app/generated/jni/react/renderer/components/RNFBAppTurboModules/RNFBAppTurboModulesJSI-generated.cpp new file mode 100644 index 0000000000..1fab136ed3 --- /dev/null +++ b/packages/app/android/src/reactnative/java/io/invertase/firebase/app/generated/jni/react/renderer/components/RNFBAppTurboModules/RNFBAppTurboModulesJSI-generated.cpp @@ -0,0 +1,187 @@ +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleCpp.js + */ + +#include "RNFBAppTurboModulesJSI.h" + +namespace facebook::react { + +static jsi::Value __hostFunction_NativeRNFBTurboAppCxxSpecJSI_getConstants(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getConstants( + rt + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboAppCxxSpecJSI_initializeApp(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->initializeApp( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asObject(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asObject(rt) + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboAppCxxSpecJSI_setAutomaticDataCollectionEnabled(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + static_cast(&turboModule)->setAutomaticDataCollectionEnabled( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asBool() + ); + return jsi::Value::undefined(); +} +static jsi::Value __hostFunction_NativeRNFBTurboAppCxxSpecJSI_deleteApp(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->deleteApp( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt) + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboAppCxxSpecJSI_eventsNotifyReady(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + static_cast(&turboModule)->eventsNotifyReady( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asBool() + ); + return jsi::Value::undefined(); +} +static jsi::Value __hostFunction_NativeRNFBTurboAppCxxSpecJSI_eventsGetListeners(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->eventsGetListeners( + rt + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboAppCxxSpecJSI_eventsPing(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->eventsPing( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asObject(rt) + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboAppCxxSpecJSI_eventsAddListener(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + static_cast(&turboModule)->eventsAddListener( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt) + ); + return jsi::Value::undefined(); +} +static jsi::Value __hostFunction_NativeRNFBTurboAppCxxSpecJSI_eventsRemoveListener(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + static_cast(&turboModule)->eventsRemoveListener( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asBool() + ); + return jsi::Value::undefined(); +} +static jsi::Value __hostFunction_NativeRNFBTurboAppCxxSpecJSI_addListener(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + static_cast(&turboModule)->addListener( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt) + ); + return jsi::Value::undefined(); +} +static jsi::Value __hostFunction_NativeRNFBTurboAppCxxSpecJSI_removeListeners(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + static_cast(&turboModule)->removeListeners( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asNumber() + ); + return jsi::Value::undefined(); +} +static jsi::Value __hostFunction_NativeRNFBTurboAppCxxSpecJSI_metaGetAll(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->metaGetAll( + rt + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboAppCxxSpecJSI_jsonGetAll(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->jsonGetAll( + rt + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboAppCxxSpecJSI_preferencesSetBool(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->preferencesSetBool( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asBool() + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboAppCxxSpecJSI_preferencesSetString(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->preferencesSetString( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt) + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboAppCxxSpecJSI_preferencesGetAll(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->preferencesGetAll( + rt + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboAppCxxSpecJSI_preferencesClearAll(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->preferencesClearAll( + rt + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboAppCxxSpecJSI_setLogLevel(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + static_cast(&turboModule)->setLogLevel( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt) + ); + return jsi::Value::undefined(); +} + +NativeRNFBTurboAppCxxSpecJSI::NativeRNFBTurboAppCxxSpecJSI(std::shared_ptr jsInvoker) + : TurboModule("NativeRNFBTurboApp", jsInvoker) { + methodMap_["getConstants"] = MethodMetadata {0, __hostFunction_NativeRNFBTurboAppCxxSpecJSI_getConstants}; + methodMap_["initializeApp"] = MethodMetadata {2, __hostFunction_NativeRNFBTurboAppCxxSpecJSI_initializeApp}; + methodMap_["setAutomaticDataCollectionEnabled"] = MethodMetadata {2, __hostFunction_NativeRNFBTurboAppCxxSpecJSI_setAutomaticDataCollectionEnabled}; + methodMap_["deleteApp"] = MethodMetadata {1, __hostFunction_NativeRNFBTurboAppCxxSpecJSI_deleteApp}; + methodMap_["eventsNotifyReady"] = MethodMetadata {1, __hostFunction_NativeRNFBTurboAppCxxSpecJSI_eventsNotifyReady}; + methodMap_["eventsGetListeners"] = MethodMetadata {0, __hostFunction_NativeRNFBTurboAppCxxSpecJSI_eventsGetListeners}; + methodMap_["eventsPing"] = MethodMetadata {2, __hostFunction_NativeRNFBTurboAppCxxSpecJSI_eventsPing}; + methodMap_["eventsAddListener"] = MethodMetadata {1, __hostFunction_NativeRNFBTurboAppCxxSpecJSI_eventsAddListener}; + methodMap_["eventsRemoveListener"] = MethodMetadata {2, __hostFunction_NativeRNFBTurboAppCxxSpecJSI_eventsRemoveListener}; + methodMap_["addListener"] = MethodMetadata {1, __hostFunction_NativeRNFBTurboAppCxxSpecJSI_addListener}; + methodMap_["removeListeners"] = MethodMetadata {1, __hostFunction_NativeRNFBTurboAppCxxSpecJSI_removeListeners}; + methodMap_["metaGetAll"] = MethodMetadata {0, __hostFunction_NativeRNFBTurboAppCxxSpecJSI_metaGetAll}; + methodMap_["jsonGetAll"] = MethodMetadata {0, __hostFunction_NativeRNFBTurboAppCxxSpecJSI_jsonGetAll}; + methodMap_["preferencesSetBool"] = MethodMetadata {2, __hostFunction_NativeRNFBTurboAppCxxSpecJSI_preferencesSetBool}; + methodMap_["preferencesSetString"] = MethodMetadata {2, __hostFunction_NativeRNFBTurboAppCxxSpecJSI_preferencesSetString}; + methodMap_["preferencesGetAll"] = MethodMetadata {0, __hostFunction_NativeRNFBTurboAppCxxSpecJSI_preferencesGetAll}; + methodMap_["preferencesClearAll"] = MethodMetadata {0, __hostFunction_NativeRNFBTurboAppCxxSpecJSI_preferencesClearAll}; + methodMap_["setLogLevel"] = MethodMetadata {1, __hostFunction_NativeRNFBTurboAppCxxSpecJSI_setLogLevel}; +} +static jsi::Value __hostFunction_NativeRNFBTurboUtilsCxxSpecJSI_getConstants(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getConstants( + rt + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboUtilsCxxSpecJSI_androidGetPlayServicesStatus(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->androidGetPlayServicesStatus( + rt + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboUtilsCxxSpecJSI_androidPromptForPlayServices(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->androidPromptForPlayServices( + rt + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboUtilsCxxSpecJSI_androidResolutionForPlayServices(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->androidResolutionForPlayServices( + rt + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboUtilsCxxSpecJSI_androidMakePlayServicesAvailable(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->androidMakePlayServicesAvailable( + rt + ); +} + +NativeRNFBTurboUtilsCxxSpecJSI::NativeRNFBTurboUtilsCxxSpecJSI(std::shared_ptr jsInvoker) + : TurboModule("NativeRNFBTurboUtils", jsInvoker) { + methodMap_["getConstants"] = MethodMetadata {0, __hostFunction_NativeRNFBTurboUtilsCxxSpecJSI_getConstants}; + methodMap_["androidGetPlayServicesStatus"] = MethodMetadata {0, __hostFunction_NativeRNFBTurboUtilsCxxSpecJSI_androidGetPlayServicesStatus}; + methodMap_["androidPromptForPlayServices"] = MethodMetadata {0, __hostFunction_NativeRNFBTurboUtilsCxxSpecJSI_androidPromptForPlayServices}; + methodMap_["androidResolutionForPlayServices"] = MethodMetadata {0, __hostFunction_NativeRNFBTurboUtilsCxxSpecJSI_androidResolutionForPlayServices}; + methodMap_["androidMakePlayServicesAvailable"] = MethodMetadata {0, __hostFunction_NativeRNFBTurboUtilsCxxSpecJSI_androidMakePlayServicesAvailable}; +} + + +} // namespace facebook::react diff --git a/packages/app/android/src/reactnative/java/io/invertase/firebase/app/generated/jni/react/renderer/components/RNFBAppTurboModules/RNFBAppTurboModulesJSI.h b/packages/app/android/src/reactnative/java/io/invertase/firebase/app/generated/jni/react/renderer/components/RNFBAppTurboModules/RNFBAppTurboModulesJSI.h new file mode 100644 index 0000000000..2a25d7e6e9 --- /dev/null +++ b/packages/app/android/src/reactnative/java/io/invertase/firebase/app/generated/jni/react/renderer/components/RNFBAppTurboModules/RNFBAppTurboModulesJSI.h @@ -0,0 +1,606 @@ +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleH.js + */ + +#pragma once + +#include +#include + +namespace facebook::react { + + + +#pragma mark - NativeRNFBTurboAppFirebaseAppConfig + +template +struct NativeRNFBTurboAppFirebaseAppConfig { + P0 name; + P1 automaticResourceManagement; + P2 automaticDataCollectionEnabled; + bool operator==(const NativeRNFBTurboAppFirebaseAppConfig &other) const { + return name == other.name && automaticResourceManagement == other.automaticResourceManagement && automaticDataCollectionEnabled == other.automaticDataCollectionEnabled; + } +}; + +template +struct NativeRNFBTurboAppFirebaseAppConfigBridging { + static T types; + + static T fromJs( + jsi::Runtime &rt, + const jsi::Object &value, + const std::shared_ptr &jsInvoker) { + T result{ + bridging::fromJs(rt, value.getProperty(rt, "name"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, "automaticResourceManagement"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, "automaticDataCollectionEnabled"), jsInvoker)}; + return result; + } + +#ifdef DEBUG + static jsi::String nameToJs(jsi::Runtime &rt, decltype(types.name) value) { + return bridging::toJs(rt, value); + } + + static bool automaticResourceManagementToJs(jsi::Runtime &rt, decltype(types.automaticResourceManagement) value) { + return bridging::toJs(rt, value); + } + + static bool automaticDataCollectionEnabledToJs(jsi::Runtime &rt, decltype(types.automaticDataCollectionEnabled) value) { + return bridging::toJs(rt, value); + } +#endif + + static jsi::Object toJs( + jsi::Runtime &rt, + const T &value, + const std::shared_ptr &jsInvoker) { + auto result = facebook::jsi::Object(rt); + result.setProperty(rt, "name", bridging::toJs(rt, value.name, jsInvoker)); + if (value.automaticResourceManagement) { + result.setProperty(rt, "automaticResourceManagement", bridging::toJs(rt, value.automaticResourceManagement.value(), jsInvoker)); + } + if (value.automaticDataCollectionEnabled) { + result.setProperty(rt, "automaticDataCollectionEnabled", bridging::toJs(rt, value.automaticDataCollectionEnabled.value(), jsInvoker)); + } + return result; + } +}; + + + +#pragma mark - NativeRNFBTurboAppFirebaseAppOptions + +template +struct NativeRNFBTurboAppFirebaseAppOptions { + P0 apiKey; + P1 appId; + P2 databaseURL; + P3 messagingSenderId; + P4 projectId; + P5 storageBucket; + P6 authDomain; + P7 iosBundleId; + P8 iosClientId; + P9 appGroupId; + bool operator==(const NativeRNFBTurboAppFirebaseAppOptions &other) const { + return apiKey == other.apiKey && appId == other.appId && databaseURL == other.databaseURL && messagingSenderId == other.messagingSenderId && projectId == other.projectId && storageBucket == other.storageBucket && authDomain == other.authDomain && iosBundleId == other.iosBundleId && iosClientId == other.iosClientId && appGroupId == other.appGroupId; + } +}; + +template +struct NativeRNFBTurboAppFirebaseAppOptionsBridging { + static T types; + + static T fromJs( + jsi::Runtime &rt, + const jsi::Object &value, + const std::shared_ptr &jsInvoker) { + T result{ + bridging::fromJs(rt, value.getProperty(rt, "apiKey"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, "appId"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, "databaseURL"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, "messagingSenderId"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, "projectId"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, "storageBucket"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, "authDomain"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, "iosBundleId"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, "iosClientId"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, "appGroupId"), jsInvoker)}; + return result; + } + +#ifdef DEBUG + static jsi::String apiKeyToJs(jsi::Runtime &rt, decltype(types.apiKey) value) { + return bridging::toJs(rt, value); + } + + static jsi::String appIdToJs(jsi::Runtime &rt, decltype(types.appId) value) { + return bridging::toJs(rt, value); + } + + static std::optional databaseURLToJs(jsi::Runtime &rt, decltype(types.databaseURL) value) { + return bridging::toJs(rt, value); + } + + static jsi::String messagingSenderIdToJs(jsi::Runtime &rt, decltype(types.messagingSenderId) value) { + return bridging::toJs(rt, value); + } + + static jsi::String projectIdToJs(jsi::Runtime &rt, decltype(types.projectId) value) { + return bridging::toJs(rt, value); + } + + static std::optional storageBucketToJs(jsi::Runtime &rt, decltype(types.storageBucket) value) { + return bridging::toJs(rt, value); + } + + static std::optional authDomainToJs(jsi::Runtime &rt, decltype(types.authDomain) value) { + return bridging::toJs(rt, value); + } + + static std::optional iosBundleIdToJs(jsi::Runtime &rt, decltype(types.iosBundleId) value) { + return bridging::toJs(rt, value); + } + + static std::optional iosClientIdToJs(jsi::Runtime &rt, decltype(types.iosClientId) value) { + return bridging::toJs(rt, value); + } + + static std::optional appGroupIdToJs(jsi::Runtime &rt, decltype(types.appGroupId) value) { + return bridging::toJs(rt, value); + } +#endif + + static jsi::Object toJs( + jsi::Runtime &rt, + const T &value, + const std::shared_ptr &jsInvoker) { + auto result = facebook::jsi::Object(rt); + result.setProperty(rt, "apiKey", bridging::toJs(rt, value.apiKey, jsInvoker)); + result.setProperty(rt, "appId", bridging::toJs(rt, value.appId, jsInvoker)); + if (value.databaseURL) { + result.setProperty(rt, "databaseURL", bridging::toJs(rt, value.databaseURL.value(), jsInvoker)); + } + result.setProperty(rt, "messagingSenderId", bridging::toJs(rt, value.messagingSenderId, jsInvoker)); + result.setProperty(rt, "projectId", bridging::toJs(rt, value.projectId, jsInvoker)); + if (value.storageBucket) { + result.setProperty(rt, "storageBucket", bridging::toJs(rt, value.storageBucket.value(), jsInvoker)); + } + if (value.authDomain) { + result.setProperty(rt, "authDomain", bridging::toJs(rt, value.authDomain.value(), jsInvoker)); + } + if (value.iosBundleId) { + result.setProperty(rt, "iosBundleId", bridging::toJs(rt, value.iosBundleId.value(), jsInvoker)); + } + if (value.iosClientId) { + result.setProperty(rt, "iosClientId", bridging::toJs(rt, value.iosClientId.value(), jsInvoker)); + } + if (value.appGroupId) { + result.setProperty(rt, "appGroupId", bridging::toJs(rt, value.appGroupId.value(), jsInvoker)); + } + return result; + } +}; + + + +#pragma mark - NativeRNFBTurboAppNativeFirebaseApp + +template +struct NativeRNFBTurboAppNativeFirebaseApp { + P0 appConfig; + P1 options; + bool operator==(const NativeRNFBTurboAppNativeFirebaseApp &other) const { + return appConfig == other.appConfig && options == other.options; + } +}; + +template +struct NativeRNFBTurboAppNativeFirebaseAppBridging { + static T types; + + static T fromJs( + jsi::Runtime &rt, + const jsi::Object &value, + const std::shared_ptr &jsInvoker) { + T result{ + bridging::fromJs(rt, value.getProperty(rt, "appConfig"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, "options"), jsInvoker)}; + return result; + } + +#ifdef DEBUG + static jsi::Object appConfigToJs(jsi::Runtime &rt, decltype(types.appConfig) value) { + return bridging::toJs(rt, value); + } + + static jsi::Object optionsToJs(jsi::Runtime &rt, decltype(types.options) value) { + return bridging::toJs(rt, value); + } +#endif + + static jsi::Object toJs( + jsi::Runtime &rt, + const T &value, + const std::shared_ptr &jsInvoker) { + auto result = facebook::jsi::Object(rt); + result.setProperty(rt, "appConfig", bridging::toJs(rt, value.appConfig, jsInvoker)); + result.setProperty(rt, "options", bridging::toJs(rt, value.options, jsInvoker)); + return result; + } +}; + +class JSI_EXPORT NativeRNFBTurboAppCxxSpecJSI : public TurboModule { +protected: + NativeRNFBTurboAppCxxSpecJSI(std::shared_ptr jsInvoker); + +public: + virtual jsi::Object getConstants(jsi::Runtime &rt) = 0; + virtual jsi::Value initializeApp(jsi::Runtime &rt, jsi::Object options, jsi::Object appConfig) = 0; + virtual void setAutomaticDataCollectionEnabled(jsi::Runtime &rt, jsi::String appName, bool enabled) = 0; + virtual jsi::Value deleteApp(jsi::Runtime &rt, jsi::String appName) = 0; + virtual void eventsNotifyReady(jsi::Runtime &rt, bool ready) = 0; + virtual jsi::Value eventsGetListeners(jsi::Runtime &rt) = 0; + virtual jsi::Value eventsPing(jsi::Runtime &rt, jsi::String eventName, jsi::Object eventBody) = 0; + virtual void eventsAddListener(jsi::Runtime &rt, jsi::String eventName) = 0; + virtual void eventsRemoveListener(jsi::Runtime &rt, jsi::String eventName, bool all) = 0; + virtual void addListener(jsi::Runtime &rt, jsi::String eventName) = 0; + virtual void removeListeners(jsi::Runtime &rt, double count) = 0; + virtual jsi::Value metaGetAll(jsi::Runtime &rt) = 0; + virtual jsi::Value jsonGetAll(jsi::Runtime &rt) = 0; + virtual jsi::Value preferencesSetBool(jsi::Runtime &rt, jsi::String key, bool value) = 0; + virtual jsi::Value preferencesSetString(jsi::Runtime &rt, jsi::String key, jsi::String value) = 0; + virtual jsi::Value preferencesGetAll(jsi::Runtime &rt) = 0; + virtual jsi::Value preferencesClearAll(jsi::Runtime &rt) = 0; + virtual void setLogLevel(jsi::Runtime &rt, jsi::String logLevel) = 0; + +}; + +template +class JSI_EXPORT NativeRNFBTurboAppCxxSpec : public TurboModule { +public: + jsi::Value create(jsi::Runtime &rt, const jsi::PropNameID &propName) override { + return delegate_.create(rt, propName); + } + + std::vector getPropertyNames(jsi::Runtime& runtime) override { + return delegate_.getPropertyNames(runtime); + } + + static constexpr std::string_view kModuleName = "NativeRNFBTurboApp"; + +protected: + NativeRNFBTurboAppCxxSpec(std::shared_ptr jsInvoker) + : TurboModule(std::string{NativeRNFBTurboAppCxxSpec::kModuleName}, jsInvoker), + delegate_(reinterpret_cast(this), jsInvoker) {} + + +private: + class Delegate : public NativeRNFBTurboAppCxxSpecJSI { + public: + Delegate(T *instance, std::shared_ptr jsInvoker) : + NativeRNFBTurboAppCxxSpecJSI(std::move(jsInvoker)), instance_(instance) { + + } + + jsi::Object getConstants(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::getConstants) == 1, + "Expected getConstants(...) to have 1 parameters"); + + return bridging::callFromJs( + rt, &T::getConstants, jsInvoker_, instance_); + } + jsi::Value initializeApp(jsi::Runtime &rt, jsi::Object options, jsi::Object appConfig) override { + static_assert( + bridging::getParameterCount(&T::initializeApp) == 3, + "Expected initializeApp(...) to have 3 parameters"); + + return bridging::callFromJs( + rt, &T::initializeApp, jsInvoker_, instance_, std::move(options), std::move(appConfig)); + } + void setAutomaticDataCollectionEnabled(jsi::Runtime &rt, jsi::String appName, bool enabled) override { + static_assert( + bridging::getParameterCount(&T::setAutomaticDataCollectionEnabled) == 3, + "Expected setAutomaticDataCollectionEnabled(...) to have 3 parameters"); + + return bridging::callFromJs( + rt, &T::setAutomaticDataCollectionEnabled, jsInvoker_, instance_, std::move(appName), std::move(enabled)); + } + jsi::Value deleteApp(jsi::Runtime &rt, jsi::String appName) override { + static_assert( + bridging::getParameterCount(&T::deleteApp) == 2, + "Expected deleteApp(...) to have 2 parameters"); + + return bridging::callFromJs( + rt, &T::deleteApp, jsInvoker_, instance_, std::move(appName)); + } + void eventsNotifyReady(jsi::Runtime &rt, bool ready) override { + static_assert( + bridging::getParameterCount(&T::eventsNotifyReady) == 2, + "Expected eventsNotifyReady(...) to have 2 parameters"); + + return bridging::callFromJs( + rt, &T::eventsNotifyReady, jsInvoker_, instance_, std::move(ready)); + } + jsi::Value eventsGetListeners(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::eventsGetListeners) == 1, + "Expected eventsGetListeners(...) to have 1 parameters"); + + return bridging::callFromJs( + rt, &T::eventsGetListeners, jsInvoker_, instance_); + } + jsi::Value eventsPing(jsi::Runtime &rt, jsi::String eventName, jsi::Object eventBody) override { + static_assert( + bridging::getParameterCount(&T::eventsPing) == 3, + "Expected eventsPing(...) to have 3 parameters"); + + return bridging::callFromJs( + rt, &T::eventsPing, jsInvoker_, instance_, std::move(eventName), std::move(eventBody)); + } + void eventsAddListener(jsi::Runtime &rt, jsi::String eventName) override { + static_assert( + bridging::getParameterCount(&T::eventsAddListener) == 2, + "Expected eventsAddListener(...) to have 2 parameters"); + + return bridging::callFromJs( + rt, &T::eventsAddListener, jsInvoker_, instance_, std::move(eventName)); + } + void eventsRemoveListener(jsi::Runtime &rt, jsi::String eventName, bool all) override { + static_assert( + bridging::getParameterCount(&T::eventsRemoveListener) == 3, + "Expected eventsRemoveListener(...) to have 3 parameters"); + + return bridging::callFromJs( + rt, &T::eventsRemoveListener, jsInvoker_, instance_, std::move(eventName), std::move(all)); + } + void addListener(jsi::Runtime &rt, jsi::String eventName) override { + static_assert( + bridging::getParameterCount(&T::addListener) == 2, + "Expected addListener(...) to have 2 parameters"); + + return bridging::callFromJs( + rt, &T::addListener, jsInvoker_, instance_, std::move(eventName)); + } + void removeListeners(jsi::Runtime &rt, double count) override { + static_assert( + bridging::getParameterCount(&T::removeListeners) == 2, + "Expected removeListeners(...) to have 2 parameters"); + + return bridging::callFromJs( + rt, &T::removeListeners, jsInvoker_, instance_, std::move(count)); + } + jsi::Value metaGetAll(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::metaGetAll) == 1, + "Expected metaGetAll(...) to have 1 parameters"); + + return bridging::callFromJs( + rt, &T::metaGetAll, jsInvoker_, instance_); + } + jsi::Value jsonGetAll(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::jsonGetAll) == 1, + "Expected jsonGetAll(...) to have 1 parameters"); + + return bridging::callFromJs( + rt, &T::jsonGetAll, jsInvoker_, instance_); + } + jsi::Value preferencesSetBool(jsi::Runtime &rt, jsi::String key, bool value) override { + static_assert( + bridging::getParameterCount(&T::preferencesSetBool) == 3, + "Expected preferencesSetBool(...) to have 3 parameters"); + + return bridging::callFromJs( + rt, &T::preferencesSetBool, jsInvoker_, instance_, std::move(key), std::move(value)); + } + jsi::Value preferencesSetString(jsi::Runtime &rt, jsi::String key, jsi::String value) override { + static_assert( + bridging::getParameterCount(&T::preferencesSetString) == 3, + "Expected preferencesSetString(...) to have 3 parameters"); + + return bridging::callFromJs( + rt, &T::preferencesSetString, jsInvoker_, instance_, std::move(key), std::move(value)); + } + jsi::Value preferencesGetAll(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::preferencesGetAll) == 1, + "Expected preferencesGetAll(...) to have 1 parameters"); + + return bridging::callFromJs( + rt, &T::preferencesGetAll, jsInvoker_, instance_); + } + jsi::Value preferencesClearAll(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::preferencesClearAll) == 1, + "Expected preferencesClearAll(...) to have 1 parameters"); + + return bridging::callFromJs( + rt, &T::preferencesClearAll, jsInvoker_, instance_); + } + void setLogLevel(jsi::Runtime &rt, jsi::String logLevel) override { + static_assert( + bridging::getParameterCount(&T::setLogLevel) == 2, + "Expected setLogLevel(...) to have 2 parameters"); + + return bridging::callFromJs( + rt, &T::setLogLevel, jsInvoker_, instance_, std::move(logLevel)); + } + + private: + friend class NativeRNFBTurboAppCxxSpec; + T *instance_; + }; + + Delegate delegate_; +}; + + + +#pragma mark - NativeRNFBTurboUtilsPlayServicesAvailability + +template +struct NativeRNFBTurboUtilsPlayServicesAvailability { + P0 isAvailable; + P1 status; + P2 hasResolution; + P3 isUserResolvableError; + P4 error; + bool operator==(const NativeRNFBTurboUtilsPlayServicesAvailability &other) const { + return isAvailable == other.isAvailable && status == other.status && hasResolution == other.hasResolution && isUserResolvableError == other.isUserResolvableError && error == other.error; + } +}; + +template +struct NativeRNFBTurboUtilsPlayServicesAvailabilityBridging { + static T types; + + static T fromJs( + jsi::Runtime &rt, + const jsi::Object &value, + const std::shared_ptr &jsInvoker) { + T result{ + bridging::fromJs(rt, value.getProperty(rt, "isAvailable"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, "status"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, "hasResolution"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, "isUserResolvableError"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, "error"), jsInvoker)}; + return result; + } + +#ifdef DEBUG + static bool isAvailableToJs(jsi::Runtime &rt, decltype(types.isAvailable) value) { + return bridging::toJs(rt, value); + } + + static double statusToJs(jsi::Runtime &rt, decltype(types.status) value) { + return bridging::toJs(rt, value); + } + + static bool hasResolutionToJs(jsi::Runtime &rt, decltype(types.hasResolution) value) { + return bridging::toJs(rt, value); + } + + static bool isUserResolvableErrorToJs(jsi::Runtime &rt, decltype(types.isUserResolvableError) value) { + return bridging::toJs(rt, value); + } + + static jsi::String errorToJs(jsi::Runtime &rt, decltype(types.error) value) { + return bridging::toJs(rt, value); + } +#endif + + static jsi::Object toJs( + jsi::Runtime &rt, + const T &value, + const std::shared_ptr &jsInvoker) { + auto result = facebook::jsi::Object(rt); + result.setProperty(rt, "isAvailable", bridging::toJs(rt, value.isAvailable, jsInvoker)); + result.setProperty(rt, "status", bridging::toJs(rt, value.status, jsInvoker)); + result.setProperty(rt, "hasResolution", bridging::toJs(rt, value.hasResolution, jsInvoker)); + result.setProperty(rt, "isUserResolvableError", bridging::toJs(rt, value.isUserResolvableError, jsInvoker)); + if (value.error) { + result.setProperty(rt, "error", bridging::toJs(rt, value.error.value(), jsInvoker)); + } + return result; + } +}; + +class JSI_EXPORT NativeRNFBTurboUtilsCxxSpecJSI : public TurboModule { +protected: + NativeRNFBTurboUtilsCxxSpecJSI(std::shared_ptr jsInvoker); + +public: + virtual jsi::Object getConstants(jsi::Runtime &rt) = 0; + virtual jsi::Value androidGetPlayServicesStatus(jsi::Runtime &rt) = 0; + virtual jsi::Value androidPromptForPlayServices(jsi::Runtime &rt) = 0; + virtual jsi::Value androidResolutionForPlayServices(jsi::Runtime &rt) = 0; + virtual jsi::Value androidMakePlayServicesAvailable(jsi::Runtime &rt) = 0; + +}; + +template +class JSI_EXPORT NativeRNFBTurboUtilsCxxSpec : public TurboModule { +public: + jsi::Value create(jsi::Runtime &rt, const jsi::PropNameID &propName) override { + return delegate_.create(rt, propName); + } + + std::vector getPropertyNames(jsi::Runtime& runtime) override { + return delegate_.getPropertyNames(runtime); + } + + static constexpr std::string_view kModuleName = "NativeRNFBTurboUtils"; + +protected: + NativeRNFBTurboUtilsCxxSpec(std::shared_ptr jsInvoker) + : TurboModule(std::string{NativeRNFBTurboUtilsCxxSpec::kModuleName}, jsInvoker), + delegate_(reinterpret_cast(this), jsInvoker) {} + + +private: + class Delegate : public NativeRNFBTurboUtilsCxxSpecJSI { + public: + Delegate(T *instance, std::shared_ptr jsInvoker) : + NativeRNFBTurboUtilsCxxSpecJSI(std::move(jsInvoker)), instance_(instance) { + + } + + jsi::Object getConstants(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::getConstants) == 1, + "Expected getConstants(...) to have 1 parameters"); + + return bridging::callFromJs( + rt, &T::getConstants, jsInvoker_, instance_); + } + jsi::Value androidGetPlayServicesStatus(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::androidGetPlayServicesStatus) == 1, + "Expected androidGetPlayServicesStatus(...) to have 1 parameters"); + + return bridging::callFromJs( + rt, &T::androidGetPlayServicesStatus, jsInvoker_, instance_); + } + jsi::Value androidPromptForPlayServices(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::androidPromptForPlayServices) == 1, + "Expected androidPromptForPlayServices(...) to have 1 parameters"); + + return bridging::callFromJs( + rt, &T::androidPromptForPlayServices, jsInvoker_, instance_); + } + jsi::Value androidResolutionForPlayServices(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::androidResolutionForPlayServices) == 1, + "Expected androidResolutionForPlayServices(...) to have 1 parameters"); + + return bridging::callFromJs( + rt, &T::androidResolutionForPlayServices, jsInvoker_, instance_); + } + jsi::Value androidMakePlayServicesAvailable(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::androidMakePlayServicesAvailable) == 1, + "Expected androidMakePlayServicesAvailable(...) to have 1 parameters"); + + return bridging::callFromJs( + rt, &T::androidMakePlayServicesAvailable, jsInvoker_, instance_); + } + + private: + friend class NativeRNFBTurboUtilsCxxSpec; + T *instance_; + }; + + Delegate delegate_; +}; + +} // namespace facebook::react diff --git a/packages/app/android/src/reactnative/java/io/invertase/firebase/common/RCTConvertFirebase.java b/packages/app/android/src/reactnative/java/io/invertase/firebase/common/RCTConvertFirebase.java index 0a1d56235c..b8feb8236f 100644 --- a/packages/app/android/src/reactnative/java/io/invertase/firebase/common/RCTConvertFirebase.java +++ b/packages/app/android/src/reactnative/java/io/invertase/firebase/common/RCTConvertFirebase.java @@ -25,7 +25,7 @@ import com.facebook.react.bridge.WritableMap; import com.google.firebase.FirebaseApp; import com.google.firebase.FirebaseOptions; -import io.invertase.firebase.app.ReactNativeFirebaseAppModule; +import io.invertase.firebase.app.NativeRNFBTurboApp; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -57,8 +57,8 @@ public static Map firebaseAppToMap(FirebaseApp firebaseApp) { options.put("messagingSenderId", appOptions.getGcmSenderId()); options.put("storageBucket", appOptions.getStorageBucket()); - if (ReactNativeFirebaseAppModule.authDomains.get(name) != null) { - options.put("authDomain", ReactNativeFirebaseAppModule.authDomains.get(name)); + if (NativeRNFBTurboApp.authDomains.get(name) != null) { + options.put("authDomain", NativeRNFBTurboApp.authDomains.get(name)); } root.put("options", options); diff --git a/packages/app/android/src/reactnative/java/io/invertase/firebase/utils/NativeRNFBTurboUtils.java b/packages/app/android/src/reactnative/java/io/invertase/firebase/utils/NativeRNFBTurboUtils.java new file mode 100644 index 0000000000..7e31e75fe7 --- /dev/null +++ b/packages/app/android/src/reactnative/java/io/invertase/firebase/utils/NativeRNFBTurboUtils.java @@ -0,0 +1,184 @@ +package io.invertase.firebase.utils; + +/* + * Copyright (c) 2016-present Invertase Limited & Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this library except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import android.app.Activity; +import android.content.Context; +import android.content.IntentSender; +import android.os.Build; +import android.os.Environment; +import android.provider.Settings; +import android.util.Log; +import com.facebook.fbreact.specs.NativeRNFBTurboUtilsSpec; +import com.facebook.react.bridge.Arguments; +import com.facebook.react.bridge.Promise; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.WritableMap; +import com.google.android.gms.common.ConnectionResult; +import com.google.android.gms.common.GoogleApiAvailability; +import io.invertase.firebase.app.ReactNativeFirebaseApp; +import java.io.File; +import java.util.HashMap; +import java.util.Map; + +public class NativeRNFBTurboUtils extends NativeRNFBTurboUtilsSpec { + private static final String TAG = "Utils"; + private static final String KEY_MAIN_BUNDLE = "MAIN_BUNDLE"; + private static final String KEY_DOCUMENT_DIRECTORY = "DOCUMENT_DIRECTORY"; + private static final String KEY_LIBRARY_DIRECTORY = "LIBRARY_DIRECTORY"; + private static final String KEY_EXTERNAL_DIRECTORY = "EXTERNAL_DIRECTORY"; + private static final String KEY_EXT_STORAGE_DIRECTORY = "EXTERNAL_STORAGE_DIRECTORY"; + private static final String KEY_PICS_DIRECTORY = "PICTURES_DIRECTORY"; + private static final String KEY_MOVIES_DIRECTORY = "MOVIES_DIRECTORY"; + private static final String KEY_TEMP_DIRECTORY = "TEMP_DIRECTORY"; + private static final String KEY_CACHE_DIRECTORY = "CACHES_DIRECTORY"; + private static final String FIREBASE_TEST_LAB = "firebase.test.lab"; + + public NativeRNFBTurboUtils(ReactApplicationContext reactContext) { + super(reactContext); + } + + private static Boolean isRunningInTestLab() { + String testLabSetting = + Settings.System.getString( + ReactNativeFirebaseApp.getApplicationContext().getContentResolver(), FIREBASE_TEST_LAB); + + return "true".equals(testLabSetting); + } + + @Override + public void androidGetPlayServicesStatus(Promise promise) { + promise.resolve(getPlayServicesStatusMap()); + } + + @Override + public void androidPromptForPlayServices(Promise promise) { + int status = isGooglePlayServicesAvailable(); + GoogleApiAvailability gapi = GoogleApiAvailability.getInstance(); + + if (status != ConnectionResult.SUCCESS && gapi.isUserResolvableError(status)) { + Activity activity = getCurrentActivity(); + if (activity != null) { + gapi.getErrorDialog(activity, status, status).show(); + } + } + promise.resolve(null); + } + + @Override + public void androidResolutionForPlayServices(Promise promise) { + int status = isGooglePlayServicesAvailable(); + ConnectionResult connectionResult = new ConnectionResult(status); + + if (!connectionResult.isSuccess() && connectionResult.hasResolution()) { + Activity activity = getCurrentActivity(); + if (activity != null) { + try { + connectionResult.startResolutionForResult(activity, status); + } catch (IntentSender.SendIntentException error) { + Log.d(TAG, "resolutionForPlayServices", error); + } + } + } + promise.resolve(null); + } + + @Override + public void androidMakePlayServicesAvailable(Promise promise) { + int status = isGooglePlayServicesAvailable(); + + if (status != ConnectionResult.SUCCESS) { + Activity activity = getCurrentActivity(); + if (activity != null) { + GoogleApiAvailability.getInstance().makeGooglePlayServicesAvailable(activity); + } + } + promise.resolve(null); + } + + private int isGooglePlayServicesAvailable() { + GoogleApiAvailability gapi = GoogleApiAvailability.getInstance(); + return gapi.isGooglePlayServicesAvailable(getReactApplicationContext()); + } + + private WritableMap getPlayServicesStatusMap() { + WritableMap result = Arguments.createMap(); + GoogleApiAvailability gapi = GoogleApiAvailability.getInstance(); + + int status = gapi.isGooglePlayServicesAvailable(getReactApplicationContext()); + result.putInt("status", status); + + if (status == ConnectionResult.SUCCESS) { + result.putBoolean("isAvailable", true); + } else { + result.putBoolean("isAvailable", false); + result.putString("error", gapi.getErrorString(status)); + result.putBoolean("isUserResolvableError", gapi.isUserResolvableError(status)); + result.putBoolean("hasResolution", new ConnectionResult(status).hasResolution()); + } + + return result; + } + + @Override + protected Map getTypedExportedConstants() { + Map constants = new HashMap<>(); + + constants.put("isRunningInTestLab", isRunningInTestLab()); + + Context context = getReactApplicationContext(); + constants.put(KEY_MAIN_BUNDLE, ""); + constants.put(KEY_LIBRARY_DIRECTORY, context.getFilesDir().getAbsolutePath()); + constants.put(KEY_TEMP_DIRECTORY, context.getCacheDir().getAbsolutePath()); + constants.put(KEY_CACHE_DIRECTORY, context.getCacheDir().getAbsolutePath()); + + File externalDirectory = context.getExternalFilesDir(null); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + if (externalDirectory != null) { + constants.put(KEY_DOCUMENT_DIRECTORY, externalDirectory.getAbsolutePath()); + } else { + constants.put(KEY_DOCUMENT_DIRECTORY, context.getFilesDir().getAbsolutePath()); + } + } + + if (!constants.containsKey(KEY_DOCUMENT_DIRECTORY)) { + constants.put(KEY_DOCUMENT_DIRECTORY, context.getFilesDir().getAbsolutePath()); + } + + constants.put( + KEY_PICS_DIRECTORY, + Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) + .getAbsolutePath()); + + constants.put( + KEY_MOVIES_DIRECTORY, + Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES) + .getAbsolutePath()); + + File externalStorageDirectory = Environment.getExternalStorageDirectory(); + if (externalStorageDirectory != null) { + constants.put(KEY_EXT_STORAGE_DIRECTORY, externalStorageDirectory.getAbsolutePath()); + } + + if (externalDirectory != null) { + constants.put(KEY_EXTERNAL_DIRECTORY, externalDirectory.getAbsolutePath()); + } + + return constants; + } +} diff --git a/packages/app/e2e/events.e2e.js b/packages/app/e2e/events.e2e.js index 22d8dfad81..4085b2c194 100644 --- a/packages/app/e2e/events.e2e.js +++ b/packages/app/e2e/events.e2e.js @@ -21,10 +21,12 @@ const eventBody = { foo: 'bar', }; +const APP_MODULE = NativeModules.NativeRNFBTurboApp; + describe('Core -> EventEmitter', function () { describe('ReactNativeFirebaseEventEmitter', function () { it('queues events before app is ready', async function () { - const { eventsPing, eventsNotifyReady, eventsGetListeners } = NativeModules.RNFBAppModule; + const { eventsPing, eventsNotifyReady, eventsGetListeners } = APP_MODULE; await eventsNotifyReady(false); let readyToResolve = false; @@ -67,7 +69,7 @@ describe('Core -> EventEmitter', function () { }); it('can send and receive lots of events', async function () { - const { eventsPing, eventsNotifyReady } = NativeModules.RNFBAppModule; + const { eventsPing, eventsNotifyReady } = APP_MODULE; await eventsNotifyReady(true); const { resolve, reject, promise } = Promise.defer(); const emitter = NativeEventEmitter; @@ -96,7 +98,7 @@ describe('Core -> EventEmitter', function () { it('queues events before a js listener is registered', async function () { const { eventsPing, eventsNotifyReady, eventsGetListeners, eventsRemoveListener } = - NativeModules.RNFBAppModule; + APP_MODULE; await eventsNotifyReady(true); const { resolve, reject, promise } = Promise.defer(); const emitter = NativeEventEmitter; diff --git a/packages/app/ios/RNFBApp.xcodeproj/project.pbxproj b/packages/app/ios/RNFBApp.xcodeproj/project.pbxproj index cf22fc572d..1127bb625c 100644 --- a/packages/app/ios/RNFBApp.xcodeproj/project.pbxproj +++ b/packages/app/ios/RNFBApp.xcodeproj/project.pbxproj @@ -7,7 +7,7 @@ objects = { /* Begin PBXBuildFile section */ - 2744B98621F45429004F8E3F /* RNFBAppModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 2744B98521F45429004F8E3F /* RNFBAppModule.m */; }; + 2744B98621F45429004F8E3F /* RNFBAppModule.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2744B98521F45429004F8E3F /* RNFBAppModule.mm */; }; 2744B99121F46140004F8E3F /* RNFBRCTEventEmitter.m in Sources */ = {isa = PBXBuildFile; fileRef = 2744B99021F46140004F8E3F /* RNFBRCTEventEmitter.m */; }; 2744B9A421F48A4F004F8E3F /* RCTConvert+FIROptions.m in Sources */ = {isa = PBXBuildFile; fileRef = 2744B9A321F48A4F004F8E3F /* RCTConvert+FIROptions.m */; }; 2744B9A721F57C2F004F8E3F /* RCTConvert+FIRApp.m in Sources */ = {isa = PBXBuildFile; fileRef = 2744B9A621F57C2F004F8E3F /* RCTConvert+FIRApp.m */; }; @@ -15,7 +15,7 @@ 2748D8172236429D00FC8DC8 /* RNFBSharedUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 2748D8102236417700FC8DC8 /* RNFBSharedUtils.m */; }; 2748D81C223674CD00FC8DC8 /* RNFBPreferences.m in Sources */ = {isa = PBXBuildFile; fileRef = 2748D81B223674CD00FC8DC8 /* RNFBPreferences.m */; }; 2748D8202237018600FC8DC8 /* RNFBMeta.m in Sources */ = {isa = PBXBuildFile; fileRef = 2748D81F2237018600FC8DC8 /* RNFBMeta.m */; }; - 4D97BAD423042F2700077358 /* RNFBUtilsModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D97BAD323042F2700077358 /* RNFBUtilsModule.m */; }; + 4D97BAD423042F2700077358 /* RNFBUtilsModule.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4D97BAD323042F2700077358 /* RNFBUtilsModule.mm */; }; DAA1F28522FCF6AD00F4DEC1 /* RNFBVersion.m in Sources */ = {isa = PBXBuildFile; fileRef = DAA1F28422FCF6AD00F4DEC1 /* RNFBVersion.m */; }; RNFB00001A2025011100000001 /* RNFBNullSentinelInterceptor.m in Sources */ = {isa = PBXBuildFile; fileRef = RNFB00001A2025011100000002 /* RNFBNullSentinelInterceptor.m */; }; /* End PBXBuildFile section */ @@ -35,7 +35,7 @@ /* Begin PBXFileReference section */ 2744B98221F45429004F8E3F /* libRNFBApp.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRNFBApp.a; sourceTree = BUILT_PRODUCTS_DIR; }; 2744B98421F45429004F8E3F /* RNFBAppModule.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = RNFBAppModule.h; path = RNFBApp/RNFBAppModule.h; sourceTree = SOURCE_ROOT; }; - 2744B98521F45429004F8E3F /* RNFBAppModule.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = RNFBAppModule.m; path = RNFBApp/RNFBAppModule.m; sourceTree = SOURCE_ROOT; }; + 2744B98521F45429004F8E3F /* RNFBAppModule.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = RNFBAppModule.mm; path = RNFBApp/RNFBAppModule.mm; sourceTree = SOURCE_ROOT; }; 2744B98D21F45E8B004F8E3F /* RNFBRCTEventEmitter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNFBRCTEventEmitter.h; sourceTree = ""; }; 2744B99021F46140004F8E3F /* RNFBRCTEventEmitter.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNFBRCTEventEmitter.m; sourceTree = ""; }; 2744B9A221F48826004F8E3F /* RCTConvert+FIROptions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "RCTConvert+FIROptions.h"; sourceTree = ""; }; @@ -51,7 +51,7 @@ 2748D81E2237012B00FC8DC8 /* RNFBMeta.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNFBMeta.h; sourceTree = ""; }; 2748D81F2237018600FC8DC8 /* RNFBMeta.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNFBMeta.m; sourceTree = ""; }; 4D97BAD223042F0800077358 /* RNFBUtilsModule.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNFBUtilsModule.h; sourceTree = ""; }; - 4D97BAD323042F2700077358 /* RNFBUtilsModule.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNFBUtilsModule.m; sourceTree = ""; }; + 4D97BAD323042F2700077358 /* RNFBUtilsModule.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = RNFBUtilsModule.mm; sourceTree = ""; }; DAA1F28422FCF6AD00F4DEC1 /* RNFBVersion.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNFBVersion.m; sourceTree = ""; }; DAA1F28622FCF6C200F4DEC1 /* RNFBVersion.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNFBVersion.h; sourceTree = ""; }; RNFB00001A2025011100000002 /* RNFBNullSentinelInterceptor.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNFBNullSentinelInterceptor.m; sourceTree = ""; }; @@ -91,7 +91,7 @@ 2744B9A521F57BD9004F8E3F /* RCTConvert+FIRApp.h */, 2744B9A621F57C2F004F8E3F /* RCTConvert+FIRApp.m */, 2744B98421F45429004F8E3F /* RNFBAppModule.h */, - 2744B98521F45429004F8E3F /* RNFBAppModule.m */, + 2744B98521F45429004F8E3F /* RNFBAppModule.mm */, 2748D8162236428100FC8DC8 /* RNFBJSON.h */, 2748D8142236426300FC8DC8 /* RNFBJSON.m */, 2748D81A223674B600FC8DC8 /* RNFBPreferences.h */, @@ -99,7 +99,7 @@ DAA1F28422FCF6AD00F4DEC1 /* RNFBVersion.m */, DAA1F28622FCF6C200F4DEC1 /* RNFBVersion.h */, 4D97BAD223042F0800077358 /* RNFBUtilsModule.h */, - 4D97BAD323042F2700077358 /* RNFBUtilsModule.m */, + 4D97BAD323042F2700077358 /* RNFBUtilsModule.mm */, RNFB00001A2025011100000003 /* RNFBNullSentinelInterceptor.h */, RNFB00001A2025011100000002 /* RNFBNullSentinelInterceptor.m */, ); @@ -173,12 +173,12 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 2744B98621F45429004F8E3F /* RNFBAppModule.m in Sources */, + 2744B98621F45429004F8E3F /* RNFBAppModule.mm in Sources */, 2744B9A721F57C2F004F8E3F /* RCTConvert+FIRApp.m in Sources */, 2748D8172236429D00FC8DC8 /* RNFBSharedUtils.m in Sources */, 2748D81C223674CD00FC8DC8 /* RNFBPreferences.m in Sources */, DAA1F28522FCF6AD00F4DEC1 /* RNFBVersion.m in Sources */, - 4D97BAD423042F2700077358 /* RNFBUtilsModule.m in Sources */, + 4D97BAD423042F2700077358 /* RNFBUtilsModule.mm in Sources */, 2748D8202237018600FC8DC8 /* RNFBMeta.m in Sources */, 2744B99121F46140004F8E3F /* RNFBRCTEventEmitter.m in Sources */, 2744B9A421F48A4F004F8E3F /* RCTConvert+FIROptions.m in Sources */, diff --git a/packages/app/ios/RNFBApp/RNFBAppModule.h b/packages/app/ios/RNFBApp/RNFBAppModule.h index 894c019d73..70389cc55b 100644 --- a/packages/app/ios/RNFBApp/RNFBAppModule.h +++ b/packages/app/ios/RNFBApp/RNFBAppModule.h @@ -17,9 +17,7 @@ #import -#import - -@interface RNFBAppModule : NSObject +@interface RNFBAppModule : NSObject + (NSString *)getCustomDomain:(NSString *)appName; diff --git a/packages/app/ios/RNFBApp/RNFBAppModule.m b/packages/app/ios/RNFBApp/RNFBAppModule.mm similarity index 68% rename from packages/app/ios/RNFBApp/RNFBAppModule.m rename to packages/app/ios/RNFBApp/RNFBAppModule.mm index f679daad1b..3a96742813 100644 --- a/packages/app/ios/RNFBApp/RNFBAppModule.m +++ b/packages/app/ios/RNFBApp/RNFBAppModule.mm @@ -16,9 +16,12 @@ */ #import +#import #import +#import "RCTConvert+FIRApp.h" #import "RNFBAppModule.h" +#import "RNFBAppTurboModules.h" #import "RNFBJSON.h" #import "RNFBMeta.h" #import "RNFBPreferences.h" @@ -31,15 +34,19 @@ #define REGISTER_LIB #endif +@interface RNFBAppModule () +@end + @implementation RNFBAppModule #pragma mark - #pragma mark Module Setup -RCT_EXPORT_MODULE(); +RCT_EXPORT_MODULE(NativeRNFBTurboApp) -- (dispatch_queue_t)methodQueue { - return dispatch_get_main_queue(); +- (std::shared_ptr)getTurboModule: + (const facebook::react::ObjCTurboModule::InitParams &)params { + return std::make_shared(params); } - (void)setBridge:(RCTBridge *)bridge { @@ -71,54 +78,70 @@ - (void)invalidate { [[RNFBRCTEventEmitter shared] invalidate]; } +#pragma mark - +#pragma mark Constants + +- (NSDictionary *)appConstantsDictionary { + NSDictionary *firApps = [FIRApp allApps]; + NSMutableArray *appsArray = [NSMutableArray new]; + NSMutableDictionary *constants = [NSMutableDictionary new]; + + for (id key in firApps) { + [appsArray addObject:[RNFBSharedUtils firAppToDictionary:firApps[key]]]; + } + + constants[@"NATIVE_FIREBASE_APPS"] = appsArray; + constants[@"FIREBASE_RAW_JSON"] = [[RNFBJSON shared] getRawJSON]; + + return constants; +} + +- (facebook::react::ModuleConstants)constantsToExport { + return [_RCTTypedModuleConstants newWithUnsafeDictionary:[self appConstantsDictionary]]; +} + +- (facebook::react::ModuleConstants)getConstants { + return [self constantsToExport]; +} + #pragma mark - #pragma mark META Methods -RCT_EXPORT_METHOD(metaGetAll - : (RCTPromiseResolveBlock)resolve rejecter - : (RCTPromiseRejectBlock)reject) { +- (void)metaGetAll:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { resolve([RNFBMeta getAll]); } #pragma mark - #pragma mark JSON Methods -RCT_EXPORT_METHOD(jsonGetAll - : (RCTPromiseResolveBlock)resolve rejecter - : (RCTPromiseRejectBlock)reject) { +- (void)jsonGetAll:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { resolve([[RNFBJSON shared] getAll]); } #pragma mark - #pragma mark Preference Methods -RCT_EXPORT_METHOD(preferencesSetBool - : (NSString *)key boolValue - : (BOOL)boolValue resolver - : (RCTPromiseResolveBlock)resolve rejecter - : (RCTPromiseRejectBlock)reject) { - [[RNFBPreferences shared] setBooleanValue:key boolValue:boolValue]; +- (void)preferencesSetBool:(NSString *)key + value:(BOOL)value + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject { + [[RNFBPreferences shared] setBooleanValue:key boolValue:value]; resolve([NSNull null]); } -RCT_EXPORT_METHOD(preferencesSetString - : (NSString *)key stringValue - : (NSString *)stringValue resolver - : (RCTPromiseResolveBlock)resolve rejecter - : (RCTPromiseRejectBlock)reject) { - [[RNFBPreferences shared] setStringValue:key stringValue:stringValue]; +- (void)preferencesSetString:(NSString *)key + value:(NSString *)value + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject { + [[RNFBPreferences shared] setStringValue:key stringValue:value]; resolve([NSNull null]); } -RCT_EXPORT_METHOD(preferencesGetAll - : (RCTPromiseResolveBlock)resolve rejecter - : (RCTPromiseRejectBlock)reject) { +- (void)preferencesGetAll:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { resolve([[RNFBPreferences shared] getAll]); } -RCT_EXPORT_METHOD(preferencesClearAll - : (RCTPromiseResolveBlock)resolve rejecter - : (RCTPromiseRejectBlock)reject) { +- (void)preferencesClearAll:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { [[RNFBPreferences shared] clearAll]; resolve([NSNull null]); } @@ -126,52 +149,48 @@ - (void)invalidate { #pragma mark - #pragma mark Event Methods -RCT_EXPORT_METHOD(eventsNotifyReady : (BOOL)ready) { +- (void)eventsNotifyReady:(BOOL)ready { [[RNFBRCTEventEmitter shared] notifyJsReady:ready]; } -RCT_EXPORT_METHOD(eventsGetListeners - : (RCTPromiseResolveBlock)resolve rejecter - : (RCTPromiseRejectBlock)reject) { +- (void)eventsGetListeners:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { resolve([[RNFBRCTEventEmitter shared] getListenersDictionary]); } -RCT_EXPORT_METHOD(eventsPing - : (NSString *)eventName eventBody - : (NSDictionary *)eventBody resolver - : (RCTPromiseResolveBlock)resolve rejecter - : (RCTPromiseRejectBlock)reject) { +- (void)eventsPing:(NSString *)eventName + eventBody:(NSDictionary *)eventBody + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject { [[RNFBRCTEventEmitter shared] sendEventWithName:eventName body:eventBody]; resolve(eventBody); } -RCT_EXPORT_METHOD(eventsAddListener : (NSString *)eventName) { +- (void)eventsAddListener:(NSString *)eventName { [[RNFBRCTEventEmitter shared] addListener:eventName]; } -RCT_EXPORT_METHOD(eventsRemoveListener : (NSString *)eventName all : (BOOL)all) { +- (void)eventsRemoveListener:(NSString *)eventName all:(BOOL)all { [[RNFBRCTEventEmitter shared] removeListeners:eventName all:all]; } #pragma mark - #pragma mark Events Unused -RCT_EXPORT_METHOD(addListener : (NSString *)eventName) { +- (void)addListener:(NSString *)eventName { // Keep: Required for RN built in Event Emitter Calls. } -RCT_EXPORT_METHOD(removeListeners : (NSInteger)count) { +- (void)removeListeners:(double)count { // Keep: Required for RN built in Event Emitter Calls. } #pragma mark - #pragma mark Firebase App Methods -RCT_EXPORT_METHOD(initializeApp - : (NSDictionary *)options appConfig - : (NSDictionary *)appConfig resolver - : (RCTPromiseResolveBlock)resolve rejecter - : (RCTPromiseRejectBlock)reject) { +- (void)initializeApp:(NSDictionary *)options + appConfig:(NSDictionary *)appConfig + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject { RCTUnsafeExecuteOnMainQueueSync(^{ FIRApp *firApp; NSString *appName = [appConfig valueForKey:@"name"]; @@ -182,24 +201,18 @@ - (void)invalidate { GCMSenderID:messagingSenderId]; firOptions.APIKey = [options valueForKey:@"apiKey"]; firOptions.projectID = [options valueForKey:@"projectId"]; - // kFirebaseOptionsDatabaseUrl if (![[options valueForKey:@"databaseURL"] isEqual:[NSNull null]]) { firOptions.databaseURL = [options valueForKey:@"databaseURL"]; } - // kFirebaseOptionsStorageBucket if (![[options valueForKey:@"storageBucket"] isEqual:[NSNull null]]) { firOptions.storageBucket = [options valueForKey:@"storageBucket"]; } - - // kFirebaseOptionsIosBundleId if (![[options valueForKey:@"iosBundleId"] isEqual:[NSNull null]]) { firOptions.bundleID = [options valueForKey:@"iosBundleId"]; } - // kFirebaseOptionsIosClientId if (![[options valueForKey:@"iosClientId"] isEqual:[NSNull null]]) { firOptions.clientID = [options valueForKey:@"iosClientId"]; } - // kFirebaseOptionsAppGroupId if (![[options valueForKey:@"appGroupId"] isEqual:[NSNull null]]) { firOptions.appGroupID = [options valueForKey:@"appGroupId"]; } @@ -237,7 +250,7 @@ + (NSString *)getCustomDomain:(NSString *)appName { return customAuthDomains[appName]; } -RCT_EXPORT_METHOD(setLogLevel : (NSString *)logLevel) { +- (void)setLogLevel:(NSString *)logLevel { int level = FIRLoggerLevelError; if ([logLevel isEqualToString:@"verbose"]) { level = FIRLoggerLevelDebug; @@ -249,19 +262,20 @@ + (NSString *)getCustomDomain:(NSString *)appName { level = FIRLoggerLevelWarning; } DLog(@"RNFBSetLogLevel: setting level to %d from %@.", level, logLevel); - [[FIRConfiguration sharedInstance] setLoggerLevel:level]; + [[FIRConfiguration sharedInstance] setLoggerLevel:(FIRLoggerLevel)level]; } -RCT_EXPORT_METHOD(setAutomaticDataCollectionEnabled : (FIRApp *)firApp enabled : (BOOL)enabled) { +- (void)setAutomaticDataCollectionEnabled:(NSString *)appName enabled:(BOOL)enabled { + FIRApp *firApp = [RCTConvert firAppFromString:appName]; if (firApp) { firApp.dataCollectionDefaultEnabled = enabled; } } -RCT_EXPORT_METHOD(deleteApp - : (FIRApp *)firApp resolver - : (RCTPromiseResolveBlock)resolve rejecter - : (RCTPromiseRejectBlock)reject) { +- (void)deleteApp:(NSString *)appName + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject { + FIRApp *firApp = [RCTConvert firAppFromString:appName]; if (!firApp) { return resolve([NSNull null]); } @@ -270,12 +284,10 @@ + (NSString *)getCustomDomain:(NSString *)appName { if (success) { resolve([NSNull null]); } else { - // try again once more [firApp deleteApp:^(BOOL success2) { if (success2) { resolve([NSNull null]); } else { - // TODO js error builder reject(@"app/delete-app-failed", @"Failed to delete the specified app.", nil); } }]; @@ -283,23 +295,8 @@ + (NSString *)getCustomDomain:(NSString *)appName { }]; } -- (NSDictionary *)constantsToExport { - NSDictionary *firApps = [FIRApp allApps]; - NSMutableArray *appsArray = [NSMutableArray new]; - NSMutableDictionary *constants = [NSMutableDictionary new]; - - for (id key in firApps) { - [appsArray addObject:[RNFBSharedUtils firAppToDictionary:firApps[key]]]; - } - - constants[@"NATIVE_FIREBASE_APPS"] = appsArray; - - constants[@"FIREBASE_RAW_JSON"] = [[RNFBJSON shared] getRawJSON]; - - return constants; -} - + (BOOL)requiresMainQueueSetup { - return YES; + return NO; } + @end diff --git a/packages/app/ios/RNFBApp/RNFBUtilsModule.h b/packages/app/ios/RNFBApp/RNFBUtilsModule.h index 43ec807b78..9e50cd8c3a 100644 --- a/packages/app/ios/RNFBApp/RNFBUtilsModule.h +++ b/packages/app/ios/RNFBApp/RNFBUtilsModule.h @@ -18,9 +18,7 @@ #import #import -#import - -@interface RNFBUtilsModule : NSObject +@interface RNFBUtilsModule : NSObject + (BOOL)isRemoteAsset:(NSString *)localFilePath; + (BOOL)unused_isHeic:(NSString *)localFilePath; diff --git a/packages/app/ios/RNFBApp/RNFBUtilsModule.m b/packages/app/ios/RNFBApp/RNFBUtilsModule.mm similarity index 66% rename from packages/app/ios/RNFBApp/RNFBUtilsModule.m rename to packages/app/ios/RNFBApp/RNFBUtilsModule.mm index 7d28331109..e8231a0f3e 100644 --- a/packages/app/ios/RNFBApp/RNFBUtilsModule.m +++ b/packages/app/ios/RNFBApp/RNFBUtilsModule.mm @@ -18,20 +18,84 @@ #import #import "RNFBApp/RNFBSharedUtils.h" +#import "RNFBAppTurboModules.h" #import "RNFBUtilsModule.h" +@interface RNFBUtilsModule () +@end + @implementation RNFBUtilsModule #pragma mark - #pragma mark Module Setup -RCT_EXPORT_MODULE(); +RCT_EXPORT_MODULE(NativeRNFBTurboUtils) -- (dispatch_queue_t)methodQueue { - return dispatch_get_main_queue(); +- (std::shared_ptr)getTurboModule: + (const facebook::react::ObjCTurboModule::InitParams &)params { + return std::make_shared(params); } + (BOOL)requiresMainQueueSetup { - return YES; + return NO; +} + +#pragma mark - +#pragma mark Constants + +- (NSString *)getPathForDirectory:(int)directory { + NSArray *paths = + NSSearchPathForDirectoriesInDomains((NSSearchPathDirectory)directory, NSUserDomainMask, YES); + return [paths firstObject]; +} + +- (NSDictionary *)utilsConstantsDictionary { + return @{ + @"isRunningInTestLab" : @NO, + @"MAIN_BUNDLE" : [[NSBundle mainBundle] bundlePath], + @"CACHES_DIRECTORY" : [self getPathForDirectory:NSCachesDirectory], + @"DOCUMENT_DIRECTORY" : [self getPathForDirectory:NSDocumentDirectory], + @"PICTURES_DIRECTORY" : [self getPathForDirectory:NSPicturesDirectory], + @"MOVIES_DIRECTORY" : [self getPathForDirectory:NSMoviesDirectory], + @"TEMP_DIRECTORY" : NSTemporaryDirectory(), + @"LIBRARY_DIRECTORY" : [self getPathForDirectory:NSLibraryDirectory], + }; +} + +- (facebook::react::ModuleConstants) + constantsToExport { + return [_RCTTypedModuleConstants newWithUnsafeDictionary:[self utilsConstantsDictionary]]; +} + +- (facebook::react::ModuleConstants)getConstants { + return [self constantsToExport]; +} + +#pragma mark - +#pragma mark Android-only stubs + +- (void)androidGetPlayServicesStatus:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject { + resolve(@{ + @"isAvailable" : @YES, + @"status" : @0, + @"hasResolution" : @NO, + @"isUserResolvableError" : @NO, + }); +} + +- (void)androidPromptForPlayServices:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject { + resolve(nil); +} + +- (void)androidResolutionForPlayServices:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject { + resolve(nil); +} + +- (void)androidMakePlayServicesAvailable:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject { + resolve(nil); } #pragma mark - @@ -56,7 +120,6 @@ + (PHAsset *)fetchAssetForPath:(NSString *)localFilePath { if ([localFilePath hasPrefix:@"assets-library://"] || [localFilePath hasPrefix:@"ph://"]) { if ([localFilePath hasPrefix:@"assets-library://"]) { - NSURL *localFile = [[NSURL alloc] initWithString:localFilePath]; static BOOL hasWarned = NO; if (!hasWarned) { NSLog(@"'assets-library://' & 'ph://' URLs are not supported in Catalyst-based targets " @@ -77,24 +140,4 @@ + (PHAsset *)fetchAssetForPath:(NSString *)localFilePath { return asset; } -- (NSString *)getPathForDirectory:(int)directory { - NSArray *paths = - NSSearchPathForDirectoriesInDomains((NSSearchPathDirectory)directory, NSUserDomainMask, YES); - return [paths firstObject]; -} - -- (NSDictionary *)constantsToExport { - NSMutableDictionary *constants = [@{ - @"MAIN_BUNDLE" : [[NSBundle mainBundle] bundlePath], - @"CACHES_DIRECTORY" : [self getPathForDirectory:NSCachesDirectory], - @"DOCUMENT_DIRECTORY" : [self getPathForDirectory:NSDocumentDirectory], - @"PICTURES_DIRECTORY" : [self getPathForDirectory:NSPicturesDirectory], - @"MOVIES_DIRECTORY" : [self getPathForDirectory:NSMoviesDirectory], - @"TEMP_DIRECTORY" : NSTemporaryDirectory(), - @"LIBRARY_DIRECTORY" : [self getPathForDirectory:NSLibraryDirectory], - } mutableCopy]; - - return constants; -} - @end diff --git a/packages/app/ios/generated/RCTAppDependencyProvider.h b/packages/app/ios/generated/RCTAppDependencyProvider.h new file mode 100644 index 0000000000..5a1502d16f --- /dev/null +++ b/packages/app/ios/generated/RCTAppDependencyProvider.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + + +#import + +#if __has_include() +#import +#elif __has_include() +#import +#else +#import "RCTDependencyProvider.h" +#endif + +NS_ASSUME_NONNULL_BEGIN + +@interface RCTAppDependencyProvider : NSObject + +@end + +NS_ASSUME_NONNULL_END diff --git a/packages/app/ios/generated/RCTAppDependencyProvider.mm b/packages/app/ios/generated/RCTAppDependencyProvider.mm new file mode 100644 index 0000000000..b76c468c8a --- /dev/null +++ b/packages/app/ios/generated/RCTAppDependencyProvider.mm @@ -0,0 +1,40 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import "RCTAppDependencyProvider.h" +#import +#import +#import +#import + +@implementation RCTAppDependencyProvider + +- (nonnull NSArray *)URLRequestHandlerClassNames { + return RCTModulesConformingToProtocolsProvider.URLRequestHandlerClassNames; +} + +- (nonnull NSArray *)imageDataDecoderClassNames { + return RCTModulesConformingToProtocolsProvider.imageDataDecoderClassNames; +} + +- (nonnull NSArray *)imageURLLoaderClassNames { + return RCTModulesConformingToProtocolsProvider.imageURLLoaderClassNames; +} + +- (nonnull NSArray *)unstableModulesRequiringMainQueueSetup { + return RCTUnstableModulesRequiringMainQueueSetupProvider.modules; +} + +- (nonnull NSDictionary> *)thirdPartyFabricComponents { + return RCTThirdPartyComponentsProvider.thirdPartyFabricComponents; +} + +- (nonnull NSDictionary> *)moduleProviders { + return RCTModuleProviders.moduleProviders; +} + +@end diff --git a/packages/app/ios/generated/RCTModuleProviders.h b/packages/app/ios/generated/RCTModuleProviders.h new file mode 100644 index 0000000000..aff637c692 --- /dev/null +++ b/packages/app/ios/generated/RCTModuleProviders.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +@protocol RCTModuleProvider; + +@interface RCTModuleProviders: NSObject + ++ (NSDictionary> *)moduleProviders; + +@end diff --git a/packages/app/ios/generated/RCTModuleProviders.mm b/packages/app/ios/generated/RCTModuleProviders.mm new file mode 100644 index 0000000000..5f34abf2d4 --- /dev/null +++ b/packages/app/ios/generated/RCTModuleProviders.mm @@ -0,0 +1,52 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +#import "RCTModuleProviders.h" +#import +#import + +@implementation RCTModuleProviders + ++ (NSDictionary> *)moduleProviders +{ + static NSDictionary> *providers = nil; + static dispatch_once_t onceToken; + + dispatch_once(&onceToken, ^{ + NSDictionary * moduleMapping = @{ + @"NativeRNFBTurboApp": @"RNFBAppModule", // @react-native-firebase/app + @"NativeRNFBTurboUtils": @"RNFBUtilsModule", // @react-native-firebase/app + }; + + NSMutableDictionary *dict = [[NSMutableDictionary alloc] initWithCapacity:moduleMapping.count]; + + for (NSString *key in moduleMapping) { + NSString * moduleProviderName = moduleMapping[key]; + Class klass = NSClassFromString(moduleProviderName); + if (!klass) { + RCTLogError(@"Module provider %@ cannot be found in the runtime", moduleProviderName); + continue; + } + + id instance = [klass new]; + if (![instance respondsToSelector:@selector(getTurboModule:)]) { + RCTLogError(@"Module provider %@ does not conform to RCTModuleProvider", moduleProviderName); + continue; + } + + [dict setObject:instance forKey:key]; + } + + providers = dict; + }); + + return providers; +} + +@end diff --git a/packages/app/ios/generated/RCTModulesConformingToProtocolsProvider.h b/packages/app/ios/generated/RCTModulesConformingToProtocolsProvider.h new file mode 100644 index 0000000000..10eb848917 --- /dev/null +++ b/packages/app/ios/generated/RCTModulesConformingToProtocolsProvider.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +@interface RCTModulesConformingToProtocolsProvider: NSObject + ++(NSArray *)imageURLLoaderClassNames; + ++(NSArray *)imageDataDecoderClassNames; + ++(NSArray *)URLRequestHandlerClassNames; + +@end diff --git a/packages/app/ios/generated/RCTModulesConformingToProtocolsProvider.mm b/packages/app/ios/generated/RCTModulesConformingToProtocolsProvider.mm new file mode 100644 index 0000000000..a5ff82810e --- /dev/null +++ b/packages/app/ios/generated/RCTModulesConformingToProtocolsProvider.mm @@ -0,0 +1,54 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import "RCTModulesConformingToProtocolsProvider.h" + +@implementation RCTModulesConformingToProtocolsProvider + ++(NSArray *)imageURLLoaderClassNames +{ + static NSArray *classNames = nil; + static dispatch_once_t onceToken; + + dispatch_once(&onceToken, ^{ + classNames = @[ + + ]; + }); + + return classNames; +} + ++(NSArray *)imageDataDecoderClassNames +{ + static NSArray *classNames = nil; + static dispatch_once_t onceToken; + + dispatch_once(&onceToken, ^{ + classNames = @[ + + ]; + }); + + return classNames; +} + ++(NSArray *)URLRequestHandlerClassNames +{ + static NSArray *classNames = nil; + static dispatch_once_t onceToken; + + dispatch_once(&onceToken, ^{ + classNames = @[ + + ]; + }); + + return classNames; +} + +@end diff --git a/packages/app/ios/generated/RCTThirdPartyComponentsProvider.h b/packages/app/ios/generated/RCTThirdPartyComponentsProvider.h new file mode 100644 index 0000000000..ab1a249de3 --- /dev/null +++ b/packages/app/ios/generated/RCTThirdPartyComponentsProvider.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +@protocol RCTComponentViewProtocol; + +@interface RCTThirdPartyComponentsProvider: NSObject + ++ (NSDictionary> *)thirdPartyFabricComponents; + +@end diff --git a/packages/app/ios/generated/RCTThirdPartyComponentsProvider.mm b/packages/app/ios/generated/RCTThirdPartyComponentsProvider.mm new file mode 100644 index 0000000000..4e05532c39 --- /dev/null +++ b/packages/app/ios/generated/RCTThirdPartyComponentsProvider.mm @@ -0,0 +1,30 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + + +#import + +#import "RCTThirdPartyComponentsProvider.h" +#import + +@implementation RCTThirdPartyComponentsProvider + ++ (NSDictionary> *)thirdPartyFabricComponents +{ + static NSDictionary> *thirdPartyComponents = nil; + static dispatch_once_t nativeComponentsToken; + + dispatch_once(&nativeComponentsToken, ^{ + thirdPartyComponents = @{ + + }; + }); + + return thirdPartyComponents; +} + +@end diff --git a/packages/app/ios/generated/RCTUnstableModulesRequiringMainQueueSetupProvider.h b/packages/app/ios/generated/RCTUnstableModulesRequiringMainQueueSetupProvider.h new file mode 100644 index 0000000000..114d32253a --- /dev/null +++ b/packages/app/ios/generated/RCTUnstableModulesRequiringMainQueueSetupProvider.h @@ -0,0 +1,14 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +@interface RCTUnstableModulesRequiringMainQueueSetupProvider: NSObject + ++(NSArray *)modules; + +@end diff --git a/packages/app/ios/generated/RCTUnstableModulesRequiringMainQueueSetupProvider.mm b/packages/app/ios/generated/RCTUnstableModulesRequiringMainQueueSetupProvider.mm new file mode 100644 index 0000000000..9cc59ed7e3 --- /dev/null +++ b/packages/app/ios/generated/RCTUnstableModulesRequiringMainQueueSetupProvider.mm @@ -0,0 +1,19 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import "RCTUnstableModulesRequiringMainQueueSetupProvider.h" + +@implementation RCTUnstableModulesRequiringMainQueueSetupProvider + ++(NSArray *)modules +{ + return @[ + + ]; +} + +@end diff --git a/packages/app/ios/generated/RNFBAppTurboModules/RNFBAppTurboModules-generated.mm b/packages/app/ios/generated/RNFBAppTurboModules/RNFBAppTurboModules-generated.mm new file mode 100644 index 0000000000..cb0ba08784 --- /dev/null +++ b/packages/app/ios/generated/RNFBAppTurboModules/RNFBAppTurboModules-generated.mm @@ -0,0 +1,210 @@ +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleObjCpp + * + * We create an umbrella header (and corresponding implementation) here since + * Cxx compilation in BUCK has a limitation: source-code producing genrule()s + * must have a single output. More files => more genrule()s => slower builds. + */ + +#import "RNFBAppTurboModules.h" + + +@implementation NativeRNFBTurboAppSpecBase + + +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper +{ + _eventEmitterCallback = std::move(eventEmitterCallbackWrapper->_eventEmitterCallback); +} +@end + + +namespace facebook::react { + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboAppSpecJSI_initializeApp(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, PromiseKind, "initializeApp", @selector(initializeApp:appConfig:resolve:reject:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboAppSpecJSI_setAutomaticDataCollectionEnabled(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, VoidKind, "setAutomaticDataCollectionEnabled", @selector(setAutomaticDataCollectionEnabled:enabled:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboAppSpecJSI_deleteApp(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, PromiseKind, "deleteApp", @selector(deleteApp:resolve:reject:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboAppSpecJSI_eventsNotifyReady(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, VoidKind, "eventsNotifyReady", @selector(eventsNotifyReady:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboAppSpecJSI_eventsGetListeners(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, PromiseKind, "eventsGetListeners", @selector(eventsGetListeners:reject:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboAppSpecJSI_eventsPing(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, PromiseKind, "eventsPing", @selector(eventsPing:eventBody:resolve:reject:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboAppSpecJSI_eventsAddListener(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, VoidKind, "eventsAddListener", @selector(eventsAddListener:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboAppSpecJSI_eventsRemoveListener(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, VoidKind, "eventsRemoveListener", @selector(eventsRemoveListener:all:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboAppSpecJSI_addListener(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, VoidKind, "addListener", @selector(addListener:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboAppSpecJSI_removeListeners(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, VoidKind, "removeListeners", @selector(removeListeners:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboAppSpecJSI_metaGetAll(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, PromiseKind, "metaGetAll", @selector(metaGetAll:reject:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboAppSpecJSI_jsonGetAll(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, PromiseKind, "jsonGetAll", @selector(jsonGetAll:reject:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboAppSpecJSI_preferencesSetBool(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, PromiseKind, "preferencesSetBool", @selector(preferencesSetBool:value:resolve:reject:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboAppSpecJSI_preferencesSetString(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, PromiseKind, "preferencesSetString", @selector(preferencesSetString:value:resolve:reject:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboAppSpecJSI_preferencesGetAll(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, PromiseKind, "preferencesGetAll", @selector(preferencesGetAll:reject:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboAppSpecJSI_preferencesClearAll(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, PromiseKind, "preferencesClearAll", @selector(preferencesClearAll:reject:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboAppSpecJSI_setLogLevel(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, VoidKind, "setLogLevel", @selector(setLogLevel:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboAppSpecJSI_getConstants(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, ObjectKind, "getConstants", @selector(getConstants), args, count); + } + + NativeRNFBTurboAppSpecJSI::NativeRNFBTurboAppSpecJSI(const ObjCTurboModule::InitParams ¶ms) + : ObjCTurboModule(params) { + + methodMap_["initializeApp"] = MethodMetadata {2, __hostFunction_NativeRNFBTurboAppSpecJSI_initializeApp}; + + + methodMap_["setAutomaticDataCollectionEnabled"] = MethodMetadata {2, __hostFunction_NativeRNFBTurboAppSpecJSI_setAutomaticDataCollectionEnabled}; + + + methodMap_["deleteApp"] = MethodMetadata {1, __hostFunction_NativeRNFBTurboAppSpecJSI_deleteApp}; + + + methodMap_["eventsNotifyReady"] = MethodMetadata {1, __hostFunction_NativeRNFBTurboAppSpecJSI_eventsNotifyReady}; + + + methodMap_["eventsGetListeners"] = MethodMetadata {0, __hostFunction_NativeRNFBTurboAppSpecJSI_eventsGetListeners}; + + + methodMap_["eventsPing"] = MethodMetadata {2, __hostFunction_NativeRNFBTurboAppSpecJSI_eventsPing}; + + + methodMap_["eventsAddListener"] = MethodMetadata {1, __hostFunction_NativeRNFBTurboAppSpecJSI_eventsAddListener}; + + + methodMap_["eventsRemoveListener"] = MethodMetadata {2, __hostFunction_NativeRNFBTurboAppSpecJSI_eventsRemoveListener}; + + + methodMap_["addListener"] = MethodMetadata {1, __hostFunction_NativeRNFBTurboAppSpecJSI_addListener}; + + + methodMap_["removeListeners"] = MethodMetadata {1, __hostFunction_NativeRNFBTurboAppSpecJSI_removeListeners}; + + + methodMap_["metaGetAll"] = MethodMetadata {0, __hostFunction_NativeRNFBTurboAppSpecJSI_metaGetAll}; + + + methodMap_["jsonGetAll"] = MethodMetadata {0, __hostFunction_NativeRNFBTurboAppSpecJSI_jsonGetAll}; + + + methodMap_["preferencesSetBool"] = MethodMetadata {2, __hostFunction_NativeRNFBTurboAppSpecJSI_preferencesSetBool}; + + + methodMap_["preferencesSetString"] = MethodMetadata {2, __hostFunction_NativeRNFBTurboAppSpecJSI_preferencesSetString}; + + + methodMap_["preferencesGetAll"] = MethodMetadata {0, __hostFunction_NativeRNFBTurboAppSpecJSI_preferencesGetAll}; + + + methodMap_["preferencesClearAll"] = MethodMetadata {0, __hostFunction_NativeRNFBTurboAppSpecJSI_preferencesClearAll}; + + + methodMap_["setLogLevel"] = MethodMetadata {1, __hostFunction_NativeRNFBTurboAppSpecJSI_setLogLevel}; + + + methodMap_["getConstants"] = MethodMetadata {0, __hostFunction_NativeRNFBTurboAppSpecJSI_getConstants}; + + } +} // namespace facebook::react + +@implementation NativeRNFBTurboUtilsSpecBase + + +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper +{ + _eventEmitterCallback = std::move(eventEmitterCallbackWrapper->_eventEmitterCallback); +} +@end + + +namespace facebook::react { + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboUtilsSpecJSI_androidGetPlayServicesStatus(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, PromiseKind, "androidGetPlayServicesStatus", @selector(androidGetPlayServicesStatus:reject:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboUtilsSpecJSI_androidPromptForPlayServices(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, PromiseKind, "androidPromptForPlayServices", @selector(androidPromptForPlayServices:reject:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboUtilsSpecJSI_androidResolutionForPlayServices(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, PromiseKind, "androidResolutionForPlayServices", @selector(androidResolutionForPlayServices:reject:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboUtilsSpecJSI_androidMakePlayServicesAvailable(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, PromiseKind, "androidMakePlayServicesAvailable", @selector(androidMakePlayServicesAvailable:reject:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboUtilsSpecJSI_getConstants(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, ObjectKind, "getConstants", @selector(getConstants), args, count); + } + + NativeRNFBTurboUtilsSpecJSI::NativeRNFBTurboUtilsSpecJSI(const ObjCTurboModule::InitParams ¶ms) + : ObjCTurboModule(params) { + + methodMap_["androidGetPlayServicesStatus"] = MethodMetadata {0, __hostFunction_NativeRNFBTurboUtilsSpecJSI_androidGetPlayServicesStatus}; + + + methodMap_["androidPromptForPlayServices"] = MethodMetadata {0, __hostFunction_NativeRNFBTurboUtilsSpecJSI_androidPromptForPlayServices}; + + + methodMap_["androidResolutionForPlayServices"] = MethodMetadata {0, __hostFunction_NativeRNFBTurboUtilsSpecJSI_androidResolutionForPlayServices}; + + + methodMap_["androidMakePlayServicesAvailable"] = MethodMetadata {0, __hostFunction_NativeRNFBTurboUtilsSpecJSI_androidMakePlayServicesAvailable}; + + + methodMap_["getConstants"] = MethodMetadata {0, __hostFunction_NativeRNFBTurboUtilsSpecJSI_getConstants}; + + } +} // namespace facebook::react diff --git a/packages/app/ios/generated/RNFBAppTurboModules/RNFBAppTurboModules.h b/packages/app/ios/generated/RNFBAppTurboModules/RNFBAppTurboModules.h new file mode 100644 index 0000000000..77ed272284 --- /dev/null +++ b/packages/app/ios/generated/RNFBAppTurboModules/RNFBAppTurboModules.h @@ -0,0 +1,384 @@ +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleObjCpp + * + * We create an umbrella header (and corresponding implementation) here since + * Cxx compilation in BUCK has a limitation: source-code producing genrule()s + * must have a single output. More files => more genrule()s => slower builds. + */ + +#ifndef __cplusplus +#error This file must be compiled as Obj-C++. If you are importing it, you must change your file extension to .mm. +#endif + +// Avoid multiple includes of RNFBAppTurboModules symbols +#ifndef RNFBAppTurboModules_H +#define RNFBAppTurboModules_H + +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import + + +NS_ASSUME_NONNULL_BEGIN +namespace JS { + namespace NativeRNFBTurboApp { + struct FirebaseAppConfig { + + struct Builder { + struct Input { + RCTRequired name; + std::optional automaticResourceManagement; + std::optional automaticDataCollectionEnabled; + }; + + /** Initialize with a set of values */ + Builder(const Input i); + /** Initialize with an existing FirebaseAppConfig */ + Builder(FirebaseAppConfig i); + /** Builds the object. Generally used only by the infrastructure. */ + NSDictionary *buildUnsafeRawValue() const { return _factory(); }; + private: + NSDictionary *(^_factory)(void); + }; + + static FirebaseAppConfig fromUnsafeRawValue(NSDictionary *const v) { return {v}; } + NSDictionary *unsafeRawValue() const { return _v; } + private: + FirebaseAppConfig(NSDictionary *const v) : _v(v) {} + NSDictionary *_v; + }; + } +} +namespace JS { + namespace NativeRNFBTurboApp { + struct FirebaseAppOptions { + + struct Builder { + struct Input { + RCTRequired apiKey; + RCTRequired appId; + NSString *databaseURL; + RCTRequired messagingSenderId; + RCTRequired projectId; + NSString *storageBucket; + NSString *authDomain; + NSString *iosBundleId; + NSString *iosClientId; + NSString *appGroupId; + }; + + /** Initialize with a set of values */ + Builder(const Input i); + /** Initialize with an existing FirebaseAppOptions */ + Builder(FirebaseAppOptions i); + /** Builds the object. Generally used only by the infrastructure. */ + NSDictionary *buildUnsafeRawValue() const { return _factory(); }; + private: + NSDictionary *(^_factory)(void); + }; + + static FirebaseAppOptions fromUnsafeRawValue(NSDictionary *const v) { return {v}; } + NSDictionary *unsafeRawValue() const { return _v; } + private: + FirebaseAppOptions(NSDictionary *const v) : _v(v) {} + NSDictionary *_v; + }; + } +} +namespace JS { + namespace NativeRNFBTurboApp { + struct NativeFirebaseApp { + + struct Builder { + struct Input { + RCTRequired appConfig; + RCTRequired options; + }; + + /** Initialize with a set of values */ + Builder(const Input i); + /** Initialize with an existing NativeFirebaseApp */ + Builder(NativeFirebaseApp i); + /** Builds the object. Generally used only by the infrastructure. */ + NSDictionary *buildUnsafeRawValue() const { return _factory(); }; + private: + NSDictionary *(^_factory)(void); + }; + + static NativeFirebaseApp fromUnsafeRawValue(NSDictionary *const v) { return {v}; } + NSDictionary *unsafeRawValue() const { return _v; } + private: + NativeFirebaseApp(NSDictionary *const v) : _v(v) {} + NSDictionary *_v; + }; + } +} +namespace JS { + namespace NativeRNFBTurboApp { + struct Constants { + + struct Builder { + struct Input { + RCTRequired> NATIVE_FIREBASE_APPS; + RCTRequired FIREBASE_RAW_JSON; + }; + + /** Initialize with a set of values */ + Builder(const Input i); + /** Initialize with an existing Constants */ + Builder(Constants i); + /** Builds the object. Generally used only by the infrastructure. */ + NSDictionary *buildUnsafeRawValue() const { return _factory(); }; + private: + NSDictionary *(^_factory)(void); + }; + + static Constants fromUnsafeRawValue(NSDictionary *const v) { return {v}; } + NSDictionary *unsafeRawValue() const { return _v; } + private: + Constants(NSDictionary *const v) : _v(v) {} + NSDictionary *_v; + }; + } +} +@protocol NativeRNFBTurboAppSpec + +- (void)initializeApp:(NSDictionary *)options + appConfig:(NSDictionary *)appConfig + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; +- (void)setAutomaticDataCollectionEnabled:(NSString *)appName + enabled:(BOOL)enabled; +- (void)deleteApp:(NSString *)appName + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; +- (void)eventsNotifyReady:(BOOL)ready; +- (void)eventsGetListeners:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; +- (void)eventsPing:(NSString *)eventName + eventBody:(NSDictionary *)eventBody + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; +- (void)eventsAddListener:(NSString *)eventName; +- (void)eventsRemoveListener:(NSString *)eventName + all:(BOOL)all; +- (void)addListener:(NSString *)eventName; +- (void)removeListeners:(double)count; +- (void)metaGetAll:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; +- (void)jsonGetAll:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; +- (void)preferencesSetBool:(NSString *)key + value:(BOOL)value + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; +- (void)preferencesSetString:(NSString *)key + value:(NSString *)value + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; +- (void)preferencesGetAll:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; +- (void)preferencesClearAll:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; +- (void)setLogLevel:(NSString *)logLevel; +- (facebook::react::ModuleConstants)constantsToExport; +- (facebook::react::ModuleConstants)getConstants; + +@end + +@interface NativeRNFBTurboAppSpecBase : NSObject { +@protected +facebook::react::EventEmitterCallback _eventEmitterCallback; +} +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper; + + +@end + +namespace facebook::react { + /** + * ObjC++ class for module 'NativeRNFBTurboApp' + */ + class JSI_EXPORT NativeRNFBTurboAppSpecJSI : public ObjCTurboModule { + public: + NativeRNFBTurboAppSpecJSI(const ObjCTurboModule::InitParams ¶ms); + }; +} // namespace facebook::react +namespace JS { + namespace NativeRNFBTurboUtils { + struct Constants { + + struct Builder { + struct Input { + RCTRequired isRunningInTestLab; + RCTRequired MAIN_BUNDLE; + RCTRequired CACHES_DIRECTORY; + RCTRequired DOCUMENT_DIRECTORY; + NSString *EXTERNAL_DIRECTORY; + NSString *EXTERNAL_STORAGE_DIRECTORY; + RCTRequired TEMP_DIRECTORY; + RCTRequired LIBRARY_DIRECTORY; + RCTRequired PICTURES_DIRECTORY; + RCTRequired MOVIES_DIRECTORY; + NSString *FILE_TYPE_REGULAR; + NSString *FILE_TYPE_DIRECTORY; + }; + + /** Initialize with a set of values */ + Builder(const Input i); + /** Initialize with an existing Constants */ + Builder(Constants i); + /** Builds the object. Generally used only by the infrastructure. */ + NSDictionary *buildUnsafeRawValue() const { return _factory(); }; + private: + NSDictionary *(^_factory)(void); + }; + + static Constants fromUnsafeRawValue(NSDictionary *const v) { return {v}; } + NSDictionary *unsafeRawValue() const { return _v; } + private: + Constants(NSDictionary *const v) : _v(v) {} + NSDictionary *_v; + }; + } +} +@protocol NativeRNFBTurboUtilsSpec + +- (void)androidGetPlayServicesStatus:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; +- (void)androidPromptForPlayServices:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; +- (void)androidResolutionForPlayServices:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; +- (void)androidMakePlayServicesAvailable:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; +- (facebook::react::ModuleConstants)constantsToExport; +- (facebook::react::ModuleConstants)getConstants; + +@end + +@interface NativeRNFBTurboUtilsSpecBase : NSObject { +@protected +facebook::react::EventEmitterCallback _eventEmitterCallback; +} +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper; + + +@end + +namespace facebook::react { + /** + * ObjC++ class for module 'NativeRNFBTurboUtils' + */ + class JSI_EXPORT NativeRNFBTurboUtilsSpecJSI : public ObjCTurboModule { + public: + NativeRNFBTurboUtilsSpecJSI(const ObjCTurboModule::InitParams ¶ms); + }; +} // namespace facebook::react +inline JS::NativeRNFBTurboApp::FirebaseAppConfig::Builder::Builder(const Input i) : _factory(^{ + NSMutableDictionary *d = [NSMutableDictionary new]; + auto name = i.name.get(); + d[@"name"] = name; + auto automaticResourceManagement = i.automaticResourceManagement; + d[@"automaticResourceManagement"] = automaticResourceManagement.has_value() ? @((BOOL)automaticResourceManagement.value()) : nil; + auto automaticDataCollectionEnabled = i.automaticDataCollectionEnabled; + d[@"automaticDataCollectionEnabled"] = automaticDataCollectionEnabled.has_value() ? @((BOOL)automaticDataCollectionEnabled.value()) : nil; + return d; +}) {} +inline JS::NativeRNFBTurboApp::FirebaseAppConfig::Builder::Builder(FirebaseAppConfig i) : _factory(^{ + return i.unsafeRawValue(); +}) {} +inline JS::NativeRNFBTurboApp::FirebaseAppOptions::Builder::Builder(const Input i) : _factory(^{ + NSMutableDictionary *d = [NSMutableDictionary new]; + auto apiKey = i.apiKey.get(); + d[@"apiKey"] = apiKey; + auto appId = i.appId.get(); + d[@"appId"] = appId; + auto databaseURL = i.databaseURL; + d[@"databaseURL"] = databaseURL; + auto messagingSenderId = i.messagingSenderId.get(); + d[@"messagingSenderId"] = messagingSenderId; + auto projectId = i.projectId.get(); + d[@"projectId"] = projectId; + auto storageBucket = i.storageBucket; + d[@"storageBucket"] = storageBucket; + auto authDomain = i.authDomain; + d[@"authDomain"] = authDomain; + auto iosBundleId = i.iosBundleId; + d[@"iosBundleId"] = iosBundleId; + auto iosClientId = i.iosClientId; + d[@"iosClientId"] = iosClientId; + auto appGroupId = i.appGroupId; + d[@"appGroupId"] = appGroupId; + return d; +}) {} +inline JS::NativeRNFBTurboApp::FirebaseAppOptions::Builder::Builder(FirebaseAppOptions i) : _factory(^{ + return i.unsafeRawValue(); +}) {} +inline JS::NativeRNFBTurboApp::NativeFirebaseApp::Builder::Builder(const Input i) : _factory(^{ + NSMutableDictionary *d = [NSMutableDictionary new]; + auto appConfig = i.appConfig.get(); + d[@"appConfig"] = appConfig.buildUnsafeRawValue(); + auto options = i.options.get(); + d[@"options"] = options.buildUnsafeRawValue(); + return d; +}) {} +inline JS::NativeRNFBTurboApp::NativeFirebaseApp::Builder::Builder(NativeFirebaseApp i) : _factory(^{ + return i.unsafeRawValue(); +}) {} +inline JS::NativeRNFBTurboApp::Constants::Builder::Builder(const Input i) : _factory(^{ + NSMutableDictionary *d = [NSMutableDictionary new]; + auto NATIVE_FIREBASE_APPS = i.NATIVE_FIREBASE_APPS.get(); + d[@"NATIVE_FIREBASE_APPS"] = RCTConvertVecToArray(NATIVE_FIREBASE_APPS, ^id(JS::NativeRNFBTurboApp::NativeFirebaseApp::Builder el_) { return el_.buildUnsafeRawValue(); }); + auto FIREBASE_RAW_JSON = i.FIREBASE_RAW_JSON.get(); + d[@"FIREBASE_RAW_JSON"] = FIREBASE_RAW_JSON; + return d; +}) {} +inline JS::NativeRNFBTurboApp::Constants::Builder::Builder(Constants i) : _factory(^{ + return i.unsafeRawValue(); +}) {} +inline JS::NativeRNFBTurboUtils::Constants::Builder::Builder(const Input i) : _factory(^{ + NSMutableDictionary *d = [NSMutableDictionary new]; + auto isRunningInTestLab = i.isRunningInTestLab.get(); + d[@"isRunningInTestLab"] = @(isRunningInTestLab); + auto MAIN_BUNDLE = i.MAIN_BUNDLE.get(); + d[@"MAIN_BUNDLE"] = MAIN_BUNDLE; + auto CACHES_DIRECTORY = i.CACHES_DIRECTORY.get(); + d[@"CACHES_DIRECTORY"] = CACHES_DIRECTORY; + auto DOCUMENT_DIRECTORY = i.DOCUMENT_DIRECTORY.get(); + d[@"DOCUMENT_DIRECTORY"] = DOCUMENT_DIRECTORY; + auto EXTERNAL_DIRECTORY = i.EXTERNAL_DIRECTORY; + d[@"EXTERNAL_DIRECTORY"] = EXTERNAL_DIRECTORY; + auto EXTERNAL_STORAGE_DIRECTORY = i.EXTERNAL_STORAGE_DIRECTORY; + d[@"EXTERNAL_STORAGE_DIRECTORY"] = EXTERNAL_STORAGE_DIRECTORY; + auto TEMP_DIRECTORY = i.TEMP_DIRECTORY.get(); + d[@"TEMP_DIRECTORY"] = TEMP_DIRECTORY; + auto LIBRARY_DIRECTORY = i.LIBRARY_DIRECTORY.get(); + d[@"LIBRARY_DIRECTORY"] = LIBRARY_DIRECTORY; + auto PICTURES_DIRECTORY = i.PICTURES_DIRECTORY.get(); + d[@"PICTURES_DIRECTORY"] = PICTURES_DIRECTORY; + auto MOVIES_DIRECTORY = i.MOVIES_DIRECTORY.get(); + d[@"MOVIES_DIRECTORY"] = MOVIES_DIRECTORY; + auto FILE_TYPE_REGULAR = i.FILE_TYPE_REGULAR; + d[@"FILE_TYPE_REGULAR"] = FILE_TYPE_REGULAR; + auto FILE_TYPE_DIRECTORY = i.FILE_TYPE_DIRECTORY; + d[@"FILE_TYPE_DIRECTORY"] = FILE_TYPE_DIRECTORY; + return d; +}) {} +inline JS::NativeRNFBTurboUtils::Constants::Builder::Builder(Constants i) : _factory(^{ + return i.unsafeRawValue(); +}) {} +NS_ASSUME_NONNULL_END +#endif // RNFBAppTurboModules_H diff --git a/packages/app/ios/generated/RNFBAppTurboModulesJSI-generated.cpp b/packages/app/ios/generated/RNFBAppTurboModulesJSI-generated.cpp new file mode 100644 index 0000000000..1fab136ed3 --- /dev/null +++ b/packages/app/ios/generated/RNFBAppTurboModulesJSI-generated.cpp @@ -0,0 +1,187 @@ +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleCpp.js + */ + +#include "RNFBAppTurboModulesJSI.h" + +namespace facebook::react { + +static jsi::Value __hostFunction_NativeRNFBTurboAppCxxSpecJSI_getConstants(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getConstants( + rt + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboAppCxxSpecJSI_initializeApp(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->initializeApp( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asObject(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asObject(rt) + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboAppCxxSpecJSI_setAutomaticDataCollectionEnabled(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + static_cast(&turboModule)->setAutomaticDataCollectionEnabled( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asBool() + ); + return jsi::Value::undefined(); +} +static jsi::Value __hostFunction_NativeRNFBTurboAppCxxSpecJSI_deleteApp(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->deleteApp( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt) + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboAppCxxSpecJSI_eventsNotifyReady(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + static_cast(&turboModule)->eventsNotifyReady( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asBool() + ); + return jsi::Value::undefined(); +} +static jsi::Value __hostFunction_NativeRNFBTurboAppCxxSpecJSI_eventsGetListeners(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->eventsGetListeners( + rt + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboAppCxxSpecJSI_eventsPing(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->eventsPing( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asObject(rt) + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboAppCxxSpecJSI_eventsAddListener(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + static_cast(&turboModule)->eventsAddListener( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt) + ); + return jsi::Value::undefined(); +} +static jsi::Value __hostFunction_NativeRNFBTurboAppCxxSpecJSI_eventsRemoveListener(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + static_cast(&turboModule)->eventsRemoveListener( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asBool() + ); + return jsi::Value::undefined(); +} +static jsi::Value __hostFunction_NativeRNFBTurboAppCxxSpecJSI_addListener(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + static_cast(&turboModule)->addListener( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt) + ); + return jsi::Value::undefined(); +} +static jsi::Value __hostFunction_NativeRNFBTurboAppCxxSpecJSI_removeListeners(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + static_cast(&turboModule)->removeListeners( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asNumber() + ); + return jsi::Value::undefined(); +} +static jsi::Value __hostFunction_NativeRNFBTurboAppCxxSpecJSI_metaGetAll(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->metaGetAll( + rt + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboAppCxxSpecJSI_jsonGetAll(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->jsonGetAll( + rt + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboAppCxxSpecJSI_preferencesSetBool(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->preferencesSetBool( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asBool() + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboAppCxxSpecJSI_preferencesSetString(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->preferencesSetString( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt) + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboAppCxxSpecJSI_preferencesGetAll(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->preferencesGetAll( + rt + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboAppCxxSpecJSI_preferencesClearAll(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->preferencesClearAll( + rt + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboAppCxxSpecJSI_setLogLevel(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + static_cast(&turboModule)->setLogLevel( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt) + ); + return jsi::Value::undefined(); +} + +NativeRNFBTurboAppCxxSpecJSI::NativeRNFBTurboAppCxxSpecJSI(std::shared_ptr jsInvoker) + : TurboModule("NativeRNFBTurboApp", jsInvoker) { + methodMap_["getConstants"] = MethodMetadata {0, __hostFunction_NativeRNFBTurboAppCxxSpecJSI_getConstants}; + methodMap_["initializeApp"] = MethodMetadata {2, __hostFunction_NativeRNFBTurboAppCxxSpecJSI_initializeApp}; + methodMap_["setAutomaticDataCollectionEnabled"] = MethodMetadata {2, __hostFunction_NativeRNFBTurboAppCxxSpecJSI_setAutomaticDataCollectionEnabled}; + methodMap_["deleteApp"] = MethodMetadata {1, __hostFunction_NativeRNFBTurboAppCxxSpecJSI_deleteApp}; + methodMap_["eventsNotifyReady"] = MethodMetadata {1, __hostFunction_NativeRNFBTurboAppCxxSpecJSI_eventsNotifyReady}; + methodMap_["eventsGetListeners"] = MethodMetadata {0, __hostFunction_NativeRNFBTurboAppCxxSpecJSI_eventsGetListeners}; + methodMap_["eventsPing"] = MethodMetadata {2, __hostFunction_NativeRNFBTurboAppCxxSpecJSI_eventsPing}; + methodMap_["eventsAddListener"] = MethodMetadata {1, __hostFunction_NativeRNFBTurboAppCxxSpecJSI_eventsAddListener}; + methodMap_["eventsRemoveListener"] = MethodMetadata {2, __hostFunction_NativeRNFBTurboAppCxxSpecJSI_eventsRemoveListener}; + methodMap_["addListener"] = MethodMetadata {1, __hostFunction_NativeRNFBTurboAppCxxSpecJSI_addListener}; + methodMap_["removeListeners"] = MethodMetadata {1, __hostFunction_NativeRNFBTurboAppCxxSpecJSI_removeListeners}; + methodMap_["metaGetAll"] = MethodMetadata {0, __hostFunction_NativeRNFBTurboAppCxxSpecJSI_metaGetAll}; + methodMap_["jsonGetAll"] = MethodMetadata {0, __hostFunction_NativeRNFBTurboAppCxxSpecJSI_jsonGetAll}; + methodMap_["preferencesSetBool"] = MethodMetadata {2, __hostFunction_NativeRNFBTurboAppCxxSpecJSI_preferencesSetBool}; + methodMap_["preferencesSetString"] = MethodMetadata {2, __hostFunction_NativeRNFBTurboAppCxxSpecJSI_preferencesSetString}; + methodMap_["preferencesGetAll"] = MethodMetadata {0, __hostFunction_NativeRNFBTurboAppCxxSpecJSI_preferencesGetAll}; + methodMap_["preferencesClearAll"] = MethodMetadata {0, __hostFunction_NativeRNFBTurboAppCxxSpecJSI_preferencesClearAll}; + methodMap_["setLogLevel"] = MethodMetadata {1, __hostFunction_NativeRNFBTurboAppCxxSpecJSI_setLogLevel}; +} +static jsi::Value __hostFunction_NativeRNFBTurboUtilsCxxSpecJSI_getConstants(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getConstants( + rt + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboUtilsCxxSpecJSI_androidGetPlayServicesStatus(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->androidGetPlayServicesStatus( + rt + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboUtilsCxxSpecJSI_androidPromptForPlayServices(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->androidPromptForPlayServices( + rt + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboUtilsCxxSpecJSI_androidResolutionForPlayServices(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->androidResolutionForPlayServices( + rt + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboUtilsCxxSpecJSI_androidMakePlayServicesAvailable(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->androidMakePlayServicesAvailable( + rt + ); +} + +NativeRNFBTurboUtilsCxxSpecJSI::NativeRNFBTurboUtilsCxxSpecJSI(std::shared_ptr jsInvoker) + : TurboModule("NativeRNFBTurboUtils", jsInvoker) { + methodMap_["getConstants"] = MethodMetadata {0, __hostFunction_NativeRNFBTurboUtilsCxxSpecJSI_getConstants}; + methodMap_["androidGetPlayServicesStatus"] = MethodMetadata {0, __hostFunction_NativeRNFBTurboUtilsCxxSpecJSI_androidGetPlayServicesStatus}; + methodMap_["androidPromptForPlayServices"] = MethodMetadata {0, __hostFunction_NativeRNFBTurboUtilsCxxSpecJSI_androidPromptForPlayServices}; + methodMap_["androidResolutionForPlayServices"] = MethodMetadata {0, __hostFunction_NativeRNFBTurboUtilsCxxSpecJSI_androidResolutionForPlayServices}; + methodMap_["androidMakePlayServicesAvailable"] = MethodMetadata {0, __hostFunction_NativeRNFBTurboUtilsCxxSpecJSI_androidMakePlayServicesAvailable}; +} + + +} // namespace facebook::react diff --git a/packages/app/ios/generated/RNFBAppTurboModulesJSI.h b/packages/app/ios/generated/RNFBAppTurboModulesJSI.h new file mode 100644 index 0000000000..2a25d7e6e9 --- /dev/null +++ b/packages/app/ios/generated/RNFBAppTurboModulesJSI.h @@ -0,0 +1,606 @@ +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleH.js + */ + +#pragma once + +#include +#include + +namespace facebook::react { + + + +#pragma mark - NativeRNFBTurboAppFirebaseAppConfig + +template +struct NativeRNFBTurboAppFirebaseAppConfig { + P0 name; + P1 automaticResourceManagement; + P2 automaticDataCollectionEnabled; + bool operator==(const NativeRNFBTurboAppFirebaseAppConfig &other) const { + return name == other.name && automaticResourceManagement == other.automaticResourceManagement && automaticDataCollectionEnabled == other.automaticDataCollectionEnabled; + } +}; + +template +struct NativeRNFBTurboAppFirebaseAppConfigBridging { + static T types; + + static T fromJs( + jsi::Runtime &rt, + const jsi::Object &value, + const std::shared_ptr &jsInvoker) { + T result{ + bridging::fromJs(rt, value.getProperty(rt, "name"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, "automaticResourceManagement"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, "automaticDataCollectionEnabled"), jsInvoker)}; + return result; + } + +#ifdef DEBUG + static jsi::String nameToJs(jsi::Runtime &rt, decltype(types.name) value) { + return bridging::toJs(rt, value); + } + + static bool automaticResourceManagementToJs(jsi::Runtime &rt, decltype(types.automaticResourceManagement) value) { + return bridging::toJs(rt, value); + } + + static bool automaticDataCollectionEnabledToJs(jsi::Runtime &rt, decltype(types.automaticDataCollectionEnabled) value) { + return bridging::toJs(rt, value); + } +#endif + + static jsi::Object toJs( + jsi::Runtime &rt, + const T &value, + const std::shared_ptr &jsInvoker) { + auto result = facebook::jsi::Object(rt); + result.setProperty(rt, "name", bridging::toJs(rt, value.name, jsInvoker)); + if (value.automaticResourceManagement) { + result.setProperty(rt, "automaticResourceManagement", bridging::toJs(rt, value.automaticResourceManagement.value(), jsInvoker)); + } + if (value.automaticDataCollectionEnabled) { + result.setProperty(rt, "automaticDataCollectionEnabled", bridging::toJs(rt, value.automaticDataCollectionEnabled.value(), jsInvoker)); + } + return result; + } +}; + + + +#pragma mark - NativeRNFBTurboAppFirebaseAppOptions + +template +struct NativeRNFBTurboAppFirebaseAppOptions { + P0 apiKey; + P1 appId; + P2 databaseURL; + P3 messagingSenderId; + P4 projectId; + P5 storageBucket; + P6 authDomain; + P7 iosBundleId; + P8 iosClientId; + P9 appGroupId; + bool operator==(const NativeRNFBTurboAppFirebaseAppOptions &other) const { + return apiKey == other.apiKey && appId == other.appId && databaseURL == other.databaseURL && messagingSenderId == other.messagingSenderId && projectId == other.projectId && storageBucket == other.storageBucket && authDomain == other.authDomain && iosBundleId == other.iosBundleId && iosClientId == other.iosClientId && appGroupId == other.appGroupId; + } +}; + +template +struct NativeRNFBTurboAppFirebaseAppOptionsBridging { + static T types; + + static T fromJs( + jsi::Runtime &rt, + const jsi::Object &value, + const std::shared_ptr &jsInvoker) { + T result{ + bridging::fromJs(rt, value.getProperty(rt, "apiKey"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, "appId"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, "databaseURL"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, "messagingSenderId"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, "projectId"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, "storageBucket"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, "authDomain"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, "iosBundleId"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, "iosClientId"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, "appGroupId"), jsInvoker)}; + return result; + } + +#ifdef DEBUG + static jsi::String apiKeyToJs(jsi::Runtime &rt, decltype(types.apiKey) value) { + return bridging::toJs(rt, value); + } + + static jsi::String appIdToJs(jsi::Runtime &rt, decltype(types.appId) value) { + return bridging::toJs(rt, value); + } + + static std::optional databaseURLToJs(jsi::Runtime &rt, decltype(types.databaseURL) value) { + return bridging::toJs(rt, value); + } + + static jsi::String messagingSenderIdToJs(jsi::Runtime &rt, decltype(types.messagingSenderId) value) { + return bridging::toJs(rt, value); + } + + static jsi::String projectIdToJs(jsi::Runtime &rt, decltype(types.projectId) value) { + return bridging::toJs(rt, value); + } + + static std::optional storageBucketToJs(jsi::Runtime &rt, decltype(types.storageBucket) value) { + return bridging::toJs(rt, value); + } + + static std::optional authDomainToJs(jsi::Runtime &rt, decltype(types.authDomain) value) { + return bridging::toJs(rt, value); + } + + static std::optional iosBundleIdToJs(jsi::Runtime &rt, decltype(types.iosBundleId) value) { + return bridging::toJs(rt, value); + } + + static std::optional iosClientIdToJs(jsi::Runtime &rt, decltype(types.iosClientId) value) { + return bridging::toJs(rt, value); + } + + static std::optional appGroupIdToJs(jsi::Runtime &rt, decltype(types.appGroupId) value) { + return bridging::toJs(rt, value); + } +#endif + + static jsi::Object toJs( + jsi::Runtime &rt, + const T &value, + const std::shared_ptr &jsInvoker) { + auto result = facebook::jsi::Object(rt); + result.setProperty(rt, "apiKey", bridging::toJs(rt, value.apiKey, jsInvoker)); + result.setProperty(rt, "appId", bridging::toJs(rt, value.appId, jsInvoker)); + if (value.databaseURL) { + result.setProperty(rt, "databaseURL", bridging::toJs(rt, value.databaseURL.value(), jsInvoker)); + } + result.setProperty(rt, "messagingSenderId", bridging::toJs(rt, value.messagingSenderId, jsInvoker)); + result.setProperty(rt, "projectId", bridging::toJs(rt, value.projectId, jsInvoker)); + if (value.storageBucket) { + result.setProperty(rt, "storageBucket", bridging::toJs(rt, value.storageBucket.value(), jsInvoker)); + } + if (value.authDomain) { + result.setProperty(rt, "authDomain", bridging::toJs(rt, value.authDomain.value(), jsInvoker)); + } + if (value.iosBundleId) { + result.setProperty(rt, "iosBundleId", bridging::toJs(rt, value.iosBundleId.value(), jsInvoker)); + } + if (value.iosClientId) { + result.setProperty(rt, "iosClientId", bridging::toJs(rt, value.iosClientId.value(), jsInvoker)); + } + if (value.appGroupId) { + result.setProperty(rt, "appGroupId", bridging::toJs(rt, value.appGroupId.value(), jsInvoker)); + } + return result; + } +}; + + + +#pragma mark - NativeRNFBTurboAppNativeFirebaseApp + +template +struct NativeRNFBTurboAppNativeFirebaseApp { + P0 appConfig; + P1 options; + bool operator==(const NativeRNFBTurboAppNativeFirebaseApp &other) const { + return appConfig == other.appConfig && options == other.options; + } +}; + +template +struct NativeRNFBTurboAppNativeFirebaseAppBridging { + static T types; + + static T fromJs( + jsi::Runtime &rt, + const jsi::Object &value, + const std::shared_ptr &jsInvoker) { + T result{ + bridging::fromJs(rt, value.getProperty(rt, "appConfig"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, "options"), jsInvoker)}; + return result; + } + +#ifdef DEBUG + static jsi::Object appConfigToJs(jsi::Runtime &rt, decltype(types.appConfig) value) { + return bridging::toJs(rt, value); + } + + static jsi::Object optionsToJs(jsi::Runtime &rt, decltype(types.options) value) { + return bridging::toJs(rt, value); + } +#endif + + static jsi::Object toJs( + jsi::Runtime &rt, + const T &value, + const std::shared_ptr &jsInvoker) { + auto result = facebook::jsi::Object(rt); + result.setProperty(rt, "appConfig", bridging::toJs(rt, value.appConfig, jsInvoker)); + result.setProperty(rt, "options", bridging::toJs(rt, value.options, jsInvoker)); + return result; + } +}; + +class JSI_EXPORT NativeRNFBTurboAppCxxSpecJSI : public TurboModule { +protected: + NativeRNFBTurboAppCxxSpecJSI(std::shared_ptr jsInvoker); + +public: + virtual jsi::Object getConstants(jsi::Runtime &rt) = 0; + virtual jsi::Value initializeApp(jsi::Runtime &rt, jsi::Object options, jsi::Object appConfig) = 0; + virtual void setAutomaticDataCollectionEnabled(jsi::Runtime &rt, jsi::String appName, bool enabled) = 0; + virtual jsi::Value deleteApp(jsi::Runtime &rt, jsi::String appName) = 0; + virtual void eventsNotifyReady(jsi::Runtime &rt, bool ready) = 0; + virtual jsi::Value eventsGetListeners(jsi::Runtime &rt) = 0; + virtual jsi::Value eventsPing(jsi::Runtime &rt, jsi::String eventName, jsi::Object eventBody) = 0; + virtual void eventsAddListener(jsi::Runtime &rt, jsi::String eventName) = 0; + virtual void eventsRemoveListener(jsi::Runtime &rt, jsi::String eventName, bool all) = 0; + virtual void addListener(jsi::Runtime &rt, jsi::String eventName) = 0; + virtual void removeListeners(jsi::Runtime &rt, double count) = 0; + virtual jsi::Value metaGetAll(jsi::Runtime &rt) = 0; + virtual jsi::Value jsonGetAll(jsi::Runtime &rt) = 0; + virtual jsi::Value preferencesSetBool(jsi::Runtime &rt, jsi::String key, bool value) = 0; + virtual jsi::Value preferencesSetString(jsi::Runtime &rt, jsi::String key, jsi::String value) = 0; + virtual jsi::Value preferencesGetAll(jsi::Runtime &rt) = 0; + virtual jsi::Value preferencesClearAll(jsi::Runtime &rt) = 0; + virtual void setLogLevel(jsi::Runtime &rt, jsi::String logLevel) = 0; + +}; + +template +class JSI_EXPORT NativeRNFBTurboAppCxxSpec : public TurboModule { +public: + jsi::Value create(jsi::Runtime &rt, const jsi::PropNameID &propName) override { + return delegate_.create(rt, propName); + } + + std::vector getPropertyNames(jsi::Runtime& runtime) override { + return delegate_.getPropertyNames(runtime); + } + + static constexpr std::string_view kModuleName = "NativeRNFBTurboApp"; + +protected: + NativeRNFBTurboAppCxxSpec(std::shared_ptr jsInvoker) + : TurboModule(std::string{NativeRNFBTurboAppCxxSpec::kModuleName}, jsInvoker), + delegate_(reinterpret_cast(this), jsInvoker) {} + + +private: + class Delegate : public NativeRNFBTurboAppCxxSpecJSI { + public: + Delegate(T *instance, std::shared_ptr jsInvoker) : + NativeRNFBTurboAppCxxSpecJSI(std::move(jsInvoker)), instance_(instance) { + + } + + jsi::Object getConstants(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::getConstants) == 1, + "Expected getConstants(...) to have 1 parameters"); + + return bridging::callFromJs( + rt, &T::getConstants, jsInvoker_, instance_); + } + jsi::Value initializeApp(jsi::Runtime &rt, jsi::Object options, jsi::Object appConfig) override { + static_assert( + bridging::getParameterCount(&T::initializeApp) == 3, + "Expected initializeApp(...) to have 3 parameters"); + + return bridging::callFromJs( + rt, &T::initializeApp, jsInvoker_, instance_, std::move(options), std::move(appConfig)); + } + void setAutomaticDataCollectionEnabled(jsi::Runtime &rt, jsi::String appName, bool enabled) override { + static_assert( + bridging::getParameterCount(&T::setAutomaticDataCollectionEnabled) == 3, + "Expected setAutomaticDataCollectionEnabled(...) to have 3 parameters"); + + return bridging::callFromJs( + rt, &T::setAutomaticDataCollectionEnabled, jsInvoker_, instance_, std::move(appName), std::move(enabled)); + } + jsi::Value deleteApp(jsi::Runtime &rt, jsi::String appName) override { + static_assert( + bridging::getParameterCount(&T::deleteApp) == 2, + "Expected deleteApp(...) to have 2 parameters"); + + return bridging::callFromJs( + rt, &T::deleteApp, jsInvoker_, instance_, std::move(appName)); + } + void eventsNotifyReady(jsi::Runtime &rt, bool ready) override { + static_assert( + bridging::getParameterCount(&T::eventsNotifyReady) == 2, + "Expected eventsNotifyReady(...) to have 2 parameters"); + + return bridging::callFromJs( + rt, &T::eventsNotifyReady, jsInvoker_, instance_, std::move(ready)); + } + jsi::Value eventsGetListeners(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::eventsGetListeners) == 1, + "Expected eventsGetListeners(...) to have 1 parameters"); + + return bridging::callFromJs( + rt, &T::eventsGetListeners, jsInvoker_, instance_); + } + jsi::Value eventsPing(jsi::Runtime &rt, jsi::String eventName, jsi::Object eventBody) override { + static_assert( + bridging::getParameterCount(&T::eventsPing) == 3, + "Expected eventsPing(...) to have 3 parameters"); + + return bridging::callFromJs( + rt, &T::eventsPing, jsInvoker_, instance_, std::move(eventName), std::move(eventBody)); + } + void eventsAddListener(jsi::Runtime &rt, jsi::String eventName) override { + static_assert( + bridging::getParameterCount(&T::eventsAddListener) == 2, + "Expected eventsAddListener(...) to have 2 parameters"); + + return bridging::callFromJs( + rt, &T::eventsAddListener, jsInvoker_, instance_, std::move(eventName)); + } + void eventsRemoveListener(jsi::Runtime &rt, jsi::String eventName, bool all) override { + static_assert( + bridging::getParameterCount(&T::eventsRemoveListener) == 3, + "Expected eventsRemoveListener(...) to have 3 parameters"); + + return bridging::callFromJs( + rt, &T::eventsRemoveListener, jsInvoker_, instance_, std::move(eventName), std::move(all)); + } + void addListener(jsi::Runtime &rt, jsi::String eventName) override { + static_assert( + bridging::getParameterCount(&T::addListener) == 2, + "Expected addListener(...) to have 2 parameters"); + + return bridging::callFromJs( + rt, &T::addListener, jsInvoker_, instance_, std::move(eventName)); + } + void removeListeners(jsi::Runtime &rt, double count) override { + static_assert( + bridging::getParameterCount(&T::removeListeners) == 2, + "Expected removeListeners(...) to have 2 parameters"); + + return bridging::callFromJs( + rt, &T::removeListeners, jsInvoker_, instance_, std::move(count)); + } + jsi::Value metaGetAll(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::metaGetAll) == 1, + "Expected metaGetAll(...) to have 1 parameters"); + + return bridging::callFromJs( + rt, &T::metaGetAll, jsInvoker_, instance_); + } + jsi::Value jsonGetAll(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::jsonGetAll) == 1, + "Expected jsonGetAll(...) to have 1 parameters"); + + return bridging::callFromJs( + rt, &T::jsonGetAll, jsInvoker_, instance_); + } + jsi::Value preferencesSetBool(jsi::Runtime &rt, jsi::String key, bool value) override { + static_assert( + bridging::getParameterCount(&T::preferencesSetBool) == 3, + "Expected preferencesSetBool(...) to have 3 parameters"); + + return bridging::callFromJs( + rt, &T::preferencesSetBool, jsInvoker_, instance_, std::move(key), std::move(value)); + } + jsi::Value preferencesSetString(jsi::Runtime &rt, jsi::String key, jsi::String value) override { + static_assert( + bridging::getParameterCount(&T::preferencesSetString) == 3, + "Expected preferencesSetString(...) to have 3 parameters"); + + return bridging::callFromJs( + rt, &T::preferencesSetString, jsInvoker_, instance_, std::move(key), std::move(value)); + } + jsi::Value preferencesGetAll(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::preferencesGetAll) == 1, + "Expected preferencesGetAll(...) to have 1 parameters"); + + return bridging::callFromJs( + rt, &T::preferencesGetAll, jsInvoker_, instance_); + } + jsi::Value preferencesClearAll(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::preferencesClearAll) == 1, + "Expected preferencesClearAll(...) to have 1 parameters"); + + return bridging::callFromJs( + rt, &T::preferencesClearAll, jsInvoker_, instance_); + } + void setLogLevel(jsi::Runtime &rt, jsi::String logLevel) override { + static_assert( + bridging::getParameterCount(&T::setLogLevel) == 2, + "Expected setLogLevel(...) to have 2 parameters"); + + return bridging::callFromJs( + rt, &T::setLogLevel, jsInvoker_, instance_, std::move(logLevel)); + } + + private: + friend class NativeRNFBTurboAppCxxSpec; + T *instance_; + }; + + Delegate delegate_; +}; + + + +#pragma mark - NativeRNFBTurboUtilsPlayServicesAvailability + +template +struct NativeRNFBTurboUtilsPlayServicesAvailability { + P0 isAvailable; + P1 status; + P2 hasResolution; + P3 isUserResolvableError; + P4 error; + bool operator==(const NativeRNFBTurboUtilsPlayServicesAvailability &other) const { + return isAvailable == other.isAvailable && status == other.status && hasResolution == other.hasResolution && isUserResolvableError == other.isUserResolvableError && error == other.error; + } +}; + +template +struct NativeRNFBTurboUtilsPlayServicesAvailabilityBridging { + static T types; + + static T fromJs( + jsi::Runtime &rt, + const jsi::Object &value, + const std::shared_ptr &jsInvoker) { + T result{ + bridging::fromJs(rt, value.getProperty(rt, "isAvailable"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, "status"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, "hasResolution"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, "isUserResolvableError"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, "error"), jsInvoker)}; + return result; + } + +#ifdef DEBUG + static bool isAvailableToJs(jsi::Runtime &rt, decltype(types.isAvailable) value) { + return bridging::toJs(rt, value); + } + + static double statusToJs(jsi::Runtime &rt, decltype(types.status) value) { + return bridging::toJs(rt, value); + } + + static bool hasResolutionToJs(jsi::Runtime &rt, decltype(types.hasResolution) value) { + return bridging::toJs(rt, value); + } + + static bool isUserResolvableErrorToJs(jsi::Runtime &rt, decltype(types.isUserResolvableError) value) { + return bridging::toJs(rt, value); + } + + static jsi::String errorToJs(jsi::Runtime &rt, decltype(types.error) value) { + return bridging::toJs(rt, value); + } +#endif + + static jsi::Object toJs( + jsi::Runtime &rt, + const T &value, + const std::shared_ptr &jsInvoker) { + auto result = facebook::jsi::Object(rt); + result.setProperty(rt, "isAvailable", bridging::toJs(rt, value.isAvailable, jsInvoker)); + result.setProperty(rt, "status", bridging::toJs(rt, value.status, jsInvoker)); + result.setProperty(rt, "hasResolution", bridging::toJs(rt, value.hasResolution, jsInvoker)); + result.setProperty(rt, "isUserResolvableError", bridging::toJs(rt, value.isUserResolvableError, jsInvoker)); + if (value.error) { + result.setProperty(rt, "error", bridging::toJs(rt, value.error.value(), jsInvoker)); + } + return result; + } +}; + +class JSI_EXPORT NativeRNFBTurboUtilsCxxSpecJSI : public TurboModule { +protected: + NativeRNFBTurboUtilsCxxSpecJSI(std::shared_ptr jsInvoker); + +public: + virtual jsi::Object getConstants(jsi::Runtime &rt) = 0; + virtual jsi::Value androidGetPlayServicesStatus(jsi::Runtime &rt) = 0; + virtual jsi::Value androidPromptForPlayServices(jsi::Runtime &rt) = 0; + virtual jsi::Value androidResolutionForPlayServices(jsi::Runtime &rt) = 0; + virtual jsi::Value androidMakePlayServicesAvailable(jsi::Runtime &rt) = 0; + +}; + +template +class JSI_EXPORT NativeRNFBTurboUtilsCxxSpec : public TurboModule { +public: + jsi::Value create(jsi::Runtime &rt, const jsi::PropNameID &propName) override { + return delegate_.create(rt, propName); + } + + std::vector getPropertyNames(jsi::Runtime& runtime) override { + return delegate_.getPropertyNames(runtime); + } + + static constexpr std::string_view kModuleName = "NativeRNFBTurboUtils"; + +protected: + NativeRNFBTurboUtilsCxxSpec(std::shared_ptr jsInvoker) + : TurboModule(std::string{NativeRNFBTurboUtilsCxxSpec::kModuleName}, jsInvoker), + delegate_(reinterpret_cast(this), jsInvoker) {} + + +private: + class Delegate : public NativeRNFBTurboUtilsCxxSpecJSI { + public: + Delegate(T *instance, std::shared_ptr jsInvoker) : + NativeRNFBTurboUtilsCxxSpecJSI(std::move(jsInvoker)), instance_(instance) { + + } + + jsi::Object getConstants(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::getConstants) == 1, + "Expected getConstants(...) to have 1 parameters"); + + return bridging::callFromJs( + rt, &T::getConstants, jsInvoker_, instance_); + } + jsi::Value androidGetPlayServicesStatus(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::androidGetPlayServicesStatus) == 1, + "Expected androidGetPlayServicesStatus(...) to have 1 parameters"); + + return bridging::callFromJs( + rt, &T::androidGetPlayServicesStatus, jsInvoker_, instance_); + } + jsi::Value androidPromptForPlayServices(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::androidPromptForPlayServices) == 1, + "Expected androidPromptForPlayServices(...) to have 1 parameters"); + + return bridging::callFromJs( + rt, &T::androidPromptForPlayServices, jsInvoker_, instance_); + } + jsi::Value androidResolutionForPlayServices(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::androidResolutionForPlayServices) == 1, + "Expected androidResolutionForPlayServices(...) to have 1 parameters"); + + return bridging::callFromJs( + rt, &T::androidResolutionForPlayServices, jsInvoker_, instance_); + } + jsi::Value androidMakePlayServicesAvailable(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::androidMakePlayServicesAvailable) == 1, + "Expected androidMakePlayServicesAvailable(...) to have 1 parameters"); + + return bridging::callFromJs( + rt, &T::androidMakePlayServicesAvailable, jsInvoker_, instance_); + } + + private: + friend class NativeRNFBTurboUtilsCxxSpec; + T *instance_; + }; + + Delegate delegate_; +}; + +} // namespace facebook::react diff --git a/packages/app/ios/generated/ReactAppDependencyProvider.podspec b/packages/app/ios/generated/ReactAppDependencyProvider.podspec new file mode 100644 index 0000000000..230b4f718f --- /dev/null +++ b/packages/app/ios/generated/ReactAppDependencyProvider.podspec @@ -0,0 +1,34 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +version = "0.82.1" +source = { :git => 'https://github.com/facebook/react-native.git' } +if version == '1000.0.0' + # This is an unpublished version, use the latest commit hash of the react-native repo, which we’re presumably in. + source[:commit] = `git rev-parse HEAD`.strip if system("git rev-parse --git-dir > /dev/null 2>&1") +else + source[:tag] = "v#{version}" +end + +Pod::Spec.new do |s| + s.name = "ReactAppDependencyProvider" + s.version = version + s.summary = "The third party dependency provider for the app" + s.homepage = "https://reactnative.dev/" + s.documentation_url = "https://reactnative.dev/" + s.license = "MIT" + s.author = "Meta Platforms, Inc. and its affiliates" + s.platforms = min_supported_versions + s.source = source + s.source_files = "**/RCTAppDependencyProvider.{h,mm}" + + # This guard prevent to install the dependencies when we run `pod install` in the old architecture. + s.pod_target_xcconfig = { + "CLANG_CXX_LANGUAGE_STANDARD" => rct_cxx_language_standard(), + "DEFINES_MODULE" => "YES" + } + + s.dependency "ReactCodegen" +end diff --git a/packages/app/ios/generated/ReactCodegen.podspec b/packages/app/ios/generated/ReactCodegen.podspec new file mode 100644 index 0000000000..2e6a73db65 --- /dev/null +++ b/packages/app/ios/generated/ReactCodegen.podspec @@ -0,0 +1,111 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +version = "0.82.1" +source = { :git => 'https://github.com/facebook/react-native.git' } +if version == '1000.0.0' + # This is an unpublished version, use the latest commit hash of the react-native repo, which we’re presumably in. + source[:commit] = `git rev-parse HEAD`.strip if system("git rev-parse --git-dir > /dev/null 2>&1") +else + source[:tag] = "v#{version}" +end + +use_frameworks = ENV['USE_FRAMEWORKS'] != nil +folly_compiler_flags = Helpers::Constants.folly_config[:compiler_flags] +boost_compiler_flags = Helpers::Constants.boost_config[:compiler_flags] + +header_search_paths = [] +framework_search_paths = [] + +header_search_paths = [ + "\"$(PODS_ROOT)/ReactNativeDependencies\"", + "\"${PODS_ROOT}/Headers/Public/ReactCodegen/react/renderer/components\"", + "\"$(PODS_ROOT)/Headers/Private/React-Fabric\"", + "\"$(PODS_ROOT)/Headers/Private/React-RCTFabric\"", + "\"$(PODS_ROOT)/Headers/Private/Yoga\"", + "\"$(PODS_TARGET_SRCROOT)\"", +] + +if use_frameworks + ReactNativePodsUtils.create_header_search_path_for_frameworks("PODS_CONFIGURATION_BUILD_DIR", "React-Fabric", "React_Fabric", ["react/renderer/components/view/platform/cxx"]) + .concat(ReactNativePodsUtils.create_header_search_path_for_frameworks("PODS_CONFIGURATION_BUILD_DIR", "React-FabricImage", "React_FabricImage", [])) + .concat(ReactNativePodsUtils.create_header_search_path_for_frameworks("PODS_CONFIGURATION_BUILD_DIR", "React-graphics", "React_graphics", ["react/renderer/graphics/platform/ios"])) + .concat(ReactNativePodsUtils.create_header_search_path_for_frameworks("PODS_CONFIGURATION_BUILD_DIR", "ReactCommon", "ReactCommon", ["react/nativemodule/core"])) + .concat(ReactNativePodsUtils.create_header_search_path_for_frameworks("PODS_CONFIGURATION_BUILD_DIR", "React-runtimeexecutor", "React_runtimeexecutor", ["platform/ios"])) + .concat(ReactNativePodsUtils.create_header_search_path_for_frameworks("PODS_CONFIGURATION_BUILD_DIR", "React-NativeModulesApple", "React_NativeModulesApple", [])) + .concat(ReactNativePodsUtils.create_header_search_path_for_frameworks("PODS_CONFIGURATION_BUILD_DIR", "React-RCTFabric", "RCTFabric", [])) + .concat(ReactNativePodsUtils.create_header_search_path_for_frameworks("PODS_CONFIGURATION_BUILD_DIR", "React-debug", "React_debug", [])) + .concat(ReactNativePodsUtils.create_header_search_path_for_frameworks("PODS_CONFIGURATION_BUILD_DIR", "React-rendererdebug", "React_rendererdebug", [])) + .concat(ReactNativePodsUtils.create_header_search_path_for_frameworks("PODS_CONFIGURATION_BUILD_DIR", "React-utils", "React_utils", [])) + .concat(ReactNativePodsUtils.create_header_search_path_for_frameworks("PODS_CONFIGURATION_BUILD_DIR", "React-featureflags", "React_featureflags", [])) + .each { |search_path| + header_search_paths << "\"#{search_path}\"" + } + end + +Pod::Spec.new do |s| + s.name = "ReactCodegen" + s.version = version + s.summary = 'Temp pod for generated files for React Native' + s.homepage = 'https://facebook.com/' + s.license = 'Unlicense' + s.authors = 'Facebook' + s.compiler_flags = "#{folly_compiler_flags} #{boost_compiler_flags} -Wno-nullability-completeness -std=c++20" + s.source = { :git => '' } + s.header_mappings_dir = './' + s.platforms = min_supported_versions + s.source_files = "**/*.{h,mm,cpp}" + s.exclude_files = "RCTAppDependencyProvider.{h,mm}" # these files are generated in the same codegen path but needs to belong to a different pod + s.pod_target_xcconfig = { + "HEADER_SEARCH_PATHS" => header_search_paths.join(' '), + "FRAMEWORK_SEARCH_PATHS" => framework_search_paths, + "OTHER_CPLUSPLUSFLAGS" => "$(inherited) #{folly_compiler_flags} #{boost_compiler_flags}" + } + + s.dependency "React-jsiexecutor" + s.dependency "RCTRequired" + s.dependency "RCTTypeSafety" + s.dependency "React-Core" + s.dependency "React-jsi" + s.dependency "ReactCommon/turbomodule/bridging" + s.dependency "ReactCommon/turbomodule/core" + s.dependency "React-NativeModulesApple" + s.dependency 'React-graphics' + s.dependency 'React-rendererdebug' + s.dependency 'React-Fabric' + s.dependency 'React-FabricImage' + s.dependency 'React-debug' + s.dependency 'React-utils' + s.dependency 'React-featureflags' + s.dependency 'React-RCTAppDelegate' + + depend_on_js_engine(s) + add_rn_third_party_dependencies(s) + add_rncore_dependency(s) + + s.script_phases = { + 'name' => 'Generate Specs', + 'execution_position' => :before_compile, + 'input_files' => ["${PODS_ROOT}/../../specs/NativeRNFBTurboApp.ts", +"${PODS_ROOT}/../../specs/NativeRNFBTurboUtils.ts"], + 'show_env_vars_in_log' => true, + 'output_files' => ["${DERIVED_FILE_DIR}/react-codegen.log"], + 'script': <<-SCRIPT +pushd "$PODS_ROOT/../" > /dev/null +RCT_SCRIPT_POD_INSTALLATION_ROOT=$(pwd) +popd >/dev/null + +export RCT_SCRIPT_RN_DIR="$RCT_SCRIPT_POD_INSTALLATION_ROOT/../../../../node_modules/react-native" +export RCT_SCRIPT_APP_PATH="$RCT_SCRIPT_POD_INSTALLATION_ROOT/../.." +export RCT_SCRIPT_OUTPUT_DIR="$RCT_SCRIPT_POD_INSTALLATION_ROOT" +export RCT_SCRIPT_TYPE="withCodegenDiscovery" + +export SCRIPT_PHASES_SCRIPT="$RCT_SCRIPT_RN_DIR/scripts/react_native_pods_utils/script_phases.sh" +export WITH_ENVIRONMENT="$RCT_SCRIPT_RN_DIR/scripts/xcode/with-environment.sh" +/bin/sh -c '"$WITH_ENVIRONMENT" "$SCRIPT_PHASES_SCRIPT"' +SCRIPT + } + +end diff --git a/packages/app/lib/internal/RNFBNativeEventEmitter.ts b/packages/app/lib/internal/RNFBNativeEventEmitter.ts index 2abb338595..a0bc036982 100644 --- a/packages/app/lib/internal/RNFBNativeEventEmitter.ts +++ b/packages/app/lib/internal/RNFBNativeEventEmitter.ts @@ -16,6 +16,7 @@ */ import { type EmitterSubscription, NativeEventEmitter } from 'react-native'; +import { APP_NATIVE_MODULE } from './constants'; import { getReactNativeModule } from './nativeModule'; import type { RNFBAppModuleInterface } from './NativeModules'; @@ -38,10 +39,11 @@ class RNFBNativeEventEmitter extends NativeEventEmitter { ready: boolean; constructor() { - const RNFBAppModule = getReactNativeModule('RNFBAppModule'); + // NewArch-AD-18 E1: NativeEventEmitter must receive the same raw host that implements addListener/removeListeners. + const RNFBAppModule = getReactNativeModule(APP_NATIVE_MODULE); if (!RNFBAppModule) { throw new Error( - 'Native module RNFBAppModule not found. Re-check module install, linking, configuration, build and install steps.', + `Native module ${APP_NATIVE_MODULE} not found. Re-check module install, linking, configuration, build and install steps.`, ); } // Cast to any for NativeEventEmitter constructor which expects React Native's NativeModule type @@ -54,8 +56,9 @@ class RNFBNativeEventEmitter extends NativeEventEmitter { listener: (...args: unknown[]) => unknown, context?: object, ): EmitterSubscription { + // NewArch-AD-18 E1: event bridge identity requires raw app-module host for listener registration. const RNFBAppModule = getReactNativeModule( - 'RNFBAppModule', + APP_NATIVE_MODULE, ) as unknown as RNFBAppModuleInterface; if (!this.ready) { (RNFBAppModule.eventsNotifyReady as EventsNotifyReadyMethod)(true); @@ -99,7 +102,8 @@ class RNFBNativeEventEmitter extends NativeEventEmitter { // we will modify it to do our native unsubscription then call the original const originalRemove = subscription.remove; const newRemove = () => { - const module = getReactNativeModule('RNFBAppModule') as unknown as RNFBAppModuleInterface; + // NewArch-AD-18 E1: raw host for eventsRemoveListener on unsubscribe. + const module = getReactNativeModule(APP_NATIVE_MODULE) as unknown as RNFBAppModuleInterface; (module.eventsRemoveListener as EventsRemoveListenerMethod)(eventType, false); const superClass = Object.getPrototypeOf(Object.getPrototypeOf(this)); if (superClass.removeSubscription != null) { @@ -115,8 +119,9 @@ class RNFBNativeEventEmitter extends NativeEventEmitter { } removeAllListeners(eventType: string): void { + // NewArch-AD-18 E1: raw host for eventsRemoveListener. const RNFBAppModule = getReactNativeModule( - 'RNFBAppModule', + APP_NATIVE_MODULE, ) as unknown as RNFBAppModuleInterface; (RNFBAppModule.eventsRemoveListener as EventsRemoveListenerMethod)(eventType, true); super.removeAllListeners(`rnfb_${eventType}`); @@ -124,8 +129,9 @@ class RNFBNativeEventEmitter extends NativeEventEmitter { // This is likely no longer ever called, but it is here for backwards compatibility with RN <= 0.64 removeSubscription(subscription: EmitterSubscription & { eventType?: string }): void { + // NewArch-AD-18 E1: raw host for legacy removeSubscription path. const RNFBAppModule = getReactNativeModule( - 'RNFBAppModule', + APP_NATIVE_MODULE, ) as unknown as RNFBAppModuleInterface; const eventType = subscription.eventType?.replace('rnfb_', '') || ''; (RNFBAppModule.eventsRemoveListener as EventsRemoveListenerMethod)(eventType, false); diff --git a/packages/app/lib/internal/constants.ts b/packages/app/lib/internal/constants.ts index 9e8d687e8d..0675aceadf 100644 --- a/packages/app/lib/internal/constants.ts +++ b/packages/app/lib/internal/constants.ts @@ -15,6 +15,8 @@ * */ -export const APP_NATIVE_MODULE = 'RNFBAppModule'; +export const APP_NATIVE_MODULE = 'NativeRNFBTurboApp'; + +export const UTILS_NATIVE_MODULE = 'NativeRNFBTurboUtils'; export const DEFAULT_APP_NAME = '[DEFAULT]'; diff --git a/packages/app/lib/internal/nativeModuleAndroidIos.ts b/packages/app/lib/internal/nativeModuleAndroidIos.ts index ad6c02fb82..df6635ce46 100644 --- a/packages/app/lib/internal/nativeModuleAndroidIos.ts +++ b/packages/app/lib/internal/nativeModuleAndroidIos.ts @@ -1,30 +1,74 @@ /* eslint-disable no-console */ -import { NativeModules } from 'react-native'; +import { NativeModules, TurboModuleRegistry } from 'react-native'; + +const DYNAMIC_CONSTANT_KEYS = new Set(['androidPlayServices']); + +const memoizedModuleConstants = new Map>(); + +function withTurboConstants( + moduleName: string, + module: Record | undefined, +): Record | undefined { + if (!module) { + return module; + } + + const getConstants = module.getConstants; + if (typeof getConstants !== 'function') { + return module; + } + + let constants = memoizedModuleConstants.get(moduleName); + if (!constants) { + constants = (getConstants as () => Record).call(module) || {}; + memoizedModuleConstants.set(moduleName, constants); + } + + const descriptors: PropertyDescriptorMap = {}; + for (const key of Object.keys(constants)) { + if (DYNAMIC_CONSTANT_KEYS.has(key)) { + continue; + } + descriptors[key] = { + value: constants[key], + enumerable: true, + writable: true, + configurable: true, + }; + } + + return Object.create(module, descriptors); +} /** - * This is used by Android and iOS to get a native module. - * We additionally add a Proxy to the module to intercept calls - * and log them to the console for debugging purposes, if enabled. - * @param moduleName - * @returns Raw native module from React Native (object with methods/properties or undefined) + * Unified native module resolver — TurboModule first, legacy NativeModules fallback. */ export function getReactNativeModule(moduleName: string): Record | undefined { - const nativeModule = NativeModules[moduleName]; + const turboModule = TurboModuleRegistry.get(moduleName); + const nativeModule = withTurboConstants( + moduleName, + (turboModule ?? NativeModules[moduleName]) as Record | undefined, + ); + if (!globalThis.RNFBDebug) { return nativeModule; } - return new Proxy(nativeModule, { + return new Proxy(nativeModule as Record, { ownKeys(target) { - return Object.keys(target); + const keys: string[] = []; + for (const key in target) { + keys.push(key); + } + return keys; }, get: (_, name) => { - const prop = nativeModule[name as string]; + const prop = (nativeModule as Record)[name as string]; if (typeof prop !== 'function') return prop; return (...args: unknown[]) => { console.debug( `[RNFB->Native][🔵] ${moduleName}.${String(name)} -> ${JSON.stringify(args)}`, ); - const result: unknown = (prop as (...args: unknown[]) => unknown)(...args); + const result: unknown = (prop as (...args: unknown[]) => unknown).apply(nativeModule, args); if (result && typeof result === 'object' && 'then' in result) { return (result as Promise).then( (res: unknown) => { diff --git a/packages/app/lib/internal/nativeModuleWeb.ts b/packages/app/lib/internal/nativeModuleWeb.ts index cc4e7d02d7..c85b004b76 100644 --- a/packages/app/lib/internal/nativeModuleWeb.ts +++ b/packages/app/lib/internal/nativeModuleWeb.ts @@ -1,7 +1,12 @@ /* eslint-disable no-console */ import RNFBAppModule from './web/RNFBAppModule'; +import { APP_NATIVE_MODULE } from './constants'; -const nativeModuleRegistry: Record> = {}; +// Register before exporting getters — RNFBNativeEventEmitter instantiates during circular imports. +const nativeModuleRegistry: Record> = { + RNFBAppModule: RNFBAppModule as unknown as Record, + [APP_NATIVE_MODULE]: RNFBAppModule as unknown as Record, +}; export function getReactNativeModule(moduleName: string): Record | undefined { const nativeModule = nativeModuleRegistry[moduleName]; @@ -14,8 +19,11 @@ export function getReactNativeModule(moduleName: string): Record { const prop = nativeModule[name as string]; @@ -56,5 +64,3 @@ export function setReactNativeModule( ): void { nativeModuleRegistry[moduleName] = nativeModule; } - -setReactNativeModule('RNFBAppModule', RNFBAppModule); diff --git a/packages/app/lib/internal/registry/app.ts b/packages/app/lib/internal/registry/app.ts index a4b028090a..553c177c68 100644 --- a/packages/app/lib/internal/registry/app.ts +++ b/packages/app/lib/internal/registry/app.ts @@ -257,9 +257,24 @@ export function deleteApp(name: string, nativeInitialized: boolean): Promise { (app as any)._deleted = true; - for (let i = 0; i < onAppDestroyCallbacks.length; i++) { - onAppDestroyCallbacks[i]?.(app); + try { + for (let i = 0; i < onAppDestroyCallbacks.length; i++) { + try { + onAppDestroyCallbacks[i]?.(app); + } catch (e) { + // A failing destroy listener must not prevent the remaining listeners (or the + // registry cleanup below) from running. Surface it for diagnosis — partial cleanup + // here can leave a module's native/JS state stale for the deleted app. + // eslint-disable-next-line no-console + console.warn( + `Firebase: an onAppDestroy callback (index ${i}) for app '${name}' threw and was ` + + 'skipped; remaining callbacks will still run. Inspect the offending listener:', + e, + ); + } + } + } finally { + delete APP_REGISTRY[name]; } - delete APP_REGISTRY[name]; }); } diff --git a/packages/app/lib/internal/registry/nativeModule.ts b/packages/app/lib/internal/registry/nativeModule.ts index 559997b248..309e73307b 100644 --- a/packages/app/lib/internal/registry/nativeModule.ts +++ b/packages/app/lib/internal/registry/nativeModule.ts @@ -14,7 +14,7 @@ * limitations under the License. * */ -import { APP_NATIVE_MODULE } from '../constants'; +import { APP_NATIVE_MODULE, UTILS_NATIVE_MODULE } from '../constants'; import NativeFirebaseError from '../NativeFirebaseError'; import type { NativeError } from '../../types/internal'; import RNFBNativeEventEmitter from '../RNFBNativeEventEmitter'; @@ -31,8 +31,15 @@ interface NativeEvent { [key: string]: unknown; } +interface RouteEntry { + host: Record; + key: string; + argToPrepend: unknown[]; +} + const NATIVE_MODULE_REGISTRY: Record = {}; const NATIVE_MODULE_EVENT_SUBSCRIPTIONS: Record = {}; +let staticUtilsModule: WrappedNativeModule | null = null; function nativeModuleKey(module: FirebaseModule): string { return `${module._customUrlOrRegion || ''}:${module.app.name}:${module._config.namespace}`; @@ -41,11 +48,6 @@ function nativeModuleKey(module: FirebaseModule): string { /** * Wraps a native module method to provide * auto prepended args and custom Error classes. - * - * @param namespace - * @param method - * @param argToPrepend - * @returns {Function} */ function nativeModuleMethodWrapped( namespace: string, @@ -54,9 +56,6 @@ function nativeModuleMethodWrapped( isTurboModule: boolean, ): (...args: unknown[]) => unknown { return (...args: unknown[]) => { - // For iOS TurboModules, encode null values in arguments to work around - // the limitation where null values in object properties get stripped during serialization - // See: https://github.com/facebook/react-native/issues/52802 const processedArgs = isIOS && isTurboModule ? args.map(arg => encodeNullValues(arg)) : args; const allArgs = [...argToPrepend, ...processedArgs]; const possiblePromise = method(...allArgs); @@ -73,50 +72,81 @@ function nativeModuleMethodWrapped( } /** - * Prepends all arguments in prependArgs to all native method calls - * - * @param namespace - * @param NativeModule - Raw native module from React Native - * @param argToPrepend + * NewArch-AD-14 / NewArch-AD-14a: routing composite Proxy — lazy wrap+bind on first access per method. */ -function nativeModuleWrapped( +function createRoutingCompositeProxy( namespace: string, - NativeModule: Record | undefined, - argToPrepend: unknown[], + hosts: Array<{ module: Record | undefined; argToPrepend: unknown[] }>, isTurboModule: boolean, ): WrappedNativeModule { - const native: Record = {}; - if (!NativeModule) { - return NativeModule as unknown as WrappedNativeModule; - } + const routingMap: Record = {}; + const memoizedMethods: Record unknown> = {}; - const nativeModuleObj = NativeModule; - let properties = Object.keys(Object.getPrototypeOf(nativeModuleObj)); - if (!properties.length) properties = Object.keys(nativeModuleObj); - - for (let i = 0, len = properties.length; i < len; i++) { - const property = properties[i]; - if (!property) continue; - if (typeof nativeModuleObj[property] === 'function') { - native[property] = nativeModuleMethodWrapped( - namespace, - nativeModuleObj[property] as (...args: unknown[]) => unknown, - argToPrepend, - isTurboModule, - ); - } else { - native[property] = nativeModuleObj[property]; + for (const { module, argToPrepend } of hosts) { + if (!module) { + continue; + } + for (const key in module) { + if (key === 'constructor' || key === 'getConstants') { + continue; + } + routingMap[key] = { host: module, key, argToPrepend }; } } - return native; + const target = Object.create(null) as WrappedNativeModule; + + return new Proxy(target, { + get(_target, name: string | symbol) { + if (typeof name !== 'string' || !(name in routingMap)) { + return undefined; + } + + const route = routingMap[name]; + if (!route) { + return undefined; + } + + const value = route.host[route.key]; + + if (typeof value !== 'function') { + return value; + } + + if (!memoizedMethods[name]) { + memoizedMethods[name] = nativeModuleMethodWrapped( + namespace, + (value as (...args: unknown[]) => unknown).bind(route.host), + route.argToPrepend, + isTurboModule, + ) as (...args: unknown[]) => unknown; + } + + return memoizedMethods[name]; + }, + has(_target, name) { + return typeof name === 'string' && name in routingMap; + }, + ownKeys() { + return Object.keys(routingMap); + }, + getOwnPropertyDescriptor(_target, name) { + if (typeof name !== 'string' || !(name in routingMap)) { + return undefined; + } + return { + enumerable: true, + configurable: true, + }; + }, + set() { + return false; + }, + }); } /** * Initialises and wraps all the native module methods. - * - * @param module - * @returns {*} */ function initialiseNativeModule(module: FirebaseModule): WrappedNativeModule { const config = module._config; @@ -130,10 +160,20 @@ function initialiseNativeModule(module: FirebaseModule): WrappedNativeModule { disablePrependCustomUrlOrRegion, turboModule, } = config; - const multiModuleRoot: WrappedNativeModule = {}; const isTurboModule = !!turboModule; const multiModule = Array.isArray(nativeModuleName); const nativeModuleNames = multiModule ? nativeModuleName : [nativeModuleName]; + const hosts: Array<{ module: Record | undefined; argToPrepend: unknown[] }> = []; + + const argToPrepend: Array = []; + + if (hasMultiAppSupport) { + argToPrepend.push(module.app.name); + } + + if (hasCustomUrlOrRegionSupport && !disablePrependCustomUrlOrRegion) { + argToPrepend.push(module._customUrlOrRegion as string); + } for (let i = 0; i < nativeModuleNames.length; i++) { const moduleName = nativeModuleNames[i]; @@ -141,32 +181,17 @@ function initialiseNativeModule(module: FirebaseModule): WrappedNativeModule { const nativeModule = getReactNativeModule(moduleName); - // only error if there's a single native module - // as multi modules can mean some are optional if (!multiModule && !nativeModule) { throw new Error(getMissingModuleHelpText(namespace)); } - if (multiModule) { - multiModuleRoot[moduleName] = !!nativeModule; - } - - const argToPrepend: Array = []; - - if (hasMultiAppSupport) { - argToPrepend.push(module.app.name); - } - - if (hasCustomUrlOrRegionSupport && !disablePrependCustomUrlOrRegion) { - argToPrepend.push(module._customUrlOrRegion as string); + if (nativeModule) { + hosts.push({ module: nativeModule, argToPrepend }); } - - Object.assign( - multiModuleRoot, - nativeModuleWrapped(namespace, nativeModule, argToPrepend, isTurboModule), - ); } + const composite = createRoutingCompositeProxy(namespace, hosts, isTurboModule); + if (nativeEvents && Array.isArray(nativeEvents) && nativeEvents.length) { for (let i = 0, len = nativeEvents.length; i < len; i++) { const eventName = nativeEvents[i]; @@ -176,34 +201,20 @@ function initialiseNativeModule(module: FirebaseModule): WrappedNativeModule { } } - Object.freeze(multiModuleRoot); - - NATIVE_MODULE_REGISTRY[key] = multiModuleRoot; + NATIVE_MODULE_REGISTRY[key] = composite; return NATIVE_MODULE_REGISTRY[key]; } -/** - * Subscribe to a native event for js side distribution by appName - * React Native events are hard set at compile - cant do dynamic event names - * so we use a single event send it to js and js then internally can prefix it - * and distribute dynamically. - * - * @param eventName - * @private - */ function subscribeToNativeModuleEvent(eventName: string): void { if (!NATIVE_MODULE_EVENT_SUBSCRIPTIONS[eventName]) { RNFBNativeEventEmitter.addListener(eventName, (...args: unknown[]) => { const event = args[0] as NativeEvent; if (event.appName && event.databaseId) { - // Firestore requires both appName and databaseId to prefix SharedEventEmitter.emit(`${event.appName}-${event.databaseId}-${eventName}`, event); } else if (event.appName) { - // native event has an appName property - auto prefix and internally emit SharedEventEmitter.emit(`${event.appName}-${eventName}`, event); } else { - // standard event - no need to prefix SharedEventEmitter.emit(eventName, event); } }); @@ -212,12 +223,6 @@ function subscribeToNativeModuleEvent(eventName: string): void { } } -/** - * Help text for integrating the native counter parts for each firebase module. - * - * @param namespace - * @returns {string} - */ function getMissingModuleHelpText(namespace: string): string { const snippet = `firebase.${namespace}()`; @@ -236,13 +241,6 @@ function getMissingModuleHelpText(namespace: string): string { ); } -/** - * Gets a wrapped native module instance for the provided firebase module. - * Will attempt to create a new instance if non previously created. - * - * @param module - * @returns {*} - */ export function getNativeModule(module: FirebaseModule): WrappedNativeModule { const key = nativeModuleKey(module); @@ -253,11 +251,6 @@ export function getNativeModule(module: FirebaseModule): WrappedNativeModule { return initialiseNativeModule(module); } -/** - * Custom wrapped app module as it does not have it's own FirebaseModule based class. - * - * @returns {*} - */ export function getAppModule(): RNFBAppModuleInterface { if (NATIVE_MODULE_REGISTRY[APP_NATIVE_MODULE]) { return NATIVE_MODULE_REGISTRY[APP_NATIVE_MODULE] as unknown as RNFBAppModuleInterface; @@ -270,13 +263,35 @@ export function getAppModule(): RNFBAppModuleInterface { throw new Error(getMissingModuleHelpText(namespace)); } - NATIVE_MODULE_REGISTRY[APP_NATIVE_MODULE] = nativeModuleWrapped( + NATIVE_MODULE_REGISTRY[APP_NATIVE_MODULE] = createRoutingCompositeProxy( namespace, - nativeModule, - [], - // TODO: change to true when we use TurboModules for app package - false, + [{ module: nativeModule, argToPrepend: [] }], + true, ); return NATIVE_MODULE_REGISTRY[APP_NATIVE_MODULE] as unknown as RNFBAppModuleInterface; } + +/** + * Memoized wrapped utils surface for static path-constant reads (NewArch-AD-18 E5). + */ +export function getStaticUtilsModule(): WrappedNativeModule { + if (staticUtilsModule) { + return staticUtilsModule; + } + + const namespace = 'utils'; + const nativeModule = getReactNativeModule(UTILS_NATIVE_MODULE); + + if (!nativeModule) { + throw new Error(getMissingModuleHelpText(namespace)); + } + + staticUtilsModule = createRoutingCompositeProxy( + namespace, + [{ module: nativeModule, argToPrepend: [] }], + true, + ); + + return staticUtilsModule; +} diff --git a/packages/app/lib/modular.ts b/packages/app/lib/modular.ts index 52068ef85e..27966f7182 100644 --- a/packages/app/lib/modular.ts +++ b/packages/app/lib/modular.ts @@ -28,9 +28,7 @@ import { } from './internal/registry/app'; import { setUserLogHandler } from './internal/logger'; import { version as sdkVersion } from './version'; -import { getReactNativeModule } from './internal/nativeModule'; -import { APP_NATIVE_MODULE } from './internal/constants'; -import type { RNFBAppModuleInterface } from './internal/NativeModules'; +import { getAppModule } from './internal/registry/nativeModule'; /** * Renders this app unusable and frees the resources of all associated services. * @param app - The app to delete. @@ -121,10 +119,7 @@ export function setReactNativeAsyncStorage( * @returns map of key / value pairs containing native meta data */ export function metaGetAll(): Promise<{ [key: string]: string | boolean }> { - const RNFBAppModule = getReactNativeModule( - APP_NATIVE_MODULE, - ) as unknown as RNFBAppModuleInterface; - return RNFBAppModule.metaGetAll(); + return getAppModule().metaGetAll(); } /** @@ -132,10 +127,7 @@ export function metaGetAll(): Promise<{ [key: string]: string | boolean }> { * @returns map of key / value pairs containing native firebase.json constants */ export function jsonGetAll(): Promise<{ [key: string]: string | boolean }> { - const RNFBAppModule = getReactNativeModule( - APP_NATIVE_MODULE, - ) as unknown as RNFBAppModuleInterface; - return RNFBAppModule.jsonGetAll(); + return getAppModule().jsonGetAll(); } /** @@ -143,10 +135,7 @@ export function jsonGetAll(): Promise<{ [key: string]: string | boolean }> { * @returns Promise */ export function preferencesClearAll(): Promise { - const RNFBAppModule = getReactNativeModule( - APP_NATIVE_MODULE, - ) as unknown as RNFBAppModuleInterface; - return RNFBAppModule.preferencesClearAll(); + return getAppModule().preferencesClearAll(); } /** @@ -154,10 +143,7 @@ export function preferencesClearAll(): Promise { * @returns map of key / value pairs containing native preferences data */ export function preferencesGetAll(): Promise<{ [key: string]: string | boolean }> { - const RNFBAppModule = getReactNativeModule( - APP_NATIVE_MODULE, - ) as unknown as RNFBAppModuleInterface; - return RNFBAppModule.preferencesGetAll(); + return getAppModule().preferencesGetAll(); } /** @@ -167,10 +153,7 @@ export function preferencesGetAll(): Promise<{ [key: string]: string | boolean } * @returns Promise */ export function preferencesSetBool(key: string, value: boolean): Promise { - const RNFBAppModule = getReactNativeModule( - APP_NATIVE_MODULE, - ) as unknown as RNFBAppModuleInterface; - return RNFBAppModule.preferencesSetBool(key, value); + return getAppModule().preferencesSetBool(key, value); } /** @@ -180,10 +163,7 @@ export function preferencesSetBool(key: string, value: boolean): Promise { * @returns Promise */ export function preferencesSetString(key: string, value: string): Promise { - const RNFBAppModule = getReactNativeModule( - APP_NATIVE_MODULE, - ) as unknown as RNFBAppModuleInterface; - return RNFBAppModule.preferencesSetString(key, value); + return getAppModule().preferencesSetString(key, value); } export const SDK_VERSION = sdkVersion; diff --git a/packages/app/lib/utils/UtilsStatics.ts b/packages/app/lib/utils/UtilsStatics.ts index 69c9860aa6..2e82a5ebd5 100644 --- a/packages/app/lib/utils/UtilsStatics.ts +++ b/packages/app/lib/utils/UtilsStatics.ts @@ -15,7 +15,7 @@ * */ -import { NativeModules } from 'react-native'; +import { getStaticUtilsModule } from '../internal/registry/nativeModule'; import { stripTrailingSlash, isOther } from '../common'; import { Utils } from '../types/app'; import { version } from '../version'; @@ -66,7 +66,7 @@ const statics: Utils.Statics = { SDK_VERSION: version, get FilePath(): Utils.FilePath { // We don't support path constants on non-native platforms. - return processPathConstants(isOther ? {} : NativeModules.RNFBUtilsModule); + return processPathConstants(isOther ? {} : getStaticUtilsModule()); }, }; diff --git a/packages/app/lib/utils/index.ts b/packages/app/lib/utils/index.ts index 31b5f52c81..a09d0fe2c4 100644 --- a/packages/app/lib/utils/index.ts +++ b/packages/app/lib/utils/index.ts @@ -19,9 +19,10 @@ import { isIOS } from '../common'; import { FirebaseModule, getOrCreateModularInstance } from '../internal'; import type { ModuleConfig } from '../internal'; import type { ReactNativeFirebase, Utils } from '../types/app'; +import { UTILS_NATIVE_MODULE } from '../internal/constants'; const namespace = 'utils'; -const nativeModuleName = 'RNFBUtilsModule'; +const nativeModuleName = UTILS_NATIVE_MODULE; const config: ModuleConfig = { namespace, @@ -29,6 +30,7 @@ const config: ModuleConfig = { nativeEvents: false, hasMultiAppSupport: false, hasCustomUrlOrRegionSupport: false, + turboModule: true, }; class FirebaseUtilsModule extends FirebaseModule<'RNFBUtilsModule'> { @@ -49,7 +51,8 @@ class FirebaseUtilsModule extends FirebaseModule<'RNFBUtilsModule'> { error: undefined, }; } - return this.native.androidPlayServices; + // NewArch-AD-15: dynamic Play Services status — use getPlayServicesStatus() (async) on Android. + return this.getPlayServicesStatus() as unknown as Utils.PlayServicesAvailability; } getPlayServicesStatus(): Promise { diff --git a/packages/app/package.json b/packages/app/package.json index 064ea7a739..f01a9dffbe 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -5,7 +5,25 @@ "description": "A well tested, feature rich Firebase implementation for React Native, supporting iOS & Android. Individual module support for Admob, Analytics, Auth, Crash Reporting, Cloud Firestore, Database, Dynamic Links, Functions, Messaging (FCM), Remote Config, Storage and more.", "main": "./dist/module/index.js", "types": "./dist/typescript/lib/index.d.ts", + "codegenConfig": { + "name": "RNFBAppTurboModules", + "type": "modules", + "jsSrcsDir": "specs", + "includesGeneratedCode": true, + "android": { + "javaPackageName": "io.invertase.firebase.app" + }, + "ios": { + "modulesProvider": { + "NativeRNFBTurboApp": "RNFBAppModule", + "NativeRNFBTurboUtils": "RNFBUtilsModule" + } + } + }, "scripts": { + "codegen": "yarn android:codegen && yarn ios:codegen", + "android:codegen": "npx @react-native-community/cli codegen --platform android --outputPath=./android/src/reactnative/java/io/invertase/firebase/app/generated", + "ios:codegen": "npx @react-native-community/cli codegen --platform ios --outputPath=./ios/generated", "build": "genversion --esm --semi lib/version.ts && npm run build:version", "build:version": "node ./scripts/genversion-ios && node ./scripts/genversion-android", "build:clean": "rimraf android/build && rimraf ios/build", diff --git a/packages/app/react-native.config.js b/packages/app/react-native.config.js index 8502984955..377589a57b 100644 --- a/packages/app/react-native.config.js +++ b/packages/app/react-native.config.js @@ -3,6 +3,8 @@ module.exports = { platforms: { android: { packageImportPath: 'import io.invertase.firebase.app.ReactNativeFirebaseAppPackage;', + cmakeListsPath: + './src/reactnative/java/io/invertase/firebase/app/generated/jni/CMakeLists.txt', }, ios: { scriptPhases: [ diff --git a/packages/app/specs/NativeRNFBTurboApp.ts b/packages/app/specs/NativeRNFBTurboApp.ts new file mode 100644 index 0000000000..1d74f3e293 --- /dev/null +++ b/packages/app/specs/NativeRNFBTurboApp.ts @@ -0,0 +1,57 @@ +/* eslint-disable @typescript-eslint/no-wrapper-object-types */ +import type { TurboModule } from 'react-native'; +import { TurboModuleRegistry } from 'react-native'; + +export type FirebaseAppConfig = { + name: string; + automaticResourceManagement?: boolean; + automaticDataCollectionEnabled?: boolean; +}; + +export type FirebaseAppOptions = { + apiKey: string; + appId: string; + databaseURL?: string | null; + messagingSenderId: string; + projectId: string; + storageBucket?: string | null; + authDomain?: string | null; + iosBundleId?: string | null; + iosClientId?: string | null; + appGroupId?: string | null; +}; + +export type NativeFirebaseApp = { + appConfig: FirebaseAppConfig; + options: FirebaseAppOptions; +}; + +export interface Spec extends TurboModule { + getConstants(): { + NATIVE_FIREBASE_APPS: Array; + FIREBASE_RAW_JSON: string; + }; + + initializeApp(options: Object, appConfig: Object): Promise; + setAutomaticDataCollectionEnabled(appName: string, enabled: boolean): void; + deleteApp(appName: string): Promise; + + eventsNotifyReady(ready: boolean): void; + eventsGetListeners(): Promise; + eventsPing(eventName: string, eventBody: Object): Promise; + eventsAddListener(eventName: string): void; + eventsRemoveListener(eventName: string, all: boolean): void; + addListener(eventName: string): void; + removeListeners(count: number): void; + + metaGetAll(): Promise; + jsonGetAll(): Promise; + preferencesSetBool(key: string, value: boolean): Promise; + preferencesSetString(key: string, value: string): Promise; + preferencesGetAll(): Promise; + preferencesClearAll(): Promise; + + setLogLevel(logLevel: string): void; +} + +export default TurboModuleRegistry.getEnforcing('NativeRNFBTurboApp'); diff --git a/packages/app/specs/NativeRNFBTurboUtils.ts b/packages/app/specs/NativeRNFBTurboUtils.ts new file mode 100644 index 0000000000..57ad14e631 --- /dev/null +++ b/packages/app/specs/NativeRNFBTurboUtils.ts @@ -0,0 +1,34 @@ +import type { TurboModule } from 'react-native'; +import { TurboModuleRegistry } from 'react-native'; + +export type PlayServicesAvailability = { + isAvailable: boolean; + status: number; + hasResolution: boolean; + isUserResolvableError: boolean; + error?: string; +}; + +export interface Spec extends TurboModule { + getConstants(): { + isRunningInTestLab: boolean; + MAIN_BUNDLE: string; + CACHES_DIRECTORY: string; + DOCUMENT_DIRECTORY: string; + EXTERNAL_DIRECTORY?: string; + EXTERNAL_STORAGE_DIRECTORY?: string; + TEMP_DIRECTORY: string; + LIBRARY_DIRECTORY: string; + PICTURES_DIRECTORY: string; + MOVIES_DIRECTORY: string; + FILE_TYPE_REGULAR?: string; + FILE_TYPE_DIRECTORY?: string; + }; + + androidGetPlayServicesStatus(): Promise; + androidPromptForPlayServices(): Promise; + androidResolutionForPlayServices(): Promise; + androidMakePlayServicesAvailable(): Promise; +} + +export default TurboModuleRegistry.getEnforcing('NativeRNFBTurboUtils'); diff --git a/packages/app/type-test.ts b/packages/app/type-test.ts index 0fb0d3b07d..40c495bb73 100644 --- a/packages/app/type-test.ts +++ b/packages/app/type-test.ts @@ -14,14 +14,7 @@ * limitations under the License. */ -import { - getApp, - getApps, - getUtils, - initializeApp, - SDK_VERSION, - FilePath, -} from '.'; +import { getApp, getApps, getUtils, initializeApp, SDK_VERSION, FilePath } from '.'; // modular app accessors console.log(getUtils().app.name); diff --git a/packages/auth/android/src/main/java/io/invertase/firebase/auth/ReactNativeFirebaseAuthModule.java b/packages/auth/android/src/main/java/io/invertase/firebase/auth/ReactNativeFirebaseAuthModule.java index 1f58c0f974..5456dc7562 100644 --- a/packages/auth/android/src/main/java/io/invertase/firebase/auth/ReactNativeFirebaseAuthModule.java +++ b/packages/auth/android/src/main/java/io/invertase/firebase/auth/ReactNativeFirebaseAuthModule.java @@ -72,7 +72,7 @@ import com.google.firebase.auth.TwitterAuthProvider; import com.google.firebase.auth.UserInfo; import com.google.firebase.auth.UserProfileChangeRequest; -import io.invertase.firebase.app.ReactNativeFirebaseAppModule; +import io.invertase.firebase.app.NativeRNFBTurboApp; import io.invertase.firebase.common.ReactNativeFirebaseEvent; import io.invertase.firebase.common.ReactNativeFirebaseEventEmitter; import io.invertase.firebase.common.ReactNativeFirebaseModule; @@ -166,7 +166,7 @@ public void configureAuthDomain(final String appName) { Log.d(TAG, "configureAuthDomain"); FirebaseApp firebaseApp = FirebaseApp.getInstance(appName); FirebaseAuth firebaseAuth = FirebaseAuth.getInstance(firebaseApp); - String authDomain = ReactNativeFirebaseAppModule.authDomains.get(appName); + String authDomain = NativeRNFBTurboApp.authDomains.get(appName); Log.d(TAG, "configureAuthDomain - app " + appName + " domain? " + authDomain); if (authDomain != null) { firebaseAuth.setCustomAuthDomain(authDomain); diff --git a/packages/functions/android/src/main/java/io/invertase/firebase/functions/generated/jni/CMakeLists.txt b/packages/functions/android/src/main/java/io/invertase/firebase/functions/generated/jni/CMakeLists.txt index b01d2c6044..b41928d17c 100644 --- a/packages/functions/android/src/main/java/io/invertase/firebase/functions/generated/jni/CMakeLists.txt +++ b/packages/functions/android/src/main/java/io/invertase/firebase/functions/generated/jni/CMakeLists.txt @@ -6,18 +6,18 @@ cmake_minimum_required(VERSION 3.13) set(CMAKE_VERBOSE_MAKEFILE on) -file(GLOB react_codegen_SRCS CONFIGURE_DEPENDS *.cpp react/renderer/components/NativeRNFBTurboFunctions/*.cpp) +file(GLOB react_codegen_SRCS CONFIGURE_DEPENDS *.cpp react/renderer/components/RNFBFunctionsTurboModules/*.cpp) add_library( - react_codegen_NativeRNFBTurboFunctions + react_codegen_RNFBFunctionsTurboModules OBJECT ${react_codegen_SRCS} ) -target_include_directories(react_codegen_NativeRNFBTurboFunctions PUBLIC . react/renderer/components/NativeRNFBTurboFunctions) +target_include_directories(react_codegen_RNFBFunctionsTurboModules PUBLIC . react/renderer/components/RNFBFunctionsTurboModules) target_link_libraries( - react_codegen_NativeRNFBTurboFunctions + react_codegen_RNFBFunctionsTurboModules fbjni jsi # We need to link different libraries based on whether we are building rncore or not, that's necessary @@ -26,7 +26,7 @@ target_link_libraries( ) target_compile_options( - react_codegen_NativeRNFBTurboFunctions + react_codegen_RNFBFunctionsTurboModules PRIVATE -DLOG_TAG=\"ReactNative\" -fexceptions diff --git a/packages/functions/android/src/main/java/io/invertase/firebase/functions/generated/jni/NativeRNFBTurboFunctions-generated.cpp b/packages/functions/android/src/main/java/io/invertase/firebase/functions/generated/jni/RNFBFunctionsTurboModules-generated.cpp similarity index 95% rename from packages/functions/android/src/main/java/io/invertase/firebase/functions/generated/jni/NativeRNFBTurboFunctions-generated.cpp rename to packages/functions/android/src/main/java/io/invertase/firebase/functions/generated/jni/RNFBFunctionsTurboModules-generated.cpp index 63263ee488..ef3e3fa42a 100644 --- a/packages/functions/android/src/main/java/io/invertase/firebase/functions/generated/jni/NativeRNFBTurboFunctions-generated.cpp +++ b/packages/functions/android/src/main/java/io/invertase/firebase/functions/generated/jni/RNFBFunctionsTurboModules-generated.cpp @@ -8,7 +8,7 @@ * @generated by codegen project: GenerateModuleJniCpp.js */ -#include "NativeRNFBTurboFunctions.h" +#include "RNFBFunctionsTurboModules.h" namespace facebook::react { @@ -46,7 +46,7 @@ NativeRNFBTurboFunctionsSpecJSI::NativeRNFBTurboFunctionsSpecJSI(const JavaTurbo methodMap_["removeFunctionsStreaming"] = MethodMetadata {3, __hostFunction_NativeRNFBTurboFunctionsSpecJSI_removeFunctionsStreaming}; } -std::shared_ptr NativeRNFBTurboFunctions_ModuleProvider(const std::string &moduleName, const JavaTurboModule::InitParams ¶ms) { +std::shared_ptr RNFBFunctionsTurboModules_ModuleProvider(const std::string &moduleName, const JavaTurboModule::InitParams ¶ms) { if (moduleName == "NativeRNFBTurboFunctions") { return std::make_shared(params); } diff --git a/packages/functions/android/src/main/java/io/invertase/firebase/functions/generated/jni/NativeRNFBTurboFunctions.h b/packages/functions/android/src/main/java/io/invertase/firebase/functions/generated/jni/RNFBFunctionsTurboModules.h similarity index 83% rename from packages/functions/android/src/main/java/io/invertase/firebase/functions/generated/jni/NativeRNFBTurboFunctions.h rename to packages/functions/android/src/main/java/io/invertase/firebase/functions/generated/jni/RNFBFunctionsTurboModules.h index 470e1dda05..cd7324cf30 100644 --- a/packages/functions/android/src/main/java/io/invertase/firebase/functions/generated/jni/NativeRNFBTurboFunctions.h +++ b/packages/functions/android/src/main/java/io/invertase/firebase/functions/generated/jni/RNFBFunctionsTurboModules.h @@ -26,6 +26,6 @@ class JSI_EXPORT NativeRNFBTurboFunctionsSpecJSI : public JavaTurboModule { JSI_EXPORT -std::shared_ptr NativeRNFBTurboFunctions_ModuleProvider(const std::string &moduleName, const JavaTurboModule::InitParams ¶ms); +std::shared_ptr RNFBFunctionsTurboModules_ModuleProvider(const std::string &moduleName, const JavaTurboModule::InitParams ¶ms); } // namespace facebook::react diff --git a/packages/functions/ios/generated/NativeRNFBTurboFunctionsJSI-generated.cpp b/packages/functions/android/src/main/java/io/invertase/firebase/functions/generated/jni/react/renderer/components/RNFBFunctionsTurboModules/RNFBFunctionsTurboModulesJSI-generated.cpp similarity index 99% rename from packages/functions/ios/generated/NativeRNFBTurboFunctionsJSI-generated.cpp rename to packages/functions/android/src/main/java/io/invertase/firebase/functions/generated/jni/react/renderer/components/RNFBFunctionsTurboModules/RNFBFunctionsTurboModulesJSI-generated.cpp index 31cddefdf8..a7892576fb 100644 --- a/packages/functions/ios/generated/NativeRNFBTurboFunctionsJSI-generated.cpp +++ b/packages/functions/android/src/main/java/io/invertase/firebase/functions/generated/jni/react/renderer/components/RNFBFunctionsTurboModules/RNFBFunctionsTurboModulesJSI-generated.cpp @@ -7,7 +7,7 @@ * @generated by codegen project: GenerateModuleCpp.js */ -#include "NativeRNFBTurboFunctionsJSI.h" +#include "RNFBFunctionsTurboModulesJSI.h" namespace facebook::react { diff --git a/packages/functions/android/src/main/java/io/invertase/firebase/functions/generated/jni/react/renderer/components/NativeRNFBTurboFunctions/NativeRNFBTurboFunctionsJSI.h b/packages/functions/android/src/main/java/io/invertase/firebase/functions/generated/jni/react/renderer/components/RNFBFunctionsTurboModules/RNFBFunctionsTurboModulesJSI.h similarity index 100% rename from packages/functions/android/src/main/java/io/invertase/firebase/functions/generated/jni/react/renderer/components/NativeRNFBTurboFunctions/NativeRNFBTurboFunctionsJSI.h rename to packages/functions/android/src/main/java/io/invertase/firebase/functions/generated/jni/react/renderer/components/RNFBFunctionsTurboModules/RNFBFunctionsTurboModulesJSI.h diff --git a/packages/functions/ios/RNFBFunctions/RNFBFunctionsModule.h b/packages/functions/ios/RNFBFunctions/RNFBFunctionsModule.h index 106fde03d8..dbbbb172e8 100644 --- a/packages/functions/ios/RNFBFunctions/RNFBFunctionsModule.h +++ b/packages/functions/ios/RNFBFunctions/RNFBFunctionsModule.h @@ -17,7 +17,7 @@ #import #import -#import "NativeRNFBTurboFunctions.h" +#import "RNFBFunctionsTurboModules.h" @interface RNFBFunctionsModule : NSObject diff --git a/packages/functions/ios/RNFBFunctions/RNFBFunctionsModule.mm b/packages/functions/ios/RNFBFunctions/RNFBFunctionsModule.mm index 3fe5fbd1ab..100ab00d1f 100644 --- a/packages/functions/ios/RNFBFunctions/RNFBFunctionsModule.mm +++ b/packages/functions/ios/RNFBFunctions/RNFBFunctionsModule.mm @@ -18,7 +18,7 @@ #import #import -#import "NativeRNFBTurboFunctions.h" +#import "RNFBFunctionsTurboModules.h" #import "RNFBApp/RCTConvert+FIRApp.h" #import "RNFBApp/RNFBRCTEventEmitter.h" #import "RNFBApp/RNFBSharedUtils.h" diff --git a/packages/functions/ios/generated/NativeRNFBTurboFunctions/NativeRNFBTurboFunctions-generated.mm b/packages/functions/ios/generated/RNFBFunctionsTurboModules/RNFBFunctionsTurboModules-generated.mm similarity index 94% rename from packages/functions/ios/generated/NativeRNFBTurboFunctions/NativeRNFBTurboFunctions-generated.mm rename to packages/functions/ios/generated/RNFBFunctionsTurboModules/RNFBFunctionsTurboModules-generated.mm index 0c11c2b9ed..014ecd01ea 100644 --- a/packages/functions/ios/generated/NativeRNFBTurboFunctions/NativeRNFBTurboFunctions-generated.mm +++ b/packages/functions/ios/generated/RNFBFunctionsTurboModules/RNFBFunctionsTurboModules-generated.mm @@ -11,7 +11,7 @@ * must have a single output. More files => more genrule()s => slower builds. */ -#import "NativeRNFBTurboFunctions.h" +#import "RNFBFunctionsTurboModules.h" @implementation NativeRNFBTurboFunctionsSpecBase @@ -53,6 +53,12 @@ + (RCTManagedPointer *)JS_NativeRNFBTurboFunctions_SpecHttpsCallableStreamData:( return facebook::react::managedPointer(json); } @end +@implementation RCTCxxConvert (NativeRNFBTurboFunctions_SpecHttpsCallableStreamOptionsHttpsCallableStreamOptions) ++ (RCTManagedPointer *)JS_NativeRNFBTurboFunctions_SpecHttpsCallableStreamOptionsHttpsCallableStreamOptions:(id)json +{ + return facebook::react::managedPointer(json); +} +@end @implementation RCTCxxConvert (NativeRNFBTurboFunctions_SpecHttpsCallableStreamOptions) + (RCTManagedPointer *)JS_NativeRNFBTurboFunctions_SpecHttpsCallableStreamOptions:(id)json { diff --git a/packages/functions/ios/generated/NativeRNFBTurboFunctions/NativeRNFBTurboFunctions.h b/packages/functions/ios/generated/RNFBFunctionsTurboModules/RNFBFunctionsTurboModules.h similarity index 87% rename from packages/functions/ios/generated/NativeRNFBTurboFunctions/NativeRNFBTurboFunctions.h rename to packages/functions/ios/generated/RNFBFunctionsTurboModules/RNFBFunctionsTurboModules.h index bc87bcb371..0c54d334f5 100644 --- a/packages/functions/ios/generated/NativeRNFBTurboFunctions/NativeRNFBTurboFunctions.h +++ b/packages/functions/ios/generated/RNFBFunctionsTurboModules/RNFBFunctionsTurboModules.h @@ -15,9 +15,9 @@ #error This file must be compiled as Obj-C++. If you are importing it, you must change your file extension to .mm. #endif -// Avoid multiple includes of NativeRNFBTurboFunctions symbols -#ifndef NativeRNFBTurboFunctions_H -#define NativeRNFBTurboFunctions_H +// Avoid multiple includes of RNFBFunctionsTurboModules symbols +#ifndef RNFBFunctionsTurboModules_H +#define RNFBFunctionsTurboModules_H #import #import @@ -109,11 +109,28 @@ namespace JS { @interface RCTCxxConvert (NativeRNFBTurboFunctions_SpecHttpsCallableStreamData) + (RCTManagedPointer *)JS_NativeRNFBTurboFunctions_SpecHttpsCallableStreamData:(id)json; @end +namespace JS { + namespace NativeRNFBTurboFunctions { + struct SpecHttpsCallableStreamOptionsHttpsCallableStreamOptions { + id _Nullable signal() const; + std::optional limitedUseAppCheckTokens() const; + + SpecHttpsCallableStreamOptionsHttpsCallableStreamOptions(NSDictionary *const v) : _v(v) {} + private: + NSDictionary *_v; + }; + } +} + +@interface RCTCxxConvert (NativeRNFBTurboFunctions_SpecHttpsCallableStreamOptionsHttpsCallableStreamOptions) ++ (RCTManagedPointer *)JS_NativeRNFBTurboFunctions_SpecHttpsCallableStreamOptionsHttpsCallableStreamOptions:(id)json; +@end namespace JS { namespace NativeRNFBTurboFunctions { struct SpecHttpsCallableStreamOptions { std::optional timeout() const; std::optional limitedUseAppCheckTokens() const; + JS::NativeRNFBTurboFunctions::SpecHttpsCallableStreamOptionsHttpsCallableStreamOptions httpsCallableStreamOptions() const; SpecHttpsCallableStreamOptions(NSDictionary *const v) : _v(v) {} private: @@ -268,6 +285,16 @@ inline id JS::NativeRNFBTurboFunctions::SpecHttpsCallableStreamData::d id const p = _v[@"data"]; return p; } +inline id _Nullable JS::NativeRNFBTurboFunctions::SpecHttpsCallableStreamOptionsHttpsCallableStreamOptions::signal() const +{ + id const p = _v[@"signal"]; + return p; +} +inline std::optional JS::NativeRNFBTurboFunctions::SpecHttpsCallableStreamOptionsHttpsCallableStreamOptions::limitedUseAppCheckTokens() const +{ + id const p = _v[@"limitedUseAppCheckTokens"]; + return RCTBridgingToOptionalBool(p); +} inline std::optional JS::NativeRNFBTurboFunctions::SpecHttpsCallableStreamOptions::timeout() const { id const p = _v[@"timeout"]; @@ -278,6 +305,11 @@ inline std::optional JS::NativeRNFBTurboFunctions::SpecHttpsCallableStream id const p = _v[@"limitedUseAppCheckTokens"]; return RCTBridgingToOptionalBool(p); } +inline JS::NativeRNFBTurboFunctions::SpecHttpsCallableStreamOptionsHttpsCallableStreamOptions JS::NativeRNFBTurboFunctions::SpecHttpsCallableStreamOptions::httpsCallableStreamOptions() const +{ + id const p = _v[@"httpsCallableStreamOptions"]; + return JS::NativeRNFBTurboFunctions::SpecHttpsCallableStreamOptionsHttpsCallableStreamOptions(p); +} inline id JS::NativeRNFBTurboFunctions::SpecHttpsCallableStreamFromUrlData::data() const { id const p = _v[@"data"]; @@ -309,4 +341,4 @@ inline JS::NativeRNFBTurboFunctions::SpecHttpsCallableStreamFromUrlOptionsHttpsC return JS::NativeRNFBTurboFunctions::SpecHttpsCallableStreamFromUrlOptionsHttpsCallableStreamOptions(p); } NS_ASSUME_NONNULL_END -#endif // NativeRNFBTurboFunctions_H +#endif // RNFBFunctionsTurboModules_H diff --git a/packages/functions/android/src/main/java/io/invertase/firebase/functions/generated/jni/react/renderer/components/NativeRNFBTurboFunctions/NativeRNFBTurboFunctionsJSI-generated.cpp b/packages/functions/ios/generated/RNFBFunctionsTurboModulesJSI-generated.cpp similarity index 99% rename from packages/functions/android/src/main/java/io/invertase/firebase/functions/generated/jni/react/renderer/components/NativeRNFBTurboFunctions/NativeRNFBTurboFunctionsJSI-generated.cpp rename to packages/functions/ios/generated/RNFBFunctionsTurboModulesJSI-generated.cpp index 31cddefdf8..a7892576fb 100644 --- a/packages/functions/android/src/main/java/io/invertase/firebase/functions/generated/jni/react/renderer/components/NativeRNFBTurboFunctions/NativeRNFBTurboFunctionsJSI-generated.cpp +++ b/packages/functions/ios/generated/RNFBFunctionsTurboModulesJSI-generated.cpp @@ -7,7 +7,7 @@ * @generated by codegen project: GenerateModuleCpp.js */ -#include "NativeRNFBTurboFunctionsJSI.h" +#include "RNFBFunctionsTurboModulesJSI.h" namespace facebook::react { diff --git a/packages/functions/ios/generated/NativeRNFBTurboFunctionsJSI.h b/packages/functions/ios/generated/RNFBFunctionsTurboModulesJSI.h similarity index 100% rename from packages/functions/ios/generated/NativeRNFBTurboFunctionsJSI.h rename to packages/functions/ios/generated/RNFBFunctionsTurboModulesJSI.h diff --git a/packages/functions/package.json b/packages/functions/package.json index 77e798e75a..ca1a1bfc7d 100644 --- a/packages/functions/package.json +++ b/packages/functions/package.json @@ -6,7 +6,7 @@ "main": "./dist/module/index.js", "types": "./dist/typescript/lib/index.d.ts", "codegenConfig": { - "name": "NativeRNFBTurboFunctions", + "name": "RNFBFunctionsTurboModules", "type": "modules", "jsSrcsDir": "specs", "includesGeneratedCode": true, diff --git a/packages/messaging/lib/index.ts b/packages/messaging/lib/index.ts index ac113e884b..0abf46cc43 100644 --- a/packages/messaging/lib/index.ts +++ b/packages/messaging/lib/index.ts @@ -31,6 +31,7 @@ import { } from '@react-native-firebase/app/dist/module/internal'; import type { ModuleConfig } from '@react-native-firebase/app/dist/module/internal'; import { getReactNativeModule } from '@react-native-firebase/app/dist/module/internal/nativeModule'; +import { UTILS_NATIVE_MODULE } from '@react-native-firebase/app/dist/module/internal/constants'; import './types/internal'; import type { FirebaseApp } from '@react-native-firebase/app'; import type { ReactNativeFirebase } from '@react-native-firebase/app'; @@ -495,13 +496,17 @@ class FirebaseMessagingModule extends FirebaseModule im async isSupported(): Promise { if (isAndroid) { - const utilsNativeModule = getReactNativeModule('RNFBUtilsModule'); + const utilsNativeModule = getReactNativeModule(UTILS_NATIVE_MODULE); if (!utilsNativeModule) { return false; } - const playServicesAvailability = utilsNativeModule.androidPlayServices as - | { isAvailable?: boolean } + const androidGetPlayServicesStatus = utilsNativeModule.androidGetPlayServicesStatus as + | (() => Promise<{ isAvailable?: boolean }>) | undefined; + if (typeof androidGetPlayServicesStatus !== 'function') { + return false; + } + const playServicesAvailability = await androidGetPlayServicesStatus(); return playServicesAvailability?.isAvailable ?? false; } return true; diff --git a/packages/messaging/type-test.ts b/packages/messaging/type-test.ts index d111e32af0..303ad167bd 100644 --- a/packages/messaging/type-test.ts +++ b/packages/messaging/type-test.ts @@ -147,22 +147,16 @@ const modularUnsubscribeOnMessageSent = onMessageSent(modularMessaging1, (messag }); modularUnsubscribeOnMessageSent(); -const modularUnsubscribeOnSendError = onSendError( - modularMessaging1, - (evt: SendErrorEvent) => { - console.log(evt.messageId); - console.log(evt.error); - }, -); +const modularUnsubscribeOnSendError = onSendError(modularMessaging1, (evt: SendErrorEvent) => { + console.log(evt.messageId); + console.log(evt.error); +}); modularUnsubscribeOnSendError(); -setBackgroundMessageHandler( - modularMessaging1, - async (message: RemoteMessage) => { - console.log(message.data); - return Promise.resolve(); - }, -); +setBackgroundMessageHandler(modularMessaging1, async (message: RemoteMessage) => { + console.log(message.data); + return Promise.resolve(); +}); setOpenSettingsForNotificationsHandler(modularMessaging1, (message: RemoteMessage) => { console.log(message.data); diff --git a/tests/app.js b/tests/app.js index e8ddd20217..bace128e32 100644 --- a/tests/app.js +++ b/tests/app.js @@ -23,6 +23,13 @@ import { JetProvider, ConnectionText, StatusEmoji, StatusText } from 'jet'; import { TestComponents } from './local-tests'; +let harnessOverrides = {}; +try { + harnessOverrides = require('./harness.overrides.js'); +} catch (e) { + // Optional local overrides — see harness.overrides.example.js +} + const platformSupportedModules = []; if (Platform.other) { @@ -59,6 +66,11 @@ if (!Platform.other) { platformSupportedModules.push('phoneNumberVerification'); platformSupportedModules.push('ai'); } +if (Array.isArray(harnessOverrides.modules) && harnessOverrides.modules.length) { + const allowed = new Set(harnessOverrides.modules); + const filtered = platformSupportedModules.filter(module => allowed.has(module)); + platformSupportedModules.splice(0, platformSupportedModules.length, ...filtered); +} // Registering an error handler that always throw unhandled exceptions // This is to enable Jet to exit on uncaught errors const originalHandler = ErrorUtils.getGlobalHandler(); diff --git a/tests/e2e/firebase.test.js b/tests/e2e/firebase.test.js index 4005ea5069..7f52b7fd5d 100644 --- a/tests/e2e/firebase.test.js +++ b/tests/e2e/firebase.test.js @@ -176,38 +176,67 @@ function resolveIosSimulatorUdid() { } function logLaunchInstallState(label) { - const udid = resolveIosSimulatorUdid(); - if (!udid || process.platform !== 'darwin') { - console.log(`[rnfb-e2e] install-state label=${label} udid=unknown skipped=non-darwin-or-no-udid`); - return; + let platform = 'unknown'; + try { + if (typeof detox !== 'undefined' && detox?.device?.getPlatform) { + platform = detox.device.getPlatform(); + } + } catch (_) { + // Detox device may not be ready yet. } - try { - const container = execSync( - `/usr/bin/xcrun simctl get_app_container ${udid} com.invertase.testing 2>&1`, - { encoding: 'utf8', timeout: 15000 }, - ).trim(); - console.log(`[rnfb-e2e] install-state label=${label} udid=${udid} container=${container}`); - } catch (err) { - const detail = err?.stdout?.toString?.() || err?.message || String(err); - console.warn(`[rnfb-e2e] install-state label=${label} udid=${udid} container=missing detail=${detail}`); + if (platform === 'ios' && process.platform === 'darwin') { + const udid = resolveIosSimulatorUdid(); + if (!udid) { + console.log(`[rnfb-e2e] install-state label=${label} udid=unknown skipped=no-ios-udid`); + return; + } + + try { + const container = execSync( + `/usr/bin/xcrun simctl get_app_container ${udid} com.invertase.testing 2>&1`, + { encoding: 'utf8', timeout: 15000 }, + ).trim(); + console.log(`[rnfb-e2e] install-state label=${label} udid=${udid} container=${container}`); + } catch (err) { + const detail = err?.stdout?.toString?.() || err?.message || String(err); + console.warn( + `[rnfb-e2e] install-state label=${label} udid=${udid} container=missing detail=${detail}`, + ); + } + + try { + const apps = execSync(`/usr/bin/xcrun simctl listapps ${udid} 2>/dev/null`, { + encoding: 'utf8', + timeout: 30000, + }); + const invertaseLine = + apps + .split('\n') + .find(line => line.includes('com.invertase.testing')) || '(not listed)'; + console.log(`[rnfb-e2e] install-state label=${label} listapps=${invertaseLine.trim()}`); + } catch (err) { + console.warn( + `[rnfb-e2e] install-state label=${label} listapps=error detail=${err?.message || err}`, + ); + } + return; } - try { - const apps = execSync(`/usr/bin/xcrun simctl listapps ${udid} 2>/dev/null`, { - encoding: 'utf8', - timeout: 30000, - }); - const invertaseLine = - apps - .split('\n') - .find(line => line.includes('com.invertase.testing')) || '(not listed)'; - console.log(`[rnfb-e2e] install-state label=${label} listapps=${invertaseLine.trim()}`); - } catch (err) { - console.warn( - `[rnfb-e2e] install-state label=${label} listapps=error detail=${err?.message || err}`, - ); + if (platform === 'android') { + const serial = resolveAndroidSerial(); + try { + const apk = adbShell(serial, 'pm path com.invertase.testing'); + console.log(`[rnfb-e2e] install-state label=${label} serial=${serial} apk=${apk}`); + } catch (err) { + console.warn( + `[rnfb-e2e] install-state label=${label} serial=${serial} apk=missing detail=${err?.message || err}`, + ); + } + return; } + + console.log(`[rnfb-e2e] install-state label=${label} skipped=platform-${platform}`); } function rebootIosSimulator(testsDir) { diff --git a/tests/globals.js b/tests/globals.js index 40501c2520..6f43122b79 100644 --- a/tests/globals.js +++ b/tests/globals.js @@ -46,7 +46,14 @@ import shouldMatchers from 'should'; // [RNFB<--Event][📣] storage_event <- {...} // [RNFB<-Native][🟢] RNFBStorageModule.putString <- {...} // [TEST->Finish][✅] uploads a base64url string -globalThis.RNFBDebug = false; +let harnessOverrides = {}; +try { + harnessOverrides = require('./harness.overrides.js'); +} catch (e) { + // Optional local overrides — see harness.overrides.example.js +} + +globalThis.RNFBDebug = harnessOverrides.RNFBDebug ?? false; // Needed for Platform.Other session storage import AsyncStorage from '@react-native-async-storage/async-storage'; @@ -357,7 +364,8 @@ Object.defineProperty(global, 'NativeModules', { {}, { get: (target, moduleName) => { - if (moduleName.startsWith('RNF')) { + // NewArch-AD-18 E4: e2e harness routes turbo/legacy names through the unified resolver. + if (moduleName.startsWith('RNF') || moduleName.startsWith('NativeRNFBTurbo')) { return getReactNativeModule(moduleName); } return target[moduleName] || (() => {}); diff --git a/tests/harness.overrides.example.js b/tests/harness.overrides.example.js new file mode 100644 index 0000000000..11c76a351c --- /dev/null +++ b/tests/harness.overrides.example.js @@ -0,0 +1,24 @@ +/* + * Local e2e harness overrides (copy to harness.overrides.js — gitignored). + * + * Copy this file: + * cp tests/harness.overrides.example.js tests/harness.overrides.js + * + * Then edit harness.overrides.js for your local run. Never commit harness.overrides.js. + * + * Shape: + * { + * RNFBDebug?: boolean, // true = verbose RNFB native/event logging; disables test retries + * modules?: string[], // filter platformSupportedModules to this list (both Platform blocks) + * } + * + * Example — app package only, debug on: + * module.exports = { + * RNFBDebug: true, + * modules: ['app'], + * }; + * + * Omit a field (or export {}) to keep committed defaults for that field. + */ + +module.exports = {}; diff --git a/tests/ios/Podfile.lock b/tests/ios/Podfile.lock index 5b1c92bf38..8e36a5bdfe 100644 --- a/tests/ios/Podfile.lock +++ b/tests/ios/Podfile.lock @@ -225,31 +225,31 @@ PODS: - GoogleDataTransport (10.1.0): - nanopb (~> 3.30910.0) - PromisesObjC (~> 2.4) - - GoogleUtilities/AppDelegateSwizzler (8.1.1): + - GoogleUtilities/AppDelegateSwizzler (8.1.2): - GoogleUtilities/Environment - GoogleUtilities/Logger - GoogleUtilities/Network - GoogleUtilities/Privacy - - GoogleUtilities/Environment (8.1.1): + - GoogleUtilities/Environment (8.1.2): - GoogleUtilities/Privacy - - GoogleUtilities/Logger (8.1.1): + - GoogleUtilities/Logger (8.1.2): - GoogleUtilities/Environment - GoogleUtilities/Privacy - - GoogleUtilities/MethodSwizzler (8.1.1): + - GoogleUtilities/MethodSwizzler (8.1.2): - GoogleUtilities/Logger - GoogleUtilities/Privacy - - GoogleUtilities/Network (8.1.1): + - GoogleUtilities/Network (8.1.2): - GoogleUtilities/Logger - "GoogleUtilities/NSData+zlib" - GoogleUtilities/Privacy - GoogleUtilities/Reachability - - "GoogleUtilities/NSData+zlib (8.1.1)": + - "GoogleUtilities/NSData+zlib (8.1.2)": - GoogleUtilities/Privacy - - GoogleUtilities/Privacy (8.1.1) - - GoogleUtilities/Reachability (8.1.1): + - GoogleUtilities/Privacy (8.1.2) + - GoogleUtilities/Reachability (8.1.2): - GoogleUtilities/Logger - GoogleUtilities/Privacy - - GoogleUtilities/UserDefaults (8.1.1): + - GoogleUtilities/UserDefaults (8.1.2): - GoogleUtilities/Logger - GoogleUtilities/Privacy - GTMSessionFetcher/Core (5.3.0) @@ -1806,7 +1806,7 @@ PODS: - Yoga - RNDeviceInfo (15.0.2): - React-Core - - RNFBAnalytics (24.1.1): + - RNFBAnalytics (25.1.0): - DoubleConversion - FirebaseAnalytics/Core (= 12.15.0) - FirebaseAnalytics/IdentitySupport (= 12.15.0) @@ -1831,7 +1831,7 @@ PODS: - ReactCommon/turbomodule/core - RNFBApp - Yoga - - RNFBApp (24.1.1): + - RNFBApp (25.1.0): - DoubleConversion - Firebase/CoreOnly (= 12.15.0) - glog @@ -1853,7 +1853,7 @@ PODS: - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - Yoga - - RNFBAppCheck (24.1.1): + - RNFBAppCheck (25.1.0): - DoubleConversion - Firebase/AppCheck (= 12.15.0) - glog @@ -1876,7 +1876,7 @@ PODS: - ReactCommon/turbomodule/core - RNFBApp - Yoga - - RNFBAppDistribution (24.1.1): + - RNFBAppDistribution (25.1.0): - DoubleConversion - Firebase/AppDistribution (= 12.15.0) - glog @@ -1899,7 +1899,7 @@ PODS: - ReactCommon/turbomodule/core - RNFBApp - Yoga - - RNFBAuth (24.1.1): + - RNFBAuth (25.1.0): - DoubleConversion - Firebase/Auth (= 12.15.0) - glog @@ -1922,7 +1922,7 @@ PODS: - ReactCommon/turbomodule/core - RNFBApp - Yoga - - RNFBCrashlytics (24.1.1): + - RNFBCrashlytics (25.1.0): - DoubleConversion - Firebase/Crashlytics (= 12.15.0) - FirebaseCoreExtension @@ -1946,7 +1946,7 @@ PODS: - ReactCommon/turbomodule/core - RNFBApp - Yoga - - RNFBDatabase (24.1.1): + - RNFBDatabase (25.1.0): - DoubleConversion - Firebase/Database (= 12.15.0) - glog @@ -1969,7 +1969,7 @@ PODS: - ReactCommon/turbomodule/core - RNFBApp - Yoga - - RNFBFirestore (24.1.1): + - RNFBFirestore (25.1.0): - DoubleConversion - Firebase/Firestore (= 12.15.0) - glog @@ -1992,7 +1992,7 @@ PODS: - ReactCommon/turbomodule/core - RNFBApp - Yoga - - RNFBFunctions (24.1.1): + - RNFBFunctions (25.1.0): - DoubleConversion - Firebase/Functions (= 12.15.0) - glog @@ -2015,7 +2015,7 @@ PODS: - ReactCommon/turbomodule/core - RNFBApp - Yoga - - RNFBInAppMessaging (24.1.1): + - RNFBInAppMessaging (25.1.0): - DoubleConversion - Firebase/InAppMessaging (= 12.15.0) - glog @@ -2038,7 +2038,7 @@ PODS: - ReactCommon/turbomodule/core - RNFBApp - Yoga - - RNFBInstallations (24.1.1): + - RNFBInstallations (25.1.0): - DoubleConversion - Firebase/Installations (= 12.15.0) - glog @@ -2061,7 +2061,7 @@ PODS: - ReactCommon/turbomodule/core - RNFBApp - Yoga - - RNFBMessaging (24.1.1): + - RNFBMessaging (25.1.0): - DoubleConversion - Firebase/Messaging (= 12.15.0) - FirebaseCoreExtension @@ -2085,7 +2085,7 @@ PODS: - ReactCommon/turbomodule/core - RNFBApp - Yoga - - RNFBML (24.1.1): + - RNFBML (25.1.0): - DoubleConversion - glog - hermes-engine @@ -2107,7 +2107,7 @@ PODS: - ReactCommon/turbomodule/core - RNFBApp - Yoga - - RNFBPerf (24.1.1): + - RNFBPerf (25.1.0): - DoubleConversion - Firebase/Performance (= 12.15.0) - glog @@ -2130,7 +2130,7 @@ PODS: - ReactCommon/turbomodule/core - RNFBApp - Yoga - - RNFBRemoteConfig (24.1.1): + - RNFBRemoteConfig (25.1.0): - DoubleConversion - Firebase/RemoteConfig (= 12.15.0) - glog @@ -2153,7 +2153,7 @@ PODS: - ReactCommon/turbomodule/core - RNFBApp - Yoga - - RNFBStorage (24.1.1): + - RNFBStorage (25.1.0): - DoubleConversion - Firebase/Storage (= 12.15.0) - glog @@ -2534,7 +2534,7 @@ SPEC CHECKSUMS: GoogleAdsOnDeviceConversion: 80ce443fa1b4b5750913d53a04ecda644ff57744 GoogleAppMeasurement: a6d37949071d456e9147dac6789c4342e0e7a8c5 GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7 - GoogleUtilities: 4f2618a4a1e762a1ee134a1e2323bba9843e06da + GoogleUtilities: 766ace00c6b10d8148408f329d10c4f051931850 GTMSessionFetcher: 127211aeec0b1e904fc49f4f6f895dcc535b0ecf hermes-engine: b5c9cfbe6415f1b0b24759f2942c8f33e9af6347 leveldb-library: cc8b8f8e013647a295ad3f8cd2ddf49a6f19be19 @@ -2602,22 +2602,22 @@ SPEC CHECKSUMS: RecaptchaInterop: 11e0b637842dfb48308d242afc3f448062325aba RNCAsyncStorage: 6a8127b6987dc9fbce778669b252b14c8355c7ce RNDeviceInfo: 4c852998208b60dc192ae3529e5867817719ad1e - RNFBAnalytics: 4edf25551bb71542a91f75fdb82a189841ab609e - RNFBApp: fa42bb744282de8757e622921993a48aca624898 - RNFBAppCheck: ab603f89628885a3fb26a582c19c936ff5c822c3 - RNFBAppDistribution: 07259ad8ca1eaf36f95c9cab270e83ef5efb7c49 - RNFBAuth: aae485c49f699c5f6a4281df5e39070b93a7d953 - RNFBCrashlytics: 62ab87002f0bdcfbc383b99a1f439d8a2821c4f1 - RNFBDatabase: 95529c19fb9d037a806824c9a72edfe869e8a3a0 - RNFBFirestore: b16837b10adc055cb4fb45ecf49539efbc134c23 - RNFBFunctions: 355da8e22e8c09d6a75b2e189d72f55f4744c382 - RNFBInAppMessaging: daa6c1c445576ba1ab2baaac21d3b637a3b41ed5 - RNFBInstallations: 645e6eb7ebe3ac676e576458f8cbc38b21e1e1a7 - RNFBMessaging: f0c63abac187249c6a5b6613c6085a0b6742e196 - RNFBML: 2aa57d48341bfab095e836b1cebebd3e9bf6081a - RNFBPerf: 2872ddee03fcba3f81956b5e987db398034f0078 - RNFBRemoteConfig: 3f057d6d8df516a25d6dbeb0b2e80a54ada2176f - RNFBStorage: 780713864cc9e678f61974f6f2024793294cbc4f + RNFBAnalytics: 852e18e0161a43fa4009ef78e8249df60a074278 + RNFBApp: 893629fc75425937059b0f64e58ec9d5a066aefc + RNFBAppCheck: 5b0711c6f4f982fbe606f03e3b68f719c291371a + RNFBAppDistribution: 41758adfd29474d1244dfd0f17f0bd992c493051 + RNFBAuth: 6656cfdec1c2c7a238666ab46f00f37650ea4e86 + RNFBCrashlytics: 023cb897d12145878e749cc6c105e7ae6bb08996 + RNFBDatabase: 6205ca9a46bb177b1577dbf1dad08c5ea018cd67 + RNFBFirestore: df2a438176508cfefee7ac4b621f6ce5e152df1e + RNFBFunctions: d0ffe52e4f6138c3e42e69937b0592838e6f2cc9 + RNFBInAppMessaging: bcb89b77069691d903621c83cfc3a1d6bfcb43b2 + RNFBInstallations: 1073ed6c5b5f6da5378eca9f7c17bfbbd6deada6 + RNFBMessaging: 63037c34a83e479bca38d27bacb4baf485e4cde1 + RNFBML: 9b8147b6dcbe8b8da23cb1c7aa345f6f903c73a5 + RNFBPerf: 18e2f4786c1ee6ab62609c0b6236686716e41170 + RNFBRemoteConfig: 373fc5298222ecaef439c00ab420c79e9a1e7d38 + RNFBStorage: c53e4edb4f9984685cfd1adca4a16d161a353b42 SocketRocket: d4aabe649be1e368d1318fdf28a022d714d65748 Yoga: 3bb1ee33b5133befbd33872601fa46efdd48e841 From 32918c8853447eadbc5cf64d5a4ea8f3148243ce Mon Sep 17 00:00:00 2001 From: Mike Hardy Date: Tue, 30 Jun 2026 12:05:48 -0500 Subject: [PATCH 03/10] test(app): add app module type comparison config Register @react-native-firebase/app in compare:types and document 25 modular API deltas against firebase-js-sdk. Type SDK_VERSION as string. --- .github/scripts/compare-types/configs/app.ts | 149 ++++++++++++++++++ .github/scripts/compare-types/src/registry.ts | 15 ++ .../new-architecture/migration-work-queue.md | 14 +- packages/app/lib/modular.ts | 2 +- 4 files changed, 172 insertions(+), 8 deletions(-) create mode 100644 .github/scripts/compare-types/configs/app.ts diff --git a/.github/scripts/compare-types/configs/app.ts b/.github/scripts/compare-types/configs/app.ts new file mode 100644 index 0000000000..6f7b08d64b --- /dev/null +++ b/.github/scripts/compare-types/configs/app.ts @@ -0,0 +1,149 @@ +/** + * Known differences between firebase-js-sdk @firebase/app and + * @react-native-firebase/app modular API. + * + * Each entry must have a `name` and a `reason`. Any undocumented + * difference or stale entry will fail `yarn compare:types`. + */ + +import type { PackageConfig } from '../src/types'; + +const config: PackageConfig = { + nameMapping: {}, + + missingInRN: [ + { + name: 'initializeServerApp', + reason: + 'firebase-js-sdk server-side rendering entry point. Not applicable to React Native.', + }, + { + name: 'FirebaseAppSettings', + reason: + 'Settings type for firebase-js-sdk `FirebaseServerApp`. RN Firebase has no server-app API.', + }, + { + name: 'FirebaseError', + reason: + 'firebase-js-sdk base error class. RN Firebase uses `ReactNativeFirebase.NativeFirebaseError` from the native bridge instead.', + }, + { + name: 'FirebaseOptions', + reason: + 'firebase-js-sdk options interface. RN Firebase uses `ReactNativeFirebase.FirebaseAppOptions` (extends the same fields with RN-specific optional keys).', + }, + { + name: 'FirebaseServerApp', + reason: + 'firebase-js-sdk server-side app instance type. Not applicable to React Native.', + }, + { + name: 'FirebaseServerAppSettings', + reason: + 'Settings type for firebase-js-sdk server apps. Not applicable to React Native.', + }, + ], + + extraInRN: [ + { + name: 'setReactNativeAsyncStorage', + reason: + 'RN Firebase-specific hook to wire `@react-native-async-storage/async-storage` into the firebase-js-sdk Other/Hermes persistence path.', + }, + { + name: 'metaGetAll', + reason: + 'RN Firebase native bridge helper — reads all entries from the native Firebase metadata store.', + }, + { + name: 'jsonGetAll', + reason: + 'RN Firebase native bridge helper — reads all entries from the native JSON config store.', + }, + { + name: 'preferencesClearAll', + reason: + 'RN Firebase native bridge helper — clears native shared preferences used by Firebase.', + }, + { + name: 'preferencesGetAll', + reason: + 'RN Firebase native bridge helper — reads all native shared preference entries.', + }, + { + name: 'preferencesSetBool', + reason: + 'RN Firebase native bridge helper — sets a native boolean preference.', + }, + { + name: 'preferencesSetString', + reason: + 'RN Firebase native bridge helper — sets a native string preference.', + }, + { + name: 'getUtils', + reason: + 'RN Firebase entry point for the native Utils module (Play Services, file paths, etc.). No firebase-js-sdk modular equivalent.', + }, + { + name: 'FilePath', + reason: + 'RN Firebase native device file-path constants for Storage and similar file-based APIs.', + }, + { + name: 'LogCallbackParams', + reason: + 'RN Firebase log-handler callback payload type exported for modular `setLogLevel` wiring.', + }, + { + name: 'LogCallback', + reason: + 'RN Firebase log-handler callback type exported for modular logging configuration.', + }, + { + name: 'LogOptions', + reason: + 'RN Firebase log-handler options type exported for modular logging configuration.', + }, + ], + + differentShape: [ + { + name: 'deleteApp', + reason: + 'Parameter type is `ReactNativeFirebase.FirebaseApp` instead of firebase-js-sdk `FirebaseApp`. Runtime behavior matches.', + }, + { + name: 'getApp', + reason: + 'Return type is `ReactNativeFirebase.FirebaseApp` instead of firebase-js-sdk `FirebaseApp`. Runtime behavior matches.', + }, + { + name: 'getApps', + reason: + 'Return type is `ReactNativeFirebase.FirebaseApp[]` instead of firebase-js-sdk `FirebaseApp[]`. Runtime behavior matches.', + }, + { + name: 'initializeApp', + reason: + 'Returns `Promise` because initialization crosses the native bridge. Accepts `ReactNativeFirebase.FirebaseAppOptions` and optional `ReactNativeFirebase.FirebaseAppConfig` (name / auth domain) instead of firebase-js-sdk `(FirebaseOptions, string)` only.', + }, + { + name: 'registerVersion', + reason: + 'Returns `Promise` in RN Firebase vs `void` in firebase-js-sdk. Bridge-forced async today — Phase S sync-conversion candidate when native work is in-memory only.', + }, + { + name: 'setLogLevel', + reason: + 'Parameter type is `ReactNativeFirebase.LogLevelString` instead of firebase-js-sdk `LogLevelString`. Accepted values match (`debug`, `verbose`, `info`, `warn`, `error`, `silent`).', + }, + { + name: 'FirebaseApp', + reason: + 'RN Firebase exports the `ReactNativeFirebase.FirebaseApp` class/interface from shared app declarations instead of re-exporting firebase-js-sdk `FirebaseApp`.', + }, + ], +}; + +export default config; diff --git a/.github/scripts/compare-types/src/registry.ts b/.github/scripts/compare-types/src/registry.ts index be1e1ac19c..2193c56e86 100644 --- a/.github/scripts/compare-types/src/registry.ts +++ b/.github/scripts/compare-types/src/registry.ts @@ -21,6 +21,7 @@ import remoteConfigConfig from '../configs/remote-config'; import authConfig from '../configs/auth'; import installationsConfig from '../configs/installations'; import perfConfig from '../configs/perf-config'; +import appConfig from '../configs/app'; const REPO_ROOT = path.resolve(__dirname, '..', '..', '..', '..'); @@ -103,6 +104,20 @@ function optionalFirebasePackage( } export const packages: PackageEntry[] = [ + { + name: 'app', + firebaseSdkTypesPaths: [requiredFirebaseTypes('app')], + rnFirebaseModularFiles: [ + path.join(rnDist('app'), 'modular.d.ts'), + path.join(rnDist('app'), 'index.d.ts'), + ], + rnFirebaseSupportFiles: [ + path.join(rnDist('app'), 'types', 'app.d.ts'), + path.join(rnDist('app'), 'types', 'internal.d.ts'), + path.join(rnDist('app'), 'FirebaseApp.d.ts'), + ], + config: appConfig, + }, { name: 'auth', firebaseSdkTypesPaths: [requiredFirebaseTypes('auth')], diff --git a/okf-bundle/new-architecture/migration-work-queue.md b/okf-bundle/new-architecture/migration-work-queue.md index 01907811cd..bb4b0e4cb9 100644 --- a/okf-bundle/new-architecture/migration-work-queue.md +++ b/okf-bundle/new-architecture/migration-work-queue.md @@ -8,7 +8,7 @@ timestamp: 2026-06-26T00:00:00Z # TurboModule migration — work queue -> **IN PROGRESS (2026-06-30):** Phase **0** (`app` TurboModules) — **done**. Phase **0.1** (`app` compare:types) — **queued**. Decisions: [architecture-decisions.md](architecture-decisions.md). +> **IN PROGRESS (2026-06-30):** Phase **0** (`app` TurboModules) — **done**. Phase **0.1** (`app` compare:types) — **commit** pending. Decisions: [architecture-decisions.md](architecture-decisions.md). > **Goal/order:** app foundation → hard probe → easy wins → remaining complex → sync conversion → coordinated break → cleanup (events, shared-state encapsulation). Decisions: [architecture-decisions.md](architecture-decisions.md). Links: [implementation workflow](turbomodule-implementation-workflow.md), [change authoring](../testing/change-authoring-workflow.md), [functions reference](../../../packages/functions/) ([PR #8603](https://github.com/invertase/react-native-firebase/pull/8603)). Ephemeral tracker; see [OKF policy](../documentation-policy.md). @@ -161,7 +161,7 @@ Pick **one** of `firestore` or `auth` in Phase 1 (firestore = multi-module + pip | Phase | Focus | Status | Packages | |-------|--------|--------|----------| | **0** | App foundation + unified resolver | **done** | `app` | -| **0.1** | App modular type parity (`compare:types`) | **queued** | `app` — [§ Phase 0.1](#phase-01-app-comparetypes) | +| **0.1** | App modular type parity (`compare:types`) | **commit pending** | `app` — [§ Phase 0.1](#phase-01-app-comparetypes) | | **1** | Hard probe | queued | `firestore` **or** `auth` — pick one | | **2** | Easy wins | queued | `installations`, `perf`, `in-app-messaging`, `app-distribution`, `ml` | | **3** | Moderate | queued | `app-check`, `remote-config`, `analytics`, `crashlytics`, `storage` | @@ -207,7 +207,7 @@ The "keep async if it does network/IO/disk" rule in the discriminator **assumes* | Column | What to record | |--------|----------------| | Method | RNFB API + package | -| compare:types signal | Is it currently recorded as an async-vs-sync delta? (note: `app` registers in Phase **0.1**; other packages may still be unregistered — do not treat the config list as the full candidate set) | +| compare:types signal | Is it currently recorded as an async-vs-sync delta? (note: `app` is registered as of Phase **0.1**; other packages may still be unregistered — do not treat the config list as the full candidate set) | | firebase-js-sdk behavior | What the web SDK actually does under the hood — **in-memory/cached** vs **deferred IO**. Cite the SDK source. | | RNFB native behavior | What our native shell does for the same result — pure in-memory (SDK getter, parse, cached field) vs real IO (network, disk, keychain, Play Services). | | Verdict | `convert` (both in-memory) / `keep-async` (either side does real IO) / `needs-native-change` (web is in-memory but our native is needlessly IO and could be made in-memory) | @@ -267,11 +267,11 @@ Skip steps 1–2 when spec shape is known (most Tier D packages). ## Current snapshot -**Label:** `phase-0-committed`; **harness:** full (committed defaults) +**Label:** `phase-0.1-compare-types`; **harness:** n/a (types-only) -**Next item:** Phase **0.1** `app` compare:types — **implementation** +**Next item:** Phase **0.1** `app` compare:types — **commit** -**Current gates:** Phase 0 all **closed** · Phase 0.1 all **open** +**Current gates:** Phase 0 all **closed** · Phase 0.1 `review_gate` **closed** · `commit_gate` **open** **Arbiter gate:** @@ -280,7 +280,7 @@ Skip steps 1–2 when spec shape is known (most Tier D packages). |------|------|----------------------|---------------|---------------|------------------|-------------------|------------------|-------| | Design review | DR | n/a | n/a | n/a | done | none | none | ✅ Adversarial review complete. | | Phase 0 `app` TurboModules | P0 | **closed** | **closed** | **closed** | done | `full` | `feat(app): migrate app modules to TurboModules incl general migration infra` | Committed 2026-06-30. | -| Phase 0.1 `app` compare:types | P0.1 | **open** | **open** | **open** | `implementation` | `none` | `test(app): add app module type comparison config` | Queued after P0. | +| Phase 0.1 `app` compare:types | P0.1 | **closed** | **closed** | **open** | `commit` | `none` | `test(app): add app module type comparison config` | 25 deltas documented; `SDK_VERSION` typed `string`; compare:types green for `app`. | --- diff --git a/packages/app/lib/modular.ts b/packages/app/lib/modular.ts index 27966f7182..3347b607a5 100644 --- a/packages/app/lib/modular.ts +++ b/packages/app/lib/modular.ts @@ -166,7 +166,7 @@ export function preferencesSetString(key: string, value: string): Promise return getAppModule().preferencesSetString(key, value); } -export const SDK_VERSION = sdkVersion; +export const SDK_VERSION: string = sdkVersion; /** * Returns the {@link Utils.Module} instance for the default or given {@link ReactNativeFirebase.FirebaseApp}. From eef34e7584d3137e1361ab540107165156e5bf00 Mon Sep 17 00:00:00 2001 From: Mike Hardy Date: Tue, 30 Jun 2026 15:59:58 -0500 Subject: [PATCH 04/10] feat(firestore)!: migrate firestore to TurboModules BREAKING CHANGE: Firestore native bridge requires New Architecture. Legacy NativeModules bridge removed; four Codegen TurboModule specs (NativeRNFBTurboFirestore{,Collection,Document,Transaction}) with committed generated artifacts, Android/iOS turbo shells, and JS wiring. --- jest.setup.ts | 34 +- .../architecture-decisions.md | 4 +- .../new-architecture/migration-work-queue.md | 17 +- .../turbomodule-implementation-workflow.md | 6 +- packages/firestore/RNFBFirestore.podspec | 25 +- .../__tests__/nativeModuleContract.test.ts | 146 ++++ packages/firestore/android/build.gradle | 19 + .../FirestoreTurboModuleSupport.java | 56 ++ ...ule.java => NativeRNFBTurboFirestore.java} | 64 +- ...> NativeRNFBTurboFirestoreCollection.java} | 64 +- ... => NativeRNFBTurboFirestoreDocument.java} | 67 +- ... NativeRNFBTurboFirestoreTransaction.java} | 43 +- .../ReactNativeFirebaseFirestorePackage.java | 8 +- ...ativeRNFBTurboFirestoreCollectionSpec.java | 69 ++ .../NativeRNFBTurboFirestoreDocumentSpec.java | 65 ++ .../specs/NativeRNFBTurboFirestoreSpec.java | 83 +++ ...tiveRNFBTurboFirestoreTransactionSpec.java | 51 ++ .../firestore/generated/jni/CMakeLists.txt | 36 + .../RNFBFirestoreTurboModules-generated.cpp | 230 +++++++ .../generated/jni/RNFBFirestoreTurboModules.h | 55 ++ ...RNFBFirestoreTurboModulesJSI-generated.cpp | 357 ++++++++++ .../RNFBFirestoreTurboModulesJSI.h | 637 ++++++++++++++++++ .../RNFBFirestore.xcodeproj/project.pbxproj | 32 +- ...ule.m => RNFBFirestoreCollectionModule.mm} | 222 +++--- ...odule.m => RNFBFirestoreDocumentModule.mm} | 154 +++-- ...restoreModule.m => RNFBFirestoreModule.mm} | 168 ++--- ...le.m => RNFBFirestoreTransactionModule.mm} | 200 +++--- .../RNFBFirestoreTurboModules-generated.mm | 311 +++++++++ .../RNFBFirestoreTurboModules.h | 345 ++++++++++ ...RNFBFirestoreTurboModulesJSI-generated.cpp | 357 ++++++++++ .../generated/RNFBFirestoreTurboModulesJSI.h | 637 ++++++++++++++++++ packages/firestore/lib/FirestoreModule.ts | 11 +- packages/firestore/lib/FirestoreStatics.ts | 7 +- .../lib/internal/staticNativeModule.ts | 48 ++ packages/firestore/lib/types/internal.ts | 17 +- packages/firestore/package.json | 22 +- packages/firestore/react-native.config.js | 10 + .../specs/NativeRNFBTurboFirestore.ts | 36 + .../NativeRNFBTurboFirestoreCollection.ts | 80 +++ .../specs/NativeRNFBTurboFirestoreDocument.ts | 37 + .../NativeRNFBTurboFirestoreTransaction.ts | 22 + tests/ios/Podfile.lock | 2 +- 42 files changed, 4327 insertions(+), 527 deletions(-) create mode 100644 packages/firestore/__tests__/nativeModuleContract.test.ts create mode 100644 packages/firestore/android/src/reactnative/java/io/invertase/firebase/firestore/FirestoreTurboModuleSupport.java rename packages/firestore/android/src/reactnative/java/io/invertase/firebase/firestore/{ReactNativeFirebaseFirestoreModule.java => NativeRNFBTurboFirestore.java} (82%) rename packages/firestore/android/src/reactnative/java/io/invertase/firebase/firestore/{ReactNativeFirebaseFirestoreCollectionModule.java => NativeRNFBTurboFirestoreCollection.java} (91%) rename packages/firestore/android/src/reactnative/java/io/invertase/firebase/firestore/{ReactNativeFirebaseFirestoreDocumentModule.java => NativeRNFBTurboFirestoreDocument.java} (86%) rename packages/firestore/android/src/reactnative/java/io/invertase/firebase/firestore/{ReactNativeFirebaseFirestoreTransactionModule.java => NativeRNFBTurboFirestoreTransaction.java} (88%) create mode 100644 packages/firestore/android/src/reactnative/java/io/invertase/firebase/firestore/generated/java/com/facebook/fbreact/specs/NativeRNFBTurboFirestoreCollectionSpec.java create mode 100644 packages/firestore/android/src/reactnative/java/io/invertase/firebase/firestore/generated/java/com/facebook/fbreact/specs/NativeRNFBTurboFirestoreDocumentSpec.java create mode 100644 packages/firestore/android/src/reactnative/java/io/invertase/firebase/firestore/generated/java/com/facebook/fbreact/specs/NativeRNFBTurboFirestoreSpec.java create mode 100644 packages/firestore/android/src/reactnative/java/io/invertase/firebase/firestore/generated/java/com/facebook/fbreact/specs/NativeRNFBTurboFirestoreTransactionSpec.java create mode 100644 packages/firestore/android/src/reactnative/java/io/invertase/firebase/firestore/generated/jni/CMakeLists.txt create mode 100644 packages/firestore/android/src/reactnative/java/io/invertase/firebase/firestore/generated/jni/RNFBFirestoreTurboModules-generated.cpp create mode 100644 packages/firestore/android/src/reactnative/java/io/invertase/firebase/firestore/generated/jni/RNFBFirestoreTurboModules.h create mode 100644 packages/firestore/android/src/reactnative/java/io/invertase/firebase/firestore/generated/jni/react/renderer/components/RNFBFirestoreTurboModules/RNFBFirestoreTurboModulesJSI-generated.cpp create mode 100644 packages/firestore/android/src/reactnative/java/io/invertase/firebase/firestore/generated/jni/react/renderer/components/RNFBFirestoreTurboModules/RNFBFirestoreTurboModulesJSI.h rename packages/firestore/ios/RNFBFirestore/{RNFBFirestoreCollectionModule.m => RNFBFirestoreCollectionModule.mm} (76%) rename packages/firestore/ios/RNFBFirestore/{RNFBFirestoreDocumentModule.m => RNFBFirestoreDocumentModule.mm} (72%) rename packages/firestore/ios/RNFBFirestore/{RNFBFirestoreModule.m => RNFBFirestoreModule.mm} (65%) rename packages/firestore/ios/RNFBFirestore/{RNFBFirestoreTransactionModule.m => RNFBFirestoreTransactionModule.mm} (75%) create mode 100644 packages/firestore/ios/generated/RNFBFirestoreTurboModules/RNFBFirestoreTurboModules-generated.mm create mode 100644 packages/firestore/ios/generated/RNFBFirestoreTurboModules/RNFBFirestoreTurboModules.h create mode 100644 packages/firestore/ios/generated/RNFBFirestoreTurboModulesJSI-generated.cpp create mode 100644 packages/firestore/ios/generated/RNFBFirestoreTurboModulesJSI.h create mode 100644 packages/firestore/lib/internal/staticNativeModule.ts create mode 100644 packages/firestore/react-native.config.js create mode 100644 packages/firestore/specs/NativeRNFBTurboFirestore.ts create mode 100644 packages/firestore/specs/NativeRNFBTurboFirestoreCollection.ts create mode 100644 packages/firestore/specs/NativeRNFBTurboFirestoreDocument.ts create mode 100644 packages/firestore/specs/NativeRNFBTurboFirestoreTransaction.ts diff --git a/jest.setup.ts b/jest.setup.ts index 1c5370b83f..67d781886e 100644 --- a/jest.setup.ts +++ b/jest.setup.ts @@ -284,7 +284,8 @@ jest.doMock('react-native', () => { ), getServerTime: jest.fn((_appName: any, _customUrl: any) => Promise.resolve(Date.now())), }, - RNFBFirestoreModule: { + NativeRNFBTurboFirestore: { + setLogLevel: jest.fn(), loadBundle: jest.fn(() => Promise.resolve({ taskState: 'Success', @@ -303,9 +304,20 @@ jest.doMock('react-native', () => { settings: jest.fn(), addSnapshotsInSync: jest.fn(), removeSnapshotsInSync: jest.fn(), + persistenceCacheIndexManager: jest.fn(), + }, + NativeRNFBTurboFirestoreCollection: { collectionOffSnapshot: jest.fn(), namedQueryOnSnapshot: jest.fn(), collectionOnSnapshot: jest.fn(), + namedQueryGet: jest.fn(() => + Promise.resolve({ + source: 'cache', + changes: [], + documents: [], + metadata: {}, + }), + ), collectionGet: jest.fn(() => Promise.resolve({ source: 'cache', @@ -315,6 +327,15 @@ jest.doMock('react-native', () => { }), ), collectionCount: jest.fn(() => Promise.resolve({ count: 0 })), + aggregateQuery: jest.fn(() => Promise.resolve({})), + pipelineExecute: jest.fn(() => + Promise.resolve({ + results: [], + executionTime: Date.now(), + }), + ), + }, + NativeRNFBTurboFirestoreDocument: { documentDelete: jest.fn(() => Promise.resolve()), documentOffSnapshot: jest.fn(), documentOnSnapshot: jest.fn(), @@ -328,11 +349,20 @@ jest.doMock('react-native', () => { ), documentSet: jest.fn(() => Promise.resolve()), documentUpdate: jest.fn(() => Promise.resolve()), - persistenceCacheIndexManager: jest.fn(), documentBatch: jest.fn(), + }, + NativeRNFBTurboFirestoreTransaction: { transactionApplyBuffer: jest.fn(), transactionBegin: jest.fn(), transactionDispose: jest.fn(), + transactionGetDocument: jest.fn(() => + Promise.resolve({ + data: {}, + metadata: {}, + path: 'firestore/document', + exists: true, + }), + ), }, RNFBFiamModule: { isMessagesDisplaySuppressed: false, diff --git a/okf-bundle/new-architecture/architecture-decisions.md b/okf-bundle/new-architecture/architecture-decisions.md index 09bfaa7542..5c50552a28 100644 --- a/okf-bundle/new-architecture/architecture-decisions.md +++ b/okf-bundle/new-architecture/architecture-decisions.md @@ -132,7 +132,7 @@ Multiple specs/modules in one package are **merged flat** into a single resolved ## NewArch-AD-12 — One commit per package — **Accepted** -Convert a whole package (all its legacy modules → all its specs) in one `implementation → independent-review → commit` loop; land it as one `feat(): migrate to TurboModules`. Multiple specs ≠ multiple commits — they share `codegenConfig`, generated artifacts, podspec/gradle guards, and JS wiring that only build and pass e2e together. +Convert a whole package (all its legacy modules → all its specs) in one `implementation → independent-review → commit` loop; land it as one `feat()!: migrate to TurboModules` (breaking: New Architecture required). Multiple specs ≠ multiple commits — they share `codegenConfig`, generated artifacts, podspec/gradle guards, and JS wiring that only build and pass e2e together. --- @@ -263,7 +263,7 @@ Two resolution surfaces exist and must be used deliberately: | E5 | [`UtilsStatics.ts`](../../../packages/app/lib/utils/UtilsStatics.ts) `FilePath` getter | `NativeRNFBTurboUtils` | **Phase 0 fix** | Reads path **constants** synchronously from the utils host without a `FirebaseModule` instance (static getter on `Utils.Statics`). Raw was acceptable pre-turbo; under [NewArch-AD-15](#newarch-ad-15--constant-memoization-scope-static-only--accepted) migrate to a dedicated wrapped utils accessor (or memoized static read via resolver) so constants are not rebuilt per access. Turbo name is already correct. | Fix in Phase 0 re-implementation. | | E6 | [`messaging/lib/index.ts`](../../../packages/messaging/lib/index.ts) `isSupported()` | ~~`RNFBUtilsModule`~~ → `NativeRNFBTurboUtils` | **Phase 0 fix (bug)** | Cross-package read of Play Services availability. Was using **legacy module name** (returns `undefined` under turbo-only) and a **dynamic constant** (`androidPlayServices`) that can go stale. Must use turbo name + **dynamic method** `androidGetPlayServicesStatus()` per [NewArch-AD-15](#newarch-ad-15--constant-memoization-scope-static-only--accepted). | **Must-fix** in Phase 0. | | E7 | [`app/lib/modular.ts`](../../../packages/app/lib/modular.ts) `metaGetAll`, `jsonGetAll`, `preferences*` | `NativeRNFBTurboApp` | **Not an exception — migrate** | No policy reason for raw; these are app-module method calls with no arg-prepend skip. Should use **`getAppModule()`** (wrapped) for error mapping consistency. Listed here so gap-analysis catches them. | Migrate to `getAppModule()` in Phase 0. | -| E8 | [`FirestoreStatics.ts`](../../../packages/firestore/lib/FirestoreStatics.ts) `setLogLevel` | `RNFBFirestoreModule` | **Deferred — Phase 1** | Cross-package static helper bypasses `FirebaseModule`/`getNativeModule`. Acceptable until firestore migrates; then switch to turbo name + wrapped surface (or firestore-owned static that uses `getNativeModule`). | Fix when `firestore` migrates. | +| E8 | [`FirestoreStatics.ts`](../../../packages/firestore/lib/FirestoreStatics.ts) `setLogLevel` | `NativeRNFBTurboFirestore` | **Phase 1 fix** | Cross-package static helper bypasses `FirebaseModule`/`getNativeModule`. Uses turbo main host via [`getStaticFirestoreMainModule()`](../../../packages/firestore/lib/internal/staticNativeModule.ts) (NewArch-AD-18 E8). Raw access retained — no wrapped surface for static helpers. | Done — firestore Phase 1. | | E9 | [`DatabaseSyncTree.ts`](../../../packages/database/lib/DatabaseSyncTree.ts) `native` getter | `RNFBDatabaseQueryModule` | **Deferred — Phase 4** | Internal sync listener tree calls query module directly for low-latency sync ops, bypassing the merged multi-module surface. Acceptable until database migrates; then turbo name + evaluate whether wrapped merge surface suffices. | Fix when `database` migrates. | | E10 | [`phone-number-verification/lib/index.ts`](../../../packages/phone-number-verification/lib/index.ts) `getNativeModule()` | `RNFBPnvModule` | **Deferred — Phase 5** | Package bypasses `createModuleNamespace` by design ([workflow § gotchas](turbomodule-implementation-workflow.md#gotchas)). Direct resolver is intentional; update to `NativeRNFBTurboPnv` on migration. | Fix when `phone-number-verification` migrates. | diff --git a/okf-bundle/new-architecture/migration-work-queue.md b/okf-bundle/new-architecture/migration-work-queue.md index bb4b0e4cb9..d0020ec0cb 100644 --- a/okf-bundle/new-architecture/migration-work-queue.md +++ b/okf-bundle/new-architecture/migration-work-queue.md @@ -8,7 +8,7 @@ timestamp: 2026-06-26T00:00:00Z # TurboModule migration — work queue -> **IN PROGRESS (2026-06-30):** Phase **0** (`app` TurboModules) — **done**. Phase **0.1** (`app` compare:types) — **commit** pending. Decisions: [architecture-decisions.md](architecture-decisions.md). +> **IN PROGRESS (2026-06-30):** Phase **2** easy wins — **queued**. Phases **0** / **0.1** (`app`) and Phase **1** (`firestore`) — **done**. Decisions: [architecture-decisions.md](architecture-decisions.md). > **Goal/order:** app foundation → hard probe → easy wins → remaining complex → sync conversion → coordinated break → cleanup (events, shared-state encapsulation). Decisions: [architecture-decisions.md](architecture-decisions.md). Links: [implementation workflow](turbomodule-implementation-workflow.md), [change authoring](../testing/change-authoring-workflow.md), [functions reference](../../../packages/functions/) ([PR #8603](https://github.com/invertase/react-native-firebase/pull/8603)). Ephemeral tracker; see [OKF policy](../documentation-policy.md). @@ -161,8 +161,8 @@ Pick **one** of `firestore` or `auth` in Phase 1 (firestore = multi-module + pip | Phase | Focus | Status | Packages | |-------|--------|--------|----------| | **0** | App foundation + unified resolver | **done** | `app` | -| **0.1** | App modular type parity (`compare:types`) | **commit pending** | `app` — [§ Phase 0.1](#phase-01-app-comparetypes) | -| **1** | Hard probe | queued | `firestore` **or** `auth` — pick one | +| **0.1** | App modular type parity (`compare:types`) | **done** | `app` — [§ Phase 0.1](#phase-01-app-comparetypes) | +| **1** | Hard probe | **done** | `firestore` (multi-module + pipelines; NewArch-AD-14a composite) | | **2** | Easy wins | queued | `installations`, `perf`, `in-app-messaging`, `app-distribution`, `ml` | | **3** | Moderate | queued | `app-check`, `remote-config`, `analytics`, `crashlytics`, `storage` | | **4** | Remaining complex | queued | other Tier A/B + `messaging`, `database` | @@ -267,11 +267,13 @@ Skip steps 1–2 when spec shape is known (most Tier D packages). ## Current snapshot -**Label:** `phase-0.1-compare-types`; **harness:** n/a (types-only) +**Label:** `phase-2-easy-wins`; **harness:** n/a -**Next item:** Phase **0.1** `app` compare:types — **commit** +**Next item:** Phase **2** — pick first Tier D package (`installations`, `perf`, `in-app-messaging`, `app-distribution`, or `ml`) -**Current gates:** Phase 0 all **closed** · Phase 0.1 `review_gate` **closed** · `commit_gate` **open** +**Current gates:** Phase 0 / 0.1 / 1 all **closed** + +**Package pick (Phase 1):** `firestore` over `auth` — first multi-module package (×4 specs), exercises `pipelineExecute` + NewArch-AD-14a routing composite Proxy; defers largest single-spec (`auth` ×59) to Phase 4. **Arbiter gate:** @@ -280,7 +282,8 @@ Skip steps 1–2 when spec shape is known (most Tier D packages). |------|------|----------------------|---------------|---------------|------------------|-------------------|------------------|-------| | Design review | DR | n/a | n/a | n/a | done | none | none | ✅ Adversarial review complete. | | Phase 0 `app` TurboModules | P0 | **closed** | **closed** | **closed** | done | `full` | `feat(app): migrate app modules to TurboModules incl general migration infra` | Committed 2026-06-30. | -| Phase 0.1 `app` compare:types | P0.1 | **closed** | **closed** | **open** | `commit` | `none` | `test(app): add app module type comparison config` | 25 deltas documented; `SDK_VERSION` typed `string`; compare:types green for `app`. | +| Phase 0.1 `app` compare:types | P0.1 | **closed** | **closed** | **closed** | done | `none` | `test(app): add app module type comparison config` | Committed 2026-06-30. 25 deltas documented; compare:types green for `app`. | +| Phase 1 `firestore` TurboModules | P1 | **closed** | **closed** | **closed** | done | `area-focused` | `feat(firestore)!: migrate firestore to TurboModules` | Committed 2026-06-30. 4 specs; area e2e 732 pass/7 pending iOS+Android; jest 285/285; compare:types ✓. | --- diff --git a/okf-bundle/new-architecture/turbomodule-implementation-workflow.md b/okf-bundle/new-architecture/turbomodule-implementation-workflow.md index 4430bcb8ec..16b1399c67 100644 --- a/okf-bundle/new-architecture/turbomodule-implementation-workflow.md +++ b/okf-bundle/new-architecture/turbomodule-implementation-workflow.md @@ -44,7 +44,7 @@ In addition to [change authoring gates](../testing/change-authoring-workflow.md# One TurboModule spec **per legacy native module** — do not consolidate the *specs* in the first pass (database ×5, firestore ×4); each legacy module keeps its own `NativeRNFBTurbo*` spec and shell. -**Commit granularity: one commit per package, not per spec.** Splitting a multi-module package across several commits adds little value and is often impractical — the specs share `codegenConfig`, generated artifacts, podspec/`build.gradle` guards, and JS wiring that only compile and pass e2e together. Convert the whole package (all its legacy modules → all its specs) in a single `implementation` → `independent-review` → `commit` loop and land it as **one** `feat(): migrate to TurboModules` commit. Per-spec commits are only warranted if a single legacy module is genuinely independently shippable and reviewable, which is rare. Multiple specs ≠ multiple commits. +**Commit granularity: one commit per package, not per spec.** Splitting a multi-module package across several commits adds little value and is often impractical — the specs share `codegenConfig`, generated artifacts, podspec/`build.gradle` guards, and JS wiring that only compile and pass e2e together. Convert the whole package (all its legacy modules → all its specs) in a single `implementation` → `independent-review` → `commit` loop and land it as **one** `feat()!: migrate to TurboModules` commit (breaking: New Architecture required). Per-spec commits are only warranted if a single legacy module is genuinely independently shippable and reviewable, which is rare. Multiple specs ≠ multiple commits. ### Multi-spec packages (`app` precedent) @@ -164,9 +164,11 @@ Per package (or per phase batch), same commit when user-facing: ## TurboModule `commit` ```text -feat(): migrate to TurboModules +feat()!: migrate to TurboModules ``` +Breaking change (`!`): TurboModule migration requires New Architecture; legacy bridge is removed per package. + **Never stage:** `tests/harness.overrides.js`, any `.only`, temporary sub-suite edits in `tests/app.js`. ## Gotchas diff --git a/packages/firestore/RNFBFirestore.podspec b/packages/firestore/RNFBFirestore.podspec index a153aa395d..cadda65679 100644 --- a/packages/firestore/RNFBFirestore.podspec +++ b/packages/firestore/RNFBFirestore.podspec @@ -28,15 +28,28 @@ Pod::Spec.new do |s| s.macos.deployment_target = firebase_macos_target s.tvos.deployment_target = firebase_tvos_target s.swift_version = '5.10' - s.source_files = 'ios/**/*.{h,m,mm,swift}' + s.source_files = 'ios/**/*.{h,m,mm,cpp,swift}' + s.private_header_files = [ + 'ios/RNFBFirestore/RNFBFirestoreModule.h', + 'ios/RNFBFirestore/RNFBFirestoreCollectionModule.h', + 'ios/RNFBFirestore/RNFBFirestoreDocumentModule.h', + 'ios/RNFBFirestore/RNFBFirestoreTransactionModule.h', + 'ios/generated/**/*.h', + ] + s.exclude_files = 'ios/generated/RCTThirdPartyComponentsProvider.*', 'ios/generated/RCTAppDependencyProvider.*', 'ios/generated/RCTModuleProviders.*', 'ios/generated/RCTModulesConformingToProtocolsProvider.*', 'ios/generated/RCTUnstableModulesRequiringMainQueueSetupProvider.*' + + s.pod_target_xcconfig = { + "HEADER_SEARCH_PATHS" => "\"$(PODS_TARGET_SRCROOT)/ios/generated/RNFBFirestoreTurboModules\" \"$(PODS_TARGET_SRCROOT)/ios/generated\"", + } s.dependency 'RNFBApp' - # React Native dependencies - if defined?(install_modules_dependencies()) != nil - install_modules_dependencies(s); - else - s.dependency "React-Core" + install_modules_dependencies(s); + + # Fail fast for old architecture users, but safely in case the variable goes away + # completely in future react-native versions + if defined?(ENV["RCT_NEW_ARCH_ENABLED"]) != nil && (ENV["RCT_NEW_ARCH_ENABLED"] == '0') + raise "#{s.name} requires New Architecture. Enable New Architecture to use this module" end if defined?($FirebaseSDKVersion) diff --git a/packages/firestore/__tests__/nativeModuleContract.test.ts b/packages/firestore/__tests__/nativeModuleContract.test.ts new file mode 100644 index 0000000000..c302cb7d47 --- /dev/null +++ b/packages/firestore/__tests__/nativeModuleContract.test.ts @@ -0,0 +1,146 @@ +import { describe, expect, it, jest } from '@jest/globals'; +import { TurboModuleRegistry } from 'react-native'; +import type { ModuleConfig } from '@react-native-firebase/app/dist/module/internal'; +import FirebaseModule from '@react-native-firebase/app/dist/module/internal/FirebaseModule'; +import { getNativeModule } from '@react-native-firebase/app/dist/module/internal/registry/nativeModule'; +import type { WrappedNativeModule } from '@react-native-firebase/app/dist/module/internal/NativeModules'; + +const MAIN_METHODS = [ + 'setLogLevel', + 'loadBundle', + 'clearPersistence', + 'waitForPendingWrites', + 'disableNetwork', + 'enableNetwork', + 'useEmulator', + 'settings', + 'terminate', + 'persistenceCacheIndexManager', + 'addSnapshotsInSync', + 'removeSnapshotsInSync', +] as const; + +const COLLECTION_METHODS = [ + 'namedQueryOnSnapshot', + 'collectionOnSnapshot', + 'collectionOffSnapshot', + 'namedQueryGet', + 'collectionCount', + 'aggregateQuery', + 'pipelineExecute', + 'collectionGet', +] as const; + +const DOCUMENT_METHODS = [ + 'documentOnSnapshot', + 'documentOffSnapshot', + 'documentGet', + 'documentDelete', + 'documentSet', + 'documentUpdate', + 'documentBatch', +] as const; + +const TRANSACTION_METHODS = [ + 'transactionBegin', + 'transactionGetDocument', + 'transactionDispose', + 'transactionApplyBuffer', +] as const; + +const ALL_SPEC_METHODS = [ + ...MAIN_METHODS, + ...COLLECTION_METHODS, + ...DOCUMENT_METHODS, + ...TRANSACTION_METHODS, +]; + +function createTurboModuleFixture( + methods: Record, + constants: Record = {}, +): Record { + const proto = Object.create(Object.prototype, { + getConstants: { + value: () => constants, + enumerable: true, + }, + }); + + for (const [name, fn] of Object.entries(methods)) { + Object.defineProperty(proto, name, { + value: fn, + enumerable: true, + configurable: true, + }); + } + + return Object.create(proto); +} + +describe('TurboModule wrapper contract (NewArch-AD-17.1)', function () { + it('asserts merged Firestore spec method names are unique (NewArch-AD-11)', function () { + expect(new Set(ALL_SPEC_METHODS).size).toBe(ALL_SPEC_METHODS.length); + expect(ALL_SPEC_METHODS).toHaveLength(31); + }); + + it('routes methods through a 4-host merge composite Proxy (NewArch-AD-14a)', function () { + const mainMethod = jest.fn(() => 'main'); + const collectionMethod = jest.fn(() => 'collection'); + const documentMethod = jest.fn(() => 'document'); + const transactionMethod = jest.fn(() => 'transaction'); + + const hostMain = createTurboModuleFixture({ setLogLevel: mainMethod }); + const hostCollection = createTurboModuleFixture({ collectionGet: collectionMethod }); + const hostDocument = createTurboModuleFixture({ documentGet: documentMethod }); + const hostTransaction = createTurboModuleFixture({ transactionBegin: transactionMethod }); + + jest + .mocked(TurboModuleRegistry.get) + .mockReturnValueOnce(hostMain) + .mockReturnValueOnce(hostCollection) + .mockReturnValueOnce(hostDocument) + .mockReturnValueOnce(hostTransaction); + + const config: ModuleConfig = { + namespace: 'firestoreContract', + nativeModuleName: [ + 'NativeRNFBTurboFirestore', + 'NativeRNFBTurboFirestoreCollection', + 'NativeRNFBTurboFirestoreDocument', + 'NativeRNFBTurboFirestoreTransaction', + ], + nativeEvents: false, + hasMultiAppSupport: true, + hasCustomUrlOrRegionSupport: true, + turboModule: true, + }; + + class MergeModule extends FirebaseModule { + constructor() { + super({ name: '[DEFAULT]' } as any, config); + } + } + + const wrapped = getNativeModule(new MergeModule()) as WrappedNativeModule & { + setLogLevel: () => string; + collectionGet: () => string; + documentGet: () => string; + transactionBegin: () => string; + }; + + expect(wrapped.setLogLevel()).toBe('main'); + expect(wrapped.collectionGet()).toBe('collection'); + expect(wrapped.documentGet()).toBe('document'); + expect(wrapped.transactionBegin()).toBe('transaction'); + expect(mainMethod).toHaveBeenCalledTimes(1); + expect(collectionMethod).toHaveBeenCalledTimes(1); + expect(documentMethod).toHaveBeenCalledTimes(1); + expect(transactionMethod).toHaveBeenCalledTimes(1); + expect(Object.keys(wrapped).sort()).toEqual([ + 'collectionGet', + 'documentGet', + 'setLogLevel', + 'transactionBegin', + ]); + }); +}); diff --git a/packages/firestore/android/build.gradle b/packages/firestore/android/build.gradle index 2704ef66c2..7a1ca3252f 100644 --- a/packages/firestore/android/build.gradle +++ b/packages/firestore/android/build.gradle @@ -79,6 +79,7 @@ android { sourceSets { main { java.srcDirs = ['src/main/java', 'src/reactnative/java'] + java.excludes = ['**/generated/jni/**'] } } } @@ -98,3 +99,21 @@ ReactNative.shared.applyPackageVersion() ReactNative.shared.applyDefaultExcludes() ReactNative.module.applyAndroidVersions() ReactNative.module.applyReactNativeDependency("api") + +def isNewArchitectureDisabled() { + return project.hasProperty("newArchEnabled") && project.newArchEnabled != "true" +} + +if (isNewArchitectureDisabled()) { + def ANSI_RED = "\u001B[31m"; + def ANSI_RESET = "\u001B[0m"; + + println("\n\n\n") + println(ANSI_RED + "**************************************************************************************************************") + println("\n\n\n") + println("New Architecture support is required for @react-native-firebase/firestore") + println("\n\n\n") + println("**************************************************************************************************************" + ANSI_RESET) + println("\n\n\n") + System.exit(1) +} diff --git a/packages/firestore/android/src/reactnative/java/io/invertase/firebase/firestore/FirestoreTurboModuleSupport.java b/packages/firestore/android/src/reactnative/java/io/invertase/firebase/firestore/FirestoreTurboModuleSupport.java new file mode 100644 index 0000000000..3e778c9a03 --- /dev/null +++ b/packages/firestore/android/src/reactnative/java/io/invertase/firebase/firestore/FirestoreTurboModuleSupport.java @@ -0,0 +1,56 @@ +package io.invertase.firebase.firestore; + +/* + * Copyright (c) 2016-present Invertase Limited & Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this library except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import androidx.annotation.CallSuper; +import io.invertase.firebase.common.TaskExecutorService; +import java.util.concurrent.ExecutorService; + +/** + * Shared executor helpers for Firestore TurboModule shells (replaces ReactNativeFirebaseModule + * inheritance when extending generated *Spec classes). + */ +final class FirestoreTurboModuleSupport { + private final TaskExecutorService executorService; + + FirestoreTurboModuleSupport(String moduleName) { + executorService = new TaskExecutorService(moduleName); + } + + ExecutorService getExecutor() { + return executorService.getExecutor(); + } + + ExecutorService getTransactionalExecutor() { + return executorService.getTransactionalExecutor(); + } + + ExecutorService getTransactionalExecutor(String identifier) { + return executorService.getTransactionalExecutor(identifier); + } + + void removeEventListeningExecutor(String identifier) { + String executorName = executorService.getExecutorName(true, identifier); + executorService.removeExecutor(executorName); + } + + @CallSuper + void invalidate() { + executorService.shutdown(); + } +} diff --git a/packages/firestore/android/src/reactnative/java/io/invertase/firebase/firestore/ReactNativeFirebaseFirestoreModule.java b/packages/firestore/android/src/reactnative/java/io/invertase/firebase/firestore/NativeRNFBTurboFirestore.java similarity index 82% rename from packages/firestore/android/src/reactnative/java/io/invertase/firebase/firestore/ReactNativeFirebaseFirestoreModule.java rename to packages/firestore/android/src/reactnative/java/io/invertase/firebase/firestore/NativeRNFBTurboFirestore.java index 1be4991e46..785e0cac5d 100644 --- a/packages/firestore/android/src/reactnative/java/io/invertase/firebase/firestore/ReactNativeFirebaseFirestoreModule.java +++ b/packages/firestore/android/src/reactnative/java/io/invertase/firebase/firestore/NativeRNFBTurboFirestore.java @@ -22,27 +22,26 @@ import static io.invertase.firebase.firestore.UniversalFirebaseFirestoreCommon.createFirestoreKey; import static io.invertase.firebase.firestore.UniversalFirebaseFirestoreCommon.getFirestoreForApp; +import com.facebook.fbreact.specs.NativeRNFBTurboFirestoreSpec; import com.facebook.react.bridge.Arguments; import com.facebook.react.bridge.Promise; import com.facebook.react.bridge.ReactApplicationContext; -import com.facebook.react.bridge.ReactMethod; import com.facebook.react.bridge.ReadableMap; import com.facebook.react.bridge.WritableMap; import com.google.firebase.firestore.FirebaseFirestore; import com.google.firebase.firestore.LoadBundleTaskProgress; import com.google.firebase.firestore.PersistentCacheIndexManager; -import io.invertase.firebase.common.ReactNativeFirebaseModule; -public class ReactNativeFirebaseFirestoreModule extends ReactNativeFirebaseModule { +public class NativeRNFBTurboFirestore extends NativeRNFBTurboFirestoreSpec { private static final String SERVICE_NAME = "Firestore"; private final UniversalFirebaseFirestoreModule module; - ReactNativeFirebaseFirestoreModule(ReactApplicationContext reactContext) { - super(reactContext, SERVICE_NAME); + public NativeRNFBTurboFirestore(ReactApplicationContext reactContext) { + super(reactContext); module = new UniversalFirebaseFirestoreModule(reactContext, SERVICE_NAME); } - @ReactMethod + @Override public void setLogLevel(String logLevel) { if ("debug".equals(logLevel) || "error".equals(logLevel)) { FirebaseFirestore.setLoggingEnabled(true); @@ -51,7 +50,7 @@ public void setLogLevel(String logLevel) { } } - @ReactMethod + @Override public void loadBundle(String appName, String databaseId, String bundle, Promise promise) { module .loadBundle(appName, databaseId, bundle) @@ -66,7 +65,7 @@ public void loadBundle(String appName, String databaseId, String bundle, Promise }); } - @ReactMethod + @Override public void clearPersistence(String appName, String databaseId, Promise promise) { module .clearPersistence(appName, databaseId) @@ -80,7 +79,7 @@ public void clearPersistence(String appName, String databaseId, Promise promise) }); } - @ReactMethod + @Override public void waitForPendingWrites(String appName, String databaseId, Promise promise) { module .waitForPendingWrites(appName, databaseId) @@ -94,7 +93,7 @@ public void waitForPendingWrites(String appName, String databaseId, Promise prom }); } - @ReactMethod + @Override public void disableNetwork(String appName, String databaseId, Promise promise) { module .disableNetwork(appName, databaseId) @@ -108,7 +107,7 @@ public void disableNetwork(String appName, String databaseId, Promise promise) { }); } - @ReactMethod + @Override public void enableNetwork(String appName, String databaseId, Promise promise) { module .enableNetwork(appName, databaseId) @@ -122,22 +121,12 @@ public void enableNetwork(String appName, String databaseId, Promise promise) { }); } - @ReactMethod - public void useEmulator( - String appName, String databaseId, String host, int port, Promise promise) { - module - .useEmulator(appName, databaseId, host, port) - .addOnCompleteListener( - task -> { - if (task.isSuccessful()) { - promise.resolve(null); - } else { - rejectPromiseFirestoreException(promise, task.getException()); - } - }); + @Override + public void useEmulator(String appName, String databaseId, String host, double port) { + module.useEmulator(appName, databaseId, host, (int) port); } - @ReactMethod + @Override public void settings(String appName, String databaseId, ReadableMap settings, Promise promise) { String firestoreKey = createFirestoreKey(appName, databaseId); module @@ -152,7 +141,7 @@ public void settings(String appName, String databaseId, ReadableMap settings, Pr }); } - @ReactMethod + @Override public void terminate(String appName, String databaseId, Promise promise) { module .terminate(appName, databaseId) @@ -166,13 +155,14 @@ public void terminate(String appName, String databaseId, Promise promise) { }); } - @ReactMethod + @Override public void persistenceCacheIndexManager( - String appName, String databaseId, int requestType, Promise promise) { + String appName, String databaseId, double requestType, Promise promise) { + int mode = (int) requestType; PersistentCacheIndexManager indexManager = getFirestoreForApp(appName, databaseId).getPersistentCacheIndexManager(); if (indexManager != null) { - switch (requestType) { + switch (mode) { case 0: indexManager.enableIndexAutoCreation(); break; @@ -193,18 +183,14 @@ public void persistenceCacheIndexManager( promise.resolve(null); } - @ReactMethod - public void addSnapshotsInSync( - String appName, String databaseId, int listenerId, Promise promise) { - module.addSnapshotsInSync(appName, databaseId, listenerId); - promise.resolve(null); + @Override + public void addSnapshotsInSync(String appName, String databaseId, double listenerId) { + module.addSnapshotsInSync(appName, databaseId, (int) listenerId); } - @ReactMethod - public void removeSnapshotsInSync( - String appName, String databaseId, int listenerId, Promise promise) { - module.removeSnapshotsInSync(appName, databaseId, listenerId); - promise.resolve(null); + @Override + public void removeSnapshotsInSync(String appName, String databaseId, double listenerId) { + module.removeSnapshotsInSync(appName, databaseId, (int) listenerId); } private WritableMap taskProgressToWritableMap(LoadBundleTaskProgress progress) { diff --git a/packages/firestore/android/src/reactnative/java/io/invertase/firebase/firestore/ReactNativeFirebaseFirestoreCollectionModule.java b/packages/firestore/android/src/reactnative/java/io/invertase/firebase/firestore/NativeRNFBTurboFirestoreCollection.java similarity index 91% rename from packages/firestore/android/src/reactnative/java/io/invertase/firebase/firestore/ReactNativeFirebaseFirestoreCollectionModule.java rename to packages/firestore/android/src/reactnative/java/io/invertase/firebase/firestore/NativeRNFBTurboFirestoreCollection.java index 54a8c3c562..88312ce860 100644 --- a/packages/firestore/android/src/reactnative/java/io/invertase/firebase/firestore/ReactNativeFirebaseFirestoreCollectionModule.java +++ b/packages/firestore/android/src/reactnative/java/io/invertase/firebase/firestore/NativeRNFBTurboFirestoreCollection.java @@ -19,6 +19,7 @@ import static com.google.firebase.firestore.AggregateField.average; import static com.google.firebase.firestore.AggregateField.sum; +import static io.invertase.firebase.common.ReactNativeFirebaseModule.rejectPromiseWithCodeAndMessage; import static io.invertase.firebase.firestore.ReactNativeFirebaseFirestoreCommon.rejectPromiseFirestoreException; import static io.invertase.firebase.firestore.ReactNativeFirebaseFirestoreSerialize.snapshotToWritableMap; import static io.invertase.firebase.firestore.UniversalFirebaseFirestoreCommon.getFirestoreForApp; @@ -29,16 +30,17 @@ import com.google.android.gms.tasks.Tasks; import com.google.firebase.firestore.*; import io.invertase.firebase.common.ReactNativeFirebaseEventEmitter; -import io.invertase.firebase.common.ReactNativeFirebaseModule; +import com.facebook.fbreact.specs.NativeRNFBTurboFirestoreCollectionSpec; import java.util.ArrayList; -public class ReactNativeFirebaseFirestoreCollectionModule extends ReactNativeFirebaseModule { +public class NativeRNFBTurboFirestoreCollection extends NativeRNFBTurboFirestoreCollectionSpec { + private final FirestoreTurboModuleSupport turboSupport = new FirestoreTurboModuleSupport("RNFBCollection"); private static final String SERVICE_NAME = "FirestoreCollection"; private static SparseArray collectionSnapshotListeners = new SparseArray<>(); - ReactNativeFirebaseFirestoreCollectionModule(ReactApplicationContext reactContext) { - super(reactContext, SERVICE_NAME); + public NativeRNFBTurboFirestoreCollection(ReactApplicationContext reactContext) { + super(reactContext); } @Override @@ -50,10 +52,10 @@ public void invalidate() { } collectionSnapshotListeners.clear(); - super.invalidate(); + turboSupport.invalidate(); } - @ReactMethod + @Override public void namedQueryOnSnapshot( String appName, String databaseId, @@ -62,9 +64,9 @@ public void namedQueryOnSnapshot( ReadableArray filters, ReadableArray orders, ReadableMap options, - int listenerId, + double listenerId, ReadableMap listenerOptions) { - if (collectionSnapshotListeners.get(listenerId) != null) { + if (collectionSnapshotListeners.get((int) listenerId) != null) { return; } @@ -90,7 +92,7 @@ public void namedQueryOnSnapshot( }); } - @ReactMethod + @Override public void collectionOnSnapshot( String appName, String databaseId, @@ -99,9 +101,9 @@ public void collectionOnSnapshot( ReadableArray filters, ReadableArray orders, ReadableMap options, - int listenerId, + double listenerId, ReadableMap listenerOptions) { - if (collectionSnapshotListeners.get(listenerId) != null) { + if (collectionSnapshotListeners.get((int) listenerId) != null) { return; } @@ -118,17 +120,17 @@ public void collectionOnSnapshot( handleQueryOnSnapshot(firestoreQuery, appName, databaseId, listenerId, listenerOptions); } - @ReactMethod - public void collectionOffSnapshot(String appName, String databaseId, int listenerId) { - ListenerRegistration listenerRegistration = collectionSnapshotListeners.get(listenerId); + @Override + public void collectionOffSnapshot(String appName, String databaseId, double listenerId) { + ListenerRegistration listenerRegistration = collectionSnapshotListeners.get((int) listenerId); if (listenerRegistration != null) { listenerRegistration.remove(); - collectionSnapshotListeners.remove(listenerId); - removeEventListeningExecutor(Integer.toString(listenerId)); + collectionSnapshotListeners.remove((int) listenerId); + turboSupport.removeEventListeningExecutor(Integer.toString((int) listenerId)); } } - @ReactMethod + @Override public void namedQueryGet( String appName, String databaseId, @@ -160,7 +162,7 @@ public void namedQueryGet( }); } - @ReactMethod + @Override public void collectionCount( String appName, String databaseId, @@ -196,7 +198,7 @@ public void collectionCount( }); } - @ReactMethod + @Override public void aggregateQuery( String appName, String databaseId, @@ -304,7 +306,7 @@ public void aggregateQuery( }); } - @ReactMethod + @Override public void pipelineExecute( String appName, String databaseId, @@ -317,7 +319,7 @@ public void pipelineExecute( pipelineExecutor.execute(pipeline, options, promise); } - @ReactMethod + @Override public void collectionGet( String appName, String databaseId, @@ -344,7 +346,7 @@ private void handleQueryOnSnapshot( ReactNativeFirebaseFirestoreQuery firestoreQuery, String appName, String databaseId, - int listenerId, + double listenerId, ReadableMap listenerOptions) { MetadataChanges metadataChanges; SnapshotListenOptions.Builder snapshotListenOptionsBuilder = @@ -370,10 +372,10 @@ private void handleQueryOnSnapshot( final EventListener listener = (querySnapshot, exception) -> { if (exception != null) { - ListenerRegistration listenerRegistration = collectionSnapshotListeners.get(listenerId); + ListenerRegistration listenerRegistration = collectionSnapshotListeners.get((int) listenerId); if (listenerRegistration != null) { listenerRegistration.remove(); - collectionSnapshotListeners.remove(listenerId); + collectionSnapshotListeners.remove((int) listenerId); } sendOnSnapshotError(appName, databaseId, listenerId, exception); } else { @@ -384,14 +386,14 @@ private void handleQueryOnSnapshot( ListenerRegistration listenerRegistration = firestoreQuery.query.addSnapshotListener(snapshotListenOptionsBuilder.build(), listener); - collectionSnapshotListeners.put(listenerId, listenerRegistration); + collectionSnapshotListeners.put((int) listenerId, listenerRegistration); } private void handleQueryGet( ReactNativeFirebaseFirestoreQuery firestoreQuery, Source source, Promise promise) { try { firestoreQuery - .get(getExecutor(), source) + .get(turboSupport.getExecutor(), source) .addOnCompleteListener( task -> { if (task.isSuccessful()) { @@ -408,12 +410,12 @@ private void handleQueryGet( private void sendOnSnapshotEvent( String appName, String databaseId, - int listenerId, + double listenerId, QuerySnapshot querySnapshot, MetadataChanges metadataChanges) { try { Tasks.call( - getTransactionalExecutor(Integer.toString(listenerId)), + turboSupport.getTransactionalExecutor(Integer.toString((int) listenerId)), () -> snapshotToWritableMap( appName, databaseId, "onSnapshot", querySnapshot, metadataChanges)) @@ -432,7 +434,7 @@ private void sendOnSnapshotEvent( body, appName, databaseId, - listenerId)); + (int) listenerId)); } else { sendOnSnapshotError(appName, databaseId, listenerId, task.getException()); } @@ -444,7 +446,7 @@ private void sendOnSnapshotEvent( } private void sendOnSnapshotError( - String appName, String databaseId, int listenerId, Exception exception) { + String appName, String databaseId, double listenerId, Exception exception) { WritableMap body = Arguments.createMap(); WritableMap error = Arguments.createMap(); @@ -468,7 +470,7 @@ private void sendOnSnapshotError( body, appName, databaseId, - listenerId)); + (int) listenerId)); } private Source getSource(ReadableMap getOptions) { diff --git a/packages/firestore/android/src/reactnative/java/io/invertase/firebase/firestore/ReactNativeFirebaseFirestoreDocumentModule.java b/packages/firestore/android/src/reactnative/java/io/invertase/firebase/firestore/NativeRNFBTurboFirestoreDocument.java similarity index 86% rename from packages/firestore/android/src/reactnative/java/io/invertase/firebase/firestore/ReactNativeFirebaseFirestoreDocumentModule.java rename to packages/firestore/android/src/reactnative/java/io/invertase/firebase/firestore/NativeRNFBTurboFirestoreDocument.java index 81473d98e0..40b1c2a6e4 100644 --- a/packages/firestore/android/src/reactnative/java/io/invertase/firebase/firestore/ReactNativeFirebaseFirestoreDocumentModule.java +++ b/packages/firestore/android/src/reactnative/java/io/invertase/firebase/firestore/NativeRNFBTurboFirestoreDocument.java @@ -28,18 +28,19 @@ import com.google.android.gms.tasks.Tasks; import com.google.firebase.firestore.*; import io.invertase.firebase.common.ReactNativeFirebaseEventEmitter; -import io.invertase.firebase.common.ReactNativeFirebaseModule; +import com.facebook.fbreact.specs.NativeRNFBTurboFirestoreDocumentSpec; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Objects; -public class ReactNativeFirebaseFirestoreDocumentModule extends ReactNativeFirebaseModule { +public class NativeRNFBTurboFirestoreDocument extends NativeRNFBTurboFirestoreDocumentSpec { + private final FirestoreTurboModuleSupport turboSupport = new FirestoreTurboModuleSupport("RNFBDocument"); private static final String SERVICE_NAME = "FirestoreDocument"; private static SparseArray documentSnapshotListeners = new SparseArray<>(); - ReactNativeFirebaseFirestoreDocumentModule(ReactApplicationContext reactContext) { - super(reactContext, SERVICE_NAME); + public NativeRNFBTurboFirestoreDocument(ReactApplicationContext reactContext) { + super(reactContext); } @Override @@ -51,13 +52,13 @@ public void invalidate() { } documentSnapshotListeners.clear(); - super.invalidate(); + turboSupport.invalidate(); } - @ReactMethod + @Override public void documentOnSnapshot( - String appName, String databaseId, String path, int listenerId, ReadableMap listenerOptions) { - if (documentSnapshotListeners.get(listenerId) != null) { + String appName, String databaseId, String path, double listenerId, ReadableMap listenerOptions) { + if (documentSnapshotListeners.get((int) listenerId) != null) { return; } @@ -67,10 +68,10 @@ public void documentOnSnapshot( final EventListener listener = (documentSnapshot, exception) -> { if (exception != null) { - ListenerRegistration listenerRegistration = documentSnapshotListeners.get(listenerId); + ListenerRegistration listenerRegistration = documentSnapshotListeners.get((int) listenerId); if (listenerRegistration != null) { listenerRegistration.remove(); - documentSnapshotListeners.remove(listenerId); + documentSnapshotListeners.remove((int) listenerId); } sendOnSnapshotError(appName, databaseId, listenerId, exception); } else { @@ -100,19 +101,19 @@ public void documentOnSnapshot( ListenerRegistration listenerRegistration = documentReference.addSnapshotListener(snapshotListenOptionsBuilder.build(), listener); - documentSnapshotListeners.put(listenerId, listenerRegistration); + documentSnapshotListeners.put((int) listenerId, listenerRegistration); } - @ReactMethod - public void documentOffSnapshot(String appName, String databaseId, int listenerId) { - ListenerRegistration listenerRegistration = documentSnapshotListeners.get(listenerId); + @Override + public void documentOffSnapshot(String appName, String databaseId, double listenerId) { + ListenerRegistration listenerRegistration = documentSnapshotListeners.get((int) listenerId); if (listenerRegistration != null) { listenerRegistration.remove(); - documentSnapshotListeners.remove(listenerId); + documentSnapshotListeners.remove((int) listenerId); } } - @ReactMethod + @Override public void documentGet( String appName, String databaseId, String path, ReadableMap getOptions, Promise promise) { FirebaseFirestore firebaseFirestore = getFirestoreForApp(appName, databaseId); @@ -134,7 +135,7 @@ public void documentGet( } Tasks.call( - getExecutor(), + turboSupport.getExecutor(), () -> { DocumentSnapshot documentSnapshot = Tasks.await(documentReference.get(source)); return snapshotToWritableMap(appName, databaseId, documentSnapshot); @@ -149,11 +150,11 @@ public void documentGet( }); } - @ReactMethod + @Override public void documentDelete(String appName, String databaseId, String path, Promise promise) { FirebaseFirestore firebaseFirestore = getFirestoreForApp(appName, databaseId); DocumentReference documentReference = getDocumentForFirestore(firebaseFirestore, path); - Tasks.call(getTransactionalExecutor(), documentReference::delete) + Tasks.call(turboSupport.getTransactionalExecutor(), documentReference::delete) .addOnCompleteListener( task -> { if (task.isSuccessful()) { @@ -164,7 +165,7 @@ public void documentDelete(String appName, String databaseId, String path, Promi }); } - @ReactMethod + @Override public void documentSet( String appName, String databaseId, @@ -175,9 +176,9 @@ public void documentSet( FirebaseFirestore firebaseFirestore = getFirestoreForApp(appName, databaseId); DocumentReference documentReference = getDocumentForFirestore(firebaseFirestore, path); - Tasks.call(getTransactionalExecutor(), () -> parseReadableMap(firebaseFirestore, data)) + Tasks.call(turboSupport.getTransactionalExecutor(), () -> parseReadableMap(firebaseFirestore, data)) .continueWithTask( - getTransactionalExecutor(), + turboSupport.getTransactionalExecutor(), task -> { Task setTask; Map settableData = Objects.requireNonNull(task.getResult()); @@ -209,15 +210,15 @@ public void documentSet( }); } - @ReactMethod + @Override public void documentUpdate( String appName, String databaseId, String path, ReadableMap data, Promise promise) { FirebaseFirestore firebaseFirestore = getFirestoreForApp(appName, databaseId); DocumentReference documentReference = getDocumentForFirestore(firebaseFirestore, path); - Tasks.call(getTransactionalExecutor(), () -> parseReadableMap(firebaseFirestore, data)) + Tasks.call(turboSupport.getTransactionalExecutor(), () -> parseReadableMap(firebaseFirestore, data)) .continueWithTask( - getTransactionalExecutor(), + turboSupport.getTransactionalExecutor(), task -> documentReference.update(Objects.requireNonNull(task.getResult()))) .addOnCompleteListener( task -> { @@ -229,14 +230,14 @@ public void documentUpdate( }); } - @ReactMethod + @Override public void documentBatch( String appName, String databaseId, ReadableArray writes, Promise promise) { FirebaseFirestore firebaseFirestore = getFirestoreForApp(appName, databaseId); - Tasks.call(getTransactionalExecutor(), () -> parseDocumentBatches(firebaseFirestore, writes)) + Tasks.call(turboSupport.getTransactionalExecutor(), () -> parseDocumentBatches(firebaseFirestore, writes)) .continueWithTask( - getTransactionalExecutor(), + turboSupport.getTransactionalExecutor(), task -> { WriteBatch batch = firebaseFirestore.batch(); List writesArray = task.getResult(); @@ -299,9 +300,9 @@ public void documentBatch( } private void sendOnSnapshotEvent( - String appName, String databaseId, int listenerId, DocumentSnapshot documentSnapshot) { + String appName, String databaseId, double listenerId, DocumentSnapshot documentSnapshot) { try { - Tasks.call(getExecutor(), () -> snapshotToWritableMap(appName, databaseId, documentSnapshot)) + Tasks.call(turboSupport.getExecutor(), () -> snapshotToWritableMap(appName, databaseId, documentSnapshot)) .addOnCompleteListener( task -> { if (task.isSuccessful()) { @@ -317,7 +318,7 @@ private void sendOnSnapshotEvent( body, appName, databaseId, - listenerId)); + (int) listenerId)); } else { sendOnSnapshotError(appName, databaseId, listenerId, task.getException()); } @@ -329,7 +330,7 @@ private void sendOnSnapshotEvent( } private void sendOnSnapshotError( - String appName, String databaseId, int listenerId, Exception exception) { + String appName, String databaseId, double listenerId, Exception exception) { WritableMap body = Arguments.createMap(); WritableMap error = Arguments.createMap(); @@ -353,6 +354,6 @@ private void sendOnSnapshotError( body, appName, databaseId, - listenerId)); + (int) listenerId)); } } diff --git a/packages/firestore/android/src/reactnative/java/io/invertase/firebase/firestore/ReactNativeFirebaseFirestoreTransactionModule.java b/packages/firestore/android/src/reactnative/java/io/invertase/firebase/firestore/NativeRNFBTurboFirestoreTransaction.java similarity index 88% rename from packages/firestore/android/src/reactnative/java/io/invertase/firebase/firestore/ReactNativeFirebaseFirestoreTransactionModule.java rename to packages/firestore/android/src/reactnative/java/io/invertase/firebase/firestore/NativeRNFBTurboFirestoreTransaction.java index 23fe331d5d..d71f09993d 100644 --- a/packages/firestore/android/src/reactnative/java/io/invertase/firebase/firestore/ReactNativeFirebaseFirestoreTransactionModule.java +++ b/packages/firestore/android/src/reactnative/java/io/invertase/firebase/firestore/NativeRNFBTurboFirestoreTransaction.java @@ -18,6 +18,8 @@ */ import static io.invertase.firebase.common.RCTConvertFirebase.toArrayList; +import static io.invertase.firebase.common.ReactNativeFirebaseModule.rejectPromiseWithCodeAndMessage; +import static io.invertase.firebase.common.ReactNativeFirebaseModule.rejectPromiseWithExceptionMap; import static io.invertase.firebase.firestore.ReactNativeFirebaseFirestoreSerialize.parseReadableMap; import static io.invertase.firebase.firestore.ReactNativeFirebaseFirestoreSerialize.snapshotToWritableMap; import static io.invertase.firebase.firestore.UniversalFirebaseFirestoreCommon.getDocumentForFirestore; @@ -29,19 +31,20 @@ import com.google.android.gms.tasks.Tasks; import com.google.firebase.firestore.*; import io.invertase.firebase.common.ReactNativeFirebaseEventEmitter; -import io.invertase.firebase.common.ReactNativeFirebaseModule; +import com.facebook.fbreact.specs.NativeRNFBTurboFirestoreTransactionSpec; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Objects; -public class ReactNativeFirebaseFirestoreTransactionModule extends ReactNativeFirebaseModule { +public class NativeRNFBTurboFirestoreTransaction extends NativeRNFBTurboFirestoreTransactionSpec { + private final FirestoreTurboModuleSupport turboSupport = new FirestoreTurboModuleSupport("RNFBTransaction"); private static final String SERVICE_NAME = "FirestoreTransaction"; private SparseArray transactionHandlers = new SparseArray<>(); - ReactNativeFirebaseFirestoreTransactionModule(ReactApplicationContext reactContext) { - super(reactContext, SERVICE_NAME); + public NativeRNFBTurboFirestoreTransaction(ReactApplicationContext reactContext) { + super(reactContext); } @Override @@ -57,14 +60,14 @@ public void invalidate() { } transactionHandlers.clear(); - super.invalidate(); + turboSupport.invalidate(); } - @ReactMethod + @Override public void transactionGetDocument( - String appName, String databaseId, int transactionId, String path, Promise promise) { + String appName, String databaseId, double transactionId, String path, Promise promise) { ReactNativeFirebaseFirestoreTransactionHandler transactionHandler = - transactionHandlers.get(transactionId); + transactionHandlers.get((int) transactionId); if (transactionHandler == null) { rejectPromiseWithCodeAndMessage( @@ -79,7 +82,7 @@ public void transactionGetDocument( try { Tasks.call( - getTransactionalExecutor(), + turboSupport.getTransactionalExecutor(), () -> snapshotToWritableMap( appName, databaseId, transactionHandler.getDocument(documentReference))) @@ -96,32 +99,32 @@ public void transactionGetDocument( } } - @ReactMethod - public void transactionDispose(String appName, String databaseId, int transactionId) { + @Override + public void transactionDispose(String appName, String databaseId, double transactionId) { ReactNativeFirebaseFirestoreTransactionHandler transactionHandler = - transactionHandlers.get(transactionId); + transactionHandlers.get((int) transactionId); if (transactionHandler != null) { transactionHandler.abort(); - transactionHandlers.delete(transactionId); + transactionHandlers.delete((int) transactionId); } } - @ReactMethod + @Override public void transactionApplyBuffer( - String appName, String databaseId, int transactionId, ReadableArray commandBuffer) { - ReactNativeFirebaseFirestoreTransactionHandler handler = transactionHandlers.get(transactionId); + String appName, String databaseId, double transactionId, ReadableArray commandBuffer) { + ReactNativeFirebaseFirestoreTransactionHandler handler = transactionHandlers.get((int) transactionId); if (handler != null) { handler.signalBufferReceived(commandBuffer); } } - @ReactMethod - public void transactionBegin(String appName, String databaseId, int transactionId) { + @Override + public void transactionBegin(String appName, String databaseId, double transactionId) { ReactNativeFirebaseFirestoreTransactionHandler transactionHandler = - new ReactNativeFirebaseFirestoreTransactionHandler(appName, transactionId); - transactionHandlers.put(transactionId, transactionHandler); + new ReactNativeFirebaseFirestoreTransactionHandler(appName, (int) transactionId); + transactionHandlers.put((int) transactionId, transactionHandler); FirebaseFirestore firebaseFirestore = getFirestoreForApp(appName, databaseId); ReactNativeFirebaseEventEmitter emitter = ReactNativeFirebaseEventEmitter.getSharedInstance(); diff --git a/packages/firestore/android/src/reactnative/java/io/invertase/firebase/firestore/ReactNativeFirebaseFirestorePackage.java b/packages/firestore/android/src/reactnative/java/io/invertase/firebase/firestore/ReactNativeFirebaseFirestorePackage.java index 97202d8971..1427984899 100644 --- a/packages/firestore/android/src/reactnative/java/io/invertase/firebase/firestore/ReactNativeFirebaseFirestorePackage.java +++ b/packages/firestore/android/src/reactnative/java/io/invertase/firebase/firestore/ReactNativeFirebaseFirestorePackage.java @@ -30,10 +30,10 @@ public class ReactNativeFirebaseFirestorePackage implements ReactPackage { @Override public List createNativeModules(ReactApplicationContext reactContext) { List modules = new ArrayList<>(); - modules.add(new ReactNativeFirebaseFirestoreModule(reactContext)); - modules.add(new ReactNativeFirebaseFirestoreCollectionModule(reactContext)); - modules.add(new ReactNativeFirebaseFirestoreDocumentModule(reactContext)); - modules.add(new ReactNativeFirebaseFirestoreTransactionModule(reactContext)); + modules.add(new NativeRNFBTurboFirestore(reactContext)); + modules.add(new NativeRNFBTurboFirestoreCollection(reactContext)); + modules.add(new NativeRNFBTurboFirestoreDocument(reactContext)); + modules.add(new NativeRNFBTurboFirestoreTransaction(reactContext)); return modules; } diff --git a/packages/firestore/android/src/reactnative/java/io/invertase/firebase/firestore/generated/java/com/facebook/fbreact/specs/NativeRNFBTurboFirestoreCollectionSpec.java b/packages/firestore/android/src/reactnative/java/io/invertase/firebase/firestore/generated/java/com/facebook/fbreact/specs/NativeRNFBTurboFirestoreCollectionSpec.java new file mode 100644 index 0000000000..e1f106fdce --- /dev/null +++ b/packages/firestore/android/src/reactnative/java/io/invertase/firebase/firestore/generated/java/com/facebook/fbreact/specs/NativeRNFBTurboFirestoreCollectionSpec.java @@ -0,0 +1,69 @@ + +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleJavaSpec.js + * + * @nolint + */ + +package com.facebook.fbreact.specs; + +import com.facebook.proguard.annotations.DoNotStrip; +import com.facebook.react.bridge.Promise; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReactContextBaseJavaModule; +import com.facebook.react.bridge.ReactMethod; +import com.facebook.react.bridge.ReadableArray; +import com.facebook.react.bridge.ReadableMap; +import com.facebook.react.turbomodule.core.interfaces.TurboModule; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public abstract class NativeRNFBTurboFirestoreCollectionSpec extends ReactContextBaseJavaModule implements TurboModule { + public static final String NAME = "NativeRNFBTurboFirestoreCollection"; + + public NativeRNFBTurboFirestoreCollectionSpec(ReactApplicationContext reactContext) { + super(reactContext); + } + + @Override + public @Nonnull String getName() { + return NAME; + } + + @ReactMethod + @DoNotStrip + public abstract void namedQueryOnSnapshot(String appName, String databaseId, String queryName, String type, ReadableArray filters, ReadableArray orders, ReadableMap options, double listenerId, ReadableMap snapshotListenOptions); + + @ReactMethod + @DoNotStrip + public abstract void collectionOnSnapshot(String appName, String databaseId, String path, String type, ReadableArray filters, ReadableArray orders, ReadableMap options, double listenerId, ReadableMap snapshotListenOptions); + + @ReactMethod + @DoNotStrip + public abstract void collectionOffSnapshot(String appName, String databaseId, double listenerId); + + @ReactMethod + @DoNotStrip + public abstract void namedQueryGet(String appName, String databaseId, String queryName, String type, ReadableArray filters, ReadableArray orders, ReadableMap options, @Nullable ReadableMap getOptions, Promise promise); + + @ReactMethod + @DoNotStrip + public abstract void collectionGet(String appName, String databaseId, String path, String type, ReadableArray filters, ReadableArray orders, ReadableMap options, @Nullable ReadableMap getOptions, Promise promise); + + @ReactMethod + @DoNotStrip + public abstract void collectionCount(String appName, String databaseId, String path, String type, ReadableArray filters, ReadableArray orders, ReadableMap options, Promise promise); + + @ReactMethod + @DoNotStrip + public abstract void aggregateQuery(String appName, String databaseId, String path, String type, ReadableArray filters, ReadableArray orders, ReadableMap options, ReadableArray aggregateQueries, Promise promise); + + @ReactMethod + @DoNotStrip + public abstract void pipelineExecute(String appName, String databaseId, ReadableMap pipeline, @Nullable ReadableMap options, Promise promise); +} diff --git a/packages/firestore/android/src/reactnative/java/io/invertase/firebase/firestore/generated/java/com/facebook/fbreact/specs/NativeRNFBTurboFirestoreDocumentSpec.java b/packages/firestore/android/src/reactnative/java/io/invertase/firebase/firestore/generated/java/com/facebook/fbreact/specs/NativeRNFBTurboFirestoreDocumentSpec.java new file mode 100644 index 0000000000..9e500c02bf --- /dev/null +++ b/packages/firestore/android/src/reactnative/java/io/invertase/firebase/firestore/generated/java/com/facebook/fbreact/specs/NativeRNFBTurboFirestoreDocumentSpec.java @@ -0,0 +1,65 @@ + +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleJavaSpec.js + * + * @nolint + */ + +package com.facebook.fbreact.specs; + +import com.facebook.proguard.annotations.DoNotStrip; +import com.facebook.react.bridge.Promise; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReactContextBaseJavaModule; +import com.facebook.react.bridge.ReactMethod; +import com.facebook.react.bridge.ReadableArray; +import com.facebook.react.bridge.ReadableMap; +import com.facebook.react.turbomodule.core.interfaces.TurboModule; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public abstract class NativeRNFBTurboFirestoreDocumentSpec extends ReactContextBaseJavaModule implements TurboModule { + public static final String NAME = "NativeRNFBTurboFirestoreDocument"; + + public NativeRNFBTurboFirestoreDocumentSpec(ReactApplicationContext reactContext) { + super(reactContext); + } + + @Override + public @Nonnull String getName() { + return NAME; + } + + @ReactMethod + @DoNotStrip + public abstract void documentOnSnapshot(String appName, String databaseId, String path, double listenerId, ReadableMap snapshotListenOptions); + + @ReactMethod + @DoNotStrip + public abstract void documentOffSnapshot(String appName, String databaseId, double listenerId); + + @ReactMethod + @DoNotStrip + public abstract void documentGet(String appName, String databaseId, String path, @Nullable ReadableMap getOptions, Promise promise); + + @ReactMethod + @DoNotStrip + public abstract void documentDelete(String appName, String databaseId, String path, Promise promise); + + @ReactMethod + @DoNotStrip + public abstract void documentSet(String appName, String databaseId, String path, ReadableMap data, ReadableMap options, Promise promise); + + @ReactMethod + @DoNotStrip + public abstract void documentUpdate(String appName, String databaseId, String path, ReadableMap data, Promise promise); + + @ReactMethod + @DoNotStrip + public abstract void documentBatch(String appName, String databaseId, ReadableArray writes, Promise promise); +} diff --git a/packages/firestore/android/src/reactnative/java/io/invertase/firebase/firestore/generated/java/com/facebook/fbreact/specs/NativeRNFBTurboFirestoreSpec.java b/packages/firestore/android/src/reactnative/java/io/invertase/firebase/firestore/generated/java/com/facebook/fbreact/specs/NativeRNFBTurboFirestoreSpec.java new file mode 100644 index 0000000000..511165fca3 --- /dev/null +++ b/packages/firestore/android/src/reactnative/java/io/invertase/firebase/firestore/generated/java/com/facebook/fbreact/specs/NativeRNFBTurboFirestoreSpec.java @@ -0,0 +1,83 @@ + +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleJavaSpec.js + * + * @nolint + */ + +package com.facebook.fbreact.specs; + +import com.facebook.proguard.annotations.DoNotStrip; +import com.facebook.react.bridge.Promise; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReactContextBaseJavaModule; +import com.facebook.react.bridge.ReactMethod; +import com.facebook.react.bridge.ReadableMap; +import com.facebook.react.turbomodule.core.interfaces.TurboModule; +import javax.annotation.Nonnull; + +public abstract class NativeRNFBTurboFirestoreSpec extends ReactContextBaseJavaModule implements TurboModule { + public static final String NAME = "NativeRNFBTurboFirestore"; + + public NativeRNFBTurboFirestoreSpec(ReactApplicationContext reactContext) { + super(reactContext); + } + + @Override + public @Nonnull String getName() { + return NAME; + } + + @ReactMethod + @DoNotStrip + public abstract void setLogLevel(String logLevel); + + @ReactMethod + @DoNotStrip + public abstract void loadBundle(String appName, String databaseId, String bundle, Promise promise); + + @ReactMethod + @DoNotStrip + public abstract void clearPersistence(String appName, String databaseId, Promise promise); + + @ReactMethod + @DoNotStrip + public abstract void waitForPendingWrites(String appName, String databaseId, Promise promise); + + @ReactMethod + @DoNotStrip + public abstract void disableNetwork(String appName, String databaseId, Promise promise); + + @ReactMethod + @DoNotStrip + public abstract void enableNetwork(String appName, String databaseId, Promise promise); + + @ReactMethod + @DoNotStrip + public abstract void useEmulator(String appName, String databaseId, String host, double port); + + @ReactMethod + @DoNotStrip + public abstract void settings(String appName, String databaseId, ReadableMap settings, Promise promise); + + @ReactMethod + @DoNotStrip + public abstract void terminate(String appName, String databaseId, Promise promise); + + @ReactMethod + @DoNotStrip + public abstract void persistenceCacheIndexManager(String appName, String databaseId, double requestType, Promise promise); + + @ReactMethod + @DoNotStrip + public abstract void addSnapshotsInSync(String appName, String databaseId, double listenerId); + + @ReactMethod + @DoNotStrip + public abstract void removeSnapshotsInSync(String appName, String databaseId, double listenerId); +} diff --git a/packages/firestore/android/src/reactnative/java/io/invertase/firebase/firestore/generated/java/com/facebook/fbreact/specs/NativeRNFBTurboFirestoreTransactionSpec.java b/packages/firestore/android/src/reactnative/java/io/invertase/firebase/firestore/generated/java/com/facebook/fbreact/specs/NativeRNFBTurboFirestoreTransactionSpec.java new file mode 100644 index 0000000000..b10cbd061a --- /dev/null +++ b/packages/firestore/android/src/reactnative/java/io/invertase/firebase/firestore/generated/java/com/facebook/fbreact/specs/NativeRNFBTurboFirestoreTransactionSpec.java @@ -0,0 +1,51 @@ + +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleJavaSpec.js + * + * @nolint + */ + +package com.facebook.fbreact.specs; + +import com.facebook.proguard.annotations.DoNotStrip; +import com.facebook.react.bridge.Promise; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReactContextBaseJavaModule; +import com.facebook.react.bridge.ReactMethod; +import com.facebook.react.bridge.ReadableArray; +import com.facebook.react.turbomodule.core.interfaces.TurboModule; +import javax.annotation.Nonnull; + +public abstract class NativeRNFBTurboFirestoreTransactionSpec extends ReactContextBaseJavaModule implements TurboModule { + public static final String NAME = "NativeRNFBTurboFirestoreTransaction"; + + public NativeRNFBTurboFirestoreTransactionSpec(ReactApplicationContext reactContext) { + super(reactContext); + } + + @Override + public @Nonnull String getName() { + return NAME; + } + + @ReactMethod + @DoNotStrip + public abstract void transactionBegin(String appName, String databaseId, double transactionId); + + @ReactMethod + @DoNotStrip + public abstract void transactionGetDocument(String appName, String databaseId, double transactionId, String path, Promise promise); + + @ReactMethod + @DoNotStrip + public abstract void transactionDispose(String appName, String databaseId, double transactionId); + + @ReactMethod + @DoNotStrip + public abstract void transactionApplyBuffer(String appName, String databaseId, double transactionId, ReadableArray commandBuffer); +} diff --git a/packages/firestore/android/src/reactnative/java/io/invertase/firebase/firestore/generated/jni/CMakeLists.txt b/packages/firestore/android/src/reactnative/java/io/invertase/firebase/firestore/generated/jni/CMakeLists.txt new file mode 100644 index 0000000000..60992b1c48 --- /dev/null +++ b/packages/firestore/android/src/reactnative/java/io/invertase/firebase/firestore/generated/jni/CMakeLists.txt @@ -0,0 +1,36 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +cmake_minimum_required(VERSION 3.13) +set(CMAKE_VERBOSE_MAKEFILE on) + +file(GLOB react_codegen_SRCS CONFIGURE_DEPENDS *.cpp react/renderer/components/RNFBFirestoreTurboModules/*.cpp) + +add_library( + react_codegen_RNFBFirestoreTurboModules + OBJECT + ${react_codegen_SRCS} +) + +target_include_directories(react_codegen_RNFBFirestoreTurboModules PUBLIC . react/renderer/components/RNFBFirestoreTurboModules) + +target_link_libraries( + react_codegen_RNFBFirestoreTurboModules + fbjni + jsi + # We need to link different libraries based on whether we are building rncore or not, that's necessary + # because we want to break a circular dependency between react_codegen_rncore and reactnative + reactnative +) + +target_compile_options( + react_codegen_RNFBFirestoreTurboModules + PRIVATE + -DLOG_TAG=\"ReactNative\" + -fexceptions + -frtti + -std=c++20 + -Wall +) diff --git a/packages/firestore/android/src/reactnative/java/io/invertase/firebase/firestore/generated/jni/RNFBFirestoreTurboModules-generated.cpp b/packages/firestore/android/src/reactnative/java/io/invertase/firebase/firestore/generated/jni/RNFBFirestoreTurboModules-generated.cpp new file mode 100644 index 0000000000..d1d668ed6b --- /dev/null +++ b/packages/firestore/android/src/reactnative/java/io/invertase/firebase/firestore/generated/jni/RNFBFirestoreTurboModules-generated.cpp @@ -0,0 +1,230 @@ + +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleJniCpp.js + */ + +#include "RNFBFirestoreTurboModules.h" + +namespace facebook::react { + +static facebook::jsi::Value __hostFunction_NativeRNFBTurboFirestoreSpecJSI_setLogLevel(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, VoidKind, "setLogLevel", "(Ljava/lang/String;)V", args, count, cachedMethodId); +} + +static facebook::jsi::Value __hostFunction_NativeRNFBTurboFirestoreSpecJSI_loadBundle(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, PromiseKind, "loadBundle", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/facebook/react/bridge/Promise;)V", args, count, cachedMethodId); +} + +static facebook::jsi::Value __hostFunction_NativeRNFBTurboFirestoreSpecJSI_clearPersistence(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, PromiseKind, "clearPersistence", "(Ljava/lang/String;Ljava/lang/String;Lcom/facebook/react/bridge/Promise;)V", args, count, cachedMethodId); +} + +static facebook::jsi::Value __hostFunction_NativeRNFBTurboFirestoreSpecJSI_waitForPendingWrites(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, PromiseKind, "waitForPendingWrites", "(Ljava/lang/String;Ljava/lang/String;Lcom/facebook/react/bridge/Promise;)V", args, count, cachedMethodId); +} + +static facebook::jsi::Value __hostFunction_NativeRNFBTurboFirestoreSpecJSI_disableNetwork(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, PromiseKind, "disableNetwork", "(Ljava/lang/String;Ljava/lang/String;Lcom/facebook/react/bridge/Promise;)V", args, count, cachedMethodId); +} + +static facebook::jsi::Value __hostFunction_NativeRNFBTurboFirestoreSpecJSI_enableNetwork(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, PromiseKind, "enableNetwork", "(Ljava/lang/String;Ljava/lang/String;Lcom/facebook/react/bridge/Promise;)V", args, count, cachedMethodId); +} + +static facebook::jsi::Value __hostFunction_NativeRNFBTurboFirestoreSpecJSI_useEmulator(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, VoidKind, "useEmulator", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;D)V", args, count, cachedMethodId); +} + +static facebook::jsi::Value __hostFunction_NativeRNFBTurboFirestoreSpecJSI_settings(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, PromiseKind, "settings", "(Ljava/lang/String;Ljava/lang/String;Lcom/facebook/react/bridge/ReadableMap;Lcom/facebook/react/bridge/Promise;)V", args, count, cachedMethodId); +} + +static facebook::jsi::Value __hostFunction_NativeRNFBTurboFirestoreSpecJSI_terminate(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, PromiseKind, "terminate", "(Ljava/lang/String;Ljava/lang/String;Lcom/facebook/react/bridge/Promise;)V", args, count, cachedMethodId); +} + +static facebook::jsi::Value __hostFunction_NativeRNFBTurboFirestoreSpecJSI_persistenceCacheIndexManager(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, PromiseKind, "persistenceCacheIndexManager", "(Ljava/lang/String;Ljava/lang/String;DLcom/facebook/react/bridge/Promise;)V", args, count, cachedMethodId); +} + +static facebook::jsi::Value __hostFunction_NativeRNFBTurboFirestoreSpecJSI_addSnapshotsInSync(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, VoidKind, "addSnapshotsInSync", "(Ljava/lang/String;Ljava/lang/String;D)V", args, count, cachedMethodId); +} + +static facebook::jsi::Value __hostFunction_NativeRNFBTurboFirestoreSpecJSI_removeSnapshotsInSync(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, VoidKind, "removeSnapshotsInSync", "(Ljava/lang/String;Ljava/lang/String;D)V", args, count, cachedMethodId); +} + +NativeRNFBTurboFirestoreSpecJSI::NativeRNFBTurboFirestoreSpecJSI(const JavaTurboModule::InitParams ¶ms) + : JavaTurboModule(params) { + methodMap_["setLogLevel"] = MethodMetadata {1, __hostFunction_NativeRNFBTurboFirestoreSpecJSI_setLogLevel}; + methodMap_["loadBundle"] = MethodMetadata {3, __hostFunction_NativeRNFBTurboFirestoreSpecJSI_loadBundle}; + methodMap_["clearPersistence"] = MethodMetadata {2, __hostFunction_NativeRNFBTurboFirestoreSpecJSI_clearPersistence}; + methodMap_["waitForPendingWrites"] = MethodMetadata {2, __hostFunction_NativeRNFBTurboFirestoreSpecJSI_waitForPendingWrites}; + methodMap_["disableNetwork"] = MethodMetadata {2, __hostFunction_NativeRNFBTurboFirestoreSpecJSI_disableNetwork}; + methodMap_["enableNetwork"] = MethodMetadata {2, __hostFunction_NativeRNFBTurboFirestoreSpecJSI_enableNetwork}; + methodMap_["useEmulator"] = MethodMetadata {4, __hostFunction_NativeRNFBTurboFirestoreSpecJSI_useEmulator}; + methodMap_["settings"] = MethodMetadata {3, __hostFunction_NativeRNFBTurboFirestoreSpecJSI_settings}; + methodMap_["terminate"] = MethodMetadata {2, __hostFunction_NativeRNFBTurboFirestoreSpecJSI_terminate}; + methodMap_["persistenceCacheIndexManager"] = MethodMetadata {3, __hostFunction_NativeRNFBTurboFirestoreSpecJSI_persistenceCacheIndexManager}; + methodMap_["addSnapshotsInSync"] = MethodMetadata {3, __hostFunction_NativeRNFBTurboFirestoreSpecJSI_addSnapshotsInSync}; + methodMap_["removeSnapshotsInSync"] = MethodMetadata {3, __hostFunction_NativeRNFBTurboFirestoreSpecJSI_removeSnapshotsInSync}; +} +static facebook::jsi::Value __hostFunction_NativeRNFBTurboFirestoreCollectionSpecJSI_namedQueryOnSnapshot(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, VoidKind, "namedQueryOnSnapshot", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/facebook/react/bridge/ReadableArray;Lcom/facebook/react/bridge/ReadableArray;Lcom/facebook/react/bridge/ReadableMap;DLcom/facebook/react/bridge/ReadableMap;)V", args, count, cachedMethodId); +} + +static facebook::jsi::Value __hostFunction_NativeRNFBTurboFirestoreCollectionSpecJSI_collectionOnSnapshot(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, VoidKind, "collectionOnSnapshot", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/facebook/react/bridge/ReadableArray;Lcom/facebook/react/bridge/ReadableArray;Lcom/facebook/react/bridge/ReadableMap;DLcom/facebook/react/bridge/ReadableMap;)V", args, count, cachedMethodId); +} + +static facebook::jsi::Value __hostFunction_NativeRNFBTurboFirestoreCollectionSpecJSI_collectionOffSnapshot(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, VoidKind, "collectionOffSnapshot", "(Ljava/lang/String;Ljava/lang/String;D)V", args, count, cachedMethodId); +} + +static facebook::jsi::Value __hostFunction_NativeRNFBTurboFirestoreCollectionSpecJSI_namedQueryGet(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, PromiseKind, "namedQueryGet", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/facebook/react/bridge/ReadableArray;Lcom/facebook/react/bridge/ReadableArray;Lcom/facebook/react/bridge/ReadableMap;Lcom/facebook/react/bridge/ReadableMap;Lcom/facebook/react/bridge/Promise;)V", args, count, cachedMethodId); +} + +static facebook::jsi::Value __hostFunction_NativeRNFBTurboFirestoreCollectionSpecJSI_collectionGet(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, PromiseKind, "collectionGet", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/facebook/react/bridge/ReadableArray;Lcom/facebook/react/bridge/ReadableArray;Lcom/facebook/react/bridge/ReadableMap;Lcom/facebook/react/bridge/ReadableMap;Lcom/facebook/react/bridge/Promise;)V", args, count, cachedMethodId); +} + +static facebook::jsi::Value __hostFunction_NativeRNFBTurboFirestoreCollectionSpecJSI_collectionCount(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, PromiseKind, "collectionCount", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/facebook/react/bridge/ReadableArray;Lcom/facebook/react/bridge/ReadableArray;Lcom/facebook/react/bridge/ReadableMap;Lcom/facebook/react/bridge/Promise;)V", args, count, cachedMethodId); +} + +static facebook::jsi::Value __hostFunction_NativeRNFBTurboFirestoreCollectionSpecJSI_aggregateQuery(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, PromiseKind, "aggregateQuery", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/facebook/react/bridge/ReadableArray;Lcom/facebook/react/bridge/ReadableArray;Lcom/facebook/react/bridge/ReadableMap;Lcom/facebook/react/bridge/ReadableArray;Lcom/facebook/react/bridge/Promise;)V", args, count, cachedMethodId); +} + +static facebook::jsi::Value __hostFunction_NativeRNFBTurboFirestoreCollectionSpecJSI_pipelineExecute(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, PromiseKind, "pipelineExecute", "(Ljava/lang/String;Ljava/lang/String;Lcom/facebook/react/bridge/ReadableMap;Lcom/facebook/react/bridge/ReadableMap;Lcom/facebook/react/bridge/Promise;)V", args, count, cachedMethodId); +} + +NativeRNFBTurboFirestoreCollectionSpecJSI::NativeRNFBTurboFirestoreCollectionSpecJSI(const JavaTurboModule::InitParams ¶ms) + : JavaTurboModule(params) { + methodMap_["namedQueryOnSnapshot"] = MethodMetadata {9, __hostFunction_NativeRNFBTurboFirestoreCollectionSpecJSI_namedQueryOnSnapshot}; + methodMap_["collectionOnSnapshot"] = MethodMetadata {9, __hostFunction_NativeRNFBTurboFirestoreCollectionSpecJSI_collectionOnSnapshot}; + methodMap_["collectionOffSnapshot"] = MethodMetadata {3, __hostFunction_NativeRNFBTurboFirestoreCollectionSpecJSI_collectionOffSnapshot}; + methodMap_["namedQueryGet"] = MethodMetadata {8, __hostFunction_NativeRNFBTurboFirestoreCollectionSpecJSI_namedQueryGet}; + methodMap_["collectionGet"] = MethodMetadata {8, __hostFunction_NativeRNFBTurboFirestoreCollectionSpecJSI_collectionGet}; + methodMap_["collectionCount"] = MethodMetadata {7, __hostFunction_NativeRNFBTurboFirestoreCollectionSpecJSI_collectionCount}; + methodMap_["aggregateQuery"] = MethodMetadata {8, __hostFunction_NativeRNFBTurboFirestoreCollectionSpecJSI_aggregateQuery}; + methodMap_["pipelineExecute"] = MethodMetadata {4, __hostFunction_NativeRNFBTurboFirestoreCollectionSpecJSI_pipelineExecute}; +} +static facebook::jsi::Value __hostFunction_NativeRNFBTurboFirestoreDocumentSpecJSI_documentOnSnapshot(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, VoidKind, "documentOnSnapshot", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;DLcom/facebook/react/bridge/ReadableMap;)V", args, count, cachedMethodId); +} + +static facebook::jsi::Value __hostFunction_NativeRNFBTurboFirestoreDocumentSpecJSI_documentOffSnapshot(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, VoidKind, "documentOffSnapshot", "(Ljava/lang/String;Ljava/lang/String;D)V", args, count, cachedMethodId); +} + +static facebook::jsi::Value __hostFunction_NativeRNFBTurboFirestoreDocumentSpecJSI_documentGet(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, PromiseKind, "documentGet", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/facebook/react/bridge/ReadableMap;Lcom/facebook/react/bridge/Promise;)V", args, count, cachedMethodId); +} + +static facebook::jsi::Value __hostFunction_NativeRNFBTurboFirestoreDocumentSpecJSI_documentDelete(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, PromiseKind, "documentDelete", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/facebook/react/bridge/Promise;)V", args, count, cachedMethodId); +} + +static facebook::jsi::Value __hostFunction_NativeRNFBTurboFirestoreDocumentSpecJSI_documentSet(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, PromiseKind, "documentSet", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/facebook/react/bridge/ReadableMap;Lcom/facebook/react/bridge/ReadableMap;Lcom/facebook/react/bridge/Promise;)V", args, count, cachedMethodId); +} + +static facebook::jsi::Value __hostFunction_NativeRNFBTurboFirestoreDocumentSpecJSI_documentUpdate(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, PromiseKind, "documentUpdate", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/facebook/react/bridge/ReadableMap;Lcom/facebook/react/bridge/Promise;)V", args, count, cachedMethodId); +} + +static facebook::jsi::Value __hostFunction_NativeRNFBTurboFirestoreDocumentSpecJSI_documentBatch(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, PromiseKind, "documentBatch", "(Ljava/lang/String;Ljava/lang/String;Lcom/facebook/react/bridge/ReadableArray;Lcom/facebook/react/bridge/Promise;)V", args, count, cachedMethodId); +} + +NativeRNFBTurboFirestoreDocumentSpecJSI::NativeRNFBTurboFirestoreDocumentSpecJSI(const JavaTurboModule::InitParams ¶ms) + : JavaTurboModule(params) { + methodMap_["documentOnSnapshot"] = MethodMetadata {5, __hostFunction_NativeRNFBTurboFirestoreDocumentSpecJSI_documentOnSnapshot}; + methodMap_["documentOffSnapshot"] = MethodMetadata {3, __hostFunction_NativeRNFBTurboFirestoreDocumentSpecJSI_documentOffSnapshot}; + methodMap_["documentGet"] = MethodMetadata {4, __hostFunction_NativeRNFBTurboFirestoreDocumentSpecJSI_documentGet}; + methodMap_["documentDelete"] = MethodMetadata {3, __hostFunction_NativeRNFBTurboFirestoreDocumentSpecJSI_documentDelete}; + methodMap_["documentSet"] = MethodMetadata {5, __hostFunction_NativeRNFBTurboFirestoreDocumentSpecJSI_documentSet}; + methodMap_["documentUpdate"] = MethodMetadata {4, __hostFunction_NativeRNFBTurboFirestoreDocumentSpecJSI_documentUpdate}; + methodMap_["documentBatch"] = MethodMetadata {3, __hostFunction_NativeRNFBTurboFirestoreDocumentSpecJSI_documentBatch}; +} +static facebook::jsi::Value __hostFunction_NativeRNFBTurboFirestoreTransactionSpecJSI_transactionBegin(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, VoidKind, "transactionBegin", "(Ljava/lang/String;Ljava/lang/String;D)V", args, count, cachedMethodId); +} + +static facebook::jsi::Value __hostFunction_NativeRNFBTurboFirestoreTransactionSpecJSI_transactionGetDocument(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, PromiseKind, "transactionGetDocument", "(Ljava/lang/String;Ljava/lang/String;DLjava/lang/String;Lcom/facebook/react/bridge/Promise;)V", args, count, cachedMethodId); +} + +static facebook::jsi::Value __hostFunction_NativeRNFBTurboFirestoreTransactionSpecJSI_transactionDispose(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, VoidKind, "transactionDispose", "(Ljava/lang/String;Ljava/lang/String;D)V", args, count, cachedMethodId); +} + +static facebook::jsi::Value __hostFunction_NativeRNFBTurboFirestoreTransactionSpecJSI_transactionApplyBuffer(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, VoidKind, "transactionApplyBuffer", "(Ljava/lang/String;Ljava/lang/String;DLcom/facebook/react/bridge/ReadableArray;)V", args, count, cachedMethodId); +} + +NativeRNFBTurboFirestoreTransactionSpecJSI::NativeRNFBTurboFirestoreTransactionSpecJSI(const JavaTurboModule::InitParams ¶ms) + : JavaTurboModule(params) { + methodMap_["transactionBegin"] = MethodMetadata {3, __hostFunction_NativeRNFBTurboFirestoreTransactionSpecJSI_transactionBegin}; + methodMap_["transactionGetDocument"] = MethodMetadata {4, __hostFunction_NativeRNFBTurboFirestoreTransactionSpecJSI_transactionGetDocument}; + methodMap_["transactionDispose"] = MethodMetadata {3, __hostFunction_NativeRNFBTurboFirestoreTransactionSpecJSI_transactionDispose}; + methodMap_["transactionApplyBuffer"] = MethodMetadata {4, __hostFunction_NativeRNFBTurboFirestoreTransactionSpecJSI_transactionApplyBuffer}; +} + +std::shared_ptr RNFBFirestoreTurboModules_ModuleProvider(const std::string &moduleName, const JavaTurboModule::InitParams ¶ms) { + if (moduleName == "NativeRNFBTurboFirestore") { + return std::make_shared(params); + } + if (moduleName == "NativeRNFBTurboFirestoreCollection") { + return std::make_shared(params); + } + if (moduleName == "NativeRNFBTurboFirestoreDocument") { + return std::make_shared(params); + } + if (moduleName == "NativeRNFBTurboFirestoreTransaction") { + return std::make_shared(params); + } + return nullptr; +} + +} // namespace facebook::react diff --git a/packages/firestore/android/src/reactnative/java/io/invertase/firebase/firestore/generated/jni/RNFBFirestoreTurboModules.h b/packages/firestore/android/src/reactnative/java/io/invertase/firebase/firestore/generated/jni/RNFBFirestoreTurboModules.h new file mode 100644 index 0000000000..771b5ca0f5 --- /dev/null +++ b/packages/firestore/android/src/reactnative/java/io/invertase/firebase/firestore/generated/jni/RNFBFirestoreTurboModules.h @@ -0,0 +1,55 @@ + +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleJniH.js + */ + +#pragma once + +#include +#include +#include + +namespace facebook::react { + +/** + * JNI C++ class for module 'NativeRNFBTurboFirestore' + */ +class JSI_EXPORT NativeRNFBTurboFirestoreSpecJSI : public JavaTurboModule { +public: + NativeRNFBTurboFirestoreSpecJSI(const JavaTurboModule::InitParams ¶ms); +}; + +/** + * JNI C++ class for module 'NativeRNFBTurboFirestoreCollection' + */ +class JSI_EXPORT NativeRNFBTurboFirestoreCollectionSpecJSI : public JavaTurboModule { +public: + NativeRNFBTurboFirestoreCollectionSpecJSI(const JavaTurboModule::InitParams ¶ms); +}; + +/** + * JNI C++ class for module 'NativeRNFBTurboFirestoreDocument' + */ +class JSI_EXPORT NativeRNFBTurboFirestoreDocumentSpecJSI : public JavaTurboModule { +public: + NativeRNFBTurboFirestoreDocumentSpecJSI(const JavaTurboModule::InitParams ¶ms); +}; + +/** + * JNI C++ class for module 'NativeRNFBTurboFirestoreTransaction' + */ +class JSI_EXPORT NativeRNFBTurboFirestoreTransactionSpecJSI : public JavaTurboModule { +public: + NativeRNFBTurboFirestoreTransactionSpecJSI(const JavaTurboModule::InitParams ¶ms); +}; + + +JSI_EXPORT +std::shared_ptr RNFBFirestoreTurboModules_ModuleProvider(const std::string &moduleName, const JavaTurboModule::InitParams ¶ms); + +} // namespace facebook::react diff --git a/packages/firestore/android/src/reactnative/java/io/invertase/firebase/firestore/generated/jni/react/renderer/components/RNFBFirestoreTurboModules/RNFBFirestoreTurboModulesJSI-generated.cpp b/packages/firestore/android/src/reactnative/java/io/invertase/firebase/firestore/generated/jni/react/renderer/components/RNFBFirestoreTurboModules/RNFBFirestoreTurboModulesJSI-generated.cpp new file mode 100644 index 0000000000..3a1062e6af --- /dev/null +++ b/packages/firestore/android/src/reactnative/java/io/invertase/firebase/firestore/generated/jni/react/renderer/components/RNFBFirestoreTurboModules/RNFBFirestoreTurboModulesJSI-generated.cpp @@ -0,0 +1,357 @@ +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleCpp.js + */ + +#include "RNFBFirestoreTurboModulesJSI.h" + +namespace facebook::react { + +static jsi::Value __hostFunction_NativeRNFBTurboFirestoreCxxSpecJSI_setLogLevel(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + static_cast(&turboModule)->setLogLevel( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt) + ); + return jsi::Value::undefined(); +} +static jsi::Value __hostFunction_NativeRNFBTurboFirestoreCxxSpecJSI_loadBundle(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->loadBundle( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt), + count <= 2 ? throw jsi::JSError(rt, "Expected argument in position 2 to be passed") : args[2].asString(rt) + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboFirestoreCxxSpecJSI_clearPersistence(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->clearPersistence( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt) + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboFirestoreCxxSpecJSI_waitForPendingWrites(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->waitForPendingWrites( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt) + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboFirestoreCxxSpecJSI_disableNetwork(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->disableNetwork( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt) + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboFirestoreCxxSpecJSI_enableNetwork(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->enableNetwork( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt) + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboFirestoreCxxSpecJSI_useEmulator(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + static_cast(&turboModule)->useEmulator( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt), + count <= 2 ? throw jsi::JSError(rt, "Expected argument in position 2 to be passed") : args[2].asString(rt), + count <= 3 ? throw jsi::JSError(rt, "Expected argument in position 3 to be passed") : args[3].asNumber() + ); + return jsi::Value::undefined(); +} +static jsi::Value __hostFunction_NativeRNFBTurboFirestoreCxxSpecJSI_settings(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->settings( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt), + count <= 2 ? throw jsi::JSError(rt, "Expected argument in position 2 to be passed") : args[2].asObject(rt) + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboFirestoreCxxSpecJSI_terminate(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->terminate( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt) + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboFirestoreCxxSpecJSI_persistenceCacheIndexManager(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->persistenceCacheIndexManager( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt), + count <= 2 ? throw jsi::JSError(rt, "Expected argument in position 2 to be passed") : args[2].asNumber() + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboFirestoreCxxSpecJSI_addSnapshotsInSync(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + static_cast(&turboModule)->addSnapshotsInSync( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt), + count <= 2 ? throw jsi::JSError(rt, "Expected argument in position 2 to be passed") : args[2].asNumber() + ); + return jsi::Value::undefined(); +} +static jsi::Value __hostFunction_NativeRNFBTurboFirestoreCxxSpecJSI_removeSnapshotsInSync(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + static_cast(&turboModule)->removeSnapshotsInSync( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt), + count <= 2 ? throw jsi::JSError(rt, "Expected argument in position 2 to be passed") : args[2].asNumber() + ); + return jsi::Value::undefined(); +} + +NativeRNFBTurboFirestoreCxxSpecJSI::NativeRNFBTurboFirestoreCxxSpecJSI(std::shared_ptr jsInvoker) + : TurboModule("NativeRNFBTurboFirestore", jsInvoker) { + methodMap_["setLogLevel"] = MethodMetadata {1, __hostFunction_NativeRNFBTurboFirestoreCxxSpecJSI_setLogLevel}; + methodMap_["loadBundle"] = MethodMetadata {3, __hostFunction_NativeRNFBTurboFirestoreCxxSpecJSI_loadBundle}; + methodMap_["clearPersistence"] = MethodMetadata {2, __hostFunction_NativeRNFBTurboFirestoreCxxSpecJSI_clearPersistence}; + methodMap_["waitForPendingWrites"] = MethodMetadata {2, __hostFunction_NativeRNFBTurboFirestoreCxxSpecJSI_waitForPendingWrites}; + methodMap_["disableNetwork"] = MethodMetadata {2, __hostFunction_NativeRNFBTurboFirestoreCxxSpecJSI_disableNetwork}; + methodMap_["enableNetwork"] = MethodMetadata {2, __hostFunction_NativeRNFBTurboFirestoreCxxSpecJSI_enableNetwork}; + methodMap_["useEmulator"] = MethodMetadata {4, __hostFunction_NativeRNFBTurboFirestoreCxxSpecJSI_useEmulator}; + methodMap_["settings"] = MethodMetadata {3, __hostFunction_NativeRNFBTurboFirestoreCxxSpecJSI_settings}; + methodMap_["terminate"] = MethodMetadata {2, __hostFunction_NativeRNFBTurboFirestoreCxxSpecJSI_terminate}; + methodMap_["persistenceCacheIndexManager"] = MethodMetadata {3, __hostFunction_NativeRNFBTurboFirestoreCxxSpecJSI_persistenceCacheIndexManager}; + methodMap_["addSnapshotsInSync"] = MethodMetadata {3, __hostFunction_NativeRNFBTurboFirestoreCxxSpecJSI_addSnapshotsInSync}; + methodMap_["removeSnapshotsInSync"] = MethodMetadata {3, __hostFunction_NativeRNFBTurboFirestoreCxxSpecJSI_removeSnapshotsInSync}; +} +static jsi::Value __hostFunction_NativeRNFBTurboFirestoreCollectionCxxSpecJSI_namedQueryOnSnapshot(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + static_cast(&turboModule)->namedQueryOnSnapshot( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt), + count <= 2 ? throw jsi::JSError(rt, "Expected argument in position 2 to be passed") : args[2].asString(rt), + count <= 3 ? throw jsi::JSError(rt, "Expected argument in position 3 to be passed") : args[3].asString(rt), + count <= 4 ? throw jsi::JSError(rt, "Expected argument in position 4 to be passed") : args[4].asObject(rt).asArray(rt), + count <= 5 ? throw jsi::JSError(rt, "Expected argument in position 5 to be passed") : args[5].asObject(rt).asArray(rt), + count <= 6 ? throw jsi::JSError(rt, "Expected argument in position 6 to be passed") : args[6].asObject(rt), + count <= 7 ? throw jsi::JSError(rt, "Expected argument in position 7 to be passed") : args[7].asNumber(), + count <= 8 ? throw jsi::JSError(rt, "Expected argument in position 8 to be passed") : args[8].asObject(rt) + ); + return jsi::Value::undefined(); +} +static jsi::Value __hostFunction_NativeRNFBTurboFirestoreCollectionCxxSpecJSI_collectionOnSnapshot(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + static_cast(&turboModule)->collectionOnSnapshot( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt), + count <= 2 ? throw jsi::JSError(rt, "Expected argument in position 2 to be passed") : args[2].asString(rt), + count <= 3 ? throw jsi::JSError(rt, "Expected argument in position 3 to be passed") : args[3].asString(rt), + count <= 4 ? throw jsi::JSError(rt, "Expected argument in position 4 to be passed") : args[4].asObject(rt).asArray(rt), + count <= 5 ? throw jsi::JSError(rt, "Expected argument in position 5 to be passed") : args[5].asObject(rt).asArray(rt), + count <= 6 ? throw jsi::JSError(rt, "Expected argument in position 6 to be passed") : args[6].asObject(rt), + count <= 7 ? throw jsi::JSError(rt, "Expected argument in position 7 to be passed") : args[7].asNumber(), + count <= 8 ? throw jsi::JSError(rt, "Expected argument in position 8 to be passed") : args[8].asObject(rt) + ); + return jsi::Value::undefined(); +} +static jsi::Value __hostFunction_NativeRNFBTurboFirestoreCollectionCxxSpecJSI_collectionOffSnapshot(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + static_cast(&turboModule)->collectionOffSnapshot( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt), + count <= 2 ? throw jsi::JSError(rt, "Expected argument in position 2 to be passed") : args[2].asNumber() + ); + return jsi::Value::undefined(); +} +static jsi::Value __hostFunction_NativeRNFBTurboFirestoreCollectionCxxSpecJSI_namedQueryGet(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->namedQueryGet( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt), + count <= 2 ? throw jsi::JSError(rt, "Expected argument in position 2 to be passed") : args[2].asString(rt), + count <= 3 ? throw jsi::JSError(rt, "Expected argument in position 3 to be passed") : args[3].asString(rt), + count <= 4 ? throw jsi::JSError(rt, "Expected argument in position 4 to be passed") : args[4].asObject(rt).asArray(rt), + count <= 5 ? throw jsi::JSError(rt, "Expected argument in position 5 to be passed") : args[5].asObject(rt).asArray(rt), + count <= 6 ? throw jsi::JSError(rt, "Expected argument in position 6 to be passed") : args[6].asObject(rt), + count <= 7 || args[7].isUndefined() ? std::nullopt : std::make_optional(args[7].asObject(rt)) + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboFirestoreCollectionCxxSpecJSI_collectionGet(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->collectionGet( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt), + count <= 2 ? throw jsi::JSError(rt, "Expected argument in position 2 to be passed") : args[2].asString(rt), + count <= 3 ? throw jsi::JSError(rt, "Expected argument in position 3 to be passed") : args[3].asString(rt), + count <= 4 ? throw jsi::JSError(rt, "Expected argument in position 4 to be passed") : args[4].asObject(rt).asArray(rt), + count <= 5 ? throw jsi::JSError(rt, "Expected argument in position 5 to be passed") : args[5].asObject(rt).asArray(rt), + count <= 6 ? throw jsi::JSError(rt, "Expected argument in position 6 to be passed") : args[6].asObject(rt), + count <= 7 || args[7].isUndefined() ? std::nullopt : std::make_optional(args[7].asObject(rt)) + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboFirestoreCollectionCxxSpecJSI_collectionCount(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->collectionCount( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt), + count <= 2 ? throw jsi::JSError(rt, "Expected argument in position 2 to be passed") : args[2].asString(rt), + count <= 3 ? throw jsi::JSError(rt, "Expected argument in position 3 to be passed") : args[3].asString(rt), + count <= 4 ? throw jsi::JSError(rt, "Expected argument in position 4 to be passed") : args[4].asObject(rt).asArray(rt), + count <= 5 ? throw jsi::JSError(rt, "Expected argument in position 5 to be passed") : args[5].asObject(rt).asArray(rt), + count <= 6 ? throw jsi::JSError(rt, "Expected argument in position 6 to be passed") : args[6].asObject(rt) + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboFirestoreCollectionCxxSpecJSI_aggregateQuery(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->aggregateQuery( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt), + count <= 2 ? throw jsi::JSError(rt, "Expected argument in position 2 to be passed") : args[2].asString(rt), + count <= 3 ? throw jsi::JSError(rt, "Expected argument in position 3 to be passed") : args[3].asString(rt), + count <= 4 ? throw jsi::JSError(rt, "Expected argument in position 4 to be passed") : args[4].asObject(rt).asArray(rt), + count <= 5 ? throw jsi::JSError(rt, "Expected argument in position 5 to be passed") : args[5].asObject(rt).asArray(rt), + count <= 6 ? throw jsi::JSError(rt, "Expected argument in position 6 to be passed") : args[6].asObject(rt), + count <= 7 ? throw jsi::JSError(rt, "Expected argument in position 7 to be passed") : args[7].asObject(rt).asArray(rt) + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboFirestoreCollectionCxxSpecJSI_pipelineExecute(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->pipelineExecute( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt), + count <= 2 ? throw jsi::JSError(rt, "Expected argument in position 2 to be passed") : args[2].asObject(rt), + count <= 3 || args[3].isUndefined() ? std::nullopt : std::make_optional(args[3].asObject(rt)) + ); +} + +NativeRNFBTurboFirestoreCollectionCxxSpecJSI::NativeRNFBTurboFirestoreCollectionCxxSpecJSI(std::shared_ptr jsInvoker) + : TurboModule("NativeRNFBTurboFirestoreCollection", jsInvoker) { + methodMap_["namedQueryOnSnapshot"] = MethodMetadata {9, __hostFunction_NativeRNFBTurboFirestoreCollectionCxxSpecJSI_namedQueryOnSnapshot}; + methodMap_["collectionOnSnapshot"] = MethodMetadata {9, __hostFunction_NativeRNFBTurboFirestoreCollectionCxxSpecJSI_collectionOnSnapshot}; + methodMap_["collectionOffSnapshot"] = MethodMetadata {3, __hostFunction_NativeRNFBTurboFirestoreCollectionCxxSpecJSI_collectionOffSnapshot}; + methodMap_["namedQueryGet"] = MethodMetadata {8, __hostFunction_NativeRNFBTurboFirestoreCollectionCxxSpecJSI_namedQueryGet}; + methodMap_["collectionGet"] = MethodMetadata {8, __hostFunction_NativeRNFBTurboFirestoreCollectionCxxSpecJSI_collectionGet}; + methodMap_["collectionCount"] = MethodMetadata {7, __hostFunction_NativeRNFBTurboFirestoreCollectionCxxSpecJSI_collectionCount}; + methodMap_["aggregateQuery"] = MethodMetadata {8, __hostFunction_NativeRNFBTurboFirestoreCollectionCxxSpecJSI_aggregateQuery}; + methodMap_["pipelineExecute"] = MethodMetadata {4, __hostFunction_NativeRNFBTurboFirestoreCollectionCxxSpecJSI_pipelineExecute}; +} +static jsi::Value __hostFunction_NativeRNFBTurboFirestoreDocumentCxxSpecJSI_documentOnSnapshot(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + static_cast(&turboModule)->documentOnSnapshot( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt), + count <= 2 ? throw jsi::JSError(rt, "Expected argument in position 2 to be passed") : args[2].asString(rt), + count <= 3 ? throw jsi::JSError(rt, "Expected argument in position 3 to be passed") : args[3].asNumber(), + count <= 4 ? throw jsi::JSError(rt, "Expected argument in position 4 to be passed") : args[4].asObject(rt) + ); + return jsi::Value::undefined(); +} +static jsi::Value __hostFunction_NativeRNFBTurboFirestoreDocumentCxxSpecJSI_documentOffSnapshot(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + static_cast(&turboModule)->documentOffSnapshot( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt), + count <= 2 ? throw jsi::JSError(rt, "Expected argument in position 2 to be passed") : args[2].asNumber() + ); + return jsi::Value::undefined(); +} +static jsi::Value __hostFunction_NativeRNFBTurboFirestoreDocumentCxxSpecJSI_documentGet(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->documentGet( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt), + count <= 2 ? throw jsi::JSError(rt, "Expected argument in position 2 to be passed") : args[2].asString(rt), + count <= 3 || args[3].isUndefined() ? std::nullopt : std::make_optional(args[3].asObject(rt)) + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboFirestoreDocumentCxxSpecJSI_documentDelete(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->documentDelete( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt), + count <= 2 ? throw jsi::JSError(rt, "Expected argument in position 2 to be passed") : args[2].asString(rt) + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboFirestoreDocumentCxxSpecJSI_documentSet(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->documentSet( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt), + count <= 2 ? throw jsi::JSError(rt, "Expected argument in position 2 to be passed") : args[2].asString(rt), + count <= 3 ? throw jsi::JSError(rt, "Expected argument in position 3 to be passed") : args[3].asObject(rt), + count <= 4 ? throw jsi::JSError(rt, "Expected argument in position 4 to be passed") : args[4].asObject(rt) + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboFirestoreDocumentCxxSpecJSI_documentUpdate(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->documentUpdate( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt), + count <= 2 ? throw jsi::JSError(rt, "Expected argument in position 2 to be passed") : args[2].asString(rt), + count <= 3 ? throw jsi::JSError(rt, "Expected argument in position 3 to be passed") : args[3].asObject(rt) + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboFirestoreDocumentCxxSpecJSI_documentBatch(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->documentBatch( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt), + count <= 2 ? throw jsi::JSError(rt, "Expected argument in position 2 to be passed") : args[2].asObject(rt).asArray(rt) + ); +} + +NativeRNFBTurboFirestoreDocumentCxxSpecJSI::NativeRNFBTurboFirestoreDocumentCxxSpecJSI(std::shared_ptr jsInvoker) + : TurboModule("NativeRNFBTurboFirestoreDocument", jsInvoker) { + methodMap_["documentOnSnapshot"] = MethodMetadata {5, __hostFunction_NativeRNFBTurboFirestoreDocumentCxxSpecJSI_documentOnSnapshot}; + methodMap_["documentOffSnapshot"] = MethodMetadata {3, __hostFunction_NativeRNFBTurboFirestoreDocumentCxxSpecJSI_documentOffSnapshot}; + methodMap_["documentGet"] = MethodMetadata {4, __hostFunction_NativeRNFBTurboFirestoreDocumentCxxSpecJSI_documentGet}; + methodMap_["documentDelete"] = MethodMetadata {3, __hostFunction_NativeRNFBTurboFirestoreDocumentCxxSpecJSI_documentDelete}; + methodMap_["documentSet"] = MethodMetadata {5, __hostFunction_NativeRNFBTurboFirestoreDocumentCxxSpecJSI_documentSet}; + methodMap_["documentUpdate"] = MethodMetadata {4, __hostFunction_NativeRNFBTurboFirestoreDocumentCxxSpecJSI_documentUpdate}; + methodMap_["documentBatch"] = MethodMetadata {3, __hostFunction_NativeRNFBTurboFirestoreDocumentCxxSpecJSI_documentBatch}; +} +static jsi::Value __hostFunction_NativeRNFBTurboFirestoreTransactionCxxSpecJSI_transactionBegin(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + static_cast(&turboModule)->transactionBegin( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt), + count <= 2 ? throw jsi::JSError(rt, "Expected argument in position 2 to be passed") : args[2].asNumber() + ); + return jsi::Value::undefined(); +} +static jsi::Value __hostFunction_NativeRNFBTurboFirestoreTransactionCxxSpecJSI_transactionGetDocument(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->transactionGetDocument( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt), + count <= 2 ? throw jsi::JSError(rt, "Expected argument in position 2 to be passed") : args[2].asNumber(), + count <= 3 ? throw jsi::JSError(rt, "Expected argument in position 3 to be passed") : args[3].asString(rt) + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboFirestoreTransactionCxxSpecJSI_transactionDispose(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + static_cast(&turboModule)->transactionDispose( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt), + count <= 2 ? throw jsi::JSError(rt, "Expected argument in position 2 to be passed") : args[2].asNumber() + ); + return jsi::Value::undefined(); +} +static jsi::Value __hostFunction_NativeRNFBTurboFirestoreTransactionCxxSpecJSI_transactionApplyBuffer(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + static_cast(&turboModule)->transactionApplyBuffer( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt), + count <= 2 ? throw jsi::JSError(rt, "Expected argument in position 2 to be passed") : args[2].asNumber(), + count <= 3 ? throw jsi::JSError(rt, "Expected argument in position 3 to be passed") : args[3].asObject(rt).asArray(rt) + ); + return jsi::Value::undefined(); +} + +NativeRNFBTurboFirestoreTransactionCxxSpecJSI::NativeRNFBTurboFirestoreTransactionCxxSpecJSI(std::shared_ptr jsInvoker) + : TurboModule("NativeRNFBTurboFirestoreTransaction", jsInvoker) { + methodMap_["transactionBegin"] = MethodMetadata {3, __hostFunction_NativeRNFBTurboFirestoreTransactionCxxSpecJSI_transactionBegin}; + methodMap_["transactionGetDocument"] = MethodMetadata {4, __hostFunction_NativeRNFBTurboFirestoreTransactionCxxSpecJSI_transactionGetDocument}; + methodMap_["transactionDispose"] = MethodMetadata {3, __hostFunction_NativeRNFBTurboFirestoreTransactionCxxSpecJSI_transactionDispose}; + methodMap_["transactionApplyBuffer"] = MethodMetadata {4, __hostFunction_NativeRNFBTurboFirestoreTransactionCxxSpecJSI_transactionApplyBuffer}; +} + + +} // namespace facebook::react diff --git a/packages/firestore/android/src/reactnative/java/io/invertase/firebase/firestore/generated/jni/react/renderer/components/RNFBFirestoreTurboModules/RNFBFirestoreTurboModulesJSI.h b/packages/firestore/android/src/reactnative/java/io/invertase/firebase/firestore/generated/jni/react/renderer/components/RNFBFirestoreTurboModules/RNFBFirestoreTurboModulesJSI.h new file mode 100644 index 0000000000..0a6983ebd3 --- /dev/null +++ b/packages/firestore/android/src/reactnative/java/io/invertase/firebase/firestore/generated/jni/react/renderer/components/RNFBFirestoreTurboModules/RNFBFirestoreTurboModulesJSI.h @@ -0,0 +1,637 @@ +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleH.js + */ + +#pragma once + +#include +#include + +namespace facebook::react { + + + +#pragma mark - NativeRNFBTurboFirestoreFirestoreLoadBundleTaskProgress + +template +struct NativeRNFBTurboFirestoreFirestoreLoadBundleTaskProgress { + P0 bytesLoaded; + P1 documentsLoaded; + P2 totalBytes; + P3 totalDocuments; + P4 taskState; + bool operator==(const NativeRNFBTurboFirestoreFirestoreLoadBundleTaskProgress &other) const { + return bytesLoaded == other.bytesLoaded && documentsLoaded == other.documentsLoaded && totalBytes == other.totalBytes && totalDocuments == other.totalDocuments && taskState == other.taskState; + } +}; + +template +struct NativeRNFBTurboFirestoreFirestoreLoadBundleTaskProgressBridging { + static T types; + + static T fromJs( + jsi::Runtime &rt, + const jsi::Object &value, + const std::shared_ptr &jsInvoker) { + T result{ + bridging::fromJs(rt, value.getProperty(rt, "bytesLoaded"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, "documentsLoaded"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, "totalBytes"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, "totalDocuments"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, "taskState"), jsInvoker)}; + return result; + } + +#ifdef DEBUG + static double bytesLoadedToJs(jsi::Runtime &rt, decltype(types.bytesLoaded) value) { + return bridging::toJs(rt, value); + } + + static double documentsLoadedToJs(jsi::Runtime &rt, decltype(types.documentsLoaded) value) { + return bridging::toJs(rt, value); + } + + static double totalBytesToJs(jsi::Runtime &rt, decltype(types.totalBytes) value) { + return bridging::toJs(rt, value); + } + + static double totalDocumentsToJs(jsi::Runtime &rt, decltype(types.totalDocuments) value) { + return bridging::toJs(rt, value); + } + + static jsi::String taskStateToJs(jsi::Runtime &rt, decltype(types.taskState) value) { + return bridging::toJs(rt, value); + } +#endif + + static jsi::Object toJs( + jsi::Runtime &rt, + const T &value, + const std::shared_ptr &jsInvoker) { + auto result = facebook::jsi::Object(rt); + result.setProperty(rt, "bytesLoaded", bridging::toJs(rt, value.bytesLoaded, jsInvoker)); + result.setProperty(rt, "documentsLoaded", bridging::toJs(rt, value.documentsLoaded, jsInvoker)); + result.setProperty(rt, "totalBytes", bridging::toJs(rt, value.totalBytes, jsInvoker)); + result.setProperty(rt, "totalDocuments", bridging::toJs(rt, value.totalDocuments, jsInvoker)); + result.setProperty(rt, "taskState", bridging::toJs(rt, value.taskState, jsInvoker)); + return result; + } +}; + +class JSI_EXPORT NativeRNFBTurboFirestoreCxxSpecJSI : public TurboModule { +protected: + NativeRNFBTurboFirestoreCxxSpecJSI(std::shared_ptr jsInvoker); + +public: + virtual void setLogLevel(jsi::Runtime &rt, jsi::String logLevel) = 0; + virtual jsi::Value loadBundle(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, jsi::String bundle) = 0; + virtual jsi::Value clearPersistence(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId) = 0; + virtual jsi::Value waitForPendingWrites(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId) = 0; + virtual jsi::Value disableNetwork(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId) = 0; + virtual jsi::Value enableNetwork(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId) = 0; + virtual void useEmulator(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, jsi::String host, double port) = 0; + virtual jsi::Value settings(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, jsi::Object settings) = 0; + virtual jsi::Value terminate(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId) = 0; + virtual jsi::Value persistenceCacheIndexManager(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, double requestType) = 0; + virtual void addSnapshotsInSync(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, double listenerId) = 0; + virtual void removeSnapshotsInSync(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, double listenerId) = 0; + +}; + +template +class JSI_EXPORT NativeRNFBTurboFirestoreCxxSpec : public TurboModule { +public: + jsi::Value create(jsi::Runtime &rt, const jsi::PropNameID &propName) override { + return delegate_.create(rt, propName); + } + + std::vector getPropertyNames(jsi::Runtime& runtime) override { + return delegate_.getPropertyNames(runtime); + } + + static constexpr std::string_view kModuleName = "NativeRNFBTurboFirestore"; + +protected: + NativeRNFBTurboFirestoreCxxSpec(std::shared_ptr jsInvoker) + : TurboModule(std::string{NativeRNFBTurboFirestoreCxxSpec::kModuleName}, jsInvoker), + delegate_(reinterpret_cast(this), jsInvoker) {} + + +private: + class Delegate : public NativeRNFBTurboFirestoreCxxSpecJSI { + public: + Delegate(T *instance, std::shared_ptr jsInvoker) : + NativeRNFBTurboFirestoreCxxSpecJSI(std::move(jsInvoker)), instance_(instance) { + + } + + void setLogLevel(jsi::Runtime &rt, jsi::String logLevel) override { + static_assert( + bridging::getParameterCount(&T::setLogLevel) == 2, + "Expected setLogLevel(...) to have 2 parameters"); + + return bridging::callFromJs( + rt, &T::setLogLevel, jsInvoker_, instance_, std::move(logLevel)); + } + jsi::Value loadBundle(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, jsi::String bundle) override { + static_assert( + bridging::getParameterCount(&T::loadBundle) == 4, + "Expected loadBundle(...) to have 4 parameters"); + + return bridging::callFromJs( + rt, &T::loadBundle, jsInvoker_, instance_, std::move(appName), std::move(databaseId), std::move(bundle)); + } + jsi::Value clearPersistence(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId) override { + static_assert( + bridging::getParameterCount(&T::clearPersistence) == 3, + "Expected clearPersistence(...) to have 3 parameters"); + + return bridging::callFromJs( + rt, &T::clearPersistence, jsInvoker_, instance_, std::move(appName), std::move(databaseId)); + } + jsi::Value waitForPendingWrites(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId) override { + static_assert( + bridging::getParameterCount(&T::waitForPendingWrites) == 3, + "Expected waitForPendingWrites(...) to have 3 parameters"); + + return bridging::callFromJs( + rt, &T::waitForPendingWrites, jsInvoker_, instance_, std::move(appName), std::move(databaseId)); + } + jsi::Value disableNetwork(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId) override { + static_assert( + bridging::getParameterCount(&T::disableNetwork) == 3, + "Expected disableNetwork(...) to have 3 parameters"); + + return bridging::callFromJs( + rt, &T::disableNetwork, jsInvoker_, instance_, std::move(appName), std::move(databaseId)); + } + jsi::Value enableNetwork(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId) override { + static_assert( + bridging::getParameterCount(&T::enableNetwork) == 3, + "Expected enableNetwork(...) to have 3 parameters"); + + return bridging::callFromJs( + rt, &T::enableNetwork, jsInvoker_, instance_, std::move(appName), std::move(databaseId)); + } + void useEmulator(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, jsi::String host, double port) override { + static_assert( + bridging::getParameterCount(&T::useEmulator) == 5, + "Expected useEmulator(...) to have 5 parameters"); + + return bridging::callFromJs( + rt, &T::useEmulator, jsInvoker_, instance_, std::move(appName), std::move(databaseId), std::move(host), std::move(port)); + } + jsi::Value settings(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, jsi::Object settings) override { + static_assert( + bridging::getParameterCount(&T::settings) == 4, + "Expected settings(...) to have 4 parameters"); + + return bridging::callFromJs( + rt, &T::settings, jsInvoker_, instance_, std::move(appName), std::move(databaseId), std::move(settings)); + } + jsi::Value terminate(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId) override { + static_assert( + bridging::getParameterCount(&T::terminate) == 3, + "Expected terminate(...) to have 3 parameters"); + + return bridging::callFromJs( + rt, &T::terminate, jsInvoker_, instance_, std::move(appName), std::move(databaseId)); + } + jsi::Value persistenceCacheIndexManager(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, double requestType) override { + static_assert( + bridging::getParameterCount(&T::persistenceCacheIndexManager) == 4, + "Expected persistenceCacheIndexManager(...) to have 4 parameters"); + + return bridging::callFromJs( + rt, &T::persistenceCacheIndexManager, jsInvoker_, instance_, std::move(appName), std::move(databaseId), std::move(requestType)); + } + void addSnapshotsInSync(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, double listenerId) override { + static_assert( + bridging::getParameterCount(&T::addSnapshotsInSync) == 4, + "Expected addSnapshotsInSync(...) to have 4 parameters"); + + return bridging::callFromJs( + rt, &T::addSnapshotsInSync, jsInvoker_, instance_, std::move(appName), std::move(databaseId), std::move(listenerId)); + } + void removeSnapshotsInSync(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, double listenerId) override { + static_assert( + bridging::getParameterCount(&T::removeSnapshotsInSync) == 4, + "Expected removeSnapshotsInSync(...) to have 4 parameters"); + + return bridging::callFromJs( + rt, &T::removeSnapshotsInSync, jsInvoker_, instance_, std::move(appName), std::move(databaseId), std::move(listenerId)); + } + + private: + friend class NativeRNFBTurboFirestoreCxxSpec; + T *instance_; + }; + + Delegate delegate_; +}; + + + +#pragma mark - NativeRNFBTurboFirestoreCollectionFirestoreCollectionCountResult + +template +struct NativeRNFBTurboFirestoreCollectionFirestoreCollectionCountResult { + P0 count; + bool operator==(const NativeRNFBTurboFirestoreCollectionFirestoreCollectionCountResult &other) const { + return count == other.count; + } +}; + +template +struct NativeRNFBTurboFirestoreCollectionFirestoreCollectionCountResultBridging { + static T types; + + static T fromJs( + jsi::Runtime &rt, + const jsi::Object &value, + const std::shared_ptr &jsInvoker) { + T result{ + bridging::fromJs(rt, value.getProperty(rt, "count"), jsInvoker)}; + return result; + } + +#ifdef DEBUG + static double countToJs(jsi::Runtime &rt, decltype(types.count) value) { + return bridging::toJs(rt, value); + } +#endif + + static jsi::Object toJs( + jsi::Runtime &rt, + const T &value, + const std::shared_ptr &jsInvoker) { + auto result = facebook::jsi::Object(rt); + if (value.count) { + result.setProperty(rt, "count", bridging::toJs(rt, value.count.value(), jsInvoker)); + } + return result; + } +}; + +class JSI_EXPORT NativeRNFBTurboFirestoreCollectionCxxSpecJSI : public TurboModule { +protected: + NativeRNFBTurboFirestoreCollectionCxxSpecJSI(std::shared_ptr jsInvoker); + +public: + virtual void namedQueryOnSnapshot(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, jsi::String queryName, jsi::String type, jsi::Array filters, jsi::Array orders, jsi::Object options, double listenerId, jsi::Object snapshotListenOptions) = 0; + virtual void collectionOnSnapshot(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, jsi::String path, jsi::String type, jsi::Array filters, jsi::Array orders, jsi::Object options, double listenerId, jsi::Object snapshotListenOptions) = 0; + virtual void collectionOffSnapshot(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, double listenerId) = 0; + virtual jsi::Value namedQueryGet(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, jsi::String queryName, jsi::String type, jsi::Array filters, jsi::Array orders, jsi::Object options, std::optional getOptions) = 0; + virtual jsi::Value collectionGet(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, jsi::String path, jsi::String type, jsi::Array filters, jsi::Array orders, jsi::Object options, std::optional getOptions) = 0; + virtual jsi::Value collectionCount(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, jsi::String path, jsi::String type, jsi::Array filters, jsi::Array orders, jsi::Object options) = 0; + virtual jsi::Value aggregateQuery(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, jsi::String path, jsi::String type, jsi::Array filters, jsi::Array orders, jsi::Object options, jsi::Array aggregateQueries) = 0; + virtual jsi::Value pipelineExecute(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, jsi::Object pipeline, std::optional options) = 0; + +}; + +template +class JSI_EXPORT NativeRNFBTurboFirestoreCollectionCxxSpec : public TurboModule { +public: + jsi::Value create(jsi::Runtime &rt, const jsi::PropNameID &propName) override { + return delegate_.create(rt, propName); + } + + std::vector getPropertyNames(jsi::Runtime& runtime) override { + return delegate_.getPropertyNames(runtime); + } + + static constexpr std::string_view kModuleName = "NativeRNFBTurboFirestoreCollection"; + +protected: + NativeRNFBTurboFirestoreCollectionCxxSpec(std::shared_ptr jsInvoker) + : TurboModule(std::string{NativeRNFBTurboFirestoreCollectionCxxSpec::kModuleName}, jsInvoker), + delegate_(reinterpret_cast(this), jsInvoker) {} + + +private: + class Delegate : public NativeRNFBTurboFirestoreCollectionCxxSpecJSI { + public: + Delegate(T *instance, std::shared_ptr jsInvoker) : + NativeRNFBTurboFirestoreCollectionCxxSpecJSI(std::move(jsInvoker)), instance_(instance) { + + } + + void namedQueryOnSnapshot(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, jsi::String queryName, jsi::String type, jsi::Array filters, jsi::Array orders, jsi::Object options, double listenerId, jsi::Object snapshotListenOptions) override { + static_assert( + bridging::getParameterCount(&T::namedQueryOnSnapshot) == 10, + "Expected namedQueryOnSnapshot(...) to have 10 parameters"); + + return bridging::callFromJs( + rt, &T::namedQueryOnSnapshot, jsInvoker_, instance_, std::move(appName), std::move(databaseId), std::move(queryName), std::move(type), std::move(filters), std::move(orders), std::move(options), std::move(listenerId), std::move(snapshotListenOptions)); + } + void collectionOnSnapshot(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, jsi::String path, jsi::String type, jsi::Array filters, jsi::Array orders, jsi::Object options, double listenerId, jsi::Object snapshotListenOptions) override { + static_assert( + bridging::getParameterCount(&T::collectionOnSnapshot) == 10, + "Expected collectionOnSnapshot(...) to have 10 parameters"); + + return bridging::callFromJs( + rt, &T::collectionOnSnapshot, jsInvoker_, instance_, std::move(appName), std::move(databaseId), std::move(path), std::move(type), std::move(filters), std::move(orders), std::move(options), std::move(listenerId), std::move(snapshotListenOptions)); + } + void collectionOffSnapshot(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, double listenerId) override { + static_assert( + bridging::getParameterCount(&T::collectionOffSnapshot) == 4, + "Expected collectionOffSnapshot(...) to have 4 parameters"); + + return bridging::callFromJs( + rt, &T::collectionOffSnapshot, jsInvoker_, instance_, std::move(appName), std::move(databaseId), std::move(listenerId)); + } + jsi::Value namedQueryGet(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, jsi::String queryName, jsi::String type, jsi::Array filters, jsi::Array orders, jsi::Object options, std::optional getOptions) override { + static_assert( + bridging::getParameterCount(&T::namedQueryGet) == 9, + "Expected namedQueryGet(...) to have 9 parameters"); + + return bridging::callFromJs( + rt, &T::namedQueryGet, jsInvoker_, instance_, std::move(appName), std::move(databaseId), std::move(queryName), std::move(type), std::move(filters), std::move(orders), std::move(options), std::move(getOptions)); + } + jsi::Value collectionGet(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, jsi::String path, jsi::String type, jsi::Array filters, jsi::Array orders, jsi::Object options, std::optional getOptions) override { + static_assert( + bridging::getParameterCount(&T::collectionGet) == 9, + "Expected collectionGet(...) to have 9 parameters"); + + return bridging::callFromJs( + rt, &T::collectionGet, jsInvoker_, instance_, std::move(appName), std::move(databaseId), std::move(path), std::move(type), std::move(filters), std::move(orders), std::move(options), std::move(getOptions)); + } + jsi::Value collectionCount(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, jsi::String path, jsi::String type, jsi::Array filters, jsi::Array orders, jsi::Object options) override { + static_assert( + bridging::getParameterCount(&T::collectionCount) == 8, + "Expected collectionCount(...) to have 8 parameters"); + + return bridging::callFromJs( + rt, &T::collectionCount, jsInvoker_, instance_, std::move(appName), std::move(databaseId), std::move(path), std::move(type), std::move(filters), std::move(orders), std::move(options)); + } + jsi::Value aggregateQuery(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, jsi::String path, jsi::String type, jsi::Array filters, jsi::Array orders, jsi::Object options, jsi::Array aggregateQueries) override { + static_assert( + bridging::getParameterCount(&T::aggregateQuery) == 9, + "Expected aggregateQuery(...) to have 9 parameters"); + + return bridging::callFromJs( + rt, &T::aggregateQuery, jsInvoker_, instance_, std::move(appName), std::move(databaseId), std::move(path), std::move(type), std::move(filters), std::move(orders), std::move(options), std::move(aggregateQueries)); + } + jsi::Value pipelineExecute(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, jsi::Object pipeline, std::optional options) override { + static_assert( + bridging::getParameterCount(&T::pipelineExecute) == 5, + "Expected pipelineExecute(...) to have 5 parameters"); + + return bridging::callFromJs( + rt, &T::pipelineExecute, jsInvoker_, instance_, std::move(appName), std::move(databaseId), std::move(pipeline), std::move(options)); + } + + private: + friend class NativeRNFBTurboFirestoreCollectionCxxSpec; + T *instance_; + }; + + Delegate delegate_; +}; + + + +#pragma mark - NativeRNFBTurboFirestoreDocumentFirestoreSnapshotListenOptions + +template +struct NativeRNFBTurboFirestoreDocumentFirestoreSnapshotListenOptions { + P0 includeMetadataChanges; + P1 source; + bool operator==(const NativeRNFBTurboFirestoreDocumentFirestoreSnapshotListenOptions &other) const { + return includeMetadataChanges == other.includeMetadataChanges && source == other.source; + } +}; + +template +struct NativeRNFBTurboFirestoreDocumentFirestoreSnapshotListenOptionsBridging { + static T types; + + static T fromJs( + jsi::Runtime &rt, + const jsi::Object &value, + const std::shared_ptr &jsInvoker) { + T result{ + bridging::fromJs(rt, value.getProperty(rt, "includeMetadataChanges"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, "source"), jsInvoker)}; + return result; + } + +#ifdef DEBUG + static bool includeMetadataChangesToJs(jsi::Runtime &rt, decltype(types.includeMetadataChanges) value) { + return bridging::toJs(rt, value); + } + + static jsi::String sourceToJs(jsi::Runtime &rt, decltype(types.source) value) { + return bridging::toJs(rt, value); + } +#endif + + static jsi::Object toJs( + jsi::Runtime &rt, + const T &value, + const std::shared_ptr &jsInvoker) { + auto result = facebook::jsi::Object(rt); + if (value.includeMetadataChanges) { + result.setProperty(rt, "includeMetadataChanges", bridging::toJs(rt, value.includeMetadataChanges.value(), jsInvoker)); + } + if (value.source) { + result.setProperty(rt, "source", bridging::toJs(rt, value.source.value(), jsInvoker)); + } + return result; + } +}; + +class JSI_EXPORT NativeRNFBTurboFirestoreDocumentCxxSpecJSI : public TurboModule { +protected: + NativeRNFBTurboFirestoreDocumentCxxSpecJSI(std::shared_ptr jsInvoker); + +public: + virtual void documentOnSnapshot(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, jsi::String path, double listenerId, jsi::Object snapshotListenOptions) = 0; + virtual void documentOffSnapshot(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, double listenerId) = 0; + virtual jsi::Value documentGet(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, jsi::String path, std::optional getOptions) = 0; + virtual jsi::Value documentDelete(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, jsi::String path) = 0; + virtual jsi::Value documentSet(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, jsi::String path, jsi::Object data, jsi::Object options) = 0; + virtual jsi::Value documentUpdate(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, jsi::String path, jsi::Object data) = 0; + virtual jsi::Value documentBatch(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, jsi::Array writes) = 0; + +}; + +template +class JSI_EXPORT NativeRNFBTurboFirestoreDocumentCxxSpec : public TurboModule { +public: + jsi::Value create(jsi::Runtime &rt, const jsi::PropNameID &propName) override { + return delegate_.create(rt, propName); + } + + std::vector getPropertyNames(jsi::Runtime& runtime) override { + return delegate_.getPropertyNames(runtime); + } + + static constexpr std::string_view kModuleName = "NativeRNFBTurboFirestoreDocument"; + +protected: + NativeRNFBTurboFirestoreDocumentCxxSpec(std::shared_ptr jsInvoker) + : TurboModule(std::string{NativeRNFBTurboFirestoreDocumentCxxSpec::kModuleName}, jsInvoker), + delegate_(reinterpret_cast(this), jsInvoker) {} + + +private: + class Delegate : public NativeRNFBTurboFirestoreDocumentCxxSpecJSI { + public: + Delegate(T *instance, std::shared_ptr jsInvoker) : + NativeRNFBTurboFirestoreDocumentCxxSpecJSI(std::move(jsInvoker)), instance_(instance) { + + } + + void documentOnSnapshot(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, jsi::String path, double listenerId, jsi::Object snapshotListenOptions) override { + static_assert( + bridging::getParameterCount(&T::documentOnSnapshot) == 6, + "Expected documentOnSnapshot(...) to have 6 parameters"); + + return bridging::callFromJs( + rt, &T::documentOnSnapshot, jsInvoker_, instance_, std::move(appName), std::move(databaseId), std::move(path), std::move(listenerId), std::move(snapshotListenOptions)); + } + void documentOffSnapshot(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, double listenerId) override { + static_assert( + bridging::getParameterCount(&T::documentOffSnapshot) == 4, + "Expected documentOffSnapshot(...) to have 4 parameters"); + + return bridging::callFromJs( + rt, &T::documentOffSnapshot, jsInvoker_, instance_, std::move(appName), std::move(databaseId), std::move(listenerId)); + } + jsi::Value documentGet(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, jsi::String path, std::optional getOptions) override { + static_assert( + bridging::getParameterCount(&T::documentGet) == 5, + "Expected documentGet(...) to have 5 parameters"); + + return bridging::callFromJs( + rt, &T::documentGet, jsInvoker_, instance_, std::move(appName), std::move(databaseId), std::move(path), std::move(getOptions)); + } + jsi::Value documentDelete(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, jsi::String path) override { + static_assert( + bridging::getParameterCount(&T::documentDelete) == 4, + "Expected documentDelete(...) to have 4 parameters"); + + return bridging::callFromJs( + rt, &T::documentDelete, jsInvoker_, instance_, std::move(appName), std::move(databaseId), std::move(path)); + } + jsi::Value documentSet(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, jsi::String path, jsi::Object data, jsi::Object options) override { + static_assert( + bridging::getParameterCount(&T::documentSet) == 6, + "Expected documentSet(...) to have 6 parameters"); + + return bridging::callFromJs( + rt, &T::documentSet, jsInvoker_, instance_, std::move(appName), std::move(databaseId), std::move(path), std::move(data), std::move(options)); + } + jsi::Value documentUpdate(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, jsi::String path, jsi::Object data) override { + static_assert( + bridging::getParameterCount(&T::documentUpdate) == 5, + "Expected documentUpdate(...) to have 5 parameters"); + + return bridging::callFromJs( + rt, &T::documentUpdate, jsInvoker_, instance_, std::move(appName), std::move(databaseId), std::move(path), std::move(data)); + } + jsi::Value documentBatch(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, jsi::Array writes) override { + static_assert( + bridging::getParameterCount(&T::documentBatch) == 4, + "Expected documentBatch(...) to have 4 parameters"); + + return bridging::callFromJs( + rt, &T::documentBatch, jsInvoker_, instance_, std::move(appName), std::move(databaseId), std::move(writes)); + } + + private: + friend class NativeRNFBTurboFirestoreDocumentCxxSpec; + T *instance_; + }; + + Delegate delegate_; +}; + + + class JSI_EXPORT NativeRNFBTurboFirestoreTransactionCxxSpecJSI : public TurboModule { +protected: + NativeRNFBTurboFirestoreTransactionCxxSpecJSI(std::shared_ptr jsInvoker); + +public: + virtual void transactionBegin(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, double transactionId) = 0; + virtual jsi::Value transactionGetDocument(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, double transactionId, jsi::String path) = 0; + virtual void transactionDispose(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, double transactionId) = 0; + virtual void transactionApplyBuffer(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, double transactionId, jsi::Array commandBuffer) = 0; + +}; + +template +class JSI_EXPORT NativeRNFBTurboFirestoreTransactionCxxSpec : public TurboModule { +public: + jsi::Value create(jsi::Runtime &rt, const jsi::PropNameID &propName) override { + return delegate_.create(rt, propName); + } + + std::vector getPropertyNames(jsi::Runtime& runtime) override { + return delegate_.getPropertyNames(runtime); + } + + static constexpr std::string_view kModuleName = "NativeRNFBTurboFirestoreTransaction"; + +protected: + NativeRNFBTurboFirestoreTransactionCxxSpec(std::shared_ptr jsInvoker) + : TurboModule(std::string{NativeRNFBTurboFirestoreTransactionCxxSpec::kModuleName}, jsInvoker), + delegate_(reinterpret_cast(this), jsInvoker) {} + + +private: + class Delegate : public NativeRNFBTurboFirestoreTransactionCxxSpecJSI { + public: + Delegate(T *instance, std::shared_ptr jsInvoker) : + NativeRNFBTurboFirestoreTransactionCxxSpecJSI(std::move(jsInvoker)), instance_(instance) { + + } + + void transactionBegin(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, double transactionId) override { + static_assert( + bridging::getParameterCount(&T::transactionBegin) == 4, + "Expected transactionBegin(...) to have 4 parameters"); + + return bridging::callFromJs( + rt, &T::transactionBegin, jsInvoker_, instance_, std::move(appName), std::move(databaseId), std::move(transactionId)); + } + jsi::Value transactionGetDocument(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, double transactionId, jsi::String path) override { + static_assert( + bridging::getParameterCount(&T::transactionGetDocument) == 5, + "Expected transactionGetDocument(...) to have 5 parameters"); + + return bridging::callFromJs( + rt, &T::transactionGetDocument, jsInvoker_, instance_, std::move(appName), std::move(databaseId), std::move(transactionId), std::move(path)); + } + void transactionDispose(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, double transactionId) override { + static_assert( + bridging::getParameterCount(&T::transactionDispose) == 4, + "Expected transactionDispose(...) to have 4 parameters"); + + return bridging::callFromJs( + rt, &T::transactionDispose, jsInvoker_, instance_, std::move(appName), std::move(databaseId), std::move(transactionId)); + } + void transactionApplyBuffer(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, double transactionId, jsi::Array commandBuffer) override { + static_assert( + bridging::getParameterCount(&T::transactionApplyBuffer) == 5, + "Expected transactionApplyBuffer(...) to have 5 parameters"); + + return bridging::callFromJs( + rt, &T::transactionApplyBuffer, jsInvoker_, instance_, std::move(appName), std::move(databaseId), std::move(transactionId), std::move(commandBuffer)); + } + + private: + friend class NativeRNFBTurboFirestoreTransactionCxxSpec; + T *instance_; + }; + + Delegate delegate_; +}; + +} // namespace facebook::react diff --git a/packages/firestore/ios/RNFBFirestore.xcodeproj/project.pbxproj b/packages/firestore/ios/RNFBFirestore.xcodeproj/project.pbxproj index 9f15e6c527..01bf93de3a 100644 --- a/packages/firestore/ios/RNFBFirestore.xcodeproj/project.pbxproj +++ b/packages/firestore/ios/RNFBFirestore.xcodeproj/project.pbxproj @@ -7,14 +7,14 @@ objects = { /* Begin PBXBuildFile section */ - 2744B98621F45429004F8E3F /* RNFBFirestoreModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 2744B98521F45429004F8E3F /* RNFBFirestoreModule.m */; }; + 2744B98621F45429004F8E3F /* RNFBFirestoreModule.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2744B98521F45429004F8E3F /* RNFBFirestoreModule.mm */; }; 8B21821222CB9C4700A0A296 /* RCTConvert+FIRLoggerLevel.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B21821122CB9C4700A0A296 /* RCTConvert+FIRLoggerLevel.m */; }; 8B627A8122CB9ECD0056BCB3 /* RNFBFirestoreCommon.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B627A8022CB9ECD0056BCB3 /* RNFBFirestoreCommon.m */; }; - 8B9B6AE522CC9AC50062975D /* RNFBFirestoreDocumentModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B9B6AE422CC9AC50062975D /* RNFBFirestoreDocumentModule.m */; }; + 8B9B6AE522CC9AC50062975D /* RNFBFirestoreDocumentModule.mm in Sources */ = {isa = PBXBuildFile; fileRef = 8B9B6AE422CC9AC50062975D /* RNFBFirestoreDocumentModule.mm */; }; 8B9B6AE922CC9DBD0062975D /* RNFBFirestoreSerialize.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B9B6AE822CC9DBD0062975D /* RNFBFirestoreSerialize.m */; }; - 8B9B6AED22CCE11D0062975D /* RNFBFirestoreCollectionModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B9B6AEC22CCE11D0062975D /* RNFBFirestoreCollectionModule.m */; }; + 8B9B6AED22CCE11D0062975D /* RNFBFirestoreCollectionModule.mm in Sources */ = {isa = PBXBuildFile; fileRef = 8B9B6AEC22CCE11D0062975D /* RNFBFirestoreCollectionModule.mm */; }; 8B9B6AF122CCE2B90062975D /* RNFBFirestoreQuery.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B9B6AF022CCE2B90062975D /* RNFBFirestoreQuery.m */; }; - 8B9B6AF722D634AC0062975D /* RNFBFirestoreTransactionModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B9B6AF622D634AC0062975D /* RNFBFirestoreTransactionModule.m */; }; + 8B9B6AF722D634AC0062975D /* RNFBFirestoreTransactionModule.mm in Sources */ = {isa = PBXBuildFile; fileRef = 8B9B6AF622D634AC0062975D /* RNFBFirestoreTransactionModule.mm */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -32,21 +32,21 @@ /* Begin PBXFileReference section */ 2744B98221F45429004F8E3F /* libRNFBFirestore.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRNFBFirestore.a; sourceTree = BUILT_PRODUCTS_DIR; }; 2744B98421F45429004F8E3F /* RNFBFirestoreModule.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = RNFBFirestoreModule.h; path = RNFBFirestore/RNFBFirestoreModule.h; sourceTree = SOURCE_ROOT; }; - 2744B98521F45429004F8E3F /* RNFBFirestoreModule.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = RNFBFirestoreModule.m; path = RNFBFirestore/RNFBFirestoreModule.m; sourceTree = SOURCE_ROOT; }; + 2744B98521F45429004F8E3F /* RNFBFirestoreModule.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = RNFBFirestoreModule.mm; path = RNFBFirestore/RNFBFirestoreModule.mm; sourceTree = SOURCE_ROOT; }; 8B21821022CB9C3800A0A296 /* RCTConvert+FIRLoggerLevel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "RCTConvert+FIRLoggerLevel.h"; sourceTree = ""; }; 8B21821122CB9C4700A0A296 /* RCTConvert+FIRLoggerLevel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "RCTConvert+FIRLoggerLevel.m"; sourceTree = ""; }; 8B627A7F22CB9EC00056BCB3 /* RNFBFirestoreCommon.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNFBFirestoreCommon.h; sourceTree = ""; }; 8B627A8022CB9ECD0056BCB3 /* RNFBFirestoreCommon.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNFBFirestoreCommon.m; sourceTree = ""; }; 8B9B6AE322CC9AB90062975D /* RNFBFirestoreDocumentModule.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNFBFirestoreDocumentModule.h; sourceTree = ""; }; - 8B9B6AE422CC9AC50062975D /* RNFBFirestoreDocumentModule.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNFBFirestoreDocumentModule.m; sourceTree = ""; }; + 8B9B6AE422CC9AC50062975D /* RNFBFirestoreDocumentModule.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNFBFirestoreDocumentModule.mm; sourceTree = ""; }; 8B9B6AE722CC9DB20062975D /* RNFBFirestoreSerialize.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNFBFirestoreSerialize.h; sourceTree = ""; }; 8B9B6AE822CC9DBD0062975D /* RNFBFirestoreSerialize.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNFBFirestoreSerialize.m; sourceTree = ""; }; 8B9B6AEB22CCE1120062975D /* RNFBFirestoreCollectionModule.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNFBFirestoreCollectionModule.h; sourceTree = ""; }; - 8B9B6AEC22CCE11D0062975D /* RNFBFirestoreCollectionModule.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNFBFirestoreCollectionModule.m; sourceTree = ""; }; + 8B9B6AEC22CCE11D0062975D /* RNFBFirestoreCollectionModule.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNFBFirestoreCollectionModule.mm; sourceTree = ""; }; 8B9B6AEF22CCE2AF0062975D /* RNFBFirestoreQuery.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNFBFirestoreQuery.h; sourceTree = ""; }; 8B9B6AF022CCE2B90062975D /* RNFBFirestoreQuery.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNFBFirestoreQuery.m; sourceTree = ""; }; 8B9B6AF522D634A00062975D /* RNFBFirestoreTransactionModule.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNFBFirestoreTransactionModule.h; sourceTree = ""; }; - 8B9B6AF622D634AC0062975D /* RNFBFirestoreTransactionModule.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNFBFirestoreTransactionModule.m; sourceTree = ""; }; + 8B9B6AF622D634AC0062975D /* RNFBFirestoreTransactionModule.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNFBFirestoreTransactionModule.mm; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -72,21 +72,21 @@ isa = PBXGroup; children = ( 2744B98421F45429004F8E3F /* RNFBFirestoreModule.h */, - 2744B98521F45429004F8E3F /* RNFBFirestoreModule.m */, + 2744B98521F45429004F8E3F /* RNFBFirestoreModule.mm */, 8B21821022CB9C3800A0A296 /* RCTConvert+FIRLoggerLevel.h */, 8B21821122CB9C4700A0A296 /* RCTConvert+FIRLoggerLevel.m */, 8B627A7F22CB9EC00056BCB3 /* RNFBFirestoreCommon.h */, 8B627A8022CB9ECD0056BCB3 /* RNFBFirestoreCommon.m */, 8B9B6AE322CC9AB90062975D /* RNFBFirestoreDocumentModule.h */, - 8B9B6AE422CC9AC50062975D /* RNFBFirestoreDocumentModule.m */, + 8B9B6AE422CC9AC50062975D /* RNFBFirestoreDocumentModule.mm */, 8B9B6AE722CC9DB20062975D /* RNFBFirestoreSerialize.h */, 8B9B6AE822CC9DBD0062975D /* RNFBFirestoreSerialize.m */, 8B9B6AEB22CCE1120062975D /* RNFBFirestoreCollectionModule.h */, - 8B9B6AEC22CCE11D0062975D /* RNFBFirestoreCollectionModule.m */, + 8B9B6AEC22CCE11D0062975D /* RNFBFirestoreCollectionModule.mm */, 8B9B6AEF22CCE2AF0062975D /* RNFBFirestoreQuery.h */, 8B9B6AF022CCE2B90062975D /* RNFBFirestoreQuery.m */, 8B9B6AF522D634A00062975D /* RNFBFirestoreTransactionModule.h */, - 8B9B6AF622D634AC0062975D /* RNFBFirestoreTransactionModule.m */, + 8B9B6AF622D634AC0062975D /* RNFBFirestoreTransactionModule.mm */, ); path = RNFBFirestore; sourceTree = ""; @@ -159,12 +159,12 @@ buildActionMask = 2147483647; files = ( 8B9B6AF122CCE2B90062975D /* RNFBFirestoreQuery.m in Sources */, - 8B9B6AE522CC9AC50062975D /* RNFBFirestoreDocumentModule.m in Sources */, - 8B9B6AED22CCE11D0062975D /* RNFBFirestoreCollectionModule.m in Sources */, + 8B9B6AE522CC9AC50062975D /* RNFBFirestoreDocumentModule.mm in Sources */, + 8B9B6AED22CCE11D0062975D /* RNFBFirestoreCollectionModule.mm in Sources */, 8B21821222CB9C4700A0A296 /* RCTConvert+FIRLoggerLevel.m in Sources */, - 8B9B6AF722D634AC0062975D /* RNFBFirestoreTransactionModule.m in Sources */, + 8B9B6AF722D634AC0062975D /* RNFBFirestoreTransactionModule.mm in Sources */, 8B627A8122CB9ECD0056BCB3 /* RNFBFirestoreCommon.m in Sources */, - 2744B98621F45429004F8E3F /* RNFBFirestoreModule.m in Sources */, + 2744B98621F45429004F8E3F /* RNFBFirestoreModule.mm in Sources */, 8B9B6AE922CC9DBD0062975D /* RNFBFirestoreSerialize.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/packages/firestore/ios/RNFBFirestore/RNFBFirestoreCollectionModule.m b/packages/firestore/ios/RNFBFirestore/RNFBFirestoreCollectionModule.mm similarity index 76% rename from packages/firestore/ios/RNFBFirestore/RNFBFirestoreCollectionModule.m rename to packages/firestore/ios/RNFBFirestore/RNFBFirestoreCollectionModule.mm index dd21cf1896..93535aea50 100644 --- a/packages/firestore/ios/RNFBFirestore/RNFBFirestoreCollectionModule.m +++ b/packages/firestore/ios/RNFBFirestore/RNFBFirestoreCollectionModule.mm @@ -27,26 +27,33 @@ // directory. See firebase-ios-sdk#12611 for more context. #import "RNFBFirestore-Swift.h" #endif +#import "RNFBApp/RCTConvert+FIRApp.h" +#import #import #import "RNFBFirestoreCollectionModule.h" #import "RNFBFirestoreCommon.h" +#import "RNFBFirestoreTurboModules.h" static __strong NSMutableDictionary *collectionSnapshotListeners; static NSString *const RNFB_FIRESTORE_COLLECTION_SYNC = @"firestore_collection_sync_event"; +@interface RNFBFirestoreCollectionModule () +@end + @implementation RNFBFirestoreCollectionModule #pragma mark - #pragma mark Module Setup -RCT_EXPORT_MODULE(); - -- (dispatch_queue_t)methodQueue { - return [RNFBFirestoreCommon getFirestoreQueue]; +- (std::shared_ptr)getTurboModule: + (const facebook::react::ObjCTurboModule::InitParams &)params { + return std::make_shared(params); } +RCT_EXPORT_MODULE(NativeRNFBTurboFirestoreCollection); + + (BOOL)requiresMainQueueSetup { - return YES; + return NO; } - (id)init { @@ -73,28 +80,30 @@ - (void)invalidate { #pragma mark - #pragma mark Firebase Firestore Methods -RCT_EXPORT_METHOD(namedQueryOnSnapshot - : (FIRApp *)firebaseApp - : (NSString *)databaseId - : (NSString *)name - : (NSString *)type - : (NSArray *)filters - : (NSArray *)orders - : (NSDictionary *)options - : (nonnull NSNumber *)listenerId - : (NSDictionary *)listenerOptions) { - if (collectionSnapshotListeners[listenerId]) { +- (void)namedQueryOnSnapshot:(NSString *)appName + databaseId:(NSString *)databaseId + queryName:(NSString *)queryName + type:(NSString *)type + filters:(NSArray *)filters + orders:(NSArray *)orders + options:(NSDictionary *)options + listenerId:(double)listenerId + snapshotListenOptions:(NSDictionary *)snapshotListenOptions { + FIRApp *firebaseApp = [RCTConvert firAppFromString:appName]; + NSNumber *listenerIdNumber = @(listenerId); + + if (collectionSnapshotListeners[listenerIdNumber]) { return; } FIRFirestore *firestore = [RNFBFirestoreCommon getFirestoreForApp:firebaseApp databaseId:databaseId]; - [firestore getQueryNamed:name + [firestore getQueryNamed:queryName completion:^(FIRQuery *query) { if (query == nil) { [self sendSnapshotError:firebaseApp databaseId:databaseId - listenerId:listenerId + listenerId:listenerIdNumber error:nil]; return; } @@ -108,22 +117,24 @@ - (void)invalidate { [self handleQueryOnSnapshot:firebaseApp databaseId:databaseId firestoreQuery:firestoreQuery - listenerId:listenerId - listenerOptions:listenerOptions]; + listenerId:listenerIdNumber + listenerOptions:snapshotListenOptions]; }]; } -RCT_EXPORT_METHOD(collectionOnSnapshot - : (FIRApp *)firebaseApp - : (NSString *)databaseId - : (NSString *)path - : (NSString *)type - : (NSArray *)filters - : (NSArray *)orders - : (NSDictionary *)options - : (nonnull NSNumber *)listenerId - : (NSDictionary *)listenerOptions) { - if (collectionSnapshotListeners[listenerId]) { +- (void)collectionOnSnapshot:(NSString *)appName + databaseId:(NSString *)databaseId + path:(NSString *)path + type:(NSString *)type + filters:(NSArray *)filters + orders:(NSArray *)orders + options:(NSDictionary *)options + listenerId:(double)listenerId + snapshotListenOptions:(NSDictionary *)snapshotListenOptions { + FIRApp *firebaseApp = [RCTConvert firAppFromString:appName]; + NSNumber *listenerIdNumber = @(listenerId); + + if (collectionSnapshotListeners[listenerIdNumber]) { return; } @@ -139,35 +150,36 @@ - (void)invalidate { [self handleQueryOnSnapshot:firebaseApp databaseId:databaseId firestoreQuery:firestoreQuery - listenerId:listenerId - listenerOptions:listenerOptions]; + listenerId:listenerIdNumber + listenerOptions:snapshotListenOptions]; } -RCT_EXPORT_METHOD(collectionOffSnapshot - : (FIRApp *)firebaseApp - : (NSString *)databaseId - : (nonnull NSNumber *)listenerId) { - id listener = collectionSnapshotListeners[listenerId]; +- (void)collectionOffSnapshot:(NSString *)appName + databaseId:(NSString *)databaseId + listenerId:(double)listenerId { + NSNumber *listenerIdNumber = @(listenerId); + id listener = collectionSnapshotListeners[listenerIdNumber]; if (listener) { [listener remove]; - [collectionSnapshotListeners removeObjectForKey:listenerId]; + [collectionSnapshotListeners removeObjectForKey:listenerIdNumber]; } } -RCT_EXPORT_METHOD(namedQueryGet - : (FIRApp *)firebaseApp - : (NSString *)databaseId - : (NSString *)name - : (NSString *)type - : (NSArray *)filters - : (NSArray *)orders - : (NSDictionary *)options - : (NSDictionary *)getOptions - : (RCTPromiseResolveBlock)resolve - : (RCTPromiseRejectBlock)reject) { +- (void)namedQueryGet:(NSString *)appName + databaseId:(NSString *)databaseId + queryName:(NSString *)queryName + type:(NSString *)type + filters:(NSArray *)filters + orders:(NSArray *)orders + options:(NSDictionary *)options + getOptions:(NSDictionary *)getOptions + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject { + FIRApp *firebaseApp = [RCTConvert firAppFromString:appName]; + FIRFirestore *firestore = [RNFBFirestoreCommon getFirestoreForApp:firebaseApp databaseId:databaseId]; - [firestore getQueryNamed:name + [firestore getQueryNamed:queryName completion:^(FIRQuery *query) { if (query == nil) { return [RNFBFirestoreCommon promiseRejectFirestoreException:reject error:nil]; @@ -189,16 +201,17 @@ - (void)invalidate { }]; } -RCT_EXPORT_METHOD(collectionCount - : (FIRApp *)firebaseApp - : (NSString *)databaseId - : (NSString *)path - : (NSString *)type - : (NSArray *)filters - : (NSArray *)orders - : (NSDictionary *)options - : (RCTPromiseResolveBlock)resolve - : (RCTPromiseRejectBlock)reject) { +- (void)collectionCount:(NSString *)appName + databaseId:(NSString *)databaseId + path:(NSString *)path + type:(NSString *)type + filters:(NSArray *)filters + orders:(NSArray *)orders + options:(NSDictionary *)options + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject { + FIRApp *firebaseApp = [RCTConvert firAppFromString:appName]; + FIRFirestore *firestore = [RNFBFirestoreCommon getFirestoreForApp:firebaseApp databaseId:databaseId]; FIRQuery *query = [RNFBFirestoreCommon getQueryForFirestore:firestore path:path type:type]; @@ -228,17 +241,19 @@ - (void)invalidate { }]; } -RCT_EXPORT_METHOD(aggregateQuery - : (FIRApp *)firebaseApp - : (NSString *)databaseId - : (NSString *)path - : (NSString *)type - : (NSArray *)filters - : (NSArray *)orders - : (NSDictionary *)options - : (NSArray *)aggregateQueries - : (RCTPromiseResolveBlock)resolve - : (RCTPromiseRejectBlock)reject) { +- (void)aggregateQuery:(NSString *)appName + databaseId:(NSString *)databaseId + path:(NSString *)path + type:(NSString *)type + filters:(NSArray *)filters + orders:(NSArray *)orders + options:(NSDictionary *)options + aggregateQueries:(NSArray *)aggregateQueries + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject { + FIRApp *firebaseApp = [RCTConvert firAppFromString:appName]; + NSArray *aggregateQueriesArray = aggregateQueries; + FIRFirestore *firestore = [RNFBFirestoreCommon getFirestoreForApp:firebaseApp databaseId:databaseId]; @@ -257,9 +272,9 @@ - (void)invalidate { NSMutableArray *aggregateFields = [[NSMutableArray alloc] init]; - for (NSDictionary *aggregateQuery in aggregateQueries) { - NSString *aggregateType = aggregateQuery[@"aggregateType"]; - NSString *fieldPath = aggregateQuery[@"field"]; + for (NSDictionary *aggregateQueryItem in aggregateQueriesArray) { + NSString *aggregateType = aggregateQueryItem[@"aggregateType"]; + NSString *fieldPath = aggregateQueryItem[@"field"]; if ([aggregateType isEqualToString:@"count"]) { [aggregateFields addObject:[FIRAggregateField aggregateFieldForCount]]; @@ -271,17 +286,16 @@ - (void)invalidate { NSString *reason = [@"Invalid Aggregate Type: " stringByAppendingString:aggregateType]; [RNFBFirestoreCommon promiseRejectFirestoreException:reject - error:[NSException exceptionWithName: - @"RNFB Firestore: Invalid Aggregate Type" - reason:reason - userInfo:nil]]; + error:[NSError errorWithDomain:@"RNFB Firestore" + code:0 + userInfo:@{NSLocalizedDescriptionKey : reason}]]; return; } } - FIRAggregateQuery *aggregateQuery = [query aggregate:aggregateFields]; + FIRAggregateQuery *aggregateQueryInstance = [query aggregate:aggregateFields]; - [aggregateQuery + [aggregateQueryInstance aggregationWithSource:FIRAggregateSourceServer completion:^(FIRAggregateQuerySnapshot *_Nullable snapshot, NSError *_Nullable error) { @@ -290,10 +304,10 @@ - (void)invalidate { } else { NSMutableDictionary *snapshotMap = [NSMutableDictionary dictionary]; - for (NSDictionary *aggregateQuery in aggregateQueries) { - NSString *aggregateType = aggregateQuery[@"aggregateType"]; - NSString *fieldPath = aggregateQuery[@"field"]; - NSString *key = aggregateQuery[@"key"]; + for (NSDictionary *aggregateQueryItem in aggregateQueriesArray) { + NSString *aggregateType = aggregateQueryItem[@"aggregateType"]; + NSString *fieldPath = aggregateQueryItem[@"field"]; + NSString *key = aggregateQueryItem[@"key"]; if ([aggregateType isEqualToString:@"count"]) { snapshotMap[key] = snapshot.count; @@ -314,13 +328,14 @@ - (void)invalidate { }]; } -RCT_EXPORT_METHOD(pipelineExecute - : (FIRApp *)firebaseApp - : (NSString *)databaseId - : (NSDictionary *)pipeline - : (NSDictionary *)options - : (RCTPromiseResolveBlock)resolve - : (RCTPromiseRejectBlock)reject) { +- (void)pipelineExecute:(NSString *)appName + databaseId:(NSString *)databaseId + pipeline:(NSDictionary *)pipeline + options:(NSDictionary *)options + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject { + FIRApp *firebaseApp = [RCTConvert firAppFromString:appName]; + FIRFirestore *firestore = [RNFBFirestoreCommon getFirestoreForApp:firebaseApp databaseId:databaseId]; RNFBFirestorePipelineCallHandler *handler = [[RNFBFirestorePipelineCallHandler alloc] init]; @@ -352,17 +367,18 @@ - (void)invalidate { }]; } -RCT_EXPORT_METHOD(collectionGet - : (FIRApp *)firebaseApp - : (NSString *)databaseId - : (NSString *)path - : (NSString *)type - : (NSArray *)filters - : (NSArray *)orders - : (NSDictionary *)options - : (NSDictionary *)getOptions - : (RCTPromiseResolveBlock)resolve - : (RCTPromiseRejectBlock)reject) { +- (void)collectionGet:(NSString *)appName + databaseId:(NSString *)databaseId + path:(NSString *)path + type:(NSString *)type + filters:(NSArray *)filters + orders:(NSArray *)orders + options:(NSDictionary *)options + getOptions:(NSDictionary *)getOptions + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject { + FIRApp *firebaseApp = [RCTConvert firAppFromString:appName]; + FIRFirestore *firestore = [RNFBFirestoreCommon getFirestoreForApp:firebaseApp databaseId:databaseId]; FIRQuery *query = [RNFBFirestoreCommon getQueryForFirestore:firestore path:path type:type]; diff --git a/packages/firestore/ios/RNFBFirestore/RNFBFirestoreDocumentModule.m b/packages/firestore/ios/RNFBFirestore/RNFBFirestoreDocumentModule.mm similarity index 72% rename from packages/firestore/ios/RNFBFirestore/RNFBFirestoreDocumentModule.m rename to packages/firestore/ios/RNFBFirestore/RNFBFirestoreDocumentModule.mm index 6e51e42d12..6b61b0b212 100644 --- a/packages/firestore/ios/RNFBFirestore/RNFBFirestoreDocumentModule.m +++ b/packages/firestore/ios/RNFBFirestore/RNFBFirestoreDocumentModule.mm @@ -16,25 +16,31 @@ */ #import +#import "RNFBApp/RCTConvert+FIRApp.h" #import #import "RNFBFirestoreDocumentModule.h" +#import "RNFBFirestoreTurboModules.h" static __strong NSMutableDictionary *documentSnapshotListeners; static NSString *const RNFB_FIRESTORE_DOCUMENT_SYNC = @"firestore_document_sync_event"; +@interface RNFBFirestoreDocumentModule () +@end + @implementation RNFBFirestoreDocumentModule #pragma mark - #pragma mark Module Setup -RCT_EXPORT_MODULE(); - -- (dispatch_queue_t)methodQueue { - return [RNFBFirestoreCommon getFirestoreQueue]; +- (std::shared_ptr)getTurboModule: + (const facebook::react::ObjCTurboModule::InitParams &)params { + return std::make_shared(params); } +RCT_EXPORT_MODULE(NativeRNFBTurboFirestoreDocument); + + (BOOL)requiresMainQueueSetup { - return YES; + return NO; } - (id)init { @@ -61,16 +67,29 @@ - (void)invalidate { #pragma mark - #pragma mark Firebase Firestore Methods -RCT_EXPORT_METHOD(documentOnSnapshot - : (FIRApp *)firebaseApp - : (NSString *)databaseId - : (NSString *)path - : (nonnull NSNumber *)listenerId - : (NSDictionary *)listenerOptions) { - if (documentSnapshotListeners[listenerId]) { +- (void)documentOnSnapshot:(NSString *)appName + databaseId:(NSString *)databaseId + path:(NSString *)path + listenerId:(double)listenerId + snapshotListenOptions: + (JS::NativeRNFBTurboFirestoreDocument::FirestoreSnapshotListenOptions &)snapshotListenOptions { + FIRApp *firebaseApp = [RCTConvert firAppFromString:appName]; + NSNumber *listenerIdNumber = @(listenerId); + + if (documentSnapshotListeners[listenerIdNumber]) { return; } + NSMutableDictionary *listenerOptions = [NSMutableDictionary new]; + auto includeMetadataChangesOpt = snapshotListenOptions.includeMetadataChanges(); + if (includeMetadataChangesOpt.has_value()) { + listenerOptions[KEY_INCLUDE_METADATA_CHANGES] = @(*includeMetadataChangesOpt); + } + NSString *sourceString = snapshotListenOptions.source(); + if (sourceString) { + listenerOptions[KEY_SOURCE] = sourceString; + } + FIRFirestore *firestore = [RNFBFirestoreCommon getFirestoreForApp:firebaseApp databaseId:databaseId]; FIRDocumentReference *documentReference = [RNFBFirestoreCommon getDocumentForFirestore:firestore @@ -79,19 +98,19 @@ - (void)invalidate { __weak RNFBFirestoreDocumentModule *weakSelf = self; id listenerBlock = ^(FIRDocumentSnapshot *snapshot, NSError *error) { if (error) { - id listener = documentSnapshotListeners[listenerId]; + id listener = documentSnapshotListeners[listenerIdNumber]; if (listener) { [listener remove]; - [documentSnapshotListeners removeObjectForKey:listenerId]; + [documentSnapshotListeners removeObjectForKey:listenerIdNumber]; } [weakSelf sendSnapshotError:firebaseApp databaseId:databaseId - listenerId:listenerId + listenerId:listenerIdNumber error:error]; } else { [weakSelf sendSnapshotEvent:firebaseApp databaseId:databaseId - listenerId:listenerId + listenerId:listenerIdNumber snapshot:snapshot]; } }; @@ -105,43 +124,45 @@ - (void)invalidate { source = FIRListenSourceCache; } - FIRSnapshotListenOptions *snapshotListenOptions = [[[[FIRSnapshotListenOptions alloc] init] + FIRSnapshotListenOptions *nativeSnapshotListenOptions = [[[[FIRSnapshotListenOptions alloc] init] optionsWithIncludeMetadataChanges:includeMetadataChanges] optionsWithSource:source]; id listener = - [documentReference addSnapshotListenerWithOptions:snapshotListenOptions + [documentReference addSnapshotListenerWithOptions:nativeSnapshotListenOptions listener:listenerBlock]; - documentSnapshotListeners[listenerId] = listener; + documentSnapshotListeners[listenerIdNumber] = listener; } -RCT_EXPORT_METHOD(documentOffSnapshot - : (FIRApp *)firebaseApp - : (NSString *)databaseId - : (nonnull NSNumber *)listenerId) { - id listener = documentSnapshotListeners[listenerId]; +- (void)documentOffSnapshot:(NSString *)appName + databaseId:(NSString *)databaseId + listenerId:(double)listenerId { + NSNumber *listenerIdNumber = @(listenerId); + id listener = documentSnapshotListeners[listenerIdNumber]; if (listener) { [listener remove]; - [documentSnapshotListeners removeObjectForKey:listenerId]; + [documentSnapshotListeners removeObjectForKey:listenerIdNumber]; } } -RCT_EXPORT_METHOD(documentGet - : (FIRApp *)firebaseApp - : (NSString *)databaseId - : (NSString *)path - : (NSDictionary *)getOptions - : (RCTPromiseResolveBlock)resolve - : (RCTPromiseRejectBlock)reject) { +- (void)documentGet:(NSString *)appName + databaseId:(NSString *)databaseId + path:(NSString *)path + getOptions:(JS::NativeRNFBTurboFirestoreDocument::SpecDocumentGetGetOptions &)getOptions + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject { + FIRApp *firebaseApp = [RCTConvert firAppFromString:appName]; + FIRFirestore *firestore = [RNFBFirestoreCommon getFirestoreForApp:firebaseApp databaseId:databaseId]; FIRDocumentReference *documentReference = [RNFBFirestoreCommon getDocumentForFirestore:firestore path:path]; FIRFirestoreSource source; + NSString *sourceString = getOptions.source(); - if (getOptions[@"source"]) { - if ([getOptions[@"source"] isEqualToString:@"server"]) { + if (sourceString) { + if ([sourceString isEqualToString:@"server"]) { source = FIRFirestoreSourceServer; - } else if ([getOptions[@"source"] isEqualToString:@"cache"]) { + } else if ([sourceString isEqualToString:@"cache"]) { source = FIRFirestoreSourceCache; } else { source = FIRFirestoreSourceDefault; @@ -157,9 +178,10 @@ - (void)invalidate { return [RNFBFirestoreCommon promiseRejectFirestoreException:reject error:error]; } else { - NSString *appName = [RNFBSharedUtils getAppJavaScriptName:firebaseApp.name]; + NSString *resolvedAppName = + [RNFBSharedUtils getAppJavaScriptName:firebaseApp.name]; NSString *firestoreKey = - [RNFBFirestoreCommon createFirestoreKeyWithAppName:appName + [RNFBFirestoreCommon createFirestoreKeyWithAppName:resolvedAppName databaseId:databaseId]; NSDictionary *serialized = [RNFBFirestoreSerialize documentSnapshotToDictionary:snapshot @@ -169,12 +191,13 @@ - (void)invalidate { }]; } -RCT_EXPORT_METHOD(documentDelete - : (FIRApp *)firebaseApp - : (NSString *)databaseId - : (NSString *)path - : (RCTPromiseResolveBlock)resolve - : (RCTPromiseRejectBlock)reject) { +- (void)documentDelete:(NSString *)appName + databaseId:(NSString *)databaseId + path:(NSString *)path + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject { + FIRApp *firebaseApp = [RCTConvert firAppFromString:appName]; + FIRFirestore *firestore = [RNFBFirestoreCommon getFirestoreForApp:firebaseApp databaseId:databaseId]; FIRDocumentReference *documentReference = [RNFBFirestoreCommon getDocumentForFirestore:firestore @@ -189,14 +212,15 @@ - (void)invalidate { }]; } -RCT_EXPORT_METHOD(documentSet - : (FIRApp *)firebaseApp - : (NSString *)databaseId - : (NSString *)path - : (NSDictionary *)data - : (NSDictionary *)options - : (RCTPromiseResolveBlock)resolve - : (RCTPromiseRejectBlock)reject) { +- (void)documentSet:(NSString *)appName + databaseId:(NSString *)databaseId + path:(NSString *)path + data:(NSDictionary *)data + options:(NSDictionary *)options + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject { + FIRApp *firebaseApp = [RCTConvert firAppFromString:appName]; + FIRFirestore *firestore = [RNFBFirestoreCommon getFirestoreForApp:firebaseApp databaseId:databaseId]; FIRDocumentReference *documentReference = [RNFBFirestoreCommon getDocumentForFirestore:firestore @@ -223,13 +247,14 @@ - (void)invalidate { } } -RCT_EXPORT_METHOD(documentUpdate - : (FIRApp *)firebaseApp - : (NSString *)databaseId - : (NSString *)path - : (NSDictionary *)data - : (RCTPromiseResolveBlock)resolve - : (RCTPromiseRejectBlock)reject) { +- (void)documentUpdate:(NSString *)appName + databaseId:(NSString *)databaseId + path:(NSString *)path + data:(NSDictionary *)data + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject { + FIRApp *firebaseApp = [RCTConvert firAppFromString:appName]; + FIRFirestore *firestore = [RNFBFirestoreCommon getFirestoreForApp:firebaseApp databaseId:databaseId]; FIRDocumentReference *documentReference = [RNFBFirestoreCommon getDocumentForFirestore:firestore @@ -248,12 +273,13 @@ - (void)invalidate { }]; } -RCT_EXPORT_METHOD(documentBatch - : (FIRApp *)firebaseApp - : (NSString *)databaseId - : (NSArray *)writes - : (RCTPromiseResolveBlock)resolve - : (RCTPromiseRejectBlock)reject) { +- (void)documentBatch:(NSString *)appName + databaseId:(NSString *)databaseId + writes:(NSArray *)writes + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject { + FIRApp *firebaseApp = [RCTConvert firAppFromString:appName]; + FIRFirestore *firestore = [RNFBFirestoreCommon getFirestoreForApp:firebaseApp databaseId:databaseId]; FIRWriteBatch *batch = [firestore batch]; diff --git a/packages/firestore/ios/RNFBFirestore/RNFBFirestoreModule.m b/packages/firestore/ios/RNFBFirestore/RNFBFirestoreModule.mm similarity index 65% rename from packages/firestore/ios/RNFBFirestore/RNFBFirestoreModule.m rename to packages/firestore/ios/RNFBFirestore/RNFBFirestoreModule.mm index 5b9c7a63c8..09d6d94035 100644 --- a/packages/firestore/ios/RNFBFirestore/RNFBFirestoreModule.m +++ b/packages/firestore/ios/RNFBFirestore/RNFBFirestoreModule.mm @@ -16,42 +16,53 @@ */ #import "RNFBFirestoreModule.h" +#import "RNFBApp/RCTConvert+FIRApp.h" #import +#import #import #import "FirebaseFirestoreInternal/FIRPersistentCacheIndexManager.h" #import "RNFBFirestoreCommon.h" #import "RNFBPreferences.h" +#import "RNFBFirestoreTurboModules.h" NSMutableDictionary *emulatorConfigs; static __strong NSMutableDictionary *snapshotsInSyncListeners; static NSString *const RNFB_FIRESTORE_SNAPSHOTS_IN_SYNC = @"firestore_snapshots_in_sync_event"; +@interface RNFBFirestoreModule () +@end + @implementation RNFBFirestoreModule #pragma mark - #pragma mark Module Setup -RCT_EXPORT_MODULE(); - -- (dispatch_queue_t)methodQueue { - return [RNFBFirestoreCommon getFirestoreQueue]; +- (std::shared_ptr)getTurboModule: + (const facebook::react::ObjCTurboModule::InitParams &)params { + return std::make_shared(params); } +RCT_EXPORT_MODULE(NativeRNFBTurboFirestore); + + (BOOL)requiresMainQueueSetup { - return YES; + return NO; } #pragma mark - #pragma mark Firebase Firestore Methods -RCT_EXPORT_METHOD(setLogLevel : (FIRLoggerLevel)loggerLevel) { - [[FIRConfiguration sharedInstance] setLoggerLevel:loggerLevel]; +- (void)setLogLevel:(NSString *)logLevel { + if ([logLevel isEqualToString:@"debug"] || [logLevel isEqualToString:@"error"]) { + [[FIRConfiguration sharedInstance] setLoggerLevel:FIRLoggerLevelDebug]; + } else { + [[FIRConfiguration sharedInstance] setLoggerLevel:FIRLoggerLevelMin]; + } } -RCT_EXPORT_METHOD(disableNetwork - : (FIRApp *)firebaseApp - : (NSString *)databaseId - : (RCTPromiseResolveBlock)resolve - : (RCTPromiseRejectBlock)reject) { +- (void)disableNetwork:(NSString *)appName + databaseId:(NSString *)databaseId + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject { + FIRApp *firebaseApp = [RCTConvert firAppFromString:appName]; [[RNFBFirestoreCommon getFirestoreForApp:firebaseApp databaseId:databaseId] disableNetworkWithCompletion:^(NSError *error) { if (error) { @@ -62,11 +73,11 @@ + (BOOL)requiresMainQueueSetup { }]; } -RCT_EXPORT_METHOD(enableNetwork - : (FIRApp *)firebaseApp - : (NSString *)databaseId - : (RCTPromiseResolveBlock)resolve - : (RCTPromiseRejectBlock)reject) { +- (void)enableNetwork:(NSString *)appName + databaseId:(NSString *)databaseId + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject { + FIRApp *firebaseApp = [RCTConvert firAppFromString:appName]; [[RNFBFirestoreCommon getFirestoreForApp:firebaseApp databaseId:databaseId] enableNetworkWithCompletion:^(NSError *error) { if (error) { @@ -77,13 +88,11 @@ + (BOOL)requiresMainQueueSetup { }]; } -RCT_EXPORT_METHOD(settings - : (FIRApp *)firebaseApp - : (NSString *)databaseId - : (NSDictionary *)settings - : (RCTPromiseResolveBlock)resolve - : (RCTPromiseRejectBlock)reject) { - NSString *appName = [RNFBSharedUtils getAppJavaScriptName:firebaseApp.name]; +- (void)settings:(NSString *)appName + databaseId:(NSString *)databaseId + settings:(NSDictionary *)settings + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject { NSString *firestoreKey = [RNFBFirestoreCommon createFirestoreKeyWithAppName:appName databaseId:databaseId]; @@ -119,12 +128,12 @@ + (BOOL)requiresMainQueueSetup { resolve([NSNull null]); } -RCT_EXPORT_METHOD(loadBundle - : (FIRApp *)firebaseApp - : (NSString *)databaseId - : (nonnull NSString *)bundle - : (RCTPromiseResolveBlock)resolve - : (RCTPromiseRejectBlock)reject) { +- (void)loadBundle:(NSString *)appName + databaseId:(NSString *)databaseId + bundle:(NSString *)bundle + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject { + FIRApp *firebaseApp = [RCTConvert firAppFromString:appName]; NSData *bundleData = [bundle dataUsingEncoding:NSUTF8StringEncoding]; [[RNFBFirestoreCommon getFirestoreForApp:firebaseApp databaseId:databaseId] loadBundle:bundleData @@ -137,11 +146,11 @@ + (BOOL)requiresMainQueueSetup { }]; } -RCT_EXPORT_METHOD(clearPersistence - : (FIRApp *)firebaseApp - : (NSString *)databaseId - : (RCTPromiseResolveBlock)resolve - : (RCTPromiseRejectBlock)reject) { +- (void)clearPersistence:(NSString *)appName + databaseId:(NSString *)databaseId + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject { + FIRApp *firebaseApp = [RCTConvert firAppFromString:appName]; [[RNFBFirestoreCommon getFirestoreForApp:firebaseApp databaseId:databaseId] clearPersistenceWithCompletion:^(NSError *error) { if (error) { @@ -152,35 +161,34 @@ + (BOOL)requiresMainQueueSetup { }]; } -RCT_EXPORT_METHOD(useEmulator - : (FIRApp *)firebaseApp - : (NSString *)databaseId - : (nonnull NSString *)host - : (NSInteger)port) { +- (void)useEmulator:(NSString *)appName + databaseId:(NSString *)databaseId + host:(NSString *)host + port:(double)port { + FIRApp *firebaseApp = [RCTConvert firAppFromString:appName]; if (emulatorConfigs == nil) { emulatorConfigs = [[NSMutableDictionary alloc] init]; } - NSString *firestoreKey = [RNFBFirestoreCommon createFirestoreKeyWithAppName:firebaseApp.name + NSString *firestoreKey = [RNFBFirestoreCommon createFirestoreKeyWithAppName:appName databaseId:databaseId]; if (!emulatorConfigs[firestoreKey]) { FIRFirestore *firestore = [RNFBFirestoreCommon getFirestoreForApp:firebaseApp databaseId:databaseId]; - [firestore useEmulatorWithHost:host port:port]; + [firestore useEmulatorWithHost:host port:(NSInteger)port]; emulatorConfigs[firestoreKey] = @YES; - // It is not sufficient to just use emulator. You have toggle SSL off too. FIRFirestoreSettings *settings = firestore.settings; settings.sslEnabled = FALSE; firestore.settings = settings; } } -RCT_EXPORT_METHOD(waitForPendingWrites - : (FIRApp *)firebaseApp - : (NSString *)databaseId - : (RCTPromiseResolveBlock)resolve - : (RCTPromiseRejectBlock)reject) { +- (void)waitForPendingWrites:(NSString *)appName + databaseId:(NSString *)databaseId + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject { + FIRApp *firebaseApp = [RCTConvert firAppFromString:appName]; [[RNFBFirestoreCommon getFirestoreForApp:firebaseApp databaseId:databaseId] waitForPendingWritesWithCompletion:^(NSError *error) { if (error) { @@ -191,11 +199,11 @@ + (BOOL)requiresMainQueueSetup { }]; } -RCT_EXPORT_METHOD(terminate - : (FIRApp *)firebaseApp - : (NSString *)databaseId - : (RCTPromiseResolveBlock)resolve - : (RCTPromiseRejectBlock)reject) { +- (void)terminate:(NSString *)appName + databaseId:(NSString *)databaseId + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject { + FIRApp *firebaseApp = [RCTConvert firAppFromString:appName]; FIRFirestore *instance = [RNFBFirestoreCommon getFirestoreForApp:firebaseApp databaseId:databaseId]; @@ -203,7 +211,7 @@ + (BOOL)requiresMainQueueSetup { if (error) { [RNFBFirestoreCommon promiseRejectFirestoreException:reject error:error]; } else { - NSString *firestoreKey = [RNFBFirestoreCommon createFirestoreKeyWithAppName:firebaseApp.name + NSString *firestoreKey = [RNFBFirestoreCommon createFirestoreKeyWithAppName:appName databaseId:databaseId]; [instanceCache removeObjectForKey:firestoreKey]; resolve(nil); @@ -211,18 +219,18 @@ + (BOOL)requiresMainQueueSetup { }]; } -RCT_EXPORT_METHOD(persistenceCacheIndexManager - : (FIRApp *)firebaseApp - : (NSString *)databaseId - : (NSInteger)requestType - : (RCTPromiseResolveBlock)resolve - : (RCTPromiseRejectBlock)reject) { +- (void)persistenceCacheIndexManager:(NSString *)appName + databaseId:(NSString *)databaseId + requestType:(double)requestType + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject { + FIRApp *firebaseApp = [RCTConvert firAppFromString:appName]; FIRPersistentCacheIndexManager *persistentCacheIndexManager = [RNFBFirestoreCommon getFirestoreForApp:firebaseApp databaseId:databaseId] .persistentCacheIndexManager; if (persistentCacheIndexManager) { - switch (requestType) { + switch ((NSInteger)requestType) { case 0: [persistentCacheIndexManager enableIndexAutoCreation]; break; @@ -243,14 +251,12 @@ + (BOOL)requiresMainQueueSetup { resolve(nil); } -RCT_EXPORT_METHOD(addSnapshotsInSync - : (FIRApp *)firebaseApp - : (NSString *)databaseId - : (nonnull NSNumber *)listenerId - : (RCTPromiseResolveBlock)resolve - : (RCTPromiseRejectBlock)reject) { - if (snapshotsInSyncListeners[listenerId]) { - resolve(nil); +- (void)addSnapshotsInSync:(NSString *)appName + databaseId:(NSString *)databaseId + listenerId:(double)listenerId { + FIRApp *firebaseApp = [RCTConvert firAppFromString:appName]; + NSNumber *listenerIdNumber = @(listenerId); + if (snapshotsInSyncListeners[listenerIdNumber]) { return; } @@ -261,31 +267,25 @@ + (BOOL)requiresMainQueueSetup { [[RNFBRCTEventEmitter shared] sendEventWithName:RNFB_FIRESTORE_SNAPSHOTS_IN_SYNC body:@{ - @"appName" : [RNFBSharedUtils getAppJavaScriptName:firebaseApp.name], + @"appName" : appName, @"databaseId" : databaseId, - @"listenerId" : listenerId, + @"listenerId" : listenerIdNumber, @"body" : @{} }]; }]; - snapshotsInSyncListeners[listenerId] = listener; - - resolve(nil); + snapshotsInSyncListeners[listenerIdNumber] = listener; } -RCT_EXPORT_METHOD(removeSnapshotsInSync - : (FIRApp *)firebaseApp - : (NSString *)databaseId - : (nonnull NSNumber *)listenerId - : (RCTPromiseResolveBlock)resolve - : (RCTPromiseRejectBlock)reject) { - id listener = snapshotsInSyncListeners[listenerId]; +- (void)removeSnapshotsInSync:(NSString *)appName + databaseId:(NSString *)databaseId + listenerId:(double)listenerId { + NSNumber *listenerIdNumber = @(listenerId); + id listener = snapshotsInSyncListeners[listenerIdNumber]; if (listener) { [listener remove]; - [snapshotsInSyncListeners removeObjectForKey:listenerId]; + [snapshotsInSyncListeners removeObjectForKey:listenerIdNumber]; } - - resolve(nil); } - (NSMutableDictionary *)taskProgressToDictionary:(FIRLoadBundleTaskProgress *)progress { diff --git a/packages/firestore/ios/RNFBFirestore/RNFBFirestoreTransactionModule.m b/packages/firestore/ios/RNFBFirestore/RNFBFirestoreTransactionModule.mm similarity index 75% rename from packages/firestore/ios/RNFBFirestore/RNFBFirestoreTransactionModule.m rename to packages/firestore/ios/RNFBFirestore/RNFBFirestoreTransactionModule.mm index bf3dad6dda..ca273d64b0 100644 --- a/packages/firestore/ios/RNFBFirestore/RNFBFirestoreTransactionModule.m +++ b/packages/firestore/ios/RNFBFirestore/RNFBFirestoreTransactionModule.mm @@ -16,18 +16,29 @@ */ #import +#import "RNFBApp/RCTConvert+FIRApp.h" +#import #import #import "RNFBFirestoreTransactionModule.h" +#import "RNFBFirestoreTurboModules.h" static __strong NSMutableDictionary *transactions; static NSString *const RNFB_FIRESTORE_TRANSACTION_EVENT = @"firestore_transaction_event"; +@interface RNFBFirestoreTransactionModule () +@end + @implementation RNFBFirestoreTransactionModule #pragma mark - #pragma mark Module Setup -RCT_EXPORT_MODULE(); +- (std::shared_ptr)getTurboModule: + (const facebook::react::ObjCTurboModule::InitParams &)params { + return std::make_shared(params); +} + +RCT_EXPORT_MODULE(NativeRNFBTurboFirestoreTransaction); - (id)init { self = [super init]; @@ -39,11 +50,7 @@ - (id)init { } + (BOOL)requiresMainQueueSetup { - return YES; -} - -- (dispatch_queue_t)methodQueue { - return [RNFBFirestoreCommon getFirestoreQueue]; + return NO; } - (void)dealloc { @@ -59,87 +66,12 @@ - (void)invalidate { #pragma mark - #pragma mark Firebase Firestore Methods -RCT_EXPORT_METHOD(transactionGetDocument - : (FIRApp *)firebaseApp - : (NSString *)databaseId - : (nonnull NSNumber *)transactionId - : (NSString *)path - : (RCTPromiseResolveBlock)resolve - : (RCTPromiseRejectBlock)reject) { - @synchronized(transactions[[transactionId stringValue]]) { - NSMutableDictionary *transactionState = transactions[[transactionId stringValue]]; - - if (!transactionState) { - DLog(@"transactionGetDocument called for non-existent transactionId %@", transactionId); - return; - } - - NSError *error = nil; - FIRTransaction *transaction = [transactionState valueForKey:@"transaction"]; - FIRFirestore *firestore = [RNFBFirestoreCommon getFirestoreForApp:firebaseApp - databaseId:databaseId]; - FIRDocumentReference *ref = [RNFBFirestoreCommon getDocumentForFirestore:firestore path:path]; - FIRDocumentSnapshot *snapshot = [transaction getDocument:ref error:&error]; - - if (error != nil) { - [RNFBFirestoreCommon promiseRejectFirestoreException:reject error:error]; - } else { - NSString *appName = [RNFBSharedUtils getAppJavaScriptName:firebaseApp.name]; - NSString *firestoreKey = [RNFBFirestoreCommon createFirestoreKeyWithAppName:appName - databaseId:databaseId]; - NSDictionary *snapshotDict = - [RNFBFirestoreSerialize documentSnapshotToDictionary:snapshot firestoreKey:firestoreKey]; - NSString *snapshotPath = snapshotDict[@"path"]; - - if (snapshotPath == nil) { - [snapshotDict setValue:ref.path forKey:@"path"]; - } - - resolve(snapshotDict); - } - } -} - -RCT_EXPORT_METHOD(transactionDispose - : (FIRApp *)firebaseApp - : (NSString *)databaseId - : (nonnull NSNumber *)transactionId) { - @synchronized(transactions[[transactionId stringValue]]) { - NSMutableDictionary *transactionState = transactions[[transactionId stringValue]]; - - if (!transactionState) { - return; - } - - dispatch_semaphore_t semaphore = transactionState[@"semaphore"]; - transactionState[@"aborted"] = @(true); - dispatch_semaphore_signal(semaphore); - } -} - -RCT_EXPORT_METHOD(transactionApplyBuffer - : (FIRApp *)firebaseApp - : (NSString *)databaseId - : (nonnull NSNumber *)transactionId - : (NSArray *)commandBuffer) { - @synchronized(transactions[[transactionId stringValue]]) { - NSMutableDictionary *transactionState = transactions[[transactionId stringValue]]; - - if (!transactionState) { - DLog(@"transactionGetDocument called for non-existent transactionId %@", transactionId); - return; - } - - dispatch_semaphore_t semaphore = [transactionState valueForKey:@"semaphore"]; - [transactionState setValue:commandBuffer forKey:@"commandBuffer"]; - dispatch_semaphore_signal(semaphore); - } -} +- (void)transactionBegin:(NSString *)appName + databaseId:(NSString *)databaseId + transactionId:(double)transactionId { + FIRApp *firebaseApp = [RCTConvert firAppFromString:appName]; + NSNumber *transactionIdNumber = @(transactionId); -RCT_EXPORT_METHOD(transactionBegin - : (FIRApp *)firebaseApp - : (NSString *)databaseId - : (nonnull NSNumber *)transactionId) { FIRFirestore *firestore = [RNFBFirestoreCommon getFirestoreForApp:firebaseApp databaseId:databaseId]; __block BOOL aborted = false; @@ -152,18 +84,17 @@ - (void)invalidate { transactionState[@"semaphore"] = semaphore; transactionState[@"transaction"] = transaction; - if (!transactions[[transactionId stringValue]]) { - transactions[[transactionId stringValue]] = transactionState; + if (!transactions[[transactionIdNumber stringValue]]) { + transactions[[transactionIdNumber stringValue]] = transactionState; } - // build and send transaction update event dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ NSMutableDictionary *eventMap = [NSMutableDictionary new]; eventMap[@"type"] = @"update"; [[RNFBRCTEventEmitter shared] sendEventWithName:RNFB_FIRESTORE_TRANSACTION_EVENT body:@{ - @"listenerId" : transactionId, + @"listenerId" : transactionIdNumber, @"appName" : [RNFBSharedUtils getAppJavaScriptName:firebaseApp.name], @"databaseId" : databaseId, @"body" : eventMap, @@ -171,10 +102,6 @@ - (void)invalidate { }); } - // wait for the js event handler to call transactionApplyBuffer - // this wait occurs on the RNFirestore Worker Queue so if transactionApplyBuffer fails to - // signal the semaphore then no further blocks will be executed by RNFirestore until the timeout - // expires dispatch_time_t delayTime = dispatch_time(DISPATCH_TIME_NOW, 15 * NSEC_PER_SEC); BOOL timedOut = dispatch_semaphore_wait(semaphore, delayTime) != 0; @@ -252,18 +179,99 @@ - (void)invalidate { [[RNFBRCTEventEmitter shared] sendEventWithName:RNFB_FIRESTORE_TRANSACTION_EVENT body:@{ - @"listenerId" : transactionId, + @"listenerId" : transactionIdNumber, @"appName" : [RNFBSharedUtils getAppJavaScriptName:firebaseApp.name], @"databaseId" : databaseId, @"body" : eventMap, }]; } - [transactions removeObjectForKey:[transactionId stringValue]]; + [transactions removeObjectForKey:[transactionIdNumber stringValue]]; } }; [firestore runTransactionWithBlock:transactionBlock completion:completionBlock]; } +- (void)transactionGetDocument:(NSString *)appName + databaseId:(NSString *)databaseId + transactionId:(double)transactionId + path:(NSString *)path + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject { + FIRApp *firebaseApp = [RCTConvert firAppFromString:appName]; + NSNumber *transactionIdNumber = @(transactionId); + + @synchronized(transactions[[transactionIdNumber stringValue]]) { + NSMutableDictionary *transactionState = transactions[[transactionIdNumber stringValue]]; + + if (!transactionState) { + DLog(@"transactionGetDocument called for non-existent transactionId %@", transactionIdNumber); + return; + } + + NSError *error = nil; + FIRTransaction *transaction = [transactionState valueForKey:@"transaction"]; + FIRFirestore *firestore = [RNFBFirestoreCommon getFirestoreForApp:firebaseApp + databaseId:databaseId]; + FIRDocumentReference *ref = [RNFBFirestoreCommon getDocumentForFirestore:firestore path:path]; + FIRDocumentSnapshot *snapshot = [transaction getDocument:ref error:&error]; + + if (error != nil) { + [RNFBFirestoreCommon promiseRejectFirestoreException:reject error:error]; + } else { + NSString *resolvedAppName = [RNFBSharedUtils getAppJavaScriptName:firebaseApp.name]; + NSString *firestoreKey = [RNFBFirestoreCommon createFirestoreKeyWithAppName:resolvedAppName + databaseId:databaseId]; + NSDictionary *snapshotDict = + [RNFBFirestoreSerialize documentSnapshotToDictionary:snapshot firestoreKey:firestoreKey]; + NSString *snapshotPath = snapshotDict[@"path"]; + + if (snapshotPath == nil) { + [snapshotDict setValue:ref.path forKey:@"path"]; + } + + resolve(snapshotDict); + } + } +} + +- (void)transactionDispose:(NSString *)appName + databaseId:(NSString *)databaseId + transactionId:(double)transactionId { + NSNumber *transactionIdNumber = @(transactionId); + + @synchronized(transactions[[transactionIdNumber stringValue]]) { + NSMutableDictionary *transactionState = transactions[[transactionIdNumber stringValue]]; + + if (!transactionState) { + return; + } + + dispatch_semaphore_t semaphore = transactionState[@"semaphore"]; + transactionState[@"aborted"] = @(true); + dispatch_semaphore_signal(semaphore); + } +} + +- (void)transactionApplyBuffer:(NSString *)appName + databaseId:(NSString *)databaseId + transactionId:(double)transactionId + commandBuffer:(NSArray *)commandBuffer { + NSNumber *transactionIdNumber = @(transactionId); + + @synchronized(transactions[[transactionIdNumber stringValue]]) { + NSMutableDictionary *transactionState = transactions[[transactionIdNumber stringValue]]; + + if (!transactionState) { + DLog(@"transactionApplyBuffer called for non-existent transactionId %@", transactionIdNumber); + return; + } + + dispatch_semaphore_t semaphore = [transactionState valueForKey:@"semaphore"]; + [transactionState setValue:commandBuffer forKey:@"commandBuffer"]; + dispatch_semaphore_signal(semaphore); + } +} + @end diff --git a/packages/firestore/ios/generated/RNFBFirestoreTurboModules/RNFBFirestoreTurboModules-generated.mm b/packages/firestore/ios/generated/RNFBFirestoreTurboModules/RNFBFirestoreTurboModules-generated.mm new file mode 100644 index 0000000000..780b2d7f87 --- /dev/null +++ b/packages/firestore/ios/generated/RNFBFirestoreTurboModules/RNFBFirestoreTurboModules-generated.mm @@ -0,0 +1,311 @@ +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleObjCpp + * + * We create an umbrella header (and corresponding implementation) here since + * Cxx compilation in BUCK has a limitation: source-code producing genrule()s + * must have a single output. More files => more genrule()s => slower builds. + */ + +#import "RNFBFirestoreTurboModules.h" + + +@implementation NativeRNFBTurboFirestoreSpecBase + + +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper +{ + _eventEmitterCallback = std::move(eventEmitterCallbackWrapper->_eventEmitterCallback); +} +@end + + +namespace facebook::react { + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboFirestoreSpecJSI_setLogLevel(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, VoidKind, "setLogLevel", @selector(setLogLevel:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboFirestoreSpecJSI_loadBundle(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, PromiseKind, "loadBundle", @selector(loadBundle:databaseId:bundle:resolve:reject:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboFirestoreSpecJSI_clearPersistence(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, PromiseKind, "clearPersistence", @selector(clearPersistence:databaseId:resolve:reject:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboFirestoreSpecJSI_waitForPendingWrites(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, PromiseKind, "waitForPendingWrites", @selector(waitForPendingWrites:databaseId:resolve:reject:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboFirestoreSpecJSI_disableNetwork(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, PromiseKind, "disableNetwork", @selector(disableNetwork:databaseId:resolve:reject:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboFirestoreSpecJSI_enableNetwork(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, PromiseKind, "enableNetwork", @selector(enableNetwork:databaseId:resolve:reject:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboFirestoreSpecJSI_useEmulator(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, VoidKind, "useEmulator", @selector(useEmulator:databaseId:host:port:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboFirestoreSpecJSI_settings(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, PromiseKind, "settings", @selector(settings:databaseId:settings:resolve:reject:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboFirestoreSpecJSI_terminate(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, PromiseKind, "terminate", @selector(terminate:databaseId:resolve:reject:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboFirestoreSpecJSI_persistenceCacheIndexManager(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, PromiseKind, "persistenceCacheIndexManager", @selector(persistenceCacheIndexManager:databaseId:requestType:resolve:reject:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboFirestoreSpecJSI_addSnapshotsInSync(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, VoidKind, "addSnapshotsInSync", @selector(addSnapshotsInSync:databaseId:listenerId:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboFirestoreSpecJSI_removeSnapshotsInSync(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, VoidKind, "removeSnapshotsInSync", @selector(removeSnapshotsInSync:databaseId:listenerId:), args, count); + } + + NativeRNFBTurboFirestoreSpecJSI::NativeRNFBTurboFirestoreSpecJSI(const ObjCTurboModule::InitParams ¶ms) + : ObjCTurboModule(params) { + + methodMap_["setLogLevel"] = MethodMetadata {1, __hostFunction_NativeRNFBTurboFirestoreSpecJSI_setLogLevel}; + + + methodMap_["loadBundle"] = MethodMetadata {3, __hostFunction_NativeRNFBTurboFirestoreSpecJSI_loadBundle}; + + + methodMap_["clearPersistence"] = MethodMetadata {2, __hostFunction_NativeRNFBTurboFirestoreSpecJSI_clearPersistence}; + + + methodMap_["waitForPendingWrites"] = MethodMetadata {2, __hostFunction_NativeRNFBTurboFirestoreSpecJSI_waitForPendingWrites}; + + + methodMap_["disableNetwork"] = MethodMetadata {2, __hostFunction_NativeRNFBTurboFirestoreSpecJSI_disableNetwork}; + + + methodMap_["enableNetwork"] = MethodMetadata {2, __hostFunction_NativeRNFBTurboFirestoreSpecJSI_enableNetwork}; + + + methodMap_["useEmulator"] = MethodMetadata {4, __hostFunction_NativeRNFBTurboFirestoreSpecJSI_useEmulator}; + + + methodMap_["settings"] = MethodMetadata {3, __hostFunction_NativeRNFBTurboFirestoreSpecJSI_settings}; + + + methodMap_["terminate"] = MethodMetadata {2, __hostFunction_NativeRNFBTurboFirestoreSpecJSI_terminate}; + + + methodMap_["persistenceCacheIndexManager"] = MethodMetadata {3, __hostFunction_NativeRNFBTurboFirestoreSpecJSI_persistenceCacheIndexManager}; + + + methodMap_["addSnapshotsInSync"] = MethodMetadata {3, __hostFunction_NativeRNFBTurboFirestoreSpecJSI_addSnapshotsInSync}; + + + methodMap_["removeSnapshotsInSync"] = MethodMetadata {3, __hostFunction_NativeRNFBTurboFirestoreSpecJSI_removeSnapshotsInSync}; + + } +} // namespace facebook::react + +@implementation NativeRNFBTurboFirestoreCollectionSpecBase + + +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper +{ + _eventEmitterCallback = std::move(eventEmitterCallbackWrapper->_eventEmitterCallback); +} +@end + + +namespace facebook::react { + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboFirestoreCollectionSpecJSI_namedQueryOnSnapshot(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, VoidKind, "namedQueryOnSnapshot", @selector(namedQueryOnSnapshot:databaseId:queryName:type:filters:orders:options:listenerId:snapshotListenOptions:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboFirestoreCollectionSpecJSI_collectionOnSnapshot(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, VoidKind, "collectionOnSnapshot", @selector(collectionOnSnapshot:databaseId:path:type:filters:orders:options:listenerId:snapshotListenOptions:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboFirestoreCollectionSpecJSI_collectionOffSnapshot(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, VoidKind, "collectionOffSnapshot", @selector(collectionOffSnapshot:databaseId:listenerId:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboFirestoreCollectionSpecJSI_namedQueryGet(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, PromiseKind, "namedQueryGet", @selector(namedQueryGet:databaseId:queryName:type:filters:orders:options:getOptions:resolve:reject:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboFirestoreCollectionSpecJSI_collectionGet(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, PromiseKind, "collectionGet", @selector(collectionGet:databaseId:path:type:filters:orders:options:getOptions:resolve:reject:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboFirestoreCollectionSpecJSI_collectionCount(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, PromiseKind, "collectionCount", @selector(collectionCount:databaseId:path:type:filters:orders:options:resolve:reject:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboFirestoreCollectionSpecJSI_aggregateQuery(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, PromiseKind, "aggregateQuery", @selector(aggregateQuery:databaseId:path:type:filters:orders:options:aggregateQueries:resolve:reject:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboFirestoreCollectionSpecJSI_pipelineExecute(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, PromiseKind, "pipelineExecute", @selector(pipelineExecute:databaseId:pipeline:options:resolve:reject:), args, count); + } + + NativeRNFBTurboFirestoreCollectionSpecJSI::NativeRNFBTurboFirestoreCollectionSpecJSI(const ObjCTurboModule::InitParams ¶ms) + : ObjCTurboModule(params) { + + methodMap_["namedQueryOnSnapshot"] = MethodMetadata {9, __hostFunction_NativeRNFBTurboFirestoreCollectionSpecJSI_namedQueryOnSnapshot}; + + + methodMap_["collectionOnSnapshot"] = MethodMetadata {9, __hostFunction_NativeRNFBTurboFirestoreCollectionSpecJSI_collectionOnSnapshot}; + + + methodMap_["collectionOffSnapshot"] = MethodMetadata {3, __hostFunction_NativeRNFBTurboFirestoreCollectionSpecJSI_collectionOffSnapshot}; + + + methodMap_["namedQueryGet"] = MethodMetadata {8, __hostFunction_NativeRNFBTurboFirestoreCollectionSpecJSI_namedQueryGet}; + + + methodMap_["collectionGet"] = MethodMetadata {8, __hostFunction_NativeRNFBTurboFirestoreCollectionSpecJSI_collectionGet}; + + + methodMap_["collectionCount"] = MethodMetadata {7, __hostFunction_NativeRNFBTurboFirestoreCollectionSpecJSI_collectionCount}; + + + methodMap_["aggregateQuery"] = MethodMetadata {8, __hostFunction_NativeRNFBTurboFirestoreCollectionSpecJSI_aggregateQuery}; + + + methodMap_["pipelineExecute"] = MethodMetadata {4, __hostFunction_NativeRNFBTurboFirestoreCollectionSpecJSI_pipelineExecute}; + + } +} // namespace facebook::react + +@implementation NativeRNFBTurboFirestoreDocumentSpecBase + + +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper +{ + _eventEmitterCallback = std::move(eventEmitterCallbackWrapper->_eventEmitterCallback); +} +@end + +@implementation RCTCxxConvert (NativeRNFBTurboFirestoreDocument_FirestoreSnapshotListenOptions) ++ (RCTManagedPointer *)JS_NativeRNFBTurboFirestoreDocument_FirestoreSnapshotListenOptions:(id)json +{ + return facebook::react::managedPointer(json); +} +@end +@implementation RCTCxxConvert (NativeRNFBTurboFirestoreDocument_SpecDocumentGetGetOptions) ++ (RCTManagedPointer *)JS_NativeRNFBTurboFirestoreDocument_SpecDocumentGetGetOptions:(id)json +{ + return facebook::react::managedPointer(json); +} +@end +namespace facebook::react { + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboFirestoreDocumentSpecJSI_documentOnSnapshot(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, VoidKind, "documentOnSnapshot", @selector(documentOnSnapshot:databaseId:path:listenerId:snapshotListenOptions:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboFirestoreDocumentSpecJSI_documentOffSnapshot(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, VoidKind, "documentOffSnapshot", @selector(documentOffSnapshot:databaseId:listenerId:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboFirestoreDocumentSpecJSI_documentGet(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, PromiseKind, "documentGet", @selector(documentGet:databaseId:path:getOptions:resolve:reject:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboFirestoreDocumentSpecJSI_documentDelete(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, PromiseKind, "documentDelete", @selector(documentDelete:databaseId:path:resolve:reject:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboFirestoreDocumentSpecJSI_documentSet(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, PromiseKind, "documentSet", @selector(documentSet:databaseId:path:data:options:resolve:reject:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboFirestoreDocumentSpecJSI_documentUpdate(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, PromiseKind, "documentUpdate", @selector(documentUpdate:databaseId:path:data:resolve:reject:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboFirestoreDocumentSpecJSI_documentBatch(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, PromiseKind, "documentBatch", @selector(documentBatch:databaseId:writes:resolve:reject:), args, count); + } + + NativeRNFBTurboFirestoreDocumentSpecJSI::NativeRNFBTurboFirestoreDocumentSpecJSI(const ObjCTurboModule::InitParams ¶ms) + : ObjCTurboModule(params) { + + methodMap_["documentOnSnapshot"] = MethodMetadata {5, __hostFunction_NativeRNFBTurboFirestoreDocumentSpecJSI_documentOnSnapshot}; + setMethodArgConversionSelector(@"documentOnSnapshot", 4, @"JS_NativeRNFBTurboFirestoreDocument_FirestoreSnapshotListenOptions:"); + + methodMap_["documentOffSnapshot"] = MethodMetadata {3, __hostFunction_NativeRNFBTurboFirestoreDocumentSpecJSI_documentOffSnapshot}; + + + methodMap_["documentGet"] = MethodMetadata {4, __hostFunction_NativeRNFBTurboFirestoreDocumentSpecJSI_documentGet}; + setMethodArgConversionSelector(@"documentGet", 3, @"JS_NativeRNFBTurboFirestoreDocument_SpecDocumentGetGetOptions:"); + + methodMap_["documentDelete"] = MethodMetadata {3, __hostFunction_NativeRNFBTurboFirestoreDocumentSpecJSI_documentDelete}; + + + methodMap_["documentSet"] = MethodMetadata {5, __hostFunction_NativeRNFBTurboFirestoreDocumentSpecJSI_documentSet}; + + + methodMap_["documentUpdate"] = MethodMetadata {4, __hostFunction_NativeRNFBTurboFirestoreDocumentSpecJSI_documentUpdate}; + + + methodMap_["documentBatch"] = MethodMetadata {3, __hostFunction_NativeRNFBTurboFirestoreDocumentSpecJSI_documentBatch}; + + } +} // namespace facebook::react + +@implementation NativeRNFBTurboFirestoreTransactionSpecBase + + +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper +{ + _eventEmitterCallback = std::move(eventEmitterCallbackWrapper->_eventEmitterCallback); +} +@end + + +namespace facebook::react { + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboFirestoreTransactionSpecJSI_transactionBegin(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, VoidKind, "transactionBegin", @selector(transactionBegin:databaseId:transactionId:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboFirestoreTransactionSpecJSI_transactionGetDocument(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, PromiseKind, "transactionGetDocument", @selector(transactionGetDocument:databaseId:transactionId:path:resolve:reject:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboFirestoreTransactionSpecJSI_transactionDispose(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, VoidKind, "transactionDispose", @selector(transactionDispose:databaseId:transactionId:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboFirestoreTransactionSpecJSI_transactionApplyBuffer(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, VoidKind, "transactionApplyBuffer", @selector(transactionApplyBuffer:databaseId:transactionId:commandBuffer:), args, count); + } + + NativeRNFBTurboFirestoreTransactionSpecJSI::NativeRNFBTurboFirestoreTransactionSpecJSI(const ObjCTurboModule::InitParams ¶ms) + : ObjCTurboModule(params) { + + methodMap_["transactionBegin"] = MethodMetadata {3, __hostFunction_NativeRNFBTurboFirestoreTransactionSpecJSI_transactionBegin}; + + + methodMap_["transactionGetDocument"] = MethodMetadata {4, __hostFunction_NativeRNFBTurboFirestoreTransactionSpecJSI_transactionGetDocument}; + + + methodMap_["transactionDispose"] = MethodMetadata {3, __hostFunction_NativeRNFBTurboFirestoreTransactionSpecJSI_transactionDispose}; + + + methodMap_["transactionApplyBuffer"] = MethodMetadata {4, __hostFunction_NativeRNFBTurboFirestoreTransactionSpecJSI_transactionApplyBuffer}; + + } +} // namespace facebook::react diff --git a/packages/firestore/ios/generated/RNFBFirestoreTurboModules/RNFBFirestoreTurboModules.h b/packages/firestore/ios/generated/RNFBFirestoreTurboModules/RNFBFirestoreTurboModules.h new file mode 100644 index 0000000000..b0e2188cf1 --- /dev/null +++ b/packages/firestore/ios/generated/RNFBFirestoreTurboModules/RNFBFirestoreTurboModules.h @@ -0,0 +1,345 @@ +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleObjCpp + * + * We create an umbrella header (and corresponding implementation) here since + * Cxx compilation in BUCK has a limitation: source-code producing genrule()s + * must have a single output. More files => more genrule()s => slower builds. + */ + +#ifndef __cplusplus +#error This file must be compiled as Obj-C++. If you are importing it, you must change your file extension to .mm. +#endif + +// Avoid multiple includes of RNFBFirestoreTurboModules symbols +#ifndef RNFBFirestoreTurboModules_H +#define RNFBFirestoreTurboModules_H + +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import + + +NS_ASSUME_NONNULL_BEGIN + +@protocol NativeRNFBTurboFirestoreSpec + +- (void)setLogLevel:(NSString *)logLevel; +- (void)loadBundle:(NSString *)appName + databaseId:(NSString *)databaseId + bundle:(NSString *)bundle + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; +- (void)clearPersistence:(NSString *)appName + databaseId:(NSString *)databaseId + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; +- (void)waitForPendingWrites:(NSString *)appName + databaseId:(NSString *)databaseId + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; +- (void)disableNetwork:(NSString *)appName + databaseId:(NSString *)databaseId + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; +- (void)enableNetwork:(NSString *)appName + databaseId:(NSString *)databaseId + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; +- (void)useEmulator:(NSString *)appName + databaseId:(NSString *)databaseId + host:(NSString *)host + port:(double)port; +- (void)settings:(NSString *)appName + databaseId:(NSString *)databaseId + settings:(NSDictionary *)settings + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; +- (void)terminate:(NSString *)appName + databaseId:(NSString *)databaseId + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; +- (void)persistenceCacheIndexManager:(NSString *)appName + databaseId:(NSString *)databaseId + requestType:(double)requestType + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; +- (void)addSnapshotsInSync:(NSString *)appName + databaseId:(NSString *)databaseId + listenerId:(double)listenerId; +- (void)removeSnapshotsInSync:(NSString *)appName + databaseId:(NSString *)databaseId + listenerId:(double)listenerId; + +@end + +@interface NativeRNFBTurboFirestoreSpecBase : NSObject { +@protected +facebook::react::EventEmitterCallback _eventEmitterCallback; +} +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper; + + +@end + +namespace facebook::react { + /** + * ObjC++ class for module 'NativeRNFBTurboFirestore' + */ + class JSI_EXPORT NativeRNFBTurboFirestoreSpecJSI : public ObjCTurboModule { + public: + NativeRNFBTurboFirestoreSpecJSI(const ObjCTurboModule::InitParams ¶ms); + }; +} // namespace facebook::react + +@protocol NativeRNFBTurboFirestoreCollectionSpec + +- (void)namedQueryOnSnapshot:(NSString *)appName + databaseId:(NSString *)databaseId + queryName:(NSString *)queryName + type:(NSString *)type + filters:(NSArray *)filters + orders:(NSArray *)orders + options:(NSDictionary *)options + listenerId:(double)listenerId + snapshotListenOptions:(NSDictionary *)snapshotListenOptions; +- (void)collectionOnSnapshot:(NSString *)appName + databaseId:(NSString *)databaseId + path:(NSString *)path + type:(NSString *)type + filters:(NSArray *)filters + orders:(NSArray *)orders + options:(NSDictionary *)options + listenerId:(double)listenerId + snapshotListenOptions:(NSDictionary *)snapshotListenOptions; +- (void)collectionOffSnapshot:(NSString *)appName + databaseId:(NSString *)databaseId + listenerId:(double)listenerId; +- (void)namedQueryGet:(NSString *)appName + databaseId:(NSString *)databaseId + queryName:(NSString *)queryName + type:(NSString *)type + filters:(NSArray *)filters + orders:(NSArray *)orders + options:(NSDictionary *)options + getOptions:(NSDictionary *)getOptions + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; +- (void)collectionGet:(NSString *)appName + databaseId:(NSString *)databaseId + path:(NSString *)path + type:(NSString *)type + filters:(NSArray *)filters + orders:(NSArray *)orders + options:(NSDictionary *)options + getOptions:(NSDictionary *)getOptions + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; +- (void)collectionCount:(NSString *)appName + databaseId:(NSString *)databaseId + path:(NSString *)path + type:(NSString *)type + filters:(NSArray *)filters + orders:(NSArray *)orders + options:(NSDictionary *)options + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; +- (void)aggregateQuery:(NSString *)appName + databaseId:(NSString *)databaseId + path:(NSString *)path + type:(NSString *)type + filters:(NSArray *)filters + orders:(NSArray *)orders + options:(NSDictionary *)options + aggregateQueries:(NSArray *)aggregateQueries + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; +- (void)pipelineExecute:(NSString *)appName + databaseId:(NSString *)databaseId + pipeline:(NSDictionary *)pipeline + options:(NSDictionary *)options + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; + +@end + +@interface NativeRNFBTurboFirestoreCollectionSpecBase : NSObject { +@protected +facebook::react::EventEmitterCallback _eventEmitterCallback; +} +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper; + + +@end + +namespace facebook::react { + /** + * ObjC++ class for module 'NativeRNFBTurboFirestoreCollection' + */ + class JSI_EXPORT NativeRNFBTurboFirestoreCollectionSpecJSI : public ObjCTurboModule { + public: + NativeRNFBTurboFirestoreCollectionSpecJSI(const ObjCTurboModule::InitParams ¶ms); + }; +} // namespace facebook::react +namespace JS { + namespace NativeRNFBTurboFirestoreDocument { + struct FirestoreSnapshotListenOptions { + std::optional includeMetadataChanges() const; + NSString *source() const; + + FirestoreSnapshotListenOptions(NSDictionary *const v) : _v(v) {} + private: + NSDictionary *_v; + }; + } +} + +@interface RCTCxxConvert (NativeRNFBTurboFirestoreDocument_FirestoreSnapshotListenOptions) ++ (RCTManagedPointer *)JS_NativeRNFBTurboFirestoreDocument_FirestoreSnapshotListenOptions:(id)json; +@end +namespace JS { + namespace NativeRNFBTurboFirestoreDocument { + struct SpecDocumentGetGetOptions { + NSString *source() const; + + SpecDocumentGetGetOptions(NSDictionary *const v) : _v(v) {} + private: + NSDictionary *_v; + }; + } +} + +@interface RCTCxxConvert (NativeRNFBTurboFirestoreDocument_SpecDocumentGetGetOptions) ++ (RCTManagedPointer *)JS_NativeRNFBTurboFirestoreDocument_SpecDocumentGetGetOptions:(id)json; +@end +@protocol NativeRNFBTurboFirestoreDocumentSpec + +- (void)documentOnSnapshot:(NSString *)appName + databaseId:(NSString *)databaseId + path:(NSString *)path + listenerId:(double)listenerId + snapshotListenOptions:(JS::NativeRNFBTurboFirestoreDocument::FirestoreSnapshotListenOptions &)snapshotListenOptions; +- (void)documentOffSnapshot:(NSString *)appName + databaseId:(NSString *)databaseId + listenerId:(double)listenerId; +- (void)documentGet:(NSString *)appName + databaseId:(NSString *)databaseId + path:(NSString *)path + getOptions:(JS::NativeRNFBTurboFirestoreDocument::SpecDocumentGetGetOptions &)getOptions + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; +- (void)documentDelete:(NSString *)appName + databaseId:(NSString *)databaseId + path:(NSString *)path + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; +- (void)documentSet:(NSString *)appName + databaseId:(NSString *)databaseId + path:(NSString *)path + data:(NSDictionary *)data + options:(NSDictionary *)options + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; +- (void)documentUpdate:(NSString *)appName + databaseId:(NSString *)databaseId + path:(NSString *)path + data:(NSDictionary *)data + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; +- (void)documentBatch:(NSString *)appName + databaseId:(NSString *)databaseId + writes:(NSArray *)writes + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; + +@end + +@interface NativeRNFBTurboFirestoreDocumentSpecBase : NSObject { +@protected +facebook::react::EventEmitterCallback _eventEmitterCallback; +} +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper; + + +@end + +namespace facebook::react { + /** + * ObjC++ class for module 'NativeRNFBTurboFirestoreDocument' + */ + class JSI_EXPORT NativeRNFBTurboFirestoreDocumentSpecJSI : public ObjCTurboModule { + public: + NativeRNFBTurboFirestoreDocumentSpecJSI(const ObjCTurboModule::InitParams ¶ms); + }; +} // namespace facebook::react + +@protocol NativeRNFBTurboFirestoreTransactionSpec + +- (void)transactionBegin:(NSString *)appName + databaseId:(NSString *)databaseId + transactionId:(double)transactionId; +- (void)transactionGetDocument:(NSString *)appName + databaseId:(NSString *)databaseId + transactionId:(double)transactionId + path:(NSString *)path + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; +- (void)transactionDispose:(NSString *)appName + databaseId:(NSString *)databaseId + transactionId:(double)transactionId; +- (void)transactionApplyBuffer:(NSString *)appName + databaseId:(NSString *)databaseId + transactionId:(double)transactionId + commandBuffer:(NSArray *)commandBuffer; + +@end + +@interface NativeRNFBTurboFirestoreTransactionSpecBase : NSObject { +@protected +facebook::react::EventEmitterCallback _eventEmitterCallback; +} +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper; + + +@end + +namespace facebook::react { + /** + * ObjC++ class for module 'NativeRNFBTurboFirestoreTransaction' + */ + class JSI_EXPORT NativeRNFBTurboFirestoreTransactionSpecJSI : public ObjCTurboModule { + public: + NativeRNFBTurboFirestoreTransactionSpecJSI(const ObjCTurboModule::InitParams ¶ms); + }; +} // namespace facebook::react + + +inline std::optional JS::NativeRNFBTurboFirestoreDocument::FirestoreSnapshotListenOptions::includeMetadataChanges() const +{ + id const p = _v[@"includeMetadataChanges"]; + return RCTBridgingToOptionalBool(p); +} +inline NSString *JS::NativeRNFBTurboFirestoreDocument::FirestoreSnapshotListenOptions::source() const +{ + id const p = _v[@"source"]; + return RCTBridgingToOptionalString(p); +} +inline NSString *JS::NativeRNFBTurboFirestoreDocument::SpecDocumentGetGetOptions::source() const +{ + id const p = _v[@"source"]; + return RCTBridgingToOptionalString(p); +} + +NS_ASSUME_NONNULL_END +#endif // RNFBFirestoreTurboModules_H diff --git a/packages/firestore/ios/generated/RNFBFirestoreTurboModulesJSI-generated.cpp b/packages/firestore/ios/generated/RNFBFirestoreTurboModulesJSI-generated.cpp new file mode 100644 index 0000000000..3a1062e6af --- /dev/null +++ b/packages/firestore/ios/generated/RNFBFirestoreTurboModulesJSI-generated.cpp @@ -0,0 +1,357 @@ +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleCpp.js + */ + +#include "RNFBFirestoreTurboModulesJSI.h" + +namespace facebook::react { + +static jsi::Value __hostFunction_NativeRNFBTurboFirestoreCxxSpecJSI_setLogLevel(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + static_cast(&turboModule)->setLogLevel( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt) + ); + return jsi::Value::undefined(); +} +static jsi::Value __hostFunction_NativeRNFBTurboFirestoreCxxSpecJSI_loadBundle(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->loadBundle( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt), + count <= 2 ? throw jsi::JSError(rt, "Expected argument in position 2 to be passed") : args[2].asString(rt) + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboFirestoreCxxSpecJSI_clearPersistence(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->clearPersistence( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt) + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboFirestoreCxxSpecJSI_waitForPendingWrites(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->waitForPendingWrites( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt) + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboFirestoreCxxSpecJSI_disableNetwork(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->disableNetwork( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt) + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboFirestoreCxxSpecJSI_enableNetwork(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->enableNetwork( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt) + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboFirestoreCxxSpecJSI_useEmulator(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + static_cast(&turboModule)->useEmulator( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt), + count <= 2 ? throw jsi::JSError(rt, "Expected argument in position 2 to be passed") : args[2].asString(rt), + count <= 3 ? throw jsi::JSError(rt, "Expected argument in position 3 to be passed") : args[3].asNumber() + ); + return jsi::Value::undefined(); +} +static jsi::Value __hostFunction_NativeRNFBTurboFirestoreCxxSpecJSI_settings(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->settings( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt), + count <= 2 ? throw jsi::JSError(rt, "Expected argument in position 2 to be passed") : args[2].asObject(rt) + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboFirestoreCxxSpecJSI_terminate(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->terminate( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt) + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboFirestoreCxxSpecJSI_persistenceCacheIndexManager(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->persistenceCacheIndexManager( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt), + count <= 2 ? throw jsi::JSError(rt, "Expected argument in position 2 to be passed") : args[2].asNumber() + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboFirestoreCxxSpecJSI_addSnapshotsInSync(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + static_cast(&turboModule)->addSnapshotsInSync( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt), + count <= 2 ? throw jsi::JSError(rt, "Expected argument in position 2 to be passed") : args[2].asNumber() + ); + return jsi::Value::undefined(); +} +static jsi::Value __hostFunction_NativeRNFBTurboFirestoreCxxSpecJSI_removeSnapshotsInSync(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + static_cast(&turboModule)->removeSnapshotsInSync( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt), + count <= 2 ? throw jsi::JSError(rt, "Expected argument in position 2 to be passed") : args[2].asNumber() + ); + return jsi::Value::undefined(); +} + +NativeRNFBTurboFirestoreCxxSpecJSI::NativeRNFBTurboFirestoreCxxSpecJSI(std::shared_ptr jsInvoker) + : TurboModule("NativeRNFBTurboFirestore", jsInvoker) { + methodMap_["setLogLevel"] = MethodMetadata {1, __hostFunction_NativeRNFBTurboFirestoreCxxSpecJSI_setLogLevel}; + methodMap_["loadBundle"] = MethodMetadata {3, __hostFunction_NativeRNFBTurboFirestoreCxxSpecJSI_loadBundle}; + methodMap_["clearPersistence"] = MethodMetadata {2, __hostFunction_NativeRNFBTurboFirestoreCxxSpecJSI_clearPersistence}; + methodMap_["waitForPendingWrites"] = MethodMetadata {2, __hostFunction_NativeRNFBTurboFirestoreCxxSpecJSI_waitForPendingWrites}; + methodMap_["disableNetwork"] = MethodMetadata {2, __hostFunction_NativeRNFBTurboFirestoreCxxSpecJSI_disableNetwork}; + methodMap_["enableNetwork"] = MethodMetadata {2, __hostFunction_NativeRNFBTurboFirestoreCxxSpecJSI_enableNetwork}; + methodMap_["useEmulator"] = MethodMetadata {4, __hostFunction_NativeRNFBTurboFirestoreCxxSpecJSI_useEmulator}; + methodMap_["settings"] = MethodMetadata {3, __hostFunction_NativeRNFBTurboFirestoreCxxSpecJSI_settings}; + methodMap_["terminate"] = MethodMetadata {2, __hostFunction_NativeRNFBTurboFirestoreCxxSpecJSI_terminate}; + methodMap_["persistenceCacheIndexManager"] = MethodMetadata {3, __hostFunction_NativeRNFBTurboFirestoreCxxSpecJSI_persistenceCacheIndexManager}; + methodMap_["addSnapshotsInSync"] = MethodMetadata {3, __hostFunction_NativeRNFBTurboFirestoreCxxSpecJSI_addSnapshotsInSync}; + methodMap_["removeSnapshotsInSync"] = MethodMetadata {3, __hostFunction_NativeRNFBTurboFirestoreCxxSpecJSI_removeSnapshotsInSync}; +} +static jsi::Value __hostFunction_NativeRNFBTurboFirestoreCollectionCxxSpecJSI_namedQueryOnSnapshot(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + static_cast(&turboModule)->namedQueryOnSnapshot( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt), + count <= 2 ? throw jsi::JSError(rt, "Expected argument in position 2 to be passed") : args[2].asString(rt), + count <= 3 ? throw jsi::JSError(rt, "Expected argument in position 3 to be passed") : args[3].asString(rt), + count <= 4 ? throw jsi::JSError(rt, "Expected argument in position 4 to be passed") : args[4].asObject(rt).asArray(rt), + count <= 5 ? throw jsi::JSError(rt, "Expected argument in position 5 to be passed") : args[5].asObject(rt).asArray(rt), + count <= 6 ? throw jsi::JSError(rt, "Expected argument in position 6 to be passed") : args[6].asObject(rt), + count <= 7 ? throw jsi::JSError(rt, "Expected argument in position 7 to be passed") : args[7].asNumber(), + count <= 8 ? throw jsi::JSError(rt, "Expected argument in position 8 to be passed") : args[8].asObject(rt) + ); + return jsi::Value::undefined(); +} +static jsi::Value __hostFunction_NativeRNFBTurboFirestoreCollectionCxxSpecJSI_collectionOnSnapshot(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + static_cast(&turboModule)->collectionOnSnapshot( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt), + count <= 2 ? throw jsi::JSError(rt, "Expected argument in position 2 to be passed") : args[2].asString(rt), + count <= 3 ? throw jsi::JSError(rt, "Expected argument in position 3 to be passed") : args[3].asString(rt), + count <= 4 ? throw jsi::JSError(rt, "Expected argument in position 4 to be passed") : args[4].asObject(rt).asArray(rt), + count <= 5 ? throw jsi::JSError(rt, "Expected argument in position 5 to be passed") : args[5].asObject(rt).asArray(rt), + count <= 6 ? throw jsi::JSError(rt, "Expected argument in position 6 to be passed") : args[6].asObject(rt), + count <= 7 ? throw jsi::JSError(rt, "Expected argument in position 7 to be passed") : args[7].asNumber(), + count <= 8 ? throw jsi::JSError(rt, "Expected argument in position 8 to be passed") : args[8].asObject(rt) + ); + return jsi::Value::undefined(); +} +static jsi::Value __hostFunction_NativeRNFBTurboFirestoreCollectionCxxSpecJSI_collectionOffSnapshot(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + static_cast(&turboModule)->collectionOffSnapshot( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt), + count <= 2 ? throw jsi::JSError(rt, "Expected argument in position 2 to be passed") : args[2].asNumber() + ); + return jsi::Value::undefined(); +} +static jsi::Value __hostFunction_NativeRNFBTurboFirestoreCollectionCxxSpecJSI_namedQueryGet(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->namedQueryGet( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt), + count <= 2 ? throw jsi::JSError(rt, "Expected argument in position 2 to be passed") : args[2].asString(rt), + count <= 3 ? throw jsi::JSError(rt, "Expected argument in position 3 to be passed") : args[3].asString(rt), + count <= 4 ? throw jsi::JSError(rt, "Expected argument in position 4 to be passed") : args[4].asObject(rt).asArray(rt), + count <= 5 ? throw jsi::JSError(rt, "Expected argument in position 5 to be passed") : args[5].asObject(rt).asArray(rt), + count <= 6 ? throw jsi::JSError(rt, "Expected argument in position 6 to be passed") : args[6].asObject(rt), + count <= 7 || args[7].isUndefined() ? std::nullopt : std::make_optional(args[7].asObject(rt)) + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboFirestoreCollectionCxxSpecJSI_collectionGet(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->collectionGet( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt), + count <= 2 ? throw jsi::JSError(rt, "Expected argument in position 2 to be passed") : args[2].asString(rt), + count <= 3 ? throw jsi::JSError(rt, "Expected argument in position 3 to be passed") : args[3].asString(rt), + count <= 4 ? throw jsi::JSError(rt, "Expected argument in position 4 to be passed") : args[4].asObject(rt).asArray(rt), + count <= 5 ? throw jsi::JSError(rt, "Expected argument in position 5 to be passed") : args[5].asObject(rt).asArray(rt), + count <= 6 ? throw jsi::JSError(rt, "Expected argument in position 6 to be passed") : args[6].asObject(rt), + count <= 7 || args[7].isUndefined() ? std::nullopt : std::make_optional(args[7].asObject(rt)) + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboFirestoreCollectionCxxSpecJSI_collectionCount(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->collectionCount( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt), + count <= 2 ? throw jsi::JSError(rt, "Expected argument in position 2 to be passed") : args[2].asString(rt), + count <= 3 ? throw jsi::JSError(rt, "Expected argument in position 3 to be passed") : args[3].asString(rt), + count <= 4 ? throw jsi::JSError(rt, "Expected argument in position 4 to be passed") : args[4].asObject(rt).asArray(rt), + count <= 5 ? throw jsi::JSError(rt, "Expected argument in position 5 to be passed") : args[5].asObject(rt).asArray(rt), + count <= 6 ? throw jsi::JSError(rt, "Expected argument in position 6 to be passed") : args[6].asObject(rt) + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboFirestoreCollectionCxxSpecJSI_aggregateQuery(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->aggregateQuery( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt), + count <= 2 ? throw jsi::JSError(rt, "Expected argument in position 2 to be passed") : args[2].asString(rt), + count <= 3 ? throw jsi::JSError(rt, "Expected argument in position 3 to be passed") : args[3].asString(rt), + count <= 4 ? throw jsi::JSError(rt, "Expected argument in position 4 to be passed") : args[4].asObject(rt).asArray(rt), + count <= 5 ? throw jsi::JSError(rt, "Expected argument in position 5 to be passed") : args[5].asObject(rt).asArray(rt), + count <= 6 ? throw jsi::JSError(rt, "Expected argument in position 6 to be passed") : args[6].asObject(rt), + count <= 7 ? throw jsi::JSError(rt, "Expected argument in position 7 to be passed") : args[7].asObject(rt).asArray(rt) + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboFirestoreCollectionCxxSpecJSI_pipelineExecute(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->pipelineExecute( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt), + count <= 2 ? throw jsi::JSError(rt, "Expected argument in position 2 to be passed") : args[2].asObject(rt), + count <= 3 || args[3].isUndefined() ? std::nullopt : std::make_optional(args[3].asObject(rt)) + ); +} + +NativeRNFBTurboFirestoreCollectionCxxSpecJSI::NativeRNFBTurboFirestoreCollectionCxxSpecJSI(std::shared_ptr jsInvoker) + : TurboModule("NativeRNFBTurboFirestoreCollection", jsInvoker) { + methodMap_["namedQueryOnSnapshot"] = MethodMetadata {9, __hostFunction_NativeRNFBTurboFirestoreCollectionCxxSpecJSI_namedQueryOnSnapshot}; + methodMap_["collectionOnSnapshot"] = MethodMetadata {9, __hostFunction_NativeRNFBTurboFirestoreCollectionCxxSpecJSI_collectionOnSnapshot}; + methodMap_["collectionOffSnapshot"] = MethodMetadata {3, __hostFunction_NativeRNFBTurboFirestoreCollectionCxxSpecJSI_collectionOffSnapshot}; + methodMap_["namedQueryGet"] = MethodMetadata {8, __hostFunction_NativeRNFBTurboFirestoreCollectionCxxSpecJSI_namedQueryGet}; + methodMap_["collectionGet"] = MethodMetadata {8, __hostFunction_NativeRNFBTurboFirestoreCollectionCxxSpecJSI_collectionGet}; + methodMap_["collectionCount"] = MethodMetadata {7, __hostFunction_NativeRNFBTurboFirestoreCollectionCxxSpecJSI_collectionCount}; + methodMap_["aggregateQuery"] = MethodMetadata {8, __hostFunction_NativeRNFBTurboFirestoreCollectionCxxSpecJSI_aggregateQuery}; + methodMap_["pipelineExecute"] = MethodMetadata {4, __hostFunction_NativeRNFBTurboFirestoreCollectionCxxSpecJSI_pipelineExecute}; +} +static jsi::Value __hostFunction_NativeRNFBTurboFirestoreDocumentCxxSpecJSI_documentOnSnapshot(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + static_cast(&turboModule)->documentOnSnapshot( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt), + count <= 2 ? throw jsi::JSError(rt, "Expected argument in position 2 to be passed") : args[2].asString(rt), + count <= 3 ? throw jsi::JSError(rt, "Expected argument in position 3 to be passed") : args[3].asNumber(), + count <= 4 ? throw jsi::JSError(rt, "Expected argument in position 4 to be passed") : args[4].asObject(rt) + ); + return jsi::Value::undefined(); +} +static jsi::Value __hostFunction_NativeRNFBTurboFirestoreDocumentCxxSpecJSI_documentOffSnapshot(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + static_cast(&turboModule)->documentOffSnapshot( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt), + count <= 2 ? throw jsi::JSError(rt, "Expected argument in position 2 to be passed") : args[2].asNumber() + ); + return jsi::Value::undefined(); +} +static jsi::Value __hostFunction_NativeRNFBTurboFirestoreDocumentCxxSpecJSI_documentGet(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->documentGet( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt), + count <= 2 ? throw jsi::JSError(rt, "Expected argument in position 2 to be passed") : args[2].asString(rt), + count <= 3 || args[3].isUndefined() ? std::nullopt : std::make_optional(args[3].asObject(rt)) + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboFirestoreDocumentCxxSpecJSI_documentDelete(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->documentDelete( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt), + count <= 2 ? throw jsi::JSError(rt, "Expected argument in position 2 to be passed") : args[2].asString(rt) + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboFirestoreDocumentCxxSpecJSI_documentSet(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->documentSet( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt), + count <= 2 ? throw jsi::JSError(rt, "Expected argument in position 2 to be passed") : args[2].asString(rt), + count <= 3 ? throw jsi::JSError(rt, "Expected argument in position 3 to be passed") : args[3].asObject(rt), + count <= 4 ? throw jsi::JSError(rt, "Expected argument in position 4 to be passed") : args[4].asObject(rt) + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboFirestoreDocumentCxxSpecJSI_documentUpdate(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->documentUpdate( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt), + count <= 2 ? throw jsi::JSError(rt, "Expected argument in position 2 to be passed") : args[2].asString(rt), + count <= 3 ? throw jsi::JSError(rt, "Expected argument in position 3 to be passed") : args[3].asObject(rt) + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboFirestoreDocumentCxxSpecJSI_documentBatch(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->documentBatch( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt), + count <= 2 ? throw jsi::JSError(rt, "Expected argument in position 2 to be passed") : args[2].asObject(rt).asArray(rt) + ); +} + +NativeRNFBTurboFirestoreDocumentCxxSpecJSI::NativeRNFBTurboFirestoreDocumentCxxSpecJSI(std::shared_ptr jsInvoker) + : TurboModule("NativeRNFBTurboFirestoreDocument", jsInvoker) { + methodMap_["documentOnSnapshot"] = MethodMetadata {5, __hostFunction_NativeRNFBTurboFirestoreDocumentCxxSpecJSI_documentOnSnapshot}; + methodMap_["documentOffSnapshot"] = MethodMetadata {3, __hostFunction_NativeRNFBTurboFirestoreDocumentCxxSpecJSI_documentOffSnapshot}; + methodMap_["documentGet"] = MethodMetadata {4, __hostFunction_NativeRNFBTurboFirestoreDocumentCxxSpecJSI_documentGet}; + methodMap_["documentDelete"] = MethodMetadata {3, __hostFunction_NativeRNFBTurboFirestoreDocumentCxxSpecJSI_documentDelete}; + methodMap_["documentSet"] = MethodMetadata {5, __hostFunction_NativeRNFBTurboFirestoreDocumentCxxSpecJSI_documentSet}; + methodMap_["documentUpdate"] = MethodMetadata {4, __hostFunction_NativeRNFBTurboFirestoreDocumentCxxSpecJSI_documentUpdate}; + methodMap_["documentBatch"] = MethodMetadata {3, __hostFunction_NativeRNFBTurboFirestoreDocumentCxxSpecJSI_documentBatch}; +} +static jsi::Value __hostFunction_NativeRNFBTurboFirestoreTransactionCxxSpecJSI_transactionBegin(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + static_cast(&turboModule)->transactionBegin( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt), + count <= 2 ? throw jsi::JSError(rt, "Expected argument in position 2 to be passed") : args[2].asNumber() + ); + return jsi::Value::undefined(); +} +static jsi::Value __hostFunction_NativeRNFBTurboFirestoreTransactionCxxSpecJSI_transactionGetDocument(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->transactionGetDocument( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt), + count <= 2 ? throw jsi::JSError(rt, "Expected argument in position 2 to be passed") : args[2].asNumber(), + count <= 3 ? throw jsi::JSError(rt, "Expected argument in position 3 to be passed") : args[3].asString(rt) + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboFirestoreTransactionCxxSpecJSI_transactionDispose(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + static_cast(&turboModule)->transactionDispose( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt), + count <= 2 ? throw jsi::JSError(rt, "Expected argument in position 2 to be passed") : args[2].asNumber() + ); + return jsi::Value::undefined(); +} +static jsi::Value __hostFunction_NativeRNFBTurboFirestoreTransactionCxxSpecJSI_transactionApplyBuffer(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + static_cast(&turboModule)->transactionApplyBuffer( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt), + count <= 2 ? throw jsi::JSError(rt, "Expected argument in position 2 to be passed") : args[2].asNumber(), + count <= 3 ? throw jsi::JSError(rt, "Expected argument in position 3 to be passed") : args[3].asObject(rt).asArray(rt) + ); + return jsi::Value::undefined(); +} + +NativeRNFBTurboFirestoreTransactionCxxSpecJSI::NativeRNFBTurboFirestoreTransactionCxxSpecJSI(std::shared_ptr jsInvoker) + : TurboModule("NativeRNFBTurboFirestoreTransaction", jsInvoker) { + methodMap_["transactionBegin"] = MethodMetadata {3, __hostFunction_NativeRNFBTurboFirestoreTransactionCxxSpecJSI_transactionBegin}; + methodMap_["transactionGetDocument"] = MethodMetadata {4, __hostFunction_NativeRNFBTurboFirestoreTransactionCxxSpecJSI_transactionGetDocument}; + methodMap_["transactionDispose"] = MethodMetadata {3, __hostFunction_NativeRNFBTurboFirestoreTransactionCxxSpecJSI_transactionDispose}; + methodMap_["transactionApplyBuffer"] = MethodMetadata {4, __hostFunction_NativeRNFBTurboFirestoreTransactionCxxSpecJSI_transactionApplyBuffer}; +} + + +} // namespace facebook::react diff --git a/packages/firestore/ios/generated/RNFBFirestoreTurboModulesJSI.h b/packages/firestore/ios/generated/RNFBFirestoreTurboModulesJSI.h new file mode 100644 index 0000000000..0a6983ebd3 --- /dev/null +++ b/packages/firestore/ios/generated/RNFBFirestoreTurboModulesJSI.h @@ -0,0 +1,637 @@ +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleH.js + */ + +#pragma once + +#include +#include + +namespace facebook::react { + + + +#pragma mark - NativeRNFBTurboFirestoreFirestoreLoadBundleTaskProgress + +template +struct NativeRNFBTurboFirestoreFirestoreLoadBundleTaskProgress { + P0 bytesLoaded; + P1 documentsLoaded; + P2 totalBytes; + P3 totalDocuments; + P4 taskState; + bool operator==(const NativeRNFBTurboFirestoreFirestoreLoadBundleTaskProgress &other) const { + return bytesLoaded == other.bytesLoaded && documentsLoaded == other.documentsLoaded && totalBytes == other.totalBytes && totalDocuments == other.totalDocuments && taskState == other.taskState; + } +}; + +template +struct NativeRNFBTurboFirestoreFirestoreLoadBundleTaskProgressBridging { + static T types; + + static T fromJs( + jsi::Runtime &rt, + const jsi::Object &value, + const std::shared_ptr &jsInvoker) { + T result{ + bridging::fromJs(rt, value.getProperty(rt, "bytesLoaded"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, "documentsLoaded"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, "totalBytes"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, "totalDocuments"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, "taskState"), jsInvoker)}; + return result; + } + +#ifdef DEBUG + static double bytesLoadedToJs(jsi::Runtime &rt, decltype(types.bytesLoaded) value) { + return bridging::toJs(rt, value); + } + + static double documentsLoadedToJs(jsi::Runtime &rt, decltype(types.documentsLoaded) value) { + return bridging::toJs(rt, value); + } + + static double totalBytesToJs(jsi::Runtime &rt, decltype(types.totalBytes) value) { + return bridging::toJs(rt, value); + } + + static double totalDocumentsToJs(jsi::Runtime &rt, decltype(types.totalDocuments) value) { + return bridging::toJs(rt, value); + } + + static jsi::String taskStateToJs(jsi::Runtime &rt, decltype(types.taskState) value) { + return bridging::toJs(rt, value); + } +#endif + + static jsi::Object toJs( + jsi::Runtime &rt, + const T &value, + const std::shared_ptr &jsInvoker) { + auto result = facebook::jsi::Object(rt); + result.setProperty(rt, "bytesLoaded", bridging::toJs(rt, value.bytesLoaded, jsInvoker)); + result.setProperty(rt, "documentsLoaded", bridging::toJs(rt, value.documentsLoaded, jsInvoker)); + result.setProperty(rt, "totalBytes", bridging::toJs(rt, value.totalBytes, jsInvoker)); + result.setProperty(rt, "totalDocuments", bridging::toJs(rt, value.totalDocuments, jsInvoker)); + result.setProperty(rt, "taskState", bridging::toJs(rt, value.taskState, jsInvoker)); + return result; + } +}; + +class JSI_EXPORT NativeRNFBTurboFirestoreCxxSpecJSI : public TurboModule { +protected: + NativeRNFBTurboFirestoreCxxSpecJSI(std::shared_ptr jsInvoker); + +public: + virtual void setLogLevel(jsi::Runtime &rt, jsi::String logLevel) = 0; + virtual jsi::Value loadBundle(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, jsi::String bundle) = 0; + virtual jsi::Value clearPersistence(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId) = 0; + virtual jsi::Value waitForPendingWrites(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId) = 0; + virtual jsi::Value disableNetwork(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId) = 0; + virtual jsi::Value enableNetwork(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId) = 0; + virtual void useEmulator(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, jsi::String host, double port) = 0; + virtual jsi::Value settings(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, jsi::Object settings) = 0; + virtual jsi::Value terminate(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId) = 0; + virtual jsi::Value persistenceCacheIndexManager(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, double requestType) = 0; + virtual void addSnapshotsInSync(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, double listenerId) = 0; + virtual void removeSnapshotsInSync(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, double listenerId) = 0; + +}; + +template +class JSI_EXPORT NativeRNFBTurboFirestoreCxxSpec : public TurboModule { +public: + jsi::Value create(jsi::Runtime &rt, const jsi::PropNameID &propName) override { + return delegate_.create(rt, propName); + } + + std::vector getPropertyNames(jsi::Runtime& runtime) override { + return delegate_.getPropertyNames(runtime); + } + + static constexpr std::string_view kModuleName = "NativeRNFBTurboFirestore"; + +protected: + NativeRNFBTurboFirestoreCxxSpec(std::shared_ptr jsInvoker) + : TurboModule(std::string{NativeRNFBTurboFirestoreCxxSpec::kModuleName}, jsInvoker), + delegate_(reinterpret_cast(this), jsInvoker) {} + + +private: + class Delegate : public NativeRNFBTurboFirestoreCxxSpecJSI { + public: + Delegate(T *instance, std::shared_ptr jsInvoker) : + NativeRNFBTurboFirestoreCxxSpecJSI(std::move(jsInvoker)), instance_(instance) { + + } + + void setLogLevel(jsi::Runtime &rt, jsi::String logLevel) override { + static_assert( + bridging::getParameterCount(&T::setLogLevel) == 2, + "Expected setLogLevel(...) to have 2 parameters"); + + return bridging::callFromJs( + rt, &T::setLogLevel, jsInvoker_, instance_, std::move(logLevel)); + } + jsi::Value loadBundle(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, jsi::String bundle) override { + static_assert( + bridging::getParameterCount(&T::loadBundle) == 4, + "Expected loadBundle(...) to have 4 parameters"); + + return bridging::callFromJs( + rt, &T::loadBundle, jsInvoker_, instance_, std::move(appName), std::move(databaseId), std::move(bundle)); + } + jsi::Value clearPersistence(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId) override { + static_assert( + bridging::getParameterCount(&T::clearPersistence) == 3, + "Expected clearPersistence(...) to have 3 parameters"); + + return bridging::callFromJs( + rt, &T::clearPersistence, jsInvoker_, instance_, std::move(appName), std::move(databaseId)); + } + jsi::Value waitForPendingWrites(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId) override { + static_assert( + bridging::getParameterCount(&T::waitForPendingWrites) == 3, + "Expected waitForPendingWrites(...) to have 3 parameters"); + + return bridging::callFromJs( + rt, &T::waitForPendingWrites, jsInvoker_, instance_, std::move(appName), std::move(databaseId)); + } + jsi::Value disableNetwork(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId) override { + static_assert( + bridging::getParameterCount(&T::disableNetwork) == 3, + "Expected disableNetwork(...) to have 3 parameters"); + + return bridging::callFromJs( + rt, &T::disableNetwork, jsInvoker_, instance_, std::move(appName), std::move(databaseId)); + } + jsi::Value enableNetwork(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId) override { + static_assert( + bridging::getParameterCount(&T::enableNetwork) == 3, + "Expected enableNetwork(...) to have 3 parameters"); + + return bridging::callFromJs( + rt, &T::enableNetwork, jsInvoker_, instance_, std::move(appName), std::move(databaseId)); + } + void useEmulator(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, jsi::String host, double port) override { + static_assert( + bridging::getParameterCount(&T::useEmulator) == 5, + "Expected useEmulator(...) to have 5 parameters"); + + return bridging::callFromJs( + rt, &T::useEmulator, jsInvoker_, instance_, std::move(appName), std::move(databaseId), std::move(host), std::move(port)); + } + jsi::Value settings(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, jsi::Object settings) override { + static_assert( + bridging::getParameterCount(&T::settings) == 4, + "Expected settings(...) to have 4 parameters"); + + return bridging::callFromJs( + rt, &T::settings, jsInvoker_, instance_, std::move(appName), std::move(databaseId), std::move(settings)); + } + jsi::Value terminate(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId) override { + static_assert( + bridging::getParameterCount(&T::terminate) == 3, + "Expected terminate(...) to have 3 parameters"); + + return bridging::callFromJs( + rt, &T::terminate, jsInvoker_, instance_, std::move(appName), std::move(databaseId)); + } + jsi::Value persistenceCacheIndexManager(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, double requestType) override { + static_assert( + bridging::getParameterCount(&T::persistenceCacheIndexManager) == 4, + "Expected persistenceCacheIndexManager(...) to have 4 parameters"); + + return bridging::callFromJs( + rt, &T::persistenceCacheIndexManager, jsInvoker_, instance_, std::move(appName), std::move(databaseId), std::move(requestType)); + } + void addSnapshotsInSync(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, double listenerId) override { + static_assert( + bridging::getParameterCount(&T::addSnapshotsInSync) == 4, + "Expected addSnapshotsInSync(...) to have 4 parameters"); + + return bridging::callFromJs( + rt, &T::addSnapshotsInSync, jsInvoker_, instance_, std::move(appName), std::move(databaseId), std::move(listenerId)); + } + void removeSnapshotsInSync(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, double listenerId) override { + static_assert( + bridging::getParameterCount(&T::removeSnapshotsInSync) == 4, + "Expected removeSnapshotsInSync(...) to have 4 parameters"); + + return bridging::callFromJs( + rt, &T::removeSnapshotsInSync, jsInvoker_, instance_, std::move(appName), std::move(databaseId), std::move(listenerId)); + } + + private: + friend class NativeRNFBTurboFirestoreCxxSpec; + T *instance_; + }; + + Delegate delegate_; +}; + + + +#pragma mark - NativeRNFBTurboFirestoreCollectionFirestoreCollectionCountResult + +template +struct NativeRNFBTurboFirestoreCollectionFirestoreCollectionCountResult { + P0 count; + bool operator==(const NativeRNFBTurboFirestoreCollectionFirestoreCollectionCountResult &other) const { + return count == other.count; + } +}; + +template +struct NativeRNFBTurboFirestoreCollectionFirestoreCollectionCountResultBridging { + static T types; + + static T fromJs( + jsi::Runtime &rt, + const jsi::Object &value, + const std::shared_ptr &jsInvoker) { + T result{ + bridging::fromJs(rt, value.getProperty(rt, "count"), jsInvoker)}; + return result; + } + +#ifdef DEBUG + static double countToJs(jsi::Runtime &rt, decltype(types.count) value) { + return bridging::toJs(rt, value); + } +#endif + + static jsi::Object toJs( + jsi::Runtime &rt, + const T &value, + const std::shared_ptr &jsInvoker) { + auto result = facebook::jsi::Object(rt); + if (value.count) { + result.setProperty(rt, "count", bridging::toJs(rt, value.count.value(), jsInvoker)); + } + return result; + } +}; + +class JSI_EXPORT NativeRNFBTurboFirestoreCollectionCxxSpecJSI : public TurboModule { +protected: + NativeRNFBTurboFirestoreCollectionCxxSpecJSI(std::shared_ptr jsInvoker); + +public: + virtual void namedQueryOnSnapshot(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, jsi::String queryName, jsi::String type, jsi::Array filters, jsi::Array orders, jsi::Object options, double listenerId, jsi::Object snapshotListenOptions) = 0; + virtual void collectionOnSnapshot(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, jsi::String path, jsi::String type, jsi::Array filters, jsi::Array orders, jsi::Object options, double listenerId, jsi::Object snapshotListenOptions) = 0; + virtual void collectionOffSnapshot(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, double listenerId) = 0; + virtual jsi::Value namedQueryGet(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, jsi::String queryName, jsi::String type, jsi::Array filters, jsi::Array orders, jsi::Object options, std::optional getOptions) = 0; + virtual jsi::Value collectionGet(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, jsi::String path, jsi::String type, jsi::Array filters, jsi::Array orders, jsi::Object options, std::optional getOptions) = 0; + virtual jsi::Value collectionCount(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, jsi::String path, jsi::String type, jsi::Array filters, jsi::Array orders, jsi::Object options) = 0; + virtual jsi::Value aggregateQuery(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, jsi::String path, jsi::String type, jsi::Array filters, jsi::Array orders, jsi::Object options, jsi::Array aggregateQueries) = 0; + virtual jsi::Value pipelineExecute(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, jsi::Object pipeline, std::optional options) = 0; + +}; + +template +class JSI_EXPORT NativeRNFBTurboFirestoreCollectionCxxSpec : public TurboModule { +public: + jsi::Value create(jsi::Runtime &rt, const jsi::PropNameID &propName) override { + return delegate_.create(rt, propName); + } + + std::vector getPropertyNames(jsi::Runtime& runtime) override { + return delegate_.getPropertyNames(runtime); + } + + static constexpr std::string_view kModuleName = "NativeRNFBTurboFirestoreCollection"; + +protected: + NativeRNFBTurboFirestoreCollectionCxxSpec(std::shared_ptr jsInvoker) + : TurboModule(std::string{NativeRNFBTurboFirestoreCollectionCxxSpec::kModuleName}, jsInvoker), + delegate_(reinterpret_cast(this), jsInvoker) {} + + +private: + class Delegate : public NativeRNFBTurboFirestoreCollectionCxxSpecJSI { + public: + Delegate(T *instance, std::shared_ptr jsInvoker) : + NativeRNFBTurboFirestoreCollectionCxxSpecJSI(std::move(jsInvoker)), instance_(instance) { + + } + + void namedQueryOnSnapshot(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, jsi::String queryName, jsi::String type, jsi::Array filters, jsi::Array orders, jsi::Object options, double listenerId, jsi::Object snapshotListenOptions) override { + static_assert( + bridging::getParameterCount(&T::namedQueryOnSnapshot) == 10, + "Expected namedQueryOnSnapshot(...) to have 10 parameters"); + + return bridging::callFromJs( + rt, &T::namedQueryOnSnapshot, jsInvoker_, instance_, std::move(appName), std::move(databaseId), std::move(queryName), std::move(type), std::move(filters), std::move(orders), std::move(options), std::move(listenerId), std::move(snapshotListenOptions)); + } + void collectionOnSnapshot(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, jsi::String path, jsi::String type, jsi::Array filters, jsi::Array orders, jsi::Object options, double listenerId, jsi::Object snapshotListenOptions) override { + static_assert( + bridging::getParameterCount(&T::collectionOnSnapshot) == 10, + "Expected collectionOnSnapshot(...) to have 10 parameters"); + + return bridging::callFromJs( + rt, &T::collectionOnSnapshot, jsInvoker_, instance_, std::move(appName), std::move(databaseId), std::move(path), std::move(type), std::move(filters), std::move(orders), std::move(options), std::move(listenerId), std::move(snapshotListenOptions)); + } + void collectionOffSnapshot(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, double listenerId) override { + static_assert( + bridging::getParameterCount(&T::collectionOffSnapshot) == 4, + "Expected collectionOffSnapshot(...) to have 4 parameters"); + + return bridging::callFromJs( + rt, &T::collectionOffSnapshot, jsInvoker_, instance_, std::move(appName), std::move(databaseId), std::move(listenerId)); + } + jsi::Value namedQueryGet(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, jsi::String queryName, jsi::String type, jsi::Array filters, jsi::Array orders, jsi::Object options, std::optional getOptions) override { + static_assert( + bridging::getParameterCount(&T::namedQueryGet) == 9, + "Expected namedQueryGet(...) to have 9 parameters"); + + return bridging::callFromJs( + rt, &T::namedQueryGet, jsInvoker_, instance_, std::move(appName), std::move(databaseId), std::move(queryName), std::move(type), std::move(filters), std::move(orders), std::move(options), std::move(getOptions)); + } + jsi::Value collectionGet(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, jsi::String path, jsi::String type, jsi::Array filters, jsi::Array orders, jsi::Object options, std::optional getOptions) override { + static_assert( + bridging::getParameterCount(&T::collectionGet) == 9, + "Expected collectionGet(...) to have 9 parameters"); + + return bridging::callFromJs( + rt, &T::collectionGet, jsInvoker_, instance_, std::move(appName), std::move(databaseId), std::move(path), std::move(type), std::move(filters), std::move(orders), std::move(options), std::move(getOptions)); + } + jsi::Value collectionCount(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, jsi::String path, jsi::String type, jsi::Array filters, jsi::Array orders, jsi::Object options) override { + static_assert( + bridging::getParameterCount(&T::collectionCount) == 8, + "Expected collectionCount(...) to have 8 parameters"); + + return bridging::callFromJs( + rt, &T::collectionCount, jsInvoker_, instance_, std::move(appName), std::move(databaseId), std::move(path), std::move(type), std::move(filters), std::move(orders), std::move(options)); + } + jsi::Value aggregateQuery(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, jsi::String path, jsi::String type, jsi::Array filters, jsi::Array orders, jsi::Object options, jsi::Array aggregateQueries) override { + static_assert( + bridging::getParameterCount(&T::aggregateQuery) == 9, + "Expected aggregateQuery(...) to have 9 parameters"); + + return bridging::callFromJs( + rt, &T::aggregateQuery, jsInvoker_, instance_, std::move(appName), std::move(databaseId), std::move(path), std::move(type), std::move(filters), std::move(orders), std::move(options), std::move(aggregateQueries)); + } + jsi::Value pipelineExecute(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, jsi::Object pipeline, std::optional options) override { + static_assert( + bridging::getParameterCount(&T::pipelineExecute) == 5, + "Expected pipelineExecute(...) to have 5 parameters"); + + return bridging::callFromJs( + rt, &T::pipelineExecute, jsInvoker_, instance_, std::move(appName), std::move(databaseId), std::move(pipeline), std::move(options)); + } + + private: + friend class NativeRNFBTurboFirestoreCollectionCxxSpec; + T *instance_; + }; + + Delegate delegate_; +}; + + + +#pragma mark - NativeRNFBTurboFirestoreDocumentFirestoreSnapshotListenOptions + +template +struct NativeRNFBTurboFirestoreDocumentFirestoreSnapshotListenOptions { + P0 includeMetadataChanges; + P1 source; + bool operator==(const NativeRNFBTurboFirestoreDocumentFirestoreSnapshotListenOptions &other) const { + return includeMetadataChanges == other.includeMetadataChanges && source == other.source; + } +}; + +template +struct NativeRNFBTurboFirestoreDocumentFirestoreSnapshotListenOptionsBridging { + static T types; + + static T fromJs( + jsi::Runtime &rt, + const jsi::Object &value, + const std::shared_ptr &jsInvoker) { + T result{ + bridging::fromJs(rt, value.getProperty(rt, "includeMetadataChanges"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, "source"), jsInvoker)}; + return result; + } + +#ifdef DEBUG + static bool includeMetadataChangesToJs(jsi::Runtime &rt, decltype(types.includeMetadataChanges) value) { + return bridging::toJs(rt, value); + } + + static jsi::String sourceToJs(jsi::Runtime &rt, decltype(types.source) value) { + return bridging::toJs(rt, value); + } +#endif + + static jsi::Object toJs( + jsi::Runtime &rt, + const T &value, + const std::shared_ptr &jsInvoker) { + auto result = facebook::jsi::Object(rt); + if (value.includeMetadataChanges) { + result.setProperty(rt, "includeMetadataChanges", bridging::toJs(rt, value.includeMetadataChanges.value(), jsInvoker)); + } + if (value.source) { + result.setProperty(rt, "source", bridging::toJs(rt, value.source.value(), jsInvoker)); + } + return result; + } +}; + +class JSI_EXPORT NativeRNFBTurboFirestoreDocumentCxxSpecJSI : public TurboModule { +protected: + NativeRNFBTurboFirestoreDocumentCxxSpecJSI(std::shared_ptr jsInvoker); + +public: + virtual void documentOnSnapshot(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, jsi::String path, double listenerId, jsi::Object snapshotListenOptions) = 0; + virtual void documentOffSnapshot(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, double listenerId) = 0; + virtual jsi::Value documentGet(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, jsi::String path, std::optional getOptions) = 0; + virtual jsi::Value documentDelete(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, jsi::String path) = 0; + virtual jsi::Value documentSet(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, jsi::String path, jsi::Object data, jsi::Object options) = 0; + virtual jsi::Value documentUpdate(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, jsi::String path, jsi::Object data) = 0; + virtual jsi::Value documentBatch(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, jsi::Array writes) = 0; + +}; + +template +class JSI_EXPORT NativeRNFBTurboFirestoreDocumentCxxSpec : public TurboModule { +public: + jsi::Value create(jsi::Runtime &rt, const jsi::PropNameID &propName) override { + return delegate_.create(rt, propName); + } + + std::vector getPropertyNames(jsi::Runtime& runtime) override { + return delegate_.getPropertyNames(runtime); + } + + static constexpr std::string_view kModuleName = "NativeRNFBTurboFirestoreDocument"; + +protected: + NativeRNFBTurboFirestoreDocumentCxxSpec(std::shared_ptr jsInvoker) + : TurboModule(std::string{NativeRNFBTurboFirestoreDocumentCxxSpec::kModuleName}, jsInvoker), + delegate_(reinterpret_cast(this), jsInvoker) {} + + +private: + class Delegate : public NativeRNFBTurboFirestoreDocumentCxxSpecJSI { + public: + Delegate(T *instance, std::shared_ptr jsInvoker) : + NativeRNFBTurboFirestoreDocumentCxxSpecJSI(std::move(jsInvoker)), instance_(instance) { + + } + + void documentOnSnapshot(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, jsi::String path, double listenerId, jsi::Object snapshotListenOptions) override { + static_assert( + bridging::getParameterCount(&T::documentOnSnapshot) == 6, + "Expected documentOnSnapshot(...) to have 6 parameters"); + + return bridging::callFromJs( + rt, &T::documentOnSnapshot, jsInvoker_, instance_, std::move(appName), std::move(databaseId), std::move(path), std::move(listenerId), std::move(snapshotListenOptions)); + } + void documentOffSnapshot(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, double listenerId) override { + static_assert( + bridging::getParameterCount(&T::documentOffSnapshot) == 4, + "Expected documentOffSnapshot(...) to have 4 parameters"); + + return bridging::callFromJs( + rt, &T::documentOffSnapshot, jsInvoker_, instance_, std::move(appName), std::move(databaseId), std::move(listenerId)); + } + jsi::Value documentGet(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, jsi::String path, std::optional getOptions) override { + static_assert( + bridging::getParameterCount(&T::documentGet) == 5, + "Expected documentGet(...) to have 5 parameters"); + + return bridging::callFromJs( + rt, &T::documentGet, jsInvoker_, instance_, std::move(appName), std::move(databaseId), std::move(path), std::move(getOptions)); + } + jsi::Value documentDelete(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, jsi::String path) override { + static_assert( + bridging::getParameterCount(&T::documentDelete) == 4, + "Expected documentDelete(...) to have 4 parameters"); + + return bridging::callFromJs( + rt, &T::documentDelete, jsInvoker_, instance_, std::move(appName), std::move(databaseId), std::move(path)); + } + jsi::Value documentSet(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, jsi::String path, jsi::Object data, jsi::Object options) override { + static_assert( + bridging::getParameterCount(&T::documentSet) == 6, + "Expected documentSet(...) to have 6 parameters"); + + return bridging::callFromJs( + rt, &T::documentSet, jsInvoker_, instance_, std::move(appName), std::move(databaseId), std::move(path), std::move(data), std::move(options)); + } + jsi::Value documentUpdate(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, jsi::String path, jsi::Object data) override { + static_assert( + bridging::getParameterCount(&T::documentUpdate) == 5, + "Expected documentUpdate(...) to have 5 parameters"); + + return bridging::callFromJs( + rt, &T::documentUpdate, jsInvoker_, instance_, std::move(appName), std::move(databaseId), std::move(path), std::move(data)); + } + jsi::Value documentBatch(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, jsi::Array writes) override { + static_assert( + bridging::getParameterCount(&T::documentBatch) == 4, + "Expected documentBatch(...) to have 4 parameters"); + + return bridging::callFromJs( + rt, &T::documentBatch, jsInvoker_, instance_, std::move(appName), std::move(databaseId), std::move(writes)); + } + + private: + friend class NativeRNFBTurboFirestoreDocumentCxxSpec; + T *instance_; + }; + + Delegate delegate_; +}; + + + class JSI_EXPORT NativeRNFBTurboFirestoreTransactionCxxSpecJSI : public TurboModule { +protected: + NativeRNFBTurboFirestoreTransactionCxxSpecJSI(std::shared_ptr jsInvoker); + +public: + virtual void transactionBegin(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, double transactionId) = 0; + virtual jsi::Value transactionGetDocument(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, double transactionId, jsi::String path) = 0; + virtual void transactionDispose(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, double transactionId) = 0; + virtual void transactionApplyBuffer(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, double transactionId, jsi::Array commandBuffer) = 0; + +}; + +template +class JSI_EXPORT NativeRNFBTurboFirestoreTransactionCxxSpec : public TurboModule { +public: + jsi::Value create(jsi::Runtime &rt, const jsi::PropNameID &propName) override { + return delegate_.create(rt, propName); + } + + std::vector getPropertyNames(jsi::Runtime& runtime) override { + return delegate_.getPropertyNames(runtime); + } + + static constexpr std::string_view kModuleName = "NativeRNFBTurboFirestoreTransaction"; + +protected: + NativeRNFBTurboFirestoreTransactionCxxSpec(std::shared_ptr jsInvoker) + : TurboModule(std::string{NativeRNFBTurboFirestoreTransactionCxxSpec::kModuleName}, jsInvoker), + delegate_(reinterpret_cast(this), jsInvoker) {} + + +private: + class Delegate : public NativeRNFBTurboFirestoreTransactionCxxSpecJSI { + public: + Delegate(T *instance, std::shared_ptr jsInvoker) : + NativeRNFBTurboFirestoreTransactionCxxSpecJSI(std::move(jsInvoker)), instance_(instance) { + + } + + void transactionBegin(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, double transactionId) override { + static_assert( + bridging::getParameterCount(&T::transactionBegin) == 4, + "Expected transactionBegin(...) to have 4 parameters"); + + return bridging::callFromJs( + rt, &T::transactionBegin, jsInvoker_, instance_, std::move(appName), std::move(databaseId), std::move(transactionId)); + } + jsi::Value transactionGetDocument(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, double transactionId, jsi::String path) override { + static_assert( + bridging::getParameterCount(&T::transactionGetDocument) == 5, + "Expected transactionGetDocument(...) to have 5 parameters"); + + return bridging::callFromJs( + rt, &T::transactionGetDocument, jsInvoker_, instance_, std::move(appName), std::move(databaseId), std::move(transactionId), std::move(path)); + } + void transactionDispose(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, double transactionId) override { + static_assert( + bridging::getParameterCount(&T::transactionDispose) == 4, + "Expected transactionDispose(...) to have 4 parameters"); + + return bridging::callFromJs( + rt, &T::transactionDispose, jsInvoker_, instance_, std::move(appName), std::move(databaseId), std::move(transactionId)); + } + void transactionApplyBuffer(jsi::Runtime &rt, jsi::String appName, jsi::String databaseId, double transactionId, jsi::Array commandBuffer) override { + static_assert( + bridging::getParameterCount(&T::transactionApplyBuffer) == 5, + "Expected transactionApplyBuffer(...) to have 5 parameters"); + + return bridging::callFromJs( + rt, &T::transactionApplyBuffer, jsInvoker_, instance_, std::move(appName), std::move(databaseId), std::move(transactionId), std::move(commandBuffer)); + } + + private: + friend class NativeRNFBTurboFirestoreTransactionCxxSpec; + T *instance_; + }; + + Delegate delegate_; +}; + +} // namespace facebook::react diff --git a/packages/firestore/lib/FirestoreModule.ts b/packages/firestore/lib/FirestoreModule.ts index b70d388b48..d08f09e371 100644 --- a/packages/firestore/lib/FirestoreModule.ts +++ b/packages/firestore/lib/FirestoreModule.ts @@ -45,10 +45,10 @@ import fallBackModule from './web/RNFBFirestoreModule'; const namespace = 'firestore'; export const nativeModuleNames = [ - 'RNFBFirestoreModule', - 'RNFBFirestoreCollectionModule', - 'RNFBFirestoreDocumentModule', - 'RNFBFirestoreTransactionModule', + 'NativeRNFBTurboFirestore', + 'NativeRNFBTurboFirestoreCollection', + 'NativeRNFBTurboFirestoreDocument', + 'NativeRNFBTurboFirestoreTransaction', ] as const; const nativeEvents = [ @@ -64,6 +64,7 @@ export const config: ModuleConfig = { nativeEvents: [...nativeEvents], hasMultiAppSupport: true, hasCustomUrlOrRegionSupport: true, + turboModule: true, }; type FirestoreModuleSettingsState = { @@ -74,7 +75,7 @@ type FirestoreModuleSettingsState = { /** Sync event payload from emitter when fanning out collection/document/snapshots-in-sync events. */ type FirestoreSyncEventWithListenerId = { listenerId: string | number }; -export class FirebaseFirestoreModule extends FirebaseModule<'RNFBFirestoreModule'> { +export class FirebaseFirestoreModule extends FirebaseModule<'NativeRNFBTurboFirestore'> { type = 'firestore' as const; _referencePath: FirestorePath; _transactionHandler: FirestoreTransactionHandler; diff --git a/packages/firestore/lib/FirestoreStatics.ts b/packages/firestore/lib/FirestoreStatics.ts index 47756ebdbd..b5dae39520 100644 --- a/packages/firestore/lib/FirestoreStatics.ts +++ b/packages/firestore/lib/FirestoreStatics.ts @@ -15,7 +15,7 @@ * */ -import { getReactNativeModule } from '@react-native-firebase/app/dist/module/internal/nativeModule'; +import { getStaticFirestoreMainModule } from './internal/staticNativeModule'; import { Blob } from './FirestoreBlob'; import { FieldPath } from './FieldPath'; import { FieldValue } from './FieldValue'; @@ -24,7 +24,6 @@ import { GeoPoint } from './FirestoreGeoPoint'; import { Timestamp } from './FirestoreTimestamp'; import { VectorValue } from './FirestoreVectorValue'; import type { LogLevel } from './types/firestore'; -import type { RNFBFirestoreModule } from './types/internal'; type FirestoreLogLevel = LogLevel; @@ -49,8 +48,8 @@ const FirestoreStatics = { ); } - const native = getReactNativeModule('RNFBFirestoreModule') as unknown as RNFBFirestoreModule; - native.setLogLevel(logLevel); + // NewArch-AD-18 E8: static setLogLevel — no FirebaseModule instance; turbo main host. + getStaticFirestoreMainModule().setLogLevel(logLevel); }, }; diff --git a/packages/firestore/lib/internal/staticNativeModule.ts b/packages/firestore/lib/internal/staticNativeModule.ts new file mode 100644 index 0000000000..363c70081a --- /dev/null +++ b/packages/firestore/lib/internal/staticNativeModule.ts @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2016-present Invertase Limited & Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this library except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import { getReactNativeModule } from '@react-native-firebase/app/dist/module/internal/nativeModule'; +import type { LogLevel } from '../types/firestore'; + +const FIRESTORE_MAIN_NATIVE_MODULE = 'NativeRNFBTurboFirestore'; + +type StaticFirestoreMainModule = { + setLogLevel(level: LogLevel): void; +}; + +let memoizedMainModule: StaticFirestoreMainModule | null = null; + +/** Memoized main Firestore turbo host for static helpers (NewArch-AD-18 E8). */ +export function getStaticFirestoreMainModule(): StaticFirestoreMainModule { + if (memoizedMainModule) { + return memoizedMainModule; + } + + const native = getReactNativeModule( + FIRESTORE_MAIN_NATIVE_MODULE, + ) as StaticFirestoreMainModule | null; + + if (!native?.setLogLevel) { + throw new Error(`Native module ${FIRESTORE_MAIN_NATIVE_MODULE} is not registered.`); + } + + memoizedMainModule = { + setLogLevel: native.setLogLevel.bind(native), + }; + + return memoizedMainModule; +} diff --git a/packages/firestore/lib/types/internal.ts b/packages/firestore/lib/types/internal.ts index 5bb75c0365..edbbccbafc 100644 --- a/packages/firestore/lib/types/internal.ts +++ b/packages/firestore/lib/types/internal.ts @@ -422,14 +422,14 @@ export interface FirestoreEmitterInternal { * * Note: React Native Firebase internally wraps native methods and auto-prepends app name and * database ID when `hasMultiAppSupport` and `hasCustomUrlOrRegionSupport` are enabled. - * Firestore uses multiple native modules (RNFBFirestoreModule, RNFBFirestoreCollectionModule, - * RNFBFirestoreDocumentModule, RNFBFirestoreTransactionModule) which are merged into a single + * Firestore uses multiple native modules (NativeRNFBTurboFirestore, NativeRNFBTurboFirestoreCollection, + * NativeRNFBTurboFirestoreDocument, NativeRNFBTurboFirestoreTransaction) which are merged into a single * wrapped object. This interface represents that merged *wrapped* module shape exposed as * `this.native` within FirebaseFirestoreModule. */ export interface RNFBFirestoreModule { setLogLevel(level: LogLevel): Promise; - // --- Main Firestore module (RNFBFirestoreModule) --- + // --- Main Firestore module (NativeRNFBTurboFirestore) --- loadBundle(bundle: string): Promise; clearPersistence(): Promise; waitForPendingWrites(): Promise; @@ -450,7 +450,7 @@ export interface RNFBFirestoreModule { */ persistenceCacheIndexManager(mode: number): Promise; - // --- Collection module (RNFBFirestoreCollectionModule) --- + // --- Collection module (NativeRNFBTurboFirestoreCollection) --- collectionOffSnapshot(listenerId: number): void; namedQueryOnSnapshot( queryName: string, @@ -506,7 +506,7 @@ export interface RNFBFirestoreModule { options?: FirestorePipelineExecuteOptionsInternal, ): Promise; - // --- Document module (RNFBFirestoreDocumentModule) --- + // --- Document module (NativeRNFBTurboFirestoreDocument) --- documentDelete(path: string): Promise; documentOffSnapshot(listenerId: number): void; documentOnSnapshot( @@ -523,7 +523,7 @@ export interface RNFBFirestoreModule { documentUpdate(path: string, data: Record): Promise; documentBatch(writes: Array>): Promise; - // --- Transaction module (RNFBFirestoreTransactionModule) --- + // --- Transaction module (NativeRNFBTurboFirestoreTransaction) --- transactionBegin(transactionId: number): Promise; transactionDispose(transactionId: number): void; transactionGetDocument(transactionId: number, path: string): Promise; @@ -532,7 +532,10 @@ export interface RNFBFirestoreModule { declare module '@react-native-firebase/app/dist/module/internal/NativeModules' { interface ReactNativeFirebaseNativeModules { - RNFBFirestoreModule: RNFBFirestoreModule; + NativeRNFBTurboFirestore: RNFBFirestoreModule; + NativeRNFBTurboFirestoreCollection: RNFBFirestoreModule; + NativeRNFBTurboFirestoreDocument: RNFBFirestoreModule; + NativeRNFBTurboFirestoreTransaction: RNFBFirestoreModule; } } diff --git a/packages/firestore/package.json b/packages/firestore/package.json index 72ab42c8e9..ec57a4578d 100644 --- a/packages/firestore/package.json +++ b/packages/firestore/package.json @@ -5,11 +5,31 @@ "description": "React Native Firebase - Cloud Firestore is a NoSQL cloud database to store and sync data between your React Native application and Firebase's database. The API matches the Firebase Web SDK whilst taking advantage of the native SDKs performance and offline capabilities.", "main": "./dist/module/index.js", "types": "./dist/typescript/lib/index.d.ts", + "codegenConfig": { + "name": "RNFBFirestoreTurboModules", + "type": "modules", + "jsSrcsDir": "specs", + "includesGeneratedCode": true, + "android": { + "javaPackageName": "io.invertase.firebase.firestore" + }, + "ios": { + "modulesProvider": { + "NativeRNFBTurboFirestore": "RNFBFirestoreModule", + "NativeRNFBTurboFirestoreCollection": "RNFBFirestoreCollectionModule", + "NativeRNFBTurboFirestoreDocument": "RNFBFirestoreDocumentModule", + "NativeRNFBTurboFirestoreTransaction": "RNFBFirestoreTransactionModule" + } + } + }, "scripts": { "build": "genversion --esm --semi lib/version.ts", "build:clean": "rimraf android/build && rimraf ios/build", "compile": "bob build", - "prepare": "yarn run build && yarn compile" + "prepare": "yarn run build && yarn compile", + "codegen": "yarn android:codegen && yarn ios:codegen", + "android:codegen": "npx @react-native-community/cli codegen --platform android --outputPath=./android/src/reactnative/java/io/invertase/firebase/firestore/generated", + "ios:codegen": "npx @react-native-community/cli codegen --platform ios --outputPath=./ios/generated" }, "repository": { "type": "git", diff --git a/packages/firestore/react-native.config.js b/packages/firestore/react-native.config.js new file mode 100644 index 0000000000..a0045be577 --- /dev/null +++ b/packages/firestore/react-native.config.js @@ -0,0 +1,10 @@ +module.exports = { + dependency: { + platforms: { + android: { + cmakeListsPath: + './src/reactnative/java/io/invertase/firebase/firestore/generated/jni/CMakeLists.txt', + }, + }, + }, +}; diff --git a/packages/firestore/specs/NativeRNFBTurboFirestore.ts b/packages/firestore/specs/NativeRNFBTurboFirestore.ts new file mode 100644 index 0000000000..474eeb1f06 --- /dev/null +++ b/packages/firestore/specs/NativeRNFBTurboFirestore.ts @@ -0,0 +1,36 @@ +/* eslint-disable @typescript-eslint/no-wrapper-object-types */ +import type { TurboModule } from 'react-native'; +import { TurboModuleRegistry } from 'react-native'; + +export type FirestoreLoadBundleTaskProgress = { + bytesLoaded: number; + documentsLoaded: number; + totalBytes: number; + totalDocuments: number; + taskState: 'Running' | 'Success' | 'Error'; +}; + +export interface Spec extends TurboModule { + setLogLevel(logLevel: string): void; + loadBundle( + appName: string, + databaseId: string, + bundle: string, + ): Promise; + clearPersistence(appName: string, databaseId: string): Promise; + waitForPendingWrites(appName: string, databaseId: string): Promise; + disableNetwork(appName: string, databaseId: string): Promise; + enableNetwork(appName: string, databaseId: string): Promise; + useEmulator(appName: string, databaseId: string, host: string, port: number): void; + settings(appName: string, databaseId: string, settings: Object): Promise; + terminate(appName: string, databaseId: string): Promise; + persistenceCacheIndexManager( + appName: string, + databaseId: string, + requestType: number, + ): Promise; + addSnapshotsInSync(appName: string, databaseId: string, listenerId: number): void; + removeSnapshotsInSync(appName: string, databaseId: string, listenerId: number): void; +} + +export default TurboModuleRegistry.getEnforcing('NativeRNFBTurboFirestore'); diff --git a/packages/firestore/specs/NativeRNFBTurboFirestoreCollection.ts b/packages/firestore/specs/NativeRNFBTurboFirestoreCollection.ts new file mode 100644 index 0000000000..7c459fd7ab --- /dev/null +++ b/packages/firestore/specs/NativeRNFBTurboFirestoreCollection.ts @@ -0,0 +1,80 @@ +/* eslint-disable @typescript-eslint/no-wrapper-object-types */ +import type { TurboModule } from 'react-native'; +import { TurboModuleRegistry } from 'react-native'; + +export type FirestoreCollectionCountResult = { + count?: number; +}; + +export interface Spec extends TurboModule { + namedQueryOnSnapshot( + appName: string, + databaseId: string, + queryName: string, + type: string, + filters: ReadonlyArray, + orders: ReadonlyArray, + options: Object, + listenerId: number, + snapshotListenOptions: Object, + ): void; + collectionOnSnapshot( + appName: string, + databaseId: string, + path: string, + type: string, + filters: ReadonlyArray, + orders: ReadonlyArray, + options: Object, + listenerId: number, + snapshotListenOptions: Object, + ): void; + collectionOffSnapshot(appName: string, databaseId: string, listenerId: number): void; + namedQueryGet( + appName: string, + databaseId: string, + queryName: string, + type: string, + filters: ReadonlyArray, + orders: ReadonlyArray, + options: Object, + getOptions?: Object, + ): Promise; + collectionGet( + appName: string, + databaseId: string, + path: string, + type: string, + filters: ReadonlyArray, + orders: ReadonlyArray, + options: Object, + getOptions?: Object, + ): Promise; + collectionCount( + appName: string, + databaseId: string, + path: string, + type: string, + filters: ReadonlyArray, + orders: ReadonlyArray, + options: Object, + ): Promise; + aggregateQuery( + appName: string, + databaseId: string, + path: string, + type: string, + filters: ReadonlyArray, + orders: ReadonlyArray, + options: Object, + aggregateQueries: ReadonlyArray, + ): Promise; + pipelineExecute( + appName: string, + databaseId: string, + pipeline: Object, + options?: Object, + ): Promise; +} + +export default TurboModuleRegistry.getEnforcing('NativeRNFBTurboFirestoreCollection'); diff --git a/packages/firestore/specs/NativeRNFBTurboFirestoreDocument.ts b/packages/firestore/specs/NativeRNFBTurboFirestoreDocument.ts new file mode 100644 index 0000000000..79b27999fa --- /dev/null +++ b/packages/firestore/specs/NativeRNFBTurboFirestoreDocument.ts @@ -0,0 +1,37 @@ +/* eslint-disable @typescript-eslint/no-wrapper-object-types */ +import type { TurboModule } from 'react-native'; +import { TurboModuleRegistry } from 'react-native'; + +export type FirestoreSnapshotListenOptions = { + includeMetadataChanges?: boolean; + source?: string; +}; + +export interface Spec extends TurboModule { + documentOnSnapshot( + appName: string, + databaseId: string, + path: string, + listenerId: number, + snapshotListenOptions: FirestoreSnapshotListenOptions, + ): void; + documentOffSnapshot(appName: string, databaseId: string, listenerId: number): void; + documentGet( + appName: string, + databaseId: string, + path: string, + getOptions?: { source?: string }, + ): Promise; + documentDelete(appName: string, databaseId: string, path: string): Promise; + documentSet( + appName: string, + databaseId: string, + path: string, + data: Object, + options: Object, + ): Promise; + documentUpdate(appName: string, databaseId: string, path: string, data: Object): Promise; + documentBatch(appName: string, databaseId: string, writes: Object[]): Promise; +} + +export default TurboModuleRegistry.getEnforcing('NativeRNFBTurboFirestoreDocument'); diff --git a/packages/firestore/specs/NativeRNFBTurboFirestoreTransaction.ts b/packages/firestore/specs/NativeRNFBTurboFirestoreTransaction.ts new file mode 100644 index 0000000000..32367c6bfe --- /dev/null +++ b/packages/firestore/specs/NativeRNFBTurboFirestoreTransaction.ts @@ -0,0 +1,22 @@ +/* eslint-disable @typescript-eslint/no-wrapper-object-types */ +import type { TurboModule } from 'react-native'; +import { TurboModuleRegistry } from 'react-native'; + +export interface Spec extends TurboModule { + transactionBegin(appName: string, databaseId: string, transactionId: number): void; + transactionGetDocument( + appName: string, + databaseId: string, + transactionId: number, + path: string, + ): Promise; + transactionDispose(appName: string, databaseId: string, transactionId: number): void; + transactionApplyBuffer( + appName: string, + databaseId: string, + transactionId: number, + commandBuffer: Object[], + ): void; +} + +export default TurboModuleRegistry.getEnforcing('NativeRNFBTurboFirestoreTransaction'); diff --git a/tests/ios/Podfile.lock b/tests/ios/Podfile.lock index 8e36a5bdfe..f94f8bb7a7 100644 --- a/tests/ios/Podfile.lock +++ b/tests/ios/Podfile.lock @@ -2609,7 +2609,7 @@ SPEC CHECKSUMS: RNFBAuth: 6656cfdec1c2c7a238666ab46f00f37650ea4e86 RNFBCrashlytics: 023cb897d12145878e749cc6c105e7ae6bb08996 RNFBDatabase: 6205ca9a46bb177b1577dbf1dad08c5ea018cd67 - RNFBFirestore: df2a438176508cfefee7ac4b621f6ce5e152df1e + RNFBFirestore: 7b2480c59acae62bb9607cdf28c1e0e157641288 RNFBFunctions: d0ffe52e4f6138c3e42e69937b0592838e6f2cc9 RNFBInAppMessaging: bcb89b77069691d903621c83cfc3a1d6bfcb43b2 RNFBInstallations: 1073ed6c5b5f6da5378eca9f7c17bfbbd6deada6 From 6924759c5668eb47caa6b1a3f4990bfd33029cf1 Mon Sep 17 00:00:00 2001 From: Mike Hardy Date: Tue, 30 Jun 2026 18:41:52 -0500 Subject: [PATCH 05/10] fix(app, android): handle possible null external storage directory Environment.getExternalStoragePublicDirectory can return null when external storage is unavailable; guard the pictures and movies directory constants instead of dereferencing getAbsolutePath directly. --- .../firebase/utils/NativeRNFBTurboUtils.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/app/android/src/reactnative/java/io/invertase/firebase/utils/NativeRNFBTurboUtils.java b/packages/app/android/src/reactnative/java/io/invertase/firebase/utils/NativeRNFBTurboUtils.java index 7e31e75fe7..884d9ddbde 100644 --- a/packages/app/android/src/reactnative/java/io/invertase/firebase/utils/NativeRNFBTurboUtils.java +++ b/packages/app/android/src/reactnative/java/io/invertase/firebase/utils/NativeRNFBTurboUtils.java @@ -160,15 +160,15 @@ protected Map getTypedExportedConstants() { constants.put(KEY_DOCUMENT_DIRECTORY, context.getFilesDir().getAbsolutePath()); } + File picturesDirectory = + Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES); constants.put( - KEY_PICS_DIRECTORY, - Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) - .getAbsolutePath()); + KEY_PICS_DIRECTORY, picturesDirectory != null ? picturesDirectory.getAbsolutePath() : ""); + File moviesDirectory = + Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES); constants.put( - KEY_MOVIES_DIRECTORY, - Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES) - .getAbsolutePath()); + KEY_MOVIES_DIRECTORY, moviesDirectory != null ? moviesDirectory.getAbsolutePath() : ""); File externalStorageDirectory = Environment.getExternalStorageDirectory(); if (externalStorageDirectory != null) { From ee6a66d93121e48fe6be03b1ab4a32b901b7a786 Mon Sep 17 00:00:00 2001 From: Mike Hardy Date: Wed, 1 Jul 2026 07:05:41 -0500 Subject: [PATCH 06/10] feat(installations)!: migrate installations to TurboModules --- jest.setup.ts | 19 ++- .../new-architecture/migration-work-queue.md | 23 ++-- .../lib/internal/nativeModuleAndroidIos.ts | 2 +- .../installations/RNFBInstallations.podspec | 13 +- .../__tests__/nativeModuleContract.test.ts | 57 +++++++++ packages/installations/android/build.gradle | 19 +++ .../NativeRNFBTurboInstallations.java | 114 ++++++++++++++++++ ...actNativeFirebaseInstallationsPackage.java | 2 +- .../NativeRNFBTurboInstallationsSpec.java | 46 +++++++ .../generated/jni/CMakeLists.txt | 36 ++++++ ...NFBInstallationsTurboModules-generated.cpp | 44 +++++++ .../jni/RNFBInstallationsTurboModules.h | 31 +++++ ...InstallationsTurboModulesJSI-generated.cpp | 42 +++++++ .../RNFBInstallationsTurboModulesJSI.h | 89 ++++++++++++++ .../project.pbxproj | 8 +- .../RNFBInstallationsModule.h | 6 +- ...onsModule.m => RNFBInstallationsModule.mm} | 47 ++++---- ...RNFBInstallationsTurboModules-generated.mm | 53 ++++++++ .../RNFBInstallationsTurboModules.h | 71 +++++++++++ ...InstallationsTurboModulesJSI-generated.cpp | 42 +++++++ .../RNFBInstallationsTurboModulesJSI.h | 89 ++++++++++++++ packages/installations/lib/index.ts | 5 +- packages/installations/lib/types/internal.ts | 4 +- packages/installations/package.json | 19 ++- packages/installations/react-native.config.js | 10 ++ .../specs/NativeRNFBTurboInstallations.ts | 10 ++ 26 files changed, 843 insertions(+), 58 deletions(-) create mode 100644 packages/installations/__tests__/nativeModuleContract.test.ts create mode 100644 packages/installations/android/src/main/java/io/invertase/firebase/installations/NativeRNFBTurboInstallations.java create mode 100644 packages/installations/android/src/main/java/io/invertase/firebase/installations/generated/java/com/facebook/fbreact/specs/NativeRNFBTurboInstallationsSpec.java create mode 100644 packages/installations/android/src/main/java/io/invertase/firebase/installations/generated/jni/CMakeLists.txt create mode 100644 packages/installations/android/src/main/java/io/invertase/firebase/installations/generated/jni/RNFBInstallationsTurboModules-generated.cpp create mode 100644 packages/installations/android/src/main/java/io/invertase/firebase/installations/generated/jni/RNFBInstallationsTurboModules.h create mode 100644 packages/installations/android/src/main/java/io/invertase/firebase/installations/generated/jni/react/renderer/components/RNFBInstallationsTurboModules/RNFBInstallationsTurboModulesJSI-generated.cpp create mode 100644 packages/installations/android/src/main/java/io/invertase/firebase/installations/generated/jni/react/renderer/components/RNFBInstallationsTurboModules/RNFBInstallationsTurboModulesJSI.h rename packages/installations/ios/RNFBInstallations/{RNFBInstallationsModule.m => RNFBInstallationsModule.mm} (81%) create mode 100644 packages/installations/ios/generated/RNFBInstallationsTurboModules/RNFBInstallationsTurboModules-generated.mm create mode 100644 packages/installations/ios/generated/RNFBInstallationsTurboModules/RNFBInstallationsTurboModules.h create mode 100644 packages/installations/ios/generated/RNFBInstallationsTurboModulesJSI-generated.cpp create mode 100644 packages/installations/ios/generated/RNFBInstallationsTurboModulesJSI.h create mode 100644 packages/installations/react-native.config.js create mode 100644 packages/installations/specs/NativeRNFBTurboInstallations.ts diff --git a/jest.setup.ts b/jest.setup.ts index 67d781886e..d10acadf5e 100644 --- a/jest.setup.ts +++ b/jest.setup.ts @@ -211,7 +211,7 @@ jest.doMock('react-native', () => { addAppCheckListener: jest.fn(), removeAppCheckListener: jest.fn(), }, - RNFBAppDistributionModule: { + NativeRNFBTurboAppDistribution: { isTesterSignedIn: jest.fn(), signInTester: jest.fn(), checkForUpdate: jest.fn(), @@ -364,17 +364,21 @@ jest.doMock('react-native', () => { }), ), }, - RNFBFiamModule: { + NativeRNFBTurboFiam: { + getConstants: () => ({ + isMessagesDisplaySuppressed: false, + isAutomaticDataCollectionEnabled: true, + }), isMessagesDisplaySuppressed: false, isAutomaticDataCollectionEnabled: true, setMessagesDisplaySuppressed: jest.fn(), setAutomaticDataCollectionEnabled: jest.fn(), triggerEvent: jest.fn(), }, - RNFBInstallationsModule: { + NativeRNFBTurboInstallations: { getId: jest.fn(), getToken: jest.fn(), - delete: jest.fn(), + deleteInstallations: jest.fn(), }, RNFBMessagingModule: { isAutoInitEnabled: true, @@ -402,7 +406,11 @@ jest.doMock('react-native', () => { setDeliveryMetricsExportToBigQuery: jest.fn(), setNotificationDelegationEnabled: jest.fn(), }, - RNFBPerfModule: { + NativeRNFBTurboPerf: { + getConstants: () => ({ + isPerformanceCollectionEnabled: true, + isInstrumentationEnabled: true, + }), isPerformanceCollectionEnabled: true, isInstrumentationEnabled: true, instrumentationEnabled: jest.fn(() => Promise.resolve()), @@ -414,6 +422,7 @@ jest.doMock('react-native', () => { startHttpMetric: jest.fn(() => Promise.resolve()), stopHttpMetric: jest.fn(() => Promise.resolve()), }, + NativeRNFBTurboML: {}, RNFBConfigModule: { onConfigUpdated: jest.fn(), reset: jest.fn(() => diff --git a/okf-bundle/new-architecture/migration-work-queue.md b/okf-bundle/new-architecture/migration-work-queue.md index d0020ec0cb..63ff2b9427 100644 --- a/okf-bundle/new-architecture/migration-work-queue.md +++ b/okf-bundle/new-architecture/migration-work-queue.md @@ -8,7 +8,7 @@ timestamp: 2026-06-26T00:00:00Z # TurboModule migration — work queue -> **IN PROGRESS (2026-06-30):** Phase **2** easy wins — **queued**. Phases **0** / **0.1** (`app`) and Phase **1** (`firestore`) — **done**. Decisions: [architecture-decisions.md](architecture-decisions.md). +> **IN PROGRESS (2026-06-30):** Phase **2** — committing P2a `installations`. > **Goal/order:** app foundation → hard probe → easy wins → remaining complex → sync conversion → coordinated break → cleanup (events, shared-state encapsulation). Decisions: [architecture-decisions.md](architecture-decisions.md). Links: [implementation workflow](turbomodule-implementation-workflow.md), [change authoring](../testing/change-authoring-workflow.md), [functions reference](../../../packages/functions/) ([PR #8603](https://github.com/invertase/react-native-firebase/pull/8603)). Ephemeral tracker; see [OKF policy](../documentation-policy.md). @@ -163,7 +163,7 @@ Pick **one** of `firestore` or `auth` in Phase 1 (firestore = multi-module + pip | **0** | App foundation + unified resolver | **done** | `app` | | **0.1** | App modular type parity (`compare:types`) | **done** | `app` — [§ Phase 0.1](#phase-01-app-comparetypes) | | **1** | Hard probe | **done** | `firestore` (multi-module + pipelines; NewArch-AD-14a composite) | -| **2** | Easy wins | queued | `installations`, `perf`, `in-app-messaging`, `app-distribution`, `ml` | +| **2** | Easy wins | **commit-ready** | `installations`, `perf`, `in-app-messaging`, `app-distribution`, `ml` | | **3** | Moderate | queued | `app-check`, `remote-config`, `analytics`, `crashlytics`, `storage` | | **4** | Remaining complex | queued | other Tier A/B + `messaging`, `database` | | **5** | Android-only / misc | queued | `phone-number-verification` | @@ -267,13 +267,11 @@ Skip steps 1–2 when spec shape is known (most Tier D packages). ## Current snapshot -**Label:** `phase-2-easy-wins`; **harness:** n/a +**Label:** `phase-2-easy-wins`; **harness:** local overrides (delete before Phase R) -**Next item:** Phase **2** — pick first Tier D package (`installations`, `perf`, `in-app-messaging`, `app-distribution`, or `ml`) +**Next item:** Phase **2** P2a `installations` — **commit** -**Current gates:** Phase 0 / 0.1 / 1 all **closed** - -**Package pick (Phase 1):** `firestore` over `auth` — first multi-module package (×4 specs), exercises `pipelineExecute` + NewArch-AD-14a routing composite Proxy; defers largest single-spec (`auth` ×59) to Phase 4. +**Current gates:** P2a–P2e `commit_gate` **open** (impl + review closed) **Arbiter gate:** @@ -281,9 +279,14 @@ Skip steps 1–2 when spec shape is known (most Tier D packages). | Item | Code | `implementation_gate` | `review_gate` | `commit_gate` | `next_work_type` | `validation_tier` | `commit_subject` | Notes | |------|------|----------------------|---------------|---------------|------------------|-------------------|------------------|-------| | Design review | DR | n/a | n/a | n/a | done | none | none | ✅ Adversarial review complete. | -| Phase 0 `app` TurboModules | P0 | **closed** | **closed** | **closed** | done | `full` | `feat(app): migrate app modules to TurboModules incl general migration infra` | Committed 2026-06-30. | -| Phase 0.1 `app` compare:types | P0.1 | **closed** | **closed** | **closed** | done | `none` | `test(app): add app module type comparison config` | Committed 2026-06-30. 25 deltas documented; compare:types green for `app`. | -| Phase 1 `firestore` TurboModules | P1 | **closed** | **closed** | **closed** | done | `area-focused` | `feat(firestore)!: migrate firestore to TurboModules` | Committed 2026-06-30. 4 specs; area e2e 732 pass/7 pending iOS+Android; jest 285/285; compare:types ✓. | +| Phase 0 `app` TurboModules | P0 | **closed** | **closed** | **closed** | done | `full` | `feat(app)!: migrate app modules to TurboModules incl general migration infra` | Committed 2026-06-30. | +| Phase 0.1 `app` compare:types | P0.1 | **closed** | **closed** | **closed** | done | `none` | `test(app): add app module type comparison config` | Committed 2026-06-30. | +| Phase 1 `firestore` TurboModules | P1 | **closed** | **closed** | **closed** | done | `area-focused` | `feat(firestore)!: migrate firestore to TurboModules` | Committed 2026-06-30. | +| Phase 2 `installations` | P2a | **closed** | **closed** | **open** | `commit` | `area-focused` | `feat(installations)!: migrate installations to TurboModules` | Review closed 2026-06-30. Remediation: iOS `invalidate` no-op. | +| Phase 2 `perf` | P2b | **closed** | **closed** | **open** | `commit` | `area-focused` | `feat(perf)!: migrate perf to TurboModules` | Review green 2026-06-30. Deferred: dead legacy Java shell; `xdescribe` pending; vacuous iOS screenTrace e2e. | +| Phase 2 `in-app-messaging` | P2c | **closed** | **closed** | **open** | `commit` | `area-focused` | `feat(in-app-messaging)!: migrate in-app-messaging to TurboModules` | Review green 2026-06-30. Deferred: dead legacy Java; stale JSDoc; 3 xdescribe pending. | +| Phase 2 `app-distribution` | P2d | **closed** | **closed** | **open** | `commit` | `area-focused` | `feat(app-distribution)!: migrate app-distribution to TurboModules` | Review green 2026-06-30: Android 1 pass + 4 pending; iOS 3 pass + 2 pending. Duplicate codegen + legacy Java removed. | +| Phase 2 `ml` | P2e | **closed** | **closed** | **open** | `commit` | `area-focused` | `feat(ml)!: migrate ml to TurboModules` | Review green 2026-06-30: 1 pass Android + iOS. Stub module. | --- diff --git a/packages/app/lib/internal/nativeModuleAndroidIos.ts b/packages/app/lib/internal/nativeModuleAndroidIos.ts index df6635ce46..98ebc244d9 100644 --- a/packages/app/lib/internal/nativeModuleAndroidIos.ts +++ b/packages/app/lib/internal/nativeModuleAndroidIos.ts @@ -50,7 +50,7 @@ export function getReactNativeModule(moduleName: string): Record | undefined, ); - if (!globalThis.RNFBDebug) { + if (!globalThis.RNFBDebug || !nativeModule) { return nativeModule; } return new Proxy(nativeModule as Record, { diff --git a/packages/installations/RNFBInstallations.podspec b/packages/installations/RNFBInstallations.podspec index c4f480878e..18b46db1a4 100644 --- a/packages/installations/RNFBInstallations.podspec +++ b/packages/installations/RNFBInstallations.podspec @@ -28,15 +28,16 @@ Pod::Spec.new do |s| s.ios.deployment_target = firebase_ios_target s.macos.deployment_target = firebase_macos_target s.tvos.deployment_target = firebase_tvos_target - s.source_files = 'ios/**/*.{h,m}' + s.source_files = 'ios/**/*.{h,m,mm,cpp,swift}' + s.private_header_files = "ios/**/*.h" + s.exclude_files = 'ios/generated/RCTThirdPartyComponentsProvider.*', 'ios/generated/RCTAppDependencyProvider.*', 'ios/generated/RCTModuleProviders.*', 'ios/generated/RCTModulesConformingToProtocolsProvider.*', 'ios/generated/RCTUnstableModulesRequiringMainQueueSetupProvider.*' s.dependency 'RNFBApp' - # React Native dependencies - if defined?(install_modules_dependencies()) != nil - install_modules_dependencies(s); - else - s.dependency "React-Core" + install_modules_dependencies(s); + + if defined?(ENV["RCT_NEW_ARCH_ENABLED"]) != nil && (ENV["RCT_NEW_ARCH_ENABLED"] == '0') + raise "#{s.name} requires New Architecture. Enable New Architecture to use this module" end if defined?($FirebaseSDKVersion) diff --git a/packages/installations/__tests__/nativeModuleContract.test.ts b/packages/installations/__tests__/nativeModuleContract.test.ts new file mode 100644 index 0000000000..b889185e8f --- /dev/null +++ b/packages/installations/__tests__/nativeModuleContract.test.ts @@ -0,0 +1,57 @@ +import { describe, expect, it, jest } from '@jest/globals'; +import { TurboModuleRegistry } from 'react-native'; +import type { ModuleConfig } from '@react-native-firebase/app/dist/module/internal'; +import FirebaseModule from '@react-native-firebase/app/dist/module/internal/FirebaseModule'; +import { getNativeModule } from '@react-native-firebase/app/dist/module/internal/registry/nativeModule'; +import type { WrappedNativeModule } from '@react-native-firebase/app/dist/module/internal/NativeModules'; + +const SPEC_METHODS = ['deleteInstallations', 'getId', 'getToken'] as const; + +function createTurboModuleFixture(methods: Record): Record { + const proto = Object.create(Object.prototype); + + for (const [name, fn] of Object.entries(methods)) { + Object.defineProperty(proto, name, { + value: fn, + enumerable: true, + configurable: true, + }); + } + + return Object.create(proto); +} + +describe('TurboModule wrapper contract (NewArch-AD-17.1)', function () { + it('exposes every spec method callable through the real wrapper', function () { + const mocks = Object.fromEntries( + SPEC_METHODS.map(method => [method, jest.fn(() => Promise.resolve(method))]), + ) as Record; + + const raw = createTurboModuleFixture(mocks); + jest.mocked(TurboModuleRegistry.get).mockReturnValueOnce(raw); + + const config: ModuleConfig = { + namespace: 'installations', + nativeModuleName: 'NativeRNFBTurboInstallations', + nativeEvents: false, + hasMultiAppSupport: true, + hasCustomUrlOrRegionSupport: false, + turboModule: true, + }; + + class ContractModule extends FirebaseModule { + constructor() { + super({ name: '[DEFAULT]' } as any, config); + } + } + + const wrapped = getNativeModule(new ContractModule()) as WrappedNativeModule & + Record<(typeof SPEC_METHODS)[number], () => Promise>; + + for (const method of SPEC_METHODS) { + void wrapped[method](); + expect(mocks[method]).toHaveBeenCalledTimes(1); + expect(Object.keys(wrapped)).toContain(method); + } + }); +}); diff --git a/packages/installations/android/build.gradle b/packages/installations/android/build.gradle index 457b25d51a..895dc5c885 100644 --- a/packages/installations/android/build.gradle +++ b/packages/installations/android/build.gradle @@ -81,6 +81,7 @@ android { sourceSets { main { java.srcDirs = ['src/main/java', 'src/reactnative/java'] + java.excludes = ['**/generated/jni/**'] } } } @@ -100,3 +101,21 @@ ReactNative.shared.applyPackageVersion() ReactNative.shared.applyDefaultExcludes() ReactNative.module.applyAndroidVersions() ReactNative.module.applyReactNativeDependency("api") + +def isNewArchitectureDisabled() { + return project.hasProperty("newArchEnabled") && project.newArchEnabled != "true" +} + +if (isNewArchitectureDisabled()) { + def ANSI_RED = "\u001B[31m"; + def ANSI_RESET = "\u001B[0m"; + + println("\n\n\n") + println(ANSI_RED + "**************************************************************************************************************") + println("\n\n\n") + println("New Architecture support is required for @react-native-firebase/installations") + println("\n\n\n") + println("**************************************************************************************************************" + ANSI_RESET) + println("\n\n\n") + System.exit(1) +} diff --git a/packages/installations/android/src/main/java/io/invertase/firebase/installations/NativeRNFBTurboInstallations.java b/packages/installations/android/src/main/java/io/invertase/firebase/installations/NativeRNFBTurboInstallations.java new file mode 100644 index 0000000000..6ca1f380be --- /dev/null +++ b/packages/installations/android/src/main/java/io/invertase/firebase/installations/NativeRNFBTurboInstallations.java @@ -0,0 +1,114 @@ +package io.invertase.firebase.installations; + +/* + * Copyright (c) 2016-present Invertase Limited & Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this library except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import android.util.Log; +import com.facebook.fbreact.specs.NativeRNFBTurboInstallationsSpec; +import com.facebook.react.bridge.Promise; +import com.facebook.react.bridge.ReactApplicationContext; +import com.google.android.gms.tasks.Tasks; +import com.google.firebase.FirebaseApp; +import com.google.firebase.installations.FirebaseInstallations; +import io.invertase.firebase.common.TaskExecutorService; +import java.util.concurrent.ExecutorService; + +public class NativeRNFBTurboInstallations extends NativeRNFBTurboInstallationsSpec { + private static final String TAG = "Installations"; + private final TaskExecutorService executorService; + + public NativeRNFBTurboInstallations(ReactApplicationContext reactContext) { + super(reactContext); + this.executorService = new TaskExecutorService("UniversalInstallationsModule"); + } + + private ExecutorService getExecutor() { + return executorService.getExecutor(); + } + + @Override + public void getId(String appName, Promise promise) { + FirebaseApp firebaseApp = FirebaseApp.getInstance(appName); + + Tasks.call( + getExecutor(), + () -> Tasks.await(FirebaseInstallations.getInstance(firebaseApp).getId())) + .addOnCompleteListener( + getExecutor(), + task -> { + if (task.isSuccessful()) { + promise.resolve(task.getResult()); + } else { + Log.e( + TAG, + "RNFB: Unknown error while fetching Installations ID " + + task.getException().getMessage()); + promise.reject("id-error", task.getException().getMessage()); + } + }); + } + + @Override + public void getToken(String appName, boolean forceRefresh, Promise promise) { + FirebaseApp firebaseApp = FirebaseApp.getInstance(appName); + Tasks.call( + getExecutor(), + () -> + Tasks.await( + FirebaseInstallations.getInstance(firebaseApp).getToken(forceRefresh))) + .addOnCompleteListener( + getExecutor(), + task -> { + if (task.isSuccessful()) { + promise.resolve(task.getResult().getToken()); + } else { + Log.e( + TAG, + "RNFB: Unknown error while fetching Installations token " + + task.getException().getMessage()); + promise.reject("token-error", task.getException().getMessage()); + } + }); + } + + @Override + public void deleteInstallations(String appName, Promise promise) { + FirebaseApp firebaseApp = FirebaseApp.getInstance(appName); + Tasks.call( + getExecutor(), + () -> Tasks.await(FirebaseInstallations.getInstance(firebaseApp).delete())) + .addOnCompleteListener( + getExecutor(), + task -> { + if (task.isSuccessful()) { + promise.resolve(null); + } else { + Log.e( + TAG, + "RNFB: Unknown error while deleting Installations" + + task.getException().getMessage()); + promise.reject("delete-error", task.getException().getMessage()); + } + }); + } + + @Override + public void invalidate() { + super.invalidate(); + executorService.shutdown(); + } +} diff --git a/packages/installations/android/src/main/java/io/invertase/firebase/installations/ReactNativeFirebaseInstallationsPackage.java b/packages/installations/android/src/main/java/io/invertase/firebase/installations/ReactNativeFirebaseInstallationsPackage.java index a845533203..21e1321462 100644 --- a/packages/installations/android/src/main/java/io/invertase/firebase/installations/ReactNativeFirebaseInstallationsPackage.java +++ b/packages/installations/android/src/main/java/io/invertase/firebase/installations/ReactNativeFirebaseInstallationsPackage.java @@ -30,7 +30,7 @@ public class ReactNativeFirebaseInstallationsPackage implements ReactPackage { @Override public List createNativeModules(ReactApplicationContext reactContext) { List modules = new ArrayList<>(); - modules.add(new ReactNativeFirebaseInstallationsModule(reactContext)); + modules.add(new NativeRNFBTurboInstallations(reactContext)); return modules; } diff --git a/packages/installations/android/src/main/java/io/invertase/firebase/installations/generated/java/com/facebook/fbreact/specs/NativeRNFBTurboInstallationsSpec.java b/packages/installations/android/src/main/java/io/invertase/firebase/installations/generated/java/com/facebook/fbreact/specs/NativeRNFBTurboInstallationsSpec.java new file mode 100644 index 0000000000..705577476d --- /dev/null +++ b/packages/installations/android/src/main/java/io/invertase/firebase/installations/generated/java/com/facebook/fbreact/specs/NativeRNFBTurboInstallationsSpec.java @@ -0,0 +1,46 @@ + +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleJavaSpec.js + * + * @nolint + */ + +package com.facebook.fbreact.specs; + +import com.facebook.proguard.annotations.DoNotStrip; +import com.facebook.react.bridge.Promise; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReactContextBaseJavaModule; +import com.facebook.react.bridge.ReactMethod; +import com.facebook.react.turbomodule.core.interfaces.TurboModule; +import javax.annotation.Nonnull; + +public abstract class NativeRNFBTurboInstallationsSpec extends ReactContextBaseJavaModule implements TurboModule { + public static final String NAME = "NativeRNFBTurboInstallations"; + + public NativeRNFBTurboInstallationsSpec(ReactApplicationContext reactContext) { + super(reactContext); + } + + @Override + public @Nonnull String getName() { + return NAME; + } + + @ReactMethod + @DoNotStrip + public abstract void deleteInstallations(String appName, Promise promise); + + @ReactMethod + @DoNotStrip + public abstract void getId(String appName, Promise promise); + + @ReactMethod + @DoNotStrip + public abstract void getToken(String appName, boolean forceRefresh, Promise promise); +} diff --git a/packages/installations/android/src/main/java/io/invertase/firebase/installations/generated/jni/CMakeLists.txt b/packages/installations/android/src/main/java/io/invertase/firebase/installations/generated/jni/CMakeLists.txt new file mode 100644 index 0000000000..bcabc17be0 --- /dev/null +++ b/packages/installations/android/src/main/java/io/invertase/firebase/installations/generated/jni/CMakeLists.txt @@ -0,0 +1,36 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +cmake_minimum_required(VERSION 3.13) +set(CMAKE_VERBOSE_MAKEFILE on) + +file(GLOB react_codegen_SRCS CONFIGURE_DEPENDS *.cpp react/renderer/components/RNFBInstallationsTurboModules/*.cpp) + +add_library( + react_codegen_RNFBInstallationsTurboModules + OBJECT + ${react_codegen_SRCS} +) + +target_include_directories(react_codegen_RNFBInstallationsTurboModules PUBLIC . react/renderer/components/RNFBInstallationsTurboModules) + +target_link_libraries( + react_codegen_RNFBInstallationsTurboModules + fbjni + jsi + # We need to link different libraries based on whether we are building rncore or not, that's necessary + # because we want to break a circular dependency between react_codegen_rncore and reactnative + reactnative +) + +target_compile_options( + react_codegen_RNFBInstallationsTurboModules + PRIVATE + -DLOG_TAG=\"ReactNative\" + -fexceptions + -frtti + -std=c++20 + -Wall +) diff --git a/packages/installations/android/src/main/java/io/invertase/firebase/installations/generated/jni/RNFBInstallationsTurboModules-generated.cpp b/packages/installations/android/src/main/java/io/invertase/firebase/installations/generated/jni/RNFBInstallationsTurboModules-generated.cpp new file mode 100644 index 0000000000..c17e285ea6 --- /dev/null +++ b/packages/installations/android/src/main/java/io/invertase/firebase/installations/generated/jni/RNFBInstallationsTurboModules-generated.cpp @@ -0,0 +1,44 @@ + +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleJniCpp.js + */ + +#include "RNFBInstallationsTurboModules.h" + +namespace facebook::react { + +static facebook::jsi::Value __hostFunction_NativeRNFBTurboInstallationsSpecJSI_deleteInstallations(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, PromiseKind, "deleteInstallations", "(Ljava/lang/String;Lcom/facebook/react/bridge/Promise;)V", args, count, cachedMethodId); +} + +static facebook::jsi::Value __hostFunction_NativeRNFBTurboInstallationsSpecJSI_getId(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, PromiseKind, "getId", "(Ljava/lang/String;Lcom/facebook/react/bridge/Promise;)V", args, count, cachedMethodId); +} + +static facebook::jsi::Value __hostFunction_NativeRNFBTurboInstallationsSpecJSI_getToken(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, PromiseKind, "getToken", "(Ljava/lang/String;ZLcom/facebook/react/bridge/Promise;)V", args, count, cachedMethodId); +} + +NativeRNFBTurboInstallationsSpecJSI::NativeRNFBTurboInstallationsSpecJSI(const JavaTurboModule::InitParams ¶ms) + : JavaTurboModule(params) { + methodMap_["deleteInstallations"] = MethodMetadata {1, __hostFunction_NativeRNFBTurboInstallationsSpecJSI_deleteInstallations}; + methodMap_["getId"] = MethodMetadata {1, __hostFunction_NativeRNFBTurboInstallationsSpecJSI_getId}; + methodMap_["getToken"] = MethodMetadata {2, __hostFunction_NativeRNFBTurboInstallationsSpecJSI_getToken}; +} + +std::shared_ptr RNFBInstallationsTurboModules_ModuleProvider(const std::string &moduleName, const JavaTurboModule::InitParams ¶ms) { + if (moduleName == "NativeRNFBTurboInstallations") { + return std::make_shared(params); + } + return nullptr; +} + +} // namespace facebook::react diff --git a/packages/installations/android/src/main/java/io/invertase/firebase/installations/generated/jni/RNFBInstallationsTurboModules.h b/packages/installations/android/src/main/java/io/invertase/firebase/installations/generated/jni/RNFBInstallationsTurboModules.h new file mode 100644 index 0000000000..f486952eec --- /dev/null +++ b/packages/installations/android/src/main/java/io/invertase/firebase/installations/generated/jni/RNFBInstallationsTurboModules.h @@ -0,0 +1,31 @@ + +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleJniH.js + */ + +#pragma once + +#include +#include +#include + +namespace facebook::react { + +/** + * JNI C++ class for module 'NativeRNFBTurboInstallations' + */ +class JSI_EXPORT NativeRNFBTurboInstallationsSpecJSI : public JavaTurboModule { +public: + NativeRNFBTurboInstallationsSpecJSI(const JavaTurboModule::InitParams ¶ms); +}; + + +JSI_EXPORT +std::shared_ptr RNFBInstallationsTurboModules_ModuleProvider(const std::string &moduleName, const JavaTurboModule::InitParams ¶ms); + +} // namespace facebook::react diff --git a/packages/installations/android/src/main/java/io/invertase/firebase/installations/generated/jni/react/renderer/components/RNFBInstallationsTurboModules/RNFBInstallationsTurboModulesJSI-generated.cpp b/packages/installations/android/src/main/java/io/invertase/firebase/installations/generated/jni/react/renderer/components/RNFBInstallationsTurboModules/RNFBInstallationsTurboModulesJSI-generated.cpp new file mode 100644 index 0000000000..13cbc1153e --- /dev/null +++ b/packages/installations/android/src/main/java/io/invertase/firebase/installations/generated/jni/react/renderer/components/RNFBInstallationsTurboModules/RNFBInstallationsTurboModulesJSI-generated.cpp @@ -0,0 +1,42 @@ +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleCpp.js + */ + +#include "RNFBInstallationsTurboModulesJSI.h" + +namespace facebook::react { + +static jsi::Value __hostFunction_NativeRNFBTurboInstallationsCxxSpecJSI_deleteInstallations(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->deleteInstallations( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt) + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboInstallationsCxxSpecJSI_getId(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getId( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt) + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboInstallationsCxxSpecJSI_getToken(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getToken( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asBool() + ); +} + +NativeRNFBTurboInstallationsCxxSpecJSI::NativeRNFBTurboInstallationsCxxSpecJSI(std::shared_ptr jsInvoker) + : TurboModule("NativeRNFBTurboInstallations", jsInvoker) { + methodMap_["deleteInstallations"] = MethodMetadata {1, __hostFunction_NativeRNFBTurboInstallationsCxxSpecJSI_deleteInstallations}; + methodMap_["getId"] = MethodMetadata {1, __hostFunction_NativeRNFBTurboInstallationsCxxSpecJSI_getId}; + methodMap_["getToken"] = MethodMetadata {2, __hostFunction_NativeRNFBTurboInstallationsCxxSpecJSI_getToken}; +} + + +} // namespace facebook::react diff --git a/packages/installations/android/src/main/java/io/invertase/firebase/installations/generated/jni/react/renderer/components/RNFBInstallationsTurboModules/RNFBInstallationsTurboModulesJSI.h b/packages/installations/android/src/main/java/io/invertase/firebase/installations/generated/jni/react/renderer/components/RNFBInstallationsTurboModules/RNFBInstallationsTurboModulesJSI.h new file mode 100644 index 0000000000..fb43d1115d --- /dev/null +++ b/packages/installations/android/src/main/java/io/invertase/firebase/installations/generated/jni/react/renderer/components/RNFBInstallationsTurboModules/RNFBInstallationsTurboModulesJSI.h @@ -0,0 +1,89 @@ +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleH.js + */ + +#pragma once + +#include +#include + +namespace facebook::react { + + + class JSI_EXPORT NativeRNFBTurboInstallationsCxxSpecJSI : public TurboModule { +protected: + NativeRNFBTurboInstallationsCxxSpecJSI(std::shared_ptr jsInvoker); + +public: + virtual jsi::Value deleteInstallations(jsi::Runtime &rt, jsi::String appName) = 0; + virtual jsi::Value getId(jsi::Runtime &rt, jsi::String appName) = 0; + virtual jsi::Value getToken(jsi::Runtime &rt, jsi::String appName, bool forceRefresh) = 0; + +}; + +template +class JSI_EXPORT NativeRNFBTurboInstallationsCxxSpec : public TurboModule { +public: + jsi::Value create(jsi::Runtime &rt, const jsi::PropNameID &propName) override { + return delegate_.create(rt, propName); + } + + std::vector getPropertyNames(jsi::Runtime& runtime) override { + return delegate_.getPropertyNames(runtime); + } + + static constexpr std::string_view kModuleName = "NativeRNFBTurboInstallations"; + +protected: + NativeRNFBTurboInstallationsCxxSpec(std::shared_ptr jsInvoker) + : TurboModule(std::string{NativeRNFBTurboInstallationsCxxSpec::kModuleName}, jsInvoker), + delegate_(reinterpret_cast(this), jsInvoker) {} + + +private: + class Delegate : public NativeRNFBTurboInstallationsCxxSpecJSI { + public: + Delegate(T *instance, std::shared_ptr jsInvoker) : + NativeRNFBTurboInstallationsCxxSpecJSI(std::move(jsInvoker)), instance_(instance) { + + } + + jsi::Value deleteInstallations(jsi::Runtime &rt, jsi::String appName) override { + static_assert( + bridging::getParameterCount(&T::deleteInstallations) == 2, + "Expected deleteInstallations(...) to have 2 parameters"); + + return bridging::callFromJs( + rt, &T::deleteInstallations, jsInvoker_, instance_, std::move(appName)); + } + jsi::Value getId(jsi::Runtime &rt, jsi::String appName) override { + static_assert( + bridging::getParameterCount(&T::getId) == 2, + "Expected getId(...) to have 2 parameters"); + + return bridging::callFromJs( + rt, &T::getId, jsInvoker_, instance_, std::move(appName)); + } + jsi::Value getToken(jsi::Runtime &rt, jsi::String appName, bool forceRefresh) override { + static_assert( + bridging::getParameterCount(&T::getToken) == 3, + "Expected getToken(...) to have 3 parameters"); + + return bridging::callFromJs( + rt, &T::getToken, jsInvoker_, instance_, std::move(appName), std::move(forceRefresh)); + } + + private: + friend class NativeRNFBTurboInstallationsCxxSpec; + T *instance_; + }; + + Delegate delegate_; +}; + +} // namespace facebook::react diff --git a/packages/installations/ios/RNFBInstallations.xcodeproj/project.pbxproj b/packages/installations/ios/RNFBInstallations.xcodeproj/project.pbxproj index d238d5a79d..1843e46ea3 100644 --- a/packages/installations/ios/RNFBInstallations.xcodeproj/project.pbxproj +++ b/packages/installations/ios/RNFBInstallations.xcodeproj/project.pbxproj @@ -7,7 +7,7 @@ objects = { /* Begin PBXBuildFile section */ - 2744B98621F45429004F8E3F /* RNFBInstallationsModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 2744B98521F45429004F8E3F /* RNFBInstallationsModule.m */; }; + 2744B98621F45429004F8E3F /* RNFBInstallationsModule.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2744B98521F45429004F8E3F /* RNFBInstallationsModule.mm */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -25,7 +25,7 @@ /* Begin PBXFileReference section */ 2744B98221F45429004F8E3F /* libRNFBInstallations.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRNFBInstallations.a; sourceTree = BUILT_PRODUCTS_DIR; }; 2744B98421F45429004F8E3F /* RNFBInstallationsModule.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = RNFBInstallationsModule.h; path = RNFBInstallations/RNFBInstallationsModule.h; sourceTree = SOURCE_ROOT; }; - 2744B98521F45429004F8E3F /* RNFBInstallationsModule.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = RNFBInstallationsModule.m; path = RNFBInstallations/RNFBInstallationsModule.m; sourceTree = SOURCE_ROOT; }; + 2744B98521F45429004F8E3F /* RNFBInstallationsModule.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = RNFBInstallationsModule.mm; path = RNFBInstallations/RNFBInstallationsModule.mm; sourceTree = SOURCE_ROOT; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -53,7 +53,7 @@ 2744B9A121F48736004F8E3F /* converters */, 2744B98C21F45C64004F8E3F /* common */, 2744B98421F45429004F8E3F /* RNFBInstallationsModule.h */, - 2744B98521F45429004F8E3F /* RNFBInstallationsModule.m */, + 2744B98521F45429004F8E3F /* RNFBInstallationsModule.mm */, ); path = RNFBInstallations; sourceTree = ""; @@ -124,7 +124,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 2744B98621F45429004F8E3F /* RNFBInstallationsModule.m in Sources */, + 2744B98621F45429004F8E3F /* RNFBInstallationsModule.mm in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/packages/installations/ios/RNFBInstallations/RNFBInstallationsModule.h b/packages/installations/ios/RNFBInstallations/RNFBInstallationsModule.h index a734bb8f29..c2a7242252 100644 --- a/packages/installations/ios/RNFBInstallations/RNFBInstallationsModule.h +++ b/packages/installations/ios/RNFBInstallations/RNFBInstallationsModule.h @@ -16,9 +16,9 @@ */ #import +#import +#import "RNFBInstallationsTurboModules.h" -#import - -@interface RNFBInstallationsModule : NSObject +@interface RNFBInstallationsModule : NSObject @end diff --git a/packages/installations/ios/RNFBInstallations/RNFBInstallationsModule.m b/packages/installations/ios/RNFBInstallations/RNFBInstallationsModule.mm similarity index 81% rename from packages/installations/ios/RNFBInstallations/RNFBInstallationsModule.m rename to packages/installations/ios/RNFBInstallations/RNFBInstallationsModule.mm index 7b07b36a0b..cccde86738 100644 --- a/packages/installations/ios/RNFBInstallations/RNFBInstallationsModule.m +++ b/packages/installations/ios/RNFBInstallations/RNFBInstallationsModule.mm @@ -18,32 +18,35 @@ #import #import +#import "RNFBApp/RCTConvert+FIRApp.h" #import "RNFBApp/RNFBSharedUtils.h" #import "RNFBInstallationsModule.h" #import "FirebaseInstallations/FIRInstallations.h" @implementation RNFBInstallationsModule -#pragma mark - -#pragma mark Module Setup -RCT_EXPORT_MODULE(); +RCT_EXPORT_MODULE(NativeRNFBTurboInstallations) -- (dispatch_queue_t)methodQueue { - return dispatch_get_main_queue(); ++ (BOOL)requiresMainQueueSetup { + return NO; } -#pragma mark - -#pragma mark Firebase Installations Methods +- (std::shared_ptr)getTurboModule: + (const facebook::react::ObjCTurboModule::InitParams &)params { + return std::make_shared(params); +} + +- (void)invalidate { +} -RCT_EXPORT_METHOD(delete - : (FIRApp *)firebaseApp - : (RCTPromiseResolveBlock)resolve - : (RCTPromiseRejectBlock)reject) { +- (void)deleteInstallations:(NSString *)appName + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject { + FIRApp *firebaseApp = [RCTConvert firAppFromString:appName]; FIRInstallations *installations = [FIRInstallations installationsWithApp:firebaseApp]; [installations deleteWithCompletion:^(NSError *_Nullable error) { if (error != nil) { - // Handle any errors if the delete failed DLog(@"Unable to delete Installations ID: %@", error); [RNFBSharedUtils rejectPromiseWithUserInfo:reject userInfo:(NSMutableDictionary *)@{ @@ -57,14 +60,13 @@ - (dispatch_queue_t)methodQueue { }]; } -RCT_EXPORT_METHOD(getId - : (FIRApp *)firebaseApp - : (RCTPromiseResolveBlock)resolve - : (RCTPromiseRejectBlock)reject) { +- (void)getId:(NSString *)appName + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject { + FIRApp *firebaseApp = [RCTConvert firAppFromString:appName]; FIRInstallations *installations = [FIRInstallations installationsWithApp:firebaseApp]; [installations installationIDWithCompletion:^(NSString *_Nullable id, NSError *_Nullable error) { if (error != nil) { - // Handle any errors if the id was not retrieved. DLog(@"Unable to retrieve Installations ID: %@", error); [RNFBSharedUtils rejectPromiseWithUserInfo:reject userInfo:(NSMutableDictionary *)@{ @@ -87,17 +89,16 @@ - (dispatch_queue_t)methodQueue { }]; } -RCT_EXPORT_METHOD(getToken - : (FIRApp *)firebaseApp - : (BOOL)forceRefresh - : (RCTPromiseResolveBlock)resolve - : (RCTPromiseRejectBlock)reject) { +- (void)getToken:(NSString *)appName + forceRefresh:(BOOL)forceRefresh + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject { + FIRApp *firebaseApp = [RCTConvert firAppFromString:appName]; FIRInstallations *installations = [FIRInstallations installationsWithApp:firebaseApp]; [installations authTokenForcingRefresh:forceRefresh completion:^(FIRInstallationsAuthTokenResult *_Nullable token, NSError *_Nullable error) { if (error != nil) { - // Handle any errors if the token was not retrieved. DLog(@"Unable to retrieve Installations auth token: %@", error); [RNFBSharedUtils rejectPromiseWithUserInfo:reject diff --git a/packages/installations/ios/generated/RNFBInstallationsTurboModules/RNFBInstallationsTurboModules-generated.mm b/packages/installations/ios/generated/RNFBInstallationsTurboModules/RNFBInstallationsTurboModules-generated.mm new file mode 100644 index 0000000000..0d4115c274 --- /dev/null +++ b/packages/installations/ios/generated/RNFBInstallationsTurboModules/RNFBInstallationsTurboModules-generated.mm @@ -0,0 +1,53 @@ +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleObjCpp + * + * We create an umbrella header (and corresponding implementation) here since + * Cxx compilation in BUCK has a limitation: source-code producing genrule()s + * must have a single output. More files => more genrule()s => slower builds. + */ + +#import "RNFBInstallationsTurboModules.h" + + +@implementation NativeRNFBTurboInstallationsSpecBase + + +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper +{ + _eventEmitterCallback = std::move(eventEmitterCallbackWrapper->_eventEmitterCallback); +} +@end + + +namespace facebook::react { + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboInstallationsSpecJSI_deleteInstallations(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, PromiseKind, "deleteInstallations", @selector(deleteInstallations:resolve:reject:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboInstallationsSpecJSI_getId(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, PromiseKind, "getId", @selector(getId:resolve:reject:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboInstallationsSpecJSI_getToken(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, PromiseKind, "getToken", @selector(getToken:forceRefresh:resolve:reject:), args, count); + } + + NativeRNFBTurboInstallationsSpecJSI::NativeRNFBTurboInstallationsSpecJSI(const ObjCTurboModule::InitParams ¶ms) + : ObjCTurboModule(params) { + + methodMap_["deleteInstallations"] = MethodMetadata {1, __hostFunction_NativeRNFBTurboInstallationsSpecJSI_deleteInstallations}; + + + methodMap_["getId"] = MethodMetadata {1, __hostFunction_NativeRNFBTurboInstallationsSpecJSI_getId}; + + + methodMap_["getToken"] = MethodMetadata {2, __hostFunction_NativeRNFBTurboInstallationsSpecJSI_getToken}; + + } +} // namespace facebook::react diff --git a/packages/installations/ios/generated/RNFBInstallationsTurboModules/RNFBInstallationsTurboModules.h b/packages/installations/ios/generated/RNFBInstallationsTurboModules/RNFBInstallationsTurboModules.h new file mode 100644 index 0000000000..4df0e4ba22 --- /dev/null +++ b/packages/installations/ios/generated/RNFBInstallationsTurboModules/RNFBInstallationsTurboModules.h @@ -0,0 +1,71 @@ +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleObjCpp + * + * We create an umbrella header (and corresponding implementation) here since + * Cxx compilation in BUCK has a limitation: source-code producing genrule()s + * must have a single output. More files => more genrule()s => slower builds. + */ + +#ifndef __cplusplus +#error This file must be compiled as Obj-C++. If you are importing it, you must change your file extension to .mm. +#endif + +// Avoid multiple includes of RNFBInstallationsTurboModules symbols +#ifndef RNFBInstallationsTurboModules_H +#define RNFBInstallationsTurboModules_H + +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import + + +NS_ASSUME_NONNULL_BEGIN + +@protocol NativeRNFBTurboInstallationsSpec + +- (void)deleteInstallations:(NSString *)appName + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; +- (void)getId:(NSString *)appName + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; +- (void)getToken:(NSString *)appName + forceRefresh:(BOOL)forceRefresh + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; + +@end + +@interface NativeRNFBTurboInstallationsSpecBase : NSObject { +@protected +facebook::react::EventEmitterCallback _eventEmitterCallback; +} +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper; + + +@end + +namespace facebook::react { + /** + * ObjC++ class for module 'NativeRNFBTurboInstallations' + */ + class JSI_EXPORT NativeRNFBTurboInstallationsSpecJSI : public ObjCTurboModule { + public: + NativeRNFBTurboInstallationsSpecJSI(const ObjCTurboModule::InitParams ¶ms); + }; +} // namespace facebook::react + +NS_ASSUME_NONNULL_END +#endif // RNFBInstallationsTurboModules_H diff --git a/packages/installations/ios/generated/RNFBInstallationsTurboModulesJSI-generated.cpp b/packages/installations/ios/generated/RNFBInstallationsTurboModulesJSI-generated.cpp new file mode 100644 index 0000000000..13cbc1153e --- /dev/null +++ b/packages/installations/ios/generated/RNFBInstallationsTurboModulesJSI-generated.cpp @@ -0,0 +1,42 @@ +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleCpp.js + */ + +#include "RNFBInstallationsTurboModulesJSI.h" + +namespace facebook::react { + +static jsi::Value __hostFunction_NativeRNFBTurboInstallationsCxxSpecJSI_deleteInstallations(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->deleteInstallations( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt) + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboInstallationsCxxSpecJSI_getId(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getId( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt) + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboInstallationsCxxSpecJSI_getToken(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getToken( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asBool() + ); +} + +NativeRNFBTurboInstallationsCxxSpecJSI::NativeRNFBTurboInstallationsCxxSpecJSI(std::shared_ptr jsInvoker) + : TurboModule("NativeRNFBTurboInstallations", jsInvoker) { + methodMap_["deleteInstallations"] = MethodMetadata {1, __hostFunction_NativeRNFBTurboInstallationsCxxSpecJSI_deleteInstallations}; + methodMap_["getId"] = MethodMetadata {1, __hostFunction_NativeRNFBTurboInstallationsCxxSpecJSI_getId}; + methodMap_["getToken"] = MethodMetadata {2, __hostFunction_NativeRNFBTurboInstallationsCxxSpecJSI_getToken}; +} + + +} // namespace facebook::react diff --git a/packages/installations/ios/generated/RNFBInstallationsTurboModulesJSI.h b/packages/installations/ios/generated/RNFBInstallationsTurboModulesJSI.h new file mode 100644 index 0000000000..fb43d1115d --- /dev/null +++ b/packages/installations/ios/generated/RNFBInstallationsTurboModulesJSI.h @@ -0,0 +1,89 @@ +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleH.js + */ + +#pragma once + +#include +#include + +namespace facebook::react { + + + class JSI_EXPORT NativeRNFBTurboInstallationsCxxSpecJSI : public TurboModule { +protected: + NativeRNFBTurboInstallationsCxxSpecJSI(std::shared_ptr jsInvoker); + +public: + virtual jsi::Value deleteInstallations(jsi::Runtime &rt, jsi::String appName) = 0; + virtual jsi::Value getId(jsi::Runtime &rt, jsi::String appName) = 0; + virtual jsi::Value getToken(jsi::Runtime &rt, jsi::String appName, bool forceRefresh) = 0; + +}; + +template +class JSI_EXPORT NativeRNFBTurboInstallationsCxxSpec : public TurboModule { +public: + jsi::Value create(jsi::Runtime &rt, const jsi::PropNameID &propName) override { + return delegate_.create(rt, propName); + } + + std::vector getPropertyNames(jsi::Runtime& runtime) override { + return delegate_.getPropertyNames(runtime); + } + + static constexpr std::string_view kModuleName = "NativeRNFBTurboInstallations"; + +protected: + NativeRNFBTurboInstallationsCxxSpec(std::shared_ptr jsInvoker) + : TurboModule(std::string{NativeRNFBTurboInstallationsCxxSpec::kModuleName}, jsInvoker), + delegate_(reinterpret_cast(this), jsInvoker) {} + + +private: + class Delegate : public NativeRNFBTurboInstallationsCxxSpecJSI { + public: + Delegate(T *instance, std::shared_ptr jsInvoker) : + NativeRNFBTurboInstallationsCxxSpecJSI(std::move(jsInvoker)), instance_(instance) { + + } + + jsi::Value deleteInstallations(jsi::Runtime &rt, jsi::String appName) override { + static_assert( + bridging::getParameterCount(&T::deleteInstallations) == 2, + "Expected deleteInstallations(...) to have 2 parameters"); + + return bridging::callFromJs( + rt, &T::deleteInstallations, jsInvoker_, instance_, std::move(appName)); + } + jsi::Value getId(jsi::Runtime &rt, jsi::String appName) override { + static_assert( + bridging::getParameterCount(&T::getId) == 2, + "Expected getId(...) to have 2 parameters"); + + return bridging::callFromJs( + rt, &T::getId, jsInvoker_, instance_, std::move(appName)); + } + jsi::Value getToken(jsi::Runtime &rt, jsi::String appName, bool forceRefresh) override { + static_assert( + bridging::getParameterCount(&T::getToken) == 3, + "Expected getToken(...) to have 3 parameters"); + + return bridging::callFromJs( + rt, &T::getToken, jsInvoker_, instance_, std::move(appName), std::move(forceRefresh)); + } + + private: + friend class NativeRNFBTurboInstallationsCxxSpec; + T *instance_; + }; + + Delegate delegate_; +}; + +} // namespace facebook::react diff --git a/packages/installations/lib/index.ts b/packages/installations/lib/index.ts index f71489451c..c923877193 100644 --- a/packages/installations/lib/index.ts +++ b/packages/installations/lib/index.ts @@ -31,7 +31,7 @@ import type { import type { InstallationsInternal } from './types/internal'; import { version } from './version'; -const nativeModuleName = 'RNFBInstallationsModule'; +const nativeModuleName = 'NativeRNFBTurboInstallations'; class FirebaseInstallationsModule extends FirebaseModule { getId(): Promise { @@ -47,7 +47,7 @@ class FirebaseInstallationsModule extends FirebaseModule { - return this.native.delete(); + return this.native.deleteInstallations(); } onIdChange(): () => void { @@ -66,6 +66,7 @@ const config: ModuleConfig = { nativeEvents: false, // TODO implement android id change listener: ['installations_id_changed'], hasMultiAppSupport: true, hasCustomUrlOrRegionSupport: false, + turboModule: true, }; /** diff --git a/packages/installations/lib/types/internal.ts b/packages/installations/lib/types/internal.ts index 54979c5681..22a10bbe88 100644 --- a/packages/installations/lib/types/internal.ts +++ b/packages/installations/lib/types/internal.ts @@ -20,12 +20,12 @@ import type { Installations } from './installations'; export interface RNFBInstallationsModule { getId(): Promise; getToken(forceRefresh: boolean): Promise; - delete(): Promise; + deleteInstallations(): Promise; } declare module '@react-native-firebase/app/dist/module/internal/NativeModules' { interface ReactNativeFirebaseNativeModules { - RNFBInstallationsModule: RNFBInstallationsModule; + NativeRNFBTurboInstallations: RNFBInstallationsModule; } } diff --git a/packages/installations/package.json b/packages/installations/package.json index cfd85f2128..85fb57660d 100644 --- a/packages/installations/package.json +++ b/packages/installations/package.json @@ -5,11 +5,28 @@ "description": "React Native Firebase - Installations", "main": "./dist/module/index.js", "types": "./dist/typescript/lib/index.d.ts", + "codegenConfig": { + "name": "RNFBInstallationsTurboModules", + "type": "modules", + "jsSrcsDir": "specs", + "includesGeneratedCode": true, + "android": { + "javaPackageName": "io.invertase.firebase.installations" + }, + "ios": { + "modulesProvider": { + "NativeRNFBTurboInstallations": "RNFBInstallationsModule" + } + } + }, "scripts": { "build": "genversion --esm --semi lib/version.ts", "build:clean": "rimraf android/build && rimraf ios/build", "compile": "bob build", - "prepare": "yarn run build && yarn compile" + "prepare": "yarn run build && yarn compile", + "codegen": "yarn android:codegen && yarn ios:codegen", + "android:codegen": "npx @react-native-community/cli codegen --platform android --outputPath=./android/src/main/java/io/invertase/firebase/installations/generated", + "ios:codegen": "npx @react-native-community/cli codegen --platform ios --outputPath=./ios/generated" }, "repository": { "type": "git", diff --git a/packages/installations/react-native.config.js b/packages/installations/react-native.config.js new file mode 100644 index 0000000000..258c0e8802 --- /dev/null +++ b/packages/installations/react-native.config.js @@ -0,0 +1,10 @@ +module.exports = { + dependency: { + platforms: { + android: { + cmakeListsPath: + './src/main/java/io/invertase/firebase/installations/generated/jni/CMakeLists.txt', + }, + }, + }, +}; diff --git a/packages/installations/specs/NativeRNFBTurboInstallations.ts b/packages/installations/specs/NativeRNFBTurboInstallations.ts new file mode 100644 index 0000000000..e7e6a8bafb --- /dev/null +++ b/packages/installations/specs/NativeRNFBTurboInstallations.ts @@ -0,0 +1,10 @@ +import type { TurboModule } from 'react-native'; +import { TurboModuleRegistry } from 'react-native'; + +export interface Spec extends TurboModule { + deleteInstallations(appName: string): Promise; + getId(appName: string): Promise; + getToken(appName: string, forceRefresh: boolean): Promise; +} + +export default TurboModuleRegistry.getEnforcing('NativeRNFBTurboInstallations'); From 85cb213432698a07b34a00dbc0888a3d0bd1de1d Mon Sep 17 00:00:00 2001 From: Mike Hardy Date: Wed, 1 Jul 2026 07:05:50 -0500 Subject: [PATCH 07/10] feat(perf)!: migrate perf to TurboModules --- .../new-architecture/migration-work-queue.md | 4 +- packages/perf/RNFBPerf.podspec | 13 +- .../__tests__/nativeModuleContract.test.ts | 80 ++++++ packages/perf/android/build.gradle | 19 ++ .../firebase/perf/NativeRNFBTurboPerf.java | 161 +++++++++++ .../perf/ReactNativeFirebasePerfPackage.java | 2 +- .../specs/NativeRNFBTurboPerfSpec.java | 100 +++++++ .../perf/generated/jni/CMakeLists.txt | 36 +++ .../jni/RNFBPerfTurboModules-generated.cpp | 80 ++++++ .../perf/generated/jni/RNFBPerfTurboModules.h | 31 ++ .../RNFBPerfTurboModulesJSI-generated.cpp | 88 ++++++ .../RNFBPerfTurboModulesJSI.h | 267 ++++++++++++++++++ .../ios/RNFBPerf.xcodeproj/project.pbxproj | 8 +- packages/perf/ios/RNFBPerf/RNFBPerfModule.h | 5 +- .../{RNFBPerfModule.m => RNFBPerfModule.mm} | 139 ++++----- .../RNFBPerfTurboModules-generated.mm | 106 +++++++ .../RNFBPerfTurboModules.h | 200 +++++++++++++ .../RNFBPerfTurboModulesJSI-generated.cpp | 88 ++++++ .../ios/generated/RNFBPerfTurboModulesJSI.h | 267 ++++++++++++++++++ packages/perf/lib/index.ts | 3 +- packages/perf/lib/types/internal.ts | 2 +- packages/perf/package.json | 19 +- packages/perf/react-native.config.js | 10 + packages/perf/specs/NativeRNFBTurboPerf.ts | 44 +++ 24 files changed, 1690 insertions(+), 82 deletions(-) create mode 100644 packages/perf/__tests__/nativeModuleContract.test.ts create mode 100644 packages/perf/android/src/reactnative/java/io/invertase/firebase/perf/NativeRNFBTurboPerf.java create mode 100644 packages/perf/android/src/reactnative/java/io/invertase/firebase/perf/generated/java/com/facebook/fbreact/specs/NativeRNFBTurboPerfSpec.java create mode 100644 packages/perf/android/src/reactnative/java/io/invertase/firebase/perf/generated/jni/CMakeLists.txt create mode 100644 packages/perf/android/src/reactnative/java/io/invertase/firebase/perf/generated/jni/RNFBPerfTurboModules-generated.cpp create mode 100644 packages/perf/android/src/reactnative/java/io/invertase/firebase/perf/generated/jni/RNFBPerfTurboModules.h create mode 100644 packages/perf/android/src/reactnative/java/io/invertase/firebase/perf/generated/jni/react/renderer/components/RNFBPerfTurboModules/RNFBPerfTurboModulesJSI-generated.cpp create mode 100644 packages/perf/android/src/reactnative/java/io/invertase/firebase/perf/generated/jni/react/renderer/components/RNFBPerfTurboModules/RNFBPerfTurboModulesJSI.h rename packages/perf/ios/RNFBPerf/{RNFBPerfModule.m => RNFBPerfModule.mm} (56%) create mode 100644 packages/perf/ios/generated/RNFBPerfTurboModules/RNFBPerfTurboModules-generated.mm create mode 100644 packages/perf/ios/generated/RNFBPerfTurboModules/RNFBPerfTurboModules.h create mode 100644 packages/perf/ios/generated/RNFBPerfTurboModulesJSI-generated.cpp create mode 100644 packages/perf/ios/generated/RNFBPerfTurboModulesJSI.h create mode 100644 packages/perf/react-native.config.js create mode 100644 packages/perf/specs/NativeRNFBTurboPerf.ts diff --git a/okf-bundle/new-architecture/migration-work-queue.md b/okf-bundle/new-architecture/migration-work-queue.md index 63ff2b9427..880173e52a 100644 --- a/okf-bundle/new-architecture/migration-work-queue.md +++ b/okf-bundle/new-architecture/migration-work-queue.md @@ -8,7 +8,7 @@ timestamp: 2026-06-26T00:00:00Z # TurboModule migration — work queue -> **IN PROGRESS (2026-06-30):** Phase **2** — committing P2a `installations`. +> **IN PROGRESS (2026-06-30):** Phase **2** — committing P2b `perf`. > **Goal/order:** app foundation → hard probe → easy wins → remaining complex → sync conversion → coordinated break → cleanup (events, shared-state encapsulation). Decisions: [architecture-decisions.md](architecture-decisions.md). Links: [implementation workflow](turbomodule-implementation-workflow.md), [change authoring](../testing/change-authoring-workflow.md), [functions reference](../../../packages/functions/) ([PR #8603](https://github.com/invertase/react-native-firebase/pull/8603)). Ephemeral tracker; see [OKF policy](../documentation-policy.md). @@ -282,7 +282,7 @@ Skip steps 1–2 when spec shape is known (most Tier D packages). | Phase 0 `app` TurboModules | P0 | **closed** | **closed** | **closed** | done | `full` | `feat(app)!: migrate app modules to TurboModules incl general migration infra` | Committed 2026-06-30. | | Phase 0.1 `app` compare:types | P0.1 | **closed** | **closed** | **closed** | done | `none` | `test(app): add app module type comparison config` | Committed 2026-06-30. | | Phase 1 `firestore` TurboModules | P1 | **closed** | **closed** | **closed** | done | `area-focused` | `feat(firestore)!: migrate firestore to TurboModules` | Committed 2026-06-30. | -| Phase 2 `installations` | P2a | **closed** | **closed** | **open** | `commit` | `area-focused` | `feat(installations)!: migrate installations to TurboModules` | Review closed 2026-06-30. Remediation: iOS `invalidate` no-op. | +| Phase 2 `installations` | P2a | **closed** | **closed** | **closed** | done | `area-focused` | `feat(installations)!: migrate installations to TurboModules` | Committed 2026-06-30. Remediation: iOS `invalidate` no-op. | | Phase 2 `perf` | P2b | **closed** | **closed** | **open** | `commit` | `area-focused` | `feat(perf)!: migrate perf to TurboModules` | Review green 2026-06-30. Deferred: dead legacy Java shell; `xdescribe` pending; vacuous iOS screenTrace e2e. | | Phase 2 `in-app-messaging` | P2c | **closed** | **closed** | **open** | `commit` | `area-focused` | `feat(in-app-messaging)!: migrate in-app-messaging to TurboModules` | Review green 2026-06-30. Deferred: dead legacy Java; stale JSDoc; 3 xdescribe pending. | | Phase 2 `app-distribution` | P2d | **closed** | **closed** | **open** | `commit` | `area-focused` | `feat(app-distribution)!: migrate app-distribution to TurboModules` | Review green 2026-06-30: Android 1 pass + 4 pending; iOS 3 pass + 2 pending. Duplicate codegen + legacy Java removed. | diff --git a/packages/perf/RNFBPerf.podspec b/packages/perf/RNFBPerf.podspec index 8456941ddb..4902987ec5 100644 --- a/packages/perf/RNFBPerf.podspec +++ b/packages/perf/RNFBPerf.podspec @@ -28,15 +28,16 @@ Pod::Spec.new do |s| s.ios.deployment_target = firebase_ios_target s.macos.deployment_target = firebase_macos_target s.tvos.deployment_target = firebase_tvos_target - s.source_files = 'ios/**/*.{h,m}' + s.source_files = 'ios/**/*.{h,m,mm,cpp,swift}' + s.private_header_files = "ios/**/*.h" + s.exclude_files = 'ios/generated/RCTThirdPartyComponentsProvider.*', 'ios/generated/RCTAppDependencyProvider.*', 'ios/generated/RCTModuleProviders.*', 'ios/generated/RCTModulesConformingToProtocolsProvider.*', 'ios/generated/RCTUnstableModulesRequiringMainQueueSetupProvider.*' s.dependency 'RNFBApp' - # React Native dependencies - if defined?(install_modules_dependencies()) != nil - install_modules_dependencies(s); - else - s.dependency "React-Core" + install_modules_dependencies(s); + + if defined?(ENV["RCT_NEW_ARCH_ENABLED"]) != nil && (ENV["RCT_NEW_ARCH_ENABLED"] == '0') + raise "#{s.name} requires New Architecture. Enable New Architecture to use this module" end if defined?($FirebaseSDKVersion) diff --git a/packages/perf/__tests__/nativeModuleContract.test.ts b/packages/perf/__tests__/nativeModuleContract.test.ts new file mode 100644 index 0000000000..fb782144af --- /dev/null +++ b/packages/perf/__tests__/nativeModuleContract.test.ts @@ -0,0 +1,80 @@ +import { describe, expect, it, jest } from '@jest/globals'; +import { TurboModuleRegistry } from 'react-native'; +import type { ModuleConfig } from '@react-native-firebase/app/dist/module/internal'; +import FirebaseModule from '@react-native-firebase/app/dist/module/internal/FirebaseModule'; +import { getNativeModule } from '@react-native-firebase/app/dist/module/internal/registry/nativeModule'; +import type { WrappedNativeModule } from '@react-native-firebase/app/dist/module/internal/NativeModules'; + +const SPEC_METHODS = [ + 'setPerformanceCollectionEnabled', + 'instrumentationEnabled', + 'startTrace', + 'stopTrace', + 'startScreenTrace', + 'stopScreenTrace', + 'startHttpMetric', + 'stopHttpMetric', +] as const; + +function createTurboModuleFixture( + methods: Record, + constants: Record = {}, +): Record { + const proto = Object.create(Object.prototype, { + getConstants: { + value: () => constants, + enumerable: true, + }, + }); + + for (const [name, fn] of Object.entries(methods)) { + Object.defineProperty(proto, name, { + value: fn, + enumerable: true, + configurable: true, + }); + } + + return Object.create(proto); +} + +describe('TurboModule wrapper contract (NewArch-AD-17.1)', function () { + it('exposes every spec method callable through the real wrapper', function () { + const mocks = Object.fromEntries( + SPEC_METHODS.map(method => [method, jest.fn(() => Promise.resolve(null))]), + ) as Record; + + const raw = createTurboModuleFixture(mocks, { + isPerformanceCollectionEnabled: true, + isInstrumentationEnabled: true, + }); + jest.mocked(TurboModuleRegistry.get).mockReturnValueOnce(raw); + + const config: ModuleConfig = { + namespace: 'perf', + nativeModuleName: 'NativeRNFBTurboPerf', + nativeEvents: false, + hasMultiAppSupport: false, + hasCustomUrlOrRegionSupport: false, + turboModule: true, + }; + + class ContractModule extends FirebaseModule { + constructor() { + super({ name: '[DEFAULT]' } as any, config); + } + } + + const wrapped = getNativeModule(new ContractModule()) as WrappedNativeModule & + Record<(typeof SPEC_METHODS)[number], () => Promise>; + + for (const method of SPEC_METHODS) { + void wrapped[method](); + expect(mocks[method]).toHaveBeenCalledTimes(1); + expect(Object.keys(wrapped)).toContain(method); + } + + expect(wrapped.isPerformanceCollectionEnabled).toBe(true); + expect(wrapped.isInstrumentationEnabled).toBe(true); + }); +}); diff --git a/packages/perf/android/build.gradle b/packages/perf/android/build.gradle index e3d276e755..918244d92b 100644 --- a/packages/perf/android/build.gradle +++ b/packages/perf/android/build.gradle @@ -121,6 +121,7 @@ android { sourceSets { main { java.srcDirs = ['src/main/java', 'src/reactnative/java'] + java.excludes = ['**/generated/jni/**'] } } } @@ -140,3 +141,21 @@ ReactNative.shared.applyPackageVersion() ReactNative.shared.applyDefaultExcludes() ReactNative.module.applyAndroidVersions() ReactNative.module.applyReactNativeDependency("api") + +def isNewArchitectureDisabled() { + return project.hasProperty("newArchEnabled") && project.newArchEnabled != "true" +} + +if (isNewArchitectureDisabled()) { + def ANSI_RED = "\u001B[31m"; + def ANSI_RESET = "\u001B[0m"; + + println("\n\n\n") + println(ANSI_RED + "**************************************************************************************************************") + println("\n\n\n") + println("New Architecture support is required for @react-native-firebase/perf") + println("\n\n\n") + println("**************************************************************************************************************" + ANSI_RESET) + println("\n\n\n") + System.exit(1) +} diff --git a/packages/perf/android/src/reactnative/java/io/invertase/firebase/perf/NativeRNFBTurboPerf.java b/packages/perf/android/src/reactnative/java/io/invertase/firebase/perf/NativeRNFBTurboPerf.java new file mode 100644 index 0000000000..52a4c32e01 --- /dev/null +++ b/packages/perf/android/src/reactnative/java/io/invertase/firebase/perf/NativeRNFBTurboPerf.java @@ -0,0 +1,161 @@ +package io.invertase.firebase.perf; + +/* + * Copyright (c) 2016-present Invertase Limited & Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this library except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import android.app.Activity; +import com.facebook.fbreact.specs.NativeRNFBTurboPerfSpec; +import com.facebook.react.bridge.Arguments; +import com.facebook.react.bridge.Promise; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReadableMap; +import java.util.Map; + +public class NativeRNFBTurboPerf extends NativeRNFBTurboPerfSpec { + private static final String SERVICE_NAME = "Perf"; + private final UniversalFirebasePerfModule module; + + public NativeRNFBTurboPerf(ReactApplicationContext reactContext) { + super(reactContext); + this.module = new UniversalFirebasePerfModule(reactContext, SERVICE_NAME); + } + + @Override + public void invalidate() { + super.invalidate(); + module.onTearDown(); + } + + @Override + protected Map getTypedExportedConstants() { + return module.getConstants(); + } + + @Override + public void setPerformanceCollectionEnabled(boolean enabled, Promise promise) { + module + .setPerformanceCollectionEnabled(enabled) + .addOnCompleteListener( + task -> { + if (task.isSuccessful()) { + promise.resolve(task.getResult()); + } else { + promise.reject(task.getException()); + } + }); + } + + @Override + public void instrumentationEnabled(boolean enabled, Promise promise) { + promise.resolve(null); + } + + @Override + public void startTrace(double id, String identifier, Promise promise) { + module + .startTrace((int) id, identifier) + .addOnCompleteListener( + task -> { + if (task.isSuccessful()) { + promise.resolve(task.getResult()); + } else { + promise.reject(task.getException()); + } + }); + } + + @Override + public void stopTrace(double id, ReadableMap traceData, Promise promise) { + module + .stopTrace( + (int) id, + Arguments.toBundle(traceData.getMap("metrics")), + Arguments.toBundle(traceData.getMap("attributes"))) + .addOnCompleteListener( + task -> { + if (task.isSuccessful()) { + promise.resolve(task.getResult()); + } else { + promise.reject(task.getException()); + } + }); + } + + @Override + public void startScreenTrace(double id, String identifier, Promise promise) { + Activity currentActivity = getCurrentActivity(); + + if (currentActivity == null) { + promise.resolve(null); + return; + } + + module + .startScreenTrace(currentActivity, (int) id, identifier) + .addOnCompleteListener( + task -> { + if (task.isSuccessful()) { + promise.resolve(task.getResult()); + } else { + promise.reject(task.getException()); + } + }); + } + + @Override + public void stopScreenTrace(double id, Promise promise) { + module + .stopScreenTrace((int) id) + .addOnCompleteListener( + task -> { + if (task.isSuccessful()) { + promise.resolve(task.getResult()); + } else { + promise.reject(task.getException()); + } + }); + } + + @Override + public void startHttpMetric(double id, String url, String httpMethod, Promise promise) { + module + .startHttpMetric((int) id, url, httpMethod) + .addOnCompleteListener( + task -> { + if (task.isSuccessful()) { + promise.resolve(task.getResult()); + } else { + promise.reject(task.getException()); + } + }); + } + + @Override + public void stopHttpMetric(double id, ReadableMap metricData, Promise promise) { + module + .stopHttpMetric( + (int) id, Arguments.toBundle(metricData), Arguments.toBundle(metricData.getMap("attributes"))) + .addOnCompleteListener( + task -> { + if (task.isSuccessful()) { + promise.resolve(task.getResult()); + } else { + promise.reject(task.getException()); + } + }); + } +} diff --git a/packages/perf/android/src/reactnative/java/io/invertase/firebase/perf/ReactNativeFirebasePerfPackage.java b/packages/perf/android/src/reactnative/java/io/invertase/firebase/perf/ReactNativeFirebasePerfPackage.java index bc72b5f43c..ca39f53fc5 100644 --- a/packages/perf/android/src/reactnative/java/io/invertase/firebase/perf/ReactNativeFirebasePerfPackage.java +++ b/packages/perf/android/src/reactnative/java/io/invertase/firebase/perf/ReactNativeFirebasePerfPackage.java @@ -32,7 +32,7 @@ public class ReactNativeFirebasePerfPackage implements ReactPackage { @Override public List createNativeModules(@Nonnull ReactApplicationContext reactContext) { List modules = new ArrayList<>(); - modules.add(new ReactNativeFirebasePerfModule(reactContext)); + modules.add(new NativeRNFBTurboPerf(reactContext)); return modules; } diff --git a/packages/perf/android/src/reactnative/java/io/invertase/firebase/perf/generated/java/com/facebook/fbreact/specs/NativeRNFBTurboPerfSpec.java b/packages/perf/android/src/reactnative/java/io/invertase/firebase/perf/generated/java/com/facebook/fbreact/specs/NativeRNFBTurboPerfSpec.java new file mode 100644 index 0000000000..5e44603763 --- /dev/null +++ b/packages/perf/android/src/reactnative/java/io/invertase/firebase/perf/generated/java/com/facebook/fbreact/specs/NativeRNFBTurboPerfSpec.java @@ -0,0 +1,100 @@ + +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleJavaSpec.js + * + * @nolint + */ + +package com.facebook.fbreact.specs; + +import com.facebook.proguard.annotations.DoNotStrip; +import com.facebook.react.bridge.Promise; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReactContextBaseJavaModule; +import com.facebook.react.bridge.ReactMethod; +import com.facebook.react.bridge.ReadableMap; +import com.facebook.react.common.build.ReactBuildConfig; +import com.facebook.react.turbomodule.core.interfaces.TurboModule; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public abstract class NativeRNFBTurboPerfSpec extends ReactContextBaseJavaModule implements TurboModule { + public static final String NAME = "NativeRNFBTurboPerf"; + + public NativeRNFBTurboPerfSpec(ReactApplicationContext reactContext) { + super(reactContext); + } + + @Override + public @Nonnull String getName() { + return NAME; + } + + protected abstract Map getTypedExportedConstants(); + + @Override + @DoNotStrip + public final @Nullable Map getConstants() { + Map constants = getTypedExportedConstants(); + if (ReactBuildConfig.DEBUG || ReactBuildConfig.IS_INTERNAL_BUILD) { + Set obligatoryFlowConstants = new HashSet<>(Arrays.asList( + "isInstrumentationEnabled", + "isPerformanceCollectionEnabled" + )); + Set optionalFlowConstants = new HashSet<>(); + Set undeclaredConstants = new HashSet<>(constants.keySet()); + undeclaredConstants.removeAll(obligatoryFlowConstants); + undeclaredConstants.removeAll(optionalFlowConstants); + if (!undeclaredConstants.isEmpty()) { + throw new IllegalStateException(String.format("Native Module Flow doesn't declare constants: %s", undeclaredConstants)); + } + undeclaredConstants = obligatoryFlowConstants; + undeclaredConstants.removeAll(constants.keySet()); + if (!undeclaredConstants.isEmpty()) { + throw new IllegalStateException(String.format("Native Module doesn't fill in constants: %s", undeclaredConstants)); + } + } + return constants; + } + + @ReactMethod + @DoNotStrip + public abstract void setPerformanceCollectionEnabled(boolean enabled, Promise promise); + + @ReactMethod + @DoNotStrip + public abstract void instrumentationEnabled(boolean enabled, Promise promise); + + @ReactMethod + @DoNotStrip + public abstract void startTrace(double id, String identifier, Promise promise); + + @ReactMethod + @DoNotStrip + public abstract void stopTrace(double id, ReadableMap traceData, Promise promise); + + @ReactMethod + @DoNotStrip + public abstract void startScreenTrace(double id, String identifier, Promise promise); + + @ReactMethod + @DoNotStrip + public abstract void stopScreenTrace(double id, Promise promise); + + @ReactMethod + @DoNotStrip + public abstract void startHttpMetric(double id, String url, String httpMethod, Promise promise); + + @ReactMethod + @DoNotStrip + public abstract void stopHttpMetric(double id, ReadableMap metricData, Promise promise); +} diff --git a/packages/perf/android/src/reactnative/java/io/invertase/firebase/perf/generated/jni/CMakeLists.txt b/packages/perf/android/src/reactnative/java/io/invertase/firebase/perf/generated/jni/CMakeLists.txt new file mode 100644 index 0000000000..9b1c3cd9d6 --- /dev/null +++ b/packages/perf/android/src/reactnative/java/io/invertase/firebase/perf/generated/jni/CMakeLists.txt @@ -0,0 +1,36 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +cmake_minimum_required(VERSION 3.13) +set(CMAKE_VERBOSE_MAKEFILE on) + +file(GLOB react_codegen_SRCS CONFIGURE_DEPENDS *.cpp react/renderer/components/RNFBPerfTurboModules/*.cpp) + +add_library( + react_codegen_RNFBPerfTurboModules + OBJECT + ${react_codegen_SRCS} +) + +target_include_directories(react_codegen_RNFBPerfTurboModules PUBLIC . react/renderer/components/RNFBPerfTurboModules) + +target_link_libraries( + react_codegen_RNFBPerfTurboModules + fbjni + jsi + # We need to link different libraries based on whether we are building rncore or not, that's necessary + # because we want to break a circular dependency between react_codegen_rncore and reactnative + reactnative +) + +target_compile_options( + react_codegen_RNFBPerfTurboModules + PRIVATE + -DLOG_TAG=\"ReactNative\" + -fexceptions + -frtti + -std=c++20 + -Wall +) diff --git a/packages/perf/android/src/reactnative/java/io/invertase/firebase/perf/generated/jni/RNFBPerfTurboModules-generated.cpp b/packages/perf/android/src/reactnative/java/io/invertase/firebase/perf/generated/jni/RNFBPerfTurboModules-generated.cpp new file mode 100644 index 0000000000..ec793d0307 --- /dev/null +++ b/packages/perf/android/src/reactnative/java/io/invertase/firebase/perf/generated/jni/RNFBPerfTurboModules-generated.cpp @@ -0,0 +1,80 @@ + +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleJniCpp.js + */ + +#include "RNFBPerfTurboModules.h" + +namespace facebook::react { + +static facebook::jsi::Value __hostFunction_NativeRNFBTurboPerfSpecJSI_getConstants(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, ObjectKind, "getConstants", "()Ljava/util/Map;", args, count, cachedMethodId); +} + +static facebook::jsi::Value __hostFunction_NativeRNFBTurboPerfSpecJSI_setPerformanceCollectionEnabled(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, PromiseKind, "setPerformanceCollectionEnabled", "(ZLcom/facebook/react/bridge/Promise;)V", args, count, cachedMethodId); +} + +static facebook::jsi::Value __hostFunction_NativeRNFBTurboPerfSpecJSI_instrumentationEnabled(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, PromiseKind, "instrumentationEnabled", "(ZLcom/facebook/react/bridge/Promise;)V", args, count, cachedMethodId); +} + +static facebook::jsi::Value __hostFunction_NativeRNFBTurboPerfSpecJSI_startTrace(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, PromiseKind, "startTrace", "(DLjava/lang/String;Lcom/facebook/react/bridge/Promise;)V", args, count, cachedMethodId); +} + +static facebook::jsi::Value __hostFunction_NativeRNFBTurboPerfSpecJSI_stopTrace(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, PromiseKind, "stopTrace", "(DLcom/facebook/react/bridge/ReadableMap;Lcom/facebook/react/bridge/Promise;)V", args, count, cachedMethodId); +} + +static facebook::jsi::Value __hostFunction_NativeRNFBTurboPerfSpecJSI_startScreenTrace(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, PromiseKind, "startScreenTrace", "(DLjava/lang/String;Lcom/facebook/react/bridge/Promise;)V", args, count, cachedMethodId); +} + +static facebook::jsi::Value __hostFunction_NativeRNFBTurboPerfSpecJSI_stopScreenTrace(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, PromiseKind, "stopScreenTrace", "(DLcom/facebook/react/bridge/Promise;)V", args, count, cachedMethodId); +} + +static facebook::jsi::Value __hostFunction_NativeRNFBTurboPerfSpecJSI_startHttpMetric(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, PromiseKind, "startHttpMetric", "(DLjava/lang/String;Ljava/lang/String;Lcom/facebook/react/bridge/Promise;)V", args, count, cachedMethodId); +} + +static facebook::jsi::Value __hostFunction_NativeRNFBTurboPerfSpecJSI_stopHttpMetric(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, PromiseKind, "stopHttpMetric", "(DLcom/facebook/react/bridge/ReadableMap;Lcom/facebook/react/bridge/Promise;)V", args, count, cachedMethodId); +} + +NativeRNFBTurboPerfSpecJSI::NativeRNFBTurboPerfSpecJSI(const JavaTurboModule::InitParams ¶ms) + : JavaTurboModule(params) { + methodMap_["getConstants"] = MethodMetadata {0, __hostFunction_NativeRNFBTurboPerfSpecJSI_getConstants}; + methodMap_["setPerformanceCollectionEnabled"] = MethodMetadata {1, __hostFunction_NativeRNFBTurboPerfSpecJSI_setPerformanceCollectionEnabled}; + methodMap_["instrumentationEnabled"] = MethodMetadata {1, __hostFunction_NativeRNFBTurboPerfSpecJSI_instrumentationEnabled}; + methodMap_["startTrace"] = MethodMetadata {2, __hostFunction_NativeRNFBTurboPerfSpecJSI_startTrace}; + methodMap_["stopTrace"] = MethodMetadata {2, __hostFunction_NativeRNFBTurboPerfSpecJSI_stopTrace}; + methodMap_["startScreenTrace"] = MethodMetadata {2, __hostFunction_NativeRNFBTurboPerfSpecJSI_startScreenTrace}; + methodMap_["stopScreenTrace"] = MethodMetadata {1, __hostFunction_NativeRNFBTurboPerfSpecJSI_stopScreenTrace}; + methodMap_["startHttpMetric"] = MethodMetadata {3, __hostFunction_NativeRNFBTurboPerfSpecJSI_startHttpMetric}; + methodMap_["stopHttpMetric"] = MethodMetadata {2, __hostFunction_NativeRNFBTurboPerfSpecJSI_stopHttpMetric}; +} + +std::shared_ptr RNFBPerfTurboModules_ModuleProvider(const std::string &moduleName, const JavaTurboModule::InitParams ¶ms) { + if (moduleName == "NativeRNFBTurboPerf") { + return std::make_shared(params); + } + return nullptr; +} + +} // namespace facebook::react diff --git a/packages/perf/android/src/reactnative/java/io/invertase/firebase/perf/generated/jni/RNFBPerfTurboModules.h b/packages/perf/android/src/reactnative/java/io/invertase/firebase/perf/generated/jni/RNFBPerfTurboModules.h new file mode 100644 index 0000000000..216709d700 --- /dev/null +++ b/packages/perf/android/src/reactnative/java/io/invertase/firebase/perf/generated/jni/RNFBPerfTurboModules.h @@ -0,0 +1,31 @@ + +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleJniH.js + */ + +#pragma once + +#include +#include +#include + +namespace facebook::react { + +/** + * JNI C++ class for module 'NativeRNFBTurboPerf' + */ +class JSI_EXPORT NativeRNFBTurboPerfSpecJSI : public JavaTurboModule { +public: + NativeRNFBTurboPerfSpecJSI(const JavaTurboModule::InitParams ¶ms); +}; + + +JSI_EXPORT +std::shared_ptr RNFBPerfTurboModules_ModuleProvider(const std::string &moduleName, const JavaTurboModule::InitParams ¶ms); + +} // namespace facebook::react diff --git a/packages/perf/android/src/reactnative/java/io/invertase/firebase/perf/generated/jni/react/renderer/components/RNFBPerfTurboModules/RNFBPerfTurboModulesJSI-generated.cpp b/packages/perf/android/src/reactnative/java/io/invertase/firebase/perf/generated/jni/react/renderer/components/RNFBPerfTurboModules/RNFBPerfTurboModulesJSI-generated.cpp new file mode 100644 index 0000000000..43dc7a037d --- /dev/null +++ b/packages/perf/android/src/reactnative/java/io/invertase/firebase/perf/generated/jni/react/renderer/components/RNFBPerfTurboModules/RNFBPerfTurboModulesJSI-generated.cpp @@ -0,0 +1,88 @@ +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleCpp.js + */ + +#include "RNFBPerfTurboModulesJSI.h" + +namespace facebook::react { + +static jsi::Value __hostFunction_NativeRNFBTurboPerfCxxSpecJSI_getConstants(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getConstants( + rt + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboPerfCxxSpecJSI_setPerformanceCollectionEnabled(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->setPerformanceCollectionEnabled( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asBool() + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboPerfCxxSpecJSI_instrumentationEnabled(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->instrumentationEnabled( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asBool() + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboPerfCxxSpecJSI_startTrace(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->startTrace( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asNumber(), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt) + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboPerfCxxSpecJSI_stopTrace(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->stopTrace( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asNumber(), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asObject(rt) + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboPerfCxxSpecJSI_startScreenTrace(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->startScreenTrace( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asNumber(), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt) + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboPerfCxxSpecJSI_stopScreenTrace(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->stopScreenTrace( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asNumber() + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboPerfCxxSpecJSI_startHttpMetric(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->startHttpMetric( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asNumber(), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt), + count <= 2 ? throw jsi::JSError(rt, "Expected argument in position 2 to be passed") : args[2].asString(rt) + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboPerfCxxSpecJSI_stopHttpMetric(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->stopHttpMetric( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asNumber(), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asObject(rt) + ); +} + +NativeRNFBTurboPerfCxxSpecJSI::NativeRNFBTurboPerfCxxSpecJSI(std::shared_ptr jsInvoker) + : TurboModule("NativeRNFBTurboPerf", jsInvoker) { + methodMap_["getConstants"] = MethodMetadata {0, __hostFunction_NativeRNFBTurboPerfCxxSpecJSI_getConstants}; + methodMap_["setPerformanceCollectionEnabled"] = MethodMetadata {1, __hostFunction_NativeRNFBTurboPerfCxxSpecJSI_setPerformanceCollectionEnabled}; + methodMap_["instrumentationEnabled"] = MethodMetadata {1, __hostFunction_NativeRNFBTurboPerfCxxSpecJSI_instrumentationEnabled}; + methodMap_["startTrace"] = MethodMetadata {2, __hostFunction_NativeRNFBTurboPerfCxxSpecJSI_startTrace}; + methodMap_["stopTrace"] = MethodMetadata {2, __hostFunction_NativeRNFBTurboPerfCxxSpecJSI_stopTrace}; + methodMap_["startScreenTrace"] = MethodMetadata {2, __hostFunction_NativeRNFBTurboPerfCxxSpecJSI_startScreenTrace}; + methodMap_["stopScreenTrace"] = MethodMetadata {1, __hostFunction_NativeRNFBTurboPerfCxxSpecJSI_stopScreenTrace}; + methodMap_["startHttpMetric"] = MethodMetadata {3, __hostFunction_NativeRNFBTurboPerfCxxSpecJSI_startHttpMetric}; + methodMap_["stopHttpMetric"] = MethodMetadata {2, __hostFunction_NativeRNFBTurboPerfCxxSpecJSI_stopHttpMetric}; +} + + +} // namespace facebook::react diff --git a/packages/perf/android/src/reactnative/java/io/invertase/firebase/perf/generated/jni/react/renderer/components/RNFBPerfTurboModules/RNFBPerfTurboModulesJSI.h b/packages/perf/android/src/reactnative/java/io/invertase/firebase/perf/generated/jni/react/renderer/components/RNFBPerfTurboModules/RNFBPerfTurboModulesJSI.h new file mode 100644 index 0000000000..a2762fc32e --- /dev/null +++ b/packages/perf/android/src/reactnative/java/io/invertase/firebase/perf/generated/jni/react/renderer/components/RNFBPerfTurboModules/RNFBPerfTurboModulesJSI.h @@ -0,0 +1,267 @@ +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleH.js + */ + +#pragma once + +#include +#include + +namespace facebook::react { + + + +#pragma mark - NativeRNFBTurboPerfHttpMetricData + +template +struct NativeRNFBTurboPerfHttpMetricData { + P0 attributes; + P1 httpResponseCode; + P2 requestPayloadSize; + P3 responsePayloadSize; + P4 responseContentType; + bool operator==(const NativeRNFBTurboPerfHttpMetricData &other) const { + return attributes == other.attributes && httpResponseCode == other.httpResponseCode && requestPayloadSize == other.requestPayloadSize && responsePayloadSize == other.responsePayloadSize && responseContentType == other.responseContentType; + } +}; + +template +struct NativeRNFBTurboPerfHttpMetricDataBridging { + static T types; + + static T fromJs( + jsi::Runtime &rt, + const jsi::Object &value, + const std::shared_ptr &jsInvoker) { + T result{ + bridging::fromJs(rt, value.getProperty(rt, "attributes"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, "httpResponseCode"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, "requestPayloadSize"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, "responsePayloadSize"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, "responseContentType"), jsInvoker)}; + return result; + } + +#ifdef DEBUG + static jsi::Object attributesToJs(jsi::Runtime &rt, decltype(types.attributes) value) { + return bridging::toJs(rt, value); + } + + static double httpResponseCodeToJs(jsi::Runtime &rt, decltype(types.httpResponseCode) value) { + return bridging::toJs(rt, value); + } + + static double requestPayloadSizeToJs(jsi::Runtime &rt, decltype(types.requestPayloadSize) value) { + return bridging::toJs(rt, value); + } + + static double responsePayloadSizeToJs(jsi::Runtime &rt, decltype(types.responsePayloadSize) value) { + return bridging::toJs(rt, value); + } + + static jsi::String responseContentTypeToJs(jsi::Runtime &rt, decltype(types.responseContentType) value) { + return bridging::toJs(rt, value); + } +#endif + + static jsi::Object toJs( + jsi::Runtime &rt, + const T &value, + const std::shared_ptr &jsInvoker) { + auto result = facebook::jsi::Object(rt); + result.setProperty(rt, "attributes", bridging::toJs(rt, value.attributes, jsInvoker)); + if (value.httpResponseCode) { + result.setProperty(rt, "httpResponseCode", bridging::toJs(rt, value.httpResponseCode.value(), jsInvoker)); + } + if (value.requestPayloadSize) { + result.setProperty(rt, "requestPayloadSize", bridging::toJs(rt, value.requestPayloadSize.value(), jsInvoker)); + } + if (value.responsePayloadSize) { + result.setProperty(rt, "responsePayloadSize", bridging::toJs(rt, value.responsePayloadSize.value(), jsInvoker)); + } + if (value.responseContentType) { + result.setProperty(rt, "responseContentType", bridging::toJs(rt, value.responseContentType.value(), jsInvoker)); + } + return result; + } +}; + + + +#pragma mark - NativeRNFBTurboPerfTraceData + +template +struct NativeRNFBTurboPerfTraceData { + P0 metrics; + P1 attributes; + bool operator==(const NativeRNFBTurboPerfTraceData &other) const { + return metrics == other.metrics && attributes == other.attributes; + } +}; + +template +struct NativeRNFBTurboPerfTraceDataBridging { + static T types; + + static T fromJs( + jsi::Runtime &rt, + const jsi::Object &value, + const std::shared_ptr &jsInvoker) { + T result{ + bridging::fromJs(rt, value.getProperty(rt, "metrics"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, "attributes"), jsInvoker)}; + return result; + } + +#ifdef DEBUG + static jsi::Object metricsToJs(jsi::Runtime &rt, decltype(types.metrics) value) { + return bridging::toJs(rt, value); + } + + static jsi::Object attributesToJs(jsi::Runtime &rt, decltype(types.attributes) value) { + return bridging::toJs(rt, value); + } +#endif + + static jsi::Object toJs( + jsi::Runtime &rt, + const T &value, + const std::shared_ptr &jsInvoker) { + auto result = facebook::jsi::Object(rt); + result.setProperty(rt, "metrics", bridging::toJs(rt, value.metrics, jsInvoker)); + result.setProperty(rt, "attributes", bridging::toJs(rt, value.attributes, jsInvoker)); + return result; + } +}; + +class JSI_EXPORT NativeRNFBTurboPerfCxxSpecJSI : public TurboModule { +protected: + NativeRNFBTurboPerfCxxSpecJSI(std::shared_ptr jsInvoker); + +public: + virtual jsi::Object getConstants(jsi::Runtime &rt) = 0; + virtual jsi::Value setPerformanceCollectionEnabled(jsi::Runtime &rt, bool enabled) = 0; + virtual jsi::Value instrumentationEnabled(jsi::Runtime &rt, bool enabled) = 0; + virtual jsi::Value startTrace(jsi::Runtime &rt, double id, jsi::String identifier) = 0; + virtual jsi::Value stopTrace(jsi::Runtime &rt, double id, jsi::Object traceData) = 0; + virtual jsi::Value startScreenTrace(jsi::Runtime &rt, double id, jsi::String identifier) = 0; + virtual jsi::Value stopScreenTrace(jsi::Runtime &rt, double id) = 0; + virtual jsi::Value startHttpMetric(jsi::Runtime &rt, double id, jsi::String url, jsi::String httpMethod) = 0; + virtual jsi::Value stopHttpMetric(jsi::Runtime &rt, double id, jsi::Object metricData) = 0; + +}; + +template +class JSI_EXPORT NativeRNFBTurboPerfCxxSpec : public TurboModule { +public: + jsi::Value create(jsi::Runtime &rt, const jsi::PropNameID &propName) override { + return delegate_.create(rt, propName); + } + + std::vector getPropertyNames(jsi::Runtime& runtime) override { + return delegate_.getPropertyNames(runtime); + } + + static constexpr std::string_view kModuleName = "NativeRNFBTurboPerf"; + +protected: + NativeRNFBTurboPerfCxxSpec(std::shared_ptr jsInvoker) + : TurboModule(std::string{NativeRNFBTurboPerfCxxSpec::kModuleName}, jsInvoker), + delegate_(reinterpret_cast(this), jsInvoker) {} + + +private: + class Delegate : public NativeRNFBTurboPerfCxxSpecJSI { + public: + Delegate(T *instance, std::shared_ptr jsInvoker) : + NativeRNFBTurboPerfCxxSpecJSI(std::move(jsInvoker)), instance_(instance) { + + } + + jsi::Object getConstants(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::getConstants) == 1, + "Expected getConstants(...) to have 1 parameters"); + + return bridging::callFromJs( + rt, &T::getConstants, jsInvoker_, instance_); + } + jsi::Value setPerformanceCollectionEnabled(jsi::Runtime &rt, bool enabled) override { + static_assert( + bridging::getParameterCount(&T::setPerformanceCollectionEnabled) == 2, + "Expected setPerformanceCollectionEnabled(...) to have 2 parameters"); + + return bridging::callFromJs( + rt, &T::setPerformanceCollectionEnabled, jsInvoker_, instance_, std::move(enabled)); + } + jsi::Value instrumentationEnabled(jsi::Runtime &rt, bool enabled) override { + static_assert( + bridging::getParameterCount(&T::instrumentationEnabled) == 2, + "Expected instrumentationEnabled(...) to have 2 parameters"); + + return bridging::callFromJs( + rt, &T::instrumentationEnabled, jsInvoker_, instance_, std::move(enabled)); + } + jsi::Value startTrace(jsi::Runtime &rt, double id, jsi::String identifier) override { + static_assert( + bridging::getParameterCount(&T::startTrace) == 3, + "Expected startTrace(...) to have 3 parameters"); + + return bridging::callFromJs( + rt, &T::startTrace, jsInvoker_, instance_, std::move(id), std::move(identifier)); + } + jsi::Value stopTrace(jsi::Runtime &rt, double id, jsi::Object traceData) override { + static_assert( + bridging::getParameterCount(&T::stopTrace) == 3, + "Expected stopTrace(...) to have 3 parameters"); + + return bridging::callFromJs( + rt, &T::stopTrace, jsInvoker_, instance_, std::move(id), std::move(traceData)); + } + jsi::Value startScreenTrace(jsi::Runtime &rt, double id, jsi::String identifier) override { + static_assert( + bridging::getParameterCount(&T::startScreenTrace) == 3, + "Expected startScreenTrace(...) to have 3 parameters"); + + return bridging::callFromJs( + rt, &T::startScreenTrace, jsInvoker_, instance_, std::move(id), std::move(identifier)); + } + jsi::Value stopScreenTrace(jsi::Runtime &rt, double id) override { + static_assert( + bridging::getParameterCount(&T::stopScreenTrace) == 2, + "Expected stopScreenTrace(...) to have 2 parameters"); + + return bridging::callFromJs( + rt, &T::stopScreenTrace, jsInvoker_, instance_, std::move(id)); + } + jsi::Value startHttpMetric(jsi::Runtime &rt, double id, jsi::String url, jsi::String httpMethod) override { + static_assert( + bridging::getParameterCount(&T::startHttpMetric) == 4, + "Expected startHttpMetric(...) to have 4 parameters"); + + return bridging::callFromJs( + rt, &T::startHttpMetric, jsInvoker_, instance_, std::move(id), std::move(url), std::move(httpMethod)); + } + jsi::Value stopHttpMetric(jsi::Runtime &rt, double id, jsi::Object metricData) override { + static_assert( + bridging::getParameterCount(&T::stopHttpMetric) == 3, + "Expected stopHttpMetric(...) to have 3 parameters"); + + return bridging::callFromJs( + rt, &T::stopHttpMetric, jsInvoker_, instance_, std::move(id), std::move(metricData)); + } + + private: + friend class NativeRNFBTurboPerfCxxSpec; + T *instance_; + }; + + Delegate delegate_; +}; + +} // namespace facebook::react diff --git a/packages/perf/ios/RNFBPerf.xcodeproj/project.pbxproj b/packages/perf/ios/RNFBPerf.xcodeproj/project.pbxproj index 1c89d66708..ae5944ddf5 100644 --- a/packages/perf/ios/RNFBPerf.xcodeproj/project.pbxproj +++ b/packages/perf/ios/RNFBPerf.xcodeproj/project.pbxproj @@ -7,7 +7,7 @@ objects = { /* Begin PBXBuildFile section */ - 2744B98621F45429004F8E3F /* RNFBPerfModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 2744B98521F45429004F8E3F /* RNFBPerfModule.m */; }; + 2744B98621F45429004F8E3F /* RNFBPerfModule.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2744B98521F45429004F8E3F /* RNFBPerfModule.mm */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -25,7 +25,7 @@ /* Begin PBXFileReference section */ 2744B98221F45429004F8E3F /* libRNFBPerf.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRNFBPerf.a; sourceTree = BUILT_PRODUCTS_DIR; }; 2744B98421F45429004F8E3F /* RNFBPerfModule.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = RNFBPerfModule.h; path = RNFBPerf/RNFBPerfModule.h; sourceTree = SOURCE_ROOT; }; - 2744B98521F45429004F8E3F /* RNFBPerfModule.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = RNFBPerfModule.m; path = RNFBPerf/RNFBPerfModule.m; sourceTree = SOURCE_ROOT; }; + 2744B98521F45429004F8E3F /* RNFBPerfModule.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = RNFBPerfModule.mm; path = RNFBPerf/RNFBPerfModule.mm; sourceTree = SOURCE_ROOT; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -53,7 +53,7 @@ 2744B9A121F48736004F8E3F /* converters */, 2744B98C21F45C64004F8E3F /* common */, 2744B98421F45429004F8E3F /* RNFBPerfModule.h */, - 2744B98521F45429004F8E3F /* RNFBPerfModule.m */, + 2744B98521F45429004F8E3F /* RNFBPerfModule.mm */, ); path = RNFBPerf; sourceTree = ""; @@ -124,7 +124,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 2744B98621F45429004F8E3F /* RNFBPerfModule.m in Sources */, + 2744B98621F45429004F8E3F /* RNFBPerfModule.mm in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/packages/perf/ios/RNFBPerf/RNFBPerfModule.h b/packages/perf/ios/RNFBPerf/RNFBPerfModule.h index bf74772747..2306743947 100644 --- a/packages/perf/ios/RNFBPerf/RNFBPerfModule.h +++ b/packages/perf/ios/RNFBPerf/RNFBPerfModule.h @@ -16,8 +16,9 @@ */ #import +#import +#import "RNFBPerfTurboModules.h" -#import +@interface RNFBPerfModule : NSObject -@interface RNFBPerfModule : NSObject @end diff --git a/packages/perf/ios/RNFBPerf/RNFBPerfModule.m b/packages/perf/ios/RNFBPerf/RNFBPerfModule.mm similarity index 56% rename from packages/perf/ios/RNFBPerf/RNFBPerfModule.m rename to packages/perf/ios/RNFBPerf/RNFBPerfModule.mm index 96570231a3..756fb2293f 100644 --- a/packages/perf/ios/RNFBPerf/RNFBPerfModule.m +++ b/packages/perf/ios/RNFBPerf/RNFBPerfModule.mm @@ -25,10 +25,12 @@ static __strong NSMutableDictionary *httpMetrics; @implementation RNFBPerfModule -#pragma mark - -#pragma mark Module Setup -RCT_EXPORT_MODULE(); +RCT_EXPORT_MODULE(NativeRNFBTurboPerf) + ++ (BOOL)requiresMainQueueSetup { + return NO; +} - (instancetype)init { self = [super init]; @@ -42,7 +44,7 @@ - (instancetype)init { return self; } -- (void)dealloc { +- (void)invalidate { @synchronized([self class]) { for (NSString *key in [traces allKeys]) { [traces removeObjectForKey:key]; @@ -54,7 +56,7 @@ - (void)dealloc { } } -- (NSDictionary *)constantsToExport { +- (NSDictionary *)perfConstantsDictionary { NSMutableDictionary *constants = [NSMutableDictionary new]; constants[@"isPerformanceCollectionEnabled"] = @([RCTConvert BOOL:@([FIRPerformance sharedInstance].dataCollectionEnabled)]); @@ -63,48 +65,58 @@ - (NSDictionary *)constantsToExport { return constants; } -+ (BOOL)requiresMainQueueSetup { - return NO; +- (facebook::react::ModuleConstants)constantsToExport { + return [_RCTTypedModuleConstants newWithUnsafeDictionary:[self perfConstantsDictionary]]; } -#pragma mark - -#pragma mark Firebase Perf Methods +- (facebook::react::ModuleConstants)getConstants { + return [self constantsToExport]; +} + +- (std::shared_ptr)getTurboModule: + (const facebook::react::ObjCTurboModule::InitParams &)params { + return std::make_shared(params); +} -RCT_EXPORT_METHOD(setPerformanceCollectionEnabled - : (BOOL)enabled resolver - : (RCTPromiseResolveBlock)resolve rejecter - : (RCTPromiseRejectBlock)reject) { +- (void)setPerformanceCollectionEnabled:(BOOL)enabled + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject { [FIRPerformance sharedInstance].dataCollectionEnabled = (BOOL)enabled; resolve([NSNull null]); } -RCT_EXPORT_METHOD(startTrace - : (nonnull NSNumber *)id identifier - : (NSString *)identifier resolver - : (RCTPromiseResolveBlock)resolve rejecter - : (RCTPromiseRejectBlock)reject) { +- (void)instrumentationEnabled:(BOOL)enabled + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject { + [FIRPerformance sharedInstance].instrumentationEnabled = (BOOL)enabled; + resolve([NSNull null]); +} + +- (void)startTrace:(double)id + identifier:(NSString *)identifier + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject { FIRTrace *trace = [[FIRPerformance sharedInstance] traceWithName:identifier]; [trace start]; @synchronized([self class]) { - traces[id] = trace; + traces[@((int)id)] = trace; } resolve([NSNull null]); } -RCT_EXPORT_METHOD(stopTrace - : (nonnull NSNumber *)id traceData - : (NSDictionary *)traceData resolver - : (RCTPromiseResolveBlock)resolve rejecter - : (RCTPromiseRejectBlock)reject) { +- (void)stopTrace:(double)id + traceData:(JS::NativeRNFBTurboPerf::TraceData &)traceData + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject { FIRTrace *trace; @synchronized([self class]) { - trace = traces[id]; + trace = traces[@((int)id)]; } - NSDictionary *metrics = traceData[@"metrics"]; - NSDictionary *attributes = traceData[@"attributes"]; + NSDictionary *metrics = (NSDictionary *)traceData.metrics(); + NSDictionary *attributes = (NSDictionary *)traceData.attributes(); [metrics enumerateKeysAndObjectsUsingBlock:^(NSString *metricName, NSNumber *value, BOOL *stop) { [trace setIntValue:[value longLongValue] forMetric:metricName]; @@ -118,24 +130,36 @@ + (BOOL)requiresMainQueueSetup { [trace stop]; @synchronized([self class]) { - [traces removeObjectForKey:id]; + [traces removeObjectForKey:@((int)id)]; } resolve([NSNull null]); } -RCT_EXPORT_METHOD(startHttpMetric - : (nonnull NSNumber *)id url - : (NSString *)url httpMethod - : (NSString *)httpMethod resolver - : (RCTPromiseResolveBlock)resolve rejecter - : (RCTPromiseRejectBlock)reject) { +- (void)startScreenTrace:(double)id + identifier:(NSString *)identifier + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject { + resolve([NSNull null]); +} + +- (void)stopScreenTrace:(double)id + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject { + resolve([NSNull null]); +} + +- (void)startHttpMetric:(double)id + url:(NSString *)url + httpMethod:(NSString *)httpMethod + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject { FIRHTTPMethod method = FIRHTTPMethodGET; NSURL *toNSURL = [NSURL URLWithString:url]; if ([httpMethod compare:@"put" options:NSCaseInsensitiveSearch] == NSOrderedSame) method = FIRHTTPMethodPUT; if ([httpMethod compare:@"post" options:NSCaseInsensitiveSearch] == NSOrderedSame) - method = FIRHTTPMethodPUT; + method = FIRHTTPMethodPOST; if ([httpMethod compare:@"head" options:NSCaseInsensitiveSearch] == NSOrderedSame) method = FIRHTTPMethodHEAD; if ([httpMethod compare:@"trace" options:NSCaseInsensitiveSearch] == NSOrderedSame) @@ -153,63 +177,50 @@ + (BOOL)requiresMainQueueSetup { [httpMetric start]; @synchronized([self class]) { - httpMetrics[id] = httpMetric; + httpMetrics[@((int)id)] = httpMetric; } resolve([NSNull null]); } -RCT_EXPORT_METHOD(stopHttpMetric - : (nonnull NSNumber *)id metricData - : (NSDictionary *)metricData resolver - : (RCTPromiseResolveBlock)resolve rejecter - : (RCTPromiseRejectBlock)reject) { +- (void)stopHttpMetric:(double)id + metricData:(JS::NativeRNFBTurboPerf::HttpMetricData &)metricData + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject { FIRHTTPMetric *httpMetric; @synchronized([self class]) { - httpMetric = httpMetrics[id]; + httpMetric = httpMetrics[@((int)id)]; } - NSDictionary *attributes = metricData[@"attributes"]; + NSDictionary *attributes = (NSDictionary *)metricData.attributes(); [attributes enumerateKeysAndObjectsUsingBlock:^(NSString *attributeName, NSString *value, BOOL *stop) { [httpMetric setValue:value forAttribute:attributeName]; }]; - if (metricData[@"httpResponseCode"]) { - NSNumber *responseCode = (NSNumber *)metricData[@"httpResponseCode"]; - [httpMetric setResponseCode:[responseCode integerValue]]; + if (metricData.httpResponseCode().has_value()) { + [httpMetric setResponseCode:(NSInteger)metricData.httpResponseCode().value()]; } - if (metricData[@"requestPayloadSize"]) { - NSNumber *requestPayloadSize = (NSNumber *)metricData[@"requestPayloadSize"]; - [httpMetric setRequestPayloadSize:[requestPayloadSize longValue]]; + if (metricData.requestPayloadSize().has_value()) { + [httpMetric setRequestPayloadSize:(NSInteger)metricData.requestPayloadSize().value()]; } - if (metricData[@"responsePayloadSize"]) { - NSNumber *responsePayloadSize = (NSNumber *)metricData[@"responsePayloadSize"]; - [httpMetric setResponsePayloadSize:[responsePayloadSize longValue]]; + if (metricData.responsePayloadSize().has_value()) { + [httpMetric setResponsePayloadSize:(NSInteger)metricData.responsePayloadSize().value()]; } - if (metricData[@"responseContentType"]) { - NSString *responseContentType = (NSString *)metricData[@"responseContentType"]; - [httpMetric setResponseContentType:responseContentType]; + if (metricData.responseContentType() != nil) { + [httpMetric setResponseContentType:metricData.responseContentType()]; } [httpMetric stop]; @synchronized([self class]) { - [httpMetrics removeObjectForKey:id]; + [httpMetrics removeObjectForKey:@((int)id)]; } resolve([NSNull null]); } -RCT_EXPORT_METHOD(instrumentationEnabled - : (BOOL)enabled resolver - : (RCTPromiseResolveBlock)resolve rejecter - : (RCTPromiseRejectBlock)reject) { - [FIRPerformance sharedInstance].instrumentationEnabled = (BOOL)enabled; - resolve([NSNull null]); -} - @end diff --git a/packages/perf/ios/generated/RNFBPerfTurboModules/RNFBPerfTurboModules-generated.mm b/packages/perf/ios/generated/RNFBPerfTurboModules/RNFBPerfTurboModules-generated.mm new file mode 100644 index 0000000000..caee9d60d2 --- /dev/null +++ b/packages/perf/ios/generated/RNFBPerfTurboModules/RNFBPerfTurboModules-generated.mm @@ -0,0 +1,106 @@ +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleObjCpp + * + * We create an umbrella header (and corresponding implementation) here since + * Cxx compilation in BUCK has a limitation: source-code producing genrule()s + * must have a single output. More files => more genrule()s => slower builds. + */ + +#import "RNFBPerfTurboModules.h" + + +@implementation NativeRNFBTurboPerfSpecBase + + +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper +{ + _eventEmitterCallback = std::move(eventEmitterCallbackWrapper->_eventEmitterCallback); +} +@end + +@implementation RCTCxxConvert (NativeRNFBTurboPerf_TraceData) ++ (RCTManagedPointer *)JS_NativeRNFBTurboPerf_TraceData:(id)json +{ + return facebook::react::managedPointer(json); +} +@end +@implementation RCTCxxConvert (NativeRNFBTurboPerf_HttpMetricData) ++ (RCTManagedPointer *)JS_NativeRNFBTurboPerf_HttpMetricData:(id)json +{ + return facebook::react::managedPointer(json); +} +@end +namespace facebook::react { + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboPerfSpecJSI_setPerformanceCollectionEnabled(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, PromiseKind, "setPerformanceCollectionEnabled", @selector(setPerformanceCollectionEnabled:resolve:reject:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboPerfSpecJSI_instrumentationEnabled(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, PromiseKind, "instrumentationEnabled", @selector(instrumentationEnabled:resolve:reject:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboPerfSpecJSI_startTrace(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, PromiseKind, "startTrace", @selector(startTrace:identifier:resolve:reject:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboPerfSpecJSI_stopTrace(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, PromiseKind, "stopTrace", @selector(stopTrace:traceData:resolve:reject:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboPerfSpecJSI_startScreenTrace(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, PromiseKind, "startScreenTrace", @selector(startScreenTrace:identifier:resolve:reject:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboPerfSpecJSI_stopScreenTrace(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, PromiseKind, "stopScreenTrace", @selector(stopScreenTrace:resolve:reject:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboPerfSpecJSI_startHttpMetric(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, PromiseKind, "startHttpMetric", @selector(startHttpMetric:url:httpMethod:resolve:reject:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboPerfSpecJSI_stopHttpMetric(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, PromiseKind, "stopHttpMetric", @selector(stopHttpMetric:metricData:resolve:reject:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboPerfSpecJSI_getConstants(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, ObjectKind, "getConstants", @selector(getConstants), args, count); + } + + NativeRNFBTurboPerfSpecJSI::NativeRNFBTurboPerfSpecJSI(const ObjCTurboModule::InitParams ¶ms) + : ObjCTurboModule(params) { + + methodMap_["setPerformanceCollectionEnabled"] = MethodMetadata {1, __hostFunction_NativeRNFBTurboPerfSpecJSI_setPerformanceCollectionEnabled}; + + + methodMap_["instrumentationEnabled"] = MethodMetadata {1, __hostFunction_NativeRNFBTurboPerfSpecJSI_instrumentationEnabled}; + + + methodMap_["startTrace"] = MethodMetadata {2, __hostFunction_NativeRNFBTurboPerfSpecJSI_startTrace}; + + + methodMap_["stopTrace"] = MethodMetadata {2, __hostFunction_NativeRNFBTurboPerfSpecJSI_stopTrace}; + setMethodArgConversionSelector(@"stopTrace", 1, @"JS_NativeRNFBTurboPerf_TraceData:"); + + methodMap_["startScreenTrace"] = MethodMetadata {2, __hostFunction_NativeRNFBTurboPerfSpecJSI_startScreenTrace}; + + + methodMap_["stopScreenTrace"] = MethodMetadata {1, __hostFunction_NativeRNFBTurboPerfSpecJSI_stopScreenTrace}; + + + methodMap_["startHttpMetric"] = MethodMetadata {3, __hostFunction_NativeRNFBTurboPerfSpecJSI_startHttpMetric}; + + + methodMap_["stopHttpMetric"] = MethodMetadata {2, __hostFunction_NativeRNFBTurboPerfSpecJSI_stopHttpMetric}; + setMethodArgConversionSelector(@"stopHttpMetric", 1, @"JS_NativeRNFBTurboPerf_HttpMetricData:"); + + methodMap_["getConstants"] = MethodMetadata {0, __hostFunction_NativeRNFBTurboPerfSpecJSI_getConstants}; + + } +} // namespace facebook::react diff --git a/packages/perf/ios/generated/RNFBPerfTurboModules/RNFBPerfTurboModules.h b/packages/perf/ios/generated/RNFBPerfTurboModules/RNFBPerfTurboModules.h new file mode 100644 index 0000000000..4588ce1381 --- /dev/null +++ b/packages/perf/ios/generated/RNFBPerfTurboModules/RNFBPerfTurboModules.h @@ -0,0 +1,200 @@ +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleObjCpp + * + * We create an umbrella header (and corresponding implementation) here since + * Cxx compilation in BUCK has a limitation: source-code producing genrule()s + * must have a single output. More files => more genrule()s => slower builds. + */ + +#ifndef __cplusplus +#error This file must be compiled as Obj-C++. If you are importing it, you must change your file extension to .mm. +#endif + +// Avoid multiple includes of RNFBPerfTurboModules symbols +#ifndef RNFBPerfTurboModules_H +#define RNFBPerfTurboModules_H + +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import + + +NS_ASSUME_NONNULL_BEGIN +namespace JS { + namespace NativeRNFBTurboPerf { + struct TraceData { + id metrics() const; + id attributes() const; + + TraceData(NSDictionary *const v) : _v(v) {} + private: + NSDictionary *_v; + }; + } +} + +@interface RCTCxxConvert (NativeRNFBTurboPerf_TraceData) ++ (RCTManagedPointer *)JS_NativeRNFBTurboPerf_TraceData:(id)json; +@end +namespace JS { + namespace NativeRNFBTurboPerf { + struct HttpMetricData { + id attributes() const; + std::optional httpResponseCode() const; + std::optional requestPayloadSize() const; + std::optional responsePayloadSize() const; + NSString *responseContentType() const; + + HttpMetricData(NSDictionary *const v) : _v(v) {} + private: + NSDictionary *_v; + }; + } +} + +@interface RCTCxxConvert (NativeRNFBTurboPerf_HttpMetricData) ++ (RCTManagedPointer *)JS_NativeRNFBTurboPerf_HttpMetricData:(id)json; +@end +namespace JS { + namespace NativeRNFBTurboPerf { + struct Constants { + + struct Builder { + struct Input { + RCTRequired isPerformanceCollectionEnabled; + RCTRequired isInstrumentationEnabled; + }; + + /** Initialize with a set of values */ + Builder(const Input i); + /** Initialize with an existing Constants */ + Builder(Constants i); + /** Builds the object. Generally used only by the infrastructure. */ + NSDictionary *buildUnsafeRawValue() const { return _factory(); }; + private: + NSDictionary *(^_factory)(void); + }; + + static Constants fromUnsafeRawValue(NSDictionary *const v) { return {v}; } + NSDictionary *unsafeRawValue() const { return _v; } + private: + Constants(NSDictionary *const v) : _v(v) {} + NSDictionary *_v; + }; + } +} +@protocol NativeRNFBTurboPerfSpec + +- (void)setPerformanceCollectionEnabled:(BOOL)enabled + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; +- (void)instrumentationEnabled:(BOOL)enabled + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; +- (void)startTrace:(double)id + identifier:(NSString *)identifier + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; +- (void)stopTrace:(double)id + traceData:(JS::NativeRNFBTurboPerf::TraceData &)traceData + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; +- (void)startScreenTrace:(double)id + identifier:(NSString *)identifier + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; +- (void)stopScreenTrace:(double)id + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; +- (void)startHttpMetric:(double)id + url:(NSString *)url + httpMethod:(NSString *)httpMethod + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; +- (void)stopHttpMetric:(double)id + metricData:(JS::NativeRNFBTurboPerf::HttpMetricData &)metricData + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; +- (facebook::react::ModuleConstants)constantsToExport; +- (facebook::react::ModuleConstants)getConstants; + +@end + +@interface NativeRNFBTurboPerfSpecBase : NSObject { +@protected +facebook::react::EventEmitterCallback _eventEmitterCallback; +} +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper; + + +@end + +namespace facebook::react { + /** + * ObjC++ class for module 'NativeRNFBTurboPerf' + */ + class JSI_EXPORT NativeRNFBTurboPerfSpecJSI : public ObjCTurboModule { + public: + NativeRNFBTurboPerfSpecJSI(const ObjCTurboModule::InitParams ¶ms); + }; +} // namespace facebook::react +inline id JS::NativeRNFBTurboPerf::TraceData::metrics() const +{ + id const p = _v[@"metrics"]; + return p; +} +inline id JS::NativeRNFBTurboPerf::TraceData::attributes() const +{ + id const p = _v[@"attributes"]; + return p; +} +inline id JS::NativeRNFBTurboPerf::HttpMetricData::attributes() const +{ + id const p = _v[@"attributes"]; + return p; +} +inline std::optional JS::NativeRNFBTurboPerf::HttpMetricData::httpResponseCode() const +{ + id const p = _v[@"httpResponseCode"]; + return RCTBridgingToOptionalDouble(p); +} +inline std::optional JS::NativeRNFBTurboPerf::HttpMetricData::requestPayloadSize() const +{ + id const p = _v[@"requestPayloadSize"]; + return RCTBridgingToOptionalDouble(p); +} +inline std::optional JS::NativeRNFBTurboPerf::HttpMetricData::responsePayloadSize() const +{ + id const p = _v[@"responsePayloadSize"]; + return RCTBridgingToOptionalDouble(p); +} +inline NSString *JS::NativeRNFBTurboPerf::HttpMetricData::responseContentType() const +{ + id const p = _v[@"responseContentType"]; + return RCTBridgingToOptionalString(p); +} +inline JS::NativeRNFBTurboPerf::Constants::Builder::Builder(const Input i) : _factory(^{ + NSMutableDictionary *d = [NSMutableDictionary new]; + auto isPerformanceCollectionEnabled = i.isPerformanceCollectionEnabled.get(); + d[@"isPerformanceCollectionEnabled"] = @(isPerformanceCollectionEnabled); + auto isInstrumentationEnabled = i.isInstrumentationEnabled.get(); + d[@"isInstrumentationEnabled"] = @(isInstrumentationEnabled); + return d; +}) {} +inline JS::NativeRNFBTurboPerf::Constants::Builder::Builder(Constants i) : _factory(^{ + return i.unsafeRawValue(); +}) {} +NS_ASSUME_NONNULL_END +#endif // RNFBPerfTurboModules_H diff --git a/packages/perf/ios/generated/RNFBPerfTurboModulesJSI-generated.cpp b/packages/perf/ios/generated/RNFBPerfTurboModulesJSI-generated.cpp new file mode 100644 index 0000000000..43dc7a037d --- /dev/null +++ b/packages/perf/ios/generated/RNFBPerfTurboModulesJSI-generated.cpp @@ -0,0 +1,88 @@ +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleCpp.js + */ + +#include "RNFBPerfTurboModulesJSI.h" + +namespace facebook::react { + +static jsi::Value __hostFunction_NativeRNFBTurboPerfCxxSpecJSI_getConstants(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getConstants( + rt + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboPerfCxxSpecJSI_setPerformanceCollectionEnabled(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->setPerformanceCollectionEnabled( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asBool() + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboPerfCxxSpecJSI_instrumentationEnabled(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->instrumentationEnabled( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asBool() + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboPerfCxxSpecJSI_startTrace(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->startTrace( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asNumber(), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt) + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboPerfCxxSpecJSI_stopTrace(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->stopTrace( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asNumber(), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asObject(rt) + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboPerfCxxSpecJSI_startScreenTrace(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->startScreenTrace( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asNumber(), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt) + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboPerfCxxSpecJSI_stopScreenTrace(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->stopScreenTrace( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asNumber() + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboPerfCxxSpecJSI_startHttpMetric(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->startHttpMetric( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asNumber(), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt), + count <= 2 ? throw jsi::JSError(rt, "Expected argument in position 2 to be passed") : args[2].asString(rt) + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboPerfCxxSpecJSI_stopHttpMetric(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->stopHttpMetric( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asNumber(), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asObject(rt) + ); +} + +NativeRNFBTurboPerfCxxSpecJSI::NativeRNFBTurboPerfCxxSpecJSI(std::shared_ptr jsInvoker) + : TurboModule("NativeRNFBTurboPerf", jsInvoker) { + methodMap_["getConstants"] = MethodMetadata {0, __hostFunction_NativeRNFBTurboPerfCxxSpecJSI_getConstants}; + methodMap_["setPerformanceCollectionEnabled"] = MethodMetadata {1, __hostFunction_NativeRNFBTurboPerfCxxSpecJSI_setPerformanceCollectionEnabled}; + methodMap_["instrumentationEnabled"] = MethodMetadata {1, __hostFunction_NativeRNFBTurboPerfCxxSpecJSI_instrumentationEnabled}; + methodMap_["startTrace"] = MethodMetadata {2, __hostFunction_NativeRNFBTurboPerfCxxSpecJSI_startTrace}; + methodMap_["stopTrace"] = MethodMetadata {2, __hostFunction_NativeRNFBTurboPerfCxxSpecJSI_stopTrace}; + methodMap_["startScreenTrace"] = MethodMetadata {2, __hostFunction_NativeRNFBTurboPerfCxxSpecJSI_startScreenTrace}; + methodMap_["stopScreenTrace"] = MethodMetadata {1, __hostFunction_NativeRNFBTurboPerfCxxSpecJSI_stopScreenTrace}; + methodMap_["startHttpMetric"] = MethodMetadata {3, __hostFunction_NativeRNFBTurboPerfCxxSpecJSI_startHttpMetric}; + methodMap_["stopHttpMetric"] = MethodMetadata {2, __hostFunction_NativeRNFBTurboPerfCxxSpecJSI_stopHttpMetric}; +} + + +} // namespace facebook::react diff --git a/packages/perf/ios/generated/RNFBPerfTurboModulesJSI.h b/packages/perf/ios/generated/RNFBPerfTurboModulesJSI.h new file mode 100644 index 0000000000..a2762fc32e --- /dev/null +++ b/packages/perf/ios/generated/RNFBPerfTurboModulesJSI.h @@ -0,0 +1,267 @@ +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleH.js + */ + +#pragma once + +#include +#include + +namespace facebook::react { + + + +#pragma mark - NativeRNFBTurboPerfHttpMetricData + +template +struct NativeRNFBTurboPerfHttpMetricData { + P0 attributes; + P1 httpResponseCode; + P2 requestPayloadSize; + P3 responsePayloadSize; + P4 responseContentType; + bool operator==(const NativeRNFBTurboPerfHttpMetricData &other) const { + return attributes == other.attributes && httpResponseCode == other.httpResponseCode && requestPayloadSize == other.requestPayloadSize && responsePayloadSize == other.responsePayloadSize && responseContentType == other.responseContentType; + } +}; + +template +struct NativeRNFBTurboPerfHttpMetricDataBridging { + static T types; + + static T fromJs( + jsi::Runtime &rt, + const jsi::Object &value, + const std::shared_ptr &jsInvoker) { + T result{ + bridging::fromJs(rt, value.getProperty(rt, "attributes"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, "httpResponseCode"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, "requestPayloadSize"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, "responsePayloadSize"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, "responseContentType"), jsInvoker)}; + return result; + } + +#ifdef DEBUG + static jsi::Object attributesToJs(jsi::Runtime &rt, decltype(types.attributes) value) { + return bridging::toJs(rt, value); + } + + static double httpResponseCodeToJs(jsi::Runtime &rt, decltype(types.httpResponseCode) value) { + return bridging::toJs(rt, value); + } + + static double requestPayloadSizeToJs(jsi::Runtime &rt, decltype(types.requestPayloadSize) value) { + return bridging::toJs(rt, value); + } + + static double responsePayloadSizeToJs(jsi::Runtime &rt, decltype(types.responsePayloadSize) value) { + return bridging::toJs(rt, value); + } + + static jsi::String responseContentTypeToJs(jsi::Runtime &rt, decltype(types.responseContentType) value) { + return bridging::toJs(rt, value); + } +#endif + + static jsi::Object toJs( + jsi::Runtime &rt, + const T &value, + const std::shared_ptr &jsInvoker) { + auto result = facebook::jsi::Object(rt); + result.setProperty(rt, "attributes", bridging::toJs(rt, value.attributes, jsInvoker)); + if (value.httpResponseCode) { + result.setProperty(rt, "httpResponseCode", bridging::toJs(rt, value.httpResponseCode.value(), jsInvoker)); + } + if (value.requestPayloadSize) { + result.setProperty(rt, "requestPayloadSize", bridging::toJs(rt, value.requestPayloadSize.value(), jsInvoker)); + } + if (value.responsePayloadSize) { + result.setProperty(rt, "responsePayloadSize", bridging::toJs(rt, value.responsePayloadSize.value(), jsInvoker)); + } + if (value.responseContentType) { + result.setProperty(rt, "responseContentType", bridging::toJs(rt, value.responseContentType.value(), jsInvoker)); + } + return result; + } +}; + + + +#pragma mark - NativeRNFBTurboPerfTraceData + +template +struct NativeRNFBTurboPerfTraceData { + P0 metrics; + P1 attributes; + bool operator==(const NativeRNFBTurboPerfTraceData &other) const { + return metrics == other.metrics && attributes == other.attributes; + } +}; + +template +struct NativeRNFBTurboPerfTraceDataBridging { + static T types; + + static T fromJs( + jsi::Runtime &rt, + const jsi::Object &value, + const std::shared_ptr &jsInvoker) { + T result{ + bridging::fromJs(rt, value.getProperty(rt, "metrics"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, "attributes"), jsInvoker)}; + return result; + } + +#ifdef DEBUG + static jsi::Object metricsToJs(jsi::Runtime &rt, decltype(types.metrics) value) { + return bridging::toJs(rt, value); + } + + static jsi::Object attributesToJs(jsi::Runtime &rt, decltype(types.attributes) value) { + return bridging::toJs(rt, value); + } +#endif + + static jsi::Object toJs( + jsi::Runtime &rt, + const T &value, + const std::shared_ptr &jsInvoker) { + auto result = facebook::jsi::Object(rt); + result.setProperty(rt, "metrics", bridging::toJs(rt, value.metrics, jsInvoker)); + result.setProperty(rt, "attributes", bridging::toJs(rt, value.attributes, jsInvoker)); + return result; + } +}; + +class JSI_EXPORT NativeRNFBTurboPerfCxxSpecJSI : public TurboModule { +protected: + NativeRNFBTurboPerfCxxSpecJSI(std::shared_ptr jsInvoker); + +public: + virtual jsi::Object getConstants(jsi::Runtime &rt) = 0; + virtual jsi::Value setPerformanceCollectionEnabled(jsi::Runtime &rt, bool enabled) = 0; + virtual jsi::Value instrumentationEnabled(jsi::Runtime &rt, bool enabled) = 0; + virtual jsi::Value startTrace(jsi::Runtime &rt, double id, jsi::String identifier) = 0; + virtual jsi::Value stopTrace(jsi::Runtime &rt, double id, jsi::Object traceData) = 0; + virtual jsi::Value startScreenTrace(jsi::Runtime &rt, double id, jsi::String identifier) = 0; + virtual jsi::Value stopScreenTrace(jsi::Runtime &rt, double id) = 0; + virtual jsi::Value startHttpMetric(jsi::Runtime &rt, double id, jsi::String url, jsi::String httpMethod) = 0; + virtual jsi::Value stopHttpMetric(jsi::Runtime &rt, double id, jsi::Object metricData) = 0; + +}; + +template +class JSI_EXPORT NativeRNFBTurboPerfCxxSpec : public TurboModule { +public: + jsi::Value create(jsi::Runtime &rt, const jsi::PropNameID &propName) override { + return delegate_.create(rt, propName); + } + + std::vector getPropertyNames(jsi::Runtime& runtime) override { + return delegate_.getPropertyNames(runtime); + } + + static constexpr std::string_view kModuleName = "NativeRNFBTurboPerf"; + +protected: + NativeRNFBTurboPerfCxxSpec(std::shared_ptr jsInvoker) + : TurboModule(std::string{NativeRNFBTurboPerfCxxSpec::kModuleName}, jsInvoker), + delegate_(reinterpret_cast(this), jsInvoker) {} + + +private: + class Delegate : public NativeRNFBTurboPerfCxxSpecJSI { + public: + Delegate(T *instance, std::shared_ptr jsInvoker) : + NativeRNFBTurboPerfCxxSpecJSI(std::move(jsInvoker)), instance_(instance) { + + } + + jsi::Object getConstants(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::getConstants) == 1, + "Expected getConstants(...) to have 1 parameters"); + + return bridging::callFromJs( + rt, &T::getConstants, jsInvoker_, instance_); + } + jsi::Value setPerformanceCollectionEnabled(jsi::Runtime &rt, bool enabled) override { + static_assert( + bridging::getParameterCount(&T::setPerformanceCollectionEnabled) == 2, + "Expected setPerformanceCollectionEnabled(...) to have 2 parameters"); + + return bridging::callFromJs( + rt, &T::setPerformanceCollectionEnabled, jsInvoker_, instance_, std::move(enabled)); + } + jsi::Value instrumentationEnabled(jsi::Runtime &rt, bool enabled) override { + static_assert( + bridging::getParameterCount(&T::instrumentationEnabled) == 2, + "Expected instrumentationEnabled(...) to have 2 parameters"); + + return bridging::callFromJs( + rt, &T::instrumentationEnabled, jsInvoker_, instance_, std::move(enabled)); + } + jsi::Value startTrace(jsi::Runtime &rt, double id, jsi::String identifier) override { + static_assert( + bridging::getParameterCount(&T::startTrace) == 3, + "Expected startTrace(...) to have 3 parameters"); + + return bridging::callFromJs( + rt, &T::startTrace, jsInvoker_, instance_, std::move(id), std::move(identifier)); + } + jsi::Value stopTrace(jsi::Runtime &rt, double id, jsi::Object traceData) override { + static_assert( + bridging::getParameterCount(&T::stopTrace) == 3, + "Expected stopTrace(...) to have 3 parameters"); + + return bridging::callFromJs( + rt, &T::stopTrace, jsInvoker_, instance_, std::move(id), std::move(traceData)); + } + jsi::Value startScreenTrace(jsi::Runtime &rt, double id, jsi::String identifier) override { + static_assert( + bridging::getParameterCount(&T::startScreenTrace) == 3, + "Expected startScreenTrace(...) to have 3 parameters"); + + return bridging::callFromJs( + rt, &T::startScreenTrace, jsInvoker_, instance_, std::move(id), std::move(identifier)); + } + jsi::Value stopScreenTrace(jsi::Runtime &rt, double id) override { + static_assert( + bridging::getParameterCount(&T::stopScreenTrace) == 2, + "Expected stopScreenTrace(...) to have 2 parameters"); + + return bridging::callFromJs( + rt, &T::stopScreenTrace, jsInvoker_, instance_, std::move(id)); + } + jsi::Value startHttpMetric(jsi::Runtime &rt, double id, jsi::String url, jsi::String httpMethod) override { + static_assert( + bridging::getParameterCount(&T::startHttpMetric) == 4, + "Expected startHttpMetric(...) to have 4 parameters"); + + return bridging::callFromJs( + rt, &T::startHttpMetric, jsInvoker_, instance_, std::move(id), std::move(url), std::move(httpMethod)); + } + jsi::Value stopHttpMetric(jsi::Runtime &rt, double id, jsi::Object metricData) override { + static_assert( + bridging::getParameterCount(&T::stopHttpMetric) == 3, + "Expected stopHttpMetric(...) to have 3 parameters"); + + return bridging::callFromJs( + rt, &T::stopHttpMetric, jsInvoker_, instance_, std::move(id), std::move(metricData)); + } + + private: + friend class NativeRNFBTurboPerfCxxSpec; + T *instance_; + }; + + Delegate delegate_; +}; + +} // namespace facebook::react diff --git a/packages/perf/lib/index.ts b/packages/perf/lib/index.ts index c6b300ef6d..d505d879a8 100644 --- a/packages/perf/lib/index.ts +++ b/packages/perf/lib/index.ts @@ -41,7 +41,7 @@ import type { } from './types/perf'; import type { PerfInternal } from './types/internal'; -const nativeModuleName = 'RNFBPerfModule' as const; +const nativeModuleName = 'NativeRNFBTurboPerf' as const; const VALID_HTTP_METHODS: HttpMethod[] = [ 'CONNECT', @@ -174,6 +174,7 @@ const config: ModuleConfig = { nativeEvents: false, hasMultiAppSupport: false, hasCustomUrlOrRegionSupport: false, + turboModule: true, }; export const SDK_VERSION = version; diff --git a/packages/perf/lib/types/internal.ts b/packages/perf/lib/types/internal.ts index 31e074c472..4575b60f36 100644 --- a/packages/perf/lib/types/internal.ts +++ b/packages/perf/lib/types/internal.ts @@ -63,6 +63,6 @@ export interface RNFBPerfNativeModule { declare module '@react-native-firebase/app/dist/module/internal/NativeModules' { interface ReactNativeFirebaseNativeModules { - RNFBPerfModule: RNFBPerfNativeModule; + NativeRNFBTurboPerf: RNFBPerfNativeModule; } } diff --git a/packages/perf/package.json b/packages/perf/package.json index 48d32cdb84..9d3d85c6e7 100644 --- a/packages/perf/package.json +++ b/packages/perf/package.json @@ -5,13 +5,30 @@ "description": "React Native Firebase - React Native Firebase provides native integration with Performance Monitoring to gain insight into key performance characteristics within your React Native application.", "main": "./dist/module/index.js", "types": "./dist/typescript/lib/index.d.ts", + "codegenConfig": { + "name": "RNFBPerfTurboModules", + "type": "modules", + "jsSrcsDir": "specs", + "includesGeneratedCode": true, + "android": { + "javaPackageName": "io.invertase.firebase.perf" + }, + "ios": { + "modulesProvider": { + "NativeRNFBTurboPerf": "RNFBPerfModule" + } + } + }, "scripts": { "build": "genversion --esm --semi lib/version.ts", "build:clean": "rimraf android/build && rimraf ios/build", "build:plugin": "rimraf plugin/build && tsc --build plugin", "compile": "bob build", "lint:plugin": "eslint plugin/src/*", - "prepare": "yarn run build && yarn compile && yarn run build:plugin" + "prepare": "yarn run build && yarn compile && yarn run build:plugin", + "codegen": "yarn android:codegen && yarn ios:codegen", + "android:codegen": "npx @react-native-community/cli codegen --platform android --outputPath=./android/src/reactnative/java/io/invertase/firebase/perf/generated", + "ios:codegen": "npx @react-native-community/cli codegen --platform ios --outputPath=./ios/generated" }, "repository": { "type": "git", diff --git a/packages/perf/react-native.config.js b/packages/perf/react-native.config.js new file mode 100644 index 0000000000..cfaf853f3d --- /dev/null +++ b/packages/perf/react-native.config.js @@ -0,0 +1,10 @@ +module.exports = { + dependency: { + platforms: { + android: { + cmakeListsPath: + './src/reactnative/java/io/invertase/firebase/perf/generated/jni/CMakeLists.txt', + }, + }, + }, +}; diff --git a/packages/perf/specs/NativeRNFBTurboPerf.ts b/packages/perf/specs/NativeRNFBTurboPerf.ts new file mode 100644 index 0000000000..c14298c299 --- /dev/null +++ b/packages/perf/specs/NativeRNFBTurboPerf.ts @@ -0,0 +1,44 @@ +import type { TurboModule } from 'react-native'; +import { TurboModuleRegistry } from 'react-native'; + +export type HttpMethod = + | 'CONNECT' + | 'DELETE' + | 'GET' + | 'HEAD' + | 'OPTIONS' + | 'PATCH' + | 'POST' + | 'PUT' + | 'TRACE'; + +export interface TraceData { + metrics: { [key: string]: number }; + attributes: { [key: string]: string }; +} + +export interface HttpMetricData { + attributes: { [key: string]: string }; + httpResponseCode?: number; + requestPayloadSize?: number; + responsePayloadSize?: number; + responseContentType?: string; +} + +export interface Spec extends TurboModule { + getConstants(): { + isPerformanceCollectionEnabled: boolean; + isInstrumentationEnabled: boolean; + }; + + setPerformanceCollectionEnabled(enabled: boolean): Promise; + instrumentationEnabled(enabled: boolean): Promise; + startTrace(id: number, identifier: string): Promise; + stopTrace(id: number, traceData: TraceData): Promise; + startScreenTrace(id: number, identifier: string): Promise; + stopScreenTrace(id: number): Promise; + startHttpMetric(id: number, url: string, httpMethod: HttpMethod): Promise; + stopHttpMetric(id: number, metricData: HttpMetricData): Promise; +} + +export default TurboModuleRegistry.getEnforcing('NativeRNFBTurboPerf'); From 7fbca8c38469460d24948356699fbd2cdc5593cc Mon Sep 17 00:00:00 2001 From: Mike Hardy Date: Wed, 1 Jul 2026 07:06:10 -0500 Subject: [PATCH 08/10] feat(in-app-messaging)!: migrate in-app-messaging to TurboModules --- .../new-architecture/migration-work-queue.md | 4 +- .../RNFBInAppMessaging.podspec | 13 ++- .../__tests__/nativeModuleContract.test.ts | 75 ++++++++++++ .../in-app-messaging/android/build.gradle | 19 +++ .../firebase/fiam/NativeRNFBTurboFiam.java | 80 +++++++++++++ .../fiam/ReactNativeFirebaseFiamPackage.java | 2 +- .../specs/NativeRNFBTurboFiamSpec.java | 79 +++++++++++++ .../fiam/generated/jni/CMakeLists.txt | 36 ++++++ ...FBInAppMessagingTurboModules-generated.cpp | 50 ++++++++ .../jni/RNFBInAppMessagingTurboModules.h | 31 +++++ ...nAppMessagingTurboModulesJSI-generated.cpp | 47 ++++++++ .../RNFBInAppMessagingTurboModulesJSI.h | 98 ++++++++++++++++ .../ios/RNFBFiam.xcodeproj/project.pbxproj | 8 +- .../ios/RNFBFiam/RNFBFiamModule.h | 5 +- .../{RNFBFiamModule.m => RNFBFiamModule.mm} | 46 ++++---- ...NFBInAppMessagingTurboModules-generated.mm | 60 ++++++++++ .../RNFBInAppMessagingTurboModules.h | 109 ++++++++++++++++++ ...nAppMessagingTurboModulesJSI-generated.cpp | 47 ++++++++ .../RNFBInAppMessagingTurboModulesJSI.h | 98 ++++++++++++++++ packages/in-app-messaging/lib/index.ts | 3 +- .../in-app-messaging/lib/types/internal.ts | 2 +- packages/in-app-messaging/package.json | 19 ++- .../in-app-messaging/react-native.config.js | 10 ++ .../specs/NativeRNFBTurboFiam.ts | 15 +++ 24 files changed, 916 insertions(+), 40 deletions(-) create mode 100644 packages/in-app-messaging/__tests__/nativeModuleContract.test.ts create mode 100644 packages/in-app-messaging/android/src/reactnative/java/io/invertase/firebase/fiam/NativeRNFBTurboFiam.java create mode 100644 packages/in-app-messaging/android/src/reactnative/java/io/invertase/firebase/fiam/generated/java/com/facebook/fbreact/specs/NativeRNFBTurboFiamSpec.java create mode 100644 packages/in-app-messaging/android/src/reactnative/java/io/invertase/firebase/fiam/generated/jni/CMakeLists.txt create mode 100644 packages/in-app-messaging/android/src/reactnative/java/io/invertase/firebase/fiam/generated/jni/RNFBInAppMessagingTurboModules-generated.cpp create mode 100644 packages/in-app-messaging/android/src/reactnative/java/io/invertase/firebase/fiam/generated/jni/RNFBInAppMessagingTurboModules.h create mode 100644 packages/in-app-messaging/android/src/reactnative/java/io/invertase/firebase/fiam/generated/jni/react/renderer/components/RNFBInAppMessagingTurboModules/RNFBInAppMessagingTurboModulesJSI-generated.cpp create mode 100644 packages/in-app-messaging/android/src/reactnative/java/io/invertase/firebase/fiam/generated/jni/react/renderer/components/RNFBInAppMessagingTurboModules/RNFBInAppMessagingTurboModulesJSI.h rename packages/in-app-messaging/ios/RNFBFiam/{RNFBFiamModule.m => RNFBFiamModule.mm} (56%) create mode 100644 packages/in-app-messaging/ios/generated/RNFBInAppMessagingTurboModules/RNFBInAppMessagingTurboModules-generated.mm create mode 100644 packages/in-app-messaging/ios/generated/RNFBInAppMessagingTurboModules/RNFBInAppMessagingTurboModules.h create mode 100644 packages/in-app-messaging/ios/generated/RNFBInAppMessagingTurboModulesJSI-generated.cpp create mode 100644 packages/in-app-messaging/ios/generated/RNFBInAppMessagingTurboModulesJSI.h create mode 100644 packages/in-app-messaging/react-native.config.js create mode 100644 packages/in-app-messaging/specs/NativeRNFBTurboFiam.ts diff --git a/okf-bundle/new-architecture/migration-work-queue.md b/okf-bundle/new-architecture/migration-work-queue.md index 880173e52a..3c6ef83f37 100644 --- a/okf-bundle/new-architecture/migration-work-queue.md +++ b/okf-bundle/new-architecture/migration-work-queue.md @@ -8,7 +8,7 @@ timestamp: 2026-06-26T00:00:00Z # TurboModule migration — work queue -> **IN PROGRESS (2026-06-30):** Phase **2** — committing P2b `perf`. +> **IN PROGRESS (2026-06-30):** Phase **2** — committing P2c `in-app-messaging`. > **Goal/order:** app foundation → hard probe → easy wins → remaining complex → sync conversion → coordinated break → cleanup (events, shared-state encapsulation). Decisions: [architecture-decisions.md](architecture-decisions.md). Links: [implementation workflow](turbomodule-implementation-workflow.md), [change authoring](../testing/change-authoring-workflow.md), [functions reference](../../../packages/functions/) ([PR #8603](https://github.com/invertase/react-native-firebase/pull/8603)). Ephemeral tracker; see [OKF policy](../documentation-policy.md). @@ -283,7 +283,7 @@ Skip steps 1–2 when spec shape is known (most Tier D packages). | Phase 0.1 `app` compare:types | P0.1 | **closed** | **closed** | **closed** | done | `none` | `test(app): add app module type comparison config` | Committed 2026-06-30. | | Phase 1 `firestore` TurboModules | P1 | **closed** | **closed** | **closed** | done | `area-focused` | `feat(firestore)!: migrate firestore to TurboModules` | Committed 2026-06-30. | | Phase 2 `installations` | P2a | **closed** | **closed** | **closed** | done | `area-focused` | `feat(installations)!: migrate installations to TurboModules` | Committed 2026-06-30. Remediation: iOS `invalidate` no-op. | -| Phase 2 `perf` | P2b | **closed** | **closed** | **open** | `commit` | `area-focused` | `feat(perf)!: migrate perf to TurboModules` | Review green 2026-06-30. Deferred: dead legacy Java shell; `xdescribe` pending; vacuous iOS screenTrace e2e. | +| Phase 2 `perf` | P2b | **closed** | **closed** | **closed** | done | `area-focused` | `feat(perf)!: migrate perf to TurboModules` | Committed 2026-06-30. | | Phase 2 `in-app-messaging` | P2c | **closed** | **closed** | **open** | `commit` | `area-focused` | `feat(in-app-messaging)!: migrate in-app-messaging to TurboModules` | Review green 2026-06-30. Deferred: dead legacy Java; stale JSDoc; 3 xdescribe pending. | | Phase 2 `app-distribution` | P2d | **closed** | **closed** | **open** | `commit` | `area-focused` | `feat(app-distribution)!: migrate app-distribution to TurboModules` | Review green 2026-06-30: Android 1 pass + 4 pending; iOS 3 pass + 2 pending. Duplicate codegen + legacy Java removed. | | Phase 2 `ml` | P2e | **closed** | **closed** | **open** | `commit` | `area-focused` | `feat(ml)!: migrate ml to TurboModules` | Review green 2026-06-30: 1 pass Android + iOS. Stub module. | diff --git a/packages/in-app-messaging/RNFBInAppMessaging.podspec b/packages/in-app-messaging/RNFBInAppMessaging.podspec index aa72f52e42..913a93afa0 100644 --- a/packages/in-app-messaging/RNFBInAppMessaging.podspec +++ b/packages/in-app-messaging/RNFBInAppMessaging.podspec @@ -28,15 +28,16 @@ Pod::Spec.new do |s| s.ios.deployment_target = firebase_ios_target s.macos.deployment_target = firebase_macos_target s.tvos.deployment_target = firebase_tvos_target - s.source_files = 'ios/**/*.{h,m}' + s.source_files = 'ios/**/*.{h,m,mm,cpp,swift}' + s.private_header_files = "ios/**/*.h" + s.exclude_files = 'ios/generated/RCTThirdPartyComponentsProvider.*', 'ios/generated/RCTAppDependencyProvider.*', 'ios/generated/RCTModuleProviders.*', 'ios/generated/RCTModulesConformingToProtocolsProvider.*', 'ios/generated/RCTUnstableModulesRequiringMainQueueSetupProvider.*' s.dependency 'RNFBApp' - # React Native dependencies - if defined?(install_modules_dependencies()) != nil - install_modules_dependencies(s); - else - s.dependency "React-Core" + install_modules_dependencies(s); + + if defined?(ENV["RCT_NEW_ARCH_ENABLED"]) != nil && (ENV["RCT_NEW_ARCH_ENABLED"] == '0') + raise "#{s.name} requires New Architecture. Enable New Architecture to use this module" end if defined?($FirebaseSDKVersion) diff --git a/packages/in-app-messaging/__tests__/nativeModuleContract.test.ts b/packages/in-app-messaging/__tests__/nativeModuleContract.test.ts new file mode 100644 index 0000000000..f87889bfaf --- /dev/null +++ b/packages/in-app-messaging/__tests__/nativeModuleContract.test.ts @@ -0,0 +1,75 @@ +import { describe, expect, it, jest } from '@jest/globals'; +import { TurboModuleRegistry } from 'react-native'; +import type { ModuleConfig } from '@react-native-firebase/app/dist/module/internal'; +import FirebaseModule from '@react-native-firebase/app/dist/module/internal/FirebaseModule'; +import { getNativeModule } from '@react-native-firebase/app/dist/module/internal/registry/nativeModule'; +import type { WrappedNativeModule } from '@react-native-firebase/app/dist/module/internal/NativeModules'; + +const SPEC_METHODS = [ + 'setAutomaticDataCollectionEnabled', + 'setMessagesDisplaySuppressed', + 'triggerEvent', +] as const; + +function createTurboModuleFixture( + methods: Record, + constants: Record = {}, +): Record { + const proto = Object.create(Object.prototype, { + getConstants: { + value: () => constants, + enumerable: true, + }, + }); + + for (const [name, fn] of Object.entries(methods)) { + Object.defineProperty(proto, name, { + value: fn, + enumerable: true, + configurable: true, + }); + } + + return Object.create(proto); +} + +describe('TurboModule wrapper contract (NewArch-AD-17.1)', function () { + it('exposes every spec method callable through the real wrapper', function () { + const mocks = Object.fromEntries( + SPEC_METHODS.map(method => [method, jest.fn(() => Promise.resolve(null))]), + ) as Record; + + const raw = createTurboModuleFixture(mocks, { + isMessagesDisplaySuppressed: false, + isAutomaticDataCollectionEnabled: true, + }); + jest.mocked(TurboModuleRegistry.get).mockReturnValueOnce(raw); + + const config: ModuleConfig = { + namespace: 'inAppMessaging', + nativeModuleName: 'NativeRNFBTurboFiam', + nativeEvents: false, + hasMultiAppSupport: false, + hasCustomUrlOrRegionSupport: false, + turboModule: true, + }; + + class ContractModule extends FirebaseModule { + constructor() { + super({ name: '[DEFAULT]' } as any, config); + } + } + + const wrapped = getNativeModule(new ContractModule()) as WrappedNativeModule & + Record<(typeof SPEC_METHODS)[number], () => Promise>; + + for (const method of SPEC_METHODS) { + void wrapped[method](); + expect(mocks[method]).toHaveBeenCalledTimes(1); + expect(Object.keys(wrapped)).toContain(method); + } + + expect(wrapped.isMessagesDisplaySuppressed).toBe(false); + expect(wrapped.isAutomaticDataCollectionEnabled).toBe(true); + }); +}); diff --git a/packages/in-app-messaging/android/build.gradle b/packages/in-app-messaging/android/build.gradle index 03f5af014c..e00af98778 100644 --- a/packages/in-app-messaging/android/build.gradle +++ b/packages/in-app-messaging/android/build.gradle @@ -112,6 +112,7 @@ android { sourceSets { main { java.srcDirs = ['src/main/java', 'src/reactnative/java'] + java.excludes = ['**/generated/jni/**'] } } } @@ -131,3 +132,21 @@ ReactNative.shared.applyPackageVersion() ReactNative.shared.applyDefaultExcludes() ReactNative.module.applyAndroidVersions() ReactNative.module.applyReactNativeDependency("api") + +def isNewArchitectureDisabled() { + return project.hasProperty("newArchEnabled") && project.newArchEnabled != "true" +} + +if (isNewArchitectureDisabled()) { + def ANSI_RED = "\u001B[31m"; + def ANSI_RESET = "\u001B[0m"; + + println("\n\n\n") + println(ANSI_RED + "**************************************************************************************************************") + println("\n\n\n") + println("New Architecture support is required for @react-native-firebase/in-app-messaging") + println("\n\n\n") + println("**************************************************************************************************************" + ANSI_RESET) + println("\n\n\n") + System.exit(1) +} diff --git a/packages/in-app-messaging/android/src/reactnative/java/io/invertase/firebase/fiam/NativeRNFBTurboFiam.java b/packages/in-app-messaging/android/src/reactnative/java/io/invertase/firebase/fiam/NativeRNFBTurboFiam.java new file mode 100644 index 0000000000..fe9d9cf80d --- /dev/null +++ b/packages/in-app-messaging/android/src/reactnative/java/io/invertase/firebase/fiam/NativeRNFBTurboFiam.java @@ -0,0 +1,80 @@ +package io.invertase.firebase.fiam; + +/* + * Copyright (c) 2016-present Invertase Limited & Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this library except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import com.facebook.fbreact.specs.NativeRNFBTurboFiamSpec; +import com.facebook.react.bridge.Promise; +import com.facebook.react.bridge.ReactApplicationContext; +import java.util.Map; + +public class NativeRNFBTurboFiam extends NativeRNFBTurboFiamSpec { + private static final String SERVICE_NAME = "Fiam"; + private final UniversalFirebaseFiamModule module; + + public NativeRNFBTurboFiam(ReactApplicationContext reactContext) { + super(reactContext); + module = new UniversalFirebaseFiamModule(reactContext, SERVICE_NAME); + } + + @Override + protected Map getTypedExportedConstants() { + return module.getConstants(); + } + + @Override + public void setAutomaticDataCollectionEnabled(boolean enabled, Promise promise) { + module + .setAutomaticDataCollectionEnabled(enabled) + .addOnCompleteListener( + task -> { + if (task.isSuccessful()) { + promise.resolve(task.getResult()); + } else { + promise.reject(task.getException()); + } + }); + } + + @Override + public void setMessagesDisplaySuppressed(boolean enabled, Promise promise) { + module + .setMessagesDisplaySuppressed(enabled) + .addOnCompleteListener( + task -> { + if (task.isSuccessful()) { + promise.resolve(task.getResult()); + } else { + promise.reject(task.getException()); + } + }); + } + + @Override + public void triggerEvent(String eventId, Promise promise) { + module + .triggerEvent(eventId) + .addOnCompleteListener( + task -> { + if (task.isSuccessful()) { + promise.resolve(task.getResult()); + } else { + promise.reject(task.getException()); + } + }); + } +} diff --git a/packages/in-app-messaging/android/src/reactnative/java/io/invertase/firebase/fiam/ReactNativeFirebaseFiamPackage.java b/packages/in-app-messaging/android/src/reactnative/java/io/invertase/firebase/fiam/ReactNativeFirebaseFiamPackage.java index c5ad55c239..248d5ba33a 100644 --- a/packages/in-app-messaging/android/src/reactnative/java/io/invertase/firebase/fiam/ReactNativeFirebaseFiamPackage.java +++ b/packages/in-app-messaging/android/src/reactnative/java/io/invertase/firebase/fiam/ReactNativeFirebaseFiamPackage.java @@ -32,7 +32,7 @@ public class ReactNativeFirebaseFiamPackage implements ReactPackage { @Override public List createNativeModules(@Nonnull ReactApplicationContext reactContext) { List modules = new ArrayList<>(); - modules.add(new ReactNativeFirebaseFiamModule(reactContext)); + modules.add(new NativeRNFBTurboFiam(reactContext)); return modules; } diff --git a/packages/in-app-messaging/android/src/reactnative/java/io/invertase/firebase/fiam/generated/java/com/facebook/fbreact/specs/NativeRNFBTurboFiamSpec.java b/packages/in-app-messaging/android/src/reactnative/java/io/invertase/firebase/fiam/generated/java/com/facebook/fbreact/specs/NativeRNFBTurboFiamSpec.java new file mode 100644 index 0000000000..7db1bf6c6d --- /dev/null +++ b/packages/in-app-messaging/android/src/reactnative/java/io/invertase/firebase/fiam/generated/java/com/facebook/fbreact/specs/NativeRNFBTurboFiamSpec.java @@ -0,0 +1,79 @@ + +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleJavaSpec.js + * + * @nolint + */ + +package com.facebook.fbreact.specs; + +import com.facebook.proguard.annotations.DoNotStrip; +import com.facebook.react.bridge.Promise; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReactContextBaseJavaModule; +import com.facebook.react.bridge.ReactMethod; +import com.facebook.react.common.build.ReactBuildConfig; +import com.facebook.react.turbomodule.core.interfaces.TurboModule; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public abstract class NativeRNFBTurboFiamSpec extends ReactContextBaseJavaModule implements TurboModule { + public static final String NAME = "NativeRNFBTurboFiam"; + + public NativeRNFBTurboFiamSpec(ReactApplicationContext reactContext) { + super(reactContext); + } + + @Override + public @Nonnull String getName() { + return NAME; + } + + protected abstract Map getTypedExportedConstants(); + + @Override + @DoNotStrip + public final @Nullable Map getConstants() { + Map constants = getTypedExportedConstants(); + if (ReactBuildConfig.DEBUG || ReactBuildConfig.IS_INTERNAL_BUILD) { + Set obligatoryFlowConstants = new HashSet<>(Arrays.asList( + "isAutomaticDataCollectionEnabled", + "isMessagesDisplaySuppressed" + )); + Set optionalFlowConstants = new HashSet<>(); + Set undeclaredConstants = new HashSet<>(constants.keySet()); + undeclaredConstants.removeAll(obligatoryFlowConstants); + undeclaredConstants.removeAll(optionalFlowConstants); + if (!undeclaredConstants.isEmpty()) { + throw new IllegalStateException(String.format("Native Module Flow doesn't declare constants: %s", undeclaredConstants)); + } + undeclaredConstants = obligatoryFlowConstants; + undeclaredConstants.removeAll(constants.keySet()); + if (!undeclaredConstants.isEmpty()) { + throw new IllegalStateException(String.format("Native Module doesn't fill in constants: %s", undeclaredConstants)); + } + } + return constants; + } + + @ReactMethod + @DoNotStrip + public abstract void setAutomaticDataCollectionEnabled(boolean enabled, Promise promise); + + @ReactMethod + @DoNotStrip + public abstract void setMessagesDisplaySuppressed(boolean enabled, Promise promise); + + @ReactMethod + @DoNotStrip + public abstract void triggerEvent(String eventId, Promise promise); +} diff --git a/packages/in-app-messaging/android/src/reactnative/java/io/invertase/firebase/fiam/generated/jni/CMakeLists.txt b/packages/in-app-messaging/android/src/reactnative/java/io/invertase/firebase/fiam/generated/jni/CMakeLists.txt new file mode 100644 index 0000000000..7218e1aa93 --- /dev/null +++ b/packages/in-app-messaging/android/src/reactnative/java/io/invertase/firebase/fiam/generated/jni/CMakeLists.txt @@ -0,0 +1,36 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +cmake_minimum_required(VERSION 3.13) +set(CMAKE_VERBOSE_MAKEFILE on) + +file(GLOB react_codegen_SRCS CONFIGURE_DEPENDS *.cpp react/renderer/components/RNFBInAppMessagingTurboModules/*.cpp) + +add_library( + react_codegen_RNFBInAppMessagingTurboModules + OBJECT + ${react_codegen_SRCS} +) + +target_include_directories(react_codegen_RNFBInAppMessagingTurboModules PUBLIC . react/renderer/components/RNFBInAppMessagingTurboModules) + +target_link_libraries( + react_codegen_RNFBInAppMessagingTurboModules + fbjni + jsi + # We need to link different libraries based on whether we are building rncore or not, that's necessary + # because we want to break a circular dependency between react_codegen_rncore and reactnative + reactnative +) + +target_compile_options( + react_codegen_RNFBInAppMessagingTurboModules + PRIVATE + -DLOG_TAG=\"ReactNative\" + -fexceptions + -frtti + -std=c++20 + -Wall +) diff --git a/packages/in-app-messaging/android/src/reactnative/java/io/invertase/firebase/fiam/generated/jni/RNFBInAppMessagingTurboModules-generated.cpp b/packages/in-app-messaging/android/src/reactnative/java/io/invertase/firebase/fiam/generated/jni/RNFBInAppMessagingTurboModules-generated.cpp new file mode 100644 index 0000000000..27956820d3 --- /dev/null +++ b/packages/in-app-messaging/android/src/reactnative/java/io/invertase/firebase/fiam/generated/jni/RNFBInAppMessagingTurboModules-generated.cpp @@ -0,0 +1,50 @@ + +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleJniCpp.js + */ + +#include "RNFBInAppMessagingTurboModules.h" + +namespace facebook::react { + +static facebook::jsi::Value __hostFunction_NativeRNFBTurboFiamSpecJSI_getConstants(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, ObjectKind, "getConstants", "()Ljava/util/Map;", args, count, cachedMethodId); +} + +static facebook::jsi::Value __hostFunction_NativeRNFBTurboFiamSpecJSI_setAutomaticDataCollectionEnabled(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, PromiseKind, "setAutomaticDataCollectionEnabled", "(ZLcom/facebook/react/bridge/Promise;)V", args, count, cachedMethodId); +} + +static facebook::jsi::Value __hostFunction_NativeRNFBTurboFiamSpecJSI_setMessagesDisplaySuppressed(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, PromiseKind, "setMessagesDisplaySuppressed", "(ZLcom/facebook/react/bridge/Promise;)V", args, count, cachedMethodId); +} + +static facebook::jsi::Value __hostFunction_NativeRNFBTurboFiamSpecJSI_triggerEvent(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, PromiseKind, "triggerEvent", "(Ljava/lang/String;Lcom/facebook/react/bridge/Promise;)V", args, count, cachedMethodId); +} + +NativeRNFBTurboFiamSpecJSI::NativeRNFBTurboFiamSpecJSI(const JavaTurboModule::InitParams ¶ms) + : JavaTurboModule(params) { + methodMap_["getConstants"] = MethodMetadata {0, __hostFunction_NativeRNFBTurboFiamSpecJSI_getConstants}; + methodMap_["setAutomaticDataCollectionEnabled"] = MethodMetadata {1, __hostFunction_NativeRNFBTurboFiamSpecJSI_setAutomaticDataCollectionEnabled}; + methodMap_["setMessagesDisplaySuppressed"] = MethodMetadata {1, __hostFunction_NativeRNFBTurboFiamSpecJSI_setMessagesDisplaySuppressed}; + methodMap_["triggerEvent"] = MethodMetadata {1, __hostFunction_NativeRNFBTurboFiamSpecJSI_triggerEvent}; +} + +std::shared_ptr RNFBInAppMessagingTurboModules_ModuleProvider(const std::string &moduleName, const JavaTurboModule::InitParams ¶ms) { + if (moduleName == "NativeRNFBTurboFiam") { + return std::make_shared(params); + } + return nullptr; +} + +} // namespace facebook::react diff --git a/packages/in-app-messaging/android/src/reactnative/java/io/invertase/firebase/fiam/generated/jni/RNFBInAppMessagingTurboModules.h b/packages/in-app-messaging/android/src/reactnative/java/io/invertase/firebase/fiam/generated/jni/RNFBInAppMessagingTurboModules.h new file mode 100644 index 0000000000..bce3c4e93e --- /dev/null +++ b/packages/in-app-messaging/android/src/reactnative/java/io/invertase/firebase/fiam/generated/jni/RNFBInAppMessagingTurboModules.h @@ -0,0 +1,31 @@ + +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleJniH.js + */ + +#pragma once + +#include +#include +#include + +namespace facebook::react { + +/** + * JNI C++ class for module 'NativeRNFBTurboFiam' + */ +class JSI_EXPORT NativeRNFBTurboFiamSpecJSI : public JavaTurboModule { +public: + NativeRNFBTurboFiamSpecJSI(const JavaTurboModule::InitParams ¶ms); +}; + + +JSI_EXPORT +std::shared_ptr RNFBInAppMessagingTurboModules_ModuleProvider(const std::string &moduleName, const JavaTurboModule::InitParams ¶ms); + +} // namespace facebook::react diff --git a/packages/in-app-messaging/android/src/reactnative/java/io/invertase/firebase/fiam/generated/jni/react/renderer/components/RNFBInAppMessagingTurboModules/RNFBInAppMessagingTurboModulesJSI-generated.cpp b/packages/in-app-messaging/android/src/reactnative/java/io/invertase/firebase/fiam/generated/jni/react/renderer/components/RNFBInAppMessagingTurboModules/RNFBInAppMessagingTurboModulesJSI-generated.cpp new file mode 100644 index 0000000000..aaa1d537f3 --- /dev/null +++ b/packages/in-app-messaging/android/src/reactnative/java/io/invertase/firebase/fiam/generated/jni/react/renderer/components/RNFBInAppMessagingTurboModules/RNFBInAppMessagingTurboModulesJSI-generated.cpp @@ -0,0 +1,47 @@ +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleCpp.js + */ + +#include "RNFBInAppMessagingTurboModulesJSI.h" + +namespace facebook::react { + +static jsi::Value __hostFunction_NativeRNFBTurboFiamCxxSpecJSI_getConstants(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getConstants( + rt + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboFiamCxxSpecJSI_setAutomaticDataCollectionEnabled(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->setAutomaticDataCollectionEnabled( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asBool() + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboFiamCxxSpecJSI_setMessagesDisplaySuppressed(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->setMessagesDisplaySuppressed( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asBool() + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboFiamCxxSpecJSI_triggerEvent(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->triggerEvent( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt) + ); +} + +NativeRNFBTurboFiamCxxSpecJSI::NativeRNFBTurboFiamCxxSpecJSI(std::shared_ptr jsInvoker) + : TurboModule("NativeRNFBTurboFiam", jsInvoker) { + methodMap_["getConstants"] = MethodMetadata {0, __hostFunction_NativeRNFBTurboFiamCxxSpecJSI_getConstants}; + methodMap_["setAutomaticDataCollectionEnabled"] = MethodMetadata {1, __hostFunction_NativeRNFBTurboFiamCxxSpecJSI_setAutomaticDataCollectionEnabled}; + methodMap_["setMessagesDisplaySuppressed"] = MethodMetadata {1, __hostFunction_NativeRNFBTurboFiamCxxSpecJSI_setMessagesDisplaySuppressed}; + methodMap_["triggerEvent"] = MethodMetadata {1, __hostFunction_NativeRNFBTurboFiamCxxSpecJSI_triggerEvent}; +} + + +} // namespace facebook::react diff --git a/packages/in-app-messaging/android/src/reactnative/java/io/invertase/firebase/fiam/generated/jni/react/renderer/components/RNFBInAppMessagingTurboModules/RNFBInAppMessagingTurboModulesJSI.h b/packages/in-app-messaging/android/src/reactnative/java/io/invertase/firebase/fiam/generated/jni/react/renderer/components/RNFBInAppMessagingTurboModules/RNFBInAppMessagingTurboModulesJSI.h new file mode 100644 index 0000000000..2e35299e2b --- /dev/null +++ b/packages/in-app-messaging/android/src/reactnative/java/io/invertase/firebase/fiam/generated/jni/react/renderer/components/RNFBInAppMessagingTurboModules/RNFBInAppMessagingTurboModulesJSI.h @@ -0,0 +1,98 @@ +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleH.js + */ + +#pragma once + +#include +#include + +namespace facebook::react { + + + class JSI_EXPORT NativeRNFBTurboFiamCxxSpecJSI : public TurboModule { +protected: + NativeRNFBTurboFiamCxxSpecJSI(std::shared_ptr jsInvoker); + +public: + virtual jsi::Object getConstants(jsi::Runtime &rt) = 0; + virtual jsi::Value setAutomaticDataCollectionEnabled(jsi::Runtime &rt, bool enabled) = 0; + virtual jsi::Value setMessagesDisplaySuppressed(jsi::Runtime &rt, bool enabled) = 0; + virtual jsi::Value triggerEvent(jsi::Runtime &rt, jsi::String eventId) = 0; + +}; + +template +class JSI_EXPORT NativeRNFBTurboFiamCxxSpec : public TurboModule { +public: + jsi::Value create(jsi::Runtime &rt, const jsi::PropNameID &propName) override { + return delegate_.create(rt, propName); + } + + std::vector getPropertyNames(jsi::Runtime& runtime) override { + return delegate_.getPropertyNames(runtime); + } + + static constexpr std::string_view kModuleName = "NativeRNFBTurboFiam"; + +protected: + NativeRNFBTurboFiamCxxSpec(std::shared_ptr jsInvoker) + : TurboModule(std::string{NativeRNFBTurboFiamCxxSpec::kModuleName}, jsInvoker), + delegate_(reinterpret_cast(this), jsInvoker) {} + + +private: + class Delegate : public NativeRNFBTurboFiamCxxSpecJSI { + public: + Delegate(T *instance, std::shared_ptr jsInvoker) : + NativeRNFBTurboFiamCxxSpecJSI(std::move(jsInvoker)), instance_(instance) { + + } + + jsi::Object getConstants(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::getConstants) == 1, + "Expected getConstants(...) to have 1 parameters"); + + return bridging::callFromJs( + rt, &T::getConstants, jsInvoker_, instance_); + } + jsi::Value setAutomaticDataCollectionEnabled(jsi::Runtime &rt, bool enabled) override { + static_assert( + bridging::getParameterCount(&T::setAutomaticDataCollectionEnabled) == 2, + "Expected setAutomaticDataCollectionEnabled(...) to have 2 parameters"); + + return bridging::callFromJs( + rt, &T::setAutomaticDataCollectionEnabled, jsInvoker_, instance_, std::move(enabled)); + } + jsi::Value setMessagesDisplaySuppressed(jsi::Runtime &rt, bool enabled) override { + static_assert( + bridging::getParameterCount(&T::setMessagesDisplaySuppressed) == 2, + "Expected setMessagesDisplaySuppressed(...) to have 2 parameters"); + + return bridging::callFromJs( + rt, &T::setMessagesDisplaySuppressed, jsInvoker_, instance_, std::move(enabled)); + } + jsi::Value triggerEvent(jsi::Runtime &rt, jsi::String eventId) override { + static_assert( + bridging::getParameterCount(&T::triggerEvent) == 2, + "Expected triggerEvent(...) to have 2 parameters"); + + return bridging::callFromJs( + rt, &T::triggerEvent, jsInvoker_, instance_, std::move(eventId)); + } + + private: + friend class NativeRNFBTurboFiamCxxSpec; + T *instance_; + }; + + Delegate delegate_; +}; + +} // namespace facebook::react diff --git a/packages/in-app-messaging/ios/RNFBFiam.xcodeproj/project.pbxproj b/packages/in-app-messaging/ios/RNFBFiam.xcodeproj/project.pbxproj index 63d1dca8be..1e0fe2d218 100644 --- a/packages/in-app-messaging/ios/RNFBFiam.xcodeproj/project.pbxproj +++ b/packages/in-app-messaging/ios/RNFBFiam.xcodeproj/project.pbxproj @@ -7,7 +7,7 @@ objects = { /* Begin PBXBuildFile section */ - 2744B98621F45429004F8E3F /* RNFBFiamModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 2744B98521F45429004F8E3F /* RNFBFiamModule.m */; }; + 2744B98621F45429004F8E3F /* RNFBFiamModule.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2744B98521F45429004F8E3F /* RNFBFiamModule.mm */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -25,7 +25,7 @@ /* Begin PBXFileReference section */ 2744B98221F45429004F8E3F /* libRNFBFiam.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRNFBFiam.a; sourceTree = BUILT_PRODUCTS_DIR; }; 2744B98421F45429004F8E3F /* RNFBFiamModule.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = RNFBFiamModule.h; path = RNFBFiam/RNFBFiamModule.h; sourceTree = SOURCE_ROOT; }; - 2744B98521F45429004F8E3F /* RNFBFiamModule.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = RNFBFiamModule.m; path = RNFBFiam/RNFBFiamModule.m; sourceTree = SOURCE_ROOT; }; + 2744B98521F45429004F8E3F /* RNFBFiamModule.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = RNFBFiamModule.mm; path = RNFBFiam/RNFBFiamModule.mm; sourceTree = SOURCE_ROOT; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -53,7 +53,7 @@ 2744B9A121F48736004F8E3F /* converters */, 2744B98C21F45C64004F8E3F /* common */, 2744B98421F45429004F8E3F /* RNFBFiamModule.h */, - 2744B98521F45429004F8E3F /* RNFBFiamModule.m */, + 2744B98521F45429004F8E3F /* RNFBFiamModule.mm */, ); path = RNFBFiam; sourceTree = ""; @@ -124,7 +124,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 2744B98621F45429004F8E3F /* RNFBFiamModule.m in Sources */, + 2744B98621F45429004F8E3F /* RNFBFiamModule.mm in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/packages/in-app-messaging/ios/RNFBFiam/RNFBFiamModule.h b/packages/in-app-messaging/ios/RNFBFiam/RNFBFiamModule.h index da7912b4aa..0abd306bce 100644 --- a/packages/in-app-messaging/ios/RNFBFiam/RNFBFiamModule.h +++ b/packages/in-app-messaging/ios/RNFBFiam/RNFBFiamModule.h @@ -16,9 +16,8 @@ */ #import +#import "RNFBInAppMessagingTurboModules.h" -#import - -@interface RNFBFiamModule : NSObject +@interface RNFBFiamModule : NSObject @end diff --git a/packages/in-app-messaging/ios/RNFBFiam/RNFBFiamModule.m b/packages/in-app-messaging/ios/RNFBFiam/RNFBFiamModule.mm similarity index 56% rename from packages/in-app-messaging/ios/RNFBFiam/RNFBFiamModule.m rename to packages/in-app-messaging/ios/RNFBFiam/RNFBFiamModule.mm index 2b860c389e..660cbb3402 100644 --- a/packages/in-app-messaging/ios/RNFBFiam/RNFBFiamModule.m +++ b/packages/in-app-messaging/ios/RNFBFiam/RNFBFiamModule.mm @@ -19,16 +19,17 @@ #import #import -#import "RNFBApp/RNFBSharedUtils.h" #import "RNFBFiamModule.h" @implementation RNFBFiamModule -#pragma mark - -#pragma mark Module Setup -RCT_EXPORT_MODULE(); +RCT_EXPORT_MODULE(NativeRNFBTurboFiam) -- (NSDictionary *)constantsToExport { ++ (BOOL)requiresMainQueueSetup { + return NO; +} + +- (NSDictionary *)fiamConstantsDictionary { NSMutableDictionary *constants = [NSMutableDictionary new]; constants[@"isMessagesDisplaySuppressed"] = @([RCTConvert BOOL:@([FIRInAppMessaging inAppMessaging].messageDisplaySuppressed)]); @@ -37,33 +38,36 @@ - (NSDictionary *)constantsToExport { return constants; } -+ (BOOL)requiresMainQueueSetup { - return NO; +- (facebook::react::ModuleConstants)constantsToExport { + return [_RCTTypedModuleConstants newWithUnsafeDictionary:[self fiamConstantsDictionary]]; +} + +- (facebook::react::ModuleConstants)getConstants { + return [self constantsToExport]; } -#pragma mark - -#pragma mark Firebase Fiam Methods +- (std::shared_ptr)getTurboModule: + (const facebook::react::ObjCTurboModule::InitParams &)params { + return std::make_shared(params); +} -RCT_EXPORT_METHOD(setAutomaticDataCollectionEnabled - : (BOOL)enabled resolver - : (RCTPromiseResolveBlock)resolve rejecter - : (RCTPromiseRejectBlock)reject) { +- (void)setAutomaticDataCollectionEnabled:(BOOL)enabled + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject { [FIRInAppMessaging inAppMessaging].automaticDataCollectionEnabled = (BOOL)enabled; resolve([NSNull null]); } -RCT_EXPORT_METHOD(setMessagesDisplaySuppressed - : (BOOL)enabled resolver - : (RCTPromiseResolveBlock)resolve rejecter - : (RCTPromiseRejectBlock)reject) { +- (void)setMessagesDisplaySuppressed:(BOOL)enabled + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject { [FIRInAppMessaging inAppMessaging].messageDisplaySuppressed = (BOOL)enabled; resolve([NSNull null]); } -RCT_EXPORT_METHOD(triggerEvent - : (NSString *)eventId resolver - : (RCTPromiseResolveBlock)resolve rejecter - : (RCTPromiseRejectBlock)reject) { +- (void)triggerEvent:(NSString *)eventId + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject { [[FIRInAppMessaging inAppMessaging] triggerEvent:eventId]; resolve([NSNull null]); } diff --git a/packages/in-app-messaging/ios/generated/RNFBInAppMessagingTurboModules/RNFBInAppMessagingTurboModules-generated.mm b/packages/in-app-messaging/ios/generated/RNFBInAppMessagingTurboModules/RNFBInAppMessagingTurboModules-generated.mm new file mode 100644 index 0000000000..5dd5f027f5 --- /dev/null +++ b/packages/in-app-messaging/ios/generated/RNFBInAppMessagingTurboModules/RNFBInAppMessagingTurboModules-generated.mm @@ -0,0 +1,60 @@ +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleObjCpp + * + * We create an umbrella header (and corresponding implementation) here since + * Cxx compilation in BUCK has a limitation: source-code producing genrule()s + * must have a single output. More files => more genrule()s => slower builds. + */ + +#import "RNFBInAppMessagingTurboModules.h" + + +@implementation NativeRNFBTurboFiamSpecBase + + +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper +{ + _eventEmitterCallback = std::move(eventEmitterCallbackWrapper->_eventEmitterCallback); +} +@end + + +namespace facebook::react { + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboFiamSpecJSI_setAutomaticDataCollectionEnabled(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, PromiseKind, "setAutomaticDataCollectionEnabled", @selector(setAutomaticDataCollectionEnabled:resolve:reject:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboFiamSpecJSI_setMessagesDisplaySuppressed(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, PromiseKind, "setMessagesDisplaySuppressed", @selector(setMessagesDisplaySuppressed:resolve:reject:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboFiamSpecJSI_triggerEvent(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, PromiseKind, "triggerEvent", @selector(triggerEvent:resolve:reject:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboFiamSpecJSI_getConstants(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, ObjectKind, "getConstants", @selector(getConstants), args, count); + } + + NativeRNFBTurboFiamSpecJSI::NativeRNFBTurboFiamSpecJSI(const ObjCTurboModule::InitParams ¶ms) + : ObjCTurboModule(params) { + + methodMap_["setAutomaticDataCollectionEnabled"] = MethodMetadata {1, __hostFunction_NativeRNFBTurboFiamSpecJSI_setAutomaticDataCollectionEnabled}; + + + methodMap_["setMessagesDisplaySuppressed"] = MethodMetadata {1, __hostFunction_NativeRNFBTurboFiamSpecJSI_setMessagesDisplaySuppressed}; + + + methodMap_["triggerEvent"] = MethodMetadata {1, __hostFunction_NativeRNFBTurboFiamSpecJSI_triggerEvent}; + + + methodMap_["getConstants"] = MethodMetadata {0, __hostFunction_NativeRNFBTurboFiamSpecJSI_getConstants}; + + } +} // namespace facebook::react diff --git a/packages/in-app-messaging/ios/generated/RNFBInAppMessagingTurboModules/RNFBInAppMessagingTurboModules.h b/packages/in-app-messaging/ios/generated/RNFBInAppMessagingTurboModules/RNFBInAppMessagingTurboModules.h new file mode 100644 index 0000000000..b1d3ebbbe0 --- /dev/null +++ b/packages/in-app-messaging/ios/generated/RNFBInAppMessagingTurboModules/RNFBInAppMessagingTurboModules.h @@ -0,0 +1,109 @@ +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleObjCpp + * + * We create an umbrella header (and corresponding implementation) here since + * Cxx compilation in BUCK has a limitation: source-code producing genrule()s + * must have a single output. More files => more genrule()s => slower builds. + */ + +#ifndef __cplusplus +#error This file must be compiled as Obj-C++. If you are importing it, you must change your file extension to .mm. +#endif + +// Avoid multiple includes of RNFBInAppMessagingTurboModules symbols +#ifndef RNFBInAppMessagingTurboModules_H +#define RNFBInAppMessagingTurboModules_H + +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import + + +NS_ASSUME_NONNULL_BEGIN +namespace JS { + namespace NativeRNFBTurboFiam { + struct Constants { + + struct Builder { + struct Input { + RCTRequired isMessagesDisplaySuppressed; + RCTRequired isAutomaticDataCollectionEnabled; + }; + + /** Initialize with a set of values */ + Builder(const Input i); + /** Initialize with an existing Constants */ + Builder(Constants i); + /** Builds the object. Generally used only by the infrastructure. */ + NSDictionary *buildUnsafeRawValue() const { return _factory(); }; + private: + NSDictionary *(^_factory)(void); + }; + + static Constants fromUnsafeRawValue(NSDictionary *const v) { return {v}; } + NSDictionary *unsafeRawValue() const { return _v; } + private: + Constants(NSDictionary *const v) : _v(v) {} + NSDictionary *_v; + }; + } +} +@protocol NativeRNFBTurboFiamSpec + +- (void)setAutomaticDataCollectionEnabled:(BOOL)enabled + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; +- (void)setMessagesDisplaySuppressed:(BOOL)enabled + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; +- (void)triggerEvent:(NSString *)eventId + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; +- (facebook::react::ModuleConstants)constantsToExport; +- (facebook::react::ModuleConstants)getConstants; + +@end + +@interface NativeRNFBTurboFiamSpecBase : NSObject { +@protected +facebook::react::EventEmitterCallback _eventEmitterCallback; +} +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper; + + +@end + +namespace facebook::react { + /** + * ObjC++ class for module 'NativeRNFBTurboFiam' + */ + class JSI_EXPORT NativeRNFBTurboFiamSpecJSI : public ObjCTurboModule { + public: + NativeRNFBTurboFiamSpecJSI(const ObjCTurboModule::InitParams ¶ms); + }; +} // namespace facebook::react +inline JS::NativeRNFBTurboFiam::Constants::Builder::Builder(const Input i) : _factory(^{ + NSMutableDictionary *d = [NSMutableDictionary new]; + auto isMessagesDisplaySuppressed = i.isMessagesDisplaySuppressed.get(); + d[@"isMessagesDisplaySuppressed"] = @(isMessagesDisplaySuppressed); + auto isAutomaticDataCollectionEnabled = i.isAutomaticDataCollectionEnabled.get(); + d[@"isAutomaticDataCollectionEnabled"] = @(isAutomaticDataCollectionEnabled); + return d; +}) {} +inline JS::NativeRNFBTurboFiam::Constants::Builder::Builder(Constants i) : _factory(^{ + return i.unsafeRawValue(); +}) {} +NS_ASSUME_NONNULL_END +#endif // RNFBInAppMessagingTurboModules_H diff --git a/packages/in-app-messaging/ios/generated/RNFBInAppMessagingTurboModulesJSI-generated.cpp b/packages/in-app-messaging/ios/generated/RNFBInAppMessagingTurboModulesJSI-generated.cpp new file mode 100644 index 0000000000..aaa1d537f3 --- /dev/null +++ b/packages/in-app-messaging/ios/generated/RNFBInAppMessagingTurboModulesJSI-generated.cpp @@ -0,0 +1,47 @@ +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleCpp.js + */ + +#include "RNFBInAppMessagingTurboModulesJSI.h" + +namespace facebook::react { + +static jsi::Value __hostFunction_NativeRNFBTurboFiamCxxSpecJSI_getConstants(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getConstants( + rt + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboFiamCxxSpecJSI_setAutomaticDataCollectionEnabled(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->setAutomaticDataCollectionEnabled( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asBool() + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboFiamCxxSpecJSI_setMessagesDisplaySuppressed(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->setMessagesDisplaySuppressed( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asBool() + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboFiamCxxSpecJSI_triggerEvent(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->triggerEvent( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt) + ); +} + +NativeRNFBTurboFiamCxxSpecJSI::NativeRNFBTurboFiamCxxSpecJSI(std::shared_ptr jsInvoker) + : TurboModule("NativeRNFBTurboFiam", jsInvoker) { + methodMap_["getConstants"] = MethodMetadata {0, __hostFunction_NativeRNFBTurboFiamCxxSpecJSI_getConstants}; + methodMap_["setAutomaticDataCollectionEnabled"] = MethodMetadata {1, __hostFunction_NativeRNFBTurboFiamCxxSpecJSI_setAutomaticDataCollectionEnabled}; + methodMap_["setMessagesDisplaySuppressed"] = MethodMetadata {1, __hostFunction_NativeRNFBTurboFiamCxxSpecJSI_setMessagesDisplaySuppressed}; + methodMap_["triggerEvent"] = MethodMetadata {1, __hostFunction_NativeRNFBTurboFiamCxxSpecJSI_triggerEvent}; +} + + +} // namespace facebook::react diff --git a/packages/in-app-messaging/ios/generated/RNFBInAppMessagingTurboModulesJSI.h b/packages/in-app-messaging/ios/generated/RNFBInAppMessagingTurboModulesJSI.h new file mode 100644 index 0000000000..2e35299e2b --- /dev/null +++ b/packages/in-app-messaging/ios/generated/RNFBInAppMessagingTurboModulesJSI.h @@ -0,0 +1,98 @@ +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleH.js + */ + +#pragma once + +#include +#include + +namespace facebook::react { + + + class JSI_EXPORT NativeRNFBTurboFiamCxxSpecJSI : public TurboModule { +protected: + NativeRNFBTurboFiamCxxSpecJSI(std::shared_ptr jsInvoker); + +public: + virtual jsi::Object getConstants(jsi::Runtime &rt) = 0; + virtual jsi::Value setAutomaticDataCollectionEnabled(jsi::Runtime &rt, bool enabled) = 0; + virtual jsi::Value setMessagesDisplaySuppressed(jsi::Runtime &rt, bool enabled) = 0; + virtual jsi::Value triggerEvent(jsi::Runtime &rt, jsi::String eventId) = 0; + +}; + +template +class JSI_EXPORT NativeRNFBTurboFiamCxxSpec : public TurboModule { +public: + jsi::Value create(jsi::Runtime &rt, const jsi::PropNameID &propName) override { + return delegate_.create(rt, propName); + } + + std::vector getPropertyNames(jsi::Runtime& runtime) override { + return delegate_.getPropertyNames(runtime); + } + + static constexpr std::string_view kModuleName = "NativeRNFBTurboFiam"; + +protected: + NativeRNFBTurboFiamCxxSpec(std::shared_ptr jsInvoker) + : TurboModule(std::string{NativeRNFBTurboFiamCxxSpec::kModuleName}, jsInvoker), + delegate_(reinterpret_cast(this), jsInvoker) {} + + +private: + class Delegate : public NativeRNFBTurboFiamCxxSpecJSI { + public: + Delegate(T *instance, std::shared_ptr jsInvoker) : + NativeRNFBTurboFiamCxxSpecJSI(std::move(jsInvoker)), instance_(instance) { + + } + + jsi::Object getConstants(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::getConstants) == 1, + "Expected getConstants(...) to have 1 parameters"); + + return bridging::callFromJs( + rt, &T::getConstants, jsInvoker_, instance_); + } + jsi::Value setAutomaticDataCollectionEnabled(jsi::Runtime &rt, bool enabled) override { + static_assert( + bridging::getParameterCount(&T::setAutomaticDataCollectionEnabled) == 2, + "Expected setAutomaticDataCollectionEnabled(...) to have 2 parameters"); + + return bridging::callFromJs( + rt, &T::setAutomaticDataCollectionEnabled, jsInvoker_, instance_, std::move(enabled)); + } + jsi::Value setMessagesDisplaySuppressed(jsi::Runtime &rt, bool enabled) override { + static_assert( + bridging::getParameterCount(&T::setMessagesDisplaySuppressed) == 2, + "Expected setMessagesDisplaySuppressed(...) to have 2 parameters"); + + return bridging::callFromJs( + rt, &T::setMessagesDisplaySuppressed, jsInvoker_, instance_, std::move(enabled)); + } + jsi::Value triggerEvent(jsi::Runtime &rt, jsi::String eventId) override { + static_assert( + bridging::getParameterCount(&T::triggerEvent) == 2, + "Expected triggerEvent(...) to have 2 parameters"); + + return bridging::callFromJs( + rt, &T::triggerEvent, jsInvoker_, instance_, std::move(eventId)); + } + + private: + friend class NativeRNFBTurboFiamCxxSpec; + T *instance_; + }; + + Delegate delegate_; +}; + +} // namespace facebook::react diff --git a/packages/in-app-messaging/lib/index.ts b/packages/in-app-messaging/lib/index.ts index 067c6a8989..a4d7a6f761 100644 --- a/packages/in-app-messaging/lib/index.ts +++ b/packages/in-app-messaging/lib/index.ts @@ -28,7 +28,7 @@ import type { InAppMessaging } from './types/in-app-messaging'; import fallBackModule from './web/RNFBFiamModule'; import { version } from './version'; -const nativeModuleName = 'RNFBFiamModule'; +const nativeModuleName = 'NativeRNFBTurboFiam'; class FirebaseFiamModule extends FirebaseModule { private _isMessagesDisplaySuppressed: boolean; @@ -84,6 +84,7 @@ const config: ModuleConfig = { nativeEvents: false, hasMultiAppSupport: false, hasCustomUrlOrRegionSupport: false, + turboModule: true, }; /** diff --git a/packages/in-app-messaging/lib/types/internal.ts b/packages/in-app-messaging/lib/types/internal.ts index 48e44ffbdb..940124031b 100644 --- a/packages/in-app-messaging/lib/types/internal.ts +++ b/packages/in-app-messaging/lib/types/internal.ts @@ -30,7 +30,7 @@ export interface RNFBFiamModule { declare module '@react-native-firebase/app/dist/module/internal/NativeModules' { interface ReactNativeFirebaseNativeModules { - RNFBFiamModule: RNFBFiamModule; + NativeRNFBTurboFiam: RNFBFiamModule; } } diff --git a/packages/in-app-messaging/package.json b/packages/in-app-messaging/package.json index 1904922848..52751a6a7c 100644 --- a/packages/in-app-messaging/package.json +++ b/packages/in-app-messaging/package.json @@ -5,11 +5,28 @@ "description": "React Native Firebase - Firebase In-App Messaging helps you engage your app's active users by sending them targeted, contextual messages that encourage them to use key app features. React Native Firebase provides support for both native Android & iOS integration with a simple JavaScript API.", "main": "./dist/module/index.js", "types": "./dist/typescript/lib/index.d.ts", + "codegenConfig": { + "name": "RNFBInAppMessagingTurboModules", + "type": "modules", + "jsSrcsDir": "specs", + "includesGeneratedCode": true, + "android": { + "javaPackageName": "io.invertase.firebase.fiam" + }, + "ios": { + "modulesProvider": { + "NativeRNFBTurboFiam": "RNFBFiamModule" + } + } + }, "scripts": { "build": "genversion --esm --semi lib/version.ts", "build:clean": "rimraf android/build && rimraf ios/build", "compile": "bob build", - "prepare": "yarn run build && yarn compile" + "prepare": "yarn run build && yarn compile", + "codegen": "yarn android:codegen && yarn ios:codegen", + "android:codegen": "npx @react-native-community/cli codegen --platform android --outputPath=./android/src/reactnative/java/io/invertase/firebase/fiam/generated", + "ios:codegen": "npx @react-native-community/cli codegen --platform ios --outputPath=./ios/generated" }, "repository": { "type": "git", diff --git a/packages/in-app-messaging/react-native.config.js b/packages/in-app-messaging/react-native.config.js new file mode 100644 index 0000000000..ab43246054 --- /dev/null +++ b/packages/in-app-messaging/react-native.config.js @@ -0,0 +1,10 @@ +module.exports = { + dependency: { + platforms: { + android: { + cmakeListsPath: + './src/reactnative/java/io/invertase/firebase/fiam/generated/jni/CMakeLists.txt', + }, + }, + }, +}; diff --git a/packages/in-app-messaging/specs/NativeRNFBTurboFiam.ts b/packages/in-app-messaging/specs/NativeRNFBTurboFiam.ts new file mode 100644 index 0000000000..581c6e073e --- /dev/null +++ b/packages/in-app-messaging/specs/NativeRNFBTurboFiam.ts @@ -0,0 +1,15 @@ +import type { TurboModule } from 'react-native'; +import { TurboModuleRegistry } from 'react-native'; + +export interface Spec extends TurboModule { + getConstants(): { + isMessagesDisplaySuppressed: boolean; + isAutomaticDataCollectionEnabled: boolean; + }; + + setAutomaticDataCollectionEnabled(enabled: boolean): Promise; + setMessagesDisplaySuppressed(enabled: boolean): Promise; + triggerEvent(eventId: string): Promise; +} + +export default TurboModuleRegistry.getEnforcing('NativeRNFBTurboFiam'); From ab3041a7285e62bafb1c45147be0453b7292e60a Mon Sep 17 00:00:00 2001 From: Mike Hardy Date: Wed, 1 Jul 2026 07:06:24 -0500 Subject: [PATCH 09/10] feat(app-distribution)!: migrate app-distribution to TurboModules --- .../new-architecture/migration-work-queue.md | 4 +- .../RNFBAppDistribution.podspec | 13 +- .../__tests__/nativeModuleContract.test.ts | 62 +++++++ .../app-distribution/android/build.gradle | 19 ++ ...va => NativeRNFBTurboAppDistribution.java} | 31 ++-- ...tNativeFirebaseAppDistributionPackage.java | 2 +- .../NativeRNFBTurboAppDistributionSpec.java | 50 ++++++ .../generated/jni/CMakeLists.txt | 36 ++++ ...BAppDistributionTurboModules-generated.cpp | 50 ++++++ .../jni/RNFBAppDistributionTurboModules.h | 31 ++++ ...pDistributionTurboModulesJSI-generated.cpp | 44 +++++ .../RNFBAppDistributionTurboModulesJSI.h | 166 ++++++++++++++++++ .../project.pbxproj | 8 +- .../RNFBAppDistributionModule.h | 5 +- ...nModule.m => RNFBAppDistributionModule.mm} | 32 ++-- ...FBAppDistributionTurboModules-generated.mm | 60 +++++++ .../RNFBAppDistributionTurboModules.h | 69 ++++++++ ...pDistributionTurboModulesJSI-generated.cpp | 44 +++++ .../RNFBAppDistributionTurboModulesJSI.h | 166 ++++++++++++++++++ packages/app-distribution/lib/index.ts | 3 +- .../app-distribution/lib/types/internal.ts | 2 +- packages/app-distribution/package.json | 19 +- .../app-distribution/react-native.config.js | 10 ++ .../specs/NativeRNFBTurboAppDistribution.ts | 19 ++ 24 files changed, 889 insertions(+), 56 deletions(-) create mode 100644 packages/app-distribution/__tests__/nativeModuleContract.test.ts rename packages/app-distribution/android/src/main/java/io/invertase/firebase/appdistribution/{ReactNativeFirebaseAppDistributionModule.java => NativeRNFBTurboAppDistribution.java} (52%) create mode 100644 packages/app-distribution/android/src/main/java/io/invertase/firebase/appdistribution/generated/java/com/facebook/fbreact/specs/NativeRNFBTurboAppDistributionSpec.java create mode 100644 packages/app-distribution/android/src/main/java/io/invertase/firebase/appdistribution/generated/jni/CMakeLists.txt create mode 100644 packages/app-distribution/android/src/main/java/io/invertase/firebase/appdistribution/generated/jni/RNFBAppDistributionTurboModules-generated.cpp create mode 100644 packages/app-distribution/android/src/main/java/io/invertase/firebase/appdistribution/generated/jni/RNFBAppDistributionTurboModules.h create mode 100644 packages/app-distribution/android/src/main/java/io/invertase/firebase/appdistribution/generated/jni/react/renderer/components/RNFBAppDistributionTurboModules/RNFBAppDistributionTurboModulesJSI-generated.cpp create mode 100644 packages/app-distribution/android/src/main/java/io/invertase/firebase/appdistribution/generated/jni/react/renderer/components/RNFBAppDistributionTurboModules/RNFBAppDistributionTurboModulesJSI.h rename packages/app-distribution/ios/RNFBAppDistribution/{RNFBAppDistributionModule.m => RNFBAppDistributionModule.mm} (77%) create mode 100644 packages/app-distribution/ios/generated/RNFBAppDistributionTurboModules/RNFBAppDistributionTurboModules-generated.mm create mode 100644 packages/app-distribution/ios/generated/RNFBAppDistributionTurboModules/RNFBAppDistributionTurboModules.h create mode 100644 packages/app-distribution/ios/generated/RNFBAppDistributionTurboModulesJSI-generated.cpp create mode 100644 packages/app-distribution/ios/generated/RNFBAppDistributionTurboModulesJSI.h create mode 100644 packages/app-distribution/react-native.config.js create mode 100644 packages/app-distribution/specs/NativeRNFBTurboAppDistribution.ts diff --git a/okf-bundle/new-architecture/migration-work-queue.md b/okf-bundle/new-architecture/migration-work-queue.md index 3c6ef83f37..b28613ae99 100644 --- a/okf-bundle/new-architecture/migration-work-queue.md +++ b/okf-bundle/new-architecture/migration-work-queue.md @@ -8,7 +8,7 @@ timestamp: 2026-06-26T00:00:00Z # TurboModule migration — work queue -> **IN PROGRESS (2026-06-30):** Phase **2** — committing P2c `in-app-messaging`. +> **IN PROGRESS (2026-06-30):** Phase **2** — committing P2d `app-distribution`. > **Goal/order:** app foundation → hard probe → easy wins → remaining complex → sync conversion → coordinated break → cleanup (events, shared-state encapsulation). Decisions: [architecture-decisions.md](architecture-decisions.md). Links: [implementation workflow](turbomodule-implementation-workflow.md), [change authoring](../testing/change-authoring-workflow.md), [functions reference](../../../packages/functions/) ([PR #8603](https://github.com/invertase/react-native-firebase/pull/8603)). Ephemeral tracker; see [OKF policy](../documentation-policy.md). @@ -284,7 +284,7 @@ Skip steps 1–2 when spec shape is known (most Tier D packages). | Phase 1 `firestore` TurboModules | P1 | **closed** | **closed** | **closed** | done | `area-focused` | `feat(firestore)!: migrate firestore to TurboModules` | Committed 2026-06-30. | | Phase 2 `installations` | P2a | **closed** | **closed** | **closed** | done | `area-focused` | `feat(installations)!: migrate installations to TurboModules` | Committed 2026-06-30. Remediation: iOS `invalidate` no-op. | | Phase 2 `perf` | P2b | **closed** | **closed** | **closed** | done | `area-focused` | `feat(perf)!: migrate perf to TurboModules` | Committed 2026-06-30. | -| Phase 2 `in-app-messaging` | P2c | **closed** | **closed** | **open** | `commit` | `area-focused` | `feat(in-app-messaging)!: migrate in-app-messaging to TurboModules` | Review green 2026-06-30. Deferred: dead legacy Java; stale JSDoc; 3 xdescribe pending. | +| Phase 2 `in-app-messaging` | P2c | **closed** | **closed** | **closed** | done | `area-focused` | `feat(in-app-messaging)!: migrate in-app-messaging to TurboModules` | Committed 2026-06-30. | | Phase 2 `app-distribution` | P2d | **closed** | **closed** | **open** | `commit` | `area-focused` | `feat(app-distribution)!: migrate app-distribution to TurboModules` | Review green 2026-06-30: Android 1 pass + 4 pending; iOS 3 pass + 2 pending. Duplicate codegen + legacy Java removed. | | Phase 2 `ml` | P2e | **closed** | **closed** | **open** | `commit` | `area-focused` | `feat(ml)!: migrate ml to TurboModules` | Review green 2026-06-30: 1 pass Android + iOS. Stub module. | diff --git a/packages/app-distribution/RNFBAppDistribution.podspec b/packages/app-distribution/RNFBAppDistribution.podspec index f3e0b6e240..2aa00086d4 100644 --- a/packages/app-distribution/RNFBAppDistribution.podspec +++ b/packages/app-distribution/RNFBAppDistribution.podspec @@ -25,15 +25,16 @@ Pod::Spec.new do |s| s.social_media_url = 'http://twitter.com/invertaseio' s.ios.deployment_target = firebase_ios_target s.macos.deployment_target = firebase_macos_target - s.source_files = 'ios/**/*.{h,m}' + s.source_files = 'ios/**/*.{h,m,mm,cpp,swift}' + s.private_header_files = "ios/**/*.h" + s.exclude_files = 'ios/generated/RCTThirdPartyComponentsProvider.*', 'ios/generated/RCTAppDependencyProvider.*', 'ios/generated/RCTModuleProviders.*', 'ios/generated/RCTModulesConformingToProtocolsProvider.*', 'ios/generated/RCTUnstableModulesRequiringMainQueueSetupProvider.*' s.dependency 'RNFBApp' - # React Native dependencies - if defined?(install_modules_dependencies()) != nil - install_modules_dependencies(s); - else - s.dependency "React-Core" + install_modules_dependencies(s); + + if defined?(ENV["RCT_NEW_ARCH_ENABLED"]) != nil && (ENV["RCT_NEW_ARCH_ENABLED"] == '0') + raise "#{s.name} requires New Architecture. Enable New Architecture to use this module" end if defined?($FirebaseSDKVersion) diff --git a/packages/app-distribution/__tests__/nativeModuleContract.test.ts b/packages/app-distribution/__tests__/nativeModuleContract.test.ts new file mode 100644 index 0000000000..0fcf31586b --- /dev/null +++ b/packages/app-distribution/__tests__/nativeModuleContract.test.ts @@ -0,0 +1,62 @@ +import { describe, expect, it, jest } from '@jest/globals'; +import { TurboModuleRegistry } from 'react-native'; +import type { ModuleConfig } from '@react-native-firebase/app/dist/module/internal'; +import FirebaseModule from '@react-native-firebase/app/dist/module/internal/FirebaseModule'; +import { getNativeModule } from '@react-native-firebase/app/dist/module/internal/registry/nativeModule'; +import type { WrappedNativeModule } from '@react-native-firebase/app/dist/module/internal/NativeModules'; + +const SPEC_METHODS = [ + 'isTesterSignedIn', + 'signInTester', + 'signOutTester', + 'checkForUpdate', +] as const; + +function createTurboModuleFixture(methods: Record): Record { + const proto = Object.create(Object.prototype); + + for (const [name, fn] of Object.entries(methods)) { + Object.defineProperty(proto, name, { + value: fn, + enumerable: true, + configurable: true, + }); + } + + return Object.create(proto); +} + +describe('TurboModule wrapper contract (NewArch-AD-17.1)', function () { + it('exposes every spec method callable through the real wrapper', function () { + const mocks = Object.fromEntries( + SPEC_METHODS.map(method => [method, jest.fn(() => Promise.resolve(null))]), + ) as Record; + + const raw = createTurboModuleFixture(mocks); + jest.mocked(TurboModuleRegistry.get).mockReturnValueOnce(raw); + + const config: ModuleConfig = { + namespace: 'appDistribution', + nativeModuleName: 'NativeRNFBTurboAppDistribution', + nativeEvents: false, + hasMultiAppSupport: false, + hasCustomUrlOrRegionSupport: false, + turboModule: true, + }; + + class ContractModule extends FirebaseModule { + constructor() { + super({ name: '[DEFAULT]' } as any, config); + } + } + + const wrapped = getNativeModule(new ContractModule()) as WrappedNativeModule & + Record<(typeof SPEC_METHODS)[number], () => Promise>; + + for (const method of SPEC_METHODS) { + void wrapped[method](); + expect(mocks[method]).toHaveBeenCalledTimes(1); + expect(Object.keys(wrapped)).toContain(method); + } + }); +}); diff --git a/packages/app-distribution/android/build.gradle b/packages/app-distribution/android/build.gradle index 56199353bb..f102800890 100644 --- a/packages/app-distribution/android/build.gradle +++ b/packages/app-distribution/android/build.gradle @@ -81,6 +81,7 @@ android { sourceSets { main { java.srcDirs = ['src/main/java', 'src/reactnative/java'] + java.excludes = ['**/generated/jni/**'] } } } @@ -105,3 +106,21 @@ ReactNative.shared.applyPackageVersion() ReactNative.shared.applyDefaultExcludes() ReactNative.module.applyAndroidVersions() ReactNative.module.applyReactNativeDependency("api") + +def isNewArchitectureDisabled() { + return project.hasProperty("newArchEnabled") && project.newArchEnabled != "true" +} + +if (isNewArchitectureDisabled()) { + def ANSI_RED = "\u001B[31m"; + def ANSI_RESET = "\u001B[0m"; + + println("\n\n\n") + println(ANSI_RED + "**************************************************************************************************************") + println("\n\n\n") + println("New Architecture support is required for @react-native-firebase/app-distribution") + println("\n\n\n") + println("**************************************************************************************************************" + ANSI_RESET) + println("\n\n\n") + System.exit(1) +} diff --git a/packages/app-distribution/android/src/main/java/io/invertase/firebase/appdistribution/ReactNativeFirebaseAppDistributionModule.java b/packages/app-distribution/android/src/main/java/io/invertase/firebase/appdistribution/NativeRNFBTurboAppDistribution.java similarity index 52% rename from packages/app-distribution/android/src/main/java/io/invertase/firebase/appdistribution/ReactNativeFirebaseAppDistributionModule.java rename to packages/app-distribution/android/src/main/java/io/invertase/firebase/appdistribution/NativeRNFBTurboAppDistribution.java index 8ea25f332b..3543add12e 100644 --- a/packages/app-distribution/android/src/main/java/io/invertase/firebase/appdistribution/ReactNativeFirebaseAppDistributionModule.java +++ b/packages/app-distribution/android/src/main/java/io/invertase/firebase/appdistribution/NativeRNFBTurboAppDistribution.java @@ -17,37 +17,34 @@ * */ -import com.facebook.react.bridge.*; -import io.invertase.firebase.common.ReactNativeFirebaseModule; +import com.facebook.fbreact.specs.NativeRNFBTurboAppDistributionSpec; +import com.facebook.react.bridge.Promise; +import com.facebook.react.bridge.ReactApplicationContext; -public class ReactNativeFirebaseAppDistributionModule extends ReactNativeFirebaseModule { +public class NativeRNFBTurboAppDistribution extends NativeRNFBTurboAppDistributionSpec { private static final String TAG = "AppDistribution"; - ReactNativeFirebaseAppDistributionModule(ReactApplicationContext reactContext) { - super(reactContext, TAG); + public NativeRNFBTurboAppDistribution(ReactApplicationContext reactContext) { + super(reactContext); } - @ReactMethod + @Override public void isTesterSignedIn(Promise promise) { - rejectPromiseWithCodeAndMessage( - promise, "platform-unsupported", "Android is not supported for App Distribution"); + promise.reject("platform-unsupported", "Android is not supported for App Distribution"); } - @ReactMethod + @Override public void signInTester(Promise promise) { - rejectPromiseWithCodeAndMessage( - promise, "platform-unsupported", "Android is not supported for App Distribution"); + promise.reject("platform-unsupported", "Android is not supported for App Distribution"); } - @ReactMethod + @Override public void checkForUpdate(Promise promise) { - rejectPromiseWithCodeAndMessage( - promise, "platform-unsupported", "Android is not supported for App Distribution"); + promise.reject("platform-unsupported", "Android is not supported for App Distribution"); } - @ReactMethod + @Override public void signOutTester(Promise promise) { - rejectPromiseWithCodeAndMessage( - promise, "platform-unsupported", "Android is not supported for App Distribution"); + promise.reject("platform-unsupported", "Android is not supported for App Distribution"); } } diff --git a/packages/app-distribution/android/src/main/java/io/invertase/firebase/appdistribution/ReactNativeFirebaseAppDistributionPackage.java b/packages/app-distribution/android/src/main/java/io/invertase/firebase/appdistribution/ReactNativeFirebaseAppDistributionPackage.java index 0cf7521a93..6234b97387 100644 --- a/packages/app-distribution/android/src/main/java/io/invertase/firebase/appdistribution/ReactNativeFirebaseAppDistributionPackage.java +++ b/packages/app-distribution/android/src/main/java/io/invertase/firebase/appdistribution/ReactNativeFirebaseAppDistributionPackage.java @@ -30,7 +30,7 @@ public class ReactNativeFirebaseAppDistributionPackage implements ReactPackage { @Override public List createNativeModules(ReactApplicationContext reactContext) { List modules = new ArrayList<>(); - modules.add(new ReactNativeFirebaseAppDistributionModule(reactContext)); + modules.add(new NativeRNFBTurboAppDistribution(reactContext)); return modules; } diff --git a/packages/app-distribution/android/src/main/java/io/invertase/firebase/appdistribution/generated/java/com/facebook/fbreact/specs/NativeRNFBTurboAppDistributionSpec.java b/packages/app-distribution/android/src/main/java/io/invertase/firebase/appdistribution/generated/java/com/facebook/fbreact/specs/NativeRNFBTurboAppDistributionSpec.java new file mode 100644 index 0000000000..d14f2af706 --- /dev/null +++ b/packages/app-distribution/android/src/main/java/io/invertase/firebase/appdistribution/generated/java/com/facebook/fbreact/specs/NativeRNFBTurboAppDistributionSpec.java @@ -0,0 +1,50 @@ + +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleJavaSpec.js + * + * @nolint + */ + +package com.facebook.fbreact.specs; + +import com.facebook.proguard.annotations.DoNotStrip; +import com.facebook.react.bridge.Promise; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReactContextBaseJavaModule; +import com.facebook.react.bridge.ReactMethod; +import com.facebook.react.turbomodule.core.interfaces.TurboModule; +import javax.annotation.Nonnull; + +public abstract class NativeRNFBTurboAppDistributionSpec extends ReactContextBaseJavaModule implements TurboModule { + public static final String NAME = "NativeRNFBTurboAppDistribution"; + + public NativeRNFBTurboAppDistributionSpec(ReactApplicationContext reactContext) { + super(reactContext); + } + + @Override + public @Nonnull String getName() { + return NAME; + } + + @ReactMethod + @DoNotStrip + public abstract void isTesterSignedIn(Promise promise); + + @ReactMethod + @DoNotStrip + public abstract void signInTester(Promise promise); + + @ReactMethod + @DoNotStrip + public abstract void signOutTester(Promise promise); + + @ReactMethod + @DoNotStrip + public abstract void checkForUpdate(Promise promise); +} diff --git a/packages/app-distribution/android/src/main/java/io/invertase/firebase/appdistribution/generated/jni/CMakeLists.txt b/packages/app-distribution/android/src/main/java/io/invertase/firebase/appdistribution/generated/jni/CMakeLists.txt new file mode 100644 index 0000000000..b14bf3abf3 --- /dev/null +++ b/packages/app-distribution/android/src/main/java/io/invertase/firebase/appdistribution/generated/jni/CMakeLists.txt @@ -0,0 +1,36 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +cmake_minimum_required(VERSION 3.13) +set(CMAKE_VERBOSE_MAKEFILE on) + +file(GLOB react_codegen_SRCS CONFIGURE_DEPENDS *.cpp react/renderer/components/RNFBAppDistributionTurboModules/*.cpp) + +add_library( + react_codegen_RNFBAppDistributionTurboModules + OBJECT + ${react_codegen_SRCS} +) + +target_include_directories(react_codegen_RNFBAppDistributionTurboModules PUBLIC . react/renderer/components/RNFBAppDistributionTurboModules) + +target_link_libraries( + react_codegen_RNFBAppDistributionTurboModules + fbjni + jsi + # We need to link different libraries based on whether we are building rncore or not, that's necessary + # because we want to break a circular dependency between react_codegen_rncore and reactnative + reactnative +) + +target_compile_options( + react_codegen_RNFBAppDistributionTurboModules + PRIVATE + -DLOG_TAG=\"ReactNative\" + -fexceptions + -frtti + -std=c++20 + -Wall +) diff --git a/packages/app-distribution/android/src/main/java/io/invertase/firebase/appdistribution/generated/jni/RNFBAppDistributionTurboModules-generated.cpp b/packages/app-distribution/android/src/main/java/io/invertase/firebase/appdistribution/generated/jni/RNFBAppDistributionTurboModules-generated.cpp new file mode 100644 index 0000000000..3b0f6733b5 --- /dev/null +++ b/packages/app-distribution/android/src/main/java/io/invertase/firebase/appdistribution/generated/jni/RNFBAppDistributionTurboModules-generated.cpp @@ -0,0 +1,50 @@ + +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleJniCpp.js + */ + +#include "RNFBAppDistributionTurboModules.h" + +namespace facebook::react { + +static facebook::jsi::Value __hostFunction_NativeRNFBTurboAppDistributionSpecJSI_isTesterSignedIn(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, PromiseKind, "isTesterSignedIn", "(Lcom/facebook/react/bridge/Promise;)V", args, count, cachedMethodId); +} + +static facebook::jsi::Value __hostFunction_NativeRNFBTurboAppDistributionSpecJSI_signInTester(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, PromiseKind, "signInTester", "(Lcom/facebook/react/bridge/Promise;)V", args, count, cachedMethodId); +} + +static facebook::jsi::Value __hostFunction_NativeRNFBTurboAppDistributionSpecJSI_signOutTester(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, PromiseKind, "signOutTester", "(Lcom/facebook/react/bridge/Promise;)V", args, count, cachedMethodId); +} + +static facebook::jsi::Value __hostFunction_NativeRNFBTurboAppDistributionSpecJSI_checkForUpdate(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, PromiseKind, "checkForUpdate", "(Lcom/facebook/react/bridge/Promise;)V", args, count, cachedMethodId); +} + +NativeRNFBTurboAppDistributionSpecJSI::NativeRNFBTurboAppDistributionSpecJSI(const JavaTurboModule::InitParams ¶ms) + : JavaTurboModule(params) { + methodMap_["isTesterSignedIn"] = MethodMetadata {0, __hostFunction_NativeRNFBTurboAppDistributionSpecJSI_isTesterSignedIn}; + methodMap_["signInTester"] = MethodMetadata {0, __hostFunction_NativeRNFBTurboAppDistributionSpecJSI_signInTester}; + methodMap_["signOutTester"] = MethodMetadata {0, __hostFunction_NativeRNFBTurboAppDistributionSpecJSI_signOutTester}; + methodMap_["checkForUpdate"] = MethodMetadata {0, __hostFunction_NativeRNFBTurboAppDistributionSpecJSI_checkForUpdate}; +} + +std::shared_ptr RNFBAppDistributionTurboModules_ModuleProvider(const std::string &moduleName, const JavaTurboModule::InitParams ¶ms) { + if (moduleName == "NativeRNFBTurboAppDistribution") { + return std::make_shared(params); + } + return nullptr; +} + +} // namespace facebook::react diff --git a/packages/app-distribution/android/src/main/java/io/invertase/firebase/appdistribution/generated/jni/RNFBAppDistributionTurboModules.h b/packages/app-distribution/android/src/main/java/io/invertase/firebase/appdistribution/generated/jni/RNFBAppDistributionTurboModules.h new file mode 100644 index 0000000000..88466f6d6a --- /dev/null +++ b/packages/app-distribution/android/src/main/java/io/invertase/firebase/appdistribution/generated/jni/RNFBAppDistributionTurboModules.h @@ -0,0 +1,31 @@ + +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleJniH.js + */ + +#pragma once + +#include +#include +#include + +namespace facebook::react { + +/** + * JNI C++ class for module 'NativeRNFBTurboAppDistribution' + */ +class JSI_EXPORT NativeRNFBTurboAppDistributionSpecJSI : public JavaTurboModule { +public: + NativeRNFBTurboAppDistributionSpecJSI(const JavaTurboModule::InitParams ¶ms); +}; + + +JSI_EXPORT +std::shared_ptr RNFBAppDistributionTurboModules_ModuleProvider(const std::string &moduleName, const JavaTurboModule::InitParams ¶ms); + +} // namespace facebook::react diff --git a/packages/app-distribution/android/src/main/java/io/invertase/firebase/appdistribution/generated/jni/react/renderer/components/RNFBAppDistributionTurboModules/RNFBAppDistributionTurboModulesJSI-generated.cpp b/packages/app-distribution/android/src/main/java/io/invertase/firebase/appdistribution/generated/jni/react/renderer/components/RNFBAppDistributionTurboModules/RNFBAppDistributionTurboModulesJSI-generated.cpp new file mode 100644 index 0000000000..d4383bb504 --- /dev/null +++ b/packages/app-distribution/android/src/main/java/io/invertase/firebase/appdistribution/generated/jni/react/renderer/components/RNFBAppDistributionTurboModules/RNFBAppDistributionTurboModulesJSI-generated.cpp @@ -0,0 +1,44 @@ +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleCpp.js + */ + +#include "RNFBAppDistributionTurboModulesJSI.h" + +namespace facebook::react { + +static jsi::Value __hostFunction_NativeRNFBTurboAppDistributionCxxSpecJSI_isTesterSignedIn(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->isTesterSignedIn( + rt + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboAppDistributionCxxSpecJSI_signInTester(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->signInTester( + rt + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboAppDistributionCxxSpecJSI_signOutTester(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->signOutTester( + rt + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboAppDistributionCxxSpecJSI_checkForUpdate(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->checkForUpdate( + rt + ); +} + +NativeRNFBTurboAppDistributionCxxSpecJSI::NativeRNFBTurboAppDistributionCxxSpecJSI(std::shared_ptr jsInvoker) + : TurboModule("NativeRNFBTurboAppDistribution", jsInvoker) { + methodMap_["isTesterSignedIn"] = MethodMetadata {0, __hostFunction_NativeRNFBTurboAppDistributionCxxSpecJSI_isTesterSignedIn}; + methodMap_["signInTester"] = MethodMetadata {0, __hostFunction_NativeRNFBTurboAppDistributionCxxSpecJSI_signInTester}; + methodMap_["signOutTester"] = MethodMetadata {0, __hostFunction_NativeRNFBTurboAppDistributionCxxSpecJSI_signOutTester}; + methodMap_["checkForUpdate"] = MethodMetadata {0, __hostFunction_NativeRNFBTurboAppDistributionCxxSpecJSI_checkForUpdate}; +} + + +} // namespace facebook::react diff --git a/packages/app-distribution/android/src/main/java/io/invertase/firebase/appdistribution/generated/jni/react/renderer/components/RNFBAppDistributionTurboModules/RNFBAppDistributionTurboModulesJSI.h b/packages/app-distribution/android/src/main/java/io/invertase/firebase/appdistribution/generated/jni/react/renderer/components/RNFBAppDistributionTurboModules/RNFBAppDistributionTurboModulesJSI.h new file mode 100644 index 0000000000..66aeecd6d9 --- /dev/null +++ b/packages/app-distribution/android/src/main/java/io/invertase/firebase/appdistribution/generated/jni/react/renderer/components/RNFBAppDistributionTurboModules/RNFBAppDistributionTurboModulesJSI.h @@ -0,0 +1,166 @@ +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleH.js + */ + +#pragma once + +#include +#include + +namespace facebook::react { + + + +#pragma mark - NativeRNFBTurboAppDistributionAppDistributionRelease + +template +struct NativeRNFBTurboAppDistributionAppDistributionRelease { + P0 displayVersion; + P1 buildVersion; + P2 releaseNotes; + P3 isExpired; + P4 downloadURL; + bool operator==(const NativeRNFBTurboAppDistributionAppDistributionRelease &other) const { + return displayVersion == other.displayVersion && buildVersion == other.buildVersion && releaseNotes == other.releaseNotes && isExpired == other.isExpired && downloadURL == other.downloadURL; + } +}; + +template +struct NativeRNFBTurboAppDistributionAppDistributionReleaseBridging { + static T types; + + static T fromJs( + jsi::Runtime &rt, + const jsi::Object &value, + const std::shared_ptr &jsInvoker) { + T result{ + bridging::fromJs(rt, value.getProperty(rt, "displayVersion"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, "buildVersion"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, "releaseNotes"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, "isExpired"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, "downloadURL"), jsInvoker)}; + return result; + } + +#ifdef DEBUG + static jsi::String displayVersionToJs(jsi::Runtime &rt, decltype(types.displayVersion) value) { + return bridging::toJs(rt, value); + } + + static jsi::String buildVersionToJs(jsi::Runtime &rt, decltype(types.buildVersion) value) { + return bridging::toJs(rt, value); + } + + static std::optional releaseNotesToJs(jsi::Runtime &rt, decltype(types.releaseNotes) value) { + return bridging::toJs(rt, value); + } + + static bool isExpiredToJs(jsi::Runtime &rt, decltype(types.isExpired) value) { + return bridging::toJs(rt, value); + } + + static jsi::String downloadURLToJs(jsi::Runtime &rt, decltype(types.downloadURL) value) { + return bridging::toJs(rt, value); + } +#endif + + static jsi::Object toJs( + jsi::Runtime &rt, + const T &value, + const std::shared_ptr &jsInvoker) { + auto result = facebook::jsi::Object(rt); + result.setProperty(rt, "displayVersion", bridging::toJs(rt, value.displayVersion, jsInvoker)); + result.setProperty(rt, "buildVersion", bridging::toJs(rt, value.buildVersion, jsInvoker)); + result.setProperty(rt, "releaseNotes", bridging::toJs(rt, value.releaseNotes, jsInvoker)); + result.setProperty(rt, "isExpired", bridging::toJs(rt, value.isExpired, jsInvoker)); + result.setProperty(rt, "downloadURL", bridging::toJs(rt, value.downloadURL, jsInvoker)); + return result; + } +}; + +class JSI_EXPORT NativeRNFBTurboAppDistributionCxxSpecJSI : public TurboModule { +protected: + NativeRNFBTurboAppDistributionCxxSpecJSI(std::shared_ptr jsInvoker); + +public: + virtual jsi::Value isTesterSignedIn(jsi::Runtime &rt) = 0; + virtual jsi::Value signInTester(jsi::Runtime &rt) = 0; + virtual jsi::Value signOutTester(jsi::Runtime &rt) = 0; + virtual jsi::Value checkForUpdate(jsi::Runtime &rt) = 0; + +}; + +template +class JSI_EXPORT NativeRNFBTurboAppDistributionCxxSpec : public TurboModule { +public: + jsi::Value create(jsi::Runtime &rt, const jsi::PropNameID &propName) override { + return delegate_.create(rt, propName); + } + + std::vector getPropertyNames(jsi::Runtime& runtime) override { + return delegate_.getPropertyNames(runtime); + } + + static constexpr std::string_view kModuleName = "NativeRNFBTurboAppDistribution"; + +protected: + NativeRNFBTurboAppDistributionCxxSpec(std::shared_ptr jsInvoker) + : TurboModule(std::string{NativeRNFBTurboAppDistributionCxxSpec::kModuleName}, jsInvoker), + delegate_(reinterpret_cast(this), jsInvoker) {} + + +private: + class Delegate : public NativeRNFBTurboAppDistributionCxxSpecJSI { + public: + Delegate(T *instance, std::shared_ptr jsInvoker) : + NativeRNFBTurboAppDistributionCxxSpecJSI(std::move(jsInvoker)), instance_(instance) { + + } + + jsi::Value isTesterSignedIn(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::isTesterSignedIn) == 1, + "Expected isTesterSignedIn(...) to have 1 parameters"); + + return bridging::callFromJs( + rt, &T::isTesterSignedIn, jsInvoker_, instance_); + } + jsi::Value signInTester(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::signInTester) == 1, + "Expected signInTester(...) to have 1 parameters"); + + return bridging::callFromJs( + rt, &T::signInTester, jsInvoker_, instance_); + } + jsi::Value signOutTester(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::signOutTester) == 1, + "Expected signOutTester(...) to have 1 parameters"); + + return bridging::callFromJs( + rt, &T::signOutTester, jsInvoker_, instance_); + } + jsi::Value checkForUpdate(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::checkForUpdate) == 1, + "Expected checkForUpdate(...) to have 1 parameters"); + + return bridging::callFromJs( + rt, &T::checkForUpdate, jsInvoker_, instance_); + } + + private: + friend class NativeRNFBTurboAppDistributionCxxSpec; + T *instance_; + }; + + Delegate delegate_; +}; + +} // namespace facebook::react diff --git a/packages/app-distribution/ios/RNFBAppDistribution.xcodeproj/project.pbxproj b/packages/app-distribution/ios/RNFBAppDistribution.xcodeproj/project.pbxproj index 36828a7107..ece34e437a 100644 --- a/packages/app-distribution/ios/RNFBAppDistribution.xcodeproj/project.pbxproj +++ b/packages/app-distribution/ios/RNFBAppDistribution.xcodeproj/project.pbxproj @@ -7,7 +7,7 @@ objects = { /* Begin PBXBuildFile section */ - 2744B98621F45429004F8E3F /* RNFBAppDistributionModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 2744B98521F45429004F8E3F /* RNFBAppDistributionModule.m */; }; + 2744B98621F45429004F8E3F /* RNFBAppDistributionModule.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2744B98521F45429004F8E3F /* RNFBAppDistributionModule.mm */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -25,7 +25,7 @@ /* Begin PBXFileReference section */ 2744B98221F45429004F8E3F /* libRNFBAppDistribution.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRNFBAppDistribution.a; sourceTree = BUILT_PRODUCTS_DIR; }; 2744B98421F45429004F8E3F /* RNFBAppDistributionModule.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = RNFBAppDistributionModule.h; path = RNFBAppDistribution/RNFBAppDistributionModule.h; sourceTree = SOURCE_ROOT; }; - 2744B98521F45429004F8E3F /* RNFBAppDistributionModule.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = RNFBAppDistributionModule.m; path = RNFBAppDistribution/RNFBAppDistributionModule.m; sourceTree = SOURCE_ROOT; }; + 2744B98521F45429004F8E3F /* RNFBAppDistributionModule.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = RNFBAppDistributionModule.mm; path = RNFBAppDistribution/RNFBAppDistributionModule.mm; sourceTree = SOURCE_ROOT; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -53,7 +53,7 @@ 2744B9A121F48736004F8E3F /* converters */, 2744B98C21F45C64004F8E3F /* common */, 2744B98421F45429004F8E3F /* RNFBAppDistributionModule.h */, - 2744B98521F45429004F8E3F /* RNFBAppDistributionModule.m */, + 2744B98521F45429004F8E3F /* RNFBAppDistributionModule.mm */, ); path = RNFBAppDistribution; sourceTree = ""; @@ -124,7 +124,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 2744B98621F45429004F8E3F /* RNFBAppDistributionModule.m in Sources */, + 2744B98621F45429004F8E3F /* RNFBAppDistributionModule.mm in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/packages/app-distribution/ios/RNFBAppDistribution/RNFBAppDistributionModule.h b/packages/app-distribution/ios/RNFBAppDistribution/RNFBAppDistributionModule.h index b21dbecb14..a550e5c459 100644 --- a/packages/app-distribution/ios/RNFBAppDistribution/RNFBAppDistributionModule.h +++ b/packages/app-distribution/ios/RNFBAppDistribution/RNFBAppDistributionModule.h @@ -16,9 +16,8 @@ */ #import +#import "RNFBAppDistributionTurboModules.h" -#import - -@interface RNFBAppDistributionModule : NSObject +@interface RNFBAppDistributionModule : NSObject @end diff --git a/packages/app-distribution/ios/RNFBAppDistribution/RNFBAppDistributionModule.m b/packages/app-distribution/ios/RNFBAppDistribution/RNFBAppDistributionModule.mm similarity index 77% rename from packages/app-distribution/ios/RNFBAppDistribution/RNFBAppDistributionModule.m rename to packages/app-distribution/ios/RNFBAppDistribution/RNFBAppDistributionModule.mm index a13b881f2b..7e82fb21f6 100644 --- a/packages/app-distribution/ios/RNFBAppDistribution/RNFBAppDistributionModule.m +++ b/packages/app-distribution/ios/RNFBAppDistribution/RNFBAppDistributionModule.mm @@ -22,31 +22,28 @@ #import "RNFBAppDistributionModule.h" @implementation RNFBAppDistributionModule -#pragma mark - -#pragma mark Module Setup -RCT_EXPORT_MODULE(); +RCT_EXPORT_MODULE(NativeRNFBTurboAppDistribution) -- (dispatch_queue_t)methodQueue { - return dispatch_get_main_queue(); ++ (BOOL)requiresMainQueueSetup { + return NO; } -#pragma mark - -#pragma mark Firebase AppDistribution Methods +- (std::shared_ptr)getTurboModule: + (const facebook::react::ObjCTurboModule::InitParams &)params { + return std::make_shared(params); +} -RCT_EXPORT_METHOD(isTesterSignedIn - : (RCTPromiseResolveBlock)resolve rejecter - : (RCTPromiseRejectBlock)reject) { +- (void)isTesterSignedIn:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { FIRAppDistribution *appDistribution = [FIRAppDistribution appDistribution]; BOOL isTesterSignedIn = appDistribution.isTesterSignedIn; resolve([NSNumber numberWithBool:isTesterSignedIn]); } -RCT_EXPORT_METHOD(signInTester : (RCTPromiseResolveBlock)resolve : (RCTPromiseRejectBlock)reject) { +- (void)signInTester:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { FIRAppDistribution *appDistribution = [FIRAppDistribution appDistribution]; [appDistribution signInTesterWithCompletion:^(NSError *_Nullable error) { if (error != nil) { - // Handle any errors if the signIn failed DLog(@"Unable to signInTester: %@", error); [RNFBSharedUtils rejectPromiseWithUserInfo:reject userInfo:(NSMutableDictionary *)@{ @@ -60,21 +57,16 @@ - (dispatch_queue_t)methodQueue { }]; } -RCT_EXPORT_METHOD(signOutTester - : (RCTPromiseResolveBlock)resolve rejecter - : (RCTPromiseRejectBlock)reject) { +- (void)signOutTester:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { [[FIRAppDistribution appDistribution] signOutTester]; resolve([NSNull null]); } -RCT_EXPORT_METHOD(checkForUpdate - : (RCTPromiseResolveBlock)resolve - : (RCTPromiseRejectBlock)reject) { +- (void)checkForUpdate:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { FIRAppDistribution *appDistribution = [FIRAppDistribution appDistribution]; [appDistribution checkForUpdateWithCompletion:^(FIRAppDistributionRelease *_Nullable release, NSError *_Nullable error) { if (error != nil) { - // Handle any errors if the release was not retrieved. DLog(@"Unable to check App Distribution release: %@", error); [RNFBSharedUtils rejectPromiseWithUserInfo:reject userInfo:(NSMutableDictionary *)@{ @@ -84,7 +76,7 @@ - (dispatch_queue_t)methodQueue { return; } if (release == nil) { - DLog(@"Unable to check App Distribution release: %@", error); + DLog(@"Unable to check App Distribution release."); [RNFBSharedUtils rejectPromiseWithUserInfo:reject userInfo:(NSMutableDictionary *)@{ @"code" : @"checkupdate-null", diff --git a/packages/app-distribution/ios/generated/RNFBAppDistributionTurboModules/RNFBAppDistributionTurboModules-generated.mm b/packages/app-distribution/ios/generated/RNFBAppDistributionTurboModules/RNFBAppDistributionTurboModules-generated.mm new file mode 100644 index 0000000000..9455f8f6ad --- /dev/null +++ b/packages/app-distribution/ios/generated/RNFBAppDistributionTurboModules/RNFBAppDistributionTurboModules-generated.mm @@ -0,0 +1,60 @@ +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleObjCpp + * + * We create an umbrella header (and corresponding implementation) here since + * Cxx compilation in BUCK has a limitation: source-code producing genrule()s + * must have a single output. More files => more genrule()s => slower builds. + */ + +#import "RNFBAppDistributionTurboModules.h" + + +@implementation NativeRNFBTurboAppDistributionSpecBase + + +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper +{ + _eventEmitterCallback = std::move(eventEmitterCallbackWrapper->_eventEmitterCallback); +} +@end + + +namespace facebook::react { + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboAppDistributionSpecJSI_isTesterSignedIn(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, PromiseKind, "isTesterSignedIn", @selector(isTesterSignedIn:reject:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboAppDistributionSpecJSI_signInTester(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, PromiseKind, "signInTester", @selector(signInTester:reject:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboAppDistributionSpecJSI_signOutTester(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, PromiseKind, "signOutTester", @selector(signOutTester:reject:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeRNFBTurboAppDistributionSpecJSI_checkForUpdate(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, PromiseKind, "checkForUpdate", @selector(checkForUpdate:reject:), args, count); + } + + NativeRNFBTurboAppDistributionSpecJSI::NativeRNFBTurboAppDistributionSpecJSI(const ObjCTurboModule::InitParams ¶ms) + : ObjCTurboModule(params) { + + methodMap_["isTesterSignedIn"] = MethodMetadata {0, __hostFunction_NativeRNFBTurboAppDistributionSpecJSI_isTesterSignedIn}; + + + methodMap_["signInTester"] = MethodMetadata {0, __hostFunction_NativeRNFBTurboAppDistributionSpecJSI_signInTester}; + + + methodMap_["signOutTester"] = MethodMetadata {0, __hostFunction_NativeRNFBTurboAppDistributionSpecJSI_signOutTester}; + + + methodMap_["checkForUpdate"] = MethodMetadata {0, __hostFunction_NativeRNFBTurboAppDistributionSpecJSI_checkForUpdate}; + + } +} // namespace facebook::react diff --git a/packages/app-distribution/ios/generated/RNFBAppDistributionTurboModules/RNFBAppDistributionTurboModules.h b/packages/app-distribution/ios/generated/RNFBAppDistributionTurboModules/RNFBAppDistributionTurboModules.h new file mode 100644 index 0000000000..c5b39e5c3d --- /dev/null +++ b/packages/app-distribution/ios/generated/RNFBAppDistributionTurboModules/RNFBAppDistributionTurboModules.h @@ -0,0 +1,69 @@ +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleObjCpp + * + * We create an umbrella header (and corresponding implementation) here since + * Cxx compilation in BUCK has a limitation: source-code producing genrule()s + * must have a single output. More files => more genrule()s => slower builds. + */ + +#ifndef __cplusplus +#error This file must be compiled as Obj-C++. If you are importing it, you must change your file extension to .mm. +#endif + +// Avoid multiple includes of RNFBAppDistributionTurboModules symbols +#ifndef RNFBAppDistributionTurboModules_H +#define RNFBAppDistributionTurboModules_H + +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import + + +NS_ASSUME_NONNULL_BEGIN + +@protocol NativeRNFBTurboAppDistributionSpec + +- (void)isTesterSignedIn:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; +- (void)signInTester:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; +- (void)signOutTester:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; +- (void)checkForUpdate:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; + +@end + +@interface NativeRNFBTurboAppDistributionSpecBase : NSObject { +@protected +facebook::react::EventEmitterCallback _eventEmitterCallback; +} +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper; + + +@end + +namespace facebook::react { + /** + * ObjC++ class for module 'NativeRNFBTurboAppDistribution' + */ + class JSI_EXPORT NativeRNFBTurboAppDistributionSpecJSI : public ObjCTurboModule { + public: + NativeRNFBTurboAppDistributionSpecJSI(const ObjCTurboModule::InitParams ¶ms); + }; +} // namespace facebook::react + +NS_ASSUME_NONNULL_END +#endif // RNFBAppDistributionTurboModules_H diff --git a/packages/app-distribution/ios/generated/RNFBAppDistributionTurboModulesJSI-generated.cpp b/packages/app-distribution/ios/generated/RNFBAppDistributionTurboModulesJSI-generated.cpp new file mode 100644 index 0000000000..d4383bb504 --- /dev/null +++ b/packages/app-distribution/ios/generated/RNFBAppDistributionTurboModulesJSI-generated.cpp @@ -0,0 +1,44 @@ +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleCpp.js + */ + +#include "RNFBAppDistributionTurboModulesJSI.h" + +namespace facebook::react { + +static jsi::Value __hostFunction_NativeRNFBTurboAppDistributionCxxSpecJSI_isTesterSignedIn(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->isTesterSignedIn( + rt + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboAppDistributionCxxSpecJSI_signInTester(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->signInTester( + rt + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboAppDistributionCxxSpecJSI_signOutTester(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->signOutTester( + rt + ); +} +static jsi::Value __hostFunction_NativeRNFBTurboAppDistributionCxxSpecJSI_checkForUpdate(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->checkForUpdate( + rt + ); +} + +NativeRNFBTurboAppDistributionCxxSpecJSI::NativeRNFBTurboAppDistributionCxxSpecJSI(std::shared_ptr jsInvoker) + : TurboModule("NativeRNFBTurboAppDistribution", jsInvoker) { + methodMap_["isTesterSignedIn"] = MethodMetadata {0, __hostFunction_NativeRNFBTurboAppDistributionCxxSpecJSI_isTesterSignedIn}; + methodMap_["signInTester"] = MethodMetadata {0, __hostFunction_NativeRNFBTurboAppDistributionCxxSpecJSI_signInTester}; + methodMap_["signOutTester"] = MethodMetadata {0, __hostFunction_NativeRNFBTurboAppDistributionCxxSpecJSI_signOutTester}; + methodMap_["checkForUpdate"] = MethodMetadata {0, __hostFunction_NativeRNFBTurboAppDistributionCxxSpecJSI_checkForUpdate}; +} + + +} // namespace facebook::react diff --git a/packages/app-distribution/ios/generated/RNFBAppDistributionTurboModulesJSI.h b/packages/app-distribution/ios/generated/RNFBAppDistributionTurboModulesJSI.h new file mode 100644 index 0000000000..66aeecd6d9 --- /dev/null +++ b/packages/app-distribution/ios/generated/RNFBAppDistributionTurboModulesJSI.h @@ -0,0 +1,166 @@ +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleH.js + */ + +#pragma once + +#include +#include + +namespace facebook::react { + + + +#pragma mark - NativeRNFBTurboAppDistributionAppDistributionRelease + +template +struct NativeRNFBTurboAppDistributionAppDistributionRelease { + P0 displayVersion; + P1 buildVersion; + P2 releaseNotes; + P3 isExpired; + P4 downloadURL; + bool operator==(const NativeRNFBTurboAppDistributionAppDistributionRelease &other) const { + return displayVersion == other.displayVersion && buildVersion == other.buildVersion && releaseNotes == other.releaseNotes && isExpired == other.isExpired && downloadURL == other.downloadURL; + } +}; + +template +struct NativeRNFBTurboAppDistributionAppDistributionReleaseBridging { + static T types; + + static T fromJs( + jsi::Runtime &rt, + const jsi::Object &value, + const std::shared_ptr &jsInvoker) { + T result{ + bridging::fromJs(rt, value.getProperty(rt, "displayVersion"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, "buildVersion"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, "releaseNotes"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, "isExpired"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, "downloadURL"), jsInvoker)}; + return result; + } + +#ifdef DEBUG + static jsi::String displayVersionToJs(jsi::Runtime &rt, decltype(types.displayVersion) value) { + return bridging::toJs(rt, value); + } + + static jsi::String buildVersionToJs(jsi::Runtime &rt, decltype(types.buildVersion) value) { + return bridging::toJs(rt, value); + } + + static std::optional releaseNotesToJs(jsi::Runtime &rt, decltype(types.releaseNotes) value) { + return bridging::toJs(rt, value); + } + + static bool isExpiredToJs(jsi::Runtime &rt, decltype(types.isExpired) value) { + return bridging::toJs(rt, value); + } + + static jsi::String downloadURLToJs(jsi::Runtime &rt, decltype(types.downloadURL) value) { + return bridging::toJs(rt, value); + } +#endif + + static jsi::Object toJs( + jsi::Runtime &rt, + const T &value, + const std::shared_ptr &jsInvoker) { + auto result = facebook::jsi::Object(rt); + result.setProperty(rt, "displayVersion", bridging::toJs(rt, value.displayVersion, jsInvoker)); + result.setProperty(rt, "buildVersion", bridging::toJs(rt, value.buildVersion, jsInvoker)); + result.setProperty(rt, "releaseNotes", bridging::toJs(rt, value.releaseNotes, jsInvoker)); + result.setProperty(rt, "isExpired", bridging::toJs(rt, value.isExpired, jsInvoker)); + result.setProperty(rt, "downloadURL", bridging::toJs(rt, value.downloadURL, jsInvoker)); + return result; + } +}; + +class JSI_EXPORT NativeRNFBTurboAppDistributionCxxSpecJSI : public TurboModule { +protected: + NativeRNFBTurboAppDistributionCxxSpecJSI(std::shared_ptr jsInvoker); + +public: + virtual jsi::Value isTesterSignedIn(jsi::Runtime &rt) = 0; + virtual jsi::Value signInTester(jsi::Runtime &rt) = 0; + virtual jsi::Value signOutTester(jsi::Runtime &rt) = 0; + virtual jsi::Value checkForUpdate(jsi::Runtime &rt) = 0; + +}; + +template +class JSI_EXPORT NativeRNFBTurboAppDistributionCxxSpec : public TurboModule { +public: + jsi::Value create(jsi::Runtime &rt, const jsi::PropNameID &propName) override { + return delegate_.create(rt, propName); + } + + std::vector getPropertyNames(jsi::Runtime& runtime) override { + return delegate_.getPropertyNames(runtime); + } + + static constexpr std::string_view kModuleName = "NativeRNFBTurboAppDistribution"; + +protected: + NativeRNFBTurboAppDistributionCxxSpec(std::shared_ptr jsInvoker) + : TurboModule(std::string{NativeRNFBTurboAppDistributionCxxSpec::kModuleName}, jsInvoker), + delegate_(reinterpret_cast(this), jsInvoker) {} + + +private: + class Delegate : public NativeRNFBTurboAppDistributionCxxSpecJSI { + public: + Delegate(T *instance, std::shared_ptr jsInvoker) : + NativeRNFBTurboAppDistributionCxxSpecJSI(std::move(jsInvoker)), instance_(instance) { + + } + + jsi::Value isTesterSignedIn(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::isTesterSignedIn) == 1, + "Expected isTesterSignedIn(...) to have 1 parameters"); + + return bridging::callFromJs( + rt, &T::isTesterSignedIn, jsInvoker_, instance_); + } + jsi::Value signInTester(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::signInTester) == 1, + "Expected signInTester(...) to have 1 parameters"); + + return bridging::callFromJs( + rt, &T::signInTester, jsInvoker_, instance_); + } + jsi::Value signOutTester(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::signOutTester) == 1, + "Expected signOutTester(...) to have 1 parameters"); + + return bridging::callFromJs( + rt, &T::signOutTester, jsInvoker_, instance_); + } + jsi::Value checkForUpdate(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::checkForUpdate) == 1, + "Expected checkForUpdate(...) to have 1 parameters"); + + return bridging::callFromJs( + rt, &T::checkForUpdate, jsInvoker_, instance_); + } + + private: + friend class NativeRNFBTurboAppDistributionCxxSpec; + T *instance_; + }; + + Delegate delegate_; +}; + +} // namespace facebook::react diff --git a/packages/app-distribution/lib/index.ts b/packages/app-distribution/lib/index.ts index b29b399dc3..5895bebb3f 100644 --- a/packages/app-distribution/lib/index.ts +++ b/packages/app-distribution/lib/index.ts @@ -28,7 +28,7 @@ import type { AppDistribution, AppDistributionRelease } from './types/app-distri import type { AppDistributionInternal } from './types/internal'; import { version } from './version'; -const nativeModuleName = 'RNFBAppDistributionModule'; +const nativeModuleName = 'NativeRNFBTurboAppDistribution'; function rejectUnsupportedPlatform(): Promise { return Promise.reject( @@ -76,6 +76,7 @@ const config: ModuleConfig = { nativeEvents: false, hasMultiAppSupport: false, hasCustomUrlOrRegionSupport: false, + turboModule: true, }; export const SDK_VERSION = version; diff --git a/packages/app-distribution/lib/types/internal.ts b/packages/app-distribution/lib/types/internal.ts index 35b37ff093..57b85a53bf 100644 --- a/packages/app-distribution/lib/types/internal.ts +++ b/packages/app-distribution/lib/types/internal.ts @@ -9,7 +9,7 @@ export interface RNFBAppDistributionModule { declare module '@react-native-firebase/app/dist/module/internal/NativeModules' { interface ReactNativeFirebaseNativeModules { - RNFBAppDistributionModule: RNFBAppDistributionModule; + NativeRNFBTurboAppDistribution: RNFBAppDistributionModule; } } diff --git a/packages/app-distribution/package.json b/packages/app-distribution/package.json index 6efa1e05c6..995ed56c7b 100644 --- a/packages/app-distribution/package.json +++ b/packages/app-distribution/package.json @@ -5,13 +5,30 @@ "description": "React Native Firebase - App Distribution", "main": "./dist/module/index.js", "types": "./dist/typescript/lib/index.d.ts", + "codegenConfig": { + "name": "RNFBAppDistributionTurboModules", + "type": "modules", + "jsSrcsDir": "specs", + "includesGeneratedCode": true, + "android": { + "javaPackageName": "io.invertase.firebase.appdistribution" + }, + "ios": { + "modulesProvider": { + "NativeRNFBTurboAppDistribution": "RNFBAppDistributionModule" + } + } + }, "scripts": { "build": "genversion --esm --semi lib/version.ts", "build:clean": "rimraf android/build && rimraf ios/build", "build:plugin": "rimraf plugin/build && tsc --build plugin", "compile": "bob build", "lint:plugin": "eslint plugin/src/*", - "prepare": "yarn run build && yarn compile && yarn run build:plugin" + "prepare": "yarn run build && yarn compile && yarn run build:plugin", + "codegen": "yarn android:codegen && yarn ios:codegen", + "android:codegen": "npx @react-native-community/cli codegen --platform android --outputPath=./android/src/main/java/io/invertase/firebase/appdistribution/generated", + "ios:codegen": "npx @react-native-community/cli codegen --platform ios --outputPath=./ios/generated" }, "repository": { "type": "git", diff --git a/packages/app-distribution/react-native.config.js b/packages/app-distribution/react-native.config.js new file mode 100644 index 0000000000..f76c67c9e9 --- /dev/null +++ b/packages/app-distribution/react-native.config.js @@ -0,0 +1,10 @@ +module.exports = { + dependency: { + platforms: { + android: { + cmakeListsPath: + './src/main/java/io/invertase/firebase/appdistribution/generated/jni/CMakeLists.txt', + }, + }, + }, +}; diff --git a/packages/app-distribution/specs/NativeRNFBTurboAppDistribution.ts b/packages/app-distribution/specs/NativeRNFBTurboAppDistribution.ts new file mode 100644 index 0000000000..f5d03b4b6e --- /dev/null +++ b/packages/app-distribution/specs/NativeRNFBTurboAppDistribution.ts @@ -0,0 +1,19 @@ +import type { TurboModule } from 'react-native'; +import { TurboModuleRegistry } from 'react-native'; + +export interface AppDistributionRelease { + displayVersion: string; + buildVersion: string; + releaseNotes: string | null; + isExpired: boolean; + downloadURL: string; +} + +export interface Spec extends TurboModule { + isTesterSignedIn(): Promise; + signInTester(): Promise; + signOutTester(): Promise; + checkForUpdate(): Promise; +} + +export default TurboModuleRegistry.getEnforcing('NativeRNFBTurboAppDistribution'); From 5070a6d9f25327dfed3e6677ba0ed4268ac68d2f Mon Sep 17 00:00:00 2001 From: Mike Hardy Date: Wed, 1 Jul 2026 07:06:41 -0500 Subject: [PATCH 10/10] feat(ml)!: migrate ml to TurboModules --- .../new-architecture/migration-work-queue.md | 21 +++-- .../turbomodule-implementation-workflow.md | 76 +++++++++++++++++-- okf-bundle/testing/agent-command-policy.md | 6 ++ okf-bundle/testing/running-e2e.md | 41 +++++++++- packages/ml/RNFBML.podspec | 13 ++-- .../ml/__tests__/nativeModuleContract.test.ts | 36 +++++++++ packages/ml/android/build.gradle | 19 +++++ .../firebase/ml/NativeRNFBTurboML.java | 27 +++++++ .../ml/ReactNativeFirebaseMLPackage.java | 1 + .../fbreact/specs/NativeRNFBTurboMLSpec.java | 35 +++++++++ .../firebase/ml/generated/jni/CMakeLists.txt | 36 +++++++++ .../jni/RNFBMLTurboModules-generated.cpp | 29 +++++++ .../ml/generated/jni/RNFBMLTurboModules.h | 31 ++++++++ .../RNFBMLTurboModulesJSI-generated.cpp | 22 ++++++ .../RNFBMLTurboModulesJSI.h | 64 ++++++++++++++++ packages/ml/ios/RNFBML/RNFBMLModule.h | 23 ++++++ packages/ml/ios/RNFBML/RNFBMLModule.mm | 33 ++++++++ .../RNFBMLTurboModules-generated.mm | 34 +++++++++ .../RNFBMLTurboModules/RNFBMLTurboModules.h | 62 +++++++++++++++ .../RNFBMLTurboModulesJSI-generated.cpp | 22 ++++++ .../ml/ios/generated/RNFBMLTurboModulesJSI.h | 64 ++++++++++++++++ packages/ml/lib/index.ts | 3 +- packages/ml/lib/types/internal.ts | 2 +- packages/ml/package.json | 19 ++++- packages/ml/react-native.config.js | 10 +++ packages/ml/specs/NativeRNFBTurboML.ts | 6 ++ tests/ios/Podfile.lock | 14 ++-- 27 files changed, 715 insertions(+), 34 deletions(-) create mode 100644 packages/ml/__tests__/nativeModuleContract.test.ts create mode 100644 packages/ml/android/src/reactnative/java/io/invertase/firebase/ml/NativeRNFBTurboML.java create mode 100644 packages/ml/android/src/reactnative/java/io/invertase/firebase/ml/generated/java/com/facebook/fbreact/specs/NativeRNFBTurboMLSpec.java create mode 100644 packages/ml/android/src/reactnative/java/io/invertase/firebase/ml/generated/jni/CMakeLists.txt create mode 100644 packages/ml/android/src/reactnative/java/io/invertase/firebase/ml/generated/jni/RNFBMLTurboModules-generated.cpp create mode 100644 packages/ml/android/src/reactnative/java/io/invertase/firebase/ml/generated/jni/RNFBMLTurboModules.h create mode 100644 packages/ml/android/src/reactnative/java/io/invertase/firebase/ml/generated/jni/react/renderer/components/RNFBMLTurboModules/RNFBMLTurboModulesJSI-generated.cpp create mode 100644 packages/ml/android/src/reactnative/java/io/invertase/firebase/ml/generated/jni/react/renderer/components/RNFBMLTurboModules/RNFBMLTurboModulesJSI.h create mode 100644 packages/ml/ios/RNFBML/RNFBMLModule.h create mode 100644 packages/ml/ios/RNFBML/RNFBMLModule.mm create mode 100644 packages/ml/ios/generated/RNFBMLTurboModules/RNFBMLTurboModules-generated.mm create mode 100644 packages/ml/ios/generated/RNFBMLTurboModules/RNFBMLTurboModules.h create mode 100644 packages/ml/ios/generated/RNFBMLTurboModulesJSI-generated.cpp create mode 100644 packages/ml/ios/generated/RNFBMLTurboModulesJSI.h create mode 100644 packages/ml/react-native.config.js create mode 100644 packages/ml/specs/NativeRNFBTurboML.ts diff --git a/okf-bundle/new-architecture/migration-work-queue.md b/okf-bundle/new-architecture/migration-work-queue.md index b28613ae99..d97362d9fa 100644 --- a/okf-bundle/new-architecture/migration-work-queue.md +++ b/okf-bundle/new-architecture/migration-work-queue.md @@ -8,7 +8,7 @@ timestamp: 2026-06-26T00:00:00Z # TurboModule migration — work queue -> **IN PROGRESS (2026-06-30):** Phase **2** — committing P2d `app-distribution`. +> **IN PROGRESS (2026-06-30):** Phase **3** moderate — **implementation** (`app-check`). Phase **2** complete. > **Goal/order:** app foundation → hard probe → easy wins → remaining complex → sync conversion → coordinated break → cleanup (events, shared-state encapsulation). Decisions: [architecture-decisions.md](architecture-decisions.md). Links: [implementation workflow](turbomodule-implementation-workflow.md), [change authoring](../testing/change-authoring-workflow.md), [functions reference](../../../packages/functions/) ([PR #8603](https://github.com/invertase/react-native-firebase/pull/8603)). Ephemeral tracker; see [OKF policy](../documentation-policy.md). @@ -163,8 +163,8 @@ Pick **one** of `firestore` or `auth` in Phase 1 (firestore = multi-module + pip | **0** | App foundation + unified resolver | **done** | `app` | | **0.1** | App modular type parity (`compare:types`) | **done** | `app` — [§ Phase 0.1](#phase-01-app-comparetypes) | | **1** | Hard probe | **done** | `firestore` (multi-module + pipelines; NewArch-AD-14a composite) | -| **2** | Easy wins | **commit-ready** | `installations`, `perf`, `in-app-messaging`, `app-distribution`, `ml` | -| **3** | Moderate | queued | `app-check`, `remote-config`, `analytics`, `crashlytics`, `storage` | +| **2** | Easy wins | **done** | `installations`, `perf`, `in-app-messaging`, `app-distribution`, `ml` | +| **3** | Moderate | **in progress** | `app-check`, `remote-config`, `analytics`, `crashlytics`, `storage` | | **4** | Remaining complex | queued | other Tier A/B + `messaging`, `database` | | **5** | Android-only / misc | queued | `phone-number-verification` | | **S** | Sync conversion (forced-async → sync) | queued (scope open — [NewArch-AD-16](architecture-decisions.md#newarch-ad-16--phase-s-asyncsync-conversion--open)) | All migrated packages — [§ sync conversion](#phase-s-sync-conversion-forced-async--sync) | @@ -267,11 +267,11 @@ Skip steps 1–2 when spec shape is known (most Tier D packages). ## Current snapshot -**Label:** `phase-2-easy-wins`; **harness:** local overrides (delete before Phase R) +**Label:** `phase-3-moderate`; **harness:** pending per package -**Next item:** Phase **2** P2a `installations` — **commit** +**Next item:** Phase **3** P3a `app-check` — **implementation** -**Current gates:** P2a–P2e `commit_gate` **open** (impl + review closed) +**Current gates:** Phase **2** complete · P3a `implementation_gate` **open** **Arbiter gate:** @@ -285,8 +285,13 @@ Skip steps 1–2 when spec shape is known (most Tier D packages). | Phase 2 `installations` | P2a | **closed** | **closed** | **closed** | done | `area-focused` | `feat(installations)!: migrate installations to TurboModules` | Committed 2026-06-30. Remediation: iOS `invalidate` no-op. | | Phase 2 `perf` | P2b | **closed** | **closed** | **closed** | done | `area-focused` | `feat(perf)!: migrate perf to TurboModules` | Committed 2026-06-30. | | Phase 2 `in-app-messaging` | P2c | **closed** | **closed** | **closed** | done | `area-focused` | `feat(in-app-messaging)!: migrate in-app-messaging to TurboModules` | Committed 2026-06-30. | -| Phase 2 `app-distribution` | P2d | **closed** | **closed** | **open** | `commit` | `area-focused` | `feat(app-distribution)!: migrate app-distribution to TurboModules` | Review green 2026-06-30: Android 1 pass + 4 pending; iOS 3 pass + 2 pending. Duplicate codegen + legacy Java removed. | -| Phase 2 `ml` | P2e | **closed** | **closed** | **open** | `commit` | `area-focused` | `feat(ml)!: migrate ml to TurboModules` | Review green 2026-06-30: 1 pass Android + iOS. Stub module. | +| Phase 2 `app-distribution` | P2d | **closed** | **closed** | **closed** | done | `area-focused` | `feat(app-distribution)!: migrate app-distribution to TurboModules` | Committed 2026-06-30. | +| Phase 2 `ml` | P2e | **closed** | **closed** | **open** | `commit` | `area-focused` | `feat(ml)!: migrate ml to TurboModules` | Review green 2026-06-30. | +| Phase 3 `app-check` | P3a | **open** | **open** | **open** | `implementation` | `unit-focused` | `feat(app-check)!: migrate app-check to TurboModules` | Tier C; 7 methods; 1 event. | +| Phase 3 `remote-config` | P3b | **open** | **open** | **open** | `implementation` | `unit-focused` | `feat(remote-config)!: migrate remote-config to TurboModules` | Tier C; 11 methods; 1 event. | +| Phase 3 `analytics` | P3c | **open** | **open** | **open** | `implementation` | `unit-focused` | `feat(analytics)!: migrate analytics to TurboModules` | Tier C; 11 methods; 0 events. | +| Phase 3 `crashlytics` | P3d | **open** | **open** | **open** | `implementation` | `unit-focused` | `feat(crashlytics)!: migrate crashlytics to TurboModules` | Tier C; 14 methods; 0 events. | +| Phase 3 `storage` | P3e | **open** | **open** | **open** | `implementation` | `unit-focused` | `feat(storage)!: migrate storage to TurboModules` | Tier C; 14 methods; 1 event. | --- diff --git a/okf-bundle/new-architecture/turbomodule-implementation-workflow.md b/okf-bundle/new-architecture/turbomodule-implementation-workflow.md index 16b1399c67..ca370b058e 100644 --- a/okf-bundle/new-architecture/turbomodule-implementation-workflow.md +++ b/okf-bundle/new-architecture/turbomodule-implementation-workflow.md @@ -55,7 +55,7 @@ Phase 0 `app` is the first package with **two TurboModule specs in one `codegenC 1. Inventory `@ReactMethod` / `RCT_EXPORT_METHOD` from existing Java/ObjC sources. 2. Draft `specs/NativeRNFBTurbo*.ts` — strong types from `lib/types/internal.ts` and firebase-js-sdk shapes; `Object` / open maps only for genuinely dynamic payloads. 3. Naming: `NativeRNFBTurbo*` prefix (decision [NewArch-AD-2](architecture-decisions.md#newarch-ad-2--naming-nativernfbturbo--accepted)). -4. Run `yarn codegen` in the package; commit generated output under `android/.../generated` and `ios/generated`. +4. Regenerate codegen output; commit under `android/.../generated` and `ios/generated` — [§ Running codegen](#running-codegen-canonical). 5. For Phase 0 (`app`): include unified module resolver work in `packages/app` ([queue § reference pattern](migration-work-queue.md#reference-pattern-functions)). 6. **NewArch-AD-18 raw-resolver audit:** `grep` product code for `getReactNativeModule(` (exclude `packages/app/lib/internal/nativeModule*.ts` infrastructure). For each hit, compare against the [NewArch-AD-18 canonical exception table](architecture-decisions.md#canonical-exception-table): existing row → confirm turbo module name + in-code `// NewArch-AD-18 E:` comment; unlisted → bug (legacy name / should be wrapped) or new exception (add ADR row + rationale **before** merge). Every package migration PR must leave no unlisted raw call sites in that package's scope. @@ -92,6 +92,52 @@ Per package, repeat the [`functions`](../../../packages/functions/) shape: 6. **JS** — update namespace config; no public API changes unless unavoidable. 7. **Native business logic** — prefer keeping ObjC++/Java shell + existing Swift helpers; language modernization is out of scope ([queue rationale](migration-work-queue.md#reference-pattern-functions)). +### TurboModule native registration checklist (blocking) + +Repeat for **every** package migration. Skipping any row is the usual cause of `TypeError: new Proxy target must be an Object` (Android) or `Native module NativeRNFBTurbo* is not registered` (iOS/macOS) at runtime. + +| # | Layer | Requirement | Reference | +|---|-------|-------------|-----------| +| 1 | **Spec** | `specs/NativeRNFBTurbo*.ts`; module name = `TurboModuleRegistry.get` key. When JS reads `this.native.` (e.g. `perf`, `in-app-messaging`, `app`, `utils`), declare **`getConstants(): { … }`** in the spec — without it, codegen omits `getConstants` from the JSI method map and `withTurboConstants` has nothing to merge (runtime **`undefined`** on both platforms). | [`app/specs/NativeRNFBTurboApp.ts`](../../../packages/app/specs/NativeRNFBTurboApp.ts) | +| 2 | **codegenConfig** | `name` = aggregate library `RNFBTurboModules` (not the module name); `includesGeneratedCode: true`; `ios.modulesProvider` maps spec name → ObjC shell class | [`firestore/package.json`](../../../packages/firestore/package.json) | +| 3 | **codegen output** | Regenerate and commit `android/.../generated/` + `ios/generated/` — see [§ Running codegen](#running-codegen-canonical) | [NewArch-AD-5](architecture-decisions.md#newarch-ad-5--commit-generated-code--accepted) | +| 4 | **react-native.config.js** | `platforms.android.cmakeListsPath` → committed `generated/jni/CMakeLists.txt` — path is **relative to package root** and must match `android:codegen` `outputPath` (no duplicate `android/` prefix) | [`firestore/react-native.config.js`](../../../packages/firestore/react-native.config.js) | +| 5 | **CMake macro** | Generated `CMakeLists.txt` must use the macro for the **test app's RN version** (`tests/package.json`): **`target_compile_options`** on RN **0.78**; **`target_compile_reactnative_options`** on RN **0.81+**. Wrong macro → Android CMake configure fails or JNI never links. After `yarn codegen`, diff against [`functions`](../../../packages/functions/android/src/main/java/io/invertase/firebase/functions/generated/jni/CMakeLists.txt) (0.78) or re-run codegen when the test app upgrades. | [§ Android codegen wiring](#turbomodule-implementation) step 3 | +| 6 | **Android shell** | `NativeRNFBTurbo*` extends generated `*Spec`; **only** turbo shells registered in `ReactPackage.createNativeModules`. When the spec declares `getConstants`, implement **`protected getTypedExportedConstants()`** (generated `*Spec` owns `public getConstants()`), not a standalone `public getConstants()` override. | [`perf/.../NativeRNFBTurboPerf.java`](../../../packages/perf/android/src/reactnative/java/io/invertase/firebase/perf/NativeRNFBTurboPerf.java) | +| 7 | **Android build.gradle** | New-arch guard (`newArchEnabled`); `sourceSets { java.excludes = ['**/generated/jni/**'] }` when jni lives under `java.srcDirs` | [`firestore/android/build.gradle`](../../../packages/firestore/android/build.gradle) | +| 8 | **iOS shell** | `.mm`: `RCT_EXPORT_MODULE(NativeRNFBTurbo*)` (exact spec name); `getTurboModule:` → `NativeRNFBTurbo*SpecJSI`; `.h` imports `RNFBTurboModules.h` and conforms to `NativeRNFBTurbo*Spec` (class extension or header — see [`functions`](../../../packages/functions/ios/RNFBFunctions/RNFBFunctionsModule.h)). **Constants:** when the spec declares `getConstants`, use **typed** `facebook::react::ModuleConstants` + `[_RCTTypedModuleConstants newWithUnsafeDictionary:…]` — **not** legacy `- (NSDictionary *)getConstants` / `constantsToExport` (JSI never surfaces those to `TurboModuleRegistry.get`). | [`app/.../RNFBAppModule.mm`](../../../packages/app/ios/RNFBApp/RNFBAppModule.mm) | +| 9 | **Podspec** | `install_modules_dependencies(s)`; new-arch guard; `exclude_files` for duplicate RN codegen providers (`RCTModuleProviders.*`, etc.). Add `pod_target_xcconfig` `HEADER_SEARCH_PATHS` → `ios/generated/RNFBTurboModules` + `ios/generated` when Xcode cannot find generated spec headers (see [`firestore/RNFBFirestore.podspec`](../../../packages/firestore/RNFBFirestore.podspec)). | [`functions/RNFBFunctions.podspec`](../../../packages/functions/RNFBFunctions.podspec) | +| 10 | **JS** | `nativeModuleName` → turbo name; `turboModule: true`; web shim registers turbo name | [`firestore/lib/FirestoreModule.ts`](../../../packages/firestore/lib/FirestoreModule.ts) | +| 11 | **jest.setup.ts** | Mock `NativeRNFBTurbo*` (not legacy `RNFB*Module`) with methods on the correct host; include `getConstants: () => ({ … })` when the package reads constants | [`jest.setup.ts`](../../../jest.setup.ts) | +| 12 | **Native rebuild** | After steps 1–11: **`yarn tests:android:build`** and/or **`yarn tests:ios:build`** — Jest green alone does **not** prove native registration. **Android:** `autolinkLibrariesFromCommand` caches `tests/android/build/generated/autolinking/autolinking.json` keyed only on `tests/{package.json,yarn.lock,react-native.config.js}` — adding or changing a **package** `react-native.config.js` does **not** invalidate the cache; delete `autolinking.json` + `*.sha` under that folder (or touch `tests/package.json`) then rebuild, or JNI never links (`Proxy target must be an Object`). **iOS:** `yarn tests:ios:build` runs `pod install` + Xcode compile; required after codegen / `modulesProvider` / podspec changes. | [`tests/android/settings.gradle`](../../../tests/android/settings.gradle) | + +**Symptom → likely miss:** Android `Proxy target must be an object` → rows **4–7** or **12** (CMake not linked / **stale autolinking cache**). JS reads **`undefined`** for `this.native.isFoo` / constant-backed getters on **either platform** → row **1** (spec missing `getConstants`), row **6** (Android `getTypedExportedConstants`), row **8** (iOS still using `NSDictionary` constants). Metro redbox **`Requiring unknown module "undefined"`** at app load (before Jet connects) → **not** a registration miss — [stale JS/native toolchain](../testing/running-e2e.md#turbomodule-stale-toolchain-blocking); run checklist row **12** + Metro reset-cache; escalate to [full toolchain refresh](../testing/running-e2e.md#turbomodule-full-toolchain-refresh) if it persists. iOS `Native module NativeRNFBTurbo* is not registered` → rows **2**, **8**, **9**, **12**. iOS `unrecognized selector` on turbo method → row **8** (legacy `RCT_EXPORT_METHOD` signatures instead of spec protocol). iOS build missing generated header → row **9** (`HEADER_SEARCH_PATHS`). + +### Running codegen (canonical) + +Package `package.json` scripts (`yarn android:codegen` / `yarn ios:codegen`) are convenience wrappers; **`cd packages/ && yarn ios:codegen` often fails** after a clean install (`unknown command 'codegen'`) because `@react-native-community/cli` resolves from the **test app** workspace, not the library package cwd. + +**Canonical** — from repo root, `cd tests`, one platform at a time; `--outputPath` must match the package's `android:codegen` / `ios:codegen` script (paths differ per package — copy from [`functions/package.json`](../../../packages/functions/package.json)): + +```bash +cd tests +npx @react-native-community/cli codegen \ + --path ../packages/ \ + --platform android \ + --source library \ + --outputPath ../packages// + +npx @react-native-community/cli codegen \ + --path ../packages/ \ + --platform ios \ + --source library \ + --outputPath ../packages//ios/generated +``` + +Example (`perf` Android): `--outputPath ../packages/perf/android/src/reactnative/java/io/invertase/firebase/perf/generated`. + +After regen: commit generated dirs, then [checklist row **12**](#turbomodule-native-registration-checklist-blocking) (`:build` + Metro reset-cache before `:test-cover`). + **Unit-focused** tier per [change authoring § implementation inner loop](../testing/change-authoring-workflow.md#implementation-inner-loop) and [TurboModule area harness](#turbomodule-area-harness) below. Shared infrastructure (already landed for `functions`): @@ -113,13 +159,20 @@ Extends [change authoring § harness narrowing](../testing/change-authoring-work **Area setup (required for `unit-focused` and `area-focused` tiers):** copy [`tests/harness.overrides.example.js`](../../../tests/harness.overrides.example.js) to gitignored `tests/harness.overrides.js` — set `modules` to the package under migration and `RNFBDebug: true`. Load that package's full `packages//e2e/*.e2e.js` specs via committed `require.context` ([running e2e § local overrides](../testing/running-e2e.md#local-harness-overrides-harnessoverridesjs)). -| Package | Typical e2e entry | -|---------|-------------------| -| `app` | `packages/app/e2e/` | -| `auth` | `packages/auth/e2e/` | -| `firestore` | `packages/firestore/e2e/` (may coexist with Pipeline specs — load package module only) | -| `functions` | `packages/functions/e2e/` (reference; already migrated) | -| Others | `packages//e2e/` | +| Package | Harness `modules` key | Typical e2e entry | +|---------|----------------------|-------------------| +| `app` | `app` | `packages/app/e2e/` | +| `auth` | `auth` | `packages/auth/e2e/` | +| `firestore` | `firestore` | `packages/firestore/e2e/` (may coexist with Pipeline specs — load package module only) | +| `functions` | `functions` | `packages/functions/e2e/` (reference; already migrated) | +| `in-app-messaging` | `inAppMessaging` | `packages/in-app-messaging/e2e/` | +| `app-distribution` | `appDistribution` | `packages/app-distribution/e2e/` | +| `installations` | `installations` | `packages/installations/e2e/` | +| `perf` | `perf` | `packages/perf/e2e/` | +| `ml` | `ml` | `packages/ml/e2e/` | +| Others | match `platformSupportedModules` key in [`tests/app.js`](../../../tests/app.js) | `packages//e2e/` | + +**Harness key ≠ npm folder name** for camelCase entries (`inAppMessaging`, `appDistribution`, `remoteConfig`, …). Always copy the string from `tests/app.js` `platformSupportedModules` — wrong keys load zero specs or the wrong package ([Phase 2 review pitfall](migration-work-queue.md#current-snapshot)). **Sanity check:** pass counts must match loaded scope — not full-app totals ([running e2e § gate](../testing/running-e2e.md#harness-narrowing-gate-blocking)). @@ -182,7 +235,14 @@ Breaking change (`!`): TurboModule migration requires New Architecture; legacy b * **Android cross-module native shared state** ([NewArch-AD-10](architecture-decisions.md#newarch-ad-10--cross-package-native-state-is-centralized-in-app-with-testable-apis--accepted)) — turbo shells may expose **`public static` fields** read by other packages' native code. Phase 0: **`NativeRNFBTurboApp.authDomains`** (populated on `initializeApp`; read by [`RCTConvertFirebase`](../../../packages/app/android/src/reactnative/java/io/invertase/firebase/common/RCTConvertFirebase.java) and [`ReactNativeFirebaseAuthModule`](../../../packages/auth/android/src/main/java/io/invertase/firebase/auth/ReactNativeFirebaseAuthModule.java)). Unregistered legacy bridge classes may **delegate** to the turbo shell — do not duplicate the map on legacy classes. * **iOS auth-domain naming** — iOS keeps historical **`customAuthDomains`** + `getCustomDomain:` on the turbo shell ([`RNFBAppModule.mm`](../../../packages/app/ios/RNFBApp/RNFBAppModule.mm)); Android uses **`authDomains`** on [`NativeRNFBTurboApp`](../../../packages/app/android/src/reactnative/java/io/invertase/firebase/app/NativeRNFBTurboApp.java). Same semantics; intentional cross-platform naming carry-over. * **Spec Promise typing (Android)** — Codegen Android methods take **`Promise` args** even when the legacy bridge was sync void. Example: Play Services helpers in [`NativeRNFBTurboUtils`](../../../packages/app/specs/NativeRNFBTurboUtils.ts) — declare `Promise` / `Promise`; native resolves the promise. +* **Android codegen output path families** — always copy `android:codegen` `outputPath` from the target `package.json` (do not assume one layout). **`src/reactnative/java/.../generated`**: `app`, `firestore`, `perf`, `in-app-messaging`, `ml`. **`src/main/java/.../generated`**: `functions`, `installations`, `app-distribution`. `react-native.config.js` `cmakeListsPath` must match the same tree. +* **Duplicate generated trees** — a wrong initial `outputPath` or regen into a second folder leaves **two** `generated/` trees (e.g. `src/main/java` + `src/reactnative/java`, or `fiam/` + `in_app_messaging/`). Android then fails with `duplicate class: NativeRNFBTurbo*Spec`. Keep **one** canonical tree; delete stale dirs; align shell imports, `build.gradle` `sourceSets`, and `cmakeListsPath`. * **Dead legacy shells** — unregistered legacy Java modules (e.g. [`ReactNativeFirebaseAppModule`](../../../packages/app/android/src/reactnative/java/io/invertase/firebase/app/ReactNativeFirebaseAppModule.java)) may remain temporarily when the package registers turbo shells only. **Not a Phase 0 blocker** — track deletion as follow-on cleanup once the turbo path is verified. +* **CMake macro vs test-app RN version** — see [registration checklist § row 5](#turbomodule-native-registration-checklist-blocking). `yarn codegen` uses root `@react-native/codegen`; if it emits `target_compile_reactnative_options` but the test app is still RN 0.78, replace with `target_compile_options` (copy from [`functions` CMakeLists](../../../packages/functions/android/src/main/java/io/invertase/firebase/functions/generated/jni/CMakeLists.txt)) before first `:test-cover`. +* **TurboModule constants (both platforms)** — legacy bridge exposed constants as enumerable keys on the module object. TurboModules require the full chain in [checklist rows 1, 6, 8](#turbomodule-native-registration-checklist-blocking): spec `getConstants()` → codegen → Android `getTypedExportedConstants` → iOS typed `ModuleConstants` + `_RCTTypedModuleConstants` → `withTurboConstants` in [`nativeModuleAndroidIos.ts`](../../../packages/app/lib/internal/nativeModuleAndroidIos.ts). Skipping the spec or leaving iOS on `NSDictionary *` produces **`undefined`** in constructors like `this._foo = this.native.isFoo` even when methods work. Packages without constants (`functions`, `installations`, …) skip the constants rows. +* **Android autolinking cache** — see checklist row **12**. `npx react-native config` can show the correct `cmakeListsPath` while `tests/android/build/generated/autolinking/autolinking.json` is still stale. +* **Metro `Requiring unknown module "undefined"`** — Metro runtime error when `require()` gets module id `undefined`. **Not** the same as native constant `undefined` or `Proxy target must be an Object`. Usually **stale Metro cache and/or partial refresh** after spec/codegen/`lib/**`/podspec changes while iOS/Android debug still loads a **live** bundle from `:8081` ([running e2e § stale toolchain](../testing/running-e2e.md#turbomodule-stale-toolchain-blocking)). A static `index.bundle` fetch can succeed while the simulator still shows the redbox — treat as toolchain staleness, not a missing `import`. Escalation: [full toolchain refresh](../testing/running-e2e.md#turbomodule-full-toolchain-refresh). +* **Codegen CLI cwd** — see [§ Running codegen](#running-codegen-canonical). Do not debug `unknown command 'codegen'` by patching package scripts; run from `tests/`. * **phone-number-verification** — bypasses `createModuleNamespace`; wire spec + resolver directly in `modular.ts`. Live phase status and arbiter gates: [migration work queue](migration-work-queue.md) (ephemeral). diff --git a/okf-bundle/testing/agent-command-policy.md b/okf-bundle/testing/agent-command-policy.md index 63710d1e56..a795391399 100644 --- a/okf-bundle/testing/agent-command-policy.md +++ b/okf-bundle/testing/agent-command-policy.md @@ -95,6 +95,12 @@ Single source for **which shell commands agents may run** in this repo. E2e is a - **`yarn jet --help`** working or failing in `tests/` is **not** a valid e2e or install gate. - Jet is started **internally** by `yarn tests::test-cover`. Stale `:8090` → [pre-flight recovery](running-e2e.md#pre-flight-recovery), then re-run the same `:test-cover` command. +### TurboModule codegen + +- **`cd packages/ && yarn ios:codegen`** (or `yarn android:codegen`) often fails with **`unknown command 'codegen'`** after a clean `yarn` — `@react-native-community/cli` resolves from the **test app** workspace. +- **Canonical:** [turbomodule workflow § Running codegen](../new-architecture/turbomodule-implementation-workflow.md#running-codegen-canonical) — `cd tests`, `npx @react-native-community/cli codegen --path ../packages/ …` with `--outputPath` copied from that package's `package.json` script. +- After regen: commit `android/.../generated` + `ios/generated`, then `:build` + Metro reset-cache before `:test-cover`. + ## Subagent handoff Paste into Task / explore / work-queue prompts: diff --git a/okf-bundle/testing/running-e2e.md b/okf-bundle/testing/running-e2e.md index 84f97d145d..1b16d82260 100644 --- a/okf-bundle/testing/running-e2e.md +++ b/okf-bundle/testing/running-e2e.md @@ -43,6 +43,7 @@ yarn tests:emulator:start 3. **Rebuild when needed** - Native changed → `yarn tests:ios:build` / `yarn tests:android:build` before e2e. macOS uses firebase-js-sdk only — no native rebuild. - `packages/*/lib/**` changed → **`yarn lerna:prepare` must run to completion (exit 0) before anything else** — Metro serves `dist/module/**`, not `lib/**`. See [prepare completion gate](#prepare-completion-gate-blocking) and [agent command policy § prepare must finish first](agent-command-policy.md#prepare-must-finish-first). After prepare finishes, restart the packager with `yarn tests:packager:jet-reset-cache` when Metro was already running ([Rules §1](#rules)). + - TurboModule **codegen / spec / podspec / native shell** changed → same as native changed, plus regen codegen ([workflow § Running codegen](../new-architecture/turbomodule-implementation-workflow.md#running-codegen-canonical)) when specs changed; if app loads with Metro redbox `Requiring unknown module "undefined"`, see [TurboModule stale toolchain](#turbomodule-stale-toolchain-blocking). - TS coverage: iOS/Android embed JS at **build** time; run `:build` before `:test-cover` so Istanbul + patched test-runner coverage upload is in app. macOS loads from Metro live; after test-runner patch changes, restart the packager with `yarn tests:packager:jet-reset-cache` ([Rules §1](#rules)). 4. **Always run with coverage:** @@ -521,6 +522,42 @@ Then resume the normal iOS loop: [pre-flight](#pre-flight-is-the-host-clear-to-s CI restores the same tree from `~/Library/Detox/ios` keyed by Xcode version ([iOS workflow § Detox Framework Cache Restore](../ci-workflows/ios.md)). Local developers must rebuild when the cache is missing — it is not committed to git. + + +### TurboModule migration — stale JS/native toolchain (blocking) + +During TurboModule work, three different **`undefined`** / load failures are easy to confuse — only the third row below is fixed by the [native registration checklist](../new-architecture/turbomodule-implementation-workflow.md#turbomodule-native-registration-checklist-blocking): + +| Symptom | Likely cause | Fix (escalate in order) | +|---------|----------------|-------------------------| +| `this.native.isFoo` is **`undefined`** in JS | Spec/native **constants** chain incomplete (`getConstants`, `getTypedExportedConstants`, iOS typed constants) | [Workflow checklist rows 1, 6, 8](../new-architecture/turbomodule-implementation-workflow.md#turbomodule-native-registration-checklist-blocking) | +| Android `Proxy target must be an Object` | JNI not linked / **stale autolinking cache** | Delete `tests/android/build/generated/autolinking/autolinking.json` + `*.sha`, `:build` | +| Metro redbox **`Requiring unknown module "undefined"`** at app load | **Stale Metro and/or partial native refresh** after codegen / `lib/**` / podspec changes | Steps below; then [full refresh](#turbomodule-full-toolchain-refresh) if needed | + +**Detect:** app redbox before `Jet client connected`; `curl` of `index.bundle` may still return 200 — that does **not** rule out staleness. + +**Routine fix** (try first after codegen, podspec, or `packages/*/lib/**` edits): + +1. [Prepare completion gate](#prepare-completion-gate-blocking) — `yarn lerna:prepare` exit 0. +2. Regenerate codegen if specs changed — [workflow § Running codegen](../new-architecture/turbomodule-implementation-workflow.md#running-codegen-canonical) (`cd tests`, `npx @react-native-community/cli codegen …`). +3. **`yarn tests::build`** (includes `pod install` on iOS when needed). +4. **`yarn tests:packager:jet-reset-cache`** (Metro was running during the edits). +5. [Pre-flight](#pre-flight-is-the-host-clear-to-start) → **`yarn tests::test-cover`**. + + + +**Full toolchain refresh** — when the routine fix still shows `Requiring unknown module "undefined"` or you wiped `node_modules` mid-migration: + +1. [Pre-flight recovery](#pre-flight-recovery) — stop Metro, Jet, Detox; shutdown booted simulators. +2. Remove **all** `node_modules` (repo root, `tests/`, and under `packages/*` if present). +3. **`yarn`** at repo root (wait for exit 0 — includes `lerna:prepare`). +4. Regenerate **all** touched packages' codegen from `tests/` ([workflow § Running codegen](../new-architecture/turbomodule-implementation-workflow.md#running-codegen-canonical)). +5. **`yarn tests:ios:pod:install`** when iOS native/codegen changed. +6. **`yarn tests::build`**. +7. **`yarn tests:packager:jet-reset-cache`** → pre-flight → `:test-cover`. + +Do **not** treat this redbox as a missing TurboModule registration until the refresh sequence has been run once on a clean tree. + ## Diagnosing hangs **Local stalls** — see [stalled run detection](#stalled-run-detection) first (Metro `/status`, `Jet client connected` markers). @@ -528,7 +565,7 @@ CI restores the same tree from `~/Library/Detox/ios` keyed by Xcode version ([iO **Native / device logs** (remove instrumentation before merge): - **macOS** — `log show --predicate 'process == "io.invertase.testing"' --last 10m --style compact`; filter `com.facebook.react.log:javascript` for bundle errors. **Blank window / Jet never connects:** often `Native module NativeRNFBTurboApp is not registered` — see [TurboModule workflow § gotchas — macOS web registration](../new-architecture/turbomodule-implementation-workflow.md#gotchas). Other bundle errors → [other.md](../ci-workflows/other.md) -- **iOS** — `xcrun simctl spawn booted log stream --level debug --style compact --predicate 'process == "testing"'`; silent hangs: `sample ` on `testing` +- **iOS** — `xcrun simctl spawn booted log stream --level debug --style compact --predicate 'process == "testing"'`; silent hangs: `sample ` on `testing`. Metro redbox **`Requiring unknown module "undefined"`** → [TurboModule stale toolchain](#turbomodule-stale-toolchain-blocking), not registration checklist alone. - **Android** — `adb logcat` (filter your tags) **Benign noise:** iOS Detox `EXEC_FAIL "xcrun simctl terminate … com.invertase.testing" … found nothing to terminate` — app wasn't running; ignore. @@ -541,7 +578,7 @@ Pre-merge applies once to the branch commit stream before merge/push intended fo 1. Remove all narrowing ([full tier](#e2e-validation-tiers-unit-focused-area-focused-full)): delete `tests/harness.overrides.js` (or `{}`), revert any temporary `require.context` → single `require` edits in `tests/app.js`, remove all `.only`, remove native instrumentation. Committed `tests/globals.js` / `tests/app.js` stay at full harness defaults — do not revert durable product wiring (e.g. `NativeRNFBTurbo*` proxy). 2. [Pre-flight](#pre-flight-is-the-host-clear-to-start) — [host-clear probes](#host-clear-probes) pass before each platform run. -3. Rebuild if needed (`tests::build`; `yarn lerna:prepare` for `lib/**`). +3. Rebuild when needed (`tests::build`; `yarn lerna:prepare` for `lib/**`). After TurboModule codegen or native bridge edits, see [TurboModule stale toolchain](#turbomodule-stale-toolchain-blocking). 4. Full unfocused suite with coverage on **iOS, Android, macOS** — one platform at a time, all green. ## Notes diff --git a/packages/ml/RNFBML.podspec b/packages/ml/RNFBML.podspec index 4ab7f0a7df..44b2eefd11 100644 --- a/packages/ml/RNFBML.podspec +++ b/packages/ml/RNFBML.podspec @@ -29,15 +29,16 @@ Pod::Spec.new do |s| s.ios.deployment_target = firebase_ios_target s.macos.deployment_target = firebase_macos_target s.tvos.deployment_target = firebase_tvos_target - s.source_files = 'ios/**/*.{h,m}' + s.source_files = 'ios/**/*.{h,m,mm,cpp,swift}' + s.private_header_files = "ios/**/*.h" + s.exclude_files = 'ios/generated/RCTThirdPartyComponentsProvider.*', 'ios/generated/RCTAppDependencyProvider.*', 'ios/generated/RCTModuleProviders.*', 'ios/generated/RCTModulesConformingToProtocolsProvider.*', 'ios/generated/RCTUnstableModulesRequiringMainQueueSetupProvider.*' s.dependency 'RNFBApp' - # React Native dependencies - if defined?(install_modules_dependencies()) != nil - install_modules_dependencies(s); - else - s.dependency "React-Core" + install_modules_dependencies(s); + + if defined?(ENV["RCT_NEW_ARCH_ENABLED"]) != nil && (ENV["RCT_NEW_ARCH_ENABLED"] == '0') + raise "#{s.name} requires New Architecture. Enable New Architecture to use this module" end if defined?($FirebaseSDKVersion) diff --git a/packages/ml/__tests__/nativeModuleContract.test.ts b/packages/ml/__tests__/nativeModuleContract.test.ts new file mode 100644 index 0000000000..f5b67a037f --- /dev/null +++ b/packages/ml/__tests__/nativeModuleContract.test.ts @@ -0,0 +1,36 @@ +import { describe, expect, it, jest } from '@jest/globals'; +import { TurboModuleRegistry } from 'react-native'; +import type { ModuleConfig } from '@react-native-firebase/app/dist/module/internal'; +import FirebaseModule from '@react-native-firebase/app/dist/module/internal/FirebaseModule'; +import { getNativeModule } from '@react-native-firebase/app/dist/module/internal/registry/nativeModule'; +import type { WrappedNativeModule } from '@react-native-firebase/app/dist/module/internal/NativeModules'; + +function createTurboModuleFixture(): Record { + return Object.create(Object.prototype); +} + +describe('TurboModule wrapper contract (NewArch-AD-17.1)', function () { + it('resolves an empty stub turbo module through the real wrapper', function () { + const raw = createTurboModuleFixture(); + jest.mocked(TurboModuleRegistry.get).mockReturnValueOnce(raw); + + const config: ModuleConfig = { + namespace: 'ml', + nativeModuleName: 'NativeRNFBTurboML', + nativeEvents: false, + hasMultiAppSupport: true, + hasCustomUrlOrRegionSupport: false, + turboModule: true, + }; + + class ContractModule extends FirebaseModule { + constructor() { + super({ name: '[DEFAULT]' } as any, config); + } + } + + const wrapped = getNativeModule(new ContractModule()) as WrappedNativeModule; + expect(wrapped).toBeDefined(); + expect(Object.keys(wrapped)).toEqual([]); + }); +}); diff --git a/packages/ml/android/build.gradle b/packages/ml/android/build.gradle index b05bb6fa43..6ceadccd99 100644 --- a/packages/ml/android/build.gradle +++ b/packages/ml/android/build.gradle @@ -81,6 +81,7 @@ android { sourceSets { main { java.srcDirs = ['src/main/java', 'src/reactnative/java'] + java.excludes = ['**/generated/jni/**'] } } } @@ -100,3 +101,21 @@ ReactNative.shared.applyPackageVersion() ReactNative.shared.applyDefaultExcludes() ReactNative.module.applyAndroidVersions() ReactNative.module.applyReactNativeDependency("api") + +def isNewArchitectureDisabled() { + return project.hasProperty("newArchEnabled") && project.newArchEnabled != "true" +} + +if (isNewArchitectureDisabled()) { + def ANSI_RED = "\u001B[31m"; + def ANSI_RESET = "\u001B[0m"; + + println("\n\n\n") + println(ANSI_RED + "**************************************************************************************************************") + println("\n\n\n") + println("New Architecture support is required for @react-native-firebase/ml") + println("\n\n\n") + println("**************************************************************************************************************" + ANSI_RESET) + println("\n\n\n") + System.exit(1) +} diff --git a/packages/ml/android/src/reactnative/java/io/invertase/firebase/ml/NativeRNFBTurboML.java b/packages/ml/android/src/reactnative/java/io/invertase/firebase/ml/NativeRNFBTurboML.java new file mode 100644 index 0000000000..5c08189f16 --- /dev/null +++ b/packages/ml/android/src/reactnative/java/io/invertase/firebase/ml/NativeRNFBTurboML.java @@ -0,0 +1,27 @@ +package io.invertase.firebase.ml; + +/* + * Copyright (c) 2016-present Invertase Limited & Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this library except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import com.facebook.fbreact.specs.NativeRNFBTurboMLSpec; +import com.facebook.react.bridge.ReactApplicationContext; + +public class NativeRNFBTurboML extends NativeRNFBTurboMLSpec { + public NativeRNFBTurboML(ReactApplicationContext reactContext) { + super(reactContext); + } +} diff --git a/packages/ml/android/src/reactnative/java/io/invertase/firebase/ml/ReactNativeFirebaseMLPackage.java b/packages/ml/android/src/reactnative/java/io/invertase/firebase/ml/ReactNativeFirebaseMLPackage.java index ffb7c9c8a9..1481f89bad 100644 --- a/packages/ml/android/src/reactnative/java/io/invertase/firebase/ml/ReactNativeFirebaseMLPackage.java +++ b/packages/ml/android/src/reactnative/java/io/invertase/firebase/ml/ReactNativeFirebaseMLPackage.java @@ -32,6 +32,7 @@ public class ReactNativeFirebaseMLPackage implements ReactPackage { @Override public List createNativeModules(@Nonnull ReactApplicationContext reactContext) { List modules = new ArrayList<>(); + modules.add(new NativeRNFBTurboML(reactContext)); return modules; } diff --git a/packages/ml/android/src/reactnative/java/io/invertase/firebase/ml/generated/java/com/facebook/fbreact/specs/NativeRNFBTurboMLSpec.java b/packages/ml/android/src/reactnative/java/io/invertase/firebase/ml/generated/java/com/facebook/fbreact/specs/NativeRNFBTurboMLSpec.java new file mode 100644 index 0000000000..3e476a2556 --- /dev/null +++ b/packages/ml/android/src/reactnative/java/io/invertase/firebase/ml/generated/java/com/facebook/fbreact/specs/NativeRNFBTurboMLSpec.java @@ -0,0 +1,35 @@ + +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleJavaSpec.js + * + * @nolint + */ + +package com.facebook.fbreact.specs; + +import com.facebook.proguard.annotations.DoNotStrip; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReactContextBaseJavaModule; +import com.facebook.react.bridge.ReactMethod; +import com.facebook.react.turbomodule.core.interfaces.TurboModule; +import javax.annotation.Nonnull; + +public abstract class NativeRNFBTurboMLSpec extends ReactContextBaseJavaModule implements TurboModule { + public static final String NAME = "NativeRNFBTurboML"; + + public NativeRNFBTurboMLSpec(ReactApplicationContext reactContext) { + super(reactContext); + } + + @Override + public @Nonnull String getName() { + return NAME; + } + + +} diff --git a/packages/ml/android/src/reactnative/java/io/invertase/firebase/ml/generated/jni/CMakeLists.txt b/packages/ml/android/src/reactnative/java/io/invertase/firebase/ml/generated/jni/CMakeLists.txt new file mode 100644 index 0000000000..669b36f63a --- /dev/null +++ b/packages/ml/android/src/reactnative/java/io/invertase/firebase/ml/generated/jni/CMakeLists.txt @@ -0,0 +1,36 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +cmake_minimum_required(VERSION 3.13) +set(CMAKE_VERBOSE_MAKEFILE on) + +file(GLOB react_codegen_SRCS CONFIGURE_DEPENDS *.cpp react/renderer/components/RNFBMLTurboModules/*.cpp) + +add_library( + react_codegen_RNFBMLTurboModules + OBJECT + ${react_codegen_SRCS} +) + +target_include_directories(react_codegen_RNFBMLTurboModules PUBLIC . react/renderer/components/RNFBMLTurboModules) + +target_link_libraries( + react_codegen_RNFBMLTurboModules + fbjni + jsi + # We need to link different libraries based on whether we are building rncore or not, that's necessary + # because we want to break a circular dependency between react_codegen_rncore and reactnative + reactnative +) + +target_compile_options( + react_codegen_RNFBMLTurboModules + PRIVATE + -DLOG_TAG=\"ReactNative\" + -fexceptions + -frtti + -std=c++20 + -Wall +) diff --git a/packages/ml/android/src/reactnative/java/io/invertase/firebase/ml/generated/jni/RNFBMLTurboModules-generated.cpp b/packages/ml/android/src/reactnative/java/io/invertase/firebase/ml/generated/jni/RNFBMLTurboModules-generated.cpp new file mode 100644 index 0000000000..8b735ce82a --- /dev/null +++ b/packages/ml/android/src/reactnative/java/io/invertase/firebase/ml/generated/jni/RNFBMLTurboModules-generated.cpp @@ -0,0 +1,29 @@ + +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleJniCpp.js + */ + +#include "RNFBMLTurboModules.h" + +namespace facebook::react { + + + +NativeRNFBTurboMLSpecJSI::NativeRNFBTurboMLSpecJSI(const JavaTurboModule::InitParams ¶ms) + : JavaTurboModule(params) { + +} + +std::shared_ptr RNFBMLTurboModules_ModuleProvider(const std::string &moduleName, const JavaTurboModule::InitParams ¶ms) { + if (moduleName == "NativeRNFBTurboML") { + return std::make_shared(params); + } + return nullptr; +} + +} // namespace facebook::react diff --git a/packages/ml/android/src/reactnative/java/io/invertase/firebase/ml/generated/jni/RNFBMLTurboModules.h b/packages/ml/android/src/reactnative/java/io/invertase/firebase/ml/generated/jni/RNFBMLTurboModules.h new file mode 100644 index 0000000000..1c62f64436 --- /dev/null +++ b/packages/ml/android/src/reactnative/java/io/invertase/firebase/ml/generated/jni/RNFBMLTurboModules.h @@ -0,0 +1,31 @@ + +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleJniH.js + */ + +#pragma once + +#include +#include +#include + +namespace facebook::react { + +/** + * JNI C++ class for module 'NativeRNFBTurboML' + */ +class JSI_EXPORT NativeRNFBTurboMLSpecJSI : public JavaTurboModule { +public: + NativeRNFBTurboMLSpecJSI(const JavaTurboModule::InitParams ¶ms); +}; + + +JSI_EXPORT +std::shared_ptr RNFBMLTurboModules_ModuleProvider(const std::string &moduleName, const JavaTurboModule::InitParams ¶ms); + +} // namespace facebook::react diff --git a/packages/ml/android/src/reactnative/java/io/invertase/firebase/ml/generated/jni/react/renderer/components/RNFBMLTurboModules/RNFBMLTurboModulesJSI-generated.cpp b/packages/ml/android/src/reactnative/java/io/invertase/firebase/ml/generated/jni/react/renderer/components/RNFBMLTurboModules/RNFBMLTurboModulesJSI-generated.cpp new file mode 100644 index 0000000000..50e4c17953 --- /dev/null +++ b/packages/ml/android/src/reactnative/java/io/invertase/firebase/ml/generated/jni/react/renderer/components/RNFBMLTurboModules/RNFBMLTurboModulesJSI-generated.cpp @@ -0,0 +1,22 @@ +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleCpp.js + */ + +#include "RNFBMLTurboModulesJSI.h" + +namespace facebook::react { + + + +NativeRNFBTurboMLCxxSpecJSI::NativeRNFBTurboMLCxxSpecJSI(std::shared_ptr jsInvoker) + : TurboModule("NativeRNFBTurboML", jsInvoker) { + +} + + +} // namespace facebook::react diff --git a/packages/ml/android/src/reactnative/java/io/invertase/firebase/ml/generated/jni/react/renderer/components/RNFBMLTurboModules/RNFBMLTurboModulesJSI.h b/packages/ml/android/src/reactnative/java/io/invertase/firebase/ml/generated/jni/react/renderer/components/RNFBMLTurboModules/RNFBMLTurboModulesJSI.h new file mode 100644 index 0000000000..0de07923d0 --- /dev/null +++ b/packages/ml/android/src/reactnative/java/io/invertase/firebase/ml/generated/jni/react/renderer/components/RNFBMLTurboModules/RNFBMLTurboModulesJSI.h @@ -0,0 +1,64 @@ +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleH.js + */ + +#pragma once + +#include +#include + +namespace facebook::react { + + + class JSI_EXPORT NativeRNFBTurboMLCxxSpecJSI : public TurboModule { +protected: + NativeRNFBTurboMLCxxSpecJSI(std::shared_ptr jsInvoker); + +public: + + +}; + +template +class JSI_EXPORT NativeRNFBTurboMLCxxSpec : public TurboModule { +public: + jsi::Value create(jsi::Runtime &rt, const jsi::PropNameID &propName) override { + return delegate_.create(rt, propName); + } + + std::vector getPropertyNames(jsi::Runtime& runtime) override { + return delegate_.getPropertyNames(runtime); + } + + static constexpr std::string_view kModuleName = "NativeRNFBTurboML"; + +protected: + NativeRNFBTurboMLCxxSpec(std::shared_ptr jsInvoker) + : TurboModule(std::string{NativeRNFBTurboMLCxxSpec::kModuleName}, jsInvoker), + delegate_(reinterpret_cast(this), jsInvoker) {} + + +private: + class Delegate : public NativeRNFBTurboMLCxxSpecJSI { + public: + Delegate(T *instance, std::shared_ptr jsInvoker) : + NativeRNFBTurboMLCxxSpecJSI(std::move(jsInvoker)), instance_(instance) { + + } + + + + private: + friend class NativeRNFBTurboMLCxxSpec; + T *instance_; + }; + + Delegate delegate_; +}; + +} // namespace facebook::react diff --git a/packages/ml/ios/RNFBML/RNFBMLModule.h b/packages/ml/ios/RNFBML/RNFBMLModule.h new file mode 100644 index 0000000000..c81ffc730d --- /dev/null +++ b/packages/ml/ios/RNFBML/RNFBMLModule.h @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2016-present Invertase Limited & Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this library except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#import +#import "RNFBMLTurboModules.h" + +@interface RNFBMLModule : NSObject + +@end diff --git a/packages/ml/ios/RNFBML/RNFBMLModule.mm b/packages/ml/ios/RNFBML/RNFBMLModule.mm new file mode 100644 index 0000000000..e59ab53ac9 --- /dev/null +++ b/packages/ml/ios/RNFBML/RNFBMLModule.mm @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2016-present Invertase Limited & Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this library except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#import "RNFBMLModule.h" + +@implementation RNFBMLModule + +RCT_EXPORT_MODULE(NativeRNFBTurboML) + ++ (BOOL)requiresMainQueueSetup { + return NO; +} + +- (std::shared_ptr)getTurboModule: + (const facebook::react::ObjCTurboModule::InitParams &)params { + return std::make_shared(params); +} + +@end diff --git a/packages/ml/ios/generated/RNFBMLTurboModules/RNFBMLTurboModules-generated.mm b/packages/ml/ios/generated/RNFBMLTurboModules/RNFBMLTurboModules-generated.mm new file mode 100644 index 0000000000..0ab9a97287 --- /dev/null +++ b/packages/ml/ios/generated/RNFBMLTurboModules/RNFBMLTurboModules-generated.mm @@ -0,0 +1,34 @@ +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleObjCpp + * + * We create an umbrella header (and corresponding implementation) here since + * Cxx compilation in BUCK has a limitation: source-code producing genrule()s + * must have a single output. More files => more genrule()s => slower builds. + */ + +#import "RNFBMLTurboModules.h" + + +@implementation NativeRNFBTurboMLSpecBase + + +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper +{ + _eventEmitterCallback = std::move(eventEmitterCallbackWrapper->_eventEmitterCallback); +} +@end + + +namespace facebook::react { + + + NativeRNFBTurboMLSpecJSI::NativeRNFBTurboMLSpecJSI(const ObjCTurboModule::InitParams ¶ms) + : ObjCTurboModule(params) { + + } +} // namespace facebook::react diff --git a/packages/ml/ios/generated/RNFBMLTurboModules/RNFBMLTurboModules.h b/packages/ml/ios/generated/RNFBMLTurboModules/RNFBMLTurboModules.h new file mode 100644 index 0000000000..136e63c33b --- /dev/null +++ b/packages/ml/ios/generated/RNFBMLTurboModules/RNFBMLTurboModules.h @@ -0,0 +1,62 @@ +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleObjCpp + * + * We create an umbrella header (and corresponding implementation) here since + * Cxx compilation in BUCK has a limitation: source-code producing genrule()s + * must have a single output. More files => more genrule()s => slower builds. + */ + +#ifndef __cplusplus +#error This file must be compiled as Obj-C++. If you are importing it, you must change your file extension to .mm. +#endif + +// Avoid multiple includes of RNFBMLTurboModules symbols +#ifndef RNFBMLTurboModules_H +#define RNFBMLTurboModules_H + +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import + + +NS_ASSUME_NONNULL_BEGIN + +@protocol NativeRNFBTurboMLSpec + + + +@end + +@interface NativeRNFBTurboMLSpecBase : NSObject { +@protected +facebook::react::EventEmitterCallback _eventEmitterCallback; +} +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper; + + +@end + +namespace facebook::react { + /** + * ObjC++ class for module 'NativeRNFBTurboML' + */ + class JSI_EXPORT NativeRNFBTurboMLSpecJSI : public ObjCTurboModule { + public: + NativeRNFBTurboMLSpecJSI(const ObjCTurboModule::InitParams ¶ms); + }; +} // namespace facebook::react + +NS_ASSUME_NONNULL_END +#endif // RNFBMLTurboModules_H diff --git a/packages/ml/ios/generated/RNFBMLTurboModulesJSI-generated.cpp b/packages/ml/ios/generated/RNFBMLTurboModulesJSI-generated.cpp new file mode 100644 index 0000000000..50e4c17953 --- /dev/null +++ b/packages/ml/ios/generated/RNFBMLTurboModulesJSI-generated.cpp @@ -0,0 +1,22 @@ +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleCpp.js + */ + +#include "RNFBMLTurboModulesJSI.h" + +namespace facebook::react { + + + +NativeRNFBTurboMLCxxSpecJSI::NativeRNFBTurboMLCxxSpecJSI(std::shared_ptr jsInvoker) + : TurboModule("NativeRNFBTurboML", jsInvoker) { + +} + + +} // namespace facebook::react diff --git a/packages/ml/ios/generated/RNFBMLTurboModulesJSI.h b/packages/ml/ios/generated/RNFBMLTurboModulesJSI.h new file mode 100644 index 0000000000..0de07923d0 --- /dev/null +++ b/packages/ml/ios/generated/RNFBMLTurboModulesJSI.h @@ -0,0 +1,64 @@ +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleH.js + */ + +#pragma once + +#include +#include + +namespace facebook::react { + + + class JSI_EXPORT NativeRNFBTurboMLCxxSpecJSI : public TurboModule { +protected: + NativeRNFBTurboMLCxxSpecJSI(std::shared_ptr jsInvoker); + +public: + + +}; + +template +class JSI_EXPORT NativeRNFBTurboMLCxxSpec : public TurboModule { +public: + jsi::Value create(jsi::Runtime &rt, const jsi::PropNameID &propName) override { + return delegate_.create(rt, propName); + } + + std::vector getPropertyNames(jsi::Runtime& runtime) override { + return delegate_.getPropertyNames(runtime); + } + + static constexpr std::string_view kModuleName = "NativeRNFBTurboML"; + +protected: + NativeRNFBTurboMLCxxSpec(std::shared_ptr jsInvoker) + : TurboModule(std::string{NativeRNFBTurboMLCxxSpec::kModuleName}, jsInvoker), + delegate_(reinterpret_cast(this), jsInvoker) {} + + +private: + class Delegate : public NativeRNFBTurboMLCxxSpecJSI { + public: + Delegate(T *instance, std::shared_ptr jsInvoker) : + NativeRNFBTurboMLCxxSpecJSI(std::move(jsInvoker)), instance_(instance) { + + } + + + + private: + friend class NativeRNFBTurboMLCxxSpec; + T *instance_; + }; + + Delegate delegate_; +}; + +} // namespace facebook::react diff --git a/packages/ml/lib/index.ts b/packages/ml/lib/index.ts index ccf1a77877..ba50275116 100644 --- a/packages/ml/lib/index.ts +++ b/packages/ml/lib/index.ts @@ -24,7 +24,7 @@ import './types/internal'; import type { FirebaseApp, FirebaseML } from './types/ml'; import { version } from './version'; -const nativeModuleName = 'RNFBMLModule'; +const nativeModuleName = 'NativeRNFBTurboML'; class FirebaseMLModule extends FirebaseModule {} @@ -34,6 +34,7 @@ const config: ModuleConfig = { nativeEvents: false, hasMultiAppSupport: true, hasCustomUrlOrRegionSupport: false, + turboModule: true, }; /** diff --git a/packages/ml/lib/types/internal.ts b/packages/ml/lib/types/internal.ts index a8e2529eed..916e497cfe 100644 --- a/packages/ml/lib/types/internal.ts +++ b/packages/ml/lib/types/internal.ts @@ -24,6 +24,6 @@ export interface RNFBMLModule {} declare module '@react-native-firebase/app/dist/module/internal/NativeModules' { interface ReactNativeFirebaseNativeModules { - RNFBMLModule: RNFBMLModule; + NativeRNFBTurboML: RNFBMLModule; } } diff --git a/packages/ml/package.json b/packages/ml/package.json index 079c999b48..6f66bdd941 100644 --- a/packages/ml/package.json +++ b/packages/ml/package.json @@ -5,11 +5,28 @@ "description": "React Native Firebase - Firebase ML brings the power of machine learning vision to your React Native application, supporting both Android & iOS.", "main": "./dist/module/index.js", "types": "./dist/typescript/lib/index.d.ts", + "codegenConfig": { + "name": "RNFBMLTurboModules", + "type": "modules", + "jsSrcsDir": "specs", + "includesGeneratedCode": true, + "android": { + "javaPackageName": "io.invertase.firebase.ml" + }, + "ios": { + "modulesProvider": { + "NativeRNFBTurboML": "RNFBMLModule" + } + } + }, "scripts": { "build": "genversion --esm --semi lib/version.ts", "build:clean": "rimraf android/build && rimraf ios/build", "compile": "bob build", - "prepare": "yarn run build && yarn compile" + "prepare": "yarn run build && yarn compile", + "codegen": "yarn android:codegen && yarn ios:codegen", + "android:codegen": "npx @react-native-community/cli codegen --platform android --outputPath=./android/src/reactnative/java/io/invertase/firebase/ml/generated", + "ios:codegen": "npx @react-native-community/cli codegen --platform ios --outputPath=./ios/generated" }, "repository": { "type": "git", diff --git a/packages/ml/react-native.config.js b/packages/ml/react-native.config.js new file mode 100644 index 0000000000..e164429c53 --- /dev/null +++ b/packages/ml/react-native.config.js @@ -0,0 +1,10 @@ +module.exports = { + dependency: { + platforms: { + android: { + cmakeListsPath: + './src/reactnative/java/io/invertase/firebase/ml/generated/jni/CMakeLists.txt', + }, + }, + }, +}; diff --git a/packages/ml/specs/NativeRNFBTurboML.ts b/packages/ml/specs/NativeRNFBTurboML.ts new file mode 100644 index 0000000000..63fcbf6a04 --- /dev/null +++ b/packages/ml/specs/NativeRNFBTurboML.ts @@ -0,0 +1,6 @@ +import type { TurboModule } from 'react-native'; +import { TurboModuleRegistry } from 'react-native'; + +export interface Spec extends TurboModule {} + +export default TurboModuleRegistry.getEnforcing('NativeRNFBTurboML'); diff --git a/tests/ios/Podfile.lock b/tests/ios/Podfile.lock index f94f8bb7a7..0113187476 100644 --- a/tests/ios/Podfile.lock +++ b/tests/ios/Podfile.lock @@ -204,7 +204,7 @@ PODS: - GTMSessionFetcher/Core (< 6.0, >= 3.4) - fmt (12.1.0) - glog (0.3.5) - - GoogleAdsOnDeviceConversion (3.6.0): + - GoogleAdsOnDeviceConversion (3.6.1): - GoogleUtilities/Environment (~> 8.1) - GoogleUtilities/Logger (~> 8.1) - GoogleUtilities/Network (~> 8.1) @@ -2531,7 +2531,7 @@ SPEC CHECKSUMS: FirebaseStorage: 949f0a5a8d8a77fff68ec8733057dc76a0e08179 fmt: 530618a01105dae0fa3a2f27c81ae11fa8f67eac glog: eb93e2f488219332457c3c4eafd2738ddc7e80b8 - GoogleAdsOnDeviceConversion: 80ce443fa1b4b5750913d53a04ecda644ff57744 + GoogleAdsOnDeviceConversion: e3b71da24ff4cf01cf520756ac1c2b93c07b86ff GoogleAppMeasurement: a6d37949071d456e9147dac6789c4342e0e7a8c5 GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7 GoogleUtilities: 766ace00c6b10d8148408f329d10c4f051931850 @@ -2605,17 +2605,17 @@ SPEC CHECKSUMS: RNFBAnalytics: 852e18e0161a43fa4009ef78e8249df60a074278 RNFBApp: 893629fc75425937059b0f64e58ec9d5a066aefc RNFBAppCheck: 5b0711c6f4f982fbe606f03e3b68f719c291371a - RNFBAppDistribution: 41758adfd29474d1244dfd0f17f0bd992c493051 + RNFBAppDistribution: 5fa4b64e4e62ffca3af9851a293b64ac801d11c1 RNFBAuth: 6656cfdec1c2c7a238666ab46f00f37650ea4e86 RNFBCrashlytics: 023cb897d12145878e749cc6c105e7ae6bb08996 RNFBDatabase: 6205ca9a46bb177b1577dbf1dad08c5ea018cd67 RNFBFirestore: 7b2480c59acae62bb9607cdf28c1e0e157641288 RNFBFunctions: d0ffe52e4f6138c3e42e69937b0592838e6f2cc9 - RNFBInAppMessaging: bcb89b77069691d903621c83cfc3a1d6bfcb43b2 - RNFBInstallations: 1073ed6c5b5f6da5378eca9f7c17bfbbd6deada6 + RNFBInAppMessaging: f2d87f6f01b538581e8db0454ef1028203eae1b3 + RNFBInstallations: 9e3d5aa14c2397002f97a0215f04a43841fe5b33 RNFBMessaging: 63037c34a83e479bca38d27bacb4baf485e4cde1 - RNFBML: 9b8147b6dcbe8b8da23cb1c7aa345f6f903c73a5 - RNFBPerf: 18e2f4786c1ee6ab62609c0b6236686716e41170 + RNFBML: 06b4f3115770b0bd748ff54e0bd4b0a1226f97d6 + RNFBPerf: 4f8174e09a34ef33e674ed069fb93a4e5d34a336 RNFBRemoteConfig: 373fc5298222ecaef439c00ab420c79e9a1e7d38 RNFBStorage: c53e4edb4f9984685cfd1adca4a16d161a353b42 SocketRocket: d4aabe649be1e368d1318fdf28a022d714d65748