diff --git a/.spellcheck.dict.txt b/.spellcheck.dict.txt index 046b6a1e8e..f31529f66a 100644 --- a/.spellcheck.dict.txt +++ b/.spellcheck.dict.txt @@ -27,6 +27,7 @@ AVD axios Axios backend +Backend backgrounded backoff barcode @@ -34,6 +35,7 @@ Barcode barcodes bridgeless BUGFIX +callables CarPlay CDN Changelog @@ -58,6 +60,7 @@ DEVEX DeviceCheck Diarmid Distribution +DOM dropdown EAS e2e @@ -73,6 +76,8 @@ Firebase firebase-admin firebase-ios-sdk firebase-js-sdk +firebase-js-sdk-shaped +firebase-js-sdk. FirebaseApp FirebaseCore firestore @@ -81,6 +86,7 @@ freeform GDPR GDPR-compliant getIdToken +getters github globals gradle @@ -109,11 +115,14 @@ Javascript JDK JS JSON +JSDoc +JWT lastDocument launchProperties learnt Lerna lifecycle +lockfiles macOS MDX mlkit @@ -122,6 +131,7 @@ mono-repo multidex Multidex namespace +namespaces Namespaced namespaced natively @@ -131,6 +141,7 @@ non-firebase NoSQL Notifee notifee +nullable NPE npm NPM @@ -140,6 +151,7 @@ onwards OpenID Perf perf +parsers performant personalization plist @@ -152,6 +164,7 @@ pre-rendered prebuild preflight preloaded +prebuilt prepended programmatically PRs @@ -160,6 +173,7 @@ qa react-native-app-auth react-native-firebase react-native-mlkit +react-native-nitro-google-signin realtime Realtime reCAPTCHA @@ -205,6 +219,7 @@ TOTP triaging TurboModule TurboModules +typings TypeDoc UI uid @@ -226,6 +241,8 @@ v6 v7 v9 v22 +v23 +v24 v25 Ventura VertexAI diff --git a/docs/messaging/server-integration.mdx b/docs/messaging/server-integration.mdx index 915130951c..20115cae4c 100644 --- a/docs/messaging/server-integration.mdx +++ b/docs/messaging/server-integration.mdx @@ -176,8 +176,7 @@ This means that by default, if your app has users and you allow them to log out How and when you invalidate a token and generate a new one will be specific to your project, but a common pattern is to delete the FCM token during logout and update your back end to remove it, then to fetch the FCM token during login and update your back end systems to associate the new token with the logged in user. -[deleteToken](https://invertase.github.io/react-native-firebase/_react-native-firebase/messaging/modular/deleteToken.html) -[getToken](https://invertase.github.io/react-native-firebase/_react-native-firebase/messaging/modular/getToken.html) +Use [`deleteToken`](https://invertase.github.io/react-native-firebase/_react-native-firebase/messaging/modular/deleteToken.html) and [`getToken`](https://invertase.github.io/react-native-firebase/_react-native-firebase/messaging/modular/getToken.html) from the modular API. Note that when a token is deleted by calling the `deleteToken` method, it is immediately and permanently invalid. diff --git a/docs/migrating-to-v24.mdx b/docs/migrating-to-v24.mdx index 68f02a52de..8452830952 100644 --- a/docs/migrating-to-v24.mdx +++ b/docs/migrating-to-v24.mdx @@ -5,6 +5,8 @@ previous: /migrating-to-v23 next: /migrating-to-v25 --- +Version 24 includes breaking changes for Firestore TypeScript types and Cloud Functions native integration. Review the sections below for the modules you use. + # Firestore Version 24 introduces `withConverter` functionality from Firebase JS SDK. Due to the differences in types between references and queries in namespace vs modular API, and the namespaced APIs deprecation cycle being effectively complete with the API set for removal, we have adopted the modular API typing in general for firestore APIs. @@ -36,3 +38,50 @@ onSnapshot(doc(getFirestore(), 'foo', 'foo'), { }, }); ``` + +# Cloud Functions + +**PR:** [#8603](https://github.com/invertase/react-native-firebase/pull/8603) / v24.0.0 ([#8799](https://github.com/invertase/react-native-firebase/issues/8799) streaming callables) + +From v24 onward, `@react-native-firebase/functions` is implemented as a **TurboModule** and **requires React Native's New Architecture**. The legacy bridge module was removed. + +## Who is affected + +| You use… | Action | +| ----------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | +| `@react-native-firebase/functions` on **New Architecture** | No change required | +| `@react-native-firebase/functions` on the **legacy architecture** | Enable New Architecture, or stay on v23 if you cannot migrate yet | +| Other RN Firebase modules only | Functions is the first module with a hard requirement; `@react-native-firebase/app` prints a deprecation warning on legacy architecture builds | + +## Enable New Architecture + +**React Native CLI (Android)** — set in `android/gradle.properties`: + +```properties +newArchEnabled=true +``` + +**React Native CLI (iOS)** — New Architecture is enabled when `RCT_NEW_ARCH_ENABLED=1` during `pod install` (React Native sets this from `newArchEnabled` on recent templates). Follow the [React Native New Architecture guide](https://reactnative.dev/docs/the-new-architecture/landing-page) for your RN version. + +**Expo** — enable in your app config (Expo SDK 52+): + +```json +{ + "expo": { + "newArchEnabled": true + } +} +``` + +Rebuild native projects after changing this (`pod install`, clean Android build). + +## If New Architecture is disabled + +- **Android:** the Functions Gradle script fails the build with `New Architecture support is required for @react-native-firebase/functions`. +- **iOS:** `pod install` fails with `RNFBFunctions requires New Architecture. Enable New Architecture to use this module`. + +## API notes + +The JavaScript API (`functions()`, `httpsCallable`, modular helpers) is unchanged. v24 also adds [`httpsCallable().stream()`](/functions/usage) support, which relies on the TurboModule implementation. + +Other React Native Firebase modules still run on legacy architecture in v24, but old architecture support is deprecated project-wide and will be required for additional modules in future releases. diff --git a/docs/migrating-to-v25.mdx b/docs/migrating-to-v25.mdx index 7bae8a9593..777ce8cc54 100644 --- a/docs/migrating-to-v25.mdx +++ b/docs/migrating-to-v25.mdx @@ -5,21 +5,333 @@ previous: /migrating-to-v24 next: /typescript --- -Version 25 includes TypeScript alignment changes across multiple packages. Review the sections below for the modules you use. +Version 25 completes the TypeScript alignment started in v24. Modular types across multiple packages now match the [firebase-js-sdk](https://firebase.google.com/docs/web/modular-upgrade) modular API as closely as possible. Runtime behavior is largely unchanged; **TypeScript consumers** and apps using the **modular API** are most affected. + +If you upgraded to v24 for Firestore only, see [Migrating to v24](/migrating-to-v24) first — Firestore breaking changes remain in v24. + +## Why we made these changes + +React Native Firebase aims to be a drop-in replacement for the [firebase-js-sdk](https://firebase.google.com/docs/web/setup) — with native extensions and performance where the platform allows. At the JavaScript level we have always tracked the modular API closely, but our TypeScript declarations had diverged: namespaces specific to React Native Firebase, instance-style typings, and helper names that did not match the SDK. + +v25 finishes aligning those types module by module. For you as a developer that means: + +- **Shared mental model** — code, examples, and AI assistance written for firebase-js-sdk modular APIs map directly to React Native Firebase. +- **Safer refactors** — TypeScript catches incorrect imports and call shapes at compile time instead of at runtime. +- **Easier cross-platform work** — the same typed modular surface works across web, React Native, and shared business logic. +- **A clear path forward** — namespaced APIs remain for compatibility but modular root exports are the supported, typed source of truth. + +Most apps behave the same after updating package versions; the work is primarily import and type adjustments where TypeScript reports errors. + +## Agent-assisted migration + +This guide is written to be **complete enough for an automated first pass**. We recommend feeding this document to your coding agent, then asking it to analyze your codebase against each relevant section below and produce a concrete change list (or PR) for the packages you use. The [Automated migration checklist](#automated-migration-checklist) at the end is structured for that workflow. + +## Who is affected + +| You use… | Likely impact | +| ------------------------------------------------------------- | ------------------------------------------------------------------------------------ | +| TypeScript + modular imports (`getX()`, `ref()`, etc.) | **High** — update imports and call patterns per package sections below | +| TypeScript + namespaced API only (`firebase.storage().ref()`) | **Low–medium** — namespaced APIs remain; some types are deprecated or stricter | +| JavaScript only, no type checking | **Low** — runtime is mostly compatible; deprecated APIs still work but emit warnings | + +## General pattern + +Across v25 package migrations: + +1. Import **modular types and functions from the package root**, not from `Firebase*Types` namespaces. +2. Prefer **free functions** (`getToken(appCheck)`, `trace(perf, name)`) over instance methods on service objects. +3. `Firebase*Types` namespaces remain for namespaced compatibility but are **deprecated** for new code. +4. Namespaced APIs (`firebase.auth()`, `storage()`) still work; modular is the typed source of truth. ## Table of contents +- [Why we made these changes](#why-we-made-these-changes) +- [Agent-assisted migration](#agent-assisted-migration) +- [Who is affected](#who-is-affected) +- [General pattern](#general-pattern) +- [Tooling & native SDKs](#tooling--native-sdks) +- [Cloud Storage](#cloud-storage) +- [Realtime Database](#realtime-database) +- [Remote Config](#remote-config) +- [Performance Monitoring](#performance-monitoring) +- [Installations](#installations) - [App Check](#app-check) - [Firebase Auth](#firebase-auth) +- [Cloud Messaging](#cloud-messaging) +- [Automated migration checklist](#automated-migration-checklist) + +# Tooling & native SDKs + +**Commit:** `c8c1fc105` (SDK bump) + +| Change | Who | Action | +| --------------------------------------------------------- | -------------- | ------------------------------------------- | +| `firebase-ios-sdk` 12.12.0+ requires **Xcode 26.2+** | iOS developers | Upgrade Xcode before building v25 | +| `firebase-android-sdk` 34.12.0, `firebase-js-sdk` 12.12.0 | All | Update lockfiles / pods as usual on upgrade | + +# Cloud Storage + +**PR:** [#8824](https://github.com/invertase/react-native-firebase/pull/8824) + +Modular Storage types now match firebase-js-sdk. The namespaced API (`firebase.storage()`, `FirebaseStorageTypes`) is preserved separately and deprecated for new code. + +## Type & export changes + +| Before (v24 modular / types) | Now (v25) | +| --------------------------------------------------------------------- | ---------------------------------------------------------------------------- | +| Instance methods on `Storage` / `StorageReference` in modular typings | Use root-level functions: `ref()`, `uploadBytes()`, `getDownloadURL()`, etc. | +| `refFromURL(storage, url)` | `ref(storage, url)` — `ref()` accepts `gs://` and `https://` URLs | +| `child(ref, path)` | `ref(ref, path)` | +| Modular `toString(ref)` helper | `ref.toString()` on the reference | +| `storage.statics.StringFormat`, `TaskEvent`, `TaskState` | Import `StringFormat`, `TaskEvent`, `TaskState` from package root | +| `md5hash` in metadata | `md5Hash` (firebase-js-sdk spelling) | +| Generic `Error` in task callbacks | `NativeFirebaseError` | +| `ListOptions.pageToken` required `string` | `string \| null` (nullable, matching firebase-js-sdk) | + +## Example: modular references and uploads + +```js +// Previously +import { getStorage, refFromURL, child } from '@react-native-firebase/storage'; + +const storage = getStorage(); +const fileRef = child(refFromURL(storage, 'gs://bucket/path/file.jpg'), 'thumb.jpg'); +await fileRef.putFile(localPath); +``` + +```js +// Now +import { getStorage, ref, putFile } from '@react-native-firebase/storage'; + +const storage = getStorage(); +const fileRef = ref(ref(storage, 'gs://bucket/path/file.jpg'), 'thumb.jpg'); +await putFile(fileRef, localPath); +``` + +## Example: types and task constants + +```js +// Previously +import { getStorage, FirebaseStorageTypes } from '@react-native-firebase/storage'; + +function onState(snapshot: FirebaseStorageTypes.TaskSnapshot) { + if (snapshot.state === getStorage().app.storage().constructor.TaskState.RUNNING) { /* … */ } +} +``` + +```js +// Now +import { getStorage, ref, uploadBytesResumable, TaskState, type TaskSnapshot } from '@react-native-firebase/storage'; + +function onState(snapshot: TaskSnapshot) { + if (snapshot.state === TaskState.RUNNING) { /* … */ } +} +``` + +**RN-only helpers** (`putFile`, `writeToFile`) remain exported from the package root for native file paths. + +# Realtime Database + +**PR:** [#8977](https://github.com/invertase/react-native-firebase/pull/8977) + +Modular RTDB types (`DatabaseReference`, `Query`, `DataSnapshot`, `OnDisconnect`, `QueryConstraint`) no longer expose namespaced instance-style methods in public typings. Use function-based modular helpers. + +## Breaking changes + +| Before | Now | +| --------------------------------------------------------------- | ---------------------------------------------- | +| `import { ServerValue } from '@react-native-firebase/database'` | Use `serverTimestamp()` and `increment(delta)` | +| `await goOffline(db)` / `.then()` on `goOffline` | `goOffline(db)` returns `void` | +| `await goOnline(db)` | `goOnline(db)` returns `void` | +| `getServerTime(db)` treated as async | Returns synchronous `Date` | + +## Example: server timestamps + +```js +// Previously +import { getDatabase, ref, set, ServerValue } from '@react-native-firebase/database'; + +await set(ref(getDatabase(), 'posts/1'), { createdAt: ServerValue.TIMESTAMP }); +``` + +```js +// Now +import { getDatabase, ref, set, serverTimestamp } from '@react-native-firebase/database'; + +await set(ref(getDatabase(), 'posts/1'), { createdAt: serverTimestamp() }); +``` + +## Example: modular query helpers + +```js +// Previously — instance methods typed on modular references +import { + getDatabase, + ref, + query, + orderByChild, + equalTo, + onValue, +} from '@react-native-firebase/database'; + +const db = getDatabase(); +const scoresRef = ref(db, 'scores'); +const q = query(scoresRef, orderByChild('score'), equalTo(100)); +onValue(q, snapshot => { + /* … */ +}); +``` + +Function-based helpers (`query`, `orderByChild`, `onValue`, etc.) are unchanged at runtime; **TypeScript** may now require you to stop calling deprecated instance methods (`.orderByChild()`, `.on()`) on modular-typed references and use the modular functions instead. + +Namespaced `firebase.database.ServerValue` remains available. + +# Remote Config + +**PR:** [#8972](https://github.com/invertase/react-native-firebase/pull/8972) + +Modular Remote Config now uses firebase-js-sdk type names and instance properties. + +## Removed / renamed modular API + +| Removed (v24) | Replacement (v25) | +| ----------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- | +| `fetch(remoteConfig, expirationDurationSeconds?)` | `fetchConfig(remoteConfig)` | +| `setConfigSettings(remoteConfig, settings)` | `remoteConfig.settings = { minimumFetchIntervalMillis, fetchTimeoutMillis }` | +| `setDefaults(remoteConfig, defaults)` | `remoteConfig.defaultConfig = { … }` | +| `onConfigUpdated(remoteConfig, cb)` | `onConfigUpdate(remoteConfig, observer)` | +| `fetchTimeMillis()`, `settings()`, `lastFetchStatus()` helpers | Read `remoteConfig.fetchTimeMillis`, `.settings`, `.lastFetchStatus` | +| `RemoteConfigValue.value` / `.source` getters | `value.asString()` (etc.) and `value.getSource()` | +| Exports: `LastFetchStatus`, `ValueSource`, `ConfigSettings`, `ConfigDefaults`, `ConfigValue`, `ConfigValues`, `LastFetchStatusType`, `RemoteConfigLogLevel` | Use `FetchStatus`, `ValueSource`, `Value`, `RemoteConfigSettings`, `LogLevel` | + +**Settings field rename:** modular `RemoteConfigSettings` uses `fetchTimeoutMillis` (firebase-js-sdk), not the older React Native Firebase style `fetchTimeMillis` on the modular surface. + +## Example: fetch and read values + +```js +// Previously +import { + getRemoteConfig, + fetch, + activate, + getValue, + FirebaseRemoteConfigTypes, +} from '@react-native-firebase/remote-config'; + +const rc = getRemoteConfig(); +await fetch(rc, 3600); +await activate(rc); +const flag = getValue(rc, 'feature_enabled'); +console.log(flag.value, flag.source); +``` + +```js +// Now +import { + getRemoteConfig, + fetchConfig, + activate, + getValue, + type Value, +} from '@react-native-firebase/remote-config'; + +const rc = getRemoteConfig(); +rc.settings = { + minimumFetchIntervalMillis: 3600000, + fetchTimeoutMillis: 60000, +}; +await fetchConfig(rc); +await activate(rc); +const flag: Value = getValue(rc, 'feature_enabled'); +console.log(flag.asString(), flag.getSource()); +``` + +# Performance Monitoring + +**PR:** `4aedfe883` (TypeScript migration) + +## Breaking changes + +| Before | Now | +| ------------------------------------------------------ | ----------------------------------------------------------------------- | +| `await initializePerformance(app, settings)` | Returns `FirebasePerformance` **synchronously** | +| `perf.newTrace(name)`, `perf.startTrace(name)` | `trace(perf, name)` | +| `perf.newHttpMetric(url, method)` | `httpMetric(perf, url, method)` | +| `perf.newScreenTrace(name)` / `startScreenTrace(name)` | `newScreenTrace(perf, name)` / `startScreenTrace(perf, name)` | +| `perf.setPerformanceCollectionEnabled(bool)` | `perf.dataCollectionEnabled = bool` | +| `PerformanceSettings` React Native Firebase shape | `{ dataCollectionEnabled?, instrumentationEnabled? }` (firebase-js-sdk) | +| `trace.getAttribute(key)` typed as `string \| null` | `string \| undefined` | + +**RN-only exports retained:** `httpMetric`, `newScreenTrace`, `startScreenTrace`, `HttpMethod`, `HttpMetric`, `ScreenTrace`. + +## Example + +```js +// Previously +import { getPerformance } from '@react-native-firebase/perf'; + +const perf = getPerformance(); +const t = perf.newTrace('load_screen'); +await t.start(); +``` + +```js +// Now +import { getPerformance, trace } from '@react-native-firebase/perf'; + +const perf = getPerformance(); +const t = trace(perf, 'load_screen'); +await t.start(); +``` + +# Installations + +**PR:** `739a4ca36` (TypeScript migration) + +Modular `getInstallations()` returns a firebase-js-sdk-shaped `Installations` object exposing only `app`. Use modular helper functions instead of instance methods. + +## Breaking changes + +| Before | Now | +| -------------------------- | --------------------------------------------------------------- | +| `installations.getId()` | `getId(installations)` | +| `installations.getToken()` | `getToken(installations)` | +| `installations.delete()` | `deleteInstallations(installations)` — argument is **required** | + +## Example + +```js +// Previously +import { getInstallations } from '@react-native-firebase/installations'; + +const installations = getInstallations(); +const id = await installations.getId(); +``` + +```js +// Now +import { getInstallations, getId } from '@react-native-firebase/installations'; + +const installations = getInstallations(); +const id = await getId(installations); +``` + +Namespaced `firebase.installations()` / `FirebaseInstallationsTypes` remain available (deprecated). # App Check +**PR:** [#8889](https://github.com/invertase/react-native-firebase/pull/8889) + Version 25 aligns App Check's modular exports more closely with the Firebase JS SDK. If your app uses the modular API, import App Check types and helpers directly from `@react-native-firebase/app-check` instead of routing modular code through `FirebaseAppCheckTypes`. The most common updates are: - Import modular helpers such as `initializeAppCheck`, `getToken`, `getLimitedUseToken`, `setTokenAutoRefreshEnabled`, and `onTokenChanged` from the package root. - Import modular types such as `AppCheck` and `AppCheckTokenResult` from the package root. +- `FirebaseApp` is no longer exported from `@react-native-firebase/app-check`; import it from `@react-native-firebase/app`. +- `FirebaseAppCheckTypes` is **type-only** — use `import type { FirebaseAppCheckTypes }`. +- Modular `AppCheck` has no instance methods (matching firebase-js-sdk); use free functions. +- `onTokenChanged` callback receives `AppCheckTokenResult`, not `AppCheckListenerResult`. - Keep using `ReactNativeFirebaseAppCheckProvider` on React Native when you need native provider selection for Android / Apple / web. ```js @@ -94,17 +406,19 @@ await initializeAppCheck(getApp(), { # Firebase Auth +**PR:** [#8991](https://github.com/invertase/react-native-firebase/pull/8991) + Version 25 aligns `@react-native-firebase/auth` TypeScript types with the firebase-js-sdk modular API. Runtime behavior is largely unchanged, but TypeScript consumers should review the following breaking changes. For maintainers and coding agents: the living triage matrix is [`okf-bundle/packages/auth/compare-types-triage.md`](../okf-bundle/packages/auth/compare-types-triage.md). Run `yarn compare:types auth` after public API edits and update `.github/scripts/compare-types/configs/auth.ts` when differences are intentional. ## Platform matrix (read before changing Auth) -| Context | `Platform.OS` | Backend | Notes | -| ---------------- | ---------------------- | ------------------------------------ | ----------------------------------------------------------------------------------------------- | -| **iOS/Android** | `ios`, `android` | Native Firebase Auth SDK | Native bridge types (`verifyPhoneNumber` listener, MF overloads, async `isSignInWithEmailLink`) | -| **Other/Hermes** | e.g. macOS, Windows RN | firebase-js-sdk via `RNFBAuthModule` | No DOM; MFA/TOTP covered by `tests/local-tests` | -| **Other/Web** | browser embedding | firebase-js-sdk | DOM APIs (reCAPTCHA, redirect) possible but not all delegated yet | +| Context | `Platform.OS` | Backend | Notes | +| ---------------- | ---------------------- | --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ | +| **iOS/Android** | `ios`, `android` | Native Firebase Auth SDK | Native bridge types (`verifyPhoneNumber` listener, Multi-Factor Authentication overloads, async `isSignInWithEmailLink`) | +| **Other/Hermes** | e.g. macOS, Windows RN | firebase-js-sdk via the auth web bridge | No DOM; MFA/TOTP covered by `tests/local-tests` | +| **Other/Web** | browser embedding | firebase-js-sdk | DOM APIs (reCAPTCHA, redirect) possible but not all delegated yet | When a symbol is documented as **iOS/Android only**, do not assume it throws or is missing on Other without checking the web bridge. When compare:types signatures match but runtime differs, document in triage / this guide (not necessarily in `differentShape`). @@ -112,11 +426,11 @@ When a symbol is documented as **iOS/Android only**, do not assume it throws or Import modular types directly from `@react-native-firebase/auth` instead of `FirebaseAuthTypes` where possible. The namespaced `FirebaseAuthTypes` namespace remains available but is deprecated. -For auth errors, use `NativeFirebaseAuthError` (or the modular `AuthError` interface) instead of expecting a firebase-js-sdk `AuthError` class export — RN Firebase does not re-export the js-sdk error class. +For auth errors, use `NativeFirebaseAuthError` (or the modular `AuthError` interface) instead of expecting a firebase-js-sdk `AuthError` class export — React Native Firebase does not re-export the firebase-js-sdk error class. ## Removed modular export -- `initializeRecaptchaConfig` is not exported. React Native Firebase uses native SDK phone-auth verification rather than the browser reCAPTCHA bootstrap flow. +- `initializeRecaptchaConfig` is not exported. React Native Firebase uses native SDK Phone Auth verification rather than the browser reCAPTCHA bootstrap flow. ## Deprecated provider helpers @@ -160,7 +474,7 @@ const credential = provider.credential({ idToken, accessToken }); - `isSignInWithEmailLink(auth, emailLink)` — returns `Promise` on iOS/Android (native bridge). The firebase-js-sdk returns a synchronous `boolean`. Port web code with `await isSignInWithEmailLink(auth, link)` (or `.then(...)`). - `sendSignInLinkToEmail(auth, email, actionCodeSettings)` — `actionCodeSettings` is **required** in the modular API (matching firebase-js-sdk). -- **Namespaced email link (RNFB convenience):** `firebase.auth().sendSignInLinkToEmail(email, settings?)` still accepts omitted settings. Internally `_resolveActionCodeSettings()` defaults `url` from `app.options.authDomain` and `handleCodeInApp: true`. This is **not** platform-specific — only namespaced vs modular. Do not “fix” modular to match namespaced defaults. +- **Namespaced email link (react-native-firebase convenience):** `firebase.auth().sendSignInLinkToEmail(email, settings?)` still accepts omitted settings. Internally `_resolveActionCodeSettings()` defaults `url` from `app.options.authDomain` and `handleCodeInApp: true`. This is **not** platform-specific — only namespaced vs modular. Do not “fix” modular to match namespaced defaults. - `signInWithEmailLink(auth, email, emailLink?)` — the third argument is optional, matching firebase-js-sdk. - `signInWithRedirect` / `linkWithRedirect` — return `Promise` on native because provider flows resolve immediately with credentials instead of following the browser redirect contract. - `reauthenticateWithRedirect` — returns `Promise` on native while still updating `currentUser` after the native provider flow completes. @@ -168,9 +482,9 @@ const credential = provider.credential({ idToken, accessToken }); ## Web APIs with matching types but different native runtime (iOS/Android) -These modular helpers are exported for firebase-js-sdk API parity. **On iOS/Android they throw synchronously** (or are not applicable) because native SDKs do not implement the browser persistence, redirect, or reCAPTCHA phone-link flows. Types match the js-sdk; behaviour does not — see API reference `@remarks` on each symbol. +These modular helpers are exported for firebase-js-sdk API parity. **On iOS/Android they throw synchronously** (or are not applicable) because native SDKs do not implement the browser persistence, redirect, or reCAPTCHA phone-link flows. Types match the firebase-js-sdk; behavior does not — see API reference `@remarks` on each symbol. -| API | Native iOS/Android behaviour | +| API | Native iOS/Android behavior | | ------------------------------- | ----------------------------------------------------------------------------------------------------- | | `getRedirectResult` | Always throws — use immediate `UserCredential` from `signInWithRedirect` / `linkWithRedirect` instead | | `setPersistence` | Always throws — native SDKs manage auth state | @@ -179,12 +493,12 @@ These modular helpers are exported for firebase-js-sdk API parity. **On iOS/Andr | `linkWithPhoneNumber` | Always throws | | `reauthenticateWithPhoneNumber` | Always throws | -`initializeAuth(app, deps?)` accepts js-sdk `Dependencies` but **ignores** persistence, popup redirect resolver, and error-map deps on iOS/Android (see below). +`initializeAuth(app, deps?)` accepts the firebase-js-sdk `Dependencies` type for API parity but **ignores** persistence, popup redirect resolver, and error-map dependencies on iOS/Android (see below). -## Phone auth (iOS/Android) +## Phone Auth (iOS/Android) -- `verifyPhoneNumber(auth, phoneNumber, ...)` — **iOS/Android only** native listener flow (force-resend, auto-verification callbacks). On Other platforms use `signInWithPhoneNumber` / js-sdk `PhoneAuthProvider` instead. -- `signInWithPhoneNumber(auth, phoneNumber, appVerifier?)` — modular API no longer accepts RNFB's former `forceResend` fourth argument; use `verifyPhoneNumber` when you need the native listener / force-resend behaviour. +- `verifyPhoneNumber(auth, phoneNumber, ...)` — **iOS/Android only** native listener flow (force-resend, auto-verification callbacks). On Other platforms use `signInWithPhoneNumber` / firebase-js-sdk `PhoneAuthProvider` instead. +- `signInWithPhoneNumber(auth, phoneNumber, appVerifier?)` — modular API no longer accepts the former `forceResend` fourth argument from React Native Firebase; use `verifyPhoneNumber` when you need the native listener / force-resend behavior. ## Auth instance surface @@ -192,57 +506,122 @@ These modular helpers are exported for firebase-js-sdk API parity. **On iOS/Andr - `auth.authStateReady()`, `auth.beforeAuthStateChanged(...)`, `auth.emulatorConfig`, and `auth.updateCurrentUser(user)` are implemented on the Auth instance. - **`auth.config` runtime split (types unified):** Declarations match firebase-js-sdk `Config`, but runtime differs by platform: - **iOS/Android:** always `{}` — native SDKs do not expose the web config object. - - **Other (Hermes/Web):** firebase-js-sdk can populate `auth.config`, but RNFB does not delegate this yet. Do not read `auth.config` on native expecting `apiKey` / `authDomain`; use `getCustomAuthDomain(auth)` on iOS/Android or app options on Other until delegation lands. + - **Other (Hermes/Web):** firebase-js-sdk can populate `auth.config`, but React Native Firebase does not delegate this yet. Do not read `auth.config` on native expecting `apiKey` / `authDomain`; use `getCustomAuthDomain(auth)` on iOS/Android or app options on Other until delegation lands. ## Credential providers Provider credential factories return firebase-js-sdk-shaped credential **classes** (`OAuthCredential`, not internal type aliases) with `toJSON()` and `static fromJSON()` where applicable. -- `OAuthCredential.rawNonce` — used for Sign in with Apple and Facebook limited-login flows (matches js-sdk credential options). OAuth 1.0 token secrets (e.g. Twitter) use the inherited `AuthCredential.secret` bridge field instead of `rawNonce`. +- `OAuthCredential.rawNonce` — used for Sign in with Apple and Facebook limited-login flows (matches firebase-js-sdk credential options). OAuth 1.0 token secrets (e.g. Twitter) use the inherited `AuthCredential.secret` bridge field instead of `rawNonce`. - RN Firebase credentials retain internal `token` / `secret` bridge fields required by the native modules (implementation detail; omitted from generated API reference). - `OAuthProvider.credentialFromResult` / `credentialFromError` and sibling provider helpers (`GoogleAuthProvider`, `GithubAuthProvider`, `TwitterAuthProvider`, `FacebookAuthProvider`, `PhoneAuthProvider`) **always return `null` at runtime today**. Declared types match firebase-js-sdk. - **iOS/Android:** no native extraction planned — credentials are not recoverable from native provider results. - - **Other/Hermes:** not delegated (js-sdk credential recovery is tied to popup/redirect flows). - - **Other/Web:** future implementation should delegate to firebase-js-sdk in `RNFBAuthModule` — do not invest in native iOS/Android bridge work for this. + - **Other/Hermes:** not delegated (firebase-js-sdk credential recovery is tied to popup/redirect flows). + - **Other/Web:** future implementation should delegate to firebase-js-sdk in the auth web bridge — do not invest in native iOS/Android bridge work for this. - `GoogleAuthProvider.credential()` throws when both `idToken` and `accessToken` are absent (matching firebase-js-sdk). -- `FacebookAuthProvider.credential(token)` matches js-sdk. RNFB also exports `credential(token, secret)` for Facebook limited-login nonce behaviour — an intentional extension documented in compare:types. +- `FacebookAuthProvider.credential(token)` matches firebase-js-sdk. React Native Firebase also exports `credential(token, secret)` for Facebook limited-login nonce behavior — an intentional extension documented in compare:types. ## Multi-factor - Modular `multiFactor(user)` now uses the user's auth instance instead of always calling `getAuth()`, fixing secondary Firebase app usage. - Namespaced `firebase.auth().multiFactor(user)` now correctly validates that `user` is the `currentUser`. - `TotpSecret.generateQrCodeUrl()` returns `Promise` on iOS/Android (native bridge). firebase-js-sdk returns a synchronous string. -- `TotpSecret.openInOtpApp(qrCodeUrl)` — RN-only helper that deep-links into an OTP authenticator app; not part of firebase-js-sdk. -- **Other platforms:** MFA and TOTP flows are exercised in `tests/local-tests` via the js-sdk bridge — not a gap to “port” from native overloads. +- `TotpSecret.openInOtpApp(qrCodeUrl)` — RN-only helper that deep-links into a One-Time Password authenticator app; not part of firebase-js-sdk. +- **Other platforms:** MFA and TOTP flows are exercised in `tests/local-tests` via the firebase-js-sdk bridge — not a gap to “port” from native overloads. ## Normalized modular return values Modular helpers normalize several return shapes toward firebase-js-sdk: - `UserCredential` includes top-level `providerId` and `operationType`. -- When the native bridge returns federated metadata, `additionalUserInfo` is attached as an **enumerable** property on modular `UserCredential` objects. Core fields match js-sdk (`isNewUser`, `profile`, `providerId`, `username`); extra native keys are copied onto the object for backwards compatibility. +- When the native bridge returns federated metadata, `additionalUserInfo` is attached as an **enumerable** property on modular `UserCredential` objects. Core fields match firebase-js-sdk (`isNewUser`, `profile`, `providerId`, `username`); extra native keys are copied onto the object for backwards compatibility. - Use `getAdditionalUserInfo(userCredential)` for the canonical read (returns `AdditionalUserInfo | null`, same shape as firebase-js-sdk). For TypeScript when you need provider-specific native extras, cast to `AdditionalUserInfoNative` (`AdditionalUserInfo & Record`). - `checkActionCode` normalizes `fromEmail` to `previousEmail` and coerces multi-factor info shapes. - `signInWithPhoneNumber` wraps confirmation results and validates `verificationId` presence. -## initializeAuth +## `initializeAuth` `initializeAuth(app, deps?)` accepts the firebase-js-sdk `Dependencies` type for API parity, but persistence, popup redirect resolver, and error-map dependencies are ignored because native SDKs manage auth state. ## Namespaced type adjustments -- `FirebaseAuthTypes.UserInfo` profile fields are nullable. +- `FirebaseAuthTypes.UserInfo` profile fields can be null. - `firebase.auth().config` is typed as `Record` on the namespaced API (stricter than modular `auth.config`). -## Agent checklist (Auth v25) +# Cloud Messaging + +**PR:** [#9053](https://github.com/invertase/react-native-firebase/pull/9053) + +Notification **permission** APIs in `@react-native-firebase/messaging` are **deprecated** in v25. They are not Firebase-specific; dedicated libraries handle permissions more completely. + +| Deprecated API | Use instead | +| ------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `requestPermission(messaging, …)` | [`react-native-permissions`](https://github.com/zoontek/react-native-permissions) or [`expo-notifications`](https://docs.expo.dev/versions/latest/sdk/notifications/) (Expo) | +| `hasPermission(messaging)` | Same | +| `registerDeviceForRemoteMessages(messaging)` | Same (platform setup) | +| `isDeviceRegisteredForRemoteMessages(messaging)` | Same | +| `AuthorizationStatus` static on messaging | Permission library equivalents | + +These APIs still work at runtime but are marked `@deprecated` in TypeScript and documented for removal in a future major release. See [#6283](https://github.com/invertase/react-native-firebase/issues/6283). + +# Automated migration checklist + +Use this section when running scripted or agent-assisted upgrades from v24 → v25. + +## 1. Upgrade dependencies + +```bash +# Bump all @react-native-firebase/* packages to v25 together (monorepo versions are aligned) +yarn add @react-native-firebase/app@^25.0.0 … +cd ios && pod install +``` + +Ensure **Xcode 26.2+** for iOS builds. + +## 2. Fix TypeScript by package + +For each `@react-native-firebase/` in your imports: + +| Package | Search for | Replace with | +| --------------- | ----------------------------------------------------------------- | --------------------------------------------------------------------------- | +| `storage` | `refFromURL`, `child(`, `FirebaseStorageTypes`, `.statics.` | `ref()`, root imports, modular functions | +| `database` | `ServerValue`, `.orderByChild(`, `await goOffline` | `serverTimestamp()`, `query`/`orderByChild` functions, sync `goOffline` | +| `remote-config` | `fetch(`, `setDefaults`, `setConfigSettings`, `.value`, `.source` | `fetchConfig`, `defaultConfig`/`settings` props, `asString()`/`getSource()` | +| `perf` | `.newTrace`, `.newHttpMetric`, `await initializePerformance` | `trace()`, `httpMetric()`, sync `initializePerformance` | +| `installations` | `.getId()`, `.getToken()`, `.delete()` | `getId()`, `getToken()`, `deleteInstallations()` | +| `app-check` | `appCheck().getToken()`, value import of `FirebaseAppCheckTypes` | `initializeAppCheck` + `getToken()`, `import type` | +| `auth` | `FirebaseAuthTypes`, `AppleAuthProvider`, `OIDCAuthProvider` | Root modular types, `OAuthProvider` | +| `messaging` | `requestPermission`, `hasPermission` | `react-native-permissions` / `expo-notifications` | + +## 3. Validate + +```bash +yarn compile # root TypeScript compile +yarn compare:types # maintainers: per-package drift vs firebase-js-sdk +yarn tests:jest packages//__tests__ # targeted tests for touched packages +``` + +## 4. Namespaced API users + +If you only use `firebase.storage()`, `firebase.auth()`, etc. and do not import modular types: + +- You may see **deprecation warnings** in IDE / `@deprecated` JSDoc. +- Plan a gradual move to modular imports; namespaced removal is planned for a future major release. +- Runtime behavior should remain compatible for most flows. + +## Related PRs (v25 breaking changes since v24.0.0) -When touching `@react-native-firebase/auth` public API: +| Package | PR / commit | +| ------------------------ | --------------------------------------------------------------------- | +| Storage | [#8824](https://github.com/invertase/react-native-firebase/pull/8824) | +| App Check | [#8889](https://github.com/invertase/react-native-firebase/pull/8889) | +| Remote Config | [#8972](https://github.com/invertase/react-native-firebase/pull/8972) | +| Realtime Database | [#8977](https://github.com/invertase/react-native-firebase/pull/8977) | +| Performance | `4aedfe883` | +| Installations | `739a4ca36` | +| Auth | [#8991](https://github.com/invertase/react-native-firebase/pull/8991) | +| Messaging (deprecations) | [#9053](https://github.com/invertase/react-native-firebase/pull/9053) | +| Native SDKs (Xcode) | `c8c1fc105` | -1. Prefer modular root imports over `FirebaseAuthTypes` for new code. -2. Run `yarn compile` in `packages/auth`, then `yarn compare:types auth` — update `configs/auth.ts` for intentional gaps. -3. Consult `okf-bundle/packages/auth/compare-types-triage.md` for platform context (#8 PhoneAuthProvider MF overloads are native-only extensions; MFA on Other is not missing work). -4. Deprecations: migrate `AppleAuthProvider` / `OIDCAuthProvider` callers to `OAuthProvider`. -5. Do not assume `auth.config`, `credentialFromResult`, or redirect helpers behave like js-sdk on iOS/Android without reading triage runtime notes. -6. Update `docs/migrating-to-v25.mdx` when user-visible behaviour or migration steps change. -7. Run targeted tests: `yarn tests:jest packages/auth/__tests__/auth.test.ts` and relevant e2e under `packages/auth/e2e/`. +Packages migrated to TypeScript **without** public API breaks in v25: `@react-native-firebase/app-distribution` ([#8967](https://github.com/invertase/react-native-firebase/pull/8967)), `@react-native-firebase/ml` ([#9005](https://github.com/invertase/react-native-firebase/pull/9005)). diff --git a/docs/phone-number-verification/usage/index.mdx b/docs/phone-number-verification/usage/index.mdx index 2c8316fde3..a59758a5b5 100644 --- a/docs/phone-number-verification/usage/index.mdx +++ b/docs/phone-number-verification/usage/index.mdx @@ -23,7 +23,7 @@ yarn add @react-native-firebase/phone-number-verification # What does it do -Firebase Phone Number Verification (PNV) provides carrier-level phone number verification on Android devices without requiring SMS codes. It verifies the user's phone number directly through the device's SIM card and carrier network, providing a seamless and secure verification experience. +Firebase Phone Number Verification provides carrier-level phone number verification on Android devices without requiring SMS codes. It verifies the user's phone number directly through the device's SIM card and carrier network, providing a seamless and secure verification experience. To learn more, visit the [Firebase Phone Number Verification documentation](https://firebase.google.com/docs/phone-number-verification). @@ -36,17 +36,17 @@ Key capabilities: ## Region & carrier limitations -PNV depends on carrier cooperation. Not all carriers or regions are supported. Before relying on PNV, always call `getVerificationSupportInfo()` to check support. If a SIM slot returns `reason: 'INCAPABLE_DUE_TO_CARRIER_UNSUPPORTED'`, that carrier does not participate in PNV and you should fall back to another verification method (e.g. Firebase Auth SMS). +Phone Number Verification depends on carrier cooperation. Not all carriers or regions are supported. Before relying on Phone Number Verification, always call `getVerificationSupportInfo()` to check support. If a SIM slot returns `reason: 'INCAPABLE_DUE_TO_CARRIER_UNSUPPORTED'`, that carrier does not participate in Phone Number Verification and you should fall back to another verification method (e.g. Firebase Auth SMS). Common reasons verification may be unsupported: -| Reason | Meaning | -| -------------------------------------- | ------------------------------------------------ | -| `CAPABLE` | The SIM's carrier supports PNV. | -| `INCAPABLE_DUE_TO_CARRIER_UNSUPPORTED` | The carrier does not participate in PNV. | -| `INCAPABLE_DUE_TO_ANDROID_VERSION` | The device's Android version is too old. | -| `INCAPABLE_DUE_TO_SIM_STATE` | No SIM inserted, or SIM is in an unusable state. | -| `CAPABILITY_STATUS_UNSPECIFIED` | The SDK could not determine the status. | +| Reason | Meaning | +| -------------------------------------- | -------------------------------------------------------------- | +| `CAPABLE` | The SIM's carrier supports Phone Number Verification. | +| `INCAPABLE_DUE_TO_CARRIER_UNSUPPORTED` | The carrier does not participate in Phone Number Verification. | +| `INCAPABLE_DUE_TO_ANDROID_VERSION` | The device's Android version is too old. | +| `INCAPABLE_DUE_TO_SIM_STATE` | No SIM inserted, or SIM is in an unusable state. | +| `CAPABILITY_STATUS_UNSPECIFIED` | The SDK could not determine the status. | # Usage @@ -69,7 +69,7 @@ for (const info of supportInfo) { The method returns an array with one entry per SIM slot. Each entry includes: -- `isSupported` — whether PNV is available for this SIM. +- `isSupported` — whether Phone Number Verification is available for this SIM. - `simSlot` — the SIM slot index (0-based). - `carrierId` — the carrier identifier string. - `reason` — a `VerificationSupportStatus` string explaining why the SIM is or isn't supported. @@ -86,7 +86,7 @@ const supportInfo = await getVerificationSupportInfo(0); // SIM slot 0 ### Fallback when unsupported -If PNV is not supported, fall back to an alternative verification method: +If Phone Number Verification is not supported, fall back to an alternative verification method: ```js import { Platform } from 'react-native'; @@ -113,7 +113,7 @@ async function verifyPhoneNumber() { } } - // Carrier or device doesn't support PNV + // Carrier or device doesn't support Phone Number Verification return verifySms(); } ``` @@ -122,7 +122,7 @@ async function verifyPhoneNumber() { To initiate the full verification flow, call `getVerifiedPhoneNumber()`. This will present a consent dialog to the user asking permission to share their phone number. Your app should prepare the user for this consent screen before calling the method — for example, by explaining why their phone number is needed. -For guidance on handling user consent, see the [Firebase PNV getting started guide](https://firebase.google.com/docs/phone-number-verification/android/get-started). +For guidance on handling user consent, see the [Firebase Phone Number Verification getting started guide](https://firebase.google.com/docs/phone-number-verification/android/get-started). ```js import { getVerifiedPhoneNumber } from '@react-native-firebase/phone-number-verification'; @@ -173,11 +173,11 @@ console.log('Expires at:', new Date(result.expirationTimestamp * 1000)); ## Error handling -All methods reject with structured error codes from the Firebase PNV SDK. The `error.code` property contains one of these values: +All methods reject with structured error codes from the Firebase Phone Number Verification SDK. The `error.code` property contains one of these values: | Error Code | Meaning | | ----------------------------------------- | --------------------------------------------------------------- | -| `pnv/carrier-not-supported` | The SIM's carrier does not support PNV. | +| `pnv/carrier-not-supported` | The SIM's carrier does not support Phone Number Verification. | | `pnv/invalid-digital-credential-response` | The Digital Credential API response was invalid. | | `pnv/integrity-check-failed` | Device integrity check failed. | | `pnv/preflight-check-failed` | Server-side preflight check failed. | @@ -207,7 +207,7 @@ try { // Retry when app is in foreground break; default: - console.error('PNV error:', pnvError.code, pnvError.message); + console.error('Phone Number Verification error:', pnvError.code, pnvError.message); } } ``` @@ -216,8 +216,8 @@ try { To test without a real SIM card and carrier, use Firebase's test mode. This requires setup in the Firebase Console: -1. **Generate a test token**: In the Firebase Console, navigate to Phone Number Verification and generate a test token. Test tokens have a 7-day TTL. -2. **IAM permissions**: Ensure the service account has the required `firebasepnv.testSessions.create` permission. +1. **Generate a test token**: In the Firebase Console, navigate to Phone Number Verification and generate a test token. Test tokens have a 7-day Time-To-Live. +2. **Identity and Access Management permissions**: Ensure the service account has the required `firebasepnv.testSessions.create` permission. 3. **Google system services beta**: On the test device, enroll the Google system services app into the beta channel via Google Play. 4. **Call `enableTestSession` once**: Pass the token before any verification calls. This must be called only once per app instance — calling it again will reject with `pnv/test-session-already-enabled`. diff --git a/package.json b/package.json index 90efbd6ffd..93d8fd0e76 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ "lint:ios:fix": "find packages/*/ios -type f \\( -name '*.h' -o -name '*.cpp' -o -name '*.m' -o -name '*.mm' \\) -not -path '*/generated/*' -print0 | xargs -0 clang-format -i --style=Google", "lint:markdown": "eslint \"docs/**/*.mdx\" --max-warnings=0 && prettier --check \"docs/**/*.mdx\"", "lint:report": "eslint --output-file=eslint-report.json --format=json . --ext .js,.jsx,.ts,.tsx", - "lint:spellcheck": "spellchecker --quiet --files=\"docs/**/*.md\" --dictionaries=\"./.spellcheck.dict.txt\" --reports=\"spelling.json\" --plugins spell indefinite-article repeated-words syntax-mentions syntax-urls frontmatter", + "lint:spellcheck": "spellchecker --quiet --files=\"docs/**/*.{md,mdx}\" --dictionaries=\"./.spellcheck.dict.txt\" --reports=\"spelling.json\" --plugins spell indefinite-article repeated-words syntax-mentions syntax-urls frontmatter", "tsc:compile": "tsc --project .", "tsc:compile:consumer": "tsc --project tsconfig.consumer.json", "lint:all": "yarn lint && yarn lint:markdown && yarn lint:spellcheck && yarn tsc:compile",