Skip to content

Commit

Permalink
fix(clerk-js,clerk-react,types): Optimize Coinbase SDK loading
Browse files Browse the repository at this point in the history
Instead of lazy loading the Coinbase SDK in getEthereumProvider(), move loading when the SignIn/SignUp components mount. This fix avoid the Safari to block the Coinbase popup
  • Loading branch information
nikospapcom committed Dec 17, 2024
1 parent 9f3dcb5 commit 57f613d
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 2 deletions.
8 changes: 8 additions & 0 deletions .changeset/healthy-pears-play.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
'@clerk/clerk-js': patch
'@clerk/elements': patch
'@clerk/clerk-react': patch
'@clerk/types': patch
---

Move Coinbase SDK loading in the SignIn/SignUp components. This fix avoid the Safari to block the Coinbase popup
32 changes: 31 additions & 1 deletion packages/clerk-js/src/core/clerk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { logger } from '@clerk/shared/logger';
import { isHttpOrHttps, isValidProxyUrl, proxyUrlToAbsoluteURL } from '@clerk/shared/proxy';
import { eventPrebuiltComponentMounted, TelemetryCollector } from '@clerk/shared/telemetry';
import { addClerkPrefix, stripScheme } from '@clerk/shared/url';
import { handleValueOrFn, noop } from '@clerk/shared/utils';
import { createDeferredPromise, handleValueOrFn, noop } from '@clerk/shared/utils';
import type {
__internal_UserVerificationModalProps,
ActiveSessionResource,
Expand Down Expand Up @@ -65,7 +65,9 @@ import type {
WaitlistProps,
WaitlistResource,
Web3Provider,
Web3Strategy,
} from '@clerk/types';
import type CoinbaseWalletSDK from '@coinbase/wallet-sdk';

import type { MountComponentRenderer } from '../ui/Components';
import { UI } from '../ui/new';
Expand Down Expand Up @@ -138,6 +140,7 @@ declare global {
__clerk_publishable_key?: string;
__clerk_proxy_url?: ClerkInterface['proxyUrl'];
__clerk_domain?: ClerkInterface['domain'];
__clerk_coinbase_sdk: Promise<typeof CoinbaseWalletSDK>;
}
}

Expand Down Expand Up @@ -180,6 +183,7 @@ export class Clerk implements ClerkInterface {
protected internal_last_error: ClerkAPIError | null = null;
// converted to protected environment to support `updateEnvironment` type assertion
protected environment?: EnvironmentResource | null;
private __promise = createDeferredPromise();

#publishableKey = '';
#domain: DomainOrProxyUrl['domain'];
Expand Down Expand Up @@ -247,6 +251,20 @@ export class Clerk implements ClerkInterface {
return false;
}

get isCoinbaseWalletEnabled(): boolean {
const attributes = this.environment?.userSettings.attributes;
if (!attributes) {
return false;
}

const findWeb3Attributes = Object.entries(attributes)
.filter(([name, attr]) => attr.used_for_first_factor && name.startsWith('web3'))
.map(([, desc]) => desc.first_factors)
.flat() as any as Web3Strategy[];

return findWeb3Attributes.includes('web3_coinbase_wallet_signature');
}

get domain(): string {
if (inBrowser()) {
const strippedDomainString = stripScheme(handleValueOrFn(this.#domain, new URL(window.location.href)));
Expand Down Expand Up @@ -1654,6 +1672,16 @@ export class Clerk implements ClerkInterface {
this.environment = environment;
}

public prefetchDependencies = async (): Promise<void> => {
if (this.isCoinbaseWalletEnabled) {
window.__clerk_coinbase_sdk = this.__promise.promise as Promise<typeof CoinbaseWalletSDK>;

await import('@coinbase/wallet-sdk').then(mod => {
this.__promise.resolve(mod.CoinbaseWalletSDK);
});
}
};

__internal_setCountry = (country: string | null) => {
if (!this.__internal_country) {
this.__internal_country = country;
Expand Down Expand Up @@ -1907,6 +1935,8 @@ export class Clerk implements ClerkInterface {
return false;
}

void this.prefetchDependencies();

initComponents();

break;
Expand Down
2 changes: 1 addition & 1 deletion packages/clerk-js/src/utils/web3.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ export async function generateSignatureWithOKXWallet(params: GenerateSignaturePa

async function getEthereumProvider(provider: Web3Provider) {
if (provider === 'coinbase_wallet') {
const CoinbaseWalletSDK = await import('@coinbase/wallet-sdk').then(mod => mod.CoinbaseWalletSDK);
const CoinbaseWalletSDK = await window.__clerk_coinbase_sdk;
const sdk = new CoinbaseWalletSDK({});
return sdk.makeWeb3Provider({ options: 'all' });
}
Expand Down
11 changes: 11 additions & 0 deletions packages/react/src/isomorphicClerk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ type IsomorphicLoadedClerk = Without<
| 'client'
| '__internal_getCachedResources'
| '__internal_reloadInitialResources'
| 'prefetchDependencies'
> & {
// TODO: Align return type and parms
handleRedirectCallback: (params: HandleOAuthCallbackParams) => void;
Expand Down Expand Up @@ -173,6 +174,7 @@ type IsomorphicLoadedClerk = Without<
mountSignIn: (node: HTMLDivElement, props: SignInProps) => void;
mountUserProfile: (node: HTMLDivElement, props: UserProfileProps) => void;
mountWaitlist: (node: HTMLDivElement, props: WaitlistProps) => void;
prefetchDependencies: () => void;
client: ClientResource | undefined;
};

Expand Down Expand Up @@ -1214,4 +1216,13 @@ export class IsomorphicClerk implements IsomorphicLoadedClerk {
this.premountMethodCalls.set('signOut', callback);
}
};

prefetchDependencies = async (): Promise<void> => {
const callback = () => this.clerkjs?.prefetchDependencies();
if (this.clerkjs && this.#loaded) {
return callback() as Promise<void>;
} else {
this.premountMethodCalls.set('prefetchDependencies', callback);
}
};
}
5 changes: 5 additions & 0 deletions packages/types/src/clerk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,9 @@ export interface Clerk {

telemetry: TelemetryCollector | undefined;

/** Check if coinbase wallet is enabled. */
isCoinbaseWalletEnabled: boolean;

__internal_country?: string | null;

/**
Expand Down Expand Up @@ -606,6 +609,8 @@ export interface Clerk {
* This funtion is used to reload the initial resources (Environment/Client) from the Frontend API.
**/
__internal_reloadInitialResources: () => Promise<void>;

prefetchDependencies: () => Promise<void>;
}

export type HandleOAuthCallbackParams = TransferableOption &
Expand Down

0 comments on commit 57f613d

Please sign in to comment.