Skip to content

Commit

Permalink
feat(clerk-expo): Support swapping publishableKey at runtime (#1655)
Browse files Browse the repository at this point in the history
  • Loading branch information
BRKalow authored Sep 1, 2023
1 parent d2ffb25 commit a102c21
Show file tree
Hide file tree
Showing 6 changed files with 24 additions and 2 deletions.
7 changes: 7 additions & 0 deletions .changeset/hot-pans-grow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@clerk/clerk-js': patch
'@clerk/clerk-react': patch
'@clerk/clerk-expo': minor
---

Support swapping the Clerk publishableKey at runtime to allow users to toggle the instance being used.
1 change: 1 addition & 0 deletions packages/clerk-js/src/core/clerk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,7 @@ export default class Clerk implements ClerkInterface {

const { frontendApi, instanceType } = publishableKey as PublishableKey;

this.publishableKey = key;
this.frontendApi = frontendApi;
this.#instanceType = instanceType;
}
Expand Down
2 changes: 2 additions & 0 deletions packages/expo/src/ClerkProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ export function ClerkProvider(props: ClerkProviderProps): JSX.Element {
return (
//@ts-expect-error
<ClerkReactProvider
// Force reset the state when the provided key changes, this ensures that the provider does not retain stale state. See JS-598 for additional context.
key={key}
{...rest}
Clerk={buildClerk({ key, tokenCache })}
standardBrowser={!isReactNative()}
Expand Down
4 changes: 4 additions & 0 deletions packages/expo/src/cache.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export interface TokenCache {
getToken: (key: string) => Promise<string | undefined | null>;
saveToken: (key: string, token: string) => Promise<void>;
clearToken?: (key: string) => void;
}

const createMemoryTokenCache = (): TokenCache => {
Expand All @@ -13,6 +14,9 @@ const createMemoryTokenCache = (): TokenCache => {
getToken: key => {
return Promise.resolve(cache[key]);
},
clearToken: key => {
delete cache[key];
},
};
};

Expand Down
9 changes: 8 additions & 1 deletion packages/expo/src/singleton.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,14 @@ type BuildClerkOptions = {
};

export function buildClerk({ key, tokenCache }: BuildClerkOptions): HeadlessBrowserClerk {
if (!clerk) {
// Support "hot-swapping" the Clerk instance at runtime. See JS-598 for additional details.
const hasKeyChanged = clerk && key !== clerk.publishableKey;

if (!clerk || hasKeyChanged) {
if (hasKeyChanged) {
tokenCache.clearToken?.(KEY);
}

const getToken = tokenCache.getToken;
const saveToken = tokenCache.saveToken;
// TODO: DO NOT ACCEPT THIS
Expand Down
3 changes: 2 additions & 1 deletion packages/react/src/isomorphicClerk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,9 @@ export default class IsomorphicClerk {
static getOrCreateInstance(options: IsomorphicClerkOptions) {
// During SSR: a new instance should be created for every request
// During CSR: use the cached instance for the whole lifetime of the app
// Also will recreate the instance if the provided Clerk instance changes
// This method should be idempotent in both scenarios
if (!inClientSide() || !this.#instance) {
if (!inClientSide() || !this.#instance || (options.Clerk && this.#instance.Clerk !== options.Clerk)) {
this.#instance = new IsomorphicClerk(options);
}
return this.#instance;
Expand Down

0 comments on commit a102c21

Please sign in to comment.