Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
bf74165
fix(firestore): add QueryConstraint interface so constraint arrays ty…
MichaelVerdon Mar 10, 2026
0928332
refactor(auth)!: Migrate to typescript
MichaelVerdon Mar 19, 2026
4257b2c
refactor: auth providers to typescript
MichaelVerdon Mar 19, 2026
d43b746
refactor: password policy and modular
MichaelVerdon Mar 19, 2026
231ef34
refactor: code review fixes
MichaelVerdon Mar 19, 2026
60e59db
Merge branch 'main' into auth-typescript
MichaelVerdon Mar 19, 2026
8cb5c23
revert(firestore): remove query.ts changes from auth migration PR
MichaelVerdon Mar 19, 2026
52d3dd8
format: revert firestore changes
MichaelVerdon Mar 19, 2026
11baeaf
fix: namespaced file
MichaelVerdon Mar 20, 2026
eb5ead4
fix: types
MichaelVerdon Mar 20, 2026
90aeadf
fix: jest issues related to ai
MichaelVerdon Mar 20, 2026
8b9460a
fix: es config
MichaelVerdon Mar 20, 2026
2e7da7d
fix: tsconfig
MichaelVerdon Mar 20, 2026
a9f154e
fix: temp fix
MichaelVerdon Mar 23, 2026
7d03ba4
fix: binary base changes
MichaelVerdon Mar 23, 2026
a633029
fix: point tsconfig at app shim for react-native-binaryToBase64
MichaelVerdon Mar 23, 2026
0ec85d2
refactor: TS for TotpSecret, TotpMultiFactorGenerator, PhoneMultiFact…
MichaelVerdon Mar 23, 2026
e045def
fix: types
MichaelVerdon Mar 24, 2026
3dcd59e
fix: namespace types
MichaelVerdon Mar 24, 2026
d5513f0
reformat: js lint
MichaelVerdon Mar 24, 2026
288e441
format: fix lint
MichaelVerdon Mar 24, 2026
7b4548f
fix: call handler with explicit receiver
MichaelVerdon Mar 26, 2026
afdf5fd
chore(tests): local Detox AVD name and index entry comments
MichaelVerdon Mar 26, 2026
4c5f619
Merge origin/main into auth-typescript
MichaelVerdon Mar 26, 2026
cc670da
chore: revert temp commit
MichaelVerdon Mar 26, 2026
a2ebcc2
test: avoid instanceof User in phone sign-in e2e
MichaelVerdon Mar 27, 2026
9d6afa7
fix: avoid RangeError when User metadata omits timestamps on Android
MichaelVerdon Mar 27, 2026
46e7a08
chore: suppress console usage
MichaelVerdon Mar 27, 2026
1ef539e
fix: metadata timestamp helper
MichaelVerdon Mar 30, 2026
b7674f9
format: js format
MichaelVerdon Mar 30, 2026
908b044
chore: macos build
MichaelVerdon Mar 30, 2026
59d782e
chore: pod install
MichaelVerdon Mar 30, 2026
ac98916
chore: revert mac scripts
MichaelVerdon Mar 31, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ module.exports = {
'^.+\\.(js)$': '<rootDir>/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'],
Expand Down
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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}\"",
Expand Down
8 changes: 5 additions & 3 deletions packages/ai/__tests__/live-session.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<void>>().mockResolvedValue(undefined);
send = jest.fn<(data: string | ArrayBuffer) => void>();
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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);
}
Expand All @@ -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);
}
Expand Down
2 changes: 1 addition & 1 deletion packages/ai/lib/public-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down
2 changes: 1 addition & 1 deletion packages/ai/lib/requests/request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(' ');
Expand Down
2 changes: 1 addition & 1 deletion packages/ai/lib/requests/response-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
Expand Down
2 changes: 1 addition & 1 deletion packages/ai/lib/requests/schema-builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
Expand Down
2 changes: 1 addition & 1 deletion packages/ai/lib/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down
2 changes: 1 addition & 1 deletion packages/ai/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"]
}
},
Expand Down
6 changes: 3 additions & 3 deletions packages/app-check/lib/web/RNFBAppCheckModule.android.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// No-op for android.
const module: Record<string, never> = {};
// No-op for android. Avoid binding name `module` (Jest runs TS in a CJS context).
const noopNativeModule: Record<string, never> = {};

export default module;
export default noopNativeModule;
6 changes: 3 additions & 3 deletions packages/app-check/lib/web/RNFBAppCheckModule.ios.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// No-op for ios.
const module: Record<string, never> = {};
// No-op for ios. Avoid binding name `module` (Jest runs TS in a CJS context).
const noopNativeModule: Record<string, never> = {};

export default module;
export default noopNativeModule;
1 change: 0 additions & 1 deletion packages/app/lib/common/Base64.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
*
*/

// @ts-expect-error - No type declarations available
import binaryToBase64 from 'react-native/Libraries/Utilities/binaryToBase64';
import { promiseDefer } from './promise';

Expand Down
7 changes: 7 additions & 0 deletions packages/app/lib/shims/react-native-binaryToBase64.d.ts
Original file line number Diff line number Diff line change
@@ -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;
}
22 changes: 10 additions & 12 deletions packages/auth/e2e/phone.e2e.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 () {
Expand Down Expand Up @@ -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 () {
Expand Down
6 changes: 4 additions & 2 deletions packages/auth/e2e/user.e2e.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
}

Expand Down Expand Up @@ -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 */
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<unknown> {
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;
}
}
20 changes: 0 additions & 20 deletions packages/auth/lib/MultiFactorResolver.js

This file was deleted.

51 changes: 51 additions & 0 deletions packages/auth/lib/MultiFactorResolver.ts
Original file line number Diff line number Diff line change
@@ -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<unknown> {
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 ?? '');
}
}
Loading
Loading