Skip to content

Commit

Permalink
chore(clerk-expo): Use getClerkInstance
Browse files Browse the repository at this point in the history
  • Loading branch information
panteliselef committed May 24, 2024
1 parent cd6885f commit 4492bba
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 50 deletions.
10 changes: 5 additions & 5 deletions .changeset/calm-wasps-accept.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,21 @@
'@clerk/clerk-expo': minor
---

Introduce `createClerkClient` to avoid importing the Clerk class from clerk-js manually.
Introduce `getClerkIntance()` to avoid importing the Clerk class from clerk-js manually.

This enables developers to create and access a Clerk instance in their application outside of React.
```tsx

import { ClerkProvider, createClerkClient } from "@clerk/expo"
import { ClerkProvider, getClerkIntance } from "@clerk/expo"

const clerkInstance = createClerkClient({ publishableKey: 'xxxx' })
const clerkInstance = getClerkIntance({ publishableKey: 'xxxx' })

// Be sure to pass the new instance to ClerkProvider to avoid running multiple instances of Clerk in your application
<ClerkProvider Clerk={clerkInstance}>
<ClerkProvider publishableKey={'xxxx'}>
...
</ClerkProvider>

// Somewhere in your code, outside of React you can do
const token = await Clerk.session?.getToken();
const token = await clerkInstance.session?.getToken();
fetch('http://example.com/', {headers: {Authorization: token })
```
13 changes: 6 additions & 7 deletions packages/expo/src/ClerkProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,24 @@ import React from 'react';
import type { TokenCache } from './cache';
import { MemoryTokenCache } from './cache';
import { isReactNative } from './runtime';
import { buildClerk } from './singleton';
import { getClerkInstance } from './singleton';

export type ClerkProviderProps = ClerkReactProviderProps & {
tokenCache?: TokenCache;
};

export function ClerkProvider(props: ClerkProviderProps): JSX.Element {
const { children, tokenCache = MemoryTokenCache, publishableKey, Clerk, ...rest } = props;
const pkClerk = typeof Clerk !== 'function' ? Clerk?.publishableKey : undefined;
const key = publishableKey || pkClerk || process.env.CLERK_PUBLISHABLE_KEY || '';
const { children, tokenCache = MemoryTokenCache, publishableKey, ...rest } = props;
const pk = publishableKey || process.env.CLERK_PUBLISHABLE_KEY || '';

return (
<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}
key={pk}
{...rest}
publishableKey={key}
Clerk={Clerk || buildClerk({ publishableKey: key, tokenCache })}
publishableKey={pk}
Clerk={getClerkInstance({ publishableKey: pk, tokenCache })}
standardBrowser={!isReactNative()}
>
{children}
Expand Down
4 changes: 2 additions & 2 deletions packages/expo/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ export {
export { isClerkAPIResponseError, isEmailLinkError, isKnownError, isMetamaskError } from '@clerk/clerk-react/errors';

/**
* @deprecated Use `createClerkClient()` instead.
* @deprecated Use `getClerkInstance()` instead.
*/
export { clerk as Clerk } from './singleton';
export { createClerkClient } from './singleton';
export { getClerkInstance } from './singleton';

export * from './ClerkProvider';
export * from './useOAuth';
Expand Down
64 changes: 28 additions & 36 deletions packages/expo/src/singleton.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,58 +13,50 @@ Clerk.sdkMetadata = {
const KEY = '__clerk_client_jwt';

/**
* @deprecated This export will be dropped
* @deprecated Use `getClerkInstance` instead. `Clerk` will be removed in the next major version.
*/
export let clerk: HeadlessBrowserClerk;
let __internal_clerk: HeadlessBrowserClerk;

type BuildClerkOptions = {
publishableKey?: string;
tokenCache?: TokenCache;
};

export function createClerkClient({
export function getClerkInstance({
publishableKey = process.env.CLERK_PUBLISHABLE_KEY || '',
tokenCache = MemoryTokenCache,
}: BuildClerkOptions): HeadlessBrowserClerk {
const clerk = new Clerk(publishableKey);

tokenCache.clearToken?.(KEY);

const getToken = tokenCache.getToken;
const saveToken = tokenCache.saveToken;

clerk.__unstable__onBeforeRequest(async (requestInit: FapiRequestInit) => {
// https://reactnative.dev/docs/0.61/network#known-issues-with-fetch-and-cookie-based-authentication
requestInit.credentials = 'omit';

requestInit.url?.searchParams.append('_is_native', '1');

const jwt = await getToken(KEY);
(requestInit.headers as Headers).set('authorization', jwt || '');
});
// Support "hot-swapping" the Clerk instance at runtime. See JS-598 for additional details.
const hasKeyChanged = __internal_clerk && publishableKey !== __internal_clerk.publishableKey;

// @ts-expect-error
clerk.__unstable__onAfterResponse(async (_: FapiRequestInit, response: FapiResponse<unknown>) => {
const authHeader = response.headers.get('authorization');
if (authHeader) {
await saveToken(KEY, authHeader);
if (!__internal_clerk || hasKeyChanged) {
if (hasKeyChanged) {
tokenCache.clearToken?.(KEY);
}
});

return clerk;
}
const getToken = tokenCache.getToken;
const saveToken = tokenCache.saveToken;
__internal_clerk = clerk = new Clerk(publishableKey);

export function buildClerk({ publishableKey, tokenCache }: Required<BuildClerkOptions>): HeadlessBrowserClerk {
// Support "hot-swapping" the Clerk instance at runtime. See JS-598 for additional details.
const hasKeyChanged = clerk && publishableKey !== clerk.publishableKey;
// @ts-expect-error
__internal_clerk.__unstable__onBeforeRequest(async (requestInit: FapiRequestInit) => {
// https://reactnative.dev/docs/0.61/network#known-issues-with-fetch-and-cookie-based-authentication
requestInit.credentials = 'omit';

if (hasKeyChanged) {
tokenCache.clearToken?.(KEY);
}
requestInit.url?.searchParams.append('_is_native', '1');

if (!clerk || hasKeyChanged) {
clerk = createClerkClient({ publishableKey, tokenCache });
}
const jwt = await getToken(KEY);
(requestInit.headers as Headers).set('authorization', jwt || '');
});

return clerk;
// @ts-expect-error
__internal_clerk.__unstable__onAfterResponse(async (_: FapiRequestInit, response: FapiResponse<unknown>) => {
const authHeader = response.headers.get('authorization');
if (authHeader) {
await saveToken(KEY, authHeader);
}
});
}
return __internal_clerk;
}

0 comments on commit 4492bba

Please sign in to comment.