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
6 changes: 6 additions & 0 deletions .changeset/afraid-toes-sin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@clerk/clerk-js': patch
'@clerk/clerk-react': patch
---

Include **BUILD_DISABLE_RHC** to allow for builds which remove remotely hosted code as it is a requirement for browser extensions.
5 changes: 5 additions & 0 deletions .changeset/tidy-garlics-boil.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@clerk/chrome-extension': major
---

Consume packages with remotely hosted code removed as required by Manifest v3.
5 changes: 3 additions & 2 deletions packages/chrome-extension/src/background/clerk.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import { Clerk } from '@clerk/clerk-js';
import { Clerk } from '@clerk/clerk-js/no-rhc';

import {
createClerkClient as _createClerkClient,
type CreateClerkClientOptions as _CreateClerkClientOptions,
} from '../internal';
import { SCOPE } from '../types';

Clerk.mountComponentRenderer = undefined;

export type CreateClerkClientOptions = Omit<_CreateClerkClientOptions, 'scope'>;

export async function createClerkClient(opts: CreateClerkClientOptions): Promise<Clerk> {
Clerk.mountComponentRenderer = undefined;
const clerk = await _createClerkClient({ ...opts, scope: SCOPE.BACKGROUND });
await clerk.load({ standardBrowser: false });
return clerk;
Expand Down
6 changes: 5 additions & 1 deletion packages/chrome-extension/src/internal/clerk.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Clerk } from '@clerk/clerk-js';
import { Clerk } from '@clerk/clerk-js/no-rhc';
import { DEV_BROWSER_JWT_KEY } from '@clerk/shared/devBrowser';
import { parsePublishableKey } from '@clerk/shared/keys';
import browser from 'webextension-polyfill';
Expand Down Expand Up @@ -32,6 +32,10 @@ export async function createClerkClient({
storageCache = BrowserStorageCache,
syncHost,
}: CreateClerkClientOptions): Promise<Clerk> {
if (scope === SCOPE.BACKGROUND) {
Clerk.mountComponentRenderer = undefined;
}

// Don't cache background scripts as it can result in out-of-sync client information.
if (clerk && scope !== SCOPE.BACKGROUND) {
return clerk;
Expand Down
2 changes: 1 addition & 1 deletion packages/chrome-extension/src/react/ClerkProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { Clerk } from '@clerk/clerk-js';
import type { Clerk } from '@clerk/clerk-js/no-rhc';
import type { ClerkProviderProps as ClerkReactProviderProps } from '@clerk/clerk-react';
import { ClerkProvider as ClerkReactProvider } from '@clerk/clerk-react';
import React from 'react';
Expand Down
7 changes: 5 additions & 2 deletions packages/chrome-extension/tsup.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,27 @@ import type { Options } from 'tsup';
import { defineConfig } from 'tsup';

import { runAfterLast } from '../../scripts/utils';
// @ts-ignore
import { name, version } from './package.json';

export default defineConfig(overrideOptions => {
const isWatch = !!overrideOptions.watch;
const shouldPublish = !!overrideOptions.env?.publish;

const common: Options = {
entry: ['./src/index.ts', './src/background/index.ts', './src/internal/index.ts', './src/react/index.ts'],
entry: ['./src/index.ts', './src/background/index.ts', './src/react/index.ts'],
bundle: true,
clean: true,
minify: false,
sourcemap: true,
legacyOutput: true,
treeshake: true,
noExternal: ['@clerk/clerk-react'],
external: ['use-sync-external-store'],
define: {
PACKAGE_NAME: `"${name}"`,
PACKAGE_VERSION: `"${version}"`,
__DEV__: `${isWatch}`,
__BUILD_DISABLE_RHC__: 'true',
},
};

Expand Down
3 changes: 3 additions & 0 deletions packages/clerk-js/no-rhc/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export { Clerk } from '../dist/types/index';

export * from '../dist/types/index';
1 change: 1 addition & 0 deletions packages/clerk-js/no-rhc/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('../dist/clerk.no-rhc');
3 changes: 2 additions & 1 deletion packages/clerk-js/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@
"types": "dist/types/index.d.ts",
"files": [
"dist",
"headless"
"headless",
"no-rhc"
],
"scripts": {
"build": "pnpm build:bundle && pnpm build:declarations",
Expand Down
65 changes: 63 additions & 2 deletions packages/clerk-js/rspack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@ const isDevelopment = mode => !isProduction(mode);

const variants = {
clerk: 'clerk',
clerkNoRHC: 'clerk.no-rhc', // Omit Remotely Hosted Code
clerkBrowser: 'clerk.browser',
clerkHeadless: 'clerk.headless',
clerkHeadlessBrowser: 'clerk.headless.browser',
};

const variantToSourceFile = {
[variants.clerk]: './src/index.ts',
[variants.clerkNoRHC]: './src/index.ts',
[variants.clerkBrowser]: './src/index.browser.ts',
[variants.clerkHeadless]: './src/index.headless.ts',
[variants.clerkHeadlessBrowser]: './src/index.headless.browser.ts',
Expand All @@ -27,9 +29,10 @@ const variantToSourceFile = {
*
* @param {object} config
* @param {'development'|'production'} config.mode
* @param {boolean} [config.disableRHC=false]
* @returns { import('@rspack/cli').Configuration }
*/
const common = ({ mode }) => {
const common = ({ mode, disableRHC = false }) => {
return {
mode,
resolve: {
Expand All @@ -39,6 +42,7 @@ const common = ({ mode }) => {
},
plugins: [
new rspack.DefinePlugin({
__BUILD_DISABLE_RHC__: JSON.stringify(disableRHC),
__DEV__: isDevelopment(mode),
__PKG_VERSION__: JSON.stringify(packageJSON.version),
__PKG_NAME__: JSON.stringify(packageJSON.name),
Expand Down Expand Up @@ -400,12 +404,63 @@ const prodConfig = ({ mode, env, analysis }) => {
},
});

const clerkEsmNoRHC = merge(
entryForVariant(variants.clerkNoRHC),
common({ mode, disableRHC: true }),
commonForProd(),
commonForProdBundled(),
{
experiments: {
outputModule: true,
},
output: {
filename: '[name].mjs',
libraryTarget: 'module',
},
plugins: [
// Include the lazy chunks in the bundle as well
// so that the final bundle can be imported and bundled again
// by a different bundler, eg the webpack instance used by react-scripts
new rspack.optimize.LimitChunkCountPlugin({
maxChunks: 1,
}),
],
optimization: {
splitChunks: false,
},
},
);

const clerkCjsNoRHC = merge(
entryForVariant(variants.clerkNoRHC),
common({ mode, disableRHC: true }),
commonForProd(),
commonForProdBundled(),
{
output: {
filename: '[name].js',
libraryTarget: 'commonjs',
},
plugins: [
// Include the lazy chunks in the bundle as well
// so that the final bundle can be imported and bundled again
// by a different bundler, eg the webpack instance used by react-scripts
new rspack.optimize.LimitChunkCountPlugin({
maxChunks: 1,
}),
],
optimization: {
splitChunks: false,
},
},
);

// webpack-bundle-analyzer only supports a single build, use clerkBrowser as that's the default build we serve
if (analysis) {
return [clerkBrowser];
}

return [clerkBrowser, clerkHeadless, clerkHeadlessBrowser, clerkEsm, clerkCjs];
return [clerkBrowser, clerkHeadless, clerkHeadlessBrowser, clerkEsm, clerkEsmNoRHC, clerkCjs, clerkCjsNoRHC];
};

/**
Expand Down Expand Up @@ -478,6 +533,12 @@ const devConfig = ({ mode, env }) => {
common({ mode }),
commonForDev(),
),
// prettier-ignore
[variants.clerkBrowserNoRHC]: merge(
entryForVariant(variants.clerkBrowserNoRHC),
common({ mode, disableRHC: true }),
commonForDev(),
),
[variants.clerkHeadless]: merge(
entryForVariant(variants.clerkHeadless),
common({ mode }),
Expand Down
60 changes: 51 additions & 9 deletions packages/clerk-js/src/core/clerk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ import {
clerkMissingSignInUrlAsSatellite,
clerkOAuthCallbackDidNotCompleteSignInSignUp,
clerkRedirectUrlIsMissingScheme,
clerkUnsupportedEnvironmentWarning,
} from './errors';
import { eventBus, events } from './events';
import type { FapiClient, FapiRequestCallback } from './fapiClient';
Expand Down Expand Up @@ -175,7 +176,7 @@ export class Clerk implements ClerkInterface {
// converted to protected environment to support `updateEnvironment` type assertion
protected environment?: EnvironmentResource | null;

#publishableKey: string = '';
#publishableKey = '';
#domain: DomainOrProxyUrl['domain'];
#proxyUrl: DomainOrProxyUrl['proxyUrl'];
#authService?: AuthCookieService;
Expand Down Expand Up @@ -263,7 +264,9 @@ export class Clerk implements ClerkInterface {
const publishableKey = parsePublishableKey(this.publishableKey);

if (!publishableKey) {
return errorThrower.throwInvalidPublishableKeyError({ key: this.publishableKey });
return errorThrower.throwInvalidPublishableKeyError({
key: this.publishableKey,
});
}

return publishableKey.frontendApi;
Expand Down Expand Up @@ -557,7 +560,7 @@ export class Clerk implements ClerkInterface {
};

public mountSignIn = (node: HTMLDivElement, props?: SignInProps): void => {
if (props && props.__experimental?.newComponents && this.__experimental_ui) {
if (props?.__experimental?.newComponents && this.__experimental_ui) {
this.__experimental_ui.mount('SignIn', node, props);
} else {
this.assertComponentsReady(this.#componentControls);
Expand All @@ -583,7 +586,7 @@ export class Clerk implements ClerkInterface {
};

public mountSignUp = (node: HTMLDivElement, props?: SignUpProps): void => {
if (props && props.__experimental?.newComponents && this.__experimental_ui) {
if (props?.__experimental?.newComponents && this.__experimental_ui) {
this.__experimental_ui.mount('SignUp', node, props);
} else {
this.assertComponentsReady(this.#componentControls);
Expand Down Expand Up @@ -1325,7 +1328,13 @@ export class Clerk implements ClerkInterface {
signUp,
verifyEmailPath:
params.verifyEmailAddressUrl ||
buildURL({ base: displayConfig.signUpUrl, hashPath: '/verify-email-address' }, { stringify: true }),
buildURL(
{
base: displayConfig.signUpUrl,
hashPath: '/verify-email-address',
},
{ stringify: true },
),
verifyPhonePath:
params.verifyPhoneNumberUrl ||
buildURL({ base: displayConfig.signUpUrl, hashPath: '/verify-phone-number' }, { stringify: true }),
Expand Down Expand Up @@ -1486,6 +1495,11 @@ export class Clerk implements ClerkInterface {
public authenticateWithGoogleOneTap = async (
params: AuthenticateWithGoogleOneTapParams,
): Promise<SignInResource | SignUpResource> => {
if (__BUILD_DISABLE_RHC__) {
clerkUnsupportedEnvironmentWarning('Google One Tap');
return this.client!.signIn; // TODO: Remove not null assertion
}

return this.client?.signIn
.create({
strategy: 'google_one_tap',
Expand All @@ -1504,11 +1518,27 @@ export class Clerk implements ClerkInterface {
};

public authenticateWithMetamask = async (props: AuthenticateWithMetamaskParams = {}): Promise<void> => {
await this.authenticateWithWeb3({ ...props, strategy: 'web3_metamask_signature' });
if (__BUILD_DISABLE_RHC__) {
clerkUnsupportedEnvironmentWarning('Metamask');
return;
}

await this.authenticateWithWeb3({
...props,
strategy: 'web3_metamask_signature',
});
};

public authenticateWithCoinbaseWallet = async (props: AuthenticateWithCoinbaseWalletParams = {}): Promise<void> => {
await this.authenticateWithWeb3({ ...props, strategy: 'web3_coinbase_wallet_signature' });
if (__BUILD_DISABLE_RHC__) {
clerkUnsupportedEnvironmentWarning('Coinbase Wallet');
return;
}

await this.authenticateWithWeb3({
...props,
strategy: 'web3_coinbase_wallet_signature',
});
};

public authenticateWithWeb3 = async ({
Expand All @@ -1519,6 +1549,11 @@ export class Clerk implements ClerkInterface {
strategy,
legalAccepted,
}: ClerkAuthenticateWithWeb3Params): Promise<void> => {
if (__BUILD_DISABLE_RHC__) {
clerkUnsupportedEnvironmentWarning('Web3');
return;
}

if (!this.client || !this.environment) {
return;
}
Expand All @@ -1532,7 +1567,11 @@ export class Clerk implements ClerkInterface {

let signInOrSignUp: SignInResource | SignUpResource;
try {
signInOrSignUp = await this.client.signIn.authenticateWithWeb3({ identifier, generateSignature, strategy });
signInOrSignUp = await this.client.signIn.authenticateWithWeb3({
identifier,
generateSignature,
strategy,
});
} catch (err) {
if (isError(err, ERROR_CODES.FORM_IDENTIFIER_NOT_FOUND)) {
signInOrSignUp = await this.client.signUp.authenticateWithWeb3({
Expand Down Expand Up @@ -1642,7 +1681,10 @@ export class Clerk implements ClerkInterface {
// 2. clerk-js initializes propA with a default value
// 3. The customer update propB independently of propA and window.Clerk.updateProps is called
// 4. If we don't merge the new props with the current options, propA will be reset to undefined
const props = { ..._props, options: this.#initOptions({ ...this.#options, ..._props.options }) };
const props = {
..._props,
options: this.#initOptions({ ...this.#options, ..._props.options }),
};
return this.#componentControls?.ensureMounted().then(controls => controls.updateProps(props));
};

Expand Down
14 changes: 13 additions & 1 deletion packages/clerk-js/src/core/errors.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
const errorPrefix = 'ClerkJS:';

/**
* Used to log a warning when a Clerk feature is used in an unsupported environment.
* (Development Only)
*
* @param strategy The strategy that is not supported in the current environment.
* @returns void
* @note This is a warning and not an error because the application will still work, but the feature will not be available.
*/
export function clerkUnsupportedEnvironmentWarning(strategy: string) {
console.warn(`${errorPrefix} ${strategy} is not supported in this environment.`);
}

export function clerkNetworkError(url: string, e: Error): never {
throw new Error(`${errorPrefix} Network error at "${url}" - ${e}. Please try again.`);
}
Expand All @@ -8,7 +20,7 @@ export function clerkErrorInitFailed(): never {
throw new Error(`${errorPrefix} Something went wrong initializing Clerk.`);
}

export function clerkErrorDevInitFailed(msg: string = ''): never {
export function clerkErrorDevInitFailed(msg = ''): never {
throw new Error(`${errorPrefix} Something went wrong initializing Clerk in development mode.${msg && ` ${msg}`}`);
}

Expand Down
Loading
Loading