diff --git a/jest.config.js b/jest.config.js index e26ff06bb0..09fcb23c50 100644 --- a/jest.config.js +++ b/jest.config.js @@ -20,6 +20,10 @@ module.exports = { '^.+\\.(js)$': '/node_modules/babel-jest', '\\.(ts|tsx)$': ['ts-jest', { tsconfig: './tsconfig-jest.json' }], }, + // Strip explicit `.js` from relative imports so Jest resolves sibling `.ts` sources. + moduleNameMapper: { + '^(\\.{1,2}/.*)\\.js$': '$1', + }, setupFiles: ['./jest.setup.ts'], testMatch: ['**/packages/**/__tests__/**/*.test.(ts|js)'], modulePaths: ['node_modules', './tests/node_modules'], diff --git a/package.json b/package.json index abf1d71a63..af2c194fa6 100644 --- a/package.json +++ b/package.json @@ -57,8 +57,7 @@ "tests:ios:test-cover-reuse": "cd tests && SIMCTL_CHILD_GULGeneratedClassDisposeDisabled=1 node_modules/.bin/nyc yarn detox test --configuration ios.sim.debug --reuse --loglevel warn", "tests:ios:pod:install": "cd tests && rm -f ios/Podfile.lock && rm -rf ios/ReactNativeFirebaseDemo.xcworkspace && cd ios && pod install", "tests:macos:build": "cd tests && yarn build:macos", - "tests:macos:pod:install": "cd tests && rm -f macos/Podfile.lock && cd macos && pod install", - "tests:macos:manual": "cd tests && yarn react-native run-macos", + "tests:macos:pod:install": "cd tests && rm -f macos/Podfile.lock && cd macos && pod install", "tests:macos:manual": "cd tests && yarn react-native run-macos", "tests:macos:test": "cd tests && npx jet --target=macos --coverage", "tests:macos:test-cover": "cd tests && npx jet --target=macos --coverage", "format:js": "prettier --write \"packages/**/*.{js,ts,tsx}\"", diff --git a/packages/ai/__tests__/live-session.test.ts b/packages/ai/__tests__/live-session.test.ts index 1a638e38a4..c97b6495c2 100644 --- a/packages/ai/__tests__/live-session.test.ts +++ b/packages/ai/__tests__/live-session.test.ts @@ -29,6 +29,8 @@ import { AIError } from '../lib/errors'; import { logger } from '../lib/logger'; import { ReadableStream } from 'web-streams-polyfill'; +type LiveReceiveYield = LiveServerContent | LiveServerToolCall | LiveServerToolCallCancellation; + class MockWebSocketHandler implements WebSocketHandler { connect = jest.fn<() => Promise>().mockResolvedValue(undefined); send = jest.fn<(data: string | ArrayBuffer) => void>(); @@ -216,7 +218,7 @@ describe('LiveSession', function () { describe('receive()', function () { it('should correctly parse and transform all server message types', async function () { const receivePromise = (async () => { - const responses = []; + const responses: LiveReceiveYield[] = []; for await (const response of session.receive()) { responses.push(response); } @@ -257,7 +259,7 @@ describe('LiveSession', function () { it('should log a warning and skip messages that are not objects', async function () { const loggerSpy = jest.spyOn(logger, 'warn'); const receivePromise = (async () => { - const responses = []; + const responses: LiveReceiveYield[] = []; for await (const response of session.receive()) { responses.push(response); } @@ -282,7 +284,7 @@ describe('LiveSession', function () { it('should log a warning and skip objects of unknown type', async function () { const loggerSpy = jest.spyOn(logger, 'warn'); const receivePromise = (async () => { - const responses = []; + const responses: LiveReceiveYield[] = []; for await (const response of session.receive()) { responses.push(response); } diff --git a/packages/ai/lib/public-types.ts b/packages/ai/lib/public-types.ts index e17cb281db..fb75a5c3e6 100644 --- a/packages/ai/lib/public-types.ts +++ b/packages/ai/lib/public-types.ts @@ -16,7 +16,7 @@ */ import { ReactNativeFirebase } from '@react-native-firebase/app'; -import { FirebaseAuthTypes } from '@react-native-firebase/auth'; +import type { FirebaseAuthTypes } from '@react-native-firebase/auth'; import { FirebaseAppCheckTypes } from '@react-native-firebase/app-check'; import { Backend } from './backend'; diff --git a/packages/ai/lib/requests/request.ts b/packages/ai/lib/requests/request.ts index 1a6b978b7d..d50bac1a18 100644 --- a/packages/ai/lib/requests/request.ts +++ b/packages/ai/lib/requests/request.ts @@ -153,7 +153,7 @@ export class TemplateRequestUrl { * Log language and "fire/version" to x-goog-api-client */ function getClientHeaders(): string { - const loggingTags = []; + const loggingTags: string[] = []; loggingTags.push(`${LANGUAGE_TAG}/${PACKAGE_VERSION}`); loggingTags.push(`fire/${PACKAGE_VERSION}`); return loggingTags.join(' '); diff --git a/packages/ai/lib/requests/response-helpers.ts b/packages/ai/lib/requests/response-helpers.ts index c2667477d0..abc1357994 100644 --- a/packages/ai/lib/requests/response-helpers.ts +++ b/packages/ai/lib/requests/response-helpers.ts @@ -160,7 +160,7 @@ export function getText( response: GenerateContentResponse, partFilter: (part: Part) => boolean, ): string { - const textStrings = []; + const textStrings: string[] = []; if (response.candidates?.[0]?.content?.parts) { for (const part of response.candidates?.[0]?.content?.parts) { if (part.text && partFilter(part)) { diff --git a/packages/ai/lib/requests/schema-builder.ts b/packages/ai/lib/requests/schema-builder.ts index 21c5605cb7..a6a047fa9d 100644 --- a/packages/ai/lib/requests/schema-builder.ts +++ b/packages/ai/lib/requests/schema-builder.ts @@ -259,7 +259,7 @@ export class ObjectSchema extends Schema { toJSON(): SchemaRequest { const obj = super.toJSON(); obj.properties = { ...this.properties }; - const required = []; + const required: string[] = []; if (this.optionalProperties) { for (const propertyKey of this.optionalProperties) { if (!this.properties.hasOwnProperty(propertyKey)) { diff --git a/packages/ai/lib/service.ts b/packages/ai/lib/service.ts index 79bf741303..60a3ae6d59 100644 --- a/packages/ai/lib/service.ts +++ b/packages/ai/lib/service.ts @@ -17,7 +17,7 @@ import { ReactNativeFirebase } from '@react-native-firebase/app'; import { AI, Backend } from './public-types'; -import { FirebaseAuthTypes } from '@react-native-firebase/auth'; +import type { FirebaseAuthTypes } from '@react-native-firebase/auth'; import { FirebaseAppCheckTypes } from '@react-native-firebase/app-check'; import { VertexAIBackend } from './backend'; diff --git a/packages/ai/tsconfig.json b/packages/ai/tsconfig.json index 837c336e3e..f57afbea70 100644 --- a/packages/ai/tsconfig.json +++ b/packages/ai/tsconfig.json @@ -32,7 +32,7 @@ ], "@react-native-firebase/app/lib/internal": ["../app/dist/typescript/lib/internal"], "@react-native-firebase/app": ["../app/dist/typescript/lib"], - "@react-native-firebase/auth": ["../auth/lib"], + "@react-native-firebase/auth": ["../auth/dist/typescript/lib"], "@react-native-firebase/app-check": ["../app-check/dist/typescript/lib"] } }, diff --git a/packages/app-check/lib/web/RNFBAppCheckModule.android.ts b/packages/app-check/lib/web/RNFBAppCheckModule.android.ts index 6945829a16..2234e6431a 100644 --- a/packages/app-check/lib/web/RNFBAppCheckModule.android.ts +++ b/packages/app-check/lib/web/RNFBAppCheckModule.android.ts @@ -1,4 +1,4 @@ -// No-op for android. -const module: Record = {}; +// No-op for android. Avoid binding name `module` (Jest runs TS in a CJS context). +const noopNativeModule: Record = {}; -export default module; +export default noopNativeModule; diff --git a/packages/app-check/lib/web/RNFBAppCheckModule.ios.ts b/packages/app-check/lib/web/RNFBAppCheckModule.ios.ts index 055f3bce5b..eedc356304 100644 --- a/packages/app-check/lib/web/RNFBAppCheckModule.ios.ts +++ b/packages/app-check/lib/web/RNFBAppCheckModule.ios.ts @@ -1,4 +1,4 @@ -// No-op for ios. -const module: Record = {}; +// No-op for ios. Avoid binding name `module` (Jest runs TS in a CJS context). +const noopNativeModule: Record = {}; -export default module; +export default noopNativeModule; diff --git a/packages/app/lib/common/Base64.ts b/packages/app/lib/common/Base64.ts index 707d7f1796..96b3cda15c 100644 --- a/packages/app/lib/common/Base64.ts +++ b/packages/app/lib/common/Base64.ts @@ -15,7 +15,6 @@ * */ -// @ts-expect-error - No type declarations available import binaryToBase64 from 'react-native/Libraries/Utilities/binaryToBase64'; import { promiseDefer } from './promise'; diff --git a/packages/app/lib/shims/react-native-binaryToBase64.d.ts b/packages/app/lib/shims/react-native-binaryToBase64.d.ts new file mode 100644 index 0000000000..32f150316b --- /dev/null +++ b/packages/app/lib/shims/react-native-binaryToBase64.d.ts @@ -0,0 +1,7 @@ +/* + * Deep import from `react-native` (not declared in `@types/react-native`). + * Used by @react-native-firebase/app Base64 helper. + */ +declare module 'react-native/Libraries/Utilities/binaryToBase64' { + export default function binaryToBase64(data: ArrayBuffer | Uint8Array): string; +} diff --git a/packages/auth/e2e/phone.e2e.js b/packages/auth/e2e/phone.e2e.js index 217f220589..e2b2338bba 100644 --- a/packages/auth/e2e/phone.e2e.js +++ b/packages/auth/e2e/phone.e2e.js @@ -46,12 +46,11 @@ describe('auth() => Phone', function () { confirmResult.confirm.should.be.a.Function(); const lastSmsCode = await getLastSmsCode(testPhone); const userCredential = await confirmResult.confirm(lastSmsCode); - userCredential.user.should.be.instanceOf( - require('@react-native-firebase/auth/lib/User').default, - ); - - // Broken check, phone number is undefined - // userCredential.user.phoneNumber.should.equal(TEST_PHONE_A); + const { user } = userCredential; + // Avoid instanceof: Metro may load User from two module paths (main vs deep require). + user.constructor.name.should.equal('User'); + user.uid.should.be.a.String(); + user.phoneNumber.should.equal(testPhone); }); it('errors on invalid code', async function () { @@ -237,12 +236,11 @@ describe('auth() => Phone', function () { confirmResult.confirm.should.be.a.Function(); const lastSmsCode = await getLastSmsCode(testPhone); const userCredential = await confirmResult.confirm(lastSmsCode); - userCredential.user.should.be.instanceOf( - require('@react-native-firebase/auth/lib/User').default, - ); - - // Broken check, phone number is undefined - // userCredential.user.phoneNumber.should.equal(TEST_PHONE_A); + const { user } = userCredential; + // Avoid instanceof: Metro may load User from two module paths (main vs deep require). + user.constructor.name.should.equal('User'); + user.uid.should.be.a.String(); + user.phoneNumber.should.equal(testPhone); }); it('errors on invalid code', async function () { diff --git a/packages/auth/e2e/user.e2e.js b/packages/auth/e2e/user.e2e.js index 08e0713e49..ea1a27fc78 100644 --- a/packages/auth/e2e/user.e2e.js +++ b/packages/auth/e2e/user.e2e.js @@ -622,7 +622,8 @@ describe('auth().currentUser', function () { try { await firebase.auth().currentUser.delete(); } catch (e) { - consle.log(e); + // eslint-disable-next-line no-console + console.log(e); /* do nothing */ } @@ -1621,7 +1622,8 @@ describe('auth().currentUser', function () { try { await deleteUser(auth.currentUser); } catch (e) { - consle.log(e); + // eslint-disable-next-line no-console + console.log(e); /* do nothing */ } diff --git a/packages/auth/lib/ConfirmationResult.js b/packages/auth/lib/ConfirmationResult.ts similarity index 71% rename from packages/auth/lib/ConfirmationResult.js rename to packages/auth/lib/ConfirmationResult.ts index 25b72a2cd7..aa8e9b71bd 100644 --- a/packages/auth/lib/ConfirmationResult.js +++ b/packages/auth/lib/ConfirmationResult.ts @@ -15,19 +15,24 @@ * */ +import type { AuthInternal } from './types/internal'; + export default class ConfirmationResult { - constructor(auth, verificationId) { + _auth: AuthInternal; + _verificationId: string; + + constructor(auth: AuthInternal, verificationId: string) { this._auth = auth; this._verificationId = verificationId; } - confirm(verificationCode) { + confirm(verificationCode: string): Promise { return this._auth.native .confirmationResultConfirm(verificationCode) - .then(userCredential => this._auth._setUserCredential(userCredential)); + .then((userCredential: unknown) => this._auth._setUserCredential(userCredential)); } - get verificationId() { + get verificationId(): string { return this._verificationId; } } diff --git a/packages/auth/lib/MultiFactorResolver.js b/packages/auth/lib/MultiFactorResolver.js deleted file mode 100644 index 364c5d4ec5..0000000000 --- a/packages/auth/lib/MultiFactorResolver.js +++ /dev/null @@ -1,20 +0,0 @@ -/** - * Base class to facilitate multi-factor authentication. - */ -export default class MultiFactorResolver { - constructor(auth, resolver) { - this._auth = auth; - this.hints = resolver.hints; - this.session = resolver.session; - } - - resolveSignIn(assertion) { - const { token, secret, uid, verificationCode } = assertion; - - if (token && secret) { - return this._auth.resolveMultiFactorSignIn(this.session, token, secret); - } - - return this._auth.resolveTotpSignIn(this.session, uid, verificationCode); - } -} diff --git a/packages/auth/lib/MultiFactorResolver.ts b/packages/auth/lib/MultiFactorResolver.ts new file mode 100644 index 0000000000..cc2906a3c6 --- /dev/null +++ b/packages/auth/lib/MultiFactorResolver.ts @@ -0,0 +1,51 @@ +/* + * 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 { AuthInternal } from './types/internal'; +import type { MultiFactorInfo } from './types/auth'; + +interface ResolverShape { + hints: MultiFactorInfo[]; + session: string; +} + +export default class MultiFactorResolver { + _auth: AuthInternal; + hints: MultiFactorInfo[]; + session: string; + + constructor(auth: AuthInternal, resolver: ResolverShape) { + this._auth = auth; + this.hints = resolver.hints; + this.session = resolver.session; + } + + resolveSignIn(assertion: { + token?: string; + secret?: string; + uid?: string; + verificationCode?: string; + }): Promise { + const { token, secret, uid, verificationCode } = assertion; + + if (token && secret) { + return this._auth.resolveMultiFactorSignIn(this.session, token, secret); + } + + return this._auth.resolveTotpSignIn(this.session, uid ?? '', verificationCode ?? ''); + } +} diff --git a/packages/auth/lib/PhoneAuthListener.js b/packages/auth/lib/PhoneAuthListener.ts similarity index 53% rename from packages/auth/lib/PhoneAuthListener.js rename to packages/auth/lib/PhoneAuthListener.ts index eed1aa7021..5e8ebcf7dc 100644 --- a/packages/auth/lib/PhoneAuthListener.js +++ b/packages/auth/lib/PhoneAuthListener.ts @@ -22,22 +22,40 @@ import { promiseDefer, } from '@react-native-firebase/app/dist/module/common'; import NativeFirebaseError from '@react-native-firebase/app/dist/module/internal/NativeFirebaseError'; +import type { AuthInternal } from './types/internal'; let REQUEST_ID = 0; +export interface PhoneAuthSnapshot { + verificationId: string; + code: string | null; + error: unknown; + state: 'sent' | 'timeout' | 'verified' | 'error'; +} + export default class PhoneAuthListener { - constructor(auth, phoneNumber, timeout, forceResend) { + _auth: AuthInternal; + _reject: ((error: unknown) => void) | null; + _resolve: ((snapshot: PhoneAuthSnapshot) => void) | null; + _promise: Promise | null; + _jsStack: string | undefined; + _timeout: number; + _phoneAuthRequestId: number; + _forceResending: boolean; + _internalEvents: Record; + _publicEvents: Record; + + constructor(auth: AuthInternal, phoneNumber: string, timeout?: number, forceResend?: boolean) { this._auth = auth; this._reject = null; this._resolve = null; this._promise = null; this._jsStack = new Error().stack; - this._timeout = timeout || 20; + this._timeout = timeout ?? 20; this._phoneAuthRequestId = REQUEST_ID++; - this._forceResending = forceResend || false; + this._forceResending = forceResend ?? false; - // internal events this._internalEvents = { codeSent: `phone:auth:${this._phoneAuthRequestId}:onCodeSent`, verificationFailed: `phone:auth:${this._phoneAuthRequestId}:onVerificationFailed`, @@ -45,7 +63,6 @@ export default class PhoneAuthListener { codeAutoRetrievalTimeout: `phone:auth:${this._phoneAuthRequestId}:onCodeAutoRetrievalTimeout`, }; - // user observer events this._publicEvents = { error: `phone:auth:${this._phoneAuthRequestId}:error`, event: `phone:auth:${this._phoneAuthRequestId}:event`, @@ -57,82 +74,77 @@ export default class PhoneAuthListener { if (isAndroid) { this._auth.native.verifyPhoneNumber( phoneNumber, - this._phoneAuthRequestId + '', + String(this._phoneAuthRequestId), this._timeout, this._forceResending, ); } if (isIOS) { - this._auth.native.verifyPhoneNumber(phoneNumber, this._phoneAuthRequestId + ''); + this._auth.native.verifyPhoneNumber(phoneNumber, String(this._phoneAuthRequestId)); } } - _subscribeToEvents() { + _subscribeToEvents(): void { const events = Object.keys(this._internalEvents); for (let i = 0, len = events.length; i < len; i++) { - const type = events[i]; - const subscription = this._auth.emitter.addListener(this._internalEvents[type], event => { - this[`_${type}Handler`](event); + const type = events[i]!; + const eventName = this._internalEvents[type as keyof typeof this._internalEvents]!; + const handler = (this as unknown as Record void>)[`_${type}Handler`]; + const subscription = this._auth.emitter.addListener(eventName, (event: unknown) => { + if (typeof handler === 'function') handler.call(this, event); subscription.remove(); }); } } - _addUserObserver(observer) { - this._auth.emitter.addListener(this._publicEvents.event, observer); + _addUserObserver(observer: (snapshot: PhoneAuthSnapshot) => void): void { + this._auth.emitter.addListener(this._publicEvents.event!, observer); } - _emitToObservers(snapshot) { - this._auth.emitter.emit(this._publicEvents.event, snapshot); + _emitToObservers(snapshot: PhoneAuthSnapshot): void { + this._auth.emitter.emit(this._publicEvents.event!, snapshot); } - _emitToErrorCb(snapshot) { + _emitToErrorCb(snapshot: { error: unknown }): void { const { error } = snapshot; if (this._reject) { this._reject(error); } - this._auth.emitter.emit(this._publicEvents.error, error); + this._auth.emitter.emit(this._publicEvents.error!, error); } - _emitToSuccessCb(snapshot) { + _emitToSuccessCb(snapshot: PhoneAuthSnapshot): void { if (this._resolve) { this._resolve(snapshot); } - this._auth.emitter.emit(this._publicEvents.success, snapshot); + this._auth.emitter.emit(this._publicEvents.success!, snapshot); } - _removeAllListeners() { + _removeAllListeners(): void { setTimeout(() => { - // move to next event loop - not sure if needed - // internal listeners Object.values(this._internalEvents).forEach(event => { this._auth.emitter.removeAllListeners(event); }); - // user observer listeners Object.values(this._publicEvents).forEach(publicEvent => { this._auth.emitter.removeAllListeners(publicEvent); }); }, 0); } - _promiseDeferred() { + _promiseDeferred(): void { if (!this._promise) { - const { promise, resolve, reject } = promiseDefer(); + const { promise, resolve, reject } = promiseDefer(); this._promise = promise; this._resolve = resolve; this._reject = reject; } } - /* -------------------------- - --- INTERNAL EVENT HANDLERS - ---------------------------- */ - - _codeSentHandler(credential) { - const snapshot = { + _codeSentHandler(credential: { verificationId: string }): void { + const snapshot: PhoneAuthSnapshot = { verificationId: credential.verificationId, code: null, error: null, @@ -144,15 +156,10 @@ export default class PhoneAuthListener { if (isIOS) { this._emitToSuccessCb(snapshot); } - - if (isAndroid) { - // android can auto retrieve so we don't emit to successCb immediately, - // if auto retrieve times out then that will emit to successCb - } } - _codeAutoRetrievalTimeoutHandler(credential) { - const snapshot = { + _codeAutoRetrievalTimeoutHandler(credential: { verificationId: string }): void { + const snapshot: PhoneAuthSnapshot = { verificationId: credential.verificationId, code: null, error: null, @@ -163,10 +170,10 @@ export default class PhoneAuthListener { this._emitToSuccessCb(snapshot); } - _verificationCompleteHandler(credential) { - const snapshot = { + _verificationCompleteHandler(credential: { verificationId: string; code?: string }): void { + const snapshot: PhoneAuthSnapshot = { verificationId: credential.verificationId, - code: credential.code || null, + code: credential.code ?? null, error: null, state: 'verified', }; @@ -176,26 +183,31 @@ export default class PhoneAuthListener { this._removeAllListeners(); } - _verificationFailedHandler(state) { - const snapshot = { + _verificationFailedHandler(state: { verificationId: string; error: unknown }): void { + const snapshot: PhoneAuthSnapshot = { verificationId: state.verificationId, code: null, error: null, state: 'error', }; - snapshot.error = new NativeFirebaseError({ userInfo: state.error }, this._jsStack, 'auth'); + (snapshot as { error: unknown }).error = new NativeFirebaseError( + { userInfo: state.error } as never, + this._jsStack ?? '', + 'auth', + ); this._emitToObservers(snapshot); this._emitToErrorCb(snapshot); this._removeAllListeners(); } - /* ------------- - -- PUBLIC API - --------------*/ - - on(event, observer, errorCb, successCb) { + on( + event: string, + observer: (snapshot: PhoneAuthSnapshot) => void, + errorCb?: (error: unknown) => void, + successCb?: (snapshot: PhoneAuthSnapshot) => void, + ): this { if (event !== 'state_changed') { throw new Error( "firebase.auth.PhoneAuthListener.on(*, _, _, _) 'event' must equal 'state_changed'.", @@ -211,34 +223,45 @@ export default class PhoneAuthListener { this._addUserObserver(observer); if (isFunction(errorCb)) { - const subscription = this._auth.emitter.addListener(this._publicEvents.error, event => { - subscription.remove(); - errorCb(event); - }); + const onError = errorCb; + const subscription = this._auth.emitter.addListener( + this._publicEvents.error!, + (event: unknown) => { + subscription.remove(); + onError(event); + }, + ); } if (isFunction(successCb)) { - const subscription = this._auth.emitter.addListener(this._publicEvents.success, event => { - subscription.remove(); - successCb(event); - }); + const onSuccess = successCb; + const subscription = this._auth.emitter.addListener( + this._publicEvents.success!, + (event: PhoneAuthSnapshot) => { + subscription.remove(); + onSuccess(event); + }, + ); } return this; } - then(fn) { + then( + onFulfilled?: ((a: PhoneAuthSnapshot) => unknown) | null, + onRejected?: ((a: unknown) => unknown) | null, + ): Promise | undefined { this._promiseDeferred(); if (this._promise) { - return this._promise.then.bind(this._promise)(fn); + return this._promise.then.bind(this._promise)(onFulfilled, onRejected); } return undefined; } - catch(fn) { + catch(onRejected: (a: unknown) => unknown): Promise | undefined { this._promiseDeferred(); if (this._promise) { - return this._promise.catch.bind(this._promise)(fn); + return this._promise.catch.bind(this._promise)(onRejected); } return undefined; } diff --git a/packages/auth/lib/PhoneMultiFactorGenerator.js b/packages/auth/lib/PhoneMultiFactorGenerator.ts similarity index 86% rename from packages/auth/lib/PhoneMultiFactorGenerator.js rename to packages/auth/lib/PhoneMultiFactorGenerator.ts index 1f3bbdd4e4..d8903baba6 100644 --- a/packages/auth/lib/PhoneMultiFactorGenerator.js +++ b/packages/auth/lib/PhoneMultiFactorGenerator.ts @@ -15,6 +15,8 @@ * */ +import type { AuthCredential, MultiFactorAssertion } from './types/auth'; + export default class PhoneMultiFactorGenerator { static FACTOR_ID = 'phone'; @@ -24,9 +26,7 @@ export default class PhoneMultiFactorGenerator { ); } - static assertion(credential) { - // There is no logic here, we mainly do this for API compatibility - // (following the Web API). + static assertion(credential: AuthCredential): MultiFactorAssertion { const { token, secret } = credential; return { token, secret }; } diff --git a/packages/auth/lib/Settings.js b/packages/auth/lib/Settings.ts similarity index 73% rename from packages/auth/lib/Settings.js rename to packages/auth/lib/Settings.ts index 28f1d44d48..db71b6d618 100644 --- a/packages/auth/lib/Settings.js +++ b/packages/auth/lib/Settings.ts @@ -16,35 +16,40 @@ */ import { isAndroid } from '@react-native-firebase/app/dist/module/common'; +import type { AuthInternal } from './types/internal'; export default class Settings { - constructor(auth) { + _auth: AuthInternal; + _forceRecaptchaFlowForTesting: boolean; + _appVerificationDisabledForTesting: boolean; + + constructor(auth: AuthInternal) { this._auth = auth; this._forceRecaptchaFlowForTesting = false; this._appVerificationDisabledForTesting = false; } - get forceRecaptchaFlowForTesting() { + get forceRecaptchaFlowForTesting(): boolean { return this._forceRecaptchaFlowForTesting; } - set forceRecaptchaFlowForTesting(forceRecaptchaFlow) { + set forceRecaptchaFlowForTesting(forceRecaptchaFlow: boolean) { if (isAndroid) { this._forceRecaptchaFlowForTesting = forceRecaptchaFlow; this._auth.native.forceRecaptchaFlowForTesting(forceRecaptchaFlow); } } - get appVerificationDisabledForTesting() { + get appVerificationDisabledForTesting(): boolean { return this._appVerificationDisabledForTesting; } - set appVerificationDisabledForTesting(disabled) { + set appVerificationDisabledForTesting(disabled: boolean) { this._appVerificationDisabledForTesting = disabled; this._auth.native.setAppVerificationDisabledForTesting(disabled); } - setAutoRetrievedSmsCodeForPhoneNumber(phoneNumber, smsCode) { + setAutoRetrievedSmsCodeForPhoneNumber(phoneNumber: string, smsCode: string): Promise { if (isAndroid) { return this._auth.native.setAutoRetrievedSmsCodeForPhoneNumber(phoneNumber, smsCode); } diff --git a/packages/auth/lib/TotpMultiFactorGenerator.js b/packages/auth/lib/TotpMultiFactorGenerator.ts similarity index 64% rename from packages/auth/lib/TotpMultiFactorGenerator.js rename to packages/auth/lib/TotpMultiFactorGenerator.ts index 6d8a3561be..9356651e8d 100644 --- a/packages/auth/lib/TotpMultiFactorGenerator.js +++ b/packages/auth/lib/TotpMultiFactorGenerator.ts @@ -18,6 +18,8 @@ import { isOther } from '@react-native-firebase/app/dist/module/common'; import { TotpSecret } from './TotpSecret'; import { getAuth } from './modular'; +import type { MultiFactorAssertion } from './types/auth'; +import type { AuthInternal } from './types/internal'; export default class TotpMultiFactorGenerator { static FACTOR_ID = 'totp'; @@ -28,28 +30,28 @@ export default class TotpMultiFactorGenerator { ); } - static assertionForSignIn(uid, verificationCode) { + static assertionForSignIn(uid: string, verificationCode: string): unknown { if (isOther) { - // we require the web native assertion when using firebase-js-sdk - // as it has functions used by the SDK, a shim won't do - return getAuth().native.assertionForSignIn(uid, verificationCode); + return (getAuth() as AuthInternal).native.assertionForSignIn!(uid, verificationCode); } return { uid, verificationCode }; } - static assertionForEnrollment(totpSecret, verificationCode) { - return { totpSecret: totpSecret.secretKey, verificationCode }; + static assertionForEnrollment( + totpSecret: TotpSecret, + verificationCode: string, + ): MultiFactorAssertion { + return { + totpSecret: totpSecret.secretKey, + verificationCode, + } as unknown as MultiFactorAssertion; } - static async generateSecret(session, auth) { + static async generateSecret(session: unknown, auth: AuthInternal): Promise { if (!session) { throw new Error('Session is required to generate a TOTP secret.'); } - const { - secretKey, - // Other properties are not publicly exposed in native APIs - // hashingAlgorithm, codeLength, codeIntervalSeconds, enrollmentCompletionDeadline - } = await auth.native.generateTotpSecret(session); + const { secretKey } = await auth.native.generateTotpSecret(session); return new TotpSecret(secretKey, auth); } diff --git a/packages/auth/lib/TotpSecret.js b/packages/auth/lib/TotpSecret.ts similarity index 51% rename from packages/auth/lib/TotpSecret.js rename to packages/auth/lib/TotpSecret.ts index 027e8d92d0..d137d720d4 100644 --- a/packages/auth/lib/TotpSecret.js +++ b/packages/auth/lib/TotpSecret.ts @@ -12,56 +12,44 @@ * 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 { isString } from '@react-native-firebase/app/dist/module/common'; +import type { AuthInternal } from './types/internal'; export class TotpSecret { - constructor(secretKey, auth) { - // The native TotpSecret has many more properties, but they are - // internal to the native SDKs, we only maintain the secret in JS layer - this.secretKey = secretKey; + readonly secretKey: string; - // we do need a handle to the correct auth instance to generate QR codes etc + readonly auth: AuthInternal; + + constructor(secretKey: string, auth: AuthInternal) { + this.secretKey = secretKey; this.auth = auth; } - /** - * Shared secret key/seed used for enrolling in TOTP MFA and generating OTPs. - */ - secretKey = null; - /** * Returns a QR code URL as described in * https://github.com/google/google-authenticator/wiki/Key-Uri-Format * This can be displayed to the user as a QR code to be scanned into a TOTP app like Google Authenticator. * If the optional parameters are unspecified, an accountName of and issuer of are used. - * - * @param accountName the name of the account/app along with a user identifier. - * @param issuer issuer of the TOTP (likely the app name). - * @returns A Promise that resolves to a QR code URL string. */ - async generateQrCodeUrl(accountName, issuer) { - // accountName and issure are nullable in the API specification but are - // required by tha native SDK. The JS SDK returns '' if they are missing/empty. + async generateQrCodeUrl(accountName?: string, issuer?: string): Promise { if (!isString(accountName) || !isString(issuer) || accountName === '' || issuer === '') { return ''; } - return this.auth.native.generateQrCodeUrl(this.secretKey, accountName, issuer); + const name = accountName; + const iss = issuer; + return this.auth.native.generateQrCodeUrl(this.secretKey, name, iss); } /** * Opens the specified QR Code URL in an OTP authenticator app on the device. - * The shared secret key and account name will be populated in the OTP authenticator app. - * The URL uses the otpauth:// scheme and will be opened on an app that handles this scheme, - * if it exists on the device, possibly opening the ecocystem-specific app store with a generic - * query for compatible apps if no app exists on the device. - * - * @param qrCodeUrl the URL to open in the app, from generateQrCodeUrl */ - openInOtpApp(qrCodeUrl) { - if (isString(qrCodeUrl) && !qrCodeUrl !== '') { + openInOtpApp(qrCodeUrl: string): void | Promise | unknown { + if (isString(qrCodeUrl) && qrCodeUrl !== '') { return this.auth.native.openInOtpApp(this.secretKey, qrCodeUrl); } + return undefined; } } diff --git a/packages/auth/lib/User.js b/packages/auth/lib/User.js deleted file mode 100644 index 3ac5591aed..0000000000 --- a/packages/auth/lib/User.js +++ /dev/null @@ -1,343 +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 { - isObject, - isString, - isUndefined, - isBoolean, -} from '@react-native-firebase/app/dist/module/common'; - -export default class User { - constructor(auth, user) { - this._auth = auth; - this._user = user; - } - - get displayName() { - return this._user.displayName || null; - } - - get email() { - return this._user.email || null; - } - - get emailVerified() { - return this._user.emailVerified || false; - } - - get isAnonymous() { - return this._user.isAnonymous || false; - } - - get metadata() { - const { metadata } = this._user; - - return { - lastSignInTime: new Date(metadata.lastSignInTime).toISOString(), - creationTime: new Date(metadata.creationTime).toISOString(), - }; - } - - get multiFactor() { - return this._user.multiFactor || null; - } - - get phoneNumber() { - return this._user.phoneNumber || null; - } - - get tenantId() { - return this._user.tenantId || null; - } - - get photoURL() { - return this._user.photoURL || null; - } - - get providerData() { - return this._user.providerData; - } - - get providerId() { - return this._user.providerId; - } - - get uid() { - return this._user.uid; - } - - delete() { - return this._auth.native.delete().then(() => { - this._auth._setUser(); - }); - } - - getIdToken(forceRefresh = false) { - return this._auth.native.getIdToken(forceRefresh); - } - - getIdTokenResult(forceRefresh = false) { - return this._auth.native.getIdTokenResult(forceRefresh); - } - - linkWithCredential(credential) { - return this._auth.native - .linkWithCredential(credential.providerId, credential.token, credential.secret) - .then(userCredential => this._auth._setUserCredential(userCredential)); - } - - linkWithPopup(provider) { - // call through to linkWithRedirect for shared implementation - return this.linkWithRedirect(provider); - } - - linkWithRedirect(provider) { - return this._auth.native - .linkWithProvider(provider.toObject()) - .then(userCredential => this._auth._setUserCredential(userCredential)); - } - - reauthenticateWithCredential(credential) { - return this._auth.native - .reauthenticateWithCredential(credential.providerId, credential.token, credential.secret) - .then(userCredential => this._auth._setUserCredential(userCredential)); - } - - reauthenticateWithPopup(provider) { - // call through to reauthenticateWithRedirect for shared implementation - return this.reauthenticateWithRedirect(provider); - } - - reauthenticateWithRedirect(provider) { - return this._auth.native - .reauthenticateWithProvider(provider.toObject()) - .then(userCredential => this._auth._setUserCredential(userCredential)); - } - - reload() { - return this._auth.native.reload().then(user => { - this._auth._setUser(user); - }); - } - - sendEmailVerification(actionCodeSettings) { - if (isObject(actionCodeSettings)) { - if (!isString(actionCodeSettings.url)) { - throw new Error( - "firebase.auth.User.sendEmailVerification(*) 'actionCodeSettings.url' expected a string value.", - ); - } - - if (!isUndefined(actionCodeSettings.linkDomain) && !isString(actionCodeSettings.linkDomain)) { - throw new Error( - "firebase.auth.User.sendEmailVerification(*) 'actionCodeSettings.linkDomain' expected a string value.", - ); - } - - if ( - !isUndefined(actionCodeSettings.handleCodeInApp) && - !isBoolean(actionCodeSettings.handleCodeInApp) - ) { - throw new Error( - "firebase.auth.User.sendEmailVerification(*) 'actionCodeSettings.handleCodeInApp' expected a boolean value.", - ); - } - - if (!isUndefined(actionCodeSettings.iOS)) { - if (!isObject(actionCodeSettings.iOS)) { - throw new Error( - "firebase.auth.User.sendEmailVerification(*) 'actionCodeSettings.iOS' expected an object value.", - ); - } - if (!isString(actionCodeSettings.iOS.bundleId)) { - throw new Error( - "firebase.auth.User.sendEmailVerification(*) 'actionCodeSettings.iOS.bundleId' expected a string value.", - ); - } - } - - if (!isUndefined(actionCodeSettings.android)) { - if (!isObject(actionCodeSettings.android)) { - throw new Error( - "firebase.auth.User.sendEmailVerification(*) 'actionCodeSettings.android' expected an object value.", - ); - } - if (!isString(actionCodeSettings.android.packageName)) { - throw new Error( - "firebase.auth.User.sendEmailVerification(*) 'actionCodeSettings.android.packageName' expected a string value.", - ); - } - - if ( - !isUndefined(actionCodeSettings.android.installApp) && - !isBoolean(actionCodeSettings.android.installApp) - ) { - throw new Error( - "firebase.auth.User.sendEmailVerification(*) 'actionCodeSettings.android.installApp' expected a boolean value.", - ); - } - - if ( - !isUndefined(actionCodeSettings.android.minimumVersion) && - !isString(actionCodeSettings.android.minimumVersion) - ) { - throw new Error( - "firebase.auth.User.sendEmailVerification(*) 'actionCodeSettings.android.minimumVersion' expected a string value.", - ); - } - } - } - - return this._auth.native.sendEmailVerification(actionCodeSettings).then(user => { - this._auth._setUser(user); - }); - } - - toJSON() { - return Object.assign({}, this._user); - } - - unlink(providerId) { - return this._auth.native.unlink(providerId).then(user => this._auth._setUser(user)); - } - - updateEmail(email) { - return this._auth.native.updateEmail(email).then(user => { - this._auth._setUser(user); - }); - } - - updatePassword(password) { - return this._auth.native.updatePassword(password).then(user => { - this._auth._setUser(user); - }); - } - - updatePhoneNumber(credential) { - return this._auth.native - .updatePhoneNumber(credential.providerId, credential.token, credential.secret) - .then(user => { - this._auth._setUser(user); - }); - } - - updateProfile(updates) { - return this._auth.native.updateProfile(updates).then(user => { - this._auth._setUser(user); - }); - } - - verifyBeforeUpdateEmail(newEmail, actionCodeSettings) { - if (!isString(newEmail)) { - throw new Error( - "firebase.auth.User.verifyBeforeUpdateEmail(*) 'newEmail' expected a string value.", - ); - } - - if (isObject(actionCodeSettings)) { - if (!isString(actionCodeSettings.url)) { - throw new Error( - "firebase.auth.User.verifyBeforeUpdateEmail(_, *) 'actionCodeSettings.url' expected a string value.", - ); - } - - if (!isUndefined(actionCodeSettings.linkDomain) && !isString(actionCodeSettings.linkDomain)) { - throw new Error( - "firebase.auth.User.verifyBeforeUpdateEmail(_, *) 'actionCodeSettings.linkDomain' expected a string value.", - ); - } - - if ( - !isUndefined(actionCodeSettings.handleCodeInApp) && - !isBoolean(actionCodeSettings.handleCodeInApp) - ) { - throw new Error( - "firebase.auth.User.verifyBeforeUpdateEmail(_, *) 'actionCodeSettings.handleCodeInApp' expected a boolean value.", - ); - } - - if (!isUndefined(actionCodeSettings.iOS)) { - if (!isObject(actionCodeSettings.iOS)) { - throw new Error( - "firebase.auth.User.verifyBeforeUpdateEmail(_, *) 'actionCodeSettings.iOS' expected an object value.", - ); - } - if (!isString(actionCodeSettings.iOS.bundleId)) { - throw new Error( - "firebase.auth.User.verifyBeforeUpdateEmail(_, *) 'actionCodeSettings.iOS.bundleId' expected a string value.", - ); - } - } - - if (!isUndefined(actionCodeSettings.android)) { - if (!isObject(actionCodeSettings.android)) { - throw new Error( - "firebase.auth.User.verifyBeforeUpdateEmail(_, *) 'actionCodeSettings.android' expected an object value.", - ); - } - if (!isString(actionCodeSettings.android.packageName)) { - throw new Error( - "firebase.auth.User.verifyBeforeUpdateEmail(_, *) 'actionCodeSettings.android.packageName' expected a string value.", - ); - } - - if ( - !isUndefined(actionCodeSettings.android.installApp) && - !isBoolean(actionCodeSettings.android.installApp) - ) { - throw new Error( - "firebase.auth.User.verifyBeforeUpdateEmail(_, *) 'actionCodeSettings.android.installApp' expected a boolean value.", - ); - } - - if ( - !isUndefined(actionCodeSettings.android.minimumVersion) && - !isString(actionCodeSettings.android.minimumVersion) - ) { - throw new Error( - "firebase.auth.User.verifyBeforeUpdateEmail(_, *) 'actionCodeSettings.android.minimumVersion' expected a string value.", - ); - } - } - } - - return this._auth.native.verifyBeforeUpdateEmail(newEmail, actionCodeSettings).then(user => { - this._auth._setUser(user); - }); - } - - /** - * KNOWN UNSUPPORTED METHODS - */ - - linkWithPhoneNumber() { - throw new Error( - 'firebase.auth.User.linkWithPhoneNumber() is unsupported by the native Firebase SDKs.', - ); - } - - reauthenticateWithPhoneNumber() { - throw new Error( - 'firebase.auth.User.reauthenticateWithPhoneNumber() is unsupported by the native Firebase SDKs.', - ); - } - - get refreshToken() { - throw new Error('firebase.auth.User.refreshToken is unsupported by the native Firebase SDKs.'); - } -} diff --git a/packages/auth/lib/User.ts b/packages/auth/lib/User.ts new file mode 100644 index 0000000000..cc6cd86c95 --- /dev/null +++ b/packages/auth/lib/User.ts @@ -0,0 +1,391 @@ +/* + * 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 { + isObject, + isString, + isUndefined, + isBoolean, +} from '@react-native-firebase/app/dist/module/common'; +import type { AuthInternal, NativeUserShape } from './types/internal'; +import type { + AuthCredential, + AuthProvider, + ActionCodeSettings, + FirebaseAuth, + UserInfo, + MultiFactor, + IdTokenResult, +} from './types/auth'; +import type { FirebaseAuthTypes } from './types/namespaced'; + +/** Milliseconds since epoch; native modules use numbers, web auth supplies ISO strings (see RNFBAuthModule userMetadataToObject). */ +function metadataTimestampToMs(value: number | string | null | undefined): number { + if (value == null) { + return 0; + } + if (typeof value === 'number') { + return Number.isFinite(value) ? value : 0; + } + const s = String(value).trim(); + if (s === '') { + return 0; + } + if (/^-?\d+(\.\d+)?$/.test(s)) { + const n = Number(s); + return Number.isFinite(n) ? n : 0; + } + const parsed = new Date(s).getTime(); + return Number.isNaN(parsed) ? 0 : parsed; +} + +export default class User { + _auth: AuthInternal; + _user: NativeUserShape; + + constructor(auth: FirebaseAuth, user: NativeUserShape) { + this._auth = auth as AuthInternal; + this._user = user; + } + + get displayName(): string | null { + return this._user.displayName ?? null; + } + + get email(): string | null { + return this._user.email ?? null; + } + + get emailVerified(): boolean { + return this._user.emailVerified ?? false; + } + + get isAnonymous(): boolean { + return this._user.isAnonymous ?? false; + } + + get metadata(): { lastSignInTime: string; creationTime: string } { + const raw = this._user.metadata; + const lastMs = + raw != null && raw.lastSignInTime != null ? metadataTimestampToMs(raw.lastSignInTime) : 0; + const creationMs = + raw != null && raw.creationTime != null ? metadataTimestampToMs(raw.creationTime) : 0; + const toIso = (ms: number) => { + const d = new Date(ms); + return Number.isNaN(d.getTime()) ? new Date(0).toISOString() : d.toISOString(); + }; + return { + lastSignInTime: toIso(lastMs), + creationTime: toIso(creationMs), + }; + } + + get multiFactor(): MultiFactor | null { + return (this._user.multiFactor ?? null) as MultiFactor | null; + } + + get phoneNumber(): string | null { + return this._user.phoneNumber ?? null; + } + + get tenantId(): string | null { + return this._user.tenantId ?? null; + } + + get photoURL(): string | null { + return this._user.photoURL ?? null; + } + + get providerData(): UserInfo[] { + return (this._user.providerData ?? []) as UserInfo[]; + } + + get providerId(): string { + return this._user.providerId ?? ''; + } + + get uid(): string { + return this._user.uid ?? ''; + } + + delete(): Promise { + return this._auth.native.delete().then(() => { + this._auth._setUser(); + }); + } + + getIdToken(forceRefresh = false): Promise { + return this._auth.native.getIdToken(forceRefresh); + } + + getIdTokenResult(forceRefresh = false): Promise { + return this._auth.native.getIdTokenResult(forceRefresh) as Promise; + } + + linkWithCredential(credential: AuthCredential): Promise { + return this._auth.native + .linkWithCredential(credential.providerId, credential.token, credential.secret) + .then((userCredential: unknown) => + this._auth._setUserCredential(userCredential), + ) as Promise; + } + + linkWithPopup(provider: AuthProvider): Promise { + return this.linkWithRedirect(provider); + } + + linkWithRedirect(provider: AuthProvider): Promise { + return this._auth.native + .linkWithProvider(provider.toObject()) + .then((userCredential: unknown) => + this._auth._setUserCredential(userCredential), + ) as Promise; + } + + reauthenticateWithCredential( + credential: AuthCredential, + ): Promise { + return this._auth.native + .reauthenticateWithCredential(credential.providerId, credential.token, credential.secret) + .then((userCredential: unknown) => + this._auth._setUserCredential(userCredential), + ) as Promise; + } + + reauthenticateWithPopup(provider: AuthProvider): Promise { + return this._auth.native + .reauthenticateWithProvider(provider.toObject()) + .then((userCredential: unknown) => + this._auth._setUserCredential(userCredential), + ) as Promise; + } + + reauthenticateWithRedirect(provider: AuthProvider): Promise { + return this._auth.native + .reauthenticateWithProvider(provider.toObject()) + .then((userCredential: unknown) => { + this._auth._setUserCredential(userCredential); + }) as Promise; + } + + reload(): Promise { + return this._auth.native.reload().then((user: unknown) => { + this._auth._setUser(user); + }) as Promise; + } + + sendEmailVerification(actionCodeSettings?: ActionCodeSettings): Promise { + if (isObject(actionCodeSettings)) { + const acs = actionCodeSettings as unknown as Record; + if (!isString(acs.url)) { + throw new Error( + "firebase.auth.User.sendEmailVerification(*) 'actionCodeSettings.url' expected a string value.", + ); + } + + if (!isUndefined(acs.linkDomain) && !isString(acs.linkDomain)) { + throw new Error( + "firebase.auth.User.sendEmailVerification(*) 'actionCodeSettings.linkDomain' expected a string value.", + ); + } + + if (!isUndefined(acs.handleCodeInApp) && !isBoolean(acs.handleCodeInApp)) { + throw new Error( + "firebase.auth.User.sendEmailVerification(*) 'actionCodeSettings.handleCodeInApp' expected a boolean value.", + ); + } + + if (!isUndefined(acs.iOS)) { + if (!isObject(acs.iOS)) { + throw new Error( + "firebase.auth.User.sendEmailVerification(*) 'actionCodeSettings.iOS' expected an object value.", + ); + } + const ios = acs.iOS as Record; + if (!isString(ios.bundleId)) { + throw new Error( + "firebase.auth.User.sendEmailVerification(*) 'actionCodeSettings.iOS.bundleId' expected a string value.", + ); + } + } + + if (!isUndefined(acs.android)) { + if (!isObject(acs.android)) { + throw new Error( + "firebase.auth.User.sendEmailVerification(*) 'actionCodeSettings.android' expected an object value.", + ); + } + const android = acs.android as Record; + if (!isString(android.packageName)) { + throw new Error( + "firebase.auth.User.sendEmailVerification(*) 'actionCodeSettings.android.packageName' expected a string value.", + ); + } + + if (!isUndefined(android.installApp) && !isBoolean(android.installApp)) { + throw new Error( + "firebase.auth.User.sendEmailVerification(*) 'actionCodeSettings.android.installApp' expected a boolean value.", + ); + } + + if (!isUndefined(android.minimumVersion) && !isString(android.minimumVersion)) { + throw new Error( + "firebase.auth.User.sendEmailVerification(*) 'actionCodeSettings.android.minimumVersion' expected a string value.", + ); + } + } + } + + return this._auth.native.sendEmailVerification(actionCodeSettings).then((user: unknown) => { + this._auth._setUser(user); + }) as Promise; + } + + toJSON(): Record { + return Object.assign({}, this._user) as Record; + } + + unlink(providerId: string): Promise { + return this._auth.native + .unlink(providerId) + .then((user: unknown) => this._auth._setUser(user)) as Promise; + } + + updateEmail(email: string): Promise { + return this._auth.native.updateEmail(email).then((user: unknown) => { + this._auth._setUser(user); + }) as Promise; + } + + updatePassword(password: string): Promise { + return this._auth.native.updatePassword(password).then((user: unknown) => { + this._auth._setUser(user); + }) as Promise; + } + + updatePhoneNumber(credential: AuthCredential): Promise { + return this._auth.native + .updatePhoneNumber(credential.providerId, credential.token, credential.secret) + .then((user: unknown) => { + this._auth._setUser(user); + }) as Promise; + } + + updateProfile(updates: Record): Promise { + return this._auth.native.updateProfile(updates).then((user: unknown) => { + this._auth._setUser(user); + }) as Promise; + } + + verifyBeforeUpdateEmail( + newEmail: string, + actionCodeSettings?: ActionCodeSettings, + ): Promise { + if (!isString(newEmail)) { + throw new Error( + "firebase.auth.User.verifyBeforeUpdateEmail(*) 'newEmail' expected a string value.", + ); + } + + if (isObject(actionCodeSettings)) { + const acs = actionCodeSettings as unknown as Record; + if (!isString(acs.url)) { + throw new Error( + "firebase.auth.User.verifyBeforeUpdateEmail(_, *) 'actionCodeSettings.url' expected a string value.", + ); + } + + if (!isUndefined(acs.linkDomain) && !isString(acs.linkDomain)) { + throw new Error( + "firebase.auth.User.verifyBeforeUpdateEmail(_, *) 'actionCodeSettings.linkDomain' expected a string value.", + ); + } + + if (!isUndefined(acs.handleCodeInApp) && !isBoolean(acs.handleCodeInApp)) { + throw new Error( + "firebase.auth.User.verifyBeforeUpdateEmail(_, *) 'actionCodeSettings.handleCodeInApp' expected a boolean value.", + ); + } + + if (!isUndefined(acs.iOS)) { + if (!isObject(acs.iOS)) { + throw new Error( + "firebase.auth.User.verifyBeforeUpdateEmail(_, *) 'actionCodeSettings.iOS' expected an object value.", + ); + } + const ios = acs.iOS as Record; + if (!isString(ios.bundleId)) { + throw new Error( + "firebase.auth.User.verifyBeforeUpdateEmail(_, *) 'actionCodeSettings.iOS.bundleId' expected a string value.", + ); + } + } + + if (!isUndefined(acs.android)) { + if (!isObject(acs.android)) { + throw new Error( + "firebase.auth.User.verifyBeforeUpdateEmail(_, *) 'actionCodeSettings.android' expected an object value.", + ); + } + const android = acs.android as Record; + if (!isString(android.packageName)) { + throw new Error( + "firebase.auth.User.verifyBeforeUpdateEmail(_, *) 'actionCodeSettings.android.packageName' expected a string value.", + ); + } + + if (!isUndefined(android.installApp) && !isBoolean(android.installApp)) { + throw new Error( + "firebase.auth.User.verifyBeforeUpdateEmail(_, *) 'actionCodeSettings.android.installApp' expected a boolean value.", + ); + } + + if (!isUndefined(android.minimumVersion) && !isString(android.minimumVersion)) { + throw new Error( + "firebase.auth.User.verifyBeforeUpdateEmail(_, *) 'actionCodeSettings.android.minimumVersion' expected a string value.", + ); + } + } + } + + return this._auth.native + .verifyBeforeUpdateEmail(newEmail, actionCodeSettings) + .then((user: unknown) => { + this._auth._setUser(user); + }) as Promise; + } + + /** + * KNOWN UNSUPPORTED METHODS + */ + + linkWithPhoneNumber(): never { + throw new Error( + 'firebase.auth.User.linkWithPhoneNumber() is unsupported by the native Firebase SDKs.', + ); + } + + reauthenticateWithPhoneNumber(): never { + throw new Error( + 'firebase.auth.User.reauthenticateWithPhoneNumber() is unsupported by the native Firebase SDKs.', + ); + } + + get refreshToken(): never { + throw new Error('firebase.auth.User.refreshToken is unsupported by the native Firebase SDKs.'); + } +} diff --git a/packages/auth/lib/getMultiFactorResolver.js b/packages/auth/lib/getMultiFactorResolver.js deleted file mode 100644 index 70c3a53265..0000000000 --- a/packages/auth/lib/getMultiFactorResolver.js +++ /dev/null @@ -1,23 +0,0 @@ -import { isOther } from '@react-native-firebase/app/dist/module/common'; -import MultiFactorResolver from './MultiFactorResolver.js'; - -/** - * Create a new resolver based on an auth instance and error - * object. - * - * Returns null if no resolver object can be found on the error. - */ -export function getMultiFactorResolver(auth, error) { - if (isOther) { - return auth.native.getMultiFactorResolver(error); - } - if ( - error.hasOwnProperty('userInfo') && - error.userInfo.hasOwnProperty('resolver') && - error.userInfo.resolver - ) { - return new MultiFactorResolver(auth, error.userInfo.resolver); - } - - return null; -} diff --git a/packages/auth/lib/getMultiFactorResolver.ts b/packages/auth/lib/getMultiFactorResolver.ts new file mode 100644 index 0000000000..dc449261a5 --- /dev/null +++ b/packages/auth/lib/getMultiFactorResolver.ts @@ -0,0 +1,58 @@ +/* + * 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 { isOther } from '@react-native-firebase/app/dist/module/common'; +import MultiFactorResolver from './MultiFactorResolver'; +import type { AuthInternal } from './types/internal'; +import type { + MultiFactorError, + MultiFactorInfo, + MultiFactorResolver as MultiFactorResolverType, +} from './types/auth'; + +interface ErrorWithResolver { + userInfo?: { resolver?: unknown }; +} + +/** + * Create a new resolver based on an auth instance and error + * object. + * + * Returns null if no resolver object can be found on the error. + */ +export function getMultiFactorResolver( + auth: AuthInternal, + error: MultiFactorError | ErrorWithResolver, +): MultiFactorResolverType | null { + if (isOther && auth.native.getMultiFactorResolver) { + return auth.native.getMultiFactorResolver(error) as MultiFactorResolverType | null; + } + const err = error as ErrorWithResolver; + if ( + Object.prototype.hasOwnProperty.call(err, 'userInfo') && + err.userInfo && + Object.prototype.hasOwnProperty.call(err.userInfo, 'resolver') && + err.userInfo.resolver + ) { + return new MultiFactorResolver( + auth, + err.userInfo.resolver as { hints: MultiFactorInfo[]; session: string }, + ) as MultiFactorResolverType; + } + + return null; +} diff --git a/packages/auth/lib/index.ts b/packages/auth/lib/index.ts new file mode 100644 index 0000000000..997c95c09a --- /dev/null +++ b/packages/auth/lib/index.ts @@ -0,0 +1,56 @@ +/* + * 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 types from types/auth (explicit list: `export type *` needs TS 5+; website TypeDoc uses TS 4.x) +export type { + FirebaseAuth, + AuthSettings, + User, + UserInfo, + UserMetadata, + MultiFactor, + MultiFactorInfo, + IdTokenResult, + AuthCredential, + AuthProvider, + UserCredential, + AdditionalUserInfo, + ActionCodeSettings, + ActionCodeInfo, + ConfirmationResult, + MultiFactorResolver, + MultiFactorSession, + MultiFactorAssertion, + MultiFactorError, + Unsubscribe, +} from './types/auth'; + +// Export modular API functions +export * from './modular'; + +// Export password policy types (for validatePassword return type) +export type { + PasswordPolicyValidationStatus, + PasswordPolicyImpl, + PasswordPolicyCustomStrengthOptions, + PasswordPolicyApiResponse, +} from './password-policy/PasswordPolicyImpl'; + +// Export namespaced API (namespace export; not `export type` — invalid for namespaces in TS 4.x) +export { FirebaseAuthTypes } from './types/namespaced'; +export * from './namespaced'; +export { default } from './namespaced'; diff --git a/packages/auth/lib/modular.ts b/packages/auth/lib/modular.ts new file mode 100644 index 0000000000..ed354c1666 --- /dev/null +++ b/packages/auth/lib/modular.ts @@ -0,0 +1,602 @@ +/* + * 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 { MultiFactorUser } from './multiFactor'; +import { MODULAR_DEPRECATION_ARG } from '@react-native-firebase/app/dist/module/common'; +import type { + FirebaseAuth, + User, + UserCredential, + AuthCredential, + AuthProvider, + ActionCodeInfo, + ActionCodeSettings, + ConfirmationResult, + MultiFactorResolver, + MultiFactorError, + AdditionalUserInfo, + IdTokenResult, +} from './types/auth'; +import type { AuthInternal } from './types/internal'; +import type { PasswordPolicyValidationStatus } from './password-policy/PasswordPolicyImpl'; + +/** + * Returns the Auth instance associated with the provided FirebaseApp. + * @param app - The Firebase app instance. + * @returns The Auth instance. + */ +export function getAuth(app?: FirebaseApp): FirebaseAuth { + if (app) { + return getApp(app.name).auth() as FirebaseAuth; + } + return getApp().auth() as FirebaseAuth; +} + +/** + * This function allows more control over the Auth instance than getAuth(). + * @param app - The Firebase app instance. + * @param deps - Optional. Dependencies for the Auth instance. + * @returns The Auth instance. + */ +export function initializeAuth(app: FirebaseApp, _deps?: unknown): FirebaseAuth { + if (app) { + return getApp(app.name).auth() as FirebaseAuth; + } + return getApp().auth() as FirebaseAuth; +} + +/** + * Applies a verification code sent to the user by email or other out-of-band mechanism. + * @param {Auth} auth - The Auth instance. + * @param {string} oobCode - The out-of-band code sent to the user. + * @returns {Promise} + */ +export async function applyActionCode(auth: FirebaseAuth, oobCode: string): Promise { + return (auth as AuthInternal).applyActionCode.call(auth, oobCode, MODULAR_DEPRECATION_ARG); +} + +/** + * Adds a blocking callback that runs before an auth state change sets a new user. + * @param {Auth} auth - The Auth instance. + * @param {(user: User | null) => void} callback - A callback function to run before the auth state changes. + * @param {() => void} [onAbort] - Optional. A callback function to run if the operation is aborted. + */ +export function beforeAuthStateChanged( + _auth: FirebaseAuth, + _callback: (user: User | null) => void, + _onAbort?: () => void, +): void { + throw new Error('beforeAuthStateChanged is unsupported by the native Firebase SDKs'); +} + +/** + * Checks a verification code sent to the user by email or other out-of-band mechanism. + * @param {Auth} auth - The Auth instance. + * @param {string} oobCode - The out-of-band code sent to the user. + * @returns {Promise} + */ +export async function checkActionCode( + auth: FirebaseAuth, + oobCode: string, +): Promise { + return (auth as AuthInternal).checkActionCode.call(auth, oobCode, MODULAR_DEPRECATION_ARG); +} + +/** + * Completes the password reset process, given a confirmation code and new password. + * @param {Auth} auth - The Auth instance. + * @param {string} oobCode - The out-of-band code sent to the user. + * @param {string} newPassword - The new password. + * @returns {Promise} + */ +export async function confirmPasswordReset( + auth: FirebaseAuth, + oobCode: string, + newPassword: string, +): Promise { + return (auth as AuthInternal).confirmPasswordReset.call( + auth, + oobCode, + newPassword, + MODULAR_DEPRECATION_ARG, + ); +} + +/** + * Changes the Auth instance to communicate with the Firebase Auth Emulator, instead of production Firebase Auth services. + * @param {Auth} auth - The Auth instance. + * @param {string} url - The URL of the Firebase Auth Emulator. + * @param {{ disableWarnings: boolean }} [options] - Optional. Options for the emulator connection. + */ +export function connectAuthEmulator( + auth: FirebaseAuth, + url: string, + options?: { disableWarnings?: boolean }, +): void { + ( + (auth as AuthInternal).useEmulator as ( + url: string, + options?: unknown, + ...args: unknown[] + ) => void + ).call(auth, url, options, MODULAR_DEPRECATION_ARG); +} + +/** + * Creates a new user account associated with the specified email address and password. + * @param {Auth} auth - The Auth instance. + * @param {string} email - The user's email address. + * @param {string} password - The user's password. + * @returns {Promise} + */ +export async function createUserWithEmailAndPassword( + auth: FirebaseAuth, + email: string, + password: string, +): Promise { + return (auth as AuthInternal).createUserWithEmailAndPassword.call( + auth, + email, + password, + MODULAR_DEPRECATION_ARG, + ); +} + +/** + * Gets the list of possible sign in methods for the given email address. + * @param {Auth} auth - The Auth instance. + * @param {string} email - The user's email address. + * @returns {Promise} + */ +export async function fetchSignInMethodsForEmail( + auth: FirebaseAuth, + email: string, +): Promise { + return (auth as AuthInternal).fetchSignInMethodsForEmail.call( + auth, + email, + MODULAR_DEPRECATION_ARG, + ); +} + +/** + * Provides a MultiFactorResolver suitable for completion of a multi-factor flow. + * @param {Auth} auth - The Auth instance. + * @param {MultiFactorError} error - The multi-factor error. + * @returns {MultiFactorResolver} + */ +export function getMultiFactorResolver( + auth: FirebaseAuth, + error: MultiFactorError, +): MultiFactorResolver | null { + return (auth as AuthInternal).getMultiFactorResolver.call(auth, error, MODULAR_DEPRECATION_ARG); +} + +/** + * Returns a UserCredential from the redirect-based sign-in flow. + * @param {Auth} auth - The Auth instance. + * @param {PopupRedirectResolver} [resolver] - Optional. The popup redirect resolver. + * @returns {Promise} + */ +export async function getRedirectResult( + _auth: FirebaseAuth, + _resolver?: unknown, +): Promise { + throw new Error('getRedirectResult is unsupported by the native Firebase SDKs'); +} + +export function isSignInWithEmailLink(auth: FirebaseAuth, emailLink: string): Promise { + return (auth as AuthInternal).isSignInWithEmailLink.call( + auth, + emailLink, + MODULAR_DEPRECATION_ARG, + ); +} + +export function onAuthStateChanged( + auth: FirebaseAuth, + nextOrObserver: (user: User | null) => void | { next: (user: User | null) => void }, +): () => void { + return (auth as AuthInternal).onAuthStateChanged.call( + auth, + nextOrObserver, + MODULAR_DEPRECATION_ARG, + ); +} + +export function onIdTokenChanged( + auth: FirebaseAuth, + nextOrObserver: (user: User | null) => void | { next: (user: User | null) => void }, +): () => void { + return (auth as AuthInternal).onIdTokenChanged.call( + auth, + nextOrObserver, + MODULAR_DEPRECATION_ARG, + ); +} + +export async function revokeAccessToken(_auth: FirebaseAuth, _token: string): Promise { + throw new Error('revokeAccessToken() is only supported on Web'); +} + +export async function sendPasswordResetEmail( + auth: FirebaseAuth, + email: string, + actionCodeSettings?: ActionCodeSettings | null, +): Promise { + return (auth as AuthInternal).sendPasswordResetEmail.call( + auth, + email, + actionCodeSettings, + MODULAR_DEPRECATION_ARG, + ); +} + +export async function sendSignInLinkToEmail( + auth: FirebaseAuth, + email: string, + actionCodeSettings?: ActionCodeSettings, +): Promise { + return (auth as AuthInternal).sendSignInLinkToEmail.call( + auth, + email, + actionCodeSettings, + MODULAR_DEPRECATION_ARG, + ); +} + +export async function setPersistence(_auth: FirebaseAuth, _persistence: unknown): Promise { + throw new Error('setPersistence is unsupported by the native Firebase SDKs'); +} + +export async function signInAnonymously(auth: FirebaseAuth): Promise { + return (auth as AuthInternal).signInAnonymously.call(auth, MODULAR_DEPRECATION_ARG); +} + +export async function signInWithCredential( + auth: FirebaseAuth, + credential: AuthCredential, +): Promise { + return (auth as AuthInternal).signInWithCredential.call( + auth, + credential, + MODULAR_DEPRECATION_ARG, + ); +} + +export async function signInWithCustomToken( + auth: FirebaseAuth, + customToken: string, +): Promise { + return (auth as AuthInternal).signInWithCustomToken.call( + auth, + customToken, + MODULAR_DEPRECATION_ARG, + ); +} + +export async function signInWithEmailAndPassword( + auth: FirebaseAuth, + email: string, + password: string, +): Promise { + return (auth as AuthInternal).signInWithEmailAndPassword.call( + auth, + email, + password, + MODULAR_DEPRECATION_ARG, + ); +} + +export async function signInWithEmailLink( + auth: FirebaseAuth, + email: string, + emailLink: string, +): Promise { + return (auth as AuthInternal).signInWithEmailLink.call( + auth, + email, + emailLink, + MODULAR_DEPRECATION_ARG, + ); +} + +export async function signInWithPhoneNumber( + auth: FirebaseAuth, + phoneNumber: string, + appVerifier?: boolean, +): Promise { + return (auth as AuthInternal).signInWithPhoneNumber.call( + auth, + phoneNumber, + appVerifier, + MODULAR_DEPRECATION_ARG, + ); +} + +export function verifyPhoneNumber( + auth: FirebaseAuth, + phoneNumber: string, + autoVerifyTimeoutOrForceResend?: number | boolean, + forceResend?: boolean, +): unknown { + return (auth as AuthInternal).verifyPhoneNumber.call( + auth, + phoneNumber, + autoVerifyTimeoutOrForceResend, + forceResend, + MODULAR_DEPRECATION_ARG, + ); +} + +export async function signInWithPopup( + auth: FirebaseAuth, + provider: AuthProvider, + resolver?: unknown, +): Promise { + return (auth as AuthInternal).signInWithPopup.call( + auth, + provider, + resolver, + MODULAR_DEPRECATION_ARG, + ); +} + +export async function signInWithRedirect( + auth: FirebaseAuth, + provider: AuthProvider, + resolver?: unknown, +): Promise { + return (auth as AuthInternal).signInWithRedirect.call( + auth, + provider, + resolver, + MODULAR_DEPRECATION_ARG, + ); +} + +export async function signOut(auth: FirebaseAuth): Promise { + return (auth as AuthInternal).signOut.call(auth, MODULAR_DEPRECATION_ARG); +} + +export async function updateCurrentUser(_auth: FirebaseAuth, _user: User | null): Promise { + throw new Error('updateCurrentUser is unsupported by the native Firebase SDKs'); +} + +export function useDeviceLanguage(_auth: FirebaseAuth): void { + throw new Error('useDeviceLanguage is unsupported by the native Firebase SDKs'); +} + +export function setLanguageCode(auth: FirebaseAuth, languageCode: string): Promise { + return (auth as AuthInternal).setLanguageCode.call(auth, languageCode, MODULAR_DEPRECATION_ARG); +} + +export function useUserAccessGroup(auth: FirebaseAuth, userAccessGroup: string): Promise { + return (auth as AuthInternal).useUserAccessGroup.call( + auth, + userAccessGroup, + MODULAR_DEPRECATION_ARG, + ); +} + +export async function verifyPasswordResetCode(auth: FirebaseAuth, code: string): Promise { + return (auth as AuthInternal).verifyPasswordResetCode.call(auth, code, MODULAR_DEPRECATION_ARG); +} + +export function parseActionCodeURL(_link: string): unknown { + throw new Error('parseActionCodeURL is unsupported by the native Firebase SDKs'); +} + +export async function deleteUser(user: User): Promise { + return (user as { delete: (...args: unknown[]) => Promise }).delete.call( + user, + MODULAR_DEPRECATION_ARG, + ); +} + +export async function getIdToken(user: User, forceRefresh?: boolean): Promise { + return (user as { getIdToken: (...args: unknown[]) => Promise }).getIdToken.call( + user, + forceRefresh, + MODULAR_DEPRECATION_ARG, + ); +} + +export async function getIdTokenResult(user: User, forceRefresh?: boolean): Promise { + return ( + user as unknown as { getIdTokenResult: (...args: unknown[]) => Promise } + ).getIdTokenResult.call(user, forceRefresh, MODULAR_DEPRECATION_ARG); +} + +/** + * Links the user account with the given credentials. + * @param {User} user - The user to link the credentials with. + * @param {AuthCredential} credential - The auth credentials. + * @returns {Promise} + */ +export async function linkWithCredential( + user: User, + credential: AuthCredential, +): Promise { + return ( + user as unknown as { linkWithCredential: (...args: unknown[]) => Promise } + ).linkWithCredential.call(user, credential, MODULAR_DEPRECATION_ARG); +} + +export async function linkWithPhoneNumber( + _user: User, + _phoneNumber: string, + _appVerifier: unknown, +): Promise { + throw new Error('linkWithPhoneNumber is unsupported by the native Firebase SDKs'); +} + +export async function linkWithPopup( + user: User, + provider: AuthProvider, + resolver?: unknown, +): Promise { + return ( + user as unknown as { linkWithPopup: (...args: unknown[]) => Promise } + ).linkWithPopup.call(user, provider, resolver, MODULAR_DEPRECATION_ARG); +} + +export async function linkWithRedirect( + user: User, + provider: AuthProvider, + resolver?: unknown, +): Promise { + return ( + user as unknown as { linkWithRedirect: (...args: unknown[]) => Promise } + ).linkWithRedirect.call(user, provider, resolver, MODULAR_DEPRECATION_ARG); +} + +export function multiFactor(user: User): MultiFactorUser { + return new MultiFactorUser(getAuth() as AuthInternal, user); +} + +export async function reauthenticateWithCredential( + user: User, + credential: AuthCredential, +): Promise { + return ( + user as unknown as { + reauthenticateWithCredential: (...args: unknown[]) => Promise; + } + ).reauthenticateWithCredential.call(user, credential, MODULAR_DEPRECATION_ARG); +} + +export async function reauthenticateWithPhoneNumber( + _user: User, + _phoneNumber: string, + _appVerifier: unknown, +): Promise { + throw new Error('reauthenticateWithPhoneNumber is unsupported by the native Firebase SDKs'); +} + +export async function reauthenticateWithPopup( + user: User, + provider: AuthProvider, + resolver?: unknown, +): Promise { + return ( + user as unknown as { reauthenticateWithPopup: (...args: unknown[]) => Promise } + ).reauthenticateWithPopup.call(user, provider, resolver, MODULAR_DEPRECATION_ARG); +} + +export async function reauthenticateWithRedirect( + user: User, + provider: AuthProvider, + resolver?: unknown, +): Promise { + return ( + user as unknown as { + reauthenticateWithRedirect: (...args: unknown[]) => Promise; + } + ).reauthenticateWithRedirect.call(user, provider, resolver, MODULAR_DEPRECATION_ARG); +} + +export async function reload(user: User): Promise { + return (user as { reload: (...args: unknown[]) => Promise }).reload.call( + user, + MODULAR_DEPRECATION_ARG, + ); +} + +export async function sendEmailVerification( + user: User, + actionCodeSettings?: ActionCodeSettings, +): Promise { + return ( + user as unknown as { sendEmailVerification: (...args: unknown[]) => Promise } + ).sendEmailVerification.call(user, actionCodeSettings, MODULAR_DEPRECATION_ARG); +} + +export async function unlink(user: User, providerId: string): Promise { + return (user as unknown as { unlink: (...args: unknown[]) => Promise }).unlink.call( + user, + providerId, + MODULAR_DEPRECATION_ARG, + ); +} + +export async function updateEmail(user: User, newEmail: string): Promise { + return ( + user as unknown as { updateEmail: (...args: unknown[]) => Promise } + ).updateEmail.call(user, newEmail, MODULAR_DEPRECATION_ARG); +} + +export async function updatePassword(user: User, newPassword: string): Promise { + return ( + user as unknown as { updatePassword: (...args: unknown[]) => Promise } + ).updatePassword.call(user, newPassword, MODULAR_DEPRECATION_ARG); +} + +export async function updatePhoneNumber(user: User, credential: AuthCredential): Promise { + return ( + user as unknown as { updatePhoneNumber: (...args: unknown[]) => Promise } + ).updatePhoneNumber.call(user, credential, MODULAR_DEPRECATION_ARG); +} + +export async function updateProfile( + user: User, + profile: { displayName?: string | null; photoURL?: string | null }, +): Promise { + return ( + user as unknown as { updateProfile: (...args: unknown[]) => Promise } + ).updateProfile.call(user, profile, MODULAR_DEPRECATION_ARG); +} + +export async function verifyBeforeUpdateEmail( + user: User, + newEmail: string, + actionCodeSettings?: ActionCodeSettings, +): Promise { + return ( + user as unknown as { verifyBeforeUpdateEmail: (...args: unknown[]) => Promise } + ).verifyBeforeUpdateEmail.call(user, newEmail, actionCodeSettings, MODULAR_DEPRECATION_ARG); +} + +export function getAdditionalUserInfo( + userCredential: UserCredential, +): AdditionalUserInfo | undefined { + return userCredential.additionalUserInfo; +} + +export function getCustomAuthDomain(auth: FirebaseAuth): Promise { + return (auth as AuthInternal).getCustomAuthDomain.call(auth, MODULAR_DEPRECATION_ARG); +} + +export async function validatePassword( + auth: FirebaseAuth, + password: string, +): Promise { + if (!auth || !auth.app) { + throw new Error( + "firebase.auth().validatePassword(*) 'auth' must be a valid Auth instance with an 'app' property. Received: undefined", + ); + } + + if (password === null || password === undefined) { + throw new Error( + "firebase.auth().validatePassword(*) expected 'password' to be a non-null or a defined value.", + ); + } + + return (auth as AuthInternal).validatePassword.call(auth, password, MODULAR_DEPRECATION_ARG); +} diff --git a/packages/auth/lib/modular/index.d.ts b/packages/auth/lib/modular/index.d.ts deleted file mode 100644 index edaec52bb2..0000000000 --- a/packages/auth/lib/modular/index.d.ts +++ /dev/null @@ -1,801 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-vars */ -/* - * 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'; -import { FirebaseAuthTypes, CallbackOrObserver } from '../index'; -import { firebase } from '..'; - -import Auth = FirebaseAuthTypes.Module; -import FirebaseApp = ReactNativeFirebase.FirebaseApp; - -/** - * Returns the Auth instance associated with the provided FirebaseApp. - * @param app - The Firebase app instance. - * @returns The Auth instance. - */ -export function getAuth(app?: FirebaseApp): Auth; - -/** - * This function allows more control over the Auth instance than getAuth(). - * - * @param app - The Firebase app instance. - * @param deps - Optional. Dependencies for the Auth instance. - * @returns The Auth instance. - * - * getAuth uses platform-specific defaults to supply the Dependencies. - * In general, getAuth is the easiest way to initialize Auth and works for most use cases. - * Use initializeAuth if you need control over which persistence layer is used, or to minimize bundle size - * if you're not using either signInWithPopup or signInWithRedirect. - */ -export function initializeAuth(app: FirebaseApp, deps?: any): Auth; - -/** - * Applies a verification code sent to the user by email or other out-of-band mechanism. - * - * @param auth - The Auth instance. - * @param oobCode - The out-of-band code sent to the user. - * @returns A promise that resolves when the code is applied successfully. - */ -export function applyActionCode(auth: Auth, oobCode: string): Promise; - -/** - * Adds a blocking callback that runs before an auth state change sets a new user. - * - * @param auth - The Auth instance. - * @param callback - A callback function to run before the auth state changes. - * @param onAbort - Optional. A callback function to run if the operation is aborted. - * - */ -export function beforeAuthStateChanged( - auth: Auth, - callback: (user: FirebaseAuthTypes.User | null) => void, - onAbort?: () => void, -): void; - -/** - * Checks a verification code sent to the user by email or other out-of-band mechanism. - * - * @param auth - The Auth instance. - * @param oobCode - The out-of-band code sent to the user. - * @returns A promise that resolves with the action code information. - */ -export function checkActionCode( - auth: Auth, - oobCode: string, -): Promise; - -/** - * Completes the password reset process, given a confirmation code and new password. - * - * @param auth - The Auth instance. - * @param oobCode - The out-of-band code sent to the user. - * @param newPassword - The new password. - * @returns A promise that resolves when the password is reset. - */ -export function confirmPasswordReset( - auth: Auth, - oobCode: string, - newPassword: string, -): Promise; - -/** - * Changes the Auth instance to communicate with the Firebase Auth Emulator, instead of production Firebase Auth services. - * - * @param auth - The Auth instance. - * @param url - The URL of the Firebase Auth Emulator. - * @param options - Optional. Options for the emulator connection. - * - * This must be called synchronously immediately following the first call to initializeAuth(). Do not use with production credentials as emulator traffic is not encrypted. - */ -export function connectAuthEmulator( - auth: Auth, - url: string, - options?: { disableWarnings: boolean }, -): void; - -/** - * Creates a new user account associated with the specified email address and password. - * - * @param auth - The Auth instance. - * @param email - The user's email address. - * @param password - The user's password. - * @returns A promise that resolves with the user credentials. - */ -export function createUserWithEmailAndPassword( - auth: Auth, - email: string, - password: string, -): Promise; - -/** - * Gets the list of possible sign in methods for the given email address. - * - * @param auth - The Auth instance. - * @param email - The user's email address. - * @returns A promise that resolves with the list of sign-in methods. - */ -export function fetchSignInMethodsForEmail(auth: Auth, email: string): Promise; - -/** - * Provides a MultiFactorResolver suitable for completion of a multi-factor flow. - * - * @param auth - The Auth instance. - * @param error - The multi-factor error. - * @returns The MultiFactorResolver instance. - */ -export function getMultiFactorResolver( - auth: Auth, - error: FirebaseAuthTypes.MultiFactorError, -): FirebaseAuthTypes.MultiFactorResolver; - -/** - * Returns a UserCredential from the redirect-based sign-in flow. - * - * @param auth - The Auth instance. - * @param resolver - Optional. The popup redirect resolver. - * @returns A promise that resolves with the user credentials or null. - */ -export function getRedirectResult( - auth: Auth, - resolver?: PopupRedirectResolver, -): Promise; - -export interface PopupRedirectResolver {} - -/** - * Loads the reCAPTCHA configuration into the Auth instance. - * Does not work in a Node.js environment - * @param auth - The Auth instance. - */ -export function initializeRecaptchaConfig(auth: Auth): Promise; - -/** - * Checks if an incoming link is a sign-in with email link suitable for signInWithEmailLink. - * Note that android and other platforms require `apiKey` link parameter for signInWithEmailLink - * - * @param auth - The Auth instance. - * @param emailLink - The email link to check. - * @returns A promise that resolves if the link is a sign-in with email link. - */ -export function isSignInWithEmailLink(auth: Auth, emailLink: string): Promise; - -/** - * Adds an observer for changes to the user's sign-in state. - * - * @param auth - The Auth instance. - * @param nextOrObserver - A callback function or observer for auth state changes. - * @returns A function to unsubscribe from the auth state changes. - */ -export function onAuthStateChanged( - auth: Auth, - nextOrObserver: CallbackOrObserver, -): () => void; - -/** - * Adds an observer for changes to the signed-in user's ID token. - * - * @param auth - The Auth instance. - * @param nextOrObserver - A callback function or observer for ID token changes. - * @returns A function to unsubscribe from the ID token changes. - */ -export function onIdTokenChanged( - auth: Auth, - nextOrObserver: CallbackOrObserver, -): () => void; - -/** - * Revoke the given access token, Currently only supports Apple OAuth access tokens. - * @param auth - * @param token - */ -export declare function revokeAccessToken(auth: Auth, token: string): Promise; - -/** - * Sends a password reset email to the given email address. - * - * @param auth - The Auth instance. - * @param email - The user's email address. - * @param actionCodeSettings - Optional. Action code settings. - * @returns A promise that resolves when the email is sent. - */ -export function sendPasswordResetEmail( - auth: Auth, - email: string, - actionCodeSettings?: FirebaseAuthTypes.ActionCodeSettings, -): Promise; - -/** - * Sends a sign-in email link to the user with the specified email. - * - * @param auth - The Auth instance. - * @param email - The user's email address. - * @param actionCodeSettings - Optional, Action code settings. - * @returns A promise that resolves when the email is sent. - */ -export function sendSignInLinkToEmail( - auth: Auth, - email: string, - actionCodeSettings?: FirebaseAuthTypes.ActionCodeSettings, -): Promise; - -/** - * Type of Persistence. - * - 'SESSION' is used for temporary persistence such as `sessionStorage`. - * - 'LOCAL' is used for long term persistence such as `localStorage` or `IndexedDB`. - * - 'NONE' is used for in-memory, or no persistence. - */ -export type Persistence = { - readonly type: 'SESSION' | 'LOCAL' | 'NONE'; -}; - -/** - * Changes the type of persistence on the Auth instance for the currently saved Auth session and applies this type of persistence for future sign-in requests, including sign-in with redirect requests. - * - * @param auth - The Auth instance. - * @param persistence - The persistence type. - * @returns A promise that resolves when the persistence is set. - */ -export function setPersistence(auth: Auth, persistence: Persistence): Promise; - -/** - * Asynchronously signs in as an anonymous user. - * - * @param auth - The Auth instance. - * @returns A promise that resolves with the user credentials. - */ -export function signInAnonymously(auth: Auth): Promise; - -/** - * Asynchronously signs in with the given credentials. - * - * @param auth - The Auth instance. - * @param credential - The auth credentials. - * @returns A promise that resolves with the user credentials. - */ -export function signInWithCredential( - auth: Auth, - credential: FirebaseAuthTypes.AuthCredential, -): Promise; - -/** - * Asynchronously signs in using a custom token. - * - * @param auth - The Auth instance. - * @param customToken - The custom token. - * @returns A promise that resolves with the user credentials. - */ -export function signInWithCustomToken( - auth: Auth, - customToken: string, -): Promise; - -/** - * Asynchronously signs in using an email and password. - * - * @param auth - The Auth instance. - * @param email - The user's email address. - * @param password - The user's password. - * @returns A promise that resolves with the user credentials. - */ -export function signInWithEmailAndPassword( - auth: Auth, - email: string, - password: string, -): Promise; - -/** - * Asynchronously signs in using an email and sign-in email link. - * - * @param auth - The Auth instance. - * @param email - The user's email address. - * @param emailLink - The email link. - * @returns A promise that resolves with the user credentials. - */ -export function signInWithEmailLink( - auth: Auth, - email: string, - emailLink: string, -): Promise; - -/** - * Interface representing an application verifier. - */ -export interface ApplicationVerifier { - readonly type: string; - verify(): Promise; -} - -/** - * Asynchronously signs in using a phone number. - * - * @param auth - The Auth instance. - * @param phoneNumber - The user's phone number. - * @param appVerifier - Optional. The application verifier. - * @param forceResend - Optional. (Native only) Forces a new message to be sent if it was already recently sent. - * @returns A promise that resolves with the confirmation result. - */ -export function signInWithPhoneNumber( - auth: Auth, - phoneNumber: string, - appVerifier?: ApplicationVerifier, - forceResend?: boolean, -): Promise; - -/** - * Asynchronously signs in using a phone number. - * - * @param auth - The Auth instance. - * @param phoneNumber - The user's phone number. - * @param autoVerifyTimeoutOrForceResend - The auto verify timeout or force resend flag. - * @param forceResend - Optional. Whether to force resend. - * @returns A promise that resolves with the phone auth listener. - */ -export function verifyPhoneNumber( - auth: Auth, - phoneNumber: string, - autoVerifyTimeoutOrForceResend: number | boolean, - forceResend?: boolean, -): FirebaseAuthTypes.PhoneAuthListener; - -/** - * Authenticates a Firebase client using a popup-based OAuth authentication flow. - * - * @param auth - The Auth instance. - * @param provider - The auth provider. - * @param resolver - Optional. The popup redirect resolver. - * @returns A promise that resolves with the user credentials. - */ -export function signInWithPopup( - auth: Auth, - provider: FirebaseAuthTypes.AuthProvider, - resolver?: PopupRedirectResolver, -): Promise; - -/** - * Authenticates a Firebase client using a full-page redirect flow. - * - * @param auth - The Auth instance. - * @param provider - The auth provider. - * @param resolver - Optional. The popup redirect resolver. - * @returns A promise that resolves when the redirect is complete. - */ -export function signInWithRedirect( - auth: Auth, - provider: FirebaseAuthTypes.AuthProvider, - resolver?: PopupRedirectResolver, -): Promise; - -/** - * Signs out the current user. - * - * @param auth - The Auth instance. - * @returns A promise that resolves when the user is signed out. - */ -export function signOut(auth: Auth): Promise; - -/** - * Asynchronously sets the provided user as Auth.currentUser on the Auth instance. - * - * @param auth - The Auth instance. - * @param user - The user to set as the current user. - * @returns A promise that resolves when the user is set. - */ -export function updateCurrentUser(auth: Auth, user: FirebaseAuthTypes.User | null): Promise; - -/** - * Sets the current language to the default device/browser preference. - * - * @param auth - The Auth instance. - */ -export function useDeviceLanguage(auth: Auth): void; - -/** - * Sets the language code. - * - * #### Example - * - * ```js - * // Set language to French - * await firebase.auth().setLanguageCode('fr'); - * ``` - * @param auth - The Auth instance. - * @param languageCode An ISO language code. - * 'null' value will set the language code to the app's current language. - */ -export function setLanguageCode(auth: Auth, languageCode: string | null): Promise; - -/** - * Validates the password against the password policy configured for the project or tenant. - * - * @param auth - The Auth instance. - * @param password - The password to validate. - * - */ -export function validatePassword(auth: Auth, password: string): Promise; - -/** - * Configures a shared user access group to sync auth state across multiple apps via the Keychain. - * - * @param auth - The Auth instance. - * @param userAccessGroup - The user access group. - * @returns A promise that resolves when the user access group is set. - */ -export function useUserAccessGroup(auth: Auth, userAccessGroup: string): Promise; - -/** - * Verifies the password reset code sent to the user by email or other out-of-band mechanism. - * - * @param auth - The Auth instance. - * @param code - The password reset code. - * @returns A promise that resolves with the user's email address. - */ -export function verifyPasswordResetCode(auth: Auth, code: string): Promise; - -/** - * Parses the email action link string and returns an ActionCodeURL if the link is valid, otherwise returns null. - * - * @param link - The email action link string. - * @returns The ActionCodeURL if the link is valid, otherwise null. - */ -export function parseActionCodeURL(link: string): FirebaseAuthTypes.ActionCodeURL | null; - -/** - * Deletes and signs out the user. - * - * @param user - The user to delete. - * @returns A promise that resolves when the user is deleted. - */ -export function deleteUser(user: FirebaseAuthTypes.User): Promise; - -/** - * Returns a JSON Web Token (JWT) used to identify the user to a Firebase service. - * - * @param user - The user to get the token for. - * @param forceRefresh - Optional. Whether to force refresh the token. - * @returns A promise that resolves with the token. - */ -export function getIdToken(user: FirebaseAuthTypes.User, forceRefresh?: boolean): Promise; - -/** - * Returns a deserialized JSON Web Token (JWT) used to identify the user to a Firebase service. - * - * @param user - The user to get the token result for. - * @param forceRefresh - Optional. Whether to force refresh the token. - * @returns A promise that resolves with the token result. - */ -export function getIdTokenResult( - user: FirebaseAuthTypes.User, - forceRefresh?: boolean, -): Promise; - -/** - * Links the user account with the given credentials. - * - * @param user - The user to link the credentials with. - * @param credential - The auth credentials. - * @returns A promise that resolves with the user credentials. - */ -export function linkWithCredential( - user: FirebaseAuthTypes.User, - credential: FirebaseAuthTypes.AuthCredential, -): Promise; - -/** - * Links the user account with the given phone number. - * - * @param user - The user to link the phone number with. - * @param phoneNumber - The phone number. - * @param appVerifier - The application verifier. - * @returns A promise that resolves with the confirmation result. - */ -export function linkWithPhoneNumber( - user: FirebaseAuthTypes.User, - phoneNumber: string, - appVerifier?: ApplicationVerifier, -): Promise; - -/** - * Links the authenticated provider to the user account using a pop-up based OAuth flow. - * - * @param user - The user to link the provider with. - * @param provider - The auth provider. - * @param resolver - Optional. The popup redirect resolver. - * @returns A promise that resolves with the user credentials. - */ -export function linkWithPopup( - user: FirebaseAuthTypes.User, - provider: FirebaseAuthTypes.AuthProvider, - resolver?: PopupRedirectResolver, -): Promise; - -/** - * Links the OAuthProvider to the user account using a full-page redirect flow. - * - * @param user - The user to link the provider with. - * @param provider - The auth provider. - * @param resolver - Optional. The popup redirect resolver. - * @returns A promise that resolves when the redirect is complete. - */ -export function linkWithRedirect( - user: FirebaseAuthTypes.User, - provider: FirebaseAuthTypes.AuthProvider, - resolver?: PopupRedirectResolver, -): Promise; - -/** - * The MultiFactorUser corresponding to the user. - * - * @param user - The user to get the multi-factor user for. - * @returns The MultiFactorUser instance. - */ -export function multiFactor(user: FirebaseAuthTypes.User): FirebaseAuthTypes.MultiFactorUser; - -/** - * Re-authenticates a user using a fresh credential. - * - * @param user - The user to re-authenticate. - * @param credential - The auth credentials. - * @returns A promise that resolves with the user credentials. - */ -export function reauthenticateWithCredential( - user: FirebaseAuthTypes.User, - credential: FirebaseAuthTypes.AuthCredential, -): Promise; - -/** - * Re-authenticates a user using a fresh phone credential. - * - * @param user - The user to re-authenticate. - * @param phoneNumber - The phone number. - * @param appVerifier - The application verifier. - * @returns A promise that resolves with the confirmation result. - */ -export function reauthenticateWithPhoneNumber( - user: FirebaseAuthTypes.User, - phoneNumber: string, - appVerifier?: ApplicationVerifier, -): Promise; - -/** - * Re-authenticate a user with a federated authentication provider (Microsoft, Yahoo). For native platforms, this will open a browser window. - * - * @param user - The user to re-authenticate. - * @param provider - The auth provider. - * @param resolver - Optional. The popup redirect resolver. Web only. - * @returns A promise that resolves with the user credentials. - */ -export function reauthenticateWithPopup( - user: FirebaseAuthTypes.User, - provider: FirebaseAuthTypes.AuthProvider, - resolver?: PopupRedirectResolver, -): Promise; - -/** - * Re-authenticate a user with a federated authentication provider (Microsoft, Yahoo). For native platforms, this will open a browser window. - * - * @param user - The user to re-authenticate. - * @param provider - The auth provider. - * @param resolver - Optional. The popup redirect resolver. Web only. - * @returns A promise that resolves with no value. - */ -export function reauthenticateWithRedirect( - user: FirebaseAuthTypes.User, - provider: FirebaseAuthTypes.AuthProvider, - resolver?: PopupRedirectResolver, -): Promise; - -/** - * Reloads user account data, if signed in. - * - * @param user - The user to reload data for. - * @returns A promise that resolves when the data is reloaded. - */ -export function reload(user: FirebaseAuthTypes.User): Promise; - -/** - * Sends a verification email to a user. - * - * @param user - The user to send the email to. - * @param actionCodeSettings - Optional. Action code settings. - * @returns A promise that resolves when the email is sent. - */ -export function sendEmailVerification( - user: FirebaseAuthTypes.User, - actionCodeSettings?: FirebaseAuthTypes.ActionCodeSettings, -): Promise; - -/** - * Unlinks a provider from a user account. - * - * @param user - The user to unlink the provider from. - * @param providerId - The provider ID. - * @returns A promise that resolves with the user. - */ -export function unlink( - user: FirebaseAuthTypes.User, - providerId: string, -): Promise; - -/** - * Updates the user's email address. - * - * @param user - The user to update the email for. - * @param newEmail - The new email address. - * @returns A promise that resolves when the email is updated. - */ -export function updateEmail(user: FirebaseAuthTypes.User, newEmail: string): Promise; - -/** - * Updates the user's password. - * - * @param user - The user to update the password for. - * @param newPassword - The new password. - * @returns A promise that resolves when the password is updated. - */ -export function updatePassword(user: FirebaseAuthTypes.User, newPassword: string): Promise; - -/** - * Updates the user's phone number. - * - * @param user - The user to update the phone number for. - * @param credential - The auth credentials. - * @returns A promise that resolves when the phone number is updated. - */ -export function updatePhoneNumber( - user: FirebaseAuthTypes.User, - credential: FirebaseAuthTypes.AuthCredential, -): Promise; - -/** - * Updates a user's profile data. - * - * @param user - The user to update the profile for. - * @param profile - An object containing the profile data to update. - * @returns A promise that resolves when the profile is updated. - */ -export function updateProfile( - user: FirebaseAuthTypes.User, - { displayName, photoURL: photoUrl }: { displayName?: string | null; photoURL?: string | null }, -): Promise; - -/** - * Sends a verification email to a new email address. - * - * @param user - The user to send the email to. - * @param newEmail - The new email address. - * @param actionCodeSettings - Optional. Action code settings. - * @returns A promise that resolves when the email is sent. - */ -export function verifyBeforeUpdateEmail( - user: FirebaseAuthTypes.User, - newEmail: string, - actionCodeSettings?: FirebaseAuthTypes.ActionCodeSettings | null, -): Promise; - -/** - * Extracts provider specific AdditionalUserInfo for the given credential. - * - * @param userCredential - The user credential. - * @returns The additional user information, or null if none is available. - */ -export function getAdditionalUserInfo( - userCredential: FirebaseAuthTypes.UserCredential, -): FirebaseAuthTypes.AdditionalUserInfo | null; - -/** - * Returns the custom auth domain for the auth instance. - * - * @param auth - The Auth instance. - * @returns {Promise} A promise that resolves with the custom auth domain. - */ -export function getCustomAuthDomain(auth: Auth): Promise; - -/** - * Validates the password against the password policy configured for the project or tenant. - * - * @remarks - * If no tenant ID is set on the `Auth` instance, then this method will use the password - * policy configured for the project. Otherwise, this method will use the policy configured - * for the tenant. If a password policy has not been configured, then the default policy - * configured for all projects will be used. - * - * If an auth flow fails because a submitted password does not meet the password policy - * requirements and this method has previously been called, then this method will use the - * most recent policy available when called again. - * - * When using this method, ensure you have the Identity Toolkit enabled on the - * Google Cloud Platform with the API Key for your application permitted to use it. - * - * @example - * ``` js - * import { getAuth, validatePassword } from "firebase/auth"; - * - * const status = await validatePassword(getAuth(), passwordFromUser); - * if (!status.isValid) { - * // Password could not be validated. Use the status to show what - * // requirements are met and which are missing. - * - * // If a criterion is undefined, it is not required by policy. If the - * // criterion is defined but false, it is required but not fulfilled by - * // the given password. For example: - * const needsLowerCase = status.containsLowercaseLetter !== true; - * } - * ``` - * - * @param auth The {@link Auth} instance. - * @param password The password to validate. - * - * @public - */ -export function validatePassword(auth: Auth, password: string): Promise; - -/** - * A structure indicating which password policy requirements were met or violated and what the - * requirements are. - * - * @public - */ -export interface PasswordValidationStatus { - /** - * Whether the password meets all requirements. - */ - readonly isValid: boolean; - /** - * Whether the password meets the minimum password length, or undefined if not required. - */ - readonly meetsMinPasswordLength?: boolean; - /** - * Whether the password meets the maximum password length, or undefined if not required. - */ - readonly meetsMaxPasswordLength?: boolean; - /** - * Whether the password contains a lowercase letter, or undefined if not required. - */ - readonly containsLowercaseLetter?: boolean; - /** - * Whether the password contains an uppercase letter, or undefined if not required. - */ - readonly containsUppercaseLetter?: boolean; - /** - * Whether the password contains a numeric character, or undefined if not required. - */ - readonly containsNumericCharacter?: boolean; - /** - * Whether the password contains a non-alphanumeric character, or undefined if not required. - */ - readonly containsNonAlphanumericCharacter?: boolean; - /** - * The policy used to validate the password. - */ - readonly passwordPolicy: PasswordPolicy; -} - -export { - AppleAuthProvider, - EmailAuthProvider, - FacebookAuthProvider, - GithubAuthProvider, - GoogleAuthProvider, - OAuthProvider, - OIDCAuthProvider, - PhoneAuthProvider, - PhoneMultiFactorGenerator, - TotpMultiFactorGenerator, - TotpSecret, - TwitterAuthProvider, - PhoneAuthState, -} from '../index'; diff --git a/packages/auth/lib/modular/index.js b/packages/auth/lib/modular/index.js deleted file mode 100644 index ff408213d0..0000000000 --- a/packages/auth/lib/modular/index.js +++ /dev/null @@ -1,651 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-vars */ -/* - * 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 { MultiFactorUser } from '../multiFactor'; -import { MODULAR_DEPRECATION_ARG } from '@react-native-firebase/app/dist/module/common'; - -/** - * @typedef {import('@firebase/app-types').FirebaseApp} FirebaseApp - * @typedef {import('..').FirebaseAuthTypes} FirebaseAuthTypes - * @typedef {import('..').FirebaseAuthTypes.Module} Auth - * @typedef {import('..').FirebaseAuthTypes.CallbackOrObserver} CallbackOrObserver - * @typedef {import('..').FirebaseAuthTypes.AuthListenerCallback} AuthListenerCallback - * @typedef {import('..').FirebaseAuthTypes.ActionCodeInfo} ActionCodeInfo - * @typedef {import('..').FirebaseAuthTypes.UserCredential} UserCredential - * @typedef {import('..').FirebaseAuthTypes.MultiFactorError} MultiFactorError - * @typedef {import('..').FirebaseAuthTypes.MultiFactorUser} MultiFactorUser - * @typedef {import('..').FirebaseAuthTypes.MultiFactorResolver} MultiFactorResolver - * @typedef {import('..').FirebaseAuthTypes.ConfirmationResult} ConfirmationResult - * @typedef {import('..').FirebaseAuthTypes.AuthCredential} AuthCredential - * @typedef {import('..').FirebaseAuthTypes.AuthProvider} AuthProvider - * @typedef {import('..').FirebaseAuthTypes.PhoneAuthListener} PhoneAuthListener - * @typedef {import('..').FirebaseAuthTypes.ActionCodeSettings} ActionCodeSettings - * @typedef {import('..').FirebaseAuthTypes.User} User - * @typedef {import('..').FirebaseAuthTypes.IdTokenResult} IdTokenResult - * @typedef {import('..').FirebaseAuthTypes.AdditionalUserInfo} AdditionalUserInfo - * @typedef {import('..').FirebaseAuthTypes.ActionCodeURL} ActionCodeURL - * @typedef {import('..').FirebaseAuthTypes.ApplicationVerifier} ApplicationVerifier - */ - -/** - * Returns the Auth instance associated with the provided FirebaseApp. - * @param {FirebaseApp} [app] - The Firebase app instance. - * @returns {Auth} - */ -export function getAuth(app) { - if (app) { - return getApp(app.name).auth(); - } - return getApp().auth(); -} - -/** - * This function allows more control over the Auth instance than getAuth(). - * @param {FirebaseApp} app - The Firebase app instance. - * @param {any} [deps] - Optional. Dependencies for the Auth instance. - * @returns {Auth} - */ -export function initializeAuth(app, deps) { - if (app) { - return getApp(app.name).auth(); - } - return getApp().auth(); -} - -/** - * Applies a verification code sent to the user by email or other out-of-band mechanism. - * @param {Auth} auth - The Auth instance. - * @param {string} oobCode - The out-of-band code sent to the user. - * @returns {Promise} - */ -export async function applyActionCode(auth, oobCode) { - return auth.applyActionCode.call(auth, oobCode, MODULAR_DEPRECATION_ARG); -} - -/** - * Adds a blocking callback that runs before an auth state change sets a new user. - * @param {Auth} auth - The Auth instance. - * @param {(user: User | null) => void} callback - A callback function to run before the auth state changes. - * @param {() => void} [onAbort] - Optional. A callback function to run if the operation is aborted. - */ -export function beforeAuthStateChanged(auth, callback, onAbort) { - throw new Error('beforeAuthStateChanged is unsupported by the native Firebase SDKs'); -} - -/** - * Checks a verification code sent to the user by email or other out-of-band mechanism. - * @param {Auth} auth - The Auth instance. - * @param {string} oobCode - The out-of-band code sent to the user. - * @returns {Promise} - */ -export async function checkActionCode(auth, oobCode) { - return auth.checkActionCode.call(auth, oobCode, MODULAR_DEPRECATION_ARG); -} - -/** - * Completes the password reset process, given a confirmation code and new password. - * @param {Auth} auth - The Auth instance. - * @param {string} oobCode - The out-of-band code sent to the user. - * @param {string} newPassword - The new password. - * @returns {Promise} - */ -export async function confirmPasswordReset(auth, oobCode, newPassword) { - return auth.confirmPasswordReset.call(auth, oobCode, newPassword, MODULAR_DEPRECATION_ARG); -} - -/** - * Changes the Auth instance to communicate with the Firebase Auth Emulator, instead of production Firebase Auth services. - * @param {Auth} auth - The Auth instance. - * @param {string} url - The URL of the Firebase Auth Emulator. - * @param {{ disableWarnings: boolean }} [options] - Optional. Options for the emulator connection. - */ -export function connectAuthEmulator(auth, url, options) { - auth.useEmulator.call(auth, url, options, MODULAR_DEPRECATION_ARG); -} - -/** - * Creates a new user account associated with the specified email address and password. - * @param {Auth} auth - The Auth instance. - * @param {string} email - The user's email address. - * @param {string} password - The user's password. - * @returns {Promise} - */ -export async function createUserWithEmailAndPassword(auth, email, password) { - return auth.createUserWithEmailAndPassword.call(auth, email, password, MODULAR_DEPRECATION_ARG); -} - -/** - * Gets the list of possible sign in methods for the given email address. - * @param {Auth} auth - The Auth instance. - * @param {string} email - The user's email address. - * @returns {Promise} - */ -export async function fetchSignInMethodsForEmail(auth, email) { - return auth.fetchSignInMethodsForEmail.call(auth, email, MODULAR_DEPRECATION_ARG); -} - -/** - * Provides a MultiFactorResolver suitable for completion of a multi-factor flow. - * @param {Auth} auth - The Auth instance. - * @param {MultiFactorError} error - The multi-factor error. - * @returns {MultiFactorResolver} - */ -export function getMultiFactorResolver(auth, error) { - return auth.getMultiFactorResolver.call(auth, error, MODULAR_DEPRECATION_ARG); -} - -/** - * Returns a UserCredential from the redirect-based sign-in flow. - * @param {Auth} auth - The Auth instance. - * @param {PopupRedirectResolver} [resolver] - Optional. The popup redirect resolver. - * @returns {Promise} - */ -export async function getRedirectResult(auth, resolver) { - throw new Error('getRedirectResult is unsupported by the native Firebase SDKs'); -} - -/** - * Checks if an incoming link is a sign-in with email link suitable for signInWithEmailLink(). - * @param {Auth} auth - The Auth instance. - * @param {string} emailLink - The email link to check. - * @returns {Promise} - */ -export function isSignInWithEmailLink(auth, emailLink) { - return auth.isSignInWithEmailLink.call(auth, emailLink, MODULAR_DEPRECATION_ARG); -} - -/** - * Adds an observer for changes to the user's sign-in state. - * @param {Auth} auth - The Auth instance. - * @param {CallbackOrObserver} nextOrObserver - A callback function or observer for auth state changes. - * @returns {() => void} - */ -export function onAuthStateChanged(auth, nextOrObserver) { - return auth.onAuthStateChanged.call(auth, nextOrObserver, MODULAR_DEPRECATION_ARG); -} - -/** - * Adds an observer for changes to the signed-in user's ID token. - * @param {Auth} auth - The Auth instance. - * @param {CallbackOrObserver} nextOrObserver - A callback function or observer for ID token changes. - * @returns {() => void} - */ -export function onIdTokenChanged(auth, nextOrObserver) { - return auth.onIdTokenChanged.call(auth, nextOrObserver, MODULAR_DEPRECATION_ARG); -} - -/** - * Revoke the given access token, Currently only supports Apple OAuth access tokens. - * @param auth - The Auth Instance. - * @param token - The Access Token - */ -export async function revokeAccessToken(auth, token) { - throw new Error('revokeAccessToken() is only supported on Web'); -} //TO DO: Add Support - -/** - * Sends a password reset email to the given email address. - * @param {Auth} auth - The Auth instance. - * @param {string} email - The user's email address. - * @param {ActionCodeSettings} [actionCodeSettings] - Optional. Action code settings. - * @returns {Promise} - */ -export async function sendPasswordResetEmail(auth, email, actionCodeSettings) { - return auth.sendPasswordResetEmail.call(auth, email, actionCodeSettings, MODULAR_DEPRECATION_ARG); -} - -/** - * Sends a sign-in email link to the user with the specified email. - * @param {Auth} auth - The Auth instance. - * @param {string} email - The user's email address. - * @param {ActionCodeSettings} [actionCodeSettings] - Optional. Action code settings. - * @returns {Promise} - */ -export async function sendSignInLinkToEmail(auth, email, actionCodeSettings) { - return auth.sendSignInLinkToEmail.call(auth, email, actionCodeSettings, MODULAR_DEPRECATION_ARG); -} - -/** - * Changes the type of persistence on the Auth instance for the currently saved Auth session and applies this type of persistence for future sign-in requests, including sign-in with redirect requests. - * @param {Auth} auth - The Auth instance. - * @param {Persistence} persistence - The persistence type. - * @returns {Promise} - */ -export async function setPersistence(auth, persistence) { - throw new Error('setPersistence is unsupported by the native Firebase SDKs'); -} - -/** - * Asynchronously signs in as an anonymous user. - * @param {Auth} auth - The Auth instance. - * @returns {Promise} - */ -export async function signInAnonymously(auth) { - return auth.signInAnonymously.call(auth, MODULAR_DEPRECATION_ARG); -} - -/** - * Asynchronously signs in with the given credentials. - * @param {Auth} auth - The Auth instance. - * @param {AuthCredential} credential - The auth credentials. - * @returns {Promise} - */ -export async function signInWithCredential(auth, credential) { - return auth.signInWithCredential.call(auth, credential, MODULAR_DEPRECATION_ARG); -} - -/** - * Asynchronously signs in using a custom token. - * @param {Auth} auth - The Auth instance. - * @param {string} customToken - The custom token. - * @returns {Promise} - */ -export async function signInWithCustomToken(auth, customToken) { - return auth.signInWithCustomToken.call(auth, customToken, MODULAR_DEPRECATION_ARG); -} - -/** - * Asynchronously signs in using an email and password. - * @param {Auth} auth - The Auth instance. - * @param {string} email - The user's email address. - * @param {string} password - The user's password. - * @returns {Promise} - */ -export async function signInWithEmailAndPassword(auth, email, password) { - return auth.signInWithEmailAndPassword.call(auth, email, password, MODULAR_DEPRECATION_ARG); -} - -/** - * Asynchronously signs in using an email and sign-in email link. - * @param {Auth} auth - The Auth instance. - * @param {string} email - The user's email address. - * @param {string} emailLink - The email link. - * @returns {Promise} - */ -export async function signInWithEmailLink(auth, email, emailLink) { - return auth.signInWithEmailLink.call(auth, email, emailLink, MODULAR_DEPRECATION_ARG); -} - -/** - * Asynchronously signs in using a phone number. - * @param {Auth} auth - The Auth instance. - * @param {string} phoneNumber - The user's phone number. - * @param {ApplicationVerifier} appVerifier - The application verifier. - * @returns {Promise} - */ -export async function signInWithPhoneNumber(auth, phoneNumber, appVerifier) { - return auth.signInWithPhoneNumber.call(auth, phoneNumber, appVerifier, MODULAR_DEPRECATION_ARG); -} - -/** - * Asynchronously verifies a phone number. - * @param {Auth} auth - The Auth instance. - * @param {string} phoneNumber - The user's phone number. - * @param {number | boolean} autoVerifyTimeoutOrForceResend - The auto verify timeout or force resend flag. - * @param {boolean} [forceResend] - Optional. Whether to force resend. - * @returns {PhoneAuthListener} - */ -export function verifyPhoneNumber(auth, phoneNumber, autoVerifyTimeoutOrForceResend, forceResend) { - return auth.verifyPhoneNumber.call( - auth, - phoneNumber, - autoVerifyTimeoutOrForceResend, - forceResend, - MODULAR_DEPRECATION_ARG, - ); -} - -/** - * Authenticates a Firebase client using a popup-based OAuth authentication flow. - * @param {Auth} auth - The Auth instance. - * @param {AuthProvider} provider - The auth provider. - * @param {PopupRedirectResolver} [resolver] - Optional. The popup redirect resolver. - * @returns {Promise} - */ -export async function signInWithPopup(auth, provider, resolver) { - return auth.signInWithPopup.call(auth, provider, resolver, MODULAR_DEPRECATION_ARG); -} - -/** - * Authenticates a Firebase client using a full-page redirect flow. - * @param {Auth} auth - The Auth instance. - * @param {AuthProvider} provider - The auth provider. - * @param {PopupRedirectResolver} [resolver] - Optional. The popup redirect resolver. - * @returns {Promise} - */ -export async function signInWithRedirect(auth, provider, resolver) { - return auth.signInWithRedirect.call(auth, provider, resolver, MODULAR_DEPRECATION_ARG); -} - -/** - * Signs out the current user. - * @param {Auth} auth - The Auth instance. - * @returns {Promise} - */ -export async function signOut(auth) { - return auth.signOut.call(auth, MODULAR_DEPRECATION_ARG); -} - -/** - * Asynchronously sets the provided user as Auth.currentUser on the Auth instance. - * @param {Auth} auth - The Auth instance. - * @param {User} user - The user to set as the current user. - * @returns {Promise} - */ -export async function updateCurrentUser(auth, user) { - throw new Error('updateCurrentUser is unsupported by the native Firebase SDKs'); -} - -/** - * Sets the current language to the default device/browser preference. - * @param {Auth} auth - The Auth instance. - */ -export function useDeviceLanguage(auth) { - throw new Error('useDeviceLanguage is unsupported by the native Firebase SDKs'); -} - -/** - * Sets the language code. - * @param {Auth} auth - The Auth instance. - * @param {string} languageCode - The language code. - */ -export function setLanguageCode(auth, languageCode) { - return auth.setLanguageCode.call(auth, languageCode, MODULAR_DEPRECATION_ARG); -} - -/** - * Configures a shared user access group to sync auth state across multiple apps via the Keychain. - * @param {Auth} auth - The Auth instance. - * @param {string} userAccessGroup - The user access group. - * @returns {Promise} - */ -export function useUserAccessGroup(auth, userAccessGroup) { - return auth.useUserAccessGroup.call(auth, userAccessGroup, MODULAR_DEPRECATION_ARG); -} - -/** - * Verifies the password reset code sent to the user by email or other out-of-band mechanism. - * @param {Auth} auth - The Auth instance. - * @param {string} code - The password reset code. - * @returns {Promise} - */ -export async function verifyPasswordResetCode(auth, code) { - return auth.verifyPasswordResetCode.call(auth, code, MODULAR_DEPRECATION_ARG); -} - -/** - * Parses the email action link string and returns an ActionCodeURL if the link is valid, otherwise returns null. - * @param {string} link - The email action link string. - * @returns {ActionCodeURL | null} - */ -export function parseActionCodeURL(link) { - throw new Error('parseActionCodeURL is unsupported by the native Firebase SDKs'); -} - -/** - * Deletes and signs out the user. - * @param {User} user - The user to delete. - * @returns {Promise} - */ -export async function deleteUser(user) { - return user.delete.call(user, MODULAR_DEPRECATION_ARG); -} - -/** - * Returns a JSON Web Token (JWT) used to identify the user to a Firebase service. - * @param {User} user - The user to get the token for. - * @param {boolean} [forceRefresh] - Optional. Whether to force refresh the token. - * @returns {Promise} - */ -export async function getIdToken(user, forceRefresh) { - return user.getIdToken.call(user, forceRefresh, MODULAR_DEPRECATION_ARG); -} - -/** - * Returns a deserialized JSON Web Token (JWT) used to identify the user to a Firebase service. - * @param {User} user - The user to get the token result for. - * @param {boolean} [forceRefresh] - Optional. Whether to force refresh the token. - * @returns {Promise} - */ -export async function getIdTokenResult(user, forceRefresh) { - return user.getIdTokenResult.call(user, forceRefresh, MODULAR_DEPRECATION_ARG); -} - -/** - * Links the user account with the given credentials. - * @param {User} user - The user to link the credentials with. - * @param {AuthCredential} credential - The auth credentials. - * @returns {Promise} - */ -export async function linkWithCredential(user, credential) { - return user.linkWithCredential.call(user, credential, MODULAR_DEPRECATION_ARG); -} - -/** - * Links the user account with the given phone number. - * @param {User} user - The user to link the phone number with. - * @param {string} phoneNumber - The phone number. - * @param {ApplicationVerifier} appVerifier - The application verifier. - * @returns {Promise} - */ -export async function linkWithPhoneNumber(user, phoneNumber, appVerifier) { - throw new Error('linkWithPhoneNumber is unsupported by the native Firebase SDKs'); -} - -/** - * Links the authenticated provider to the user account using a pop-up based OAuth flow. - * @param {User} user - The user to link the provider with. - * @param {AuthProvider} provider - The auth provider. - * @param {PopupRedirectResolver} [resolver] - Optional. The popup redirect resolver. - * @returns {Promise} - */ -export async function linkWithPopup(user, provider, resolver) { - return user.linkWithPopup.call(user, provider, resolver, MODULAR_DEPRECATION_ARG); -} - -/** - * Links the OAuthProvider to the user account using a full-page redirect flow. - * @param {User} user - The user to link the provider with. - * @param {AuthProvider} provider - The auth provider. - * @param {PopupRedirectResolver} [resolver] - Optional. The popup redirect resolver. - * @returns {Promise} - */ -export async function linkWithRedirect(user, provider, resolver) { - return user.linkWithRedirect.call(user, provider, resolver, MODULAR_DEPRECATION_ARG); -} - -/** - * The MultiFactorUser corresponding to the user. - * @param {User} user - The user to get the multi-factor user for. - * @returns {MultiFactorUser} - */ -export function multiFactor(user) { - return new MultiFactorUser(getAuth(), user); -} - -/** - * Re-authenticates a user using a fresh credential. - * @param {User} user - The user to re-authenticate. - * @param {AuthCredential} credential - The auth credentials. - * @returns {Promise} - */ -export async function reauthenticateWithCredential(user, credential) { - return user.reauthenticateWithCredential.call(user, credential, MODULAR_DEPRECATION_ARG); -} - -/** - * Re-authenticates a user using a fresh phone credential. - * @param {User} user - The user to re-authenticate. - * @param {string} phoneNumber - The phone number. - * @param {ApplicationVerifier} appVerifier - The application verifier. - * @returns {Promise} - */ -export async function reauthenticateWithPhoneNumber(user, phoneNumber, appVerifier) { - throw new Error('reauthenticateWithPhoneNumber is unsupported by the native Firebase SDKs'); -} - -/** - * Re-authenticate a user with a federated authentication provider (Microsoft, Yahoo). For native platforms, this will open a browser window. - * @param {User} user - The user to re-authenticate. - * @param {AuthProvider} provider - The auth provider. - * @param {PopupRedirectResolver} [resolver] - Optional. The popup redirect resolver. Web only. - * @returns {Promise} - */ -export async function reauthenticateWithPopup(user, provider, resolver) { - return user.reauthenticateWithPopup.call(user, provider, resolver, MODULAR_DEPRECATION_ARG); -} - -/** - * Re-authenticate a user with a federated authentication provider (Microsoft, Yahoo). For native platforms, this will open a browser window. - * @param {User} user - The user to re-authenticate. - * @param {AuthProvider} provider - The auth provider. - * @param {PopupRedirectResolver} [resolver] - Optional. The popup redirect resolver. Web only. - * @returns {Promise} - */ -export async function reauthenticateWithRedirect(user, provider, resolver) { - return user.reauthenticateWithRedirect.call(user, provider, resolver, MODULAR_DEPRECATION_ARG); -} - -/** - * Reloads user account data, if signed in. - * @param {User} user - The user to reload data for. - * @returns {Promise} - */ -export async function reload(user) { - return user.reload.call(user, MODULAR_DEPRECATION_ARG); -} - -/** - * Sends a verification email to a user. - * @param {User} user - The user to send the email to. - * @param {ActionCodeSettings} [actionCodeSettings] - Optional. Action code settings. - * @returns {Promise} - */ -export async function sendEmailVerification(user, actionCodeSettings) { - return user.sendEmailVerification.call(user, actionCodeSettings, MODULAR_DEPRECATION_ARG); -} - -/** - * Unlinks a provider from a user account. - * @param {User} user - The user to unlink the provider from. - * @param {string} providerId - The provider ID. - * @returns {Promise} - */ -export async function unlink(user, providerId) { - return user.unlink.call(user, providerId, MODULAR_DEPRECATION_ARG); -} - -/** - * Updates the user's email address. - * @param {User} user - The user to update the email for. - * @param {string} newEmail - The new email address. - * @returns {Promise} - */ -export async function updateEmail(user, newEmail) { - return user.updateEmail.call(user, newEmail, MODULAR_DEPRECATION_ARG); -} - -/** - * Updates the user's password. - * @param {User} user - The user to update the password for. - * @param {string} newPassword - The new password. - * @returns {Promise} - */ -export async function updatePassword(user, newPassword) { - return user.updatePassword.call(user, newPassword, MODULAR_DEPRECATION_ARG); -} - -/** - * Updates the user's phone number. - * @param {User} user - The user to update the phone number for. - * @param {AuthCredential} credential - The auth credentials. - * @returns {Promise} - */ -export async function updatePhoneNumber(user, credential) { - return user.updatePhoneNumber.call(user, credential, MODULAR_DEPRECATION_ARG); -} - -/** - * Updates a user's profile data. - * @param {User} user - The user to update the profile for. - * @param {{ displayName?: string | null, photoURL?: string | null }} profile - An object containing the profile data to update. - * @returns {Promise} - */ -export async function updateProfile(user, { displayName, photoURL: photoUrl }) { - return user.updateProfile.call( - user, - { displayName, photoURL: photoUrl }, - MODULAR_DEPRECATION_ARG, - ); -} - -/** - * Sends a verification email to a new email address. - * @param {User} user - The user to send the email to. - * @param {string} newEmail - The new email address. - * @param {ActionCodeSettings} [actionCodeSettings] - Optional. Action code settings. - * @returns {Promise} - */ -export async function verifyBeforeUpdateEmail(user, newEmail, actionCodeSettings) { - return user.verifyBeforeUpdateEmail.call( - user, - newEmail, - actionCodeSettings, - MODULAR_DEPRECATION_ARG, - ); -} - -/** - * Extracts provider specific AdditionalUserInfo for the given credential. - * @param {UserCredential} userCredential - The user credential. - * @returns {AdditionalUserInfo | null} - */ -export function getAdditionalUserInfo(userCredential) { - return userCredential.additionalUserInfo; -} - -/** - * Returns the custom auth domain for the auth instance. - * @param {Auth} auth - The Auth instance. - * @returns {Promise} - */ -export function getCustomAuthDomain(auth) { - return auth.getCustomAuthDomain.call(auth, MODULAR_DEPRECATION_ARG); -} - -/** - * Returns a password validation status - * @param {Auth} auth - The Auth instance. - * @param {string} password - The password to validate. - * @returns {Promise} - */ -export async function validatePassword(auth, password) { - if (!auth || !auth.app) { - throw new Error( - "firebase.auth().validatePassword(*) 'auth' must be a valid Auth instance with an 'app' property. Received: undefined", - ); - } - - if (password === null || password === undefined) { - throw new Error( - "firebase.auth().validatePassword(*) expected 'password' to be a non-null or a defined value.", - ); - } - - return auth.validatePassword.call(auth, password, MODULAR_DEPRECATION_ARG); -} diff --git a/packages/auth/lib/modular/index.ts b/packages/auth/lib/modular/index.ts new file mode 100644 index 0000000000..b81a93efb1 --- /dev/null +++ b/packages/auth/lib/modular/index.ts @@ -0,0 +1,4 @@ +/* + * Re-export modular API for paths that expect `lib/modular/index` (e.g. legacy test imports). + */ +export * from '../modular'; diff --git a/packages/auth/lib/multiFactor.js b/packages/auth/lib/multiFactor.js deleted file mode 100644 index bfaca1278f..0000000000 --- a/packages/auth/lib/multiFactor.js +++ /dev/null @@ -1,50 +0,0 @@ -import { reload } from './modular'; -/** - * Return a MultiFactorUser instance the gateway to multi-factor operations. - */ -export function multiFactor(auth) { - return new MultiFactorUser(auth); -} - -export class MultiFactorUser { - constructor(auth, user) { - this._auth = auth; - if (user === undefined) { - user = auth.currentUser; - } - this._user = user; - this.enrolledFactors = user.multiFactor.enrolledFactors; - } - - getSession() { - return this._auth.native.getSession(); - } - - /** - * Finalize the enrollment process for the given multi-factor assertion. - * Optionally set a displayName. This method will reload the current user - * profile, which is necessary to see the multi-factor changes. - */ - async enroll(multiFactorAssertion, displayName) { - const { token, secret, totpSecret, verificationCode } = multiFactorAssertion; - if (token && secret) { - await this._auth.native.finalizeMultiFactorEnrollment(token, secret, displayName); - } else if (totpSecret && verificationCode) { - await this._auth.native.finalizeTotpEnrollment(totpSecret, verificationCode, displayName); - } else { - throw new Error('Invalid multi-factor assertion provided for enrollment.'); - } - - // We need to reload the user otherwise the changes are not visible - // TODO reload not working on Other platform - return reload(this._auth.currentUser); - } - - async unenroll(enrollmentId) { - await this._auth.native.unenrollMultiFactor(enrollmentId); - - if (this._auth.currentUser) { - return reload(this._auth.currentUser); - } - } -} diff --git a/packages/auth/lib/multiFactor.ts b/packages/auth/lib/multiFactor.ts new file mode 100644 index 0000000000..426960f974 --- /dev/null +++ b/packages/auth/lib/multiFactor.ts @@ -0,0 +1,84 @@ +/* + * 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 { reload } from './modular'; +import type { AuthInternal } from './types/internal'; +import type { FirebaseAuth, User } from './types/auth'; +import UserClass from './User'; + +/** User shape with multiFactor (required for MultiFactorUser). */ +interface UserWithMultiFactor { + multiFactor: { enrolledFactors: unknown[] }; +} + +/** + * Return a MultiFactorUser instance the gateway to multi-factor operations. + */ +export function multiFactor(auth: FirebaseAuth): MultiFactorUser { + return new MultiFactorUser(auth as AuthInternal); +} + +export class MultiFactorUser { + _auth: AuthInternal; + _user: UserWithMultiFactor; + enrolledFactors: unknown[]; + + constructor(auth: AuthInternal, user?: User) { + this._auth = auth; + const u = (user ?? auth.currentUser) as UserWithMultiFactor; + this._user = u; + this.enrolledFactors = this._user.multiFactor.enrolledFactors; + } + + getSession(): Promise { + return this._auth.native.getSession(); + } + + /** + * Finalize the enrollment process for the given multi-factor assertion. + * Optionally set a displayName. This method will reload the current user + * profile, which is necessary to see the multi-factor changes. + */ + async enroll( + multiFactorAssertion: { + token?: string; + secret?: string; + totpSecret?: string; + verificationCode?: string; + }, + displayName?: string, + ): Promise { + const { token, secret, totpSecret, verificationCode } = multiFactorAssertion; + if (token && secret) { + await this._auth.native.finalizeMultiFactorEnrollment(token, secret, displayName); + } else if (totpSecret && verificationCode) { + await this._auth.native.finalizeTotpEnrollment(totpSecret, verificationCode, displayName); + } else { + throw new Error('Invalid multi-factor assertion provided for enrollment.'); + } + + return reload(this._auth.currentUser as UserClass); + } + + async unenroll(enrollmentId: string): Promise { + await this._auth.native.unenrollMultiFactor(enrollmentId); + + if (this._auth.currentUser) { + return reload(this._auth.currentUser as UserClass); + } + } +} diff --git a/packages/auth/lib/index.js b/packages/auth/lib/namespaced.ts similarity index 69% rename from packages/auth/lib/index.js rename to packages/auth/lib/namespaced.ts index 3ddb6dc9f9..cb0b6a81a6 100644 --- a/packages/auth/lib/index.js +++ b/packages/auth/lib/namespaced.ts @@ -30,7 +30,11 @@ import { FirebaseModule, createModuleNamespace, getFirebaseRoot, + type ModuleConfig, } from '@react-native-firebase/app/dist/module/internal'; +import type { ReactNativeFirebase } from '@react-native-firebase/app'; +import type { FirebaseAuthTypes } from './types/namespaced'; +import type { AuthInternal, NativeUserShape } from './types/internal'; import ConfirmationResult from './ConfirmationResult'; import PhoneAuthListener from './PhoneAuthListener'; import PhoneMultiFactorGenerator from './PhoneMultiFactorGenerator'; @@ -49,7 +53,8 @@ import OIDCAuthProvider from './providers/OIDCAuthProvider'; import PhoneAuthProvider from './providers/PhoneAuthProvider'; import TwitterAuthProvider from './providers/TwitterAuthProvider'; import { TotpSecret } from './TotpSecret'; -import version from './version'; +import { version } from './version'; +// @ts-ignore — JS implementation, no separate types (see tsconfig package allowJs) import fallBackModule from './web/RNFBAuthModule'; import { PasswordPolicyMixin } from './password-policy/PasswordPolicyMixin'; @@ -96,23 +101,36 @@ const statics = { const namespace = 'auth'; const nativeModuleName = 'RNFBAuthModule'; -class FirebaseAuthModule extends FirebaseModule { - constructor(...args) { - super(...args); +class FirebaseAuthModule extends FirebaseModule { + _user: InstanceType | null; + _settings: InstanceType | null; + _authResult: boolean; + _languageCode: string; + _tenantId: string | null; + _projectPasswordPolicy: unknown; + _tenantPasswordPolicies: Record; + + constructor(...args: [unknown, ModuleConfig, ...unknown[]]) { + super( + args[0] as ReactNativeFirebase.FirebaseAppBase, + args[1] as ModuleConfig, + ...(args.slice(2) as (string | null | undefined)[]), + ); this._user = null; this._settings = null; this._authResult = false; - this._languageCode = this.native.APP_LANGUAGE[this.app._name]; + const appName = (this.app as { _name?: string })._name ?? this.app.name; + this._languageCode = (this.native.APP_LANGUAGE[appName] ?? '') as string; this._tenantId = null; this._projectPasswordPolicy = null; this._tenantPasswordPolicies = {}; if (!this.languageCode) { - this._languageCode = this.native.APP_LANGUAGE['[DEFAULT]']; + this._languageCode = (this.native.APP_LANGUAGE['[DEFAULT]'] ?? '') as string; } - if (this.native.APP_USER[this.app._name]) { - this._setUser(this.native.APP_USER[this.app._name]); + if (this.native.APP_USER[appName]) { + this._setUser(this.native.APP_USER[appName]); } this.emitter.addListener(this.eventNameForApp('auth_state_changed'), event => { @@ -156,10 +174,10 @@ class FirebaseAuthModule extends FirebaseModule { } // as this is a setter, we can't use async/await. So we set it first so it is available immediately if (code === null) { - this._languageCode = this.native.APP_LANGUAGE[this.app._name]; - + const an = (this.app as { _name?: string })._name ?? this.app.name; + this._languageCode = (this.native.APP_LANGUAGE[an] ?? '') as string; if (!this.languageCode) { - this._languageCode = this.native.APP_LANGUAGE['[DEFAULT]']; + this._languageCode = (this.native.APP_LANGUAGE['[DEFAULT]'] ?? '') as string; } } else { this._languageCode = code; @@ -168,7 +186,7 @@ class FirebaseAuthModule extends FirebaseModule { this.setLanguageCode(code); } - get config() { + get config(): Record { // for modular API, firebase JS SDK has a config object which is not available in native SDKs return {}; } @@ -179,7 +197,7 @@ class FirebaseAuthModule extends FirebaseModule { get settings() { if (!this._settings) { - this._settings = new Settings(this); + this._settings = new Settings(this as unknown as AuthInternal); } return this._settings; } @@ -188,15 +206,19 @@ class FirebaseAuthModule extends FirebaseModule { return this._user; } - _setUser(user) { - this._user = user ? createDeprecationProxy(new User(this, user)) : null; + _setUser(user: unknown) { + this._user = user + ? createDeprecationProxy(new User(this as unknown as AuthInternal, user as NativeUserShape)) + : null; this._authResult = true; this.emitter.emit(this.eventNameForApp('onUserChanged'), this._user); return this._user; } - _setUserCredential(userCredential) { - const user = createDeprecationProxy(new User(this, userCredential.user)); + _setUserCredential(userCredential: { user: unknown; additionalUserInfo?: unknown }) { + const user = createDeprecationProxy( + new User(this as unknown as AuthInternal, userCredential.user as NativeUserShape), + ); this._user = user; this._authResult = true; this.emitter.emit(this.eventNameForApp('onUserChanged'), this._user); @@ -206,7 +228,7 @@ class FirebaseAuthModule extends FirebaseModule { }; } - async setLanguageCode(code) { + async setLanguageCode(code: string | null) { if (!isString(code) && !isNull(code)) { throw new Error( "firebase.auth().setLanguageCode(*) expected 'languageCode' to be a string or null value", @@ -216,17 +238,17 @@ class FirebaseAuthModule extends FirebaseModule { await this.native.setLanguageCode(code); if (code === null) { - this._languageCode = this.native.APP_LANGUAGE[this.app._name]; - + const an = (this.app as { _name?: string })._name ?? this.app.name; + this._languageCode = (this.native.APP_LANGUAGE[an] ?? '') as string; if (!this.languageCode) { - this._languageCode = this.native.APP_LANGUAGE['[DEFAULT]']; + this._languageCode = (this.native.APP_LANGUAGE['[DEFAULT]'] ?? '') as string; } } else { this._languageCode = code; } } - async setTenantId(tenantId) { + async setTenantId(tenantId: string) { if (!isString(tenantId)) { throw new Error("firebase.auth().setTenantId(*) expected 'tenantId' to be a string"); } @@ -234,7 +256,9 @@ class FirebaseAuthModule extends FirebaseModule { await this.native.setTenantId(tenantId); } - onAuthStateChanged(listenerOrObserver) { + onAuthStateChanged( + listenerOrObserver: FirebaseAuthTypes.CallbackOrObserver, + ) { const listener = parseListenerOrObserver(listenerOrObserver); const subscription = this.emitter.addListener( this.eventNameForApp('onAuthStateChanged'), @@ -249,7 +273,9 @@ class FirebaseAuthModule extends FirebaseModule { return () => subscription.remove(); } - onIdTokenChanged(listenerOrObserver) { + onIdTokenChanged( + listenerOrObserver: FirebaseAuthTypes.CallbackOrObserver, + ) { const listener = parseListenerOrObserver(listenerOrObserver); const subscription = this.emitter.addListener( this.eventNameForApp('onIdTokenChanged'), @@ -264,7 +290,9 @@ class FirebaseAuthModule extends FirebaseModule { return () => subscription.remove(); } - onUserChanged(listenerOrObserver) { + onUserChanged( + listenerOrObserver: FirebaseAuthTypes.CallbackOrObserver, + ) { const listener = parseListenerOrObserver(listenerOrObserver); const subscription = this.emitter.addListener(this.eventNameForApp('onUserChanged'), listener); if (this._authResult) { @@ -280,7 +308,7 @@ class FirebaseAuthModule extends FirebaseModule { signOut() { return this.native.signOut().then(() => { - this._setUser(); + this._setUser(undefined); }); } @@ -290,41 +318,62 @@ class FirebaseAuthModule extends FirebaseModule { .then(userCredential => this._setUserCredential(userCredential)); } - signInWithPhoneNumber(phoneNumber, forceResend) { + signInWithPhoneNumber(phoneNumber: string, forceResend?: boolean) { if (isAndroid) { return this.native .signInWithPhoneNumber(phoneNumber, forceResend || false) - .then(result => new ConfirmationResult(this, result.verificationId)); + .then( + result => new ConfirmationResult(this as unknown as AuthInternal, result.verificationId), + ); } return this.native .signInWithPhoneNumber(phoneNumber) - .then(result => new ConfirmationResult(this, result.verificationId)); + .then( + result => new ConfirmationResult(this as unknown as AuthInternal, result.verificationId), + ); } - verifyPhoneNumber(phoneNumber, autoVerifyTimeoutOrForceResend, forceResend) { + verifyPhoneNumber( + phoneNumber: string, + autoVerifyTimeoutOrForceResend?: number | boolean, + forceResend?: boolean, + ) { let _forceResend = forceResend; let _autoVerifyTimeout = 60; if (isBoolean(autoVerifyTimeoutOrForceResend)) { _forceResend = autoVerifyTimeoutOrForceResend; - } else { + } else if (typeof autoVerifyTimeoutOrForceResend === 'number') { _autoVerifyTimeout = autoVerifyTimeoutOrForceResend; } - return new PhoneAuthListener(this, phoneNumber, _autoVerifyTimeout, _forceResend); + return new PhoneAuthListener( + this as unknown as AuthInternal, + phoneNumber, + _autoVerifyTimeout, + _forceResend, + ); } - verifyPhoneNumberWithMultiFactorInfo(multiFactorHint, session) { - return this.native.verifyPhoneNumberWithMultiFactorInfo(multiFactorHint.uid, session); + verifyPhoneNumberWithMultiFactorInfo( + multiFactorHint: FirebaseAuthTypes.MultiFactorInfo, + session: FirebaseAuthTypes.MultiFactorSession, + ) { + return this.native.verifyPhoneNumberWithMultiFactorInfo( + multiFactorHint.uid, + session as unknown as string, + ); } - verifyPhoneNumberForMultiFactor(phoneInfoOptions) { + verifyPhoneNumberForMultiFactor( + phoneInfoOptions: FirebaseAuthTypes.PhoneMultiFactorEnrollInfoOptions, + ) { const { phoneNumber, session } = phoneInfoOptions; - return this.native.verifyPhoneNumberForMultiFactor(phoneNumber, session); + return this.native.verifyPhoneNumberForMultiFactor(phoneNumber, session as unknown as string); } - resolveMultiFactorSignIn(session, verificationId, verificationCode) { + resolveMultiFactorSignIn(session: string, verificationId: string, verificationCode: string) { return this.native .resolveMultiFactorSignIn(session, verificationId, verificationCode) .then(userCredential => { @@ -332,13 +381,13 @@ class FirebaseAuthModule extends FirebaseModule { }); } - resolveTotpSignIn(session, uid, totpSecret) { + resolveTotpSignIn(session: string, uid: string, totpSecret: string) { return this.native.resolveTotpSignIn(session, uid, totpSecret).then(userCredential => { return this._setUserCredential(userCredential); }); } - createUserWithEmailAndPassword(email, password) { + createUserWithEmailAndPassword(email: string, password: string) { return ( this.native .createUserWithEmailAndPassword(email, password) @@ -346,7 +395,8 @@ class FirebaseAuthModule extends FirebaseModule { /* istanbul ignore next - native error handling cannot be unit tested */ .catch(error => { if (error.code === 'auth/password-does-not-meet-requirements') { - return this._recachePasswordPolicy() + return (this as unknown as { _recachePasswordPolicy: () => Promise }) + ._recachePasswordPolicy() .catch(() => { // Silently ignore recache failures - the original error matters more }) @@ -359,7 +409,7 @@ class FirebaseAuthModule extends FirebaseModule { ); } - signInWithEmailAndPassword(email, password) { + signInWithEmailAndPassword(email: string, password: string) { return ( this.native .signInWithEmailAndPassword(email, password) @@ -367,7 +417,8 @@ class FirebaseAuthModule extends FirebaseModule { /* istanbul ignore next - native error handling cannot be unit tested */ .catch(error => { if (error.code === 'auth/password-does-not-meet-requirements') { - return this._recachePasswordPolicy() + return (this as unknown as { _recachePasswordPolicy: () => Promise }) + ._recachePasswordPolicy() .catch(() => { // Silently ignore recache failures - the original error matters more }) @@ -380,48 +431,55 @@ class FirebaseAuthModule extends FirebaseModule { ); } - signInWithCustomToken(customToken) { + signInWithCustomToken(customToken: string) { return this.native .signInWithCustomToken(customToken) .then(userCredential => this._setUserCredential(userCredential)); } - signInWithCredential(credential) { + signInWithCredential(credential: FirebaseAuthTypes.AuthCredential) { return this.native .signInWithCredential(credential.providerId, credential.token, credential.secret) .then(userCredential => this._setUserCredential(userCredential)); } - revokeToken(authorizationCode) { + revokeToken(authorizationCode: string) { return this.native.revokeToken(authorizationCode); } - sendPasswordResetEmail(email, actionCodeSettings = null) { + sendPasswordResetEmail( + email: string, + actionCodeSettings: FirebaseAuthTypes.ActionCodeSettings | null = null, + ) { return this.native.sendPasswordResetEmail(email, actionCodeSettings); } - sendSignInLinkToEmail(email, actionCodeSettings = {}) { - return this.native.sendSignInLinkToEmail(email, actionCodeSettings); + sendSignInLinkToEmail( + email: string, + actionCodeSettings: FirebaseAuthTypes.ActionCodeSettings | Record = {}, + ) { + return this.native.sendSignInLinkToEmail(email, actionCodeSettings as Record); } - isSignInWithEmailLink(emailLink) { + isSignInWithEmailLink(emailLink: string) { return this.native.isSignInWithEmailLink(emailLink); } - signInWithEmailLink(email, emailLink) { + signInWithEmailLink(email: string, emailLink: string) { return this.native .signInWithEmailLink(email, emailLink) .then(userCredential => this._setUserCredential(userCredential)); } - confirmPasswordReset(code, newPassword) { + confirmPasswordReset(code: string, newPassword: string) { return ( this.native .confirmPasswordReset(code, newPassword) /* istanbul ignore next - native error handling cannot be unit tested */ .catch(error => { if (error.code === 'auth/password-does-not-meet-requirements') { - return this._recachePasswordPolicy() + return (this as unknown as { _recachePasswordPolicy: () => Promise }) + ._recachePasswordPolicy() .catch(() => { // Silently ignore recache failures - the original error matters more }) @@ -434,25 +492,25 @@ class FirebaseAuthModule extends FirebaseModule { ); } - applyActionCode(code) { + applyActionCode(code: string) { return this.native.applyActionCode(code).then(user => { this._setUser(user); }); } - checkActionCode(code) { + checkActionCode(code: string) { return this.native.checkActionCode(code); } - fetchSignInMethodsForEmail(email) { + fetchSignInMethodsForEmail(email: string) { return this.native.fetchSignInMethodsForEmail(email); } - verifyPasswordResetCode(code) { + verifyPasswordResetCode(code: string) { return this.native.verifyPasswordResetCode(code); } - useUserAccessGroup(userAccessGroup) { + useUserAccessGroup(userAccessGroup: string) { if (isAndroid) { return Promise.resolve(); } @@ -469,13 +527,13 @@ class FirebaseAuthModule extends FirebaseModule { throw new Error('firebase.auth().setPersistence() is unsupported by the native Firebase SDKs.'); } - signInWithPopup(provider) { + signInWithPopup(provider: FirebaseAuthTypes.AuthProvider & { toObject(): object }) { return this.native .signInWithProvider(provider.toObject()) .then(userCredential => this._setUserCredential(userCredential)); } - signInWithRedirect(provider) { + signInWithRedirect(provider: FirebaseAuthTypes.AuthProvider & { toObject(): object }) { return this.native .signInWithProvider(provider.toObject()) .then(userCredential => this._setUserCredential(userCredential)); @@ -488,7 +546,7 @@ class FirebaseAuthModule extends FirebaseModule { ); } - useEmulator(url) { + useEmulator(url: string) { if (!url || !isString(url) || !isValidUrl(url)) { throw new Error('firebase.auth().useEmulator() takes a non-empty string URL'); } @@ -520,21 +578,21 @@ class FirebaseAuthModule extends FirebaseModule { if (!urlMatches) { throw new Error('firebase.auth().useEmulator() unable to parse host and port from URL'); } - const host = urlMatches[1]; - const port = parseInt(urlMatches[2], 10); + const host = urlMatches[1]!; + const port = parseInt(urlMatches[2]!, 10); this.native.useEmulator(host, port); return [host, port]; // undocumented return, useful for unit testing } - getMultiFactorResolver(error) { - return getMultiFactorResolver(this, error); + getMultiFactorResolver(error: import('./types/auth').MultiFactorError) { + return getMultiFactorResolver(this as unknown as AuthInternal, error); } - multiFactor(user) { - if (user.userId !== this.currentUser.userId) { + multiFactor(user: InstanceType) { + if (user.uid !== this.currentUser!.uid) { throw new Error('firebase.auth().multiFactor() only operates on currentUser'); } - return new MultiFactorUser(this, user); + return new MultiFactorUser(this as unknown as AuthInternal, user); } getCustomAuthDomain() { @@ -548,9 +606,7 @@ Object.assign(FirebaseAuthModule.prototype, PasswordPolicyMixin); // import { SDK_VERSION } from '@react-native-firebase/auth'; export const SDK_VERSION = version; -// import auth from '@react-native-firebase/auth'; -// auth().X(...); -export default createModuleNamespace({ +const authNamespace = createModuleNamespace({ statics, version, namespace, @@ -561,12 +617,32 @@ export default createModuleNamespace({ ModuleClass: FirebaseAuthModule, }); -export * from './modular/index'; +type AuthNamespace = ReactNativeFirebase.FirebaseModuleWithStaticsAndApp< + FirebaseAuthTypes.Module, + FirebaseAuthTypes.Statics +> & { + auth: ReactNativeFirebase.FirebaseModuleWithStaticsAndApp< + FirebaseAuthTypes.Module, + FirebaseAuthTypes.Statics + >; + firebase: ReactNativeFirebase.Module; + app(name?: string): ReactNativeFirebase.FirebaseApp; +}; + +// import auth from '@react-native-firebase/auth'; +// auth().X(...); +export default authNamespace as unknown as AuthNamespace; // import auth, { firebase } from '@react-native-firebase/auth'; // auth().X(...); // firebase.auth().X(...); -export const firebase = getFirebaseRoot(); +export const firebase = + getFirebaseRoot() as unknown as ReactNativeFirebase.FirebaseNamespacedExport< + 'auth', + FirebaseAuthTypes.Module, + FirebaseAuthTypes.Statics, + true + >; // Register the interop module for non-native platforms. setReactNativeModule(nativeModuleName, fallBackModule); diff --git a/packages/auth/lib/password-policy/PasswordPolicyImpl.js b/packages/auth/lib/password-policy/PasswordPolicyImpl.ts similarity index 52% rename from packages/auth/lib/password-policy/PasswordPolicyImpl.js rename to packages/auth/lib/password-policy/PasswordPolicyImpl.ts index cdfb99a118..ec8c8cc176 100644 --- a/packages/auth/lib/password-policy/PasswordPolicyImpl.js +++ b/packages/auth/lib/password-policy/PasswordPolicyImpl.ts @@ -15,21 +15,60 @@ * */ -// Minimum min password length enforced by the backend, even if no minimum length is set. const MINIMUM_MIN_PASSWORD_LENGTH = 6; +export interface PasswordPolicyApiResponse { + customStrengthOptions?: { + minPasswordLength?: number; + maxPasswordLength?: number; + containsLowercaseCharacter?: boolean; + containsUppercaseCharacter?: boolean; + containsNumericCharacter?: boolean; + containsNonAlphanumericCharacter?: boolean; + }; + enforcementState?: string; + allowedNonAlphanumericCharacters?: string[]; + forceUpgradeOnSignin?: boolean; + schemaVersion?: number; +} + +export interface PasswordPolicyCustomStrengthOptions { + minPasswordLength: number; + maxPasswordLength?: number; + containsLowercaseLetter?: boolean; + containsUppercaseLetter?: boolean; + containsNumericCharacter?: boolean; + containsNonAlphanumericCharacter?: boolean; +} + +export interface PasswordPolicyValidationStatus { + isValid: boolean; + passwordPolicy: PasswordPolicyImpl; + meetsMinPasswordLength?: boolean; + meetsMaxPasswordLength?: boolean; + containsLowercaseLetter?: boolean; + containsUppercaseLetter?: boolean; + containsNumericCharacter?: boolean; + containsNonAlphanumericCharacter?: boolean; +} + /** * Stores password policy requirements and provides password validation against the policy. * * @internal */ export class PasswordPolicyImpl { - constructor(response) { - // Only include custom strength options defined in the response. - const responseOptions = response.customStrengthOptions; - this.customStrengthOptions = {}; - this.customStrengthOptions.minPasswordLength = - responseOptions.minPasswordLength ?? MINIMUM_MIN_PASSWORD_LENGTH; + customStrengthOptions: PasswordPolicyCustomStrengthOptions; + enforcementState: string; + allowedNonAlphanumericCharacters: string; + forceUpgradeOnSignin: boolean; + schemaVersion: number | undefined; + + constructor(response: PasswordPolicyApiResponse) { + const responseOptions = response.customStrengthOptions ?? {}; + this.customStrengthOptions = { + minPasswordLength: responseOptions.minPasswordLength ?? MINIMUM_MIN_PASSWORD_LENGTH, + }; if (responseOptions.maxPasswordLength) { this.customStrengthOptions.maxPasswordLength = responseOptions.maxPasswordLength; } @@ -53,9 +92,8 @@ export class PasswordPolicyImpl { this.enforcementState = response.enforcementState === 'ENFORCEMENT_STATE_UNSPECIFIED' ? 'OFF' - : response.enforcementState; + : (response.enforcementState ?? 'OFF'); - // Use an empty string if no non-alphanumeric characters are specified in the response. this.allowedNonAlphanumericCharacters = response.allowedNonAlphanumericCharacters?.join('') ?? ''; @@ -63,8 +101,8 @@ export class PasswordPolicyImpl { this.schemaVersion = response.schemaVersion; } - validatePassword(password) { - const status = { + validatePassword(password: string): PasswordPolicyValidationStatus { + const status: PasswordPolicyValidationStatus = { isValid: true, passwordPolicy: this, }; @@ -72,17 +110,17 @@ export class PasswordPolicyImpl { this.validatePasswordLengthOptions(password, status); this.validatePasswordCharacterOptions(password, status); - status.isValid &&= status.meetsMinPasswordLength ?? true; - status.isValid &&= status.meetsMaxPasswordLength ?? true; - status.isValid &&= status.containsLowercaseLetter ?? true; - status.isValid &&= status.containsUppercaseLetter ?? true; - status.isValid &&= status.containsNumericCharacter ?? true; - status.isValid &&= status.containsNonAlphanumericCharacter ?? true; + status.isValid = status.isValid && (status.meetsMinPasswordLength ?? true); + status.isValid = status.isValid && (status.meetsMaxPasswordLength ?? true); + status.isValid = status.isValid && (status.containsLowercaseLetter ?? true); + status.isValid = status.isValid && (status.containsUppercaseLetter ?? true); + status.isValid = status.isValid && (status.containsNumericCharacter ?? true); + status.isValid = status.isValid && (status.containsNonAlphanumericCharacter ?? true); return status; } - validatePasswordLengthOptions(password, status) { + validatePasswordLengthOptions(password: string, status: PasswordPolicyValidationStatus): void { const minPasswordLength = this.customStrengthOptions.minPasswordLength; const maxPasswordLength = this.customStrengthOptions.maxPasswordLength; if (minPasswordLength) { @@ -93,7 +131,7 @@ export class PasswordPolicyImpl { } } - validatePasswordCharacterOptions(password, status) { + validatePasswordCharacterOptions(password: string, status: PasswordPolicyValidationStatus): void { this.updatePasswordCharacterOptionsStatuses(status, false, false, false, false); for (let i = 0; i < password.length; i++) { @@ -109,24 +147,29 @@ export class PasswordPolicyImpl { } updatePasswordCharacterOptionsStatuses( - status, - containsLowercaseCharacter, - containsUppercaseCharacter, - containsNumericCharacter, - containsNonAlphanumericCharacter, - ) { + status: PasswordPolicyValidationStatus, + containsLowercaseCharacter: boolean, + containsUppercaseCharacter: boolean, + containsNumericCharacter: boolean, + containsNonAlphanumericCharacter: boolean, + ): void { if (this.customStrengthOptions.containsLowercaseLetter) { - status.containsLowercaseLetter ||= containsLowercaseCharacter; + status.containsLowercaseLetter = + (status.containsLowercaseLetter ?? false) || containsLowercaseCharacter; } if (this.customStrengthOptions.containsUppercaseLetter) { - status.containsUppercaseLetter ||= containsUppercaseCharacter; + status.containsUppercaseLetter = + (status.containsUppercaseLetter ?? false) || containsUppercaseCharacter; } if (this.customStrengthOptions.containsNumericCharacter) { - status.containsNumericCharacter ||= containsNumericCharacter; + status.containsNumericCharacter = + (status.containsNumericCharacter ?? false) || containsNumericCharacter; } if (this.customStrengthOptions.containsNonAlphanumericCharacter) { - status.containsNonAlphanumericCharacter ||= containsNonAlphanumericCharacter; + status.containsNonAlphanumericCharacter = + (status.containsNonAlphanumericCharacter ?? false) || containsNonAlphanumericCharacter; } } } + export default PasswordPolicyImpl; diff --git a/packages/auth/lib/password-policy/PasswordPolicyMixin.js b/packages/auth/lib/password-policy/PasswordPolicyMixin.ts similarity index 59% rename from packages/auth/lib/password-policy/PasswordPolicyMixin.js rename to packages/auth/lib/password-policy/PasswordPolicyMixin.ts index e8c916dd3a..889b6ad09f 100644 --- a/packages/auth/lib/password-policy/PasswordPolicyMixin.js +++ b/packages/auth/lib/password-policy/PasswordPolicyMixin.ts @@ -16,24 +16,29 @@ */ import { fetchPasswordPolicy } from './passwordPolicyApi'; -import { PasswordPolicyImpl } from './PasswordPolicyImpl'; +import { PasswordPolicyImpl, type PasswordPolicyValidationStatus } from './PasswordPolicyImpl'; +import type { AuthWithAppOptions } from './passwordPolicyApi'; const EXPECTED_PASSWORD_POLICY_SCHEMA_VERSION = 1; -/** - * Password policy mixin - provides password policy caching and validation. - * Expects the target object to have: _tenantId, _projectPasswordPolicy, - * _tenantPasswordPolicies, and app.options.apiKey - */ +/** Target for PasswordPolicyMixin: auth module with tenant and policy cache (and mixin methods). */ +export interface PasswordPolicyMixinTarget extends AuthWithAppOptions { + _tenantId: string | null; + _projectPasswordPolicy: PasswordPolicyImpl | null; + _tenantPasswordPolicies: Record; + _getPasswordPolicyInternal(): PasswordPolicyImpl | null; + _updatePasswordPolicy(): Promise; +} + export const PasswordPolicyMixin = { - _getPasswordPolicyInternal() { + _getPasswordPolicyInternal(this: PasswordPolicyMixinTarget): PasswordPolicyImpl | null { if (this._tenantId === null) { return this._projectPasswordPolicy; } - return this._tenantPasswordPolicies[this._tenantId]; + return this._tenantPasswordPolicies[this._tenantId] ?? null; }, - async _updatePasswordPolicy() { + async _updatePasswordPolicy(this: PasswordPolicyMixinTarget): Promise { const response = await fetchPasswordPolicy(this); const passwordPolicy = new PasswordPolicyImpl(response); if (this._tenantId === null) { @@ -43,19 +48,25 @@ export const PasswordPolicyMixin = { } }, - async _recachePasswordPolicy() { + async _recachePasswordPolicy(this: PasswordPolicyMixinTarget): Promise { if (this._getPasswordPolicyInternal()) { await this._updatePasswordPolicy(); } }, - async validatePassword(password) { + async validatePassword( + this: PasswordPolicyMixinTarget, + password: string, + ): Promise { if (!this._getPasswordPolicyInternal()) { await this._updatePasswordPolicy(); } const passwordPolicy = this._getPasswordPolicyInternal(); - if (passwordPolicy.schemaVersion !== EXPECTED_PASSWORD_POLICY_SCHEMA_VERSION) { + if ( + !passwordPolicy || + passwordPolicy.schemaVersion !== EXPECTED_PASSWORD_POLICY_SCHEMA_VERSION + ) { throw new Error( 'auth/unsupported-password-policy-schema-version: The password policy received from the backend uses a schema version that is not supported by this version of the SDK.', ); diff --git a/packages/auth/lib/password-policy/passwordPolicyApi.js b/packages/auth/lib/password-policy/passwordPolicyApi.ts similarity index 65% rename from packages/auth/lib/password-policy/passwordPolicyApi.js rename to packages/auth/lib/password-policy/passwordPolicyApi.ts index 7d375deae8..5be825b247 100644 --- a/packages/auth/lib/password-policy/passwordPolicyApi.js +++ b/packages/auth/lib/password-policy/passwordPolicyApi.ts @@ -15,16 +15,24 @@ * */ +import type { PasswordPolicyApiResponse } from './PasswordPolicyImpl'; + +/** Auth instance with app.options.apiKey (for password policy API). */ +export interface AuthWithAppOptions { + app: { options: { apiKey: string } }; +} + /** * Performs an API request to Firebase Console to get password policy json. * - * @param {Object} auth - The authentication instance - * @returns {Promise} A promise that resolves to the API response. - * @throws {Error} Throws an error if the request fails or encounters an issue. + * @param auth - The authentication instance + * @returns A promise that resolves to the API response. + * @throws Throws an error if the request fails or encounters an issue. */ -export async function fetchPasswordPolicy(auth) { +export async function fetchPasswordPolicy( + auth: AuthWithAppOptions, +): Promise { try { - // Identity toolkit API endpoint for password policy. Ensure this is enabled on Google cloud. const baseURL = 'https://identitytoolkit.googleapis.com/v2/passwordPolicy?key='; const apiKey = auth.app.options.apiKey; @@ -35,10 +43,11 @@ export async function fetchPasswordPolicy(auth) { `firebase.auth().validatePassword(*) failed to fetch password policy from Firebase Console: ${response.statusText}. Details: ${errorDetails}`, ); } - return await response.json(); + return (await response.json()) as PasswordPolicyApiResponse; } catch (error) { + const message = error instanceof Error ? error.message : String(error); throw new Error( - `firebase.auth().validatePassword(*) Failed to fetch password policy: ${error.message}`, + `firebase.auth().validatePassword(*) Failed to fetch password policy: ${message}`, ); } } diff --git a/packages/auth/lib/providers/AppleAuthProvider.js b/packages/auth/lib/providers/AppleAuthProvider.ts similarity index 85% rename from packages/auth/lib/providers/AppleAuthProvider.js rename to packages/auth/lib/providers/AppleAuthProvider.ts index 172cc1d12e..ff933b878f 100644 --- a/packages/auth/lib/providers/AppleAuthProvider.js +++ b/packages/auth/lib/providers/AppleAuthProvider.ts @@ -15,6 +15,8 @@ * */ +import type { AuthCredential } from '../types/auth'; + const providerId = 'apple.com'; export default class AppleAuthProvider { @@ -22,11 +24,11 @@ export default class AppleAuthProvider { throw new Error('`new AppleAuthProvider()` is not supported on the native Firebase SDKs.'); } - static get PROVIDER_ID() { + static get PROVIDER_ID(): string { return providerId; } - static credential(token, secret) { + static credential(token: string, secret: string): AuthCredential { return { token, secret, diff --git a/packages/auth/lib/providers/EmailAuthProvider.js b/packages/auth/lib/providers/EmailAuthProvider.ts similarity index 77% rename from packages/auth/lib/providers/EmailAuthProvider.js rename to packages/auth/lib/providers/EmailAuthProvider.ts index b722a7d29b..fc58f3fa9a 100644 --- a/packages/auth/lib/providers/EmailAuthProvider.js +++ b/packages/auth/lib/providers/EmailAuthProvider.ts @@ -15,6 +15,8 @@ * */ +import type { AuthCredential } from '../types/auth'; + const linkProviderId = 'emailLink'; const passwordProviderId = 'password'; @@ -23,19 +25,19 @@ export default class EmailAuthProvider { throw new Error('`new EmailAuthProvider()` is not supported on the native Firebase SDKs.'); } - static get EMAIL_LINK_SIGN_IN_METHOD() { + static get EMAIL_LINK_SIGN_IN_METHOD(): string { return linkProviderId; } - static get EMAIL_PASSWORD_SIGN_IN_METHOD() { + static get EMAIL_PASSWORD_SIGN_IN_METHOD(): string { return passwordProviderId; } - static get PROVIDER_ID() { + static get PROVIDER_ID(): string { return passwordProviderId; } - static credential(email, password) { + static credential(email: string, password: string): AuthCredential { return { token: email, secret: password, @@ -43,7 +45,7 @@ export default class EmailAuthProvider { }; } - static credentialWithLink(email, emailLink) { + static credentialWithLink(email: string, emailLink: string): AuthCredential { return { token: email, secret: emailLink, diff --git a/packages/auth/lib/providers/FacebookAuthProvider.js b/packages/auth/lib/providers/FacebookAuthProvider.ts similarity index 85% rename from packages/auth/lib/providers/FacebookAuthProvider.js rename to packages/auth/lib/providers/FacebookAuthProvider.ts index 50ae4d9bd5..260a019acd 100644 --- a/packages/auth/lib/providers/FacebookAuthProvider.js +++ b/packages/auth/lib/providers/FacebookAuthProvider.ts @@ -15,6 +15,8 @@ * */ +import type { AuthCredential } from '../types/auth'; + const providerId = 'facebook.com'; export default class FacebookAuthProvider { @@ -22,11 +24,11 @@ export default class FacebookAuthProvider { throw new Error('`new FacebookAuthProvider()` is not supported on the native Firebase SDKs.'); } - static get PROVIDER_ID() { + static get PROVIDER_ID(): string { return providerId; } - static credential(token, secret = '') { + static credential(token: string, secret = ''): AuthCredential { return { token, secret, diff --git a/packages/auth/lib/providers/GithubAuthProvider.js b/packages/auth/lib/providers/GithubAuthProvider.ts similarity index 86% rename from packages/auth/lib/providers/GithubAuthProvider.js rename to packages/auth/lib/providers/GithubAuthProvider.ts index c0c9c6a253..e54bd9aed8 100644 --- a/packages/auth/lib/providers/GithubAuthProvider.js +++ b/packages/auth/lib/providers/GithubAuthProvider.ts @@ -15,6 +15,8 @@ * */ +import type { AuthCredential } from '../types/auth'; + const providerId = 'github.com'; export default class GithubAuthProvider { @@ -22,11 +24,11 @@ export default class GithubAuthProvider { throw new Error('`new GithubAuthProvider()` is not supported on the native Firebase SDKs.'); } - static get PROVIDER_ID() { + static get PROVIDER_ID(): string { return providerId; } - static credential(token) { + static credential(token: string): AuthCredential { return { token, secret: '', diff --git a/packages/auth/lib/providers/GoogleAuthProvider.js b/packages/auth/lib/providers/GoogleAuthProvider.ts similarity index 85% rename from packages/auth/lib/providers/GoogleAuthProvider.js rename to packages/auth/lib/providers/GoogleAuthProvider.ts index 03cb7b55f0..5816595007 100644 --- a/packages/auth/lib/providers/GoogleAuthProvider.js +++ b/packages/auth/lib/providers/GoogleAuthProvider.ts @@ -15,6 +15,8 @@ * */ +import type { AuthCredential } from '../types/auth'; + const providerId = 'google.com'; export default class GoogleAuthProvider { @@ -22,11 +24,11 @@ export default class GoogleAuthProvider { throw new Error('`new GoogleAuthProvider()` is not supported on the native Firebase SDKs.'); } - static get PROVIDER_ID() { + static get PROVIDER_ID(): string { return providerId; } - static credential(token, secret) { + static credential(token: string, secret: string): AuthCredential { return { token, secret, diff --git a/packages/auth/lib/providers/OAuthProvider.js b/packages/auth/lib/providers/OAuthProvider.ts similarity index 66% rename from packages/auth/lib/providers/OAuthProvider.js rename to packages/auth/lib/providers/OAuthProvider.ts index feab7e004f..ac77653c14 100644 --- a/packages/auth/lib/providers/OAuthProvider.js +++ b/packages/auth/lib/providers/OAuthProvider.ts @@ -15,19 +15,18 @@ * */ +import type { AuthCredential } from '../types/auth'; + export default class OAuthProvider { - /** @internal */ - #providerId = null; - /** @internal */ - #customParameters = {}; - /** @internal */ - #scopes = []; + #providerId: string | null = null; + #customParameters: Record = {}; + #scopes: string[] = []; - constructor(providerId) { + constructor(providerId: string) { this.#providerId = providerId; } - static credential(idToken, accessToken) { + static credential(idToken: string, accessToken: string): AuthCredential { return { token: idToken, secret: accessToken, @@ -35,32 +34,36 @@ export default class OAuthProvider { }; } - get PROVIDER_ID() { + get PROVIDER_ID(): string | null { return this.#providerId; } - setCustomParameters(customOAuthParameters) { + setCustomParameters(customOAuthParameters: Record): this { this.#customParameters = customOAuthParameters; return this; } - getCustomParameters() { + getCustomParameters(): Record { return this.#customParameters; } - addScope(scope) { + addScope(scope: string): this { if (!this.#scopes.includes(scope)) { this.#scopes.push(scope); } return this; } - getScopes() { + getScopes(): string[] { return [...this.#scopes]; } /** @internal */ - toObject() { + toObject(): { + providerId: string | null; + scopes: string[]; + customParameters: Record; + } { return { providerId: this.#providerId, scopes: this.#scopes, diff --git a/packages/auth/lib/providers/OIDCAuthProvider.js b/packages/auth/lib/providers/OIDCAuthProvider.ts similarity index 83% rename from packages/auth/lib/providers/OIDCAuthProvider.js rename to packages/auth/lib/providers/OIDCAuthProvider.ts index d262a29548..e3a50e6c9f 100644 --- a/packages/auth/lib/providers/OIDCAuthProvider.js +++ b/packages/auth/lib/providers/OIDCAuthProvider.ts @@ -15,6 +15,8 @@ * */ +import type { AuthCredential } from '../types/auth'; + const providerId = 'oidc.'; export default class OIDCAuthProvider { @@ -22,11 +24,11 @@ export default class OIDCAuthProvider { throw new Error('`new OIDCAuthProvider()` is not supported on the native Firebase SDKs.'); } - static get PROVIDER_ID() { + static get PROVIDER_ID(): string { return providerId; } - static credential(oidcSuffix, idToken, accessToken) { + static credential(oidcSuffix: string, idToken: string, accessToken: string): AuthCredential { return { token: idToken, secret: accessToken, diff --git a/packages/auth/lib/providers/PhoneAuthProvider.js b/packages/auth/lib/providers/PhoneAuthProvider.ts similarity index 62% rename from packages/auth/lib/providers/PhoneAuthProvider.js rename to packages/auth/lib/providers/PhoneAuthProvider.ts index 2fb238049c..6ea5793e0f 100644 --- a/packages/auth/lib/providers/PhoneAuthProvider.js +++ b/packages/auth/lib/providers/PhoneAuthProvider.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/no-unused-vars */ /* * Copyright (c) 2016-present Invertase Limited & Contributors * @@ -16,21 +15,32 @@ * */ +import type { AuthCredential } from '../types/auth'; +import type { AuthModuleWithApp } from '../types/internal'; + const providerId = 'phone'; +export interface PhoneInfoOptions { + phoneNumber?: string; + session?: string; + multiFactorHint?: { uid: string }; +} + export default class PhoneAuthProvider { - constructor(auth) { + _auth: AuthModuleWithApp; + + constructor(auth: AuthModuleWithApp) { if (auth === undefined) { throw new Error('`new PhoneAuthProvider()` is not supported on the native Firebase SDKs.'); } this._auth = auth; } - static get PROVIDER_ID() { + static get PROVIDER_ID(): string { return providerId; } - static credential(verificationId, code) { + static credential(verificationId: string, code: string): AuthCredential { return { token: verificationId, secret: code, @@ -38,15 +48,19 @@ export default class PhoneAuthProvider { }; } - verifyPhoneNumber(phoneInfoOptions, appVerifier) { + verifyPhoneNumber(phoneInfoOptions: PhoneInfoOptions, _appVerifier?: unknown): Promise { if (phoneInfoOptions.multiFactorHint) { return this._auth.app .auth() .verifyPhoneNumberWithMultiFactorInfo( phoneInfoOptions.multiFactorHint, - phoneInfoOptions.session, + phoneInfoOptions.session ?? '', ); } - return this._auth.app.auth().verifyPhoneNumberForMultiFactor(phoneInfoOptions); + return this._auth.app + .auth() + .verifyPhoneNumberForMultiFactor( + phoneInfoOptions as { phoneNumber: string; session: string }, + ); } } diff --git a/packages/auth/lib/providers/TwitterAuthProvider.js b/packages/auth/lib/providers/TwitterAuthProvider.ts similarity index 85% rename from packages/auth/lib/providers/TwitterAuthProvider.js rename to packages/auth/lib/providers/TwitterAuthProvider.ts index 62150cc2a7..470914458d 100644 --- a/packages/auth/lib/providers/TwitterAuthProvider.js +++ b/packages/auth/lib/providers/TwitterAuthProvider.ts @@ -15,6 +15,8 @@ * */ +import type { AuthCredential } from '../types/auth'; + const providerId = 'twitter.com'; export default class TwitterAuthProvider { @@ -22,11 +24,11 @@ export default class TwitterAuthProvider { throw new Error('`new TwitterAuthProvider()` is not supported on the native Firebase SDKs.'); } - static get PROVIDER_ID() { + static get PROVIDER_ID(): string { return providerId; } - static credential(token, secret) { + static credential(token: string, secret: string): AuthCredential { return { token, secret, diff --git a/packages/auth/lib/types/auth.ts b/packages/auth/lib/types/auth.ts new file mode 100644 index 0000000000..8d90b9d65f --- /dev/null +++ b/packages/auth/lib/types/auth.ts @@ -0,0 +1,206 @@ +/* + * 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 { FirebaseAuthTypes } from './namespaced'; + +/** + * Auth instance from {@link getAuth} / `firebase.auth()`. + * Uses the namespaced module shape so compatibility methods are typed (e.g. deprecation tests). + */ +export type FirebaseAuth = FirebaseAuthTypes.Module; + +/** + * Auth settings (modular API). + */ +export interface AuthSettings { + forceRecaptchaFlowForTesting: boolean; + appVerificationDisabledForTesting: boolean; + setAutoRetrievedSmsCodeForPhoneNumber(phoneNumber: string, smsCode: string): Promise; +} + +/** + * User profile and auth state (modular API). + */ +export interface User { + readonly uid: string; + readonly email: string | null; + readonly displayName: string | null; + readonly photoURL: string | null; + readonly emailVerified: boolean; + readonly isAnonymous: boolean; + readonly phoneNumber: string | null; + readonly providerId: string; + readonly tenantId: string | null; + readonly providerData: UserInfo[]; + readonly metadata: UserMetadata; + readonly multiFactor: MultiFactor | null; + delete(): Promise; + getIdToken(forceRefresh?: boolean): Promise; + getIdTokenResult(forceRefresh?: boolean): Promise; + reload(): Promise; + toJSON(): object; +} + +/** + * User info from a provider. + */ +export interface UserInfo { + uid: string; + displayName?: string; + email?: string; + phoneNumber?: string; + photoURL?: string; + providerId: string; +} + +/** + * User metadata. + */ +export interface UserMetadata { + creationTime?: string; + lastSignInTime?: string; +} + +/** + * Multi-factor on user. + */ +export interface MultiFactor { + enrolledFactors: MultiFactorInfo[]; +} + +/** + * Multi-factor info (minimal for modular). + */ +export interface MultiFactorInfo { + uid: string; + displayName?: string; + factorId: string; + enrollmentTime: string; +} + +/** + * ID token result. + */ +export interface IdTokenResult { + token: string; + authTime: string; + issuedAtTime: string; + expirationTime: string; + signInProvider: string | null; + claims: Record; +} + +/** + * Auth credential (modular API). + */ +export interface AuthCredential { + providerId: string; + token: string; + secret: string; +} + +/** + * Auth provider (modular API). + */ +export interface AuthProvider { + readonly PROVIDER_ID: string; + credential(token: string | null, secret?: string): AuthCredential; + /** Serializes provider for native (e.g. OAuthProvider). */ + toObject(): unknown; +} + +/** + * User credential (modular API). + */ +export interface UserCredential { + user: User; + additionalUserInfo?: AdditionalUserInfo; +} + +/** + * Additional user info. + */ +export interface AdditionalUserInfo { + isNewUser: boolean; + profile?: Record; + providerId: string; + username?: string; +} + +/** + * Action code settings. + */ +export interface ActionCodeSettings { + android?: { packageName: string; installApp?: boolean; minimumVersion?: string }; + ios?: { bundleId?: string }; + handleCodeInApp?: boolean; + url: string; + dynamicLinkDomain?: string; + linkDomain?: string; +} + +/** + * Action code info. + */ +export interface ActionCodeInfo { + data: { email?: string; fromEmail?: string }; + operation: 'PASSWORD_RESET' | 'VERIFY_EMAIL' | 'RECOVER_EMAIL' | 'EMAIL_SIGNIN' | 'ERROR'; +} + +/** + * Confirmation result for phone auth. + */ +export interface ConfirmationResult { + verificationId: string | null; + confirm(verificationCode: string): Promise; +} + +/** + * Multi-factor resolver. + */ +export interface MultiFactorResolver { + hints: MultiFactorInfo[]; + session: MultiFactorSession; + resolveSignIn(assertion: MultiFactorAssertion): Promise; +} + +/** + * Multi-factor session (opaque native handle; matches FirebaseAuthTypes.MultiFactorSession). + */ +export interface MultiFactorSession {} + +/** + * Multi-factor assertion. + */ +export interface MultiFactorAssertion { + token: string; + secret: string; +} + +/** + * Multi-factor error (for getMultiFactorResolver). + */ +export interface MultiFactorError { + readonly customData: Record & { + readonly operationType: string; + }; +} + +/** + * Callback or observer type. + */ +export type Unsubscribe = () => void; diff --git a/packages/auth/lib/types/internal.ts b/packages/auth/lib/types/internal.ts new file mode 100644 index 0000000000..a133dc8532 --- /dev/null +++ b/packages/auth/lib/types/internal.ts @@ -0,0 +1,289 @@ +/* + * 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 { ModuleConfig } from '@react-native-firebase/app/dist/module/types/internal'; +import type { + FirebaseAuth, + User, + UserCredential, + AuthCredential, + AuthProvider, + ActionCodeSettings, + ActionCodeInfo, + ConfirmationResult, + MultiFactorResolver, + MultiFactorError, +} from './auth'; +import type EventEmitter from 'react-native/Libraries/vendor/emitter/EventEmitter'; + +/** + * Phone auth listener (internal shape for modular). + */ +export interface PhoneAuthListenerInternal { + on( + event: string, + observer: (snapshot: unknown) => void, + errorCb?: (error: unknown) => void, + successCb?: (snapshot: unknown) => void, + ): PhoneAuthListenerInternal; + then( + onFulfilled?: ((a: unknown) => unknown) | null, + onRejected?: ((a: unknown) => unknown) | null, + ): Promise; + catch(onRejected: (a: unknown) => unknown): Promise; +} + +/** + * Internal Auth type with access to methods called by modular API. + */ +export type AuthInternal = FirebaseAuth & { + native: RNFBAuthModule; + emitter: EventEmitter; + eventNameForApp: (...args: Array) => string; + _config: ModuleConfig; + _setUser(user?: unknown): void; + _setUserCredential(userCredential: unknown): unknown; + applyActionCode(code: string, ...args: unknown[]): Promise; + checkActionCode(code: string, ...args: unknown[]): Promise; + confirmPasswordReset(code: string, newPassword: string, ...args: unknown[]): Promise; + connectAuthEmulator(url: string, options?: unknown): void; + createUserWithEmailAndPassword( + email: string, + password: string, + ...args: unknown[] + ): Promise; + fetchSignInMethodsForEmail(email: string, ...args: unknown[]): Promise; + getMultiFactorResolver(error: MultiFactorError, ...args: unknown[]): MultiFactorResolver | null; + isSignInWithEmailLink(emailLink: string, ...args: unknown[]): Promise; + onAuthStateChanged(nextOrObserver: unknown, ...args: unknown[]): () => void; + onIdTokenChanged(nextOrObserver: unknown, ...args: unknown[]): () => void; + sendPasswordResetEmail( + email: string, + actionCodeSettings?: ActionCodeSettings | null, + ...args: unknown[] + ): Promise; + sendSignInLinkToEmail( + email: string, + actionCodeSettings?: ActionCodeSettings, + ...args: unknown[] + ): Promise; + setLanguageCode(languageCode: string | null, ...args: unknown[]): Promise; + signInAnonymously(...args: unknown[]): Promise; + signInWithCredential(credential: AuthCredential, ...args: unknown[]): Promise; + signInWithCustomToken(customToken: string, ...args: unknown[]): Promise; + signInWithEmailAndPassword( + email: string, + password: string, + ...args: unknown[] + ): Promise; + signInWithEmailLink( + email: string, + emailLink: string, + ...args: unknown[] + ): Promise; + signInWithPhoneNumber( + phoneNumber: string, + forceResend?: boolean, + ...args: unknown[] + ): Promise; + signInWithPopup( + provider: AuthProvider, + resolver?: unknown, + ...args: unknown[] + ): Promise; + signInWithRedirect( + provider: AuthProvider, + resolver?: unknown, + ...args: unknown[] + ): Promise; + signOut(...args: unknown[]): Promise; + useEmulator(url: string, options?: unknown, ...args: unknown[]): void; + useUserAccessGroup(userAccessGroup: string, ...args: unknown[]): Promise; + getCustomAuthDomain(...args: unknown[]): Promise; + verifyPasswordResetCode(code: string, ...args: unknown[]): Promise; + resolveMultiFactorSignIn( + session: string, + verificationId: string, + verificationCode: string, + ): Promise; + resolveTotpSignIn(session: string, uid: string, totpSecret: string): Promise; + verifyPhoneNumber( + phoneNumber: string, + autoVerifyTimeoutOrForceResend?: number | boolean, + forceResend?: boolean, + ...args: unknown[] + ): PhoneAuthListenerInternal; + verifyPhoneNumberForMultiFactor(phoneInfoOptions: { + phoneNumber: string; + session: string; + }): Promise; + verifyPhoneNumberWithMultiFactorInfo( + multiFactorHint: { uid: string }, + session: string, + ): Promise; + validatePassword( + password: string, + ...args: unknown[] + ): Promise; +}; + +/** Auth module with app reference (e.g. for PhoneAuthProvider). */ +export type AuthModuleWithApp = { app: { auth(): AuthInternal } }; + +/** + * Internal User type (implementation detail). + */ +export type UserInternal = User; + +/** + * Wrapped native module interface for Auth. + */ +/** Native user object shape returned from native module. */ +export interface NativeUserShape { + displayName?: string | null; + email?: string | null; + emailVerified?: boolean; + isAnonymous?: boolean; + metadata?: { lastSignInTime: number | string; creationTime: number | string }; + multiFactor?: unknown; + phoneNumber?: string | null; + tenantId?: string | null; + photoURL?: string | null; + providerData?: unknown[]; + providerId?: string; + uid?: string; +} + +export interface RNFBAuthModule { + APP_LANGUAGE: Record; + APP_USER: Record; + addAuthStateListener(): void; + addIdTokenListener(): void; + applyActionCode(code: string): Promise; + checkActionCode(code: string): Promise; + configureAuthDomain(): void; + confirmationResultConfirm( + verificationCode: string, + ): Promise<{ user: unknown; additionalUserInfo?: unknown }>; + confirmPasswordReset(code: string, newPassword: string): Promise; + createUserWithEmailAndPassword( + email: string, + password: string, + ): Promise<{ user: unknown; additionalUserInfo?: unknown }>; + delete(): Promise; + fetchSignInMethodsForEmail(email: string): Promise; + finalizeMultiFactorEnrollment(token: string, secret: string, displayName?: string): Promise; + finalizeTotpEnrollment( + totpSecret: string, + verificationCode: string, + displayName?: string, + ): Promise; + generateTotpSecret(session: unknown): Promise<{ secretKey: string }>; + generateQrCodeUrl(secretKey: string, accountName: string, issuer: string): Promise; + openInOtpApp(secretKey: string, qrCodeUrl: string): Promise | unknown; + assertionForSignIn?(uid: string, verificationCode: string): unknown; + forceRecaptchaFlowForTesting(forceRecaptchaFlow: boolean): void; + getCustomAuthDomain(): Promise; + getIdToken(forceRefresh?: boolean): Promise; + getIdTokenResult(forceRefresh?: boolean): Promise; + getMultiFactorResolver?(error: unknown): unknown; + getSession(): Promise; + isSignInWithEmailLink(emailLink: string): Promise; + linkWithCredential( + providerId: string, + token: string, + secret: string, + ): Promise<{ user: unknown; additionalUserInfo?: unknown }>; + linkWithProvider(provider: unknown): Promise<{ user: unknown; additionalUserInfo?: unknown }>; + reload(): Promise; + reauthenticateWithCredential( + providerId: string, + token: string, + secret: string, + ): Promise<{ user: unknown; additionalUserInfo?: unknown }>; + reauthenticateWithProvider( + provider: unknown, + ): Promise<{ user: unknown; additionalUserInfo?: unknown }>; + resolveMultiFactorSignIn( + session: string, + verificationId: string, + verificationCode: string, + ): Promise<{ user: unknown; additionalUserInfo?: unknown }>; + resolveTotpSignIn( + session: string, + uid: string, + totpSecret: string, + ): Promise<{ user: unknown; additionalUserInfo?: unknown }>; + revokeToken(authorizationCode: string): Promise; + sendPasswordResetEmail( + email: string, + actionCodeSettings: ActionCodeSettings | null, + ): Promise; + sendSignInLinkToEmail(email: string, actionCodeSettings: Record): Promise; + sendEmailVerification(actionCodeSettings?: unknown): Promise; + setAppVerificationDisabledForTesting(disabled: boolean): void; + setAutoRetrievedSmsCodeForPhoneNumber(phoneNumber: string, smsCode: string): Promise; + setLanguageCode(code: string | null): Promise; + setTenantId(tenantId: string): Promise; + signInAnonymously(): Promise<{ user: unknown; additionalUserInfo?: unknown }>; + signInWithCredential( + providerId: string, + token: string, + secret: string, + ): Promise<{ user: unknown; additionalUserInfo?: unknown }>; + signInWithCustomToken( + customToken: string, + ): Promise<{ user: unknown; additionalUserInfo?: unknown }>; + signInWithEmailAndPassword( + email: string, + password: string, + ): Promise<{ user: unknown; additionalUserInfo?: unknown }>; + signInWithEmailLink( + email: string, + emailLink: string, + ): Promise<{ user: unknown; additionalUserInfo?: unknown }>; + signInWithPhoneNumber( + phoneNumber: string, + forceResend?: boolean, + ): Promise<{ verificationId: string }>; + signInWithProvider(provider: unknown): Promise<{ user: unknown; additionalUserInfo?: unknown }>; + signOut(): Promise; + unlink(providerId: string): Promise; + updateEmail(email: string): Promise; + updatePassword(password: string): Promise; + updatePhoneNumber(providerId: string, token: string, secret: string): Promise; + updateProfile(updates: unknown): Promise; + useEmulator(host: string, port: number): void; + useUserAccessGroup(userAccessGroup: string): Promise; + verifyBeforeUpdateEmail(newEmail: string, actionCodeSettings?: unknown): Promise; + verifyPasswordResetCode(code: string): Promise; + verifyPhoneNumber( + phoneNumber: string, + requestIdOrTimeout?: string | number, + timeoutOrForceResend?: number | boolean, + forceResend?: boolean, + ): Promise; + verifyPhoneNumberForMultiFactor(phoneNumber: string, session: string): Promise; + verifyPhoneNumberWithMultiFactorInfo(uid: string, session: string): Promise; + unenrollMultiFactor(enrollmentId: string): Promise; +} + +declare module '@react-native-firebase/app/dist/module/internal/NativeModules' { + interface ReactNativeFirebaseNativeModules { + RNFBAuthModule: RNFBAuthModule; + } +} diff --git a/packages/auth/lib/index.d.ts b/packages/auth/lib/types/namespaced.ts similarity index 97% rename from packages/auth/lib/index.d.ts rename to packages/auth/lib/types/namespaced.ts index dfd47fd9a9..09a75cc4c2 100644 --- a/packages/auth/lib/index.d.ts +++ b/packages/auth/lib/types/namespaced.ts @@ -15,42 +15,16 @@ * */ -import { ReactNativeFirebase } from '@react-native-firebase/app'; +import type { ReactNativeFirebase } from '@react-native-firebase/app'; /** - * Firebase Authentication package for React Native. - * - * #### Example: Access the firebase export from the `auth` package: - * - * ```js - * import { firebase } from '@react-native-firebase/auth'; - * - * // firebase.auth().X - * ``` - * - * #### Example: Using the default export from the `auth` package: - * - * ```js - * import auth from '@react-native-firebase/auth'; - * - * // auth().X - * ``` - * - * #### Example: Using the default export from the `app` package: - * - * ```js - * import firebase from '@react-native-firebase/app'; - * import '@react-native-firebase/auth'; - * - * // firebase.auth().X - * ``` - * TODO @salakar @ehesp missing auth providers (PhoneAuthProvider, Facebook etc) - * - * @firebase auth + * @deprecated Use the exported types directly instead. + * FirebaseAuthTypes namespace is kept for backwards compatibility. */ +/* eslint-disable @typescript-eslint/no-namespace */ export namespace FirebaseAuthTypes { - import FirebaseModule = ReactNativeFirebase.FirebaseModule; - import NativeFirebaseError = ReactNativeFirebase.NativeFirebaseError; + type FirebaseModule = ReactNativeFirebase.FirebaseModule; + type NativeFirebaseError = ReactNativeFirebase.NativeFirebaseError; export interface NativeFirebaseAuthError extends NativeFirebaseError { userInfo: { @@ -286,16 +260,12 @@ export namespace FirebaseAuthTypes { * 3- the return value of generateQrCodeUrl is a Promise because react-native bridge is async * @public */ - export declare class TotpSecret { - /** used internally to support non-default auth instances */ - private readonly auth; + export interface TotpSecret { /** * Shared secret key/seed used for enrolling in TOTP MFA and generating OTPs. */ readonly secretKey: string; - private constructor(); - /** * Returns a QR code URL as described in * https://github.com/google/google-authenticator/wiki/Key-Uri-Format @@ -306,7 +276,7 @@ export namespace FirebaseAuthTypes { * @param issuer issuer of the TOTP (likely the app name). * @returns A Promise that resolves to a QR code URL string. */ - async generateQrCodeUrl(accountName?: string, issuer?: string): Promise; + generateQrCodeUrl(accountName?: string, issuer?: string): Promise; /** * Opens the specified QR Code URL in an OTP authenticator app on the device. @@ -336,6 +306,22 @@ export namespace FirebaseAuthTypes { ): Promise; } + /** + * Auth error with custom data. Used as base for MultiFactorError. + */ + export interface AuthError extends NativeFirebaseError { + readonly customData: Record; + } + + /** + * Operation type for multi-factor flows. + */ + export declare const OperationType: { + readonly SIGN_IN: 'signIn'; + readonly LINK: 'link'; + readonly REAUTHENTICATE: 'reauthenticate'; + }; + export declare interface MultiFactorError extends AuthError { /** Details about the MultiFactorError. */ readonly customData: AuthError['customData'] & { @@ -470,6 +456,9 @@ export namespace FirebaseAuthTypes { SDK_VERSION: string; } + /** Auth instance type (alias for Module). */ + export type Auth = Module; + /** * A structure containing additional user information from a federated identity provider via {@link auth.UserCredential}. * @@ -557,7 +546,7 @@ export namespace FirebaseAuthTypes { export type MultiFactorInfo = PhoneMultiFactorInfo | TotpMultiFactorInfo; export interface PhoneMultiFactorInfo extends MultiFactorInfoCommon { - factorId: 'phone'; + factorId: string; /** * The phone number used for this factor. */ @@ -565,7 +554,7 @@ export namespace FirebaseAuthTypes { } export interface TotpMultiFactorInfo extends MultiFactorInfoCommon { - factorId: 'totp'; + factorId: string; } export interface MultiFactorInfoCommon { @@ -1003,6 +992,8 @@ export namespace FirebaseAuthTypes { */ export type AuthListenerCallback = (user: User | null) => void; + export type CallbackOrObserver any> = T | { next: T }; + /** * A snapshot interface of the current phone auth state. * @@ -1295,6 +1286,11 @@ export namespace FirebaseAuthTypes { */ uid: string; + /** + * The tenant ID for this user, or null if the user is not associated with a tenant. + */ + tenantId: string | null; + /** * Delete the current user. * @@ -1646,7 +1642,7 @@ export namespace FirebaseAuthTypes { * * TODO @salakar missing updateCurrentUser */ - export class Module extends FirebaseModule { + export interface Module extends FirebaseModule { /** * The current `FirebaseApp` instance for this Firebase service. */ @@ -2285,48 +2281,15 @@ export namespace FirebaseAuthTypes { * Returns the custom auth domain for the auth instance. */ getCustomAuthDomain(): Promise; - /** - * Sets the language code on the auth instance. This is to match Firebase JS SDK behavior. - * Please use the `setLanguageCode` method for setting the language code. - */ - set languageCode(code: string | null); /** * Gets the config used to initialize this auth instance. This is to match Firebase JS SDK behavior. * It returns an empty map as the config is not available in the native SDK. */ - get config(): Map; + readonly config: Map; } } - -export type CallbackOrObserver any> = T | { next: T }; - -type AuthNamespace = ReactNativeFirebase.FirebaseModuleWithStaticsAndApp< - FirebaseAuthTypes.Module, - FirebaseAuthTypes.Statics -> & { - auth: ReactNativeFirebase.FirebaseModuleWithStaticsAndApp< - FirebaseAuthTypes.Module, - FirebaseAuthTypes.Statics - >; - firebase: ReactNativeFirebase.Module; - app(name?: string): ReactNativeFirebase.FirebaseApp; -}; - -declare const defaultExport: AuthNamespace; - -export const firebase: ReactNativeFirebase.Module & { - auth: typeof defaultExport; - app(name?: string): ReactNativeFirebase.FirebaseApp & { auth(): FirebaseAuthTypes.Module }; -}; - -export default defaultExport; - -/** - * Attach namespace to `firebase.` and `FirebaseApp.`. - */ declare module '@react-native-firebase/app' { namespace ReactNativeFirebase { - import FirebaseModuleWithStaticsAndApp = ReactNativeFirebase.FirebaseModuleWithStaticsAndApp; interface Module { auth: FirebaseModuleWithStaticsAndApp; } @@ -2335,5 +2298,3 @@ declare module '@react-native-firebase/app' { } } } - -export * from './modular'; diff --git a/packages/auth/package.json b/packages/auth/package.json index 0e1e805ad7..e55bed51e8 100644 --- a/packages/auth/package.json +++ b/packages/auth/package.json @@ -3,14 +3,15 @@ "version": "23.8.8", "author": "Invertase (http://invertase.io)", "description": "React Native Firebase - The authentication module provides an easy-to-use API to integrate an authentication workflow into new and existing applications. React Native Firebase provides access to all Firebase authentication methods and identity providers.", - "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", "build:plugin": "rimraf plugin/build && tsc --build plugin", "lint:plugin": "eslint plugin/src/*", - "prepare": "yarn run build && yarn run build:plugin" + "compile": "bob build", + "prepare": "yarn run build && yarn run build:plugin && yarn compile" }, "repository": { "type": "git", @@ -32,7 +33,8 @@ }, "devDependencies": { "@types/plist": "^3.0.5", - "expo": "^55.0.5" + "expo": "^54.0.27", + "react-native-builder-bob": "^0.40.13" }, "peerDependenciesMeta": { "expo": { @@ -42,5 +44,35 @@ "publishConfig": { "access": "public", "provenance": true - } + }, + "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" + } + ] + ] + }, + "eslintIgnore": [ + "node_modules/", + "dist/" + ] } diff --git a/packages/auth/tsconfig.json b/packages/auth/tsconfig.json new file mode 100644 index 0000000000..16c83c5a22 --- /dev/null +++ b/packages/auth/tsconfig.json @@ -0,0 +1,38 @@ +{ + "extends": "../../tsconfig.packages.base.json", + "compilerOptions": { + "allowJs": true, + "checkJs": false, + "noImplicitAny": false, + "baseUrl": ".", + "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/web/*": [ + "../app/dist/typescript/lib/internal/web/*" + ], + "@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": [ + "../app/dist/typescript/lib" + ], + "@react-native-firebase/app/dist/module/types/internal": [ + "../app/dist/typescript/lib/types/internal" + ], + "@react-native-firebase/app/dist/module/types/common": [ + "../app/dist/typescript/lib/types/common" + ] + } + }, + "include": ["lib/**/*"], + "exclude": ["node_modules", "dist", "__tests__", "**/*.test.ts"] +} diff --git a/packages/auth/type-test.ts b/packages/auth/type-test.ts index ab298449fa..cd9601c532 100644 --- a/packages/auth/type-test.ts +++ b/packages/auth/type-test.ts @@ -26,6 +26,7 @@ import auth, { multiFactor, EmailAuthProvider, } from '.'; +import type { ConfirmationResult, User, UserCredential } from './lib/types/auth'; console.log(auth().app); @@ -180,55 +181,49 @@ console.log(authModular2.app.name); const authModular3 = initializeAuth(firebase.app()); console.log(authModular3.app.name); -onAuthStateChanged(authInstance, (user: FirebaseAuthTypes.User | null) => { +onAuthStateChanged(authInstance, (user: User | null) => { console.log(user?.email); }); -onIdTokenChanged(authInstance, (user: FirebaseAuthTypes.User | null) => { +onIdTokenChanged(authInstance, (user: User | null) => { console.log(user?.email); }); -signInAnonymously(authInstance).then((credential: FirebaseAuthTypes.UserCredential) => { +signInAnonymously(authInstance).then((credential: UserCredential) => { console.log(credential.user.uid); }); signInWithEmailAndPassword(authInstance, 'test@example.com', 'password123').then( - (credential: FirebaseAuthTypes.UserCredential) => { + (credential: UserCredential) => { console.log(credential.user.email); }, ); const emailCredential = EmailAuthProvider.credential('test@example.com', 'password'); -signInWithCredential(authInstance, emailCredential).then( - (credential: FirebaseAuthTypes.UserCredential) => { - console.log(credential.user.email); - }, -); +signInWithCredential(authInstance, emailCredential).then((credential: UserCredential) => { + console.log(credential.user.email); +}); -signInWithCustomToken(authInstance, 'custom-token').then( - (credential: FirebaseAuthTypes.UserCredential) => { - console.log(credential.user.uid); - }, -); +signInWithCustomToken(authInstance, 'custom-token').then((credential: UserCredential) => { + console.log(credential.user.uid); +}); signInWithEmailLink(authInstance, 'test@example.com', 'email-link').then( - (credential: FirebaseAuthTypes.UserCredential) => { + (credential: UserCredential) => { console.log(credential.user.email); }, ); -signInWithPhoneNumber(authInstance, '+1234567890').then( - (result: FirebaseAuthTypes.ConfirmationResult) => { - console.log(result.verificationId); - }, -); +signInWithPhoneNumber(authInstance, '+1234567890').then((result: ConfirmationResult) => { + console.log(result.verificationId); +}); signOut(authInstance).then(() => { console.log('Signed out'); }); createUserWithEmailAndPassword(authInstance, 'new@example.com', 'password123').then( - (credential: FirebaseAuthTypes.UserCredential) => { + (credential: UserCredential) => { console.log(credential.user.email); }, ); diff --git a/packages/vertexai/package.json b/packages/vertexai/package.json index 5c2893676c..62b81a3d42 100644 --- a/packages/vertexai/package.json +++ b/packages/vertexai/package.json @@ -38,6 +38,7 @@ "provenance": true }, "devDependencies": { + "@react-native-firebase/auth": "23.8.8", "@types/text-encoding": "^0.0.40", "react-native-builder-bob": "^0.40.17", "typescript": "^5.9.3" diff --git a/packages/vertexai/tsconfig.json b/packages/vertexai/tsconfig.json index 837c336e3e..f57afbea70 100644 --- a/packages/vertexai/tsconfig.json +++ b/packages/vertexai/tsconfig.json @@ -32,7 +32,7 @@ ], "@react-native-firebase/app/lib/internal": ["../app/dist/typescript/lib/internal"], "@react-native-firebase/app": ["../app/dist/typescript/lib"], - "@react-native-firebase/auth": ["../auth/lib"], + "@react-native-firebase/auth": ["../auth/dist/typescript/lib"], "@react-native-firebase/app-check": ["../app-check/dist/typescript/lib"] } }, diff --git a/tests/macos/Podfile b/tests/macos/Podfile index 2266ab6347..3753b0cb72 100644 --- a/tests/macos/Podfile +++ b/tests/macos/Podfile @@ -28,5 +28,23 @@ target 'io.invertase.testing-macOS' do post_install do |installer| react_native_post_install(installer) + # Xcode 26+ Apple Clang: fmt 11.0.2's FMT_STRING + consteval fails with + # "call to consteval function ... is not a constant expression" (fmt#4177 / #4247). + # Until RN bumps fmt, disable compile-time format checks for pods that compile {fmt}. + %w[fmt RCT-Folly].each do |pod_name| + installer.pods_project.targets.each do |target| + next unless target.name == pod_name + + target.build_configurations.each do |config| + defs = config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] + defs = [defs] if defs.is_a?(String) + defs = ['$(inherited)'] if defs.nil? || defs.empty? + defs = defs.flatten.compact + next if defs.any? { |d| d.to_s.include?('FMT_USE_CONSTEVAL') } + + config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] = defs + ['FMT_USE_CONSTEVAL=0'] + end + end + end end end diff --git a/tests/macos/Podfile.lock b/tests/macos/Podfile.lock index 720af4d88e..af2562d442 100644 --- a/tests/macos/Podfile.lock +++ b/tests/macos/Podfile.lock @@ -1696,66 +1696,66 @@ SPEC CHECKSUMS: FBLazyVector: 31dd89ddefc65148109e00de4270d3ac484bd8c1 fmt: f6af2d677a106e3e44c9536a4c0c7f03ab53c854 glog: b7594b792ee4e02ed1f44b01d046ca25fa713e3d - RCT-Folly: abec2d7f4af402b4957c44e86ceff8725b23c1b4 + RCT-Folly: e8b53d8c0d2d9df4a6a8b0a368a1a91fc62a88cb RCTDeprecation: 9da6c2d8a3b1802142718283260fb06d702ddb07 RCTRequired: 574f9d55bda1d50676530b6c36bab4605612dfb6 RCTTypeSafety: 7de929c405e619c023116e7747118a2c5d5b2320 React: ee782717a9c48bc876ab9d625324790a750775a9 React-callinvoker: 13537424f973520ee8d5b6a9d3c6f84443c6d1ff - React-Core: 3aa02c310c18b21155fc969fda0a927fda51ecb8 - React-CoreModules: 34edcc752f034ba37ba6c10140144c1059196580 - React-cxxreact: b694977e02a1a0df7ffd1d17607171bea951cbcb + React-Core: 4842999f1b7850b39a0f697b37cebaa118779ee4 + React-CoreModules: 5b3eab1c27e3dcc291e88feec03025a9d835ba88 + React-cxxreact: 376fccb624fb98289df7b1b0f60673b680897289 React-debug: 2bc559a0e9d4fcdb3ac425f94270cc6ed7df9e05 - React-defaultsnativemodule: dd27faec88633ff9bb04500d1cb01999383c4974 - React-domnativemodule: 30cf9005cc8e89ea167756f6248f041956f0d734 - React-Fabric: 73fa84e47795752906873867162cbd3b901107ca - React-FabricComponents: 75854095d372d8a1f34e3f995efc6888b4f4b8ba - React-FabricImage: c497fcbc083a14fb7c0cfbf401d00bf6297df5b8 + React-defaultsnativemodule: 756c26280e2074525293ba1f982284f4a22aab3a + React-domnativemodule: 404b6aa2a9041b25ececa481747d0e5091444aef + React-Fabric: 90e3eb8cf989ef901e7e0d77d45160f41adfdf70 + React-FabricComponents: c4d453eb4ed794ee6b42beb6626165fae746d7b0 + React-FabricImage: 46b7e109dbc93b503688124738c6a294a1544b83 React-featureflags: 430dcdb3434a1e0e82a86fd9e54cb60c00727c91 - React-featureflagsnativemodule: ad8c74e23811350846eaac6dfc066fe0f1f591ae - React-graphics: f627b3fd3edb18bb745269c7a3f196e65d43413b - React-idlecallbacksnativemodule: d696528ae1854f3beafb8c0374b72420e0720654 - React-ImageManager: f3aec32f5a763636b7413b7dcb5ec255b12fcf91 + React-featureflagsnativemodule: a2cd701246c85ab22cd866855e2d7f88b73388c7 + React-graphics: 3bcb94cd3ce72fac1e9512e10b7336d0ab539763 + React-idlecallbacksnativemodule: 39617353e600b0b6bcaecc3224a2888ac7f05e3c + React-ImageManager: 45c24f173763276f768de21a6402d97ffaa99a96 React-jsc: 110824a6d8488ea7d8a3b72cb35e528e462f9281 - React-jserrorhandler: 024b0f3663b22e184c2cb121bb31235a1e2c93d7 - React-jsi: 3b1e85de20432d5596e4aa6bbde352fe0bf331c5 - React-jsiexecutor: 1c7f7758e1b8ccbd4665504952b009d90242a225 - React-jsinspector: 05e7f743e02c296a912a4f0c0f57e586442dc4c8 - React-jsinspectortracing: 240cbca9e33331b849d6b20f0d8b0d984994dc6b - React-jsitracing: 60136e095299445d4322fe0e07ddfdf775d3250e - React-logger: 8e5c62114dc6a8ae688d6c655dac1bc988892e64 - React-Mapbuffer: f0ac9fd9d7d860258ca7972d1660a05a3550a344 - React-microtasksnativemodule: 964c92e955968e8d086fcfcc4d6d34a587af38eb - React-NativeModulesApple: 3021d910a10f52e5fd565cce8518d2f7ab8fa512 - React-perflogger: e13bcc7a9221c3709d3c8178d9e7f709be4f1350 - React-performancetimeline: 985dbe15d489dd2004d7de871ff464050e90efb4 + React-jserrorhandler: c558b7d139d1d27580faf5eb4ed7c7fb1bd17b2f + React-jsi: 5f1e7c7efefd0f24884c86065d1d49d0db70e568 + React-jsiexecutor: b876fe70f624aabb2b95ed588c29f8899a712518 + React-jsinspector: e82b641cceefe7d64b02ff102aa357bebc6c3fab + React-jsinspectortracing: c8531ea5125d017530aac9039936d6a1d0e6848f + React-jsitracing: d43e7b3d7a953e91c79490bbd74ef8abd2a9b3e7 + React-logger: 4decf7656034a9a718ba347ecc1c87c79a04b58b + React-Mapbuffer: 4ad71d8e010591048bfa792f1ad6178181b87b9f + React-microtasksnativemodule: 06c2ee7b0abc0680ce7c32d04b1e36f58e8271e1 + React-NativeModulesApple: 3a407fb81694679cb400fc2504b37354e9234272 + React-perflogger: 96cceccf29bf5507b3f48339f1d7282827a5274c + React-performancetimeline: f3f35f8a93f3788a0f920a09f0a99d58d14dcd06 React-RCTActionSheet: c5496a827b39f505ffc1d27a52400df58e7a7433 - React-RCTAnimation: 2a3fe9a75306411bb35bb076f1460fdc20100424 - React-RCTAppDelegate: 1f046d75ff2d15a7eeda999caef966b1a4ebdf0a - React-RCTBlob: a6104aa3d9bb5ba1dd4b3325441e05660dc80332 - React-RCTFabric: 996d9e8996d15af7d137a744d60adb832a72f74a - React-RCTFBReactNativeSpec: cf50271a4ea3cf07f362a91d913157a1f2216ca0 - React-RCTImage: a3d738fd2f91fde3ed01ecc02e7330ac08fddba3 - React-RCTLinking: 852bf1d4e09642bac25ae9914e1bf526e7a2f482 - React-RCTNetwork: 9258e83aa911199f6b42a95f3f6f1bdfb3d40c73 - React-RCTSettings: aed7da613ab1b362ac60c0ee9ce2cdbaa32c8924 - React-RCTText: 6328e0e445b8b83809cab4eab7662be8b276e585 - React-RCTVibration: 3eb6934cecfd666e03d0ab67984a07be2384396f + React-RCTAnimation: 85bd4ea6add91fcebc8d878f77b06e461b56ad71 + React-RCTAppDelegate: 789cec3d32ea5d2956b132f75ba957c0c9c360ad + React-RCTBlob: c61cc2b48deab1865596193f4215734860292dc7 + React-RCTFabric: d246c64f884b1e1b54ad1743a0159aa9c1eadf2f + React-RCTFBReactNativeSpec: d94c834bd99b35ec7b229c2be14539c2690a1d8c + React-RCTImage: 0be56a9f1eb4751f49ef45fc6ad27e71746d86fd + React-RCTLinking: 18d73b57aaeca804b842722362ed26ff4685ba49 + React-RCTNetwork: 0740e1a7716e67826e86277a363c14d8cd762733 + React-RCTSettings: 013a99ae1b136d66ab43a6af136f799de59be8a4 + React-RCTText: 64e02ee03d40e880fff0577945059ab13c197e48 + React-RCTVibration: ba41c5511e2631fc85868dc641711c85f7014c0d React-rendererconsistency: 7abe42d721328057bcbc198e30a683708a4fed3e - React-rendererdebug: 658c171e28d33b6589f098bdd47f6ad95d475eef + React-rendererdebug: 3a239d4dc5b17df934ed5d185a28deaafe409e82 React-rncore: a0f8d109f16242155e59631d96a128e3d55f1d54 - React-RuntimeApple: 6622b3f91601680bf17340b5efdbbc22a2031de6 - React-RuntimeCore: 86b83e750d4a1c457220d6862f820ab3a668e6e1 + React-RuntimeApple: 295b11341ca12f204bb8cae819e73678673396d2 + React-RuntimeCore: 76c8cba00208ce89bccc44e85fae08eeb988430d React-runtimeexecutor: 4b57851b6252cb71c8812a50e8055cb0086fc180 - React-runtimescheduler: d38dc6c06bc96a5cfe8202d576db24de53470321 + React-runtimescheduler: 6f7e00c01ddd78bae5bb8dae541b8697cf92fab8 React-timing: 756815d960e39ff0d09ff9c7cb7159299edf0169 - React-utils: 6a1d2e32976fdd017617b21a1a371f914a69afdb - ReactAppDependencyProvider: 3a460ab76f1149df99ed324bb1c764b76de7a730 - ReactCodegen: 4fdcda55518b6fbc14e919d871a2d38856dcd469 - ReactCommon: 3d985abe5510d5d3955a3a60b4dd9ad2dbe309dc - RNCAsyncStorage: 23e56519cc41d3bade3c8d4479f7760cb1c11996 + React-utils: e35ed3ed4e48a381fbb35e446c0e89cce5a0605f + ReactAppDependencyProvider: 78d1aa823d2f280f83372f9abb50502cee4d0424 + ReactCodegen: cfbf6d5eabb2335c65a821c9fd8e1883e87c1ef7 + ReactCommon: a7ae79eb3489b81532aa0352e3b9b496e35a9af7 + RNCAsyncStorage: b44e8a4e798c3e1f56bffccd0f591f674fb9198f SocketRocket: 03f7111df1a343b162bf5b06ead333be808e1e0a - Yoga: 8b70615ff4b017f445272a7caa9db908e6ae0ef8 + Yoga: 187db0b2a37012c01dac36afb886a29b92bfd943 PODFILE CHECKSUM: 787ee60864ef7264ea1a666923a1119b7db1a281 diff --git a/tsconfig-jest.json b/tsconfig-jest.json index 46819e73f5..76915c39a4 100644 --- a/tsconfig-jest.json +++ b/tsconfig-jest.json @@ -1,6 +1,8 @@ { "extends": "./tsconfig.json", "compilerOptions": { + "target": "ES2015", + "noImplicitAny": false, "baseUrl": ".", "paths": { "@react-native-firebase/app": ["packages/app/lib"], diff --git a/tsconfig.json b/tsconfig.json index 7c46a89317..4c6dc9fd27 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,5 +1,6 @@ { "include": [ + "packages/app/lib/shims/react-native-binaryToBase64.d.ts", "packages/ai/lib/types/polyfills.d.ts", "packages/app-check/lib/index.d.ts", "packages/app-check/lib/modular/index.d.ts", @@ -7,8 +8,7 @@ "packages/app-distribution/lib/modular/index.d.ts", "packages/app/lib/internal/global.d.ts", "packages/app/lib/internal/web/memidb/index.d.ts", - "packages/auth/lib/index.d.ts", - "packages/auth/lib/modular/index.d.ts", + "packages/auth/lib/index.ts", "packages/crashlytics/lib/index.d.ts", "packages/crashlytics/lib/modular/index.d.ts", "packages/database/lib/index.d.ts", @@ -55,7 +55,7 @@ ], "compilerOptions": { "noEmit": true, - "target": "es5", + "target": "es2015", "module": "commonjs", "declaration": true, "importHelpers": true, @@ -76,8 +76,28 @@ "lib": ["es2015", "es2016", "esnext", "dom"], "types": ["react-native", "node"], "paths": { - "@react-native-firebase/firestore/pipelines": ["./packages/firestore/dist/typescript/lib/pipelines/index.d.ts"], - "@react-native-firebase/*": ["./packages/*/lib/index.d.ts"] + "@react-native-firebase/app/dist/module/common/*": [ + "./packages/app/lib/common/*" + ], + "@react-native-firebase/app/dist/module/common": [ + "./packages/app/lib/common/index.ts" + ], + "@react-native-firebase/app/dist/module/internal/web/*": [ + "./packages/app/lib/internal/web/*" + ], + "@react-native-firebase/app/dist/module/internal/*": [ + "./packages/app/lib/internal/*" + ], + "@react-native-firebase/app/dist/module/internal": [ + "./packages/app/lib/internal/index.ts" + ], + "@react-native-firebase/app/dist/module/types/internal": [ + "./packages/app/lib/types/internal.ts" + ], + "@react-native-firebase/firestore/pipelines": [ + "./packages/firestore/dist/typescript/lib/pipelines/index.d.ts" + ], + "@react-native-firebase/*": ["./packages/*/lib/index.ts", "./packages/*/lib/index.d.ts"] } }, "exclude": ["node_modules", "**/*.spec.ts", "packages/**/dist"] diff --git a/tsconfig.packages.base.json b/tsconfig.packages.base.json index 75813b1665..649b6eac88 100644 --- a/tsconfig.packages.base.json +++ b/tsconfig.packages.base.json @@ -1,4 +1,5 @@ { + "files": ["./packages/app/lib/shims/react-native-binaryToBase64.d.ts"], "compilerOptions": { "allowUnreachableCode": false, "allowUnusedLabels": false, diff --git a/yarn.lock b/yarn.lock index 9193338cf5..5852abd0a6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5,6 +5,18 @@ __metadata: version: 8 cacheKey: 10 +"@0no-co/graphql.web@npm:^1.0.13, @0no-co/graphql.web@npm:^1.0.8": + version: 1.2.0 + resolution: "@0no-co/graphql.web@npm:1.2.0" + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 + peerDependenciesMeta: + graphql: + optional: true + checksum: 10/bb53b2e013686df0c8ca518430e9371bd14bd26910c1ab5b7bebd76cea1867ba6160d7e01924a04af846e90d99cb8f101f35960f89a76a8a91ce1d70f74d321d + languageName: node + linkType: hard + "@apidevtools/json-schema-ref-parser@npm:^9.0.3": version: 9.1.2 resolution: "@apidevtools/json-schema-ref-parser@npm:9.1.2" @@ -85,6 +97,15 @@ __metadata: languageName: node linkType: hard +"@babel/code-frame@npm:~7.10.4": + version: 7.10.4 + resolution: "@babel/code-frame@npm:7.10.4" + dependencies: + "@babel/highlight": "npm:^7.10.4" + checksum: 10/4ef9c679515be9cb8eab519fcded953f86226155a599cf7ea209e40e088bb9a51bb5893d3307eae510b07bb3e359d64f2620957a00c27825dbe26ac62aca81f5 + languageName: node + linkType: hard + "@babel/compat-data@npm:^7.27.2, @babel/compat-data@npm:^7.27.7, @babel/compat-data@npm:^7.28.5": version: 7.28.5 resolution: "@babel/compat-data@npm:7.28.5" @@ -410,7 +431,7 @@ __metadata: languageName: node linkType: hard -"@babel/helper-validator-identifier@npm:^7.27.1, @babel/helper-validator-identifier@npm:^7.28.5": +"@babel/helper-validator-identifier@npm:^7.25.9, @babel/helper-validator-identifier@npm:^7.27.1, @babel/helper-validator-identifier@npm:^7.28.5": version: 7.28.5 resolution: "@babel/helper-validator-identifier@npm:7.28.5" checksum: 10/8e5d9b0133702cfacc7f368bf792f0f8ac0483794877c6dca5fcb73810ee138e27527701826fb58a40a004f3a5ec0a2f3c3dd5e326d262530b119918f3132ba7 @@ -455,6 +476,18 @@ __metadata: languageName: node linkType: hard +"@babel/highlight@npm:^7.10.4": + version: 7.25.9 + resolution: "@babel/highlight@npm:7.25.9" + dependencies: + "@babel/helper-validator-identifier": "npm:^7.25.9" + chalk: "npm:^2.4.2" + js-tokens: "npm:^4.0.0" + picocolors: "npm:^1.0.0" + checksum: 10/0d165283dd4eb312292cea8fec3ae0d376874b1885f476014f0136784ed5b564b2c2ba2d270587ed546ee92505056dab56493f7960c01c4e6394d71d1b2e7db6 + languageName: node + linkType: hard + "@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.23.9, @babel/parser@npm:^7.24.7, @babel/parser@npm:^7.25.3, @babel/parser@npm:^7.27.2, @babel/parser@npm:^7.28.5": version: 7.28.5 resolution: "@babel/parser@npm:7.28.5" @@ -2426,6 +2459,88 @@ __metadata: languageName: node linkType: hard +"@expo/cli@npm:54.0.23": + version: 54.0.23 + resolution: "@expo/cli@npm:54.0.23" + dependencies: + "@0no-co/graphql.web": "npm:^1.0.8" + "@expo/code-signing-certificates": "npm:^0.0.6" + "@expo/config": "npm:~12.0.13" + "@expo/config-plugins": "npm:~54.0.4" + "@expo/devcert": "npm:^1.2.1" + "@expo/env": "npm:~2.0.8" + "@expo/image-utils": "npm:^0.8.8" + "@expo/json-file": "npm:^10.0.8" + "@expo/metro": "npm:~54.2.0" + "@expo/metro-config": "npm:~54.0.14" + "@expo/osascript": "npm:^2.3.8" + "@expo/package-manager": "npm:^1.9.10" + "@expo/plist": "npm:^0.4.8" + "@expo/prebuild-config": "npm:^54.0.8" + "@expo/schema-utils": "npm:^0.1.8" + "@expo/spawn-async": "npm:^1.7.2" + "@expo/ws-tunnel": "npm:^1.0.1" + "@expo/xcpretty": "npm:^4.3.0" + "@react-native/dev-middleware": "npm:0.81.5" + "@urql/core": "npm:^5.0.6" + "@urql/exchange-retry": "npm:^1.3.0" + accepts: "npm:^1.3.8" + arg: "npm:^5.0.2" + better-opn: "npm:~3.0.2" + bplist-creator: "npm:0.1.0" + bplist-parser: "npm:^0.3.1" + chalk: "npm:^4.0.0" + ci-info: "npm:^3.3.0" + compression: "npm:^1.7.4" + connect: "npm:^3.7.0" + debug: "npm:^4.3.4" + env-editor: "npm:^0.4.1" + expo-server: "npm:^1.0.5" + freeport-async: "npm:^2.0.0" + getenv: "npm:^2.0.0" + glob: "npm:^13.0.0" + lan-network: "npm:^0.1.6" + minimatch: "npm:^9.0.0" + node-forge: "npm:^1.3.3" + npm-package-arg: "npm:^11.0.0" + ora: "npm:^3.4.0" + picomatch: "npm:^3.0.1" + pretty-bytes: "npm:^5.6.0" + pretty-format: "npm:^29.7.0" + progress: "npm:^2.0.3" + prompts: "npm:^2.3.2" + qrcode-terminal: "npm:0.11.0" + require-from-string: "npm:^2.0.2" + requireg: "npm:^0.2.2" + resolve: "npm:^1.22.2" + resolve-from: "npm:^5.0.0" + resolve.exports: "npm:^2.0.3" + semver: "npm:^7.6.0" + send: "npm:^0.19.0" + slugify: "npm:^1.3.4" + source-map-support: "npm:~0.5.21" + stacktrace-parser: "npm:^0.1.10" + structured-headers: "npm:^0.4.1" + tar: "npm:^7.5.2" + terminal-link: "npm:^2.1.1" + undici: "npm:^6.18.2" + wrap-ansi: "npm:^7.0.0" + ws: "npm:^8.12.1" + peerDependencies: + expo: "*" + expo-router: "*" + react-native: "*" + peerDependenciesMeta: + expo-router: + optional: true + react-native: + optional: true + bin: + expo-internal: build/bin/cli + checksum: 10/9a41c55aa7f628ad44048c9f41cd8d7f4f73a8bfc01adaa956ddaae87d332ae979eadb52bdab894ef5b1c9b5722486ccdb999057d8b9eed392c827f476feb79f + languageName: node + linkType: hard + "@expo/cli@npm:55.0.15": version: 55.0.15 resolution: "@expo/cli@npm:55.0.15" @@ -2511,6 +2626,28 @@ __metadata: languageName: node linkType: hard +"@expo/config-plugins@npm:~54.0.4": + version: 54.0.4 + resolution: "@expo/config-plugins@npm:54.0.4" + dependencies: + "@expo/config-types": "npm:^54.0.10" + "@expo/json-file": "npm:~10.0.8" + "@expo/plist": "npm:^0.4.8" + "@expo/sdk-runtime-versions": "npm:^1.0.0" + chalk: "npm:^4.1.2" + debug: "npm:^4.3.5" + getenv: "npm:^2.0.0" + glob: "npm:^13.0.0" + resolve-from: "npm:^5.0.0" + semver: "npm:^7.5.4" + slash: "npm:^3.0.0" + slugify: "npm:^1.6.6" + xcode: "npm:^3.0.1" + xml2js: "npm:0.6.0" + checksum: 10/55dab3f5f29b6dfb58bc32a9b0a681766f6b260ee94b1c295f67ac3c5e8f372afc512bb416f2e50901e387d4012e3a4a8fd3b461e5aa8c20e16fdcde64a07327 + languageName: node + linkType: hard + "@expo/config-plugins@npm:~55.0.6": version: 55.0.6 resolution: "@expo/config-plugins@npm:55.0.6" @@ -2532,6 +2669,13 @@ __metadata: languageName: node linkType: hard +"@expo/config-types@npm:^54.0.10": + version: 54.0.10 + resolution: "@expo/config-types@npm:54.0.10" + checksum: 10/7e4d598d2d1905dc53f2b30d5a1e0817dd486b13c89a24575deb4e25ec441b0de009d156f041a3c9a1f2121dfba28f2a24fd4fb5a056cac90502ca67c639bb8a + languageName: node + linkType: hard + "@expo/config-types@npm:^55.0.5": version: 55.0.5 resolution: "@expo/config-types@npm:55.0.5" @@ -2539,6 +2683,27 @@ __metadata: languageName: node linkType: hard +"@expo/config@npm:~12.0.13": + version: 12.0.13 + resolution: "@expo/config@npm:12.0.13" + dependencies: + "@babel/code-frame": "npm:~7.10.4" + "@expo/config-plugins": "npm:~54.0.4" + "@expo/config-types": "npm:^54.0.10" + "@expo/json-file": "npm:^10.0.8" + deepmerge: "npm:^4.3.1" + getenv: "npm:^2.0.0" + glob: "npm:^13.0.0" + require-from-string: "npm:^2.0.2" + resolve-from: "npm:^5.0.0" + resolve-workspace-root: "npm:^2.0.0" + semver: "npm:^7.6.0" + slugify: "npm:^1.3.4" + sucrase: "npm:~3.35.1" + checksum: 10/2caac758fb706a75fc6d07df31c24c22d633f522091148e615d9c28475ae35cfaed29458cfd08f13d40d71d33715e5ac618af78591c11886529157b8519fe4ea + languageName: node + linkType: hard + "@expo/config@npm:~55.0.8": version: 55.0.8 resolution: "@expo/config@npm:55.0.8" @@ -2568,6 +2733,23 @@ __metadata: languageName: node linkType: hard +"@expo/devtools@npm:0.1.8": + version: 0.1.8 + resolution: "@expo/devtools@npm:0.1.8" + dependencies: + chalk: "npm:^4.1.2" + peerDependencies: + react: "*" + react-native: "*" + peerDependenciesMeta: + react: + optional: true + react-native: + optional: true + checksum: 10/ecbf927c91b45697c53a528f77ddcc63b6bad4efc29af18f9d6f7aa0d1e6e47c8b2a061dfa29b3ebb470ce3b4c95e40dbcf51066b0ff1db17c7d1be88fe162f1 + languageName: node + linkType: hard + "@expo/devtools@npm:55.0.2": version: 55.0.2 resolution: "@expo/devtools@npm:55.0.2" @@ -2607,6 +2789,40 @@ __metadata: languageName: node linkType: hard +"@expo/env@npm:~2.0.8": + version: 2.0.11 + resolution: "@expo/env@npm:2.0.11" + dependencies: + chalk: "npm:^4.0.0" + debug: "npm:^4.3.4" + dotenv: "npm:~16.4.5" + dotenv-expand: "npm:~11.0.6" + getenv: "npm:^2.0.0" + checksum: 10/bfb307d6b35d47c58f82424c85543325370bbdc0f303cdd4ddfe5d6854e0386ad72166fec6e1da633fc7cb3b0915d7c40642c49773ae31e6faed13569d1b601c + languageName: node + linkType: hard + +"@expo/fingerprint@npm:0.15.4": + version: 0.15.4 + resolution: "@expo/fingerprint@npm:0.15.4" + dependencies: + "@expo/spawn-async": "npm:^1.7.2" + arg: "npm:^5.0.2" + chalk: "npm:^4.1.2" + debug: "npm:^4.3.4" + getenv: "npm:^2.0.0" + glob: "npm:^13.0.0" + ignore: "npm:^5.3.1" + minimatch: "npm:^9.0.0" + p-limit: "npm:^3.1.0" + resolve-from: "npm:^5.0.0" + semver: "npm:^7.6.0" + bin: + fingerprint: bin/cli.js + checksum: 10/854c5b8c298d145d58d47d45081f14fd1fc3c4880e6706257c4863ea4e56a368d055d1043538c74e35f5b23971c945bcd3e62750ffe23d2210f73d3712447b5a + languageName: node + linkType: hard + "@expo/fingerprint@npm:0.16.5": version: 0.16.5 resolution: "@expo/fingerprint@npm:0.16.5" @@ -2628,7 +2844,7 @@ __metadata: languageName: node linkType: hard -"@expo/image-utils@npm:^0.8.12": +"@expo/image-utils@npm:^0.8.12, @expo/image-utils@npm:^0.8.8": version: 0.8.12 resolution: "@expo/image-utils@npm:0.8.12" dependencies: @@ -2643,7 +2859,7 @@ __metadata: languageName: node linkType: hard -"@expo/json-file@npm:^10.0.12, @expo/json-file@npm:~10.0.12": +"@expo/json-file@npm:^10.0.12, @expo/json-file@npm:^10.0.8, @expo/json-file@npm:~10.0.12, @expo/json-file@npm:~10.0.8": version: 10.0.12 resolution: "@expo/json-file@npm:10.0.12" dependencies: @@ -2679,6 +2895,40 @@ __metadata: languageName: node linkType: hard +"@expo/metro-config@npm:54.0.14, @expo/metro-config@npm:~54.0.14": + version: 54.0.14 + resolution: "@expo/metro-config@npm:54.0.14" + dependencies: + "@babel/code-frame": "npm:^7.20.0" + "@babel/core": "npm:^7.20.0" + "@babel/generator": "npm:^7.20.5" + "@expo/config": "npm:~12.0.13" + "@expo/env": "npm:~2.0.8" + "@expo/json-file": "npm:~10.0.8" + "@expo/metro": "npm:~54.2.0" + "@expo/spawn-async": "npm:^1.7.2" + browserslist: "npm:^4.25.0" + chalk: "npm:^4.1.0" + debug: "npm:^4.3.2" + dotenv: "npm:~16.4.5" + dotenv-expand: "npm:~11.0.6" + getenv: "npm:^2.0.0" + glob: "npm:^13.0.0" + hermes-parser: "npm:^0.29.1" + jsc-safe-url: "npm:^0.2.4" + lightningcss: "npm:^1.30.1" + minimatch: "npm:^9.0.0" + postcss: "npm:~8.4.32" + resolve-from: "npm:^5.0.0" + peerDependencies: + expo: "*" + peerDependenciesMeta: + expo: + optional: true + checksum: 10/c1a67c187fcd9f3dd43cd1b33a500644715768ab55939d5e2ff354311709ea5fed2bb3c103610b0ddac961d7ab2f94f7a1d1f25d033af98690ed6b9cec9ac787 + languageName: node + linkType: hard + "@expo/metro-config@npm:55.0.9, @expo/metro-config@npm:~55.0.9": version: 55.0.9 resolution: "@expo/metro-config@npm:55.0.9" @@ -2733,7 +2983,7 @@ __metadata: languageName: node linkType: hard -"@expo/osascript@npm:^2.4.2": +"@expo/osascript@npm:^2.3.8, @expo/osascript@npm:^2.4.2": version: 2.4.2 resolution: "@expo/osascript@npm:2.4.2" dependencies: @@ -2742,7 +2992,7 @@ __metadata: languageName: node linkType: hard -"@expo/package-manager@npm:^1.10.3": +"@expo/package-manager@npm:^1.10.3, @expo/package-manager@npm:^1.9.10": version: 1.10.3 resolution: "@expo/package-manager@npm:1.10.3" dependencies: @@ -2756,6 +3006,17 @@ __metadata: languageName: node linkType: hard +"@expo/plist@npm:^0.4.8": + version: 0.4.8 + resolution: "@expo/plist@npm:0.4.8" + dependencies: + "@xmldom/xmldom": "npm:^0.8.8" + base64-js: "npm:^1.2.3" + xmlbuilder: "npm:^15.1.1" + checksum: 10/48ba4ad5cc3668e8c26c5197bf7915a29745d0ae1cba1c38aad0d797ee1835ac74fb577a9e810594063e5984d9e52b367f4069d0ef1d906ba3013fce1c01a19c + languageName: node + linkType: hard + "@expo/plist@npm:^0.5.2": version: 0.5.2 resolution: "@expo/plist@npm:0.5.2" @@ -2767,6 +3028,26 @@ __metadata: languageName: node linkType: hard +"@expo/prebuild-config@npm:^54.0.8": + version: 54.0.8 + resolution: "@expo/prebuild-config@npm:54.0.8" + dependencies: + "@expo/config": "npm:~12.0.13" + "@expo/config-plugins": "npm:~54.0.4" + "@expo/config-types": "npm:^54.0.10" + "@expo/image-utils": "npm:^0.8.8" + "@expo/json-file": "npm:^10.0.8" + "@react-native/normalize-colors": "npm:0.81.5" + debug: "npm:^4.3.1" + resolve-from: "npm:^5.0.0" + semver: "npm:^7.6.0" + xml2js: "npm:0.6.0" + peerDependencies: + expo: "*" + checksum: 10/67f0fd1ad9332ff10c554e4b31602656daf222f2c51cebde9c024cb47b7ea13653ee1b01a00b6ea7cdf8fe8c99e20955788de9dec578c394e6b2357ef5919ab9 + languageName: node + linkType: hard + "@expo/prebuild-config@npm:^55.0.8": version: 55.0.8 resolution: "@expo/prebuild-config@npm:55.0.8" @@ -2831,6 +3112,13 @@ __metadata: languageName: node linkType: hard +"@expo/schema-utils@npm:^0.1.8": + version: 0.1.8 + resolution: "@expo/schema-utils@npm:0.1.8" + checksum: 10/72c02dcd107da08bd0df829b57edca77e48d9e3386304510a043c8d19892d20ec230ccdb27f5b2e08b3576046b3bfe66afdaf1e071c6a0296fa3817dbaa49932 + languageName: node + linkType: hard + "@expo/schema-utils@npm:^55.0.2": version: 55.0.2 resolution: "@expo/schema-utils@npm:55.0.2" @@ -2861,7 +3149,7 @@ __metadata: languageName: node linkType: hard -"@expo/vector-icons@npm:^15.0.2": +"@expo/vector-icons@npm:^15.0.2, @expo/vector-icons@npm:^15.0.3": version: 15.1.1 resolution: "@expo/vector-icons@npm:15.1.1" peerDependencies: @@ -2879,7 +3167,7 @@ __metadata: languageName: node linkType: hard -"@expo/xcpretty@npm:^4.4.0": +"@expo/xcpretty@npm:^4.3.0, @expo/xcpretty@npm:^4.4.0": version: 4.4.1 resolution: "@expo/xcpretty@npm:4.4.1" dependencies: @@ -4731,7 +5019,7 @@ __metadata: languageName: node linkType: hard -"@jridgewell/gen-mapping@npm:^0.3.12, @jridgewell/gen-mapping@npm:^0.3.5": +"@jridgewell/gen-mapping@npm:^0.3.12, @jridgewell/gen-mapping@npm:^0.3.2, @jridgewell/gen-mapping@npm:^0.3.5": version: 0.3.13 resolution: "@jridgewell/gen-mapping@npm:0.3.13" dependencies: @@ -6179,8 +6467,9 @@ __metadata: resolution: "@react-native-firebase/auth@workspace:packages/auth" dependencies: "@types/plist": "npm:^3.0.5" - expo: "npm:^55.0.5" + expo: "npm:^54.0.27" plist: "npm:^3.1.0" + react-native-builder-bob: "npm:^0.40.13" peerDependencies: "@react-native-firebase/app": 23.8.8 expo: ">=47.0.0" @@ -6328,6 +6617,7 @@ __metadata: resolution: "@react-native-firebase/vertexai@workspace:packages/vertexai" dependencies: "@react-native-firebase/ai": "npm:23.8.8" + "@react-native-firebase/auth": "npm:23.8.8" "@types/text-encoding": "npm:^0.0.40" react-native-builder-bob: "npm:^0.40.17" react-native-fetch-api: "npm:^3.0.0" @@ -6387,6 +6677,16 @@ __metadata: languageName: node linkType: hard +"@react-native/babel-plugin-codegen@npm:0.81.5": + version: 0.81.5 + resolution: "@react-native/babel-plugin-codegen@npm:0.81.5" + dependencies: + "@babel/traverse": "npm:^7.25.3" + "@react-native/codegen": "npm:0.81.5" + checksum: 10/e8a4bb4c0d6f79e1162aeadb45e0495cb7515f75adda35de77c2b21be345b0e0e45ff7c4710a0ea285b9a42a8354ac66995f7bb5e7fbb144dbff3c67e1b6c9c7 + languageName: node + linkType: hard + "@react-native/babel-plugin-codegen@npm:0.83.2": version: 0.83.2 resolution: "@react-native/babel-plugin-codegen@npm:0.83.2" @@ -6452,6 +6752,61 @@ __metadata: languageName: node linkType: hard +"@react-native/babel-preset@npm:0.81.5": + version: 0.81.5 + resolution: "@react-native/babel-preset@npm:0.81.5" + dependencies: + "@babel/core": "npm:^7.25.2" + "@babel/plugin-proposal-export-default-from": "npm:^7.24.7" + "@babel/plugin-syntax-dynamic-import": "npm:^7.8.3" + "@babel/plugin-syntax-export-default-from": "npm:^7.24.7" + "@babel/plugin-syntax-nullish-coalescing-operator": "npm:^7.8.3" + "@babel/plugin-syntax-optional-chaining": "npm:^7.8.3" + "@babel/plugin-transform-arrow-functions": "npm:^7.24.7" + "@babel/plugin-transform-async-generator-functions": "npm:^7.25.4" + "@babel/plugin-transform-async-to-generator": "npm:^7.24.7" + "@babel/plugin-transform-block-scoping": "npm:^7.25.0" + "@babel/plugin-transform-class-properties": "npm:^7.25.4" + "@babel/plugin-transform-classes": "npm:^7.25.4" + "@babel/plugin-transform-computed-properties": "npm:^7.24.7" + "@babel/plugin-transform-destructuring": "npm:^7.24.8" + "@babel/plugin-transform-flow-strip-types": "npm:^7.25.2" + "@babel/plugin-transform-for-of": "npm:^7.24.7" + "@babel/plugin-transform-function-name": "npm:^7.25.1" + "@babel/plugin-transform-literals": "npm:^7.25.2" + "@babel/plugin-transform-logical-assignment-operators": "npm:^7.24.7" + "@babel/plugin-transform-modules-commonjs": "npm:^7.24.8" + "@babel/plugin-transform-named-capturing-groups-regex": "npm:^7.24.7" + "@babel/plugin-transform-nullish-coalescing-operator": "npm:^7.24.7" + "@babel/plugin-transform-numeric-separator": "npm:^7.24.7" + "@babel/plugin-transform-object-rest-spread": "npm:^7.24.7" + "@babel/plugin-transform-optional-catch-binding": "npm:^7.24.7" + "@babel/plugin-transform-optional-chaining": "npm:^7.24.8" + "@babel/plugin-transform-parameters": "npm:^7.24.7" + "@babel/plugin-transform-private-methods": "npm:^7.24.7" + "@babel/plugin-transform-private-property-in-object": "npm:^7.24.7" + "@babel/plugin-transform-react-display-name": "npm:^7.24.7" + "@babel/plugin-transform-react-jsx": "npm:^7.25.2" + "@babel/plugin-transform-react-jsx-self": "npm:^7.24.7" + "@babel/plugin-transform-react-jsx-source": "npm:^7.24.7" + "@babel/plugin-transform-regenerator": "npm:^7.24.7" + "@babel/plugin-transform-runtime": "npm:^7.24.7" + "@babel/plugin-transform-shorthand-properties": "npm:^7.24.7" + "@babel/plugin-transform-spread": "npm:^7.24.7" + "@babel/plugin-transform-sticky-regex": "npm:^7.24.7" + "@babel/plugin-transform-typescript": "npm:^7.25.2" + "@babel/plugin-transform-unicode-regex": "npm:^7.24.7" + "@babel/template": "npm:^7.25.0" + "@react-native/babel-plugin-codegen": "npm:0.81.5" + babel-plugin-syntax-hermes-parser: "npm:0.29.1" + babel-plugin-transform-flow-enums: "npm:^0.0.2" + react-refresh: "npm:^0.14.0" + peerDependencies: + "@babel/core": "*" + checksum: 10/c077e01b093be9f93e08b36dd7bc425d897749f76f9a2912cff8589f9ad3e36be0d6b54542ec6fbf13bd4b87ff7648b17a275930c546665d7b8accf4c89b6ff3 + languageName: node + linkType: hard + "@react-native/babel-preset@npm:0.83.2": version: 0.83.2 resolution: "@react-native/babel-preset@npm:0.83.2" @@ -6539,6 +6894,23 @@ __metadata: languageName: node linkType: hard +"@react-native/codegen@npm:0.81.5": + version: 0.81.5 + resolution: "@react-native/codegen@npm:0.81.5" + dependencies: + "@babel/core": "npm:^7.25.2" + "@babel/parser": "npm:^7.25.3" + glob: "npm:^7.1.1" + hermes-parser: "npm:0.29.1" + invariant: "npm:^2.2.4" + nullthrows: "npm:^1.1.1" + yargs: "npm:^17.6.2" + peerDependencies: + "@babel/core": "*" + checksum: 10/eb162a2b4232e6b6a345a659688c488610ba918e40dc8e4a9d17ed4fd3e026ca8066825128533ea5955b0eb58b3af0f8beb813f188bc506d8989285572f5d34f + languageName: node + linkType: hard + "@react-native/codegen@npm:0.82.1": version: 0.82.1 resolution: "@react-native/codegen@npm:0.82.1" @@ -6654,6 +7026,13 @@ __metadata: languageName: node linkType: hard +"@react-native/debugger-frontend@npm:0.81.5": + version: 0.81.5 + resolution: "@react-native/debugger-frontend@npm:0.81.5" + checksum: 10/a5d6e908129f8d6efe5a02251d4f64de677b9a6719b8351b57f0c2a8c40b04d923e7f5b08351c2f4968d88ce3f6fbaa94c3f5603cb10b8285c447f0ed93228fe + languageName: node + linkType: hard + "@react-native/debugger-frontend@npm:0.82.1": version: 0.82.1 resolution: "@react-native/debugger-frontend@npm:0.82.1" @@ -6727,6 +7106,25 @@ __metadata: languageName: node linkType: hard +"@react-native/dev-middleware@npm:0.81.5": + version: 0.81.5 + resolution: "@react-native/dev-middleware@npm:0.81.5" + dependencies: + "@isaacs/ttlcache": "npm:^1.4.1" + "@react-native/debugger-frontend": "npm:0.81.5" + chrome-launcher: "npm:^0.15.2" + chromium-edge-launcher: "npm:^0.2.0" + connect: "npm:^3.6.5" + debug: "npm:^4.4.0" + invariant: "npm:^2.2.4" + nullthrows: "npm:^1.1.1" + open: "npm:^7.0.3" + serve-static: "npm:^1.16.2" + ws: "npm:^6.2.3" + checksum: 10/bd65d55b98c8d28e5e4163873f496add4e67b87f3a350b57cfe4b110f217a40d0bf4207b57a4b32a4d275b5b4661f1e1fb915a76c5cbc93ab316fe37ab49503a + languageName: node + linkType: hard + "@react-native/dev-middleware@npm:0.82.1": version: 0.82.1 resolution: "@react-native/dev-middleware@npm:0.82.1" @@ -6849,6 +7247,13 @@ __metadata: languageName: node linkType: hard +"@react-native/normalize-colors@npm:0.81.5": + version: 0.81.5 + resolution: "@react-native/normalize-colors@npm:0.81.5" + checksum: 10/9a703b228b0e694436385f4438a684599f3b4f1ea16e3eb06f02b3bc2f9e091e3a754b4d25f0ad43ed7169ef5658603b30d0d78ee6bef338939313f16d85f077 + languageName: node + linkType: hard + "@react-native/normalize-colors@npm:0.82.1": version: 0.82.1 resolution: "@react-native/normalize-colors@npm:0.82.1" @@ -7725,6 +8130,28 @@ __metadata: languageName: node linkType: hard +"@urql/core@npm:^5.0.6, @urql/core@npm:^5.1.2": + version: 5.2.0 + resolution: "@urql/core@npm:5.2.0" + dependencies: + "@0no-co/graphql.web": "npm:^1.0.13" + wonka: "npm:^6.3.2" + checksum: 10/b49378550b7581e223f96c3abff33952e0409cebdef6f233250275b9548244ae99e793c9f5791b0ce707955f85c27fed5031719ea1f1279a190ffa0f9299231a + languageName: node + linkType: hard + +"@urql/exchange-retry@npm:^1.3.0": + version: 1.3.2 + resolution: "@urql/exchange-retry@npm:1.3.2" + dependencies: + "@urql/core": "npm:^5.1.2" + wonka: "npm:^6.3.2" + peerDependencies: + "@urql/core": ^5.0.0 + checksum: 10/766b8866735188f42d7371d73babd40ec166fb0adb1e9c133f6ab419f3b9e4d2aa4df4660992e12f8ccda803584e46b0104e108079e204d7d49d82dfcc93cdae + languageName: node + linkType: hard + "@vscode/sudo-prompt@npm:^9.0.0": version: 9.3.1 resolution: "@vscode/sudo-prompt@npm:9.3.1" @@ -8627,6 +9054,15 @@ __metadata: languageName: node linkType: hard +"babel-plugin-syntax-hermes-parser@npm:0.29.1, babel-plugin-syntax-hermes-parser@npm:^0.29.1": + version: 0.29.1 + resolution: "babel-plugin-syntax-hermes-parser@npm:0.29.1" + dependencies: + hermes-parser: "npm:0.29.1" + checksum: 10/bbb1eed253b4255f8c572e1cb2664868d9aa2238363e48a2d1e95e952b2c1d59e86a7051f44956407484df2c9bc6623608740eec10e2095946d241b795262cec + languageName: node + linkType: hard + "babel-plugin-syntax-hermes-parser@npm:0.32.0": version: 0.32.0 resolution: "babel-plugin-syntax-hermes-parser@npm:0.32.0" @@ -8679,6 +9115,45 @@ __metadata: languageName: node linkType: hard +"babel-preset-expo@npm:~54.0.10": + version: 54.0.10 + resolution: "babel-preset-expo@npm:54.0.10" + dependencies: + "@babel/helper-module-imports": "npm:^7.25.9" + "@babel/plugin-proposal-decorators": "npm:^7.12.9" + "@babel/plugin-proposal-export-default-from": "npm:^7.24.7" + "@babel/plugin-syntax-export-default-from": "npm:^7.24.7" + "@babel/plugin-transform-class-static-block": "npm:^7.27.1" + "@babel/plugin-transform-export-namespace-from": "npm:^7.25.9" + "@babel/plugin-transform-flow-strip-types": "npm:^7.25.2" + "@babel/plugin-transform-modules-commonjs": "npm:^7.24.8" + "@babel/plugin-transform-object-rest-spread": "npm:^7.24.7" + "@babel/plugin-transform-parameters": "npm:^7.24.7" + "@babel/plugin-transform-private-methods": "npm:^7.24.7" + "@babel/plugin-transform-private-property-in-object": "npm:^7.24.7" + "@babel/plugin-transform-runtime": "npm:^7.24.7" + "@babel/preset-react": "npm:^7.22.15" + "@babel/preset-typescript": "npm:^7.23.0" + "@react-native/babel-preset": "npm:0.81.5" + babel-plugin-react-compiler: "npm:^1.0.0" + babel-plugin-react-native-web: "npm:~0.21.0" + babel-plugin-syntax-hermes-parser: "npm:^0.29.1" + babel-plugin-transform-flow-enums: "npm:^0.0.2" + debug: "npm:^4.3.4" + resolve-from: "npm:^5.0.0" + peerDependencies: + "@babel/runtime": ^7.20.0 + expo: "*" + react-refresh: ">=0.14.0 <1.0.0" + peerDependenciesMeta: + "@babel/runtime": + optional: true + expo: + optional: true + checksum: 10/210493e87fb2566fbf774a2bf20a0cfd552eb83f7d3fb71aa4b576ebeed6d367a1d7eda64cec8d166859efde6594789946676bae0d26176a45e4be9fac2fd6a4 + languageName: node + linkType: hard + "babel-preset-expo@npm:~55.0.10": version: 55.0.10 resolution: "babel-preset-expo@npm:55.0.10" @@ -8779,7 +9254,7 @@ __metadata: languageName: node linkType: hard -"base64-js@npm:^1.3.0, base64-js@npm:^1.3.1, base64-js@npm:^1.5.1": +"base64-js@npm:^1.2.3, base64-js@npm:^1.3.0, base64-js@npm:^1.3.1, base64-js@npm:^1.5.1": version: 1.5.1 resolution: "base64-js@npm:1.5.1" checksum: 10/669632eb3745404c2f822a18fc3a0122d2f9a7a13f7fb8b5823ee19d1d2ff9ee5b52c53367176ea4ad093c332fd5ab4bd0ebae5a8e27917a4105a4cfc86b1005 @@ -8985,7 +9460,7 @@ __metadata: languageName: node linkType: hard -"brace-expansion@npm:^2.0.1": +"brace-expansion@npm:^2.0.1, brace-expansion@npm:^2.0.2": version: 2.0.2 resolution: "brace-expansion@npm:2.0.2" dependencies: @@ -9894,6 +10369,13 @@ __metadata: languageName: node linkType: hard +"commander@npm:^4.0.0": + version: 4.1.1 + resolution: "commander@npm:4.1.1" + checksum: 10/3b2dc4125f387dab73b3294dbcb0ab2a862f9c0ad748ee2b27e3544d25325b7a8cdfbcc228d103a98a716960b14478114a5206b5415bd48cdafa38797891562c + languageName: node + linkType: hard + "commander@npm:^5.1.0": version: 5.1.0 resolution: "commander@npm:5.1.0" @@ -11258,6 +11740,13 @@ __metadata: languageName: node linkType: hard +"env-editor@npm:^0.4.1": + version: 0.4.2 + resolution: "env-editor@npm:0.4.2" + checksum: 10/d162e161d9a1bddaf63f68428c587b1d823afe7d56cde039ce403cc68706c68350c92b9db44692f4ecea1d67ec80de9ba01ca70568299ed929d3fa056c40aebf + languageName: node + linkType: hard + "env-paths@npm:^2.2.0, env-paths@npm:^2.2.1": version: 2.2.1 resolution: "env-paths@npm:2.2.1" @@ -11916,6 +12405,20 @@ __metadata: languageName: node linkType: hard +"expo-asset@npm:~12.0.12": + version: 12.0.12 + resolution: "expo-asset@npm:12.0.12" + dependencies: + "@expo/image-utils": "npm:^0.8.8" + expo-constants: "npm:~18.0.12" + peerDependencies: + expo: "*" + react: "*" + react-native: "*" + checksum: 10/7034316d820837c92ac70274be56a8e59181f1513805f8a4c85e16f12e1dd75ac6d6ae0b231bd8a76adbb71be6163c05b31b1d437f15b14745c70cc1f255c8a1 + languageName: node + linkType: hard + "expo-asset@npm:~55.0.8": version: 55.0.8 resolution: "expo-asset@npm:55.0.8" @@ -11930,6 +12433,19 @@ __metadata: languageName: node linkType: hard +"expo-constants@npm:~18.0.12, expo-constants@npm:~18.0.13": + version: 18.0.13 + resolution: "expo-constants@npm:18.0.13" + dependencies: + "@expo/config": "npm:~12.0.13" + "@expo/env": "npm:~2.0.8" + peerDependencies: + expo: "*" + react-native: "*" + checksum: 10/f29c72b6f5798bd37550aafcc89c3f1a630c4910a5b69c1e19d03544f6ebf0cb65adf39db600ccbeb6e60545b2b231d244373ef3139e3c75991b380940065c6b + languageName: node + linkType: hard + "expo-constants@npm:~55.0.7": version: 55.0.7 resolution: "expo-constants@npm:55.0.7" @@ -11943,6 +12459,16 @@ __metadata: languageName: node linkType: hard +"expo-file-system@npm:~19.0.21": + version: 19.0.21 + resolution: "expo-file-system@npm:19.0.21" + peerDependencies: + expo: "*" + react-native: "*" + checksum: 10/00a2f13f8139724016f8b811303dd4a4070a315f80ee9e1877bcfd00773b38caafe4f1d3d7d4a87777e4ff53ba645aae0b4430e875f9ee5f277b88372b507811 + languageName: node + linkType: hard + "expo-file-system@npm:~55.0.10": version: 55.0.10 resolution: "expo-file-system@npm:55.0.10" @@ -11953,6 +12479,19 @@ __metadata: languageName: node linkType: hard +"expo-font@npm:~14.0.11": + version: 14.0.11 + resolution: "expo-font@npm:14.0.11" + dependencies: + fontfaceobserver: "npm:^2.1.0" + peerDependencies: + expo: "*" + react: "*" + react-native: "*" + checksum: 10/80acffecdbd49a2ba1d7ecd8727f355bf47c39873d92f5959ff3bf7fd1de3e6ac10ebe2a77b8238287c3f2b7d033df40b562505fec370f82d9444400e19d7518 + languageName: node + linkType: hard + "expo-font@npm:~55.0.4": version: 55.0.4 resolution: "expo-font@npm:55.0.4" @@ -11966,6 +12505,16 @@ __metadata: languageName: node linkType: hard +"expo-keep-awake@npm:~15.0.8": + version: 15.0.8 + resolution: "expo-keep-awake@npm:15.0.8" + peerDependencies: + expo: "*" + react: "*" + checksum: 10/d15c4ec6f033ed89db55c3c4d338db0e012dba10c471d3cca7978e38036e1c4e44c5a4970fa0d87e64c7f1d78c1320910331485bc5caf53acbbfd6277b414353 + languageName: node + linkType: hard + "expo-keep-awake@npm:~55.0.4": version: 55.0.4 resolution: "expo-keep-awake@npm:55.0.4" @@ -11976,6 +12525,21 @@ __metadata: languageName: node linkType: hard +"expo-modules-autolinking@npm:3.0.24": + version: 3.0.24 + resolution: "expo-modules-autolinking@npm:3.0.24" + dependencies: + "@expo/spawn-async": "npm:^1.7.2" + chalk: "npm:^4.1.0" + commander: "npm:^7.2.0" + require-from-string: "npm:^2.0.2" + resolve-from: "npm:^5.0.0" + bin: + expo-modules-autolinking: bin/expo-modules-autolinking.js + checksum: 10/e3b77d2fa84b77e53dca2ef608b48c4db196957c76ac7cc1aba4eb2cca44b5082a16f7af8a3549a342c7a1362f069a76fb9ebdab4be6b467e3791ad48387e15a + languageName: node + linkType: hard + "expo-modules-autolinking@npm:55.0.8": version: 55.0.8 resolution: "expo-modules-autolinking@npm:55.0.8" @@ -11990,6 +12554,18 @@ __metadata: languageName: node linkType: hard +"expo-modules-core@npm:3.0.29": + version: 3.0.29 + resolution: "expo-modules-core@npm:3.0.29" + dependencies: + invariant: "npm:^2.2.4" + peerDependencies: + react: "*" + react-native: "*" + checksum: 10/db23a1c7321db54f40f0bcb9c18e7239d798fb7fb5d8ceedf09879f7ff4d90a85e375851796008006441326ed61c00ba00950b06bc7ea74f6ba648a9dac9d053 + languageName: node + linkType: hard + "expo-modules-core@npm:55.0.14": version: 55.0.14 resolution: "expo-modules-core@npm:55.0.14" @@ -12002,6 +12578,13 @@ __metadata: languageName: node linkType: hard +"expo-server@npm:^1.0.5": + version: 1.0.5 + resolution: "expo-server@npm:1.0.5" + checksum: 10/42cda83d5b514061d4142118fa8590ff8b55218b91a7e6ac131ed71ca743301f7aae7fe6954d96671b6251959b08fe8119eb2f18500b4b5e07ea0c127d2d72c7 + languageName: node + linkType: hard + "expo-server@npm:^55.0.6": version: 55.0.6 resolution: "expo-server@npm:55.0.6" @@ -12009,6 +12592,52 @@ __metadata: languageName: node linkType: hard +"expo@npm:^54.0.27": + version: 54.0.33 + resolution: "expo@npm:54.0.33" + dependencies: + "@babel/runtime": "npm:^7.20.0" + "@expo/cli": "npm:54.0.23" + "@expo/config": "npm:~12.0.13" + "@expo/config-plugins": "npm:~54.0.4" + "@expo/devtools": "npm:0.1.8" + "@expo/fingerprint": "npm:0.15.4" + "@expo/metro": "npm:~54.2.0" + "@expo/metro-config": "npm:54.0.14" + "@expo/vector-icons": "npm:^15.0.3" + "@ungap/structured-clone": "npm:^1.3.0" + babel-preset-expo: "npm:~54.0.10" + expo-asset: "npm:~12.0.12" + expo-constants: "npm:~18.0.13" + expo-file-system: "npm:~19.0.21" + expo-font: "npm:~14.0.11" + expo-keep-awake: "npm:~15.0.8" + expo-modules-autolinking: "npm:3.0.24" + expo-modules-core: "npm:3.0.29" + pretty-format: "npm:^29.7.0" + react-refresh: "npm:^0.14.2" + whatwg-url-without-unicode: "npm:8.0.0-3" + peerDependencies: + "@expo/dom-webview": "*" + "@expo/metro-runtime": "*" + react: "*" + react-native: "*" + react-native-webview: "*" + peerDependenciesMeta: + "@expo/dom-webview": + optional: true + "@expo/metro-runtime": + optional: true + react-native-webview: + optional: true + bin: + expo: bin/cli + expo-modules-autolinking: bin/autolinking + fingerprint: bin/fingerprint + checksum: 10/ed672f78333cf50545ea1cca8181506604150cca01a8aae782da30ddcba185d68f2d48f2ca10dee575a7abbc7913cca3f4c3d34d98373b0e9706b344030fa929 + languageName: node + linkType: hard + "expo@npm:^55.0.5": version: 55.0.5 resolution: "expo@npm:55.0.5" @@ -12807,6 +13436,13 @@ __metadata: languageName: node linkType: hard +"freeport-async@npm:^2.0.0": + version: 2.0.0 + resolution: "freeport-async@npm:2.0.0" + checksum: 10/c0bc71eb48a9b60277e55f1b4c7b0c14d385e9a6b3f0870a1d8b1ae441504afd481380fe7923506364d6fb765546a5cef821dcc5fe7ec2ae17bb8902c94d49b9 + languageName: node + linkType: hard + "fresh@npm:0.5.2, fresh@npm:~0.5.2": version: 0.5.2 resolution: "fresh@npm:0.5.2" @@ -13944,7 +14580,7 @@ __metadata: languageName: node linkType: hard -"hermes-parser@npm:0.29.1": +"hermes-parser@npm:0.29.1, hermes-parser@npm:^0.29.1": version: 0.29.1 resolution: "hermes-parser@npm:0.29.1" dependencies: @@ -16282,6 +16918,15 @@ __metadata: languageName: node linkType: hard +"lan-network@npm:^0.1.6": + version: 0.1.7 + resolution: "lan-network@npm:0.1.7" + bin: + lan-network: dist/lan-network-cli.js + checksum: 10/005b6a30c114b7caa69922756cf5d5dd07679dab254127823255525b426c979388db0f1f74d7c364d96fb2c4dabcbe29bed8ed97a96c290431f3c6127a592f46 + languageName: node + linkType: hard + "lan-network@npm:^0.2.0": version: 0.2.0 resolution: "lan-network@npm:0.2.0" @@ -18408,6 +19053,15 @@ __metadata: languageName: node linkType: hard +"minimatch@npm:^9.0.0": + version: 9.0.9 + resolution: "minimatch@npm:9.0.9" + dependencies: + brace-expansion: "npm:^2.0.2" + checksum: 10/b91fad937deaffb68a45a2cb731ff3cff1c3baf9b6469c879477ed16f15c8f4ce39d63a3f75c2455107c2fdff0f3ab597d97dc09e2e93b883aafcf926ef0c8f9 + languageName: node + linkType: hard + "minimatch@npm:^9.0.4, minimatch@npm:^9.0.5": version: 9.0.5 resolution: "minimatch@npm:9.0.5" @@ -18752,7 +19406,7 @@ __metadata: languageName: node linkType: hard -"mz@npm:^2.4.0": +"mz@npm:^2.4.0, mz@npm:^2.7.0": version: 2.7.0 resolution: "mz@npm:2.7.0" dependencies: @@ -18851,6 +19505,13 @@ __metadata: languageName: node linkType: hard +"nested-error-stacks@npm:~2.0.1": + version: 2.0.1 + resolution: "nested-error-stacks@npm:2.0.1" + checksum: 10/8430d7d80ad69b1add2992ee2992a363db6c1a26a54740963bc99a004c5acb1d2a67049397062eab2caa3a312b4da89a0b85de3bdf82d7d472a6baa166311fe6 + languageName: node + linkType: hard + "netmask@npm:^2.0.2": version: 2.0.2 resolution: "netmask@npm:2.0.2" @@ -20299,7 +20960,7 @@ __metadata: languageName: node linkType: hard -"path-parse@npm:^1.0.7": +"path-parse@npm:^1.0.5, path-parse@npm:^1.0.7": version: 1.0.7 resolution: "path-parse@npm:1.0.7" checksum: 10/49abf3d81115642938a8700ec580da6e830dde670be21893c62f4e10bd7dd4c3742ddc603fe24f898cba7eb0c6bc1777f8d9ac14185d34540c6d4d80cd9cae8a @@ -20474,7 +21135,7 @@ __metadata: languageName: node linkType: hard -"picocolors@npm:^1.0.1, picocolors@npm:^1.1.1": +"picocolors@npm:^1.0.0, picocolors@npm:^1.0.1, picocolors@npm:^1.1.1": version: 1.1.1 resolution: "picocolors@npm:1.1.1" checksum: 10/e1cf46bf84886c79055fdfa9dcb3e4711ad259949e3565154b004b260cd356c5d54b31a1437ce9782624bf766272fe6b0154f5f0c744fb7af5d454d2b60db045 @@ -20488,6 +21149,13 @@ __metadata: languageName: node linkType: hard +"picomatch@npm:^3.0.1": + version: 3.0.1 + resolution: "picomatch@npm:3.0.1" + checksum: 10/65ac837fedbd0640586f7c214f6c7481e1e12f41cdcd22a95eb6a2914d1773707ed0f0b5bd2d1e39b5ec7860b43a4c9150152332a3884cd8dd1d419b2a2fa5b5 + languageName: node + linkType: hard + "picomatch@npm:^4.0.2, picomatch@npm:^4.0.3": version: 4.0.3 resolution: "picomatch@npm:4.0.3" @@ -20523,7 +21191,7 @@ __metadata: languageName: node linkType: hard -"pirates@npm:^4.0.4, pirates@npm:^4.0.6, pirates@npm:^4.0.7": +"pirates@npm:^4.0.1, pirates@npm:^4.0.4, pirates@npm:^4.0.6, pirates@npm:^4.0.7": version: 4.0.7 resolution: "pirates@npm:4.0.7" checksum: 10/2427f371366081ae42feb58214f04805d6b41d6b84d74480ebcc9e0ddbd7105a139f7c653daeaf83ad8a1a77214cf07f64178e76de048128fec501eab3305a96 @@ -20689,6 +21357,13 @@ __metadata: languageName: node linkType: hard +"pretty-bytes@npm:^5.6.0": + version: 5.6.0 + resolution: "pretty-bytes@npm:5.6.0" + checksum: 10/9c082500d1e93434b5b291bd651662936b8bd6204ec9fa17d563116a192d6d86b98f6d328526b4e8d783c07d5499e2614a807520249692da9ec81564b2f439cd + languageName: node + linkType: hard + "pretty-format@npm:30.2.0": version: 30.2.0 resolution: "pretty-format@npm:30.2.0" @@ -20992,6 +21667,15 @@ __metadata: languageName: node linkType: hard +"qrcode-terminal@npm:0.11.0": + version: 0.11.0 + resolution: "qrcode-terminal@npm:0.11.0" + bin: + qrcode-terminal: ./bin/qrcode-terminal.js + checksum: 10/61fe2336b954584f321f2593d7e33f5b235788d829ea982f11a388d1e80e9cafb086dd28e7bd1649859cac62a6eb5818c9de14657222e3f66ba7376d0edccefd + languageName: node + linkType: hard + "qs@npm:^6.14.0, qs@npm:^6.6.0, qs@npm:^6.7.0, qs@npm:~6.14.0": version: 6.14.0 resolution: "qs@npm:6.14.0" @@ -21088,7 +21772,7 @@ __metadata: languageName: node linkType: hard -"rc@npm:^1.2.8": +"rc@npm:^1.2.8, rc@npm:~1.2.7": version: 1.2.8 resolution: "rc@npm:1.2.8" dependencies: @@ -22034,6 +22718,17 @@ __metadata: languageName: node linkType: hard +"requireg@npm:^0.2.2": + version: 0.2.2 + resolution: "requireg@npm:0.2.2" + dependencies: + nested-error-stacks: "npm:~2.0.1" + rc: "npm:~1.2.7" + resolve: "npm:~1.7.1" + checksum: 10/ae3c7759448a8348307ad99f7487f4571a8e5319c5fc5e0499a8791839d1504f3baf61ca846b70731e1973a9243d9d1ef3b54f6f674a5d67d427c92a0d78b072 + languageName: node + linkType: hard + "resolve-cwd@npm:^3.0.0": version: 3.0.0 resolution: "resolve-cwd@npm:3.0.0" @@ -22071,14 +22766,14 @@ __metadata: languageName: node linkType: hard -"resolve.exports@npm:2.0.3": +"resolve.exports@npm:2.0.3, resolve.exports@npm:^2.0.3": version: 2.0.3 resolution: "resolve.exports@npm:2.0.3" checksum: 10/536efee0f30a10fac8604e6cdc7844dbc3f4313568d09f06db4f7ed8a5b8aeb8585966fe975083d1f2dfbc87cf5f8bc7ab65a5c23385c14acbb535ca79f8398a languageName: node linkType: hard -"resolve@npm:^1.1.6, resolve@npm:^1.10.0, resolve@npm:^1.22.10, resolve@npm:^1.22.11": +"resolve@npm:^1.1.6, resolve@npm:^1.10.0, resolve@npm:^1.22.10, resolve@npm:^1.22.11, resolve@npm:^1.22.2": version: 1.22.11 resolution: "resolve@npm:1.22.11" dependencies: @@ -22104,7 +22799,16 @@ __metadata: languageName: node linkType: hard -"resolve@patch:resolve@npm%3A^1.1.6#optional!builtin, resolve@patch:resolve@npm%3A^1.10.0#optional!builtin, resolve@patch:resolve@npm%3A^1.22.10#optional!builtin, resolve@patch:resolve@npm%3A^1.22.11#optional!builtin": +"resolve@npm:~1.7.1": + version: 1.7.1 + resolution: "resolve@npm:1.7.1" + dependencies: + path-parse: "npm:^1.0.5" + checksum: 10/76697bb674d9de34dcfb837739878ad95b3e0021a198c88eb235d812a20d4b15b587e8e14342da41e2a83b6ca2e0c4bfd114d0329cc5b80c264925db1afe0251 + languageName: node + linkType: hard + +"resolve@patch:resolve@npm%3A^1.1.6#optional!builtin, resolve@patch:resolve@npm%3A^1.10.0#optional!builtin, resolve@patch:resolve@npm%3A^1.22.10#optional!builtin, resolve@patch:resolve@npm%3A^1.22.11#optional!builtin, resolve@patch:resolve@npm%3A^1.22.2#optional!builtin": version: 1.22.11 resolution: "resolve@patch:resolve@npm%3A1.22.11#optional!builtin::version=1.22.11&hash=c3c19d" dependencies: @@ -22130,6 +22834,15 @@ __metadata: languageName: node linkType: hard +"resolve@patch:resolve@npm%3A~1.7.1#optional!builtin": + version: 1.7.1 + resolution: "resolve@patch:resolve@npm%3A1.7.1#optional!builtin::version=1.7.1&hash=3bafbf" + dependencies: + path-parse: "npm:^1.0.5" + checksum: 10/3bfc4ed0768c158d320bdd1076875e2c783cba03985d6052cd5142ed971e413eb8f8a81753fc4f12f3051723356898bf9c5a24d6c988dfb9de9587f710ca692d + languageName: node + linkType: hard + "restore-cursor@npm:^2.0.0": version: 2.0.0 resolution: "restore-cursor@npm:2.0.0" @@ -23617,6 +24330,24 @@ __metadata: languageName: node linkType: hard +"sucrase@npm:~3.35.1": + version: 3.35.1 + resolution: "sucrase@npm:3.35.1" + dependencies: + "@jridgewell/gen-mapping": "npm:^0.3.2" + commander: "npm:^4.0.0" + lines-and-columns: "npm:^1.1.6" + mz: "npm:^2.7.0" + pirates: "npm:^4.0.1" + tinyglobby: "npm:^0.2.11" + ts-interface-checker: "npm:^0.1.9" + bin: + sucrase: bin/sucrase + sucrase-node: bin/sucrase-node + checksum: 10/539f5c6ebc1ff8d449a89eb52b8c8944a730b9840ddadbd299a7d89ebcf16c3f4bc9aa59e1f2e112a502e5cf1508f7e02065f0e97c0435eb9a7058e997dfff5a + languageName: node + linkType: hard + "sudo-prompt@npm:^9.0.0": version: 9.2.1 resolution: "sudo-prompt@npm:9.2.1" @@ -23983,7 +24714,7 @@ __metadata: languageName: node linkType: hard -"tinyglobby@npm:^0.2.12, tinyglobby@npm:^0.2.15": +"tinyglobby@npm:^0.2.11, tinyglobby@npm:^0.2.12, tinyglobby@npm:^0.2.15": version: 0.2.15 resolution: "tinyglobby@npm:0.2.15" dependencies: @@ -24124,6 +24855,13 @@ __metadata: languageName: node linkType: hard +"ts-interface-checker@npm:^0.1.9": + version: 0.1.13 + resolution: "ts-interface-checker@npm:0.1.13" + checksum: 10/9f7346b9e25bade7a1050c001ec5a4f7023909c0e1644c5a96ae20703a131627f081479e6622a4ecee2177283d0069e651e507bedadd3904fc4010ab28ffce00 + languageName: node + linkType: hard + "ts-jest@npm:^29.4.6": version: 29.4.6 resolution: "ts-jest@npm:29.4.6" @@ -24483,6 +25221,13 @@ __metadata: languageName: node linkType: hard +"undici@npm:^6.18.2": + version: 6.24.1 + resolution: "undici@npm:6.24.1" + checksum: 10/4f84e6045520eef9ba8eabb96360b50c759f59905c1703b12187c2dbcc6d1584c5d7ecddeb45b0ed6cac84ca2d132b21bfd8a38f77fa30378b1ac5d2ae390fd9 + languageName: node + linkType: hard + "unherit@npm:^3.0.0": version: 3.0.1 resolution: "unherit@npm:3.0.1" @@ -25517,6 +26262,13 @@ __metadata: languageName: node linkType: hard +"wonka@npm:^6.3.2": + version: 6.3.5 + resolution: "wonka@npm:6.3.5" + checksum: 10/4f8adf1a758c7a9ccd2a98e21006537bfebfb68a241a6d703f47c5d2bac474cc476c3f24f1deee641c093d0ae31ea63f5c45ac76ecd90ea715e9c75b7e27ff91 + languageName: node + linkType: hard + "word-wrap@npm:^1.2.5": version: 1.2.5 resolution: "word-wrap@npm:1.2.5"