Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
14129c8
chore(shared): Add deriveState function
wobsoriano Jul 9, 2024
4c14780
chore(astro): Use shared deriveState function
wobsoriano Jul 9, 2024
b181a0c
test(shared): Test deriveState with and without initial state
wobsoriano Jul 9, 2024
0cadd2d
test(shared): Handle undefined initialState
wobsoriano Jul 9, 2024
889fb5c
chore(shared): Add and export Clerk script hotload function
wobsoriano Jul 9, 2024
5fc583a
test(astro): clean up
wobsoriano Jul 10, 2024
64f1987
test(astro): add Clerk script loader tests
wobsoriano Jul 10, 2024
133615e
chore(astro): Use shared script url builder when hotloading script
wobsoriano Jul 10, 2024
f2d5ad9
chore(astro): Use shared data attribute builder for hotloading
wobsoriano Jul 10, 2024
3fca391
chore(astro): Use shared clerk-js hotload script
wobsoriano Jul 10, 2024
142246c
chore(astro): Clean up type ignores
wobsoriano Jul 10, 2024
09f2fde
chore(astro,shared): Add changeset
wobsoriano Jul 11, 2024
ea5f607
chore(shared): Add and export version selector from react package
wobsoriano Jul 11, 2024
cb283c6
chore(astro): Fix merge conflicts
wobsoriano Jul 30, 2024
d5ed822
chore(astro): Fix incorrect file name
wobsoriano Jul 30, 2024
41038f8
chore(shared): Remove hardcoded version from clerk js script loader
wobsoriano Jul 30, 2024
1eaee79
chore(shared): Allow custom package version
wobsoriano Jul 30, 2024
84c5a46
test(shared): Handle custom package versions for versionSelector
wobsoriano Jul 31, 2024
883e734
chore(shared): Improve version selector explanation
wobsoriano Jul 31, 2024
7605a54
chore(astro): Use shared clerk-js hotload script
wobsoriano Jul 31, 2024
c9ed36e
chore(shared): Update internal package version property name
wobsoriano Jul 31, 2024
a76dd7b
chore(astro): Remove unused file
wobsoriano Aug 1, 2024
9e6c6de
chore(astro): Clean up param names
wobsoriano Aug 1, 2024
3969364
chore(clerk-react): Use shared loadClerkJsScript when hotloading Cler…
wobsoriano Aug 5, 2024
06ab32e
chore(clerk-react,astro,shared): Update changeset
wobsoriano Aug 5, 2024
a6a3a2c
chore(shared): Make options optional in loadClerkJsScript and throw i…
wobsoriano Aug 5, 2024
05b2c36
chore(shared): Update loadClerkJsScript JSDoc
wobsoriano Aug 5, 2024
674f9ae
chore(shared,clerk-react): Remove __internal_packageVersion
wobsoriano Aug 5, 2024
5195455
chore(shared): Use built-in errorThrower when loading clerk script
wobsoriano Aug 7, 2024
2304335
chore(shared,astro,react,nextjs): Use built-in error thrower when Cle…
wobsoriano Aug 7, 2024
c7c6651
chore(shared,astro,react,nextjs): Update changeset
wobsoriano Aug 7, 2024
e23fa2c
chore(shared): Update JSDoc function name
wobsoriano Aug 7, 2024
19fad8d
test(shared): Use clerk-js major version from package.json when testi…
wobsoriano Aug 7, 2024
33c28b6
chore(shared): Add nonce prop to script loader options
wobsoriano Aug 7, 2024
e9f21ab
chore(shared): Add nonce prop to to load script
wobsoriano Aug 8, 2024
e5e8fba
chore(shared): Remove extra folder
wobsoriano Aug 8, 2024
090f0e7
chore(shared): Add missing nonce to buildClerkJsScriptAttributes
wobsoriano Aug 8, 2024
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
8 changes: 8 additions & 0 deletions .changeset/nasty-baboons-cheer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
"@clerk/astro": patch
"@clerk/shared": patch
"@clerk/clerk-react": patch
"@clerk/nextjs": patch
---

Introduce functions that can be reused across front-end SDKs
14 changes: 7 additions & 7 deletions packages/astro/src/internal/create-clerk-instance.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
import { loadClerkJsScript, setClerkJsLoadingErrorPackageName } from '@clerk/shared/loadClerkJsScript';
import type { ClerkOptions } from '@clerk/types';

import { $clerk, $csrState } from '../stores/internal';
import type { AstroClerkIntegrationParams, AstroClerkUpdateOptions } from '../types';
import type { AstroClerkCreateInstanceParams, AstroClerkUpdateOptions } from '../types';
import { invokeClerkAstroJSFunctions } from './invoke-clerk-astro-js-functions';
import { mountAllClerkAstroJSComponents } from './mount-clerk-astro-js-components';
import { runOnce } from './run-once';
import { waitForClerkScript } from './utils/loadClerkJSScript';

let initOptions: ClerkOptions | undefined;

// TODO-SHARED: copied from `clerk-js`
export const CLERK_BEFORE_UNLOAD_EVENT = 'clerk:beforeunload';

setClerkJsLoadingErrorPackageName(PACKAGE_NAME);

function windowNavigate(to: URL | string): void {
const toURL = new URL(to, window.location.href);
window.dispatchEvent(new CustomEvent(CLERK_BEFORE_UNLOAD_EVENT));
Expand All @@ -35,10 +37,10 @@ function createNavigationHandler(
*/
const createClerkInstance = runOnce(createClerkInstanceInternal);

async function createClerkInstanceInternal(options?: AstroClerkIntegrationParams) {
async function createClerkInstanceInternal(options?: AstroClerkCreateInstanceParams) {
let clerkJSInstance = window.Clerk;
if (!clerkJSInstance) {
await waitForClerkScript();
await loadClerkJsScript(options);

if (!window.Clerk) {
throw new Error('Failed to download latest ClerkJS. Contact support@clerk.com.');
Expand All @@ -47,7 +49,6 @@ async function createClerkInstanceInternal(options?: AstroClerkIntegrationParams
}

if (!$clerk.get()) {
// @ts-ignore
$clerk.set(clerkJSInstance);
}

Expand All @@ -57,8 +58,7 @@ async function createClerkInstanceInternal(options?: AstroClerkIntegrationParams
routerReplace: createNavigationHandler(window.history.replaceState.bind(window.history)),
};

// TODO: Update Clerk type from @clerk/types to include this method
return (clerkJSInstance as any)
return clerkJSInstance
.load(initOptions)
.then(() => {
$csrState.setKey('isLoaded', true);
Expand Down
17 changes: 0 additions & 17 deletions packages/astro/src/internal/utils/loadClerkJSScript.ts

This file was deleted.

9 changes: 0 additions & 9 deletions packages/astro/src/internal/utils/versionSelector.ts

This file was deleted.

45 changes: 5 additions & 40 deletions packages/astro/src/server/build-clerk-hotload-script.ts
Original file line number Diff line number Diff line change
@@ -1,43 +1,8 @@
import { createDevOrStagingUrlCache, parsePublishableKey } from '@clerk/shared/keys';
import { isValidProxyUrl, proxyUrlToAbsoluteURL } from '@clerk/shared/proxy';
import { addClerkPrefix } from '@clerk/shared/url';
import { clerkJsScriptUrl } from '@clerk/shared/loadClerkJsScript';
import type { APIContext } from 'astro';

import { versionSelector } from '../internal/utils/versionSelector';
import { getSafeEnv } from './get-safe-env';

const { isDevOrStagingUrl } = createDevOrStagingUrlCache();

type BuildClerkJsScriptOptions = {
proxyUrl: string;
domain: string;
clerkJSUrl?: string;
clerkJSVariant?: 'headless' | '';
clerkJSVersion?: string;
publishableKey: string;
};

const clerkJsScriptUrl = (opts: BuildClerkJsScriptOptions) => {
const { clerkJSUrl, clerkJSVariant, clerkJSVersion, proxyUrl, domain, publishableKey } = opts;

if (clerkJSUrl) {
return clerkJSUrl;
}

let scriptHost = '';
if (!!proxyUrl && isValidProxyUrl(proxyUrl)) {
scriptHost = proxyUrlToAbsoluteURL(proxyUrl).replace(/http(s)?:\/\//, '');
} else if (domain && !isDevOrStagingUrl(parsePublishableKey(publishableKey)?.frontendApi || '')) {
scriptHost = addClerkPrefix(domain);
} else {
scriptHost = parsePublishableKey(publishableKey)?.frontendApi || '';
}

const variant = clerkJSVariant ? `${clerkJSVariant.replace(/\.+$/, '')}.` : '';
const version = versionSelector(clerkJSVersion);
return `https://${scriptHost}/npm/@clerk/clerk-js@${version}/dist/clerk.${variant}browser.js`;
};

function buildClerkHotloadScript(locals: APIContext['locals']) {
const publishableKey = getSafeEnv(locals).pk!;
const proxyUrl = getSafeEnv(locals).proxyUrl!;
Expand All @@ -51,10 +16,10 @@ function buildClerkHotloadScript(locals: APIContext['locals']) {
publishableKey,
});
return `
<script src="${scriptSrc}"
data-clerk-script
async
crossOrigin='anonymous'
<script src="${scriptSrc}"
data-clerk-js-script
async
crossOrigin='anonymous'
${publishableKey ? `data-clerk-publishable-key="${publishableKey}"` : ``}
${proxyUrl ? `data-clerk-proxy-url="${proxyUrl}"` : ``}
${domain ? `data-clerk-domain="${domain}"` : ``}
Expand Down
2 changes: 1 addition & 1 deletion packages/astro/src/stores/external.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { deriveState } from '@clerk/shared/deriveState';
import { eventMethodCalled } from '@clerk/shared/telemetry';
import { computed, onMount, type Store } from 'nanostores';

import { $clerk, $csrState, $initialState } from './internal';
import { deriveState } from './utils';

/**
* A client side store that is prepopulated with the authentication context during SSR.
Expand Down
3 changes: 2 additions & 1 deletion packages/nextjs/src/pages/ClerkProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ClerkProvider as ReactClerkProvider } from '@clerk/clerk-react';
// Override Clerk React error thrower to show that errors come from @clerk/nextjs
import { setErrorThrowerOptions } from '@clerk/clerk-react/internal';
import { setClerkJsLoadingErrorPackageName, setErrorThrowerOptions } from '@clerk/clerk-react/internal';
import { useRouter } from 'next/router';
import React from 'react';

Expand All @@ -12,6 +12,7 @@ import { invalidateNextRouterCache } from '../utils/invalidateNextRouterCache';
import { mergeNextClerkPropsWithEnv } from '../utils/mergeNextClerkPropsWithEnv';

setErrorThrowerOptions({ packageName: PACKAGE_NAME });
setClerkJsLoadingErrorPackageName(PACKAGE_NAME);

export function ClerkProvider({ children, ...props }: NextClerkProviderProps): JSX.Element {
const { __unstable_invokeMiddlewareOnAuthStateChange = true } = props;
Expand Down
3 changes: 3 additions & 0 deletions packages/react/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import './polyfills';

import { setClerkJsLoadingErrorPackageName } from '@clerk/shared/loadClerkJsScript';

import { setErrorThrowerOptions } from './errors/errorThrower';

export * from './components';
Expand All @@ -10,3 +12,4 @@ export { useEmailLink } from './hooks/useEmailLink';
export type { BrowserClerk, ClerkProp, HeadlessBrowserClerk, ClerkProviderProps } from './types';

setErrorThrowerOptions({ packageName: PACKAGE_NAME });
setClerkJsLoadingErrorPackageName(PACKAGE_NAME);
6 changes: 5 additions & 1 deletion packages/react/src/internal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,8 @@ export { setErrorThrowerOptions } from './errors/errorThrower';
export { MultisessionAppSupport } from './components/controlComponents';
export { useRoutingProps } from './hooks/useRoutingProps';

export { clerkJsScriptUrl, buildClerkJsScriptAttributes } from './utils/loadClerkJsScript';
export {
clerkJsScriptUrl,
buildClerkJsScriptAttributes,
setClerkJsLoadingErrorPackageName,
} from '@clerk/shared/loadClerkJsScript';
3 changes: 2 additions & 1 deletion packages/react/src/isomorphicClerk.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { inBrowser } from '@clerk/shared/browser';
import { handleValueOrFn } from '@clerk/shared/handleValueOrFn';
import { loadClerkJsScript } from '@clerk/shared/loadClerkJsScript';
import type { TelemetryCollector } from '@clerk/shared/telemetry';
import type {
ActiveSessionResource,
Expand Down Expand Up @@ -49,7 +50,7 @@ import type {
HeadlessBrowserClerkConstructor,
IsomorphicClerkOptions,
} from './types';
import { isConstructor, loadClerkJsScript } from './utils';
import { isConstructor } from './utils';

const SDK_METADATA = {
name: PACKAGE_NAME,
Expand Down
1 change: 0 additions & 1 deletion packages/react/src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
export * from './childrenUtils';
export * from './isConstructor';
export { loadClerkJsScript } from './loadClerkJsScript';
export * from './useMaxAllowedInstancesGuard';
export * from './useCustomElementPortal';
export * from './useCustomPages';
Expand Down
1 change: 1 addition & 0 deletions packages/shared/global.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@ export {};

declare global {
const PACKAGE_VERSION: string;
const JS_PACKAGE_VERSION: string;
const __DEV__: boolean;
}
5 changes: 5 additions & 0 deletions packages/shared/jest.config.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const { name } = require('./package.json');
const { version: clerkJsVersion } = require('../clerk-js/package.json');

/** @type {import('ts-jest').JestConfigWithTsJest} */
const config = {
Expand All @@ -17,6 +18,10 @@ const config = {
transform: {
'^.+\\.m?tsx?$': ['ts-jest', { tsconfig: 'tsconfig.test.json', diagnostics: false }],
},

globals: {
JS_PACKAGE_VERSION: clerkJsVersion,
},
};

module.exports = config;
3 changes: 3 additions & 0 deletions packages/shared/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,19 +51,22 @@
"cookie",
"date",
"deprecated",
"deriveState",
"error",
"file",
"globs",
"handleValueOrFn",
"isomorphicAtob",
"isomorphicBtoa",
"keys",
"loadClerkJsScript",
"loadScript",
"localStorageBroadcastChannel",
"poller",
"proxy",
"underscore",
"url",
"versionSelector",
"react",
"constants",
"apiUrlFromPublishableKey",
Expand Down
36 changes: 36 additions & 0 deletions packages/shared/src/__tests__/deriveState.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import type { InitialState, Resources } from '@clerk/types';

import { deriveState } from '../deriveState';

describe('deriveState', () => {
const mockInitialState = {
userId: 'user_2U330vGHg3llBga8Oi0fzzeNAaG',
sessionId: 'sess_2j1R7g3AUeKMx9M23dBO0XLEQGY',
orgId: 'org_2U330vGHg3llBga8Oi0fzzeNAaG',
} as InitialState;

const mockResources = {
client: {},
user: { id: mockInitialState.userId },
session: { id: mockInitialState.sessionId },
organization: { id: mockInitialState.orgId },
} as Resources;

it('uses SSR state when !clerkLoaded and initialState is provided', () => {
expect(deriveState(false, {} as Resources, mockInitialState)).toEqual(mockInitialState);
});

it('uses CSR state when clerkLoaded', () => {
const result = deriveState(true, mockResources, undefined);
expect(result.userId).toBe(mockInitialState.userId);
expect(result.sessionId).toBe(mockInitialState.sessionId);
expect(result.orgId).toBe(mockInitialState.orgId);
});

it('handles !clerkLoaded and undefined initialState', () => {
const result = deriveState(false, {} as Resources, undefined);
expect(result.userId).toBeUndefined();
expect(result.sessionId).toBeUndefined();
expect(result.orgId).toBeUndefined();
});
});
Loading