Skip to content
Draft
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
15 changes: 15 additions & 0 deletions .changeset/nest-multidomain-config.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
"@clerk/shared": minor
"@clerk/backend": minor
"@clerk/nextjs": minor
"@clerk/astro": minor
"@clerk/react-router": minor
"@clerk/tanstack-react-start": minor
"@clerk/clerk-js": minor
"@clerk/express": minor
"@clerk/react": minor
"@clerk/vue": minor
"@clerk/nuxt": minor
---
Comment on lines +1 to +13
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# Search for usage of the old options across the codebase
rg --type=ts --type=js -i 'isSatellite|satelliteAutoSync' -A 2 -B 2 | head -100

Repository: clerk/javascript

Length of output: 7831


🏁 Script executed:

# Search for multiDomain usage to understand the new approach
rg --type=ts --type=js -i 'multiDomain' -A 2 -B 2 | head -100

Repository: clerk/javascript

Length of output: 7141


🏁 Script executed:

# Look for deprecation warnings or compatibility aliases
rg --type=ts --type=js -i 'deprecat|compat|alias' | grep -i -E '(isSatellite|satelliteAutoSync|domain|multiDomain)' | head -50

Repository: clerk/javascript

Length of output: 343


🏁 Script executed:

# Check the changeset file content to see full description
cat .changeset/nest-multidomain-config.md

Repository: clerk/javascript

Length of output: 632


🏁 Script executed:

# Search for any TypeScript type definitions or interfaces that might define these options
fd -e d.ts -e ts | xargs rg 'isSatellite|satelliteAutoSync|multiDomain' -B 3 -A 3 | head -150

Repository: clerk/javascript

Length of output: 12265


Correct version bump severity: this is a breaking change requiring MAJOR, not MINOR.

The changeset removes top-level isSatellite, domain, and satelliteAutoSync options—they are no longer accepted at the root configuration level and must be moved under multiDomain. This is an incompatible API change per semver. The HeadlessBrowserClerk interface explicitly excludes isSatellite, and the codebase reads values exclusively from multiDomain.* properties with no backward-compatibility aliases.

While proxyUrl remains available at both levels, the removal of the three other options breaks any existing code using them at the top level. All affected packages should be bumped to MAJOR, not MINOR.

🤖 Prompt for AI Agents
In @.changeset/nest-multidomain-config.md around lines 1 - 13, The changeset
incorrectly marks breaking API removals as minor—update the release type to
MAJOR for all listed packages (the ones in the diff: "@clerk/shared",
"@clerk/backend", "@clerk/nextjs", "@clerk/astro", "@clerk/react-router",
"@clerk/tanstack-react-start", "@clerk/clerk-js", "@clerk/express",
"@clerk/react", "@clerk/vue", "@clerk/nuxt") because top-level options
isSatellite, domain, and satelliteAutoSync have been removed and moved under
multiDomain (the code and the HeadlessBrowserClerk interface no longer accept
those root-level fields), while proxyUrl remains at both levels; change the
changeset header from minor to major to reflect this breaking change.


Nest satellite configuration under a `multiDomain` key. The top-level `isSatellite`, `domain`, and `satelliteAutoSync` options are replaced by `multiDomain: { isSatellite, domain?, proxyUrl?, autoSync? }`. The `proxyUrl` option remains available at both the top level and inside `multiDomain`.
4 changes: 3 additions & 1 deletion packages/astro/src/integration/create-integration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ type HotloadAstroClerkIntegrationParams = AstroClerkIntegrationParams & {

function createIntegration<Params extends HotloadAstroClerkIntegrationParams>() {
return (params?: Params): AstroIntegration => {
const { proxyUrl, isSatellite, domain, signInUrl, signUpUrl, enableEnvSchema = true } = params || {};
const { proxyUrl, multiDomain, signInUrl, signUpUrl, enableEnvSchema = true } = params || {};
const isSatellite = multiDomain?.isSatellite;
const domain = multiDomain?.domain;

// These are not provided when the "bundled" integration is used
const clerkJSUrl = (params as any)?.clerkJSUrl as string | undefined;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,11 @@ function createInjectionScriptRunner(creator: CreateClerkInstanceInternalFn) {
clientSafeVars = JSON.parse(clientSafeVarsContainer.textContent || '{}');
}

await creator(mergeEnvVarsWithParams({ ...astroClerkOptions, ...clientSafeVars }));
await creator(
mergeEnvVarsWithParams({ ...astroClerkOptions, ...clientSafeVars }) as AstroClerkIntegrationParams & {
publishableKey: string;
},
);
}

return runner;
Expand Down
14 changes: 10 additions & 4 deletions packages/astro/src/internal/merge-env-vars-with-params.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,8 @@ const mergeEnvVarsWithParams = (params?: AstroClerkIntegrationParams & { publish
const {
signInUrl: paramSignIn,
signUpUrl: paramSignUp,
isSatellite: paramSatellite,
multiDomain: paramMultiDomain,
proxyUrl: paramProxy,
domain: paramDomain,
publishableKey: paramPublishableKey,
telemetry: paramTelemetry,
clerkJSUrl: paramClerkJSUrl,
Expand All @@ -21,12 +20,19 @@ const mergeEnvVarsWithParams = (params?: AstroClerkIntegrationParams & { publish
...rest
} = params || {};

const isSatellite = paramMultiDomain?.isSatellite || import.meta.env.PUBLIC_CLERK_IS_SATELLITE;
const domain = paramMultiDomain?.domain || import.meta.env.PUBLIC_CLERK_DOMAIN;

return {
signInUrl: paramSignIn || import.meta.env.PUBLIC_CLERK_SIGN_IN_URL,
signUpUrl: paramSignUp || import.meta.env.PUBLIC_CLERK_SIGN_UP_URL,
isSatellite: paramSatellite || import.meta.env.PUBLIC_CLERK_IS_SATELLITE,
multiDomain: isSatellite
? {
isSatellite: true as const,
...(domain ? { domain: domain as string } : {}),
}
: paramMultiDomain,
Comment on lines +23 to +34
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Fix boolean/env precedence for isSatellite.

Using || with PUBLIC_CLERK_IS_SATELLITE can treat "false" as truthy and also override an explicit multiDomain.isSatellite = false, which can incorrectly enable satellite mode. Prefer nullish coalescing and parse the env string.

Proposed fix
-  const isSatellite = paramMultiDomain?.isSatellite || import.meta.env.PUBLIC_CLERK_IS_SATELLITE;
-  const domain = paramMultiDomain?.domain || import.meta.env.PUBLIC_CLERK_DOMAIN;
+  const isSatellite =
+    paramMultiDomain?.isSatellite ?? isTruthy(import.meta.env.PUBLIC_CLERK_IS_SATELLITE);
+  const domain = paramMultiDomain?.domain ?? import.meta.env.PUBLIC_CLERK_DOMAIN;
🤖 Prompt for AI Agents
In `@packages/astro/src/internal/merge-env-vars-with-params.ts` around lines 23 -
34, The isSatellite boolean currently uses || which treats the string "false" as
truthy and overrides an explicit paramMultiDomain?.isSatellite = false; change
the logic in merge-env-vars-with-params.ts to use nullish coalescing and parse
the env value: compute isSatellite as paramMultiDomain?.isSatellite ??
(import.meta.env.PUBLIC_CLERK_IS_SATELLITE ?
import.meta.env.PUBLIC_CLERK_IS_SATELLITE === "true" : undefined) (or
equivalent) so that explicit false from paramMultiDomain wins and the env string
is parsed to a real boolean before being used in the multiDomain object.

proxyUrl: paramProxy || import.meta.env.PUBLIC_CLERK_PROXY_URL,
domain: paramDomain || import.meta.env.PUBLIC_CLERK_DOMAIN,
publishableKey: paramPublishableKey || import.meta.env.PUBLIC_CLERK_PUBLISHABLE_KEY || '',
clerkUiUrl: paramClerkUiUrl || import.meta.env.PUBLIC_CLERK_UI_URL,
clerkJSUrl: paramClerkJSUrl || import.meta.env.PUBLIC_CLERK_JS_URL,
Expand Down
8 changes: 6 additions & 2 deletions packages/astro/src/server/clerk-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,12 @@ const createClerkClientWithOptions: CreateClerkClientWithOptions = (context, opt
apiUrl: getSafeEnv(context).apiUrl,
apiVersion: getSafeEnv(context).apiVersion,
proxyUrl: getSafeEnv(context).proxyUrl,
domain: getSafeEnv(context).domain,
isSatellite: getSafeEnv(context).isSatellite,
multiDomain: getSafeEnv(context).isSatellite
? {
isSatellite: true,
...(getSafeEnv(context).domain ? { domain: getSafeEnv(context).domain } : {}),
}
: undefined,
userAgent: `${PACKAGE_NAME}@${PACKAGE_VERSION}`,
sdkMetadata: {
name: PACKAGE_NAME,
Expand Down
32 changes: 21 additions & 11 deletions packages/astro/src/server/clerk-middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -209,23 +209,28 @@ export const handleMultiDomainAndProxy = (
opts: AuthenticateRequestOptions,
context: AstroMiddlewareContextParam,
) => {
const relativeOrAbsoluteProxyUrl = handleValueOrFn(
opts?.proxyUrl,
const isSatellite = handleValueOrFn(
opts.multiDomain?.isSatellite,
new URL(clerkRequest.url),
getSafeEnv(context).isSatellite,
);
const domain = handleValueOrFn(opts.multiDomain?.domain, new URL(clerkRequest.url), getSafeEnv(context).domain);
const signInUrl = opts?.signInUrl || getSafeEnv(context).signInUrl;

// Resolve proxyUrl: multiDomain.proxyUrl takes precedence, then top-level, then env
const rawProxyUrl = handleValueOrFn(
opts.multiDomain?.proxyUrl ?? opts?.proxyUrl,
clerkRequest.clerkUrl,
getSafeEnv(context).proxyUrl,
);

let proxyUrl;
if (!!relativeOrAbsoluteProxyUrl && !isHttpOrHttps(relativeOrAbsoluteProxyUrl)) {
proxyUrl = new URL(relativeOrAbsoluteProxyUrl, clerkRequest.clerkUrl).toString();
if (!!rawProxyUrl && !isHttpOrHttps(rawProxyUrl)) {
proxyUrl = new URL(rawProxyUrl, clerkRequest.clerkUrl).toString();
} else {
proxyUrl = relativeOrAbsoluteProxyUrl;
proxyUrl = rawProxyUrl;
}

const isSatellite = handleValueOrFn(opts.isSatellite, new URL(clerkRequest.url), getSafeEnv(context).isSatellite);
const domain = handleValueOrFn(opts.domain, new URL(clerkRequest.url), getSafeEnv(context).domain);
const signInUrl = opts?.signInUrl || getSafeEnv(context).signInUrl;

if (isSatellite && !proxyUrl && !domain) {
throw new Error(missingDomainAndProxy);
}
Expand All @@ -241,8 +246,13 @@ export const handleMultiDomainAndProxy = (

return {
proxyUrl,
isSatellite,
domain,
multiDomain: isSatellite
? {
isSatellite,
...(domain ? { domain } : { proxyUrl: proxyUrl! }),
...(opts.multiDomain?.autoSync !== undefined ? { autoSync: opts.multiDomain.autoSync } : {}),
}
: undefined,
};
};

Expand Down
1 change: 0 additions & 1 deletion packages/astro/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ type AstroClerkUpdateOptions<TUi extends Ui = Ui> = Pick<ClerkOptions, 'localiza

type AstroClerkIntegrationParams<TUi extends Ui = Ui> = Without<
ClerkOptions,
| 'isSatellite'
| 'sdkMetadata'
| 'standardBrowser'
| 'selectInitialSession'
Expand Down
2 changes: 1 addition & 1 deletion packages/backend/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export type ClerkOptions = Omit<CreateBackendApiOptions, 'skipApiVersionInUrl' |
Partial<
Pick<
CreateAuthenticateRequestOptions['options'],
'audience' | 'jwtKey' | 'proxyUrl' | 'secretKey' | 'publishableKey' | 'domain' | 'isSatellite'
'audience' | 'jwtKey' | 'proxyUrl' | 'secretKey' | 'publishableKey' | 'multiDomain'
>
> & { sdkMetadata?: SDKMetadata; telemetry?: Pick<TelemetryCollectorOptions, 'disabled' | 'debug' | 'samplingRate'> };

Expand Down
6 changes: 0 additions & 6 deletions packages/backend/src/tokens/__tests__/factory.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ describe('createAuthenticateRequest({ options, apiClient })', () => {
apiVersion: 'apiVersion',
proxyUrl: 'proxyUrl',
publishableKey: TEST_PK,
isSatellite: false,
domain: 'domain',
audience: 'domain',
};

Expand All @@ -36,8 +34,6 @@ describe('createAuthenticateRequest({ options, apiClient })', () => {
apiVersion: 'apiVersion',
proxyUrl: 'proxyUrl',
publishableKey: TEST_PK,
isSatellite: false,
domain: 'domain',
audience: 'domain',
};

Expand Down Expand Up @@ -67,8 +63,6 @@ describe('createAuthenticateRequest({ options, apiClient })', () => {
apiVersion: 'apiVersion',
proxyUrl: 'proxyUrl',
publishableKey: TEST_PK,
isSatellite: false,
domain: 'domain',
audience: 'domain',
};

Expand Down
Loading
Loading