diff --git a/.changeset/healthy-pears-play.md b/.changeset/healthy-pears-play.md
new file mode 100644
index 0000000000..50ed044750
--- /dev/null
+++ b/.changeset/healthy-pears-play.md
@@ -0,0 +1,7 @@
+---
+'@clerk/clerk-js': patch
+'@clerk/clerk-react': patch
+'@clerk/types': patch
+---
+
+Introduce new method `prefetchDependencies` to load Coinbase SDK instead of loading the SDK when click the `Coinbase` button in `` / ``. This change avoid the Safari to block the Coinbase popup
diff --git a/packages/clerk-js/src/core/clerk.ts b/packages/clerk-js/src/core/clerk.ts
index b1cfd5d586..06af8720cf 100644
--- a/packages/clerk-js/src/core/clerk.ts
+++ b/packages/clerk-js/src/core/clerk.ts
@@ -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,
@@ -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';
@@ -138,6 +140,7 @@ declare global {
__clerk_publishable_key?: string;
__clerk_proxy_url?: ClerkInterface['proxyUrl'];
__clerk_domain?: ClerkInterface['domain'];
+ __clerk_coinbase_sdk: Promise;
}
}
@@ -197,6 +200,7 @@ export class Clerk implements ClerkInterface {
#options: ClerkOptions = {};
#pageLifecycle: ReturnType | null = null;
#touchThrottledUntil = 0;
+ #coinbaseSDKResolvers = createDeferredPromise();
public __internal_getCachedResources:
| (() => Promise<{ client: ClientJSONSnapshot | null; environment: EnvironmentJSONSnapshot | null }>)
@@ -369,6 +373,20 @@ export class Clerk implements ClerkInterface {
return this.#options.experimental?.combinedFlow && this.#options.signInUrl === this.#options.signUpUrl;
}
+ #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');
+ }
+
public signOut: SignOut = async (callbackOrOptions?: SignOutCallback | SignOutOptions, options?: SignOutOptions) => {
if (!this.client || this.client.sessions.length === 0) {
return;
@@ -1654,6 +1672,16 @@ export class Clerk implements ClerkInterface {
this.environment = environment;
}
+ private prefetchDependencies = async (): Promise => {
+ if (this.#isCoinbaseWalletEnabled()) {
+ window.__clerk_coinbase_sdk = this.#coinbaseSDKResolvers.promise as Promise;
+
+ await import('@coinbase/wallet-sdk').then(mod => {
+ this.#coinbaseSDKResolvers.resolve(mod.CoinbaseWalletSDK);
+ });
+ }
+ };
+
__internal_setCountry = (country: string | null) => {
if (!this.__internal_country) {
this.__internal_country = country;
@@ -1907,6 +1935,8 @@ export class Clerk implements ClerkInterface {
return false;
}
+ void this.prefetchDependencies();
+
initComponents();
break;
diff --git a/packages/clerk-js/src/utils/web3.ts b/packages/clerk-js/src/utils/web3.ts
index 2bec8b08f8..aab1e5890c 100644
--- a/packages/clerk-js/src/utils/web3.ts
+++ b/packages/clerk-js/src/utils/web3.ts
@@ -71,7 +71,11 @@ 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.catch(() => null);
+ if (!CoinbaseWalletSDK) {
+ throw new Error('Coinbase Wallet SDK is not loaded');
+ }
+
const sdk = new CoinbaseWalletSDK({});
return sdk.makeWeb3Provider({ options: 'all' });
}