From b45c5404500aae5b7dec37f226c3e82582c61334 Mon Sep 17 00:00:00 2001 From: Stefanos Anagnostou Date: Tue, 19 Nov 2024 16:42:57 +0200 Subject: [PATCH] wip --- packages/clerk-js/src/core/clerk.ts | 33 ++++++++++++++++--- packages/expo/package.json | 3 ++ .../provider/singleton/createClerkInstance.ts | 23 +++++++++++++ pnpm-lock.yaml | 29 +++++++++++++++- 4 files changed, 83 insertions(+), 5 deletions(-) diff --git a/packages/clerk-js/src/core/clerk.ts b/packages/clerk-js/src/core/clerk.ts index db377ee7cc3..7dafdb12d6d 100644 --- a/packages/clerk-js/src/core/clerk.ts +++ b/packages/clerk-js/src/core/clerk.ts @@ -118,6 +118,7 @@ import { EmailLinkError, EmailLinkErrorCode, Environment, + isClerkRuntimeError, Organization, Waitlist, } from './resources/internal'; @@ -190,6 +191,11 @@ export class Clerk implements ClerkInterface { #pageLifecycle: ReturnType | null = null; #touchThrottledUntil = 0; + public __internal_getEnvironment: (() => Promise) | undefined; + public __internal_getClient: (() => Promise) | undefined; + public __internal_setEnvironment: ((environment: EnvironmentResource) => Promise) | undefined; + public __internal_setClient: ((client: ClientResource) => Promise) | undefined; + public __internal_createPublicCredentials: | (( publicKey: PublicKeyCredentialCreationOptionsWithoutExtensions, @@ -1835,10 +1841,29 @@ export class Clerk implements ClerkInterface { }; #loadInNonStandardBrowser = async (): Promise => { - const [environment, client] = await Promise.all([ - Environment.getInstance().fetch({ touch: false }), - Client.getInstance().fetch(), - ]); + let environment, client; + try { + const [fetchedEnv, fetchedClient] = await Promise.all([ + Environment.getInstance().fetch({ touch: false }), + Client.getInstance().fetch(), + ]); + environment = fetchedEnv; + client = fetchedClient; + await this.__internal_setEnvironment?.(fetchedEnv); + await this.__internal_setClient?.(fetchedClient); + } catch (err) { + if (isClerkRuntimeError(err) && err.code === 'network_error') { + console.log('Clerk: using cached environment and client'); + environment = await this.__internal_getEnvironment?.(); + client = await this.__internal_getClient?.(); + } else { + throw err; + } + } + + if (!environment || !client) { + return false; + } this.updateClient(client); this.updateEnvironment(environment); diff --git a/packages/expo/package.json b/packages/expo/package.json index b2e6410c9f8..6270cb3d65c 100644 --- a/packages/expo/package.json +++ b/packages/expo/package.json @@ -65,12 +65,14 @@ "@clerk/expo-passkeys": "0.0.6", "@clerk/shared": "2.15.0", "@clerk/types": "4.34.0", + "@react-native-async-storage/async-storage": "^2.1.0", "base-64": "^1.0.0", "react-native-url-polyfill": "2.0.0", "tslib": "2.4.1" }, "devDependencies": { "@clerk/eslint-config-custom": "workspace:*", + "@react-native-async-storage/async-storage": "^2.1.0", "@types/base-64": "^1.0.2", "@types/node": "^20.11.24", "@types/react": "18.3.12", @@ -83,6 +85,7 @@ "typescript": "*" }, "peerDependencies": { + "@react-native-async-storage/async-storage": ">=2", "expo-auth-session": ">=5", "expo-local-authentication": ">=13.5.0", "expo-secure-store": ">=12.4.0", diff --git a/packages/expo/src/provider/singleton/createClerkInstance.ts b/packages/expo/src/provider/singleton/createClerkInstance.ts index 006f2f15d55..7d860b21b64 100644 --- a/packages/expo/src/provider/singleton/createClerkInstance.ts +++ b/packages/expo/src/provider/singleton/createClerkInstance.ts @@ -5,6 +5,7 @@ import type { PublicKeyCredentialCreationOptionsWithoutExtensions, PublicKeyCredentialRequestOptionsWithoutExtensions, } from '@clerk/types'; +import AsyncStorage from '@react-native-async-storage/async-storage'; import { Platform } from 'react-native'; import { MemoryTokenCache } from '../../cache/MemoryTokenCache'; @@ -81,6 +82,28 @@ export function createClerkInstance(ClerkClass: typeof Clerk) { __internal_clerk.__internal_isWebAuthnPlatformAuthenticatorSupported = () => { return Promise.resolve(true); }; + + // @ts-expect-error - This is an internal API + __internal_clerk.__internal_setClient = async (client: any) => { + await AsyncStorage.setItem('clerk_client', JSON.stringify(client)); + }; + + // @ts-expect-error - This is an internal API + __internal_clerk.__internal_getClient = async () => { + const client = await AsyncStorage.getItem('clerk_client'); + return client ? JSON.parse(client) : null; + }; + + // @ts-expect-error - This is an internal API + __internal_clerk.__internal_setEnvironment = async (environment: any) => { + await AsyncStorage.setItem('clerk_environment', JSON.stringify(environment)); + }; + + // @ts-expect-error - This is an internal API + __internal_clerk.__internal_getEnvironment = async () => { + const environment = await AsyncStorage.getItem('clerk_environment'); + return environment ? JSON.parse(environment) : null; + }; } // @ts-expect-error - This is an internal API diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d95daf387b6..9b1884fea82 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -595,6 +595,9 @@ importers: '@clerk/eslint-config-custom': specifier: workspace:* version: link:../eslint-config-custom + '@react-native-async-storage/async-storage': + specifier: ^2.1.0 + version: 2.1.0(react-native@0.73.9(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(react@18.3.1)) '@types/base-64': specifier: ^1.0.2 version: 1.0.2 @@ -2958,7 +2961,7 @@ packages: '@expo/bunyan@4.0.1': resolution: {integrity: sha512-+Lla7nYSiHZirgK+U/uYzsLv/X+HaJienbD5AKX1UQZHYfWaP+9uuQluRB4GrEVWF0GZ7vEVp/jzaOT9k/SQlg==} - engines: {node: '>=0.10.0'} + engines: {'0': node >=0.10.0} '@expo/cli@0.18.30': resolution: {integrity: sha512-V90TUJh9Ly8stYo8nwqIqNWCsYjE28GlVFWEhAFCUOp99foiQr8HSTpiiX5GIrprcPoWmlGoY+J5fQA29R4lFg==} @@ -4308,6 +4311,11 @@ packages: peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0 + '@react-native-async-storage/async-storage@2.1.0': + resolution: {integrity: sha512-eAGQGPTAuFNEoIQSB5j2Jh1zm5NPyBRTfjRMfCN0W1OakC5WIB5vsDyIQhUweKN9XOE2/V07lqTMGsL0dGXNkA==} + peerDependencies: + react-native: ^0.0.0-0 || >=0.65 <1.0 + '@react-native-community/cli-clean@12.3.7': resolution: {integrity: sha512-BCYW77QqyxfhiMEBOoHyciJRNV6Rhz1RvclReIKnCA9wAwmoJBeu4Mu+AwiECA2bUITX16fvPt3NwDsSd1jwfQ==} @@ -9744,6 +9752,10 @@ packages: resolution: {integrity: sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==} engines: {node: '>=0.10.0'} + is-plain-obj@2.1.0: + resolution: {integrity: sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==} + engines: {node: '>=8'} + is-plain-obj@3.0.0: resolution: {integrity: sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==} engines: {node: '>=10'} @@ -10785,6 +10797,10 @@ packages: merge-descriptors@1.0.3: resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==} + merge-options@3.0.4: + resolution: {integrity: sha512-2Sug1+knBjkaMsMgf1ctR1Ujx+Ayku4EdJN4Z+C2+JzoeF7A3OZ9KM2GY0CpQS51NR61LTurMJrRKPhSs3ZRTQ==} + engines: {node: '>=10'} + merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} @@ -19142,6 +19158,11 @@ snapshots: '@swc/helpers': 0.5.13 react: 18.3.1 + '@react-native-async-storage/async-storage@2.1.0(react-native@0.73.9(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(react@18.3.1))': + dependencies: + merge-options: 3.0.4 + react-native: 0.73.9(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(react@18.3.1) + '@react-native-community/cli-clean@12.3.7': dependencies: '@react-native-community/cli-tools': 12.3.7 @@ -26257,6 +26278,8 @@ snapshots: is-plain-obj@1.1.0: {} + is-plain-obj@2.1.0: {} + is-plain-obj@3.0.0: {} is-plain-obj@4.1.0: {} @@ -27753,6 +27776,10 @@ snapshots: merge-descriptors@1.0.3: {} + merge-options@3.0.4: + dependencies: + is-plain-obj: 2.1.0 + merge-stream@2.0.0: {} merge2@1.4.1: {}