From 7deaaa7aa5d438fda6c45d053493611cdeef2f1e Mon Sep 17 00:00:00 2001 From: Russell Wheatley Date: Thu, 14 May 2026 22:17:21 -0500 Subject: [PATCH] refactor(installations)!: migrate to TypeScript BREAKING CHANGE: installations modular types now match firebase-js-sdk Please see https://rnfirebase.io/migrating-to-v25 for help migrating if needed. react-native-firebase has a goal to be a drop-in replacement for firebase-js-sdk, with native extensions and performance. It has always worked that way at the javascript level but the typescript types have been divergent. We are fixing that as we refactor to typescript. Please bear with us as we get closer to our goal of react-native-firebase matching firebase-js-sdk both in functionality where possible, but also in exact typescript typing. Specifics for Installations: changed modular getInstallations() to return the firebase-js-sdk-style Installations type, which only exposes app; TypeScript consumers should use the modular helpers getId(installations), getToken(installations), and deleteInstallations(installations) instead of calling .getId(), .getToken(), or .delete() on the returned instance. changed modular deleteInstallations(installations) so the installations argument is required in the TypeScript surface, matching firebase-js-sdk. Code that previously relied on the old optional typing should pass getInstallations() explicitly. preserved the namespaced API surface: installations(), firebase.installations(), firebase.app().installations(), and FirebaseInstallationsTypes.Module remain available for compatibility, with deprecation annotations added. added explicit modular public types including Installations, IdChangeCallbackFn, and IdChangeUnsubscribeFn. --- .../compare-types/configs/installations.ts | 19 ++ .github/scripts/compare-types/src/registry.ts | 13 ++ .../__tests__/installations.test.ts | 3 + packages/installations/lib/index.d.ts | 173 ------------------ packages/installations/lib/index.ts | 27 +++ packages/installations/lib/modular.ts | 80 ++++++++ packages/installations/lib/modular/index.d.ts | 41 ----- packages/installations/lib/modular/index.js | 63 ------- .../lib/{index.js => namespaced.ts} | 41 +++-- .../installations/lib/types/installations.ts | 38 ++++ packages/installations/lib/types/internal.ts | 42 +++++ .../installations/lib/types/namespaced.ts | 112 ++++++++++++ packages/installations/package.json | 38 +++- packages/installations/tsconfig.json | 20 ++ packages/installations/type-test.ts | 22 ++- packages/installations/typedoc.json | 5 +- tsconfig.json | 2 - yarn.lock | 2 + 18 files changed, 442 insertions(+), 299 deletions(-) create mode 100644 .github/scripts/compare-types/configs/installations.ts delete mode 100644 packages/installations/lib/index.d.ts create mode 100644 packages/installations/lib/index.ts create mode 100644 packages/installations/lib/modular.ts delete mode 100644 packages/installations/lib/modular/index.d.ts delete mode 100644 packages/installations/lib/modular/index.js rename packages/installations/lib/{index.js => namespaced.ts} (61%) create mode 100644 packages/installations/lib/types/installations.ts create mode 100644 packages/installations/lib/types/internal.ts create mode 100644 packages/installations/lib/types/namespaced.ts create mode 100644 packages/installations/tsconfig.json diff --git a/.github/scripts/compare-types/configs/installations.ts b/.github/scripts/compare-types/configs/installations.ts new file mode 100644 index 0000000000..0a438d6107 --- /dev/null +++ b/.github/scripts/compare-types/configs/installations.ts @@ -0,0 +1,19 @@ +/** + * Known differences between the firebase-js-sdk @firebase/installations public + * API and the @react-native-firebase/installations modular API. + * + * Each entry must have a `name` (the export name) and a `reason` explaining + * why the difference exists. Any difference NOT listed here will cause CI to + * fail so that new drift is caught and deliberately acknowledged. + */ + +import type { PackageConfig } from '../src/types'; + +const config: PackageConfig = { + nameMapping: {}, + missingInRN: [], + extraInRN: [], + differentShape: [], +}; + +export default config; diff --git a/.github/scripts/compare-types/src/registry.ts b/.github/scripts/compare-types/src/registry.ts index c936186094..9efe4ada64 100644 --- a/.github/scripts/compare-types/src/registry.ts +++ b/.github/scripts/compare-types/src/registry.ts @@ -18,6 +18,7 @@ import appCheckConfig from '../configs/app-check'; import firestoreConfig from '../configs/firestore'; import firestorePipelinesConfig from '../configs/firestore-pipelines'; import remoteConfigConfig from '../configs/remote-config'; +import installationsConfig from '../configs/installations'; import perfConfig from '../configs/perf-config'; const SCRIPT_DIR = path.resolve(__dirname, '..'); @@ -197,6 +198,18 @@ export const packages: PackageEntry[] = [ ], config: appCheckConfig, }, + { + name: 'installations', + firebaseSdkTypesPaths: [ + requiredFirebaseTypes('installations'), + ], + rnFirebaseModularFiles: [ + path.join(rnDist('installations'), 'types', 'installations.d.ts'), + path.join(rnDist('installations'), 'modular.d.ts'), + ], + rnFirebaseSupportFiles: [path.join(rnDist('installations'), 'types', 'internal.d.ts')], + config: installationsConfig, + }, { name: 'firestore', firebaseSdkTypesPaths: [requiredFirebaseTypes('firestore')], diff --git a/packages/installations/__tests__/installations.test.ts b/packages/installations/__tests__/installations.test.ts index 8c76b1cd84..1a0f08203c 100644 --- a/packages/installations/__tests__/installations.test.ts +++ b/packages/installations/__tests__/installations.test.ts @@ -109,6 +109,7 @@ describe('installations()', function () { const installations = getInstallations(); installationsV9Deprecation( () => deleteInstallations(installations), + // @ts-expect-error Combines modular and namespace API () => installations.delete(), 'delete', ); @@ -118,6 +119,7 @@ describe('installations()', function () { const installations = getInstallations(); installationsV9Deprecation( () => getId(installations), + // @ts-expect-error Combines modular and namespace API () => installations.getId(), 'getId', ); @@ -127,6 +129,7 @@ describe('installations()', function () { const installations = getInstallations(); installationsV9Deprecation( () => getToken(installations), + // @ts-expect-error Combines modular and namespace API () => installations.getToken(), 'getToken', ); diff --git a/packages/installations/lib/index.d.ts b/packages/installations/lib/index.d.ts deleted file mode 100644 index 47b4434dc0..0000000000 --- a/packages/installations/lib/index.d.ts +++ /dev/null @@ -1,173 +0,0 @@ -/* - * 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 { ReactNativeFirebase } from '@react-native-firebase/app'; - -/** - * Firebase Installations package for React Native. - * - * #### Example 1 - * - * Access the firebase export from the `installations` package: - * - * ```js - * import { firebase } from '@react-native-firebase/installations'; - * - * // firebase.installations().X - * ``` - * - * #### Example 2 - * - * Using the default export from the `installations` package: - * - * ```js - * import installations from '@react-native-firebase/installations'; - * - * // installations().X - * ``` - * - * #### Example 3 - * - * Using the default export from the `app` package: - * - * ```js - * import firebase from '@react-native-firebase/app'; - * import '@react-native-firebase/installations'; - * - * // firebase.installations().X - * ``` - * - * @firebase installations - */ -export namespace FirebaseInstallationsTypes { - import FirebaseModule = ReactNativeFirebase.FirebaseModule; - - export interface Statics { - SDK_VERSION: string; - } - - /** - * The Firebase Installations service is available for the default app or a given app. - * - * #### Example 1 - * - * Get the installations instance for the **default app**: - * - * ```js - * const installationsForDefaultApp = firebase.installations(); - * ``` - * - * #### Example 2 - * - * Get the installations instance for a **secondary app**: - *˚ - * ```js - * const otherApp = firebase.app('otherApp'); - * const installationsForOtherApp = firebase.installations(otherApp); - * ``` - * - */ - export class Module extends FirebaseModule { - /** - * The current `FirebaseApp` instance for this Firebase service. - */ - app: ReactNativeFirebase.FirebaseApp; - - /** - * Creates a Firebase Installation if there isn't one for the app and - * returns the Installation ID. The installation ID is a globally unique, - * stable, URL-safe base64 string identifier that uniquely identifies the app instance. - * NOTE: If the application already has an existing FirebaseInstanceID then the InstanceID identifier will be used. - * - * @return Firebase Installation ID, this is an url-safe base64 string of a 128-bit integer. - */ - getId(): Promise; - - /** - * Retrieves (locally or from the server depending on forceRefresh value) a valid installation auth token. - * An existing token may be invalidated or expire, so it is recommended to fetch the installation auth token - * before any request to external servers (it will be refreshed automatically for firebase API calls). - * This method should be used with forceRefresh == YES when e.g. a request with the previously fetched - * installation auth token failed with “Not Authorized” error. - * - * @param forceRefresh Options to get an auth token either by force refreshing or not. - * @return Firebase Installation Authentication Token - */ - getToken(forceRefresh?: boolean): Promise; - - /** - * Deletes the Firebase Installation and all associated data from the Firebase backend. - * This call may cause Firebase Cloud Messaging, Firebase Remote Config, Firebase Predictions, - * or Firebase In-App Messaging to not function properly. Fetching a new installations ID should - * reset all the dependent services to a stable state again. A network connection is required - * for the method to succeed. If it fails, the existing installation data remains untouched. - */ - delete(): Promise; - - /** - * TODO implement id change listener for android. - * - * Sets a new callback that will get called when Installation ID changes. - * Returns an unsubscribe function that will remove the callback when called. - * Only the Android SDK supports sending ID change events. - * - * @android - */ - // onIdChange(callback: (installationId: string) => void): () => void; - } -} - -type InstallationsNamespace = ReactNativeFirebase.FirebaseModuleWithStaticsAndApp< - FirebaseInstallationsTypes.Module, - FirebaseInstallationsTypes.Statics -> & { - firebase: ReactNativeFirebase.Module; - app(name?: string): ReactNativeFirebase.FirebaseApp; -}; - -declare const defaultExport: InstallationsNamespace; - -export const firebase: ReactNativeFirebase.Module & { - installations: typeof defaultExport; - app( - name?: string, - ): ReactNativeFirebase.FirebaseApp & { installations(): FirebaseInstallationsTypes.Module }; -}; - -export * from './modular'; - -export default defaultExport; - -/** - * Attach namespace to `firebase.` and `FirebaseApp.`. - */ -declare module '@react-native-firebase/app' { - namespace ReactNativeFirebase { - import FirebaseModuleWithStaticsAndApp = ReactNativeFirebase.FirebaseModuleWithStaticsAndApp; - - interface Module { - installations: FirebaseModuleWithStaticsAndApp< - FirebaseInstallationsTypes.Module, - FirebaseInstallationsTypes.Statics - >; - } - - interface FirebaseApp { - installations(): FirebaseInstallationsTypes.Module; - } - } -} diff --git a/packages/installations/lib/index.ts b/packages/installations/lib/index.ts new file mode 100644 index 0000000000..bc592b178f --- /dev/null +++ b/packages/installations/lib/index.ts @@ -0,0 +1,27 @@ +/* + * 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. + * + */ + +// Export modular/public types. +export type * from './types/installations'; + +// Export modular API functions. +export * from './modular'; + +// Export namespaced API. +export type { FirebaseInstallationsTypes } from './types/namespaced'; +export * from './namespaced'; +export { default } from './namespaced'; diff --git a/packages/installations/lib/modular.ts b/packages/installations/lib/modular.ts new file mode 100644 index 0000000000..7b6247a592 --- /dev/null +++ b/packages/installations/lib/modular.ts @@ -0,0 +1,80 @@ +/* + * 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 { getApp } from '@react-native-firebase/app'; +import type { FirebaseApp } from '@react-native-firebase/app'; +import { MODULAR_DEPRECATION_ARG } from '@react-native-firebase/app/dist/module/common'; +import type { + IdChangeCallbackFn, + IdChangeUnsubscribeFn, + Installations, +} from './types/installations'; +import type { InstallationsInternal } from './types/internal'; + +function withModularDeprecationArg(installations: Installations): InstallationsInternal { + return installations as InstallationsInternal; +} + +/** + * Returns an instance of Installations associated with the given FirebaseApp instance. + */ +export function getInstallations(app?: FirebaseApp): Installations { + if (app) { + return getApp(app.name).installations(); + } + return getApp().installations(); +} + +/** + * Deletes the Firebase Installation and all associated data. + */ +export function deleteInstallations(installations: Installations): Promise { + const internalInstallations = withModularDeprecationArg(installations); + return internalInstallations.delete.call(internalInstallations, MODULAR_DEPRECATION_ARG); +} + +/** + * Creates a Firebase Installation if there isn't one for the app and returns the Installation ID. + */ +export function getId(installations: Installations): Promise { + const internalInstallations = withModularDeprecationArg(installations); + return internalInstallations.getId.call(internalInstallations, MODULAR_DEPRECATION_ARG); +} + +/** + * Returns a Firebase Installations auth token, identifying the current Firebase Installation. + */ +export function getToken(installations: Installations, forceRefresh?: boolean): Promise { + const internalInstallations = withModularDeprecationArg(installations); + return internalInstallations.getToken.call( + internalInstallations, + forceRefresh, + MODULAR_DEPRECATION_ARG, + ); +} + +/** + * Throw an error since react-native-firebase does not support this method. + * + * Sets a new callback that will get called when Installation ID changes. Returns an unsubscribe function that will remove the callback when called. + */ +export function onIdChange( + _installations: Installations, + _callback: IdChangeCallbackFn, +): IdChangeUnsubscribeFn { + throw new Error('onIdChange() is unsupported by the React Native Firebase SDK.'); +} diff --git a/packages/installations/lib/modular/index.d.ts b/packages/installations/lib/modular/index.d.ts deleted file mode 100644 index 8e493590ac..0000000000 --- a/packages/installations/lib/modular/index.d.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { ReactNativeFirebase } from '@react-native-firebase/app'; -import { FirebaseInstallationsTypes } from '../index'; - -import FirebaseInstallations = FirebaseInstallationsTypes.Module; -/** - * Returns an instance of Installations associated with the given FirebaseApp instance. - */ -export declare function getInstallations( - app?: ReactNativeFirebase.FirebaseApp, -): FirebaseInstallations; - -/** - * Deletes the Firebase Installation and all associated data. - */ -export declare function deleteInstallations(installations?: FirebaseInstallations): Promise; - -/** - * Creates a Firebase Installation if there isn't one for the app and returns the Installation ID. - */ -export declare function getId(installations: FirebaseInstallations): Promise; - -/** - * Returns a Firebase Installations auth token, identifying the current Firebase Installation. - */ -export declare function getToken( - installations: FirebaseInstallations, - forceRefresh?: boolean, -): Promise; - -declare type IdChangeCallbackFn = (installationId: string) => void; -declare type IdChangeUnsubscribeFn = () => void; - -/** - * Throw an error since react-native-firebase does not support this method. - * - * Sets a new callback that will get called when Installation ID changes. Returns an unsubscribe function that will remove the callback when called. - */ -export declare function onIdChange( - installations: FirebaseInstallations, - callback: IdChangeCallbackFn, -): IdChangeUnsubscribeFn; diff --git a/packages/installations/lib/modular/index.js b/packages/installations/lib/modular/index.js deleted file mode 100644 index 85a7a279b8..0000000000 --- a/packages/installations/lib/modular/index.js +++ /dev/null @@ -1,63 +0,0 @@ -/* - * 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 { getApp } from '@react-native-firebase/app'; -import { MODULAR_DEPRECATION_ARG } from '@react-native-firebase/app/dist/module/common'; -/** - * @typedef {import('..').FirebaseInstallationsTypes.Module} FirebaseInstallation - */ - -export function getInstallations(app) { - if (app) { - return getApp(app.name).installations(); - } - return getApp().installations(); -} - -/** - * @param {FirebaseInstallation} installations - * @returns {Promise} - */ -export function deleteInstallations(installations) { - return installations.delete.call(installations, MODULAR_DEPRECATION_ARG); -} - -/** - * @param {FirebaseInstallation} installations - * @returns {Promise} - */ -export function getId(installations) { - return installations.getId.call(installations, MODULAR_DEPRECATION_ARG); -} - -/** - * @param {FirebaseInstallation} installations - * @param {boolean | undefined} forceRefresh - * @returns {Promise} - */ -export function getToken(installations, forceRefresh) { - return installations.getToken.call(installations, forceRefresh, MODULAR_DEPRECATION_ARG); -} - -/** - * @param {FirebaseInstallation} installations - * @param {(string) => void} callback - * @returns {() => void} - */ -export function onIdChange(_installations, _callback) { - throw new Error('onIdChange() is unsupported by the React Native Firebase SDK.'); -} diff --git a/packages/installations/lib/index.js b/packages/installations/lib/namespaced.ts similarity index 61% rename from packages/installations/lib/index.js rename to packages/installations/lib/namespaced.ts index 65deb37618..893e24ee78 100644 --- a/packages/installations/lib/index.js +++ b/packages/installations/lib/namespaced.ts @@ -21,21 +21,22 @@ import { FirebaseModule, getFirebaseRoot, } from '@react-native-firebase/app/dist/module/internal'; +import type { ReactNativeFirebase } from '@react-native-firebase/app'; -import version from './version'; +import { version } from './version'; +import type { FirebaseInstallationsTypes } from './types/namespaced'; const statics = {}; const namespace = 'installations'; - const nativeModuleName = 'RNFBInstallationsModule'; -class FirebaseInstallationsModule extends FirebaseModule { - getId() { +class FirebaseInstallationsModule extends FirebaseModule { + getId(): Promise { return this.native.getId(); } - getToken(forceRefresh) { + getToken(forceRefresh?: boolean): Promise { if (!forceRefresh) { return this.native.getToken(false); } else { @@ -43,11 +44,11 @@ class FirebaseInstallationsModule extends FirebaseModule { } } - delete() { + delete(): Promise { return this.native.delete(); } - onIdChange() { + onIdChange(): () => void { if (isIOS) { return () => {}; } @@ -62,7 +63,7 @@ export const SDK_VERSION = version; // import installations from '@react-native-firebase/installations'; // installations().X(...); -export default createModuleNamespace({ +const installationsNamespace = createModuleNamespace({ statics, version, namespace, @@ -73,9 +74,27 @@ export default createModuleNamespace({ ModuleClass: FirebaseInstallationsModule, }); +type InstallationsNamespace = ReactNativeFirebase.FirebaseModuleWithStaticsAndApp< + FirebaseInstallationsTypes.Module, + FirebaseInstallationsTypes.Statics +> & { + installations: ReactNativeFirebase.FirebaseModuleWithStaticsAndApp< + FirebaseInstallationsTypes.Module, + FirebaseInstallationsTypes.Statics + >; + firebase: ReactNativeFirebase.Module; + app(name?: string): ReactNativeFirebase.FirebaseApp; +}; + +export default installationsNamespace as unknown as InstallationsNamespace; + // import installations, { firebase } from '@react-native-firebase/installations'; // installations().X(...); // firebase.installations().X(...); -export const firebase = getFirebaseRoot(); - -export * from './modular'; +export const firebase = + getFirebaseRoot() as unknown as ReactNativeFirebase.FirebaseNamespacedExport< + 'installations', + FirebaseInstallationsTypes.Module, + FirebaseInstallationsTypes.Statics, + false + >; diff --git a/packages/installations/lib/types/installations.ts b/packages/installations/lib/types/installations.ts new file mode 100644 index 0000000000..e1e0a14c71 --- /dev/null +++ b/packages/installations/lib/types/installations.ts @@ -0,0 +1,38 @@ +/* + * 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 type { FirebaseApp } from '@react-native-firebase/app'; + +/** + * An user defined callback function that gets called when Installations ID changes. + */ +export type IdChangeCallbackFn = (installationId: string) => void; + +/** + * Unsubscribe a callback function previously added via {@link IdChangeCallbackFn}. + */ +export type IdChangeUnsubscribeFn = () => void; + +/** + * Firebase Installations service instance. + */ +export interface Installations { + /** + * The current `FirebaseApp` instance for this Firebase service. + */ + app: FirebaseApp; +} diff --git a/packages/installations/lib/types/internal.ts b/packages/installations/lib/types/internal.ts new file mode 100644 index 0000000000..2b0b4b36b6 --- /dev/null +++ b/packages/installations/lib/types/internal.ts @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2016-present Invertase Limited & Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file 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 type { Installations } from './installations'; + +/** Optional final argument passed by modular API wrappers (MODULAR_DEPRECATION_ARG). */ +export type InstallationsModularDeprecationArg = string; + +export interface InstallationsInternal extends Installations { + delete(deprecationArg?: InstallationsModularDeprecationArg): Promise; + getId(deprecationArg?: InstallationsModularDeprecationArg): Promise; + getToken( + forceRefresh?: boolean, + deprecationArg?: InstallationsModularDeprecationArg, + ): Promise; +} + +export interface RNFBInstallationsModule { + getId(): Promise; + getToken(forceRefresh: boolean): Promise; + delete(): Promise; +} + +declare module '@react-native-firebase/app/dist/module/internal/NativeModules' { + interface ReactNativeFirebaseNativeModules { + RNFBInstallationsModule: RNFBInstallationsModule; + } +} diff --git a/packages/installations/lib/types/namespaced.ts b/packages/installations/lib/types/namespaced.ts new file mode 100644 index 0000000000..83cc3a0820 --- /dev/null +++ b/packages/installations/lib/types/namespaced.ts @@ -0,0 +1,112 @@ +/* + * 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 type { ReactNativeFirebase } from '@react-native-firebase/app'; + +/** + * Firebase Installations package for React Native. + * + * @firebase installations + */ +/** + * @deprecated Use the exported types directly instead. + * FirebaseInstallationsTypes namespace is kept for backwards compatibility. + */ +/* eslint-disable @typescript-eslint/no-namespace */ +export namespace FirebaseInstallationsTypes { + /** + * @deprecated Use the exported types directly instead. + */ + export interface Statics { + SDK_VERSION: string; + } + + /** + * The Firebase Installations service is available for the default app or a given app. + * + * @deprecated Use the exported types directly instead. FirebaseInstallationsTypes namespace is kept for backwards compatibility. + */ + export interface Module extends ReactNativeFirebase.FirebaseModule { + /** + * The current `FirebaseApp` instance for this Firebase service. + * + * @deprecated Use the exported types directly instead. + */ + app: ReactNativeFirebase.FirebaseApp; + + /** + * Creates a Firebase Installation if there isn't one for the app and returns the Installation ID. + * + * @deprecated Use `getId()` from the modular API instead. + */ + getId(): Promise; + + /** + * Retrieves a valid installation auth token. + * + * @deprecated Use `getToken()` from the modular API instead. + */ + getToken(forceRefresh?: boolean): Promise; + + /** + * Deletes the Firebase Installation and all associated data from the Firebase backend. + * + * @deprecated Use `deleteInstallations()` from the modular API instead. + */ + delete(): Promise; + } + + export type InstallationsNamespace = ReactNativeFirebase.FirebaseModuleWithStaticsAndApp< + Module, + Statics + > & { + installations: ReactNativeFirebase.FirebaseModuleWithStaticsAndApp; + firebase: ReactNativeFirebase.Module; + app(name?: string): ReactNativeFirebase.FirebaseApp; + }; +} + +declare const defaultExport: FirebaseInstallationsTypes.InstallationsNamespace; + +export declare const firebase: ReactNativeFirebase.Module & { + installations: typeof defaultExport; + app( + name?: string, + ): ReactNativeFirebase.FirebaseApp & { installations(): FirebaseInstallationsTypes.Module }; +}; + +export default defaultExport; + +/** + * Attach namespace to `firebase.` and `FirebaseApp.`. + */ +declare module '@react-native-firebase/app' { + namespace ReactNativeFirebase { + import FirebaseModuleWithStaticsAndApp = ReactNativeFirebase.FirebaseModuleWithStaticsAndApp; + + interface Module { + installations: FirebaseModuleWithStaticsAndApp< + FirebaseInstallationsTypes.Module, + FirebaseInstallationsTypes.Statics + >; + } + + interface FirebaseApp { + installations(): FirebaseInstallationsTypes.Module; + } + } +} diff --git a/packages/installations/package.json b/packages/installations/package.json index de1373a88d..125db21776 100644 --- a/packages/installations/package.json +++ b/packages/installations/package.json @@ -3,12 +3,13 @@ "version": "24.0.0", "author": "Invertase (http://invertase.io)", "description": "React Native Firebase - Installations", - "main": "lib/index.js", - "types": "lib/index.d.ts", + "main": "./dist/module/index.js", + "types": "./dist/typescript/lib/index.d.ts", "scripts": { - "build": "genversion --semi lib/version.js", + "build": "genversion --esm --semi lib/version.ts", "build:clean": "rimraf android/build && rimraf ios/build", - "prepare": "yarn run build" + "compile": "bob build", + "prepare": "yarn run build && yarn compile" }, "repository": { "type": "git", @@ -27,5 +28,34 @@ "publishConfig": { "access": "public", "provenance": true + }, + "devDependencies": { + "react-native-builder-bob": "^0.40.13" + }, + "exports": { + ".": { + "source": "./lib/index.ts", + "types": "./dist/typescript/lib/index.d.ts", + "default": "./dist/module/index.js" + }, + "./package.json": "./package.json" + }, + "react-native-builder-bob": { + "source": "lib", + "output": "dist", + "targets": [ + [ + "module", + { + "esm": true + } + ], + [ + "typescript", + { + "tsc": "../../node_modules/.bin/tsc" + } + ] + ] } } diff --git a/packages/installations/tsconfig.json b/packages/installations/tsconfig.json new file mode 100644 index 0000000000..b853d46ea2 --- /dev/null +++ b/packages/installations/tsconfig.json @@ -0,0 +1,20 @@ +{ + "extends": "../../tsconfig.packages.base.json", + "compilerOptions": { + "rootDir": ".", + "paths": { + "@react-native-firebase/app/dist/module/common/*": ["../app/dist/typescript/lib/common/*"], + "@react-native-firebase/app/dist/module/common": ["../app/dist/typescript/lib/common"], + "@react-native-firebase/app/dist/module/internal/*": [ + "../app/dist/typescript/lib/internal/*" + ], + "@react-native-firebase/app/dist/module/internal": ["../app/dist/typescript/lib/internal"], + "@react-native-firebase/app/dist/module/internal/NativeModules": [ + "../app/dist/typescript/lib/internal/NativeModules" + ], + "@react-native-firebase/app": ["../app/dist/typescript/lib"] + } + }, + "include": ["lib/**/*.ts"], + "exclude": ["node_modules", "dist", "__tests__", "**/*.test.ts", "lib/**/*.d.ts"] +} diff --git a/packages/installations/type-test.ts b/packages/installations/type-test.ts index 3df090f8b3..943d4fa128 100644 --- a/packages/installations/type-test.ts +++ b/packages/installations/type-test.ts @@ -6,6 +6,12 @@ import installations, { getToken, onIdChange, } from '.'; +import type { + FirebaseInstallationsTypes, + IdChangeCallbackFn, + IdChangeUnsubscribeFn, + Installations, +} from '.'; console.log(installations().app); @@ -55,6 +61,8 @@ installationsInstance.delete().then(() => { // checks modular API functions const modularInstallations1 = getInstallations(); console.log(modularInstallations1.app.name); +const typedInstallations: Installations = modularInstallations1; +console.log(typedInstallations.app.name); const modularInstallations2 = getInstallations(firebase.app()); console.log(modularInstallations2.app.name); @@ -78,11 +86,21 @@ deleteInstallations(modularInstallations1).then(() => { console.log('Modular installation deleted'); }); +const namespacedInstallations: FirebaseInstallationsTypes.Module = installationsInstance; +namespacedInstallations.getId().then((id: string) => { + console.log(id); +}); + // Note: onIdChange throws an error in React Native Firebase try { - onIdChange(modularInstallations1, (id: string) => { + const onInstallationsIdChange: IdChangeCallbackFn = id => { console.log(id); - }); + }; + const unsubscribe: IdChangeUnsubscribeFn = onIdChange( + modularInstallations1, + onInstallationsIdChange, + ); + unsubscribe(); } catch (error) { console.log('Modular onIdChange not supported'); } diff --git a/packages/installations/typedoc.json b/packages/installations/typedoc.json index bf93ba7159..e83cc5c235 100644 --- a/packages/installations/typedoc.json +++ b/packages/installations/typedoc.json @@ -1,6 +1,5 @@ { "$schema": "https://typedoc.org/schema.json", - "entryPoints": ["lib/index.d.ts"], - "intentionallyNotExported": ["InstallationsNamespace"] - + "entryPoints": ["lib/modular.ts", "lib/types/installations.ts"], + "tsconfig": "tsconfig.json" } diff --git a/tsconfig.json b/tsconfig.json index 45891f2d0f..f340a813d9 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -17,8 +17,6 @@ "packages/firestore/lib/modular/VectorValue.d.ts", "packages/in-app-messaging/lib/index.d.ts", "packages/in-app-messaging/lib/modular/index.d.ts", - "packages/installations/lib/index.d.ts", - "packages/installations/lib/modular/index.d.ts", "packages/ml/lib/index.d.ts", "packages/ml/lib/modular/index.d.ts", "packages/functions/type-test.ts", diff --git a/yarn.lock b/yarn.lock index 425ee1acc5..e152e7a0eb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6119,6 +6119,8 @@ __metadata: "@react-native-firebase/installations@npm:24.0.0, @react-native-firebase/installations@workspace:packages/installations": version: 0.0.0-use.local resolution: "@react-native-firebase/installations@workspace:packages/installations" + dependencies: + react-native-builder-bob: "npm:^0.40.13" peerDependencies: "@react-native-firebase/app": 24.0.0 languageName: unknown