Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 5 additions & 0 deletions .changeset/metal-lions-switch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@clerk/shared': minor
---

Introduce `getClerkJsMajorVersionOrTag()`, `getScriptUrl()`, `callWithRetry()`
5 changes: 5 additions & 0 deletions .changeset/silent-fishes-change.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@clerk/backend': minor
---

Replace utilities with @clerk/shared exports
25,039 changes: 10,855 additions & 14,184 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions packages/backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
"test:cloudflare-workerd": "tests/cloudflare-workerd/run.sh"
},
"dependencies": {
"@clerk/shared": "^0.23.1",
"@clerk/types": "^3.52.1",
"@peculiar/webcrypto": "1.4.1",
"@types/node": "16.18.6",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
export {};

declare global {
const PACKAGE_NAME: string;
const PACKAGE_VERSION: string;
const __DEV__: boolean;
}

export {};
4 changes: 2 additions & 2 deletions packages/backend/src/redirections.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ export default (QUnit: QUnit) => {
assert.raises(
() => redirectToSignIn({ returnBackUrl }),
new Error(
'Missing publishableKey. You can get your key at https://dashboard.clerk.com/last-active?path=api-keys.',
'@clerk/backend: Missing publishableKey. You can get your key at https://dashboard.clerk.com/last-active?path=api-keys.',
Comment thread
anagstef marked this conversation as resolved.
),
);
});
Expand Down Expand Up @@ -221,7 +221,7 @@ export default (QUnit: QUnit) => {
assert.raises(
() => redirectToSignUp({ returnBackUrl }),
new Error(
'Missing publishableKey. You can get your key at https://dashboard.clerk.com/last-active?path=api-keys.',
'@clerk/backend: Missing publishableKey. You can get your key at https://dashboard.clerk.com/last-active?path=api-keys.',
Comment thread
anagstef marked this conversation as resolved.
),
);
});
Expand Down
7 changes: 3 additions & 4 deletions packages/backend/src/redirections.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { missingPublishableKeyErrorMessage } from './shared';
import { parsePublishableKey } from './shared';
import { errorThrower, parsePublishableKey } from './util/shared';

type RedirectAdapter = (url: string) => any;

Expand Down Expand Up @@ -46,7 +45,7 @@ export function redirect({ redirectAdapter, signUpUrl, signInUrl, frontendApi, p

const redirectToSignUp = ({ returnBackUrl }: SignUpParams = {}) => {
if (!signUpUrl && !accountsBaseUrl) {
throw new Error(missingPublishableKeyErrorMessage);
errorThrower.throwMissingPublishableKeyError();
}

const accountsSignUpUrl = `${accountsBaseUrl}/sign-up`;
Expand All @@ -55,7 +54,7 @@ export function redirect({ redirectAdapter, signUpUrl, signInUrl, frontendApi, p

const redirectToSignIn = ({ returnBackUrl }: SignInParams = {}) => {
if (!signInUrl && !accountsBaseUrl) {
throw new Error(missingPublishableKeyErrorMessage);
errorThrower.throwMissingPublishableKeyError();
}

const accountsSignInUrl = `${accountsBaseUrl}/sign-in`;
Expand Down
15 changes: 0 additions & 15 deletions packages/backend/src/shared/index.ts

This file was deleted.

35 changes: 0 additions & 35 deletions packages/backend/src/shared/isDevOrStagingUrl.ts

This file was deleted.

56 changes: 0 additions & 56 deletions packages/backend/src/shared/parsePublishableKey.ts

This file was deleted.

45 changes: 0 additions & 45 deletions packages/backend/src/shared/url.ts

This file was deleted.

4 changes: 2 additions & 2 deletions packages/backend/src/tokens/interstitial.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ import { API_VERSION, USER_AGENT } from '../constants';
// DO NOT CHANGE: Runtime needs to be imported as a default export so that we can stub its dependencies with Sinon.js
// For more information refer to https://sinonjs.org/how-to/stub-dependency/
import runtime from '../runtime';
import { joinPaths } from '../util/path';
import {
addClerkPrefix,
callWithRetry,
getClerkJsMajorVersionOrTag,
getScriptUrl,
isDevOrStagingUrl,
parsePublishableKey,
} from '../shared';
import { joinPaths } from '../util/path';
} from '../util/shared';
import { TokenVerificationError, TokenVerificationErrorAction, TokenVerificationErrorReason } from './errors';
import type { DebugRequestSate } from './request';

Expand Down
2 changes: 1 addition & 1 deletion packages/backend/src/tokens/interstitialRule.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { isDevelopmentFromApiKey, isProductionFromApiKey } from '../shared';
import { checkCrossOrigin } from '../util/request';
import { isDevelopmentFromApiKey, isProductionFromApiKey } from '../util/shared';
import type { RequestState } from './authStatus';
import { AuthErrorReason, interstitial, signedIn, signedOut } from './authStatus';
import type { AuthenticateRequestOptions } from './request';
Expand Down
2 changes: 1 addition & 1 deletion packages/backend/src/tokens/keys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import { API_URL, API_VERSION, MAX_CACHE_LAST_UPDATED_AT_SECONDS } from '../cons
// DO NOT CHANGE: Runtime needs to be imported as a default export so that we can stub its dependencies with Sinon.js
// For more information refer to https://sinonjs.org/how-to/stub-dependency/
import runtime from '../runtime';
import { callWithRetry } from '../shared';
import { joinPaths } from '../util/path';
import { getErrorObjectByCode } from '../util/request';
import { callWithRetry } from '../util/shared';
import {
TokenVerificationError,
TokenVerificationErrorAction,
Expand Down
2 changes: 1 addition & 1 deletion packages/backend/src/tokens/request.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { API_URL, API_VERSION, constants } from '../constants';
import { isDevelopmentFromApiKey, parsePublishableKey } from '../shared';
import { assertValidSecretKey } from '../util/assertValidSecretKey';
import { buildRequest, stripAuthorizationHeader } from '../util/IsomorphicRequest';
import { isDevelopmentFromApiKey, parsePublishableKey } from '../util/shared';
import type { RequestState } from './authStatus';
import { AuthErrorReason, interstitial, signedOut, unknownState } from './authStatus';
import type { TokenCarrier } from './errors';
Expand Down
16 changes: 16 additions & 0 deletions packages/backend/src/util/shared.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
export {
addClerkPrefix,
callWithRetry,
getClerkJsMajorVersionOrTag,
getScriptUrl,
isDevelopmentFromApiKey,
isProductionFromApiKey,
parsePublishableKey,
} from '@clerk/shared';

import { buildErrorThrower } from '@clerk/shared';
// TODO: replace packageName with `${PACKAGE_NAME}@${PACKAGE_VERSION}` from tsup.config.ts
export const errorThrower = buildErrorThrower({ packageName: '@clerk/backend' });

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will fix this in another PR that will update how we build and run tests in backend package (currently tsup is not used in tests)


import { createDevOrStagingUrlCache } from '@clerk/shared';
export const { isDevOrStagingUrl } = createDevOrStagingUrlCache();
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@ function wait(ms: number) {

const MAX_NUMBER_OF_RETRIES = 5;

// TODO: Move this to @clerk/shared and reuse it with @clerk/clerk-js
/**
* Retry callback function every few hundred ms (with an exponential backoff
* based on the current attempt) until the maximum attempts has reached or
* the callback is executed successfully. The default number of maximum
* attempts is 5 and retries are triggered when callback throws an error.
*/
export async function callWithRetry<T>(
Comment thread
dimkl marked this conversation as resolved.
fn: (...args: unknown[]) => Promise<T>,
attempt = 1,
Expand Down
2 changes: 2 additions & 0 deletions packages/shared/src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,5 @@ export * from './globs';
export * from './loadScript';
export * from './runtimeEnvironment';
export { deprecated, deprecatedProperty, deprecatedObjectProperty } from './deprecated';
export { callWithRetry } from './callWithRetry';
export { isDevelopmentFromApiKey, isProductionFromApiKey, isStaging } from './instance';
1 change: 1 addition & 0 deletions packages/shared/src/utils/keys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ export function isLegacyFrontendApiKey(key: string) {
}

export function createDevOrStagingUrlCache() {
// TODO: Check if we can merge it with `./instance.ts#isStaging()`
const DEV_OR_STAGING_SUFFIXES = [

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will cater this in another iteration where we will evaluate the exports of the @clerk/shared

'.lcl.dev',
'.stg.dev',
Expand Down
39 changes: 39 additions & 0 deletions packages/shared/src/utils/url.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { isStaging } from './instance';

export function parseSearchParams(queryString = ''): URLSearchParams {
if (queryString.startsWith('?')) {
queryString = queryString.slice(1);
Expand Down Expand Up @@ -25,3 +27,40 @@ export function addClerkPrefix(str: string | undefined) {
const stripped = str.replace(regex, '');
return `clerk.${stripped}`;
}

/**
*
* Retrieve the clerk-js major tag using the major version from the pkgVersion
* param or use the frontendApi to determine if the staging tag should be used.
* The default tag is `latest` and a `next` pkgVersion also exists to retrieve
* the next canary release.
*/
export const getClerkJsMajorVersionOrTag = (frontendApi: string, pkgVersion?: string) => {
Comment thread
dimkl marked this conversation as resolved.
if (!pkgVersion && isStaging(frontendApi)) {
return 'staging';
}

if (!pkgVersion) {
return 'latest';
}

if (pkgVersion.includes('next')) {
return 'next';
}

return pkgVersion.split('.')[0] || 'latest';
};

/**
*
* Retrieve the clerk-js script url from the frontendApi and the major tag
* using the {@link getClerkJsMajorVersionOrTag} or a provided clerkJSVersion tag.
*/
export const getScriptUrl = (
Comment thread
dimkl marked this conversation as resolved.
frontendApi: string,
{ pkgVersion, clerkJSVersion }: { pkgVersion?: string; clerkJSVersion?: string },
) => {
const noSchemeFrontendApi = frontendApi.replace(/http(s)?:\/\//, '');
const major = getClerkJsMajorVersionOrTag(frontendApi, pkgVersion);
return `https://${noSchemeFrontendApi}/npm/@clerk/clerk-js@${clerkJSVersion || major}/dist/clerk.browser.js`;
};