Skip to content

Commit f05efe2

Browse files
jacekradkoLekoArts
andauthoredMar 18, 2025
feat(clerk-js): Allow Environment init with defaults (#5287)
Co-authored-by: Lennart <lekoarts@gmail.com>
1 parent c35611e commit f05efe2

26 files changed

+904
-333
lines changed
 

‎.changeset/dirty-lizards-count.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@clerk/clerk-js': minor
3+
---
4+
5+
Improve the resilience of the SDK against situations where the /v1/environment endpoint is not reachable. This is achieved by allowing the initialization of the environment with default values.

‎integration/tests/reverification.test.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ testAgainstRunningApps({ withEnv: [appConfigs.envs.withReverification] })(
160160
fictionalEmail: true,
161161
withPhoneNumber: true,
162162
});
163-
const bapiFakeUser = await u.services.users.createBapiUser({
163+
await u.services.users.createBapiUser({
164164
...delFakeUser,
165165
username: undefined,
166166
phoneNumber: undefined,

‎packages/clerk-js/bundlewatch.config.json

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"files": [
3-
{ "path": "./dist/clerk.js", "maxSize": "577kB" },
4-
{ "path": "./dist/clerk.browser.js", "maxSize": "78kB" },
3+
{ "path": "./dist/clerk.js", "maxSize": "577.5kB" },
4+
{ "path": "./dist/clerk.browser.js", "maxSize": "78.5kB" },
55
{ "path": "./dist/clerk.headless.js", "maxSize": "51KB" },
66
{ "path": "./dist/ui-common*.js", "maxSize": "94KB" },
77
{ "path": "./dist/vendors*.js", "maxSize": "30KB" },
@@ -12,7 +12,7 @@
1212
{ "path": "./dist/organizationswitcher*.js", "maxSize": "5KB" },
1313
{ "path": "./dist/organizationlist*.js", "maxSize": "5.5KB" },
1414
{ "path": "./dist/signin*.js", "maxSize": "12.4KB" },
15-
{ "path": "./dist/signup*.js", "maxSize": "6.5KB" },
15+
{ "path": "./dist/signup*.js", "maxSize": "6.55KB" },
1616
{ "path": "./dist/userbutton*.js", "maxSize": "5KB" },
1717
{ "path": "./dist/userprofile*.js", "maxSize": "15KB" },
1818
{ "path": "./dist/userverification*.js", "maxSize": "5KB" },

‎packages/clerk-js/src/core/clerk.ts

+12-8
Original file line numberDiff line numberDiff line change
@@ -326,9 +326,6 @@ export class Clerk implements ClerkInterface {
326326
public constructor(key: string, options?: DomainOrProxyUrl) {
327327
key = (key || '').trim();
328328

329-
this.#domain = options?.domain;
330-
this.#proxyUrl = options?.proxyUrl;
331-
332329
if (!key) {
333330
return errorThrower.throwMissingPublishableKeyError();
334331
}
@@ -339,8 +336,11 @@ export class Clerk implements ClerkInterface {
339336
return errorThrower.throwInvalidPublishableKeyError({ key });
340337
}
341338

342-
this.#publishableKey = key;
339+
this.#domain = options?.domain;
340+
this.#proxyUrl = options?.proxyUrl;
341+
this.environment = Environment.getInstance();
343342
this.#instanceType = publishableKey.instanceType;
343+
this.#publishableKey = key;
344344

345345
this.#fapiClient = createFapiClient({
346346
domain: this.domain,
@@ -2085,16 +2085,20 @@ export class Clerk implements ClerkInterface {
20852085
}
20862086
};
20872087

2088-
await Promise.all([initEnvironmentPromise, initClient()]).catch(async e => {
2089-
// limit the changes for this specific error for now
2088+
const [envResult, clientResult] = await Promise.allSettled([initEnvironmentPromise, initClient()]);
2089+
if (clientResult.status === 'rejected') {
2090+
const e = clientResult.reason;
2091+
20902092
if (isClerkAPIResponseError(e) && e.errors[0].code === 'requires_captcha') {
2091-
await initEnvironmentPromise;
2093+
if (envResult.status === 'rejected') {
2094+
await initEnvironmentPromise;
2095+
}
20922096
initComponents();
20932097
await initClient();
20942098
} else {
20952099
throw e;
20962100
}
2097-
});
2101+
}
20982102

20992103
this.#authService?.setClientUatCookieForDevelopmentInstances();
21002104

‎packages/clerk-js/src/core/resources/AuthConfig.ts

+14-10
Original file line numberDiff line numberDiff line change
@@ -4,29 +4,33 @@ import { unixEpochToDate } from '../../utils/date';
44
import { BaseResource } from './internal';
55

66
export class AuthConfig extends BaseResource implements AuthConfigResource {
7-
singleSessionMode!: boolean;
87
claimedAt: Date | null = null;
9-
reverification!: boolean;
8+
reverification: boolean = false;
9+
singleSessionMode: boolean = false;
1010

11-
public constructor(data: AuthConfigJSON) {
11+
public constructor(data: Partial<AuthConfigJSON> | null = null) {
1212
super();
13+
1314
this.fromJSON(data);
1415
}
1516

16-
protected fromJSON(data: AuthConfigJSON | null): this {
17-
this.singleSessionMode = data ? data.single_session_mode : true;
18-
this.claimedAt = data?.claimed_at ? unixEpochToDate(data.claimed_at) : null;
19-
this.reverification = data ? data.reverification : true;
17+
protected fromJSON(data: Partial<AuthConfigJSON> | null): this {
18+
if (!data) {
19+
return this;
20+
}
21+
this.claimedAt = this.withDefault(data.claimed_at ? unixEpochToDate(data.claimed_at) : null, this.claimedAt);
22+
this.reverification = this.withDefault(data.reverification, this.reverification);
23+
this.singleSessionMode = this.withDefault(data.single_session_mode, this.singleSessionMode);
2024
return this;
2125
}
2226

2327
public __internal_toSnapshot(): AuthConfigJSONSnapshot {
2428
return {
25-
object: 'auth_config',
26-
id: this.id || '',
27-
single_session_mode: this.singleSessionMode,
2829
claimed_at: this.claimedAt ? this.claimedAt.getTime() : null,
30+
id: this.id ?? '',
31+
object: 'auth_config',
2932
reverification: this.reverification,
33+
single_session_mode: this.singleSessionMode,
3034
};
3135
}
3236
}

‎packages/clerk-js/src/core/resources/Base.ts

+12
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,18 @@ export abstract class BaseResource {
166166

167167
protected abstract fromJSON(data: ClerkResourceJSON | null): this;
168168

169+
/**
170+
* Returns the provided value if it is not `undefined` or `null`, otherwise returns the default value.
171+
*
172+
* @template T - The type of the value.
173+
* @param value - The value to check.
174+
* @param defaultValue - The default value to return if the provided value is `undefined` or `null`.
175+
* @returns The provided value if it is not `undefined` or `null`, otherwise the default value.
176+
*/
177+
protected withDefault<T>(value: T | undefined | null, defaultValue: T): T {
178+
return value ?? defaultValue;
179+
}
180+
169181
protected async _baseGet<J extends ClerkResourceJSON | null>(opts: BaseFetchOptions = {}): Promise<this> {
170182
const json = await BaseResource._fetch<J>(
171183
{

‎packages/clerk-js/src/core/resources/CommerceSettings.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,11 @@ import { BaseResource } from './internal';
1010
* @internal
1111
*/
1212
export class __experimental_CommerceSettings extends BaseResource implements __experimental_CommerceSettingsResource {
13-
stripePublishableKey!: string;
13+
stripePublishableKey: string = '';
1414

15-
public constructor(data: __experimental_CommerceSettingsJSON | __experimental_CommerceSettingsJSONSnapshot) {
15+
public constructor(
16+
data: __experimental_CommerceSettingsJSON | __experimental_CommerceSettingsJSONSnapshot | null = null,
17+
) {
1618
super();
1719
this.fromJSON(data);
1820
}

0 commit comments

Comments
 (0)
Please sign in to comment.