diff --git a/.changeset/remove-chips-build-variant.md b/.changeset/remove-chips-build-variant.md new file mode 100644 index 00000000000..1e3fcc55808 --- /dev/null +++ b/.changeset/remove-chips-build-variant.md @@ -0,0 +1,6 @@ +--- +"@clerk/clerk-js": patch +"@clerk/shared": patch +--- + +Remove CHIPS build variant and use `partitioned_cookies` environment flag from the Clerk API to control partitioned cookie behavior at runtime. diff --git a/packages/clerk-js/package.json b/packages/clerk-js/package.json index 4e9c586748e..74ce6b269e2 100644 --- a/packages/clerk-js/package.json +++ b/packages/clerk-js/package.json @@ -42,7 +42,6 @@ "bundlewatch:fix": "node bundlewatch-fix.mjs", "clean": "rimraf ./dist", "dev": "rspack serve --config rspack.config.js", - "dev:chips": "rspack serve --config rspack.config.js --env variant=\"clerk.chips.browser\"", "dev:headless": "rspack serve --config rspack.config.js --env variant=\"clerk.headless.browser\"", "dev:origin": "rspack serve --config rspack.config.js --env devOrigin=http://localhost:${PORT:-4000}", "dev:sandbox": "rspack serve --config rspack.config.js --env devOrigin=http://localhost:${PORT:-4000} --env sandbox=1", diff --git a/packages/clerk-js/rspack.config.js b/packages/clerk-js/rspack.config.js index ff22955e6f7..e2634a6440e 100644 --- a/packages/clerk-js/rspack.config.js +++ b/packages/clerk-js/rspack.config.js @@ -16,7 +16,6 @@ const variants = { clerkHeadless: 'clerk.headless', clerkHeadlessBrowser: 'clerk.headless.browser', clerkLegacyBrowser: 'clerk.legacy.browser', - clerkCHIPS: 'clerk.chips.browser', }; const variantToSourceFile = { @@ -26,7 +25,6 @@ const variantToSourceFile = { [variants.clerkHeadless]: './src/index.headless.ts', [variants.clerkHeadlessBrowser]: './src/index.headless.browser.ts', [variants.clerkLegacyBrowser]: './src/index.legacy.browser.ts', - [variants.clerkCHIPS]: './src/index.browser.ts', }; /** @@ -58,7 +56,6 @@ const common = ({ mode, variant, disableRHC = false }) => { */ __BUILD_FLAG_KEYLESS_UI__: isDevelopment(mode), __BUILD_DISABLE_RHC__: JSON.stringify(disableRHC), - __BUILD_VARIANT_CHIPS__: variant === variants.clerkCHIPS, }), new rspack.EnvironmentPlugin({ CLERK_ENV: mode, @@ -447,13 +444,6 @@ const prodConfig = ({ mode, env, analysis }) => { // externalsForHeadless(), ); - const clerkCHIPS = merge( - entryForVariant(variants.clerkCHIPS), - common({ mode, variant: variants.clerkCHIPS }), - commonForProd(), - commonForProdChunked(), - ); - const clerkEsm = merge( entryForVariant(variants.clerk), common({ mode, variant: variants.clerk }), @@ -567,7 +557,6 @@ const prodConfig = ({ mode, env, analysis }) => { clerkLegacyBrowser, clerkHeadless, clerkHeadlessBrowser, - clerkCHIPS, clerkEsm, clerkEsmNoRHC, clerkCjs, @@ -670,11 +659,6 @@ const devConfig = ({ mode, env }) => { commonForDev(), // externalsForHeadless(), ), - [variants.clerkCHIPS]: merge( - entryForVariant(variants.clerkCHIPS), - common({ mode, variant: variants.clerkCHIPS }), - commonForDev(), - ), }; if (!entryToConfigMap[variant]) { diff --git a/packages/clerk-js/src/core/auth/AuthCookieService.ts b/packages/clerk-js/src/core/auth/AuthCookieService.ts index 51268dc6bcd..2773a54a9e4 100644 --- a/packages/clerk-js/src/core/auth/AuthCookieService.ts +++ b/packages/clerk-js/src/core/auth/AuthCookieService.ts @@ -12,6 +12,7 @@ import { debugLogger } from '@/utils/debug'; import { clerkMissingDevBrowserJwt } from '../errors'; import { eventBus, events } from '../events'; import type { FapiClient } from '../fapiClient'; +import { Environment } from '../resources/Environment'; import { createActiveContextCookie } from './cookies/activeContext'; import type { ClientUatCookieHandler } from './cookies/clientUat'; import { createClientUatCookie } from './cookies/clientUat'; @@ -74,16 +75,27 @@ export class AuthCookieService { eventBus.on(events.UserSignOut, () => this.handleSignOut()); + // After Environment resolves, re-write dev browser cookies with correct + // partitioned attributes. Dev browser cookies are initially written before + // Environment is fetched, so they may have stale attributes. + eventBus.on(events.EnvironmentUpdate, () => { + this.devBrowser.refreshCookies(); + }); + this.refreshTokenOnFocus(); this.startPollingForToken(); - this.clientUat = createClientUatCookie(cookieSuffix); - this.sessionCookie = createSessionCookie(cookieSuffix); + const cookieOptions = { + usePartitionedCookies: () => Environment.getInstance().partitionedCookies, + }; + this.clientUat = createClientUatCookie(cookieSuffix, cookieOptions); + this.sessionCookie = createSessionCookie(cookieSuffix, cookieOptions); this.activeCookie = createActiveContextCookie(); this.devBrowser = createDevBrowser({ frontendApi: clerk.frontendApi, fapiClient, cookieSuffix, + cookieOptions, }); } diff --git a/packages/clerk-js/src/core/auth/__tests__/devBrowser.test.ts b/packages/clerk-js/src/core/auth/__tests__/devBrowser.test.ts index 26fbe011864..9da60d8ba08 100644 --- a/packages/clerk-js/src/core/auth/__tests__/devBrowser.test.ts +++ b/packages/clerk-js/src/core/auth/__tests__/devBrowser.test.ts @@ -50,7 +50,8 @@ describe('Thrown errors', () => { const devBrowserHandler = createDevBrowser({ frontendApi: 'white-koala-42.clerk.accounts.dev', fapiClient: mockFapiClient, - publishableKey: 'pk_test_d2hpdGUta29hbGEtNDIuY2xlcmsuYWNjb3VudHMuZGV2JA', + cookieSuffix: 'test-suffix', + cookieOptions: { usePartitionedCookies: () => false }, }); await expect(devBrowserHandler.setup()).rejects.toThrow( diff --git a/packages/clerk-js/src/core/auth/cookies/__tests__/clientUat.test.ts b/packages/clerk-js/src/core/auth/cookies/__tests__/clientUat.test.ts index 3caca7f6c33..912d8cf0d18 100644 --- a/packages/clerk-js/src/core/auth/cookies/__tests__/clientUat.test.ts +++ b/packages/clerk-js/src/core/auth/cookies/__tests__/clientUat.test.ts @@ -19,6 +19,7 @@ describe('createClientUatCookie', () => { const mockCookieSuffix = 'test-suffix'; const mockExpires = new Date('2024-12-31'); const mockDomain = 'test.domain'; + const defaultOptions = { usePartitionedCookies: () => false }; const mockSet = vi.fn(); const mockRemove = vi.fn(); const mockGet = vi.fn(); @@ -39,14 +40,14 @@ describe('createClientUatCookie', () => { }); it('should create both suffixed and non-suffixed cookie handlers', () => { - createClientUatCookie(mockCookieSuffix); + createClientUatCookie(mockCookieSuffix, defaultOptions); expect(createCookieHandler).toHaveBeenCalledTimes(2); expect(createCookieHandler).toHaveBeenCalledWith('__client_uat'); expect(createCookieHandler).toHaveBeenCalledWith('__client_uat_test-suffix'); }); it('should set cookies with correct parameters in non-cross-origin context', () => { - const cookieHandler = createClientUatCookie(mockCookieSuffix); + const cookieHandler = createClientUatCookie(mockCookieSuffix, defaultOptions); cookieHandler.set({ id: 'test-client', updatedAt: new Date('2024-01-01'), @@ -65,7 +66,7 @@ describe('createClientUatCookie', () => { it('should set cookies with None sameSite in cross-origin context', () => { (inCrossOriginIframe as ReturnType).mockReturnValue(true); - const cookieHandler = createClientUatCookie(mockCookieSuffix); + const cookieHandler = createClientUatCookie(mockCookieSuffix, defaultOptions); cookieHandler.set({ id: 'test-client', updatedAt: new Date('2024-01-01'), @@ -82,7 +83,7 @@ describe('createClientUatCookie', () => { }); it('should set value to 0 when client is undefined', () => { - const cookieHandler = createClientUatCookie(mockCookieSuffix); + const cookieHandler = createClientUatCookie(mockCookieSuffix, defaultOptions); cookieHandler.set(undefined); expect(mockSet).toHaveBeenCalledWith('0', { @@ -95,7 +96,7 @@ describe('createClientUatCookie', () => { }); it('should set value to 0 when client has no signed in sessions', () => { - const cookieHandler = createClientUatCookie(mockCookieSuffix); + const cookieHandler = createClientUatCookie(mockCookieSuffix, defaultOptions); cookieHandler.set({ id: 'test-client', updatedAt: new Date('2024-01-01'), @@ -114,7 +115,7 @@ describe('createClientUatCookie', () => { it('should get cookie value from suffixed cookie first, then fallback to non-suffixed', () => { mockGet.mockImplementationOnce(() => '1234567890').mockImplementationOnce(() => '9876543210'); - const cookieHandler = createClientUatCookie(mockCookieSuffix); + const cookieHandler = createClientUatCookie(mockCookieSuffix, defaultOptions); const result = cookieHandler.get(); expect(result).toBe(1234567890); @@ -123,7 +124,7 @@ describe('createClientUatCookie', () => { it('should return 0 when no cookie value is present', () => { mockGet.mockImplementationOnce(() => undefined).mockImplementationOnce(() => undefined); - const cookieHandler = createClientUatCookie(mockCookieSuffix); + const cookieHandler = createClientUatCookie(mockCookieSuffix, defaultOptions); const result = cookieHandler.get(); expect(result).toBe(0); @@ -131,7 +132,7 @@ describe('createClientUatCookie', () => { it('should set cookies with SameSite=None when the host requires it', () => { (requiresSameSiteNone as ReturnType).mockReturnValue(true); - const cookieHandler = createClientUatCookie(mockCookieSuffix); + const cookieHandler = createClientUatCookie(mockCookieSuffix, defaultOptions); cookieHandler.set({ id: 'test-client', updatedAt: new Date('2024-01-01'), @@ -146,4 +147,21 @@ describe('createClientUatCookie', () => { partitioned: false, }); }); + + it('should set partitioned cookies when usePartitionedCookies returns true', () => { + const cookieHandler = createClientUatCookie(mockCookieSuffix, { usePartitionedCookies: () => true }); + cookieHandler.set({ + id: 'test-client', + updatedAt: new Date('2024-01-01'), + signedInSessions: ['session1'], + }); + + expect(mockSet).toHaveBeenCalledWith('1704067200', { + domain: mockDomain, + expires: mockExpires, + sameSite: 'None', + secure: true, + partitioned: true, + }); + }); }); diff --git a/packages/clerk-js/src/core/auth/cookies/__tests__/session.test.ts b/packages/clerk-js/src/core/auth/cookies/__tests__/session.test.ts index 2e63ad845ee..5018fb04caf 100644 --- a/packages/clerk-js/src/core/auth/cookies/__tests__/session.test.ts +++ b/packages/clerk-js/src/core/auth/cookies/__tests__/session.test.ts @@ -17,6 +17,7 @@ describe('createSessionCookie', () => { const mockCookieSuffix = 'test-suffix'; const mockToken = 'test-token'; const mockExpires = new Date('2024-12-31'); + const defaultOptions = { usePartitionedCookies: () => false }; const mockSet = vi.fn(); const mockRemove = vi.fn(); const mockGet = vi.fn(); @@ -36,14 +37,14 @@ describe('createSessionCookie', () => { }); it('should create both suffixed and non-suffixed cookie handlers', () => { - createSessionCookie(mockCookieSuffix); + createSessionCookie(mockCookieSuffix, defaultOptions); expect(createCookieHandler).toHaveBeenCalledTimes(2); expect(createCookieHandler).toHaveBeenCalledWith('__session'); expect(createCookieHandler).toHaveBeenCalledWith('__session_test-suffix'); }); it('should set cookies with correct parameters in non-cross-origin context', () => { - const cookieHandler = createSessionCookie(mockCookieSuffix); + const cookieHandler = createSessionCookie(mockCookieSuffix, defaultOptions); cookieHandler.set(mockToken); expect(mockSet).toHaveBeenCalledTimes(2); @@ -57,7 +58,7 @@ describe('createSessionCookie', () => { it('should set cookies with None sameSite in cross-origin context', () => { (inCrossOriginIframe as ReturnType).mockReturnValue(true); - const cookieHandler = createSessionCookie(mockCookieSuffix); + const cookieHandler = createSessionCookie(mockCookieSuffix, defaultOptions); cookieHandler.set(mockToken); expect(mockSet).toHaveBeenCalledWith(mockToken, { @@ -69,14 +70,14 @@ describe('createSessionCookie', () => { }); it('should remove both cookies when remove is called', () => { - const cookieHandler = createSessionCookie(mockCookieSuffix); + const cookieHandler = createSessionCookie(mockCookieSuffix, defaultOptions); cookieHandler.remove(); expect(mockRemove).toHaveBeenCalledTimes(2); }); it('should remove cookies with the same attributes as set', () => { - const cookieHandler = createSessionCookie(mockCookieSuffix); + const cookieHandler = createSessionCookie(mockCookieSuffix, defaultOptions); cookieHandler.set(mockToken); cookieHandler.remove(); @@ -102,7 +103,7 @@ describe('createSessionCookie', () => { it('should get cookie value from suffixed cookie first, then fallback to non-suffixed', () => { mockGet.mockImplementationOnce(() => 'suffixed-value').mockImplementationOnce(() => 'non-suffixed-value'); - const cookieHandler = createSessionCookie(mockCookieSuffix); + const cookieHandler = createSessionCookie(mockCookieSuffix, defaultOptions); const result = cookieHandler.get(); expect(result).toBe('suffixed-value'); @@ -111,7 +112,7 @@ describe('createSessionCookie', () => { it('should fallback to non-suffixed cookie when suffixed cookie is not present', () => { mockGet.mockImplementationOnce(() => undefined).mockImplementationOnce(() => 'non-suffixed-value'); - const cookieHandler = createSessionCookie(mockCookieSuffix); + const cookieHandler = createSessionCookie(mockCookieSuffix, defaultOptions); const result = cookieHandler.get(); expect(result).toBe('non-suffixed-value'); @@ -119,7 +120,7 @@ describe('createSessionCookie', () => { it('should set cookies with None sameSite on .replit.dev origins', () => { (requiresSameSiteNone as ReturnType).mockReturnValue(true); - const cookieHandler = createSessionCookie(mockCookieSuffix); + const cookieHandler = createSessionCookie(mockCookieSuffix, defaultOptions); cookieHandler.set(mockToken); expect(mockSet).toHaveBeenCalledWith(mockToken, { @@ -129,4 +130,17 @@ describe('createSessionCookie', () => { partitioned: false, }); }); + + it('should set partitioned cookies when usePartitionedCookies returns true', () => { + const cookieHandler = createSessionCookie(mockCookieSuffix, { usePartitionedCookies: () => true }); + cookieHandler.set(mockToken); + + expect(mockRemove).toHaveBeenCalledTimes(2); + expect(mockSet).toHaveBeenCalledWith(mockToken, { + expires: mockExpires, + sameSite: 'None', + secure: true, + partitioned: true, + }); + }); }); diff --git a/packages/clerk-js/src/core/auth/cookies/clientUat.ts b/packages/clerk-js/src/core/auth/cookies/clientUat.ts index a90d5a77184..0a19c7e908b 100644 --- a/packages/clerk-js/src/core/auth/cookies/clientUat.ts +++ b/packages/clerk-js/src/core/auth/cookies/clientUat.ts @@ -15,13 +15,20 @@ export type ClientUatCookieHandler = { get: () => number; }; +export type ClientUatCookieOptions = { + usePartitionedCookies: () => boolean; +}; + /** * Create a long-lived JS cookie to store the client last updated_at timestamp * for development instances (for production instance is set by FAPI). * The cookie is used as hint from the Clerk Backend packages to identify * if the user is authenticated or not. */ -export const createClientUatCookie = (cookieSuffix: string): ClientUatCookieHandler => { +export const createClientUatCookie = ( + cookieSuffix: string, + options: ClientUatCookieOptions, +): ClientUatCookieHandler => { const clientUatCookie = createCookieHandler(CLIENT_UAT_COOKIE_NAME); const suffixedClientUatCookie = createCookieHandler(getSuffixedCookieName(CLIENT_UAT_COOKIE_NAME, cookieSuffix)); @@ -38,13 +45,10 @@ export const createClientUatCookie = (cookieSuffix: string): ClientUatCookieHand * Generally, this is handled by redirectWithAuth() being called and relying on the dev browser ID in the URL, * but if that isn't used we rely on this. In production, nothing is cross-domain and Lax is used when client_uat is set from FAPI. */ - const sameSite = __BUILD_VARIANT_CHIPS__ - ? 'None' - : inCrossOriginIframe() || requiresSameSiteNone() - ? 'None' - : 'Strict'; + const isPartitioned = options.usePartitionedCookies(); + const sameSite = isPartitioned || inCrossOriginIframe() || requiresSameSiteNone() ? 'None' : 'Strict'; const secure = getSecureAttribute(sameSite); - const partitioned = __BUILD_VARIANT_CHIPS__ && secure; + const partitioned = isPartitioned && secure; const domain = getCookieDomain(undefined, undefined, { sameSite, secure }); // '0' indicates the user is signed out diff --git a/packages/clerk-js/src/core/auth/cookies/devBrowser.ts b/packages/clerk-js/src/core/auth/cookies/devBrowser.ts index f7b6c6c5851..7b6807c49f1 100644 --- a/packages/clerk-js/src/core/auth/cookies/devBrowser.ts +++ b/packages/clerk-js/src/core/auth/cookies/devBrowser.ts @@ -13,10 +13,16 @@ export type DevBrowserCookieHandler = { remove: () => void; }; -const getCookieAttributes = (): { sameSite: string; secure: boolean } => { - const sameSite = inCrossOriginIframe() || requiresSameSiteNone() ? 'None' : 'Lax'; +export type DevBrowserCookieOptions = { + usePartitionedCookies: () => boolean; +}; + +const getCookieAttributes = (options: DevBrowserCookieOptions) => { + const isPartitioned = options.usePartitionedCookies(); + const sameSite = isPartitioned || inCrossOriginIframe() || requiresSameSiteNone() ? 'None' : 'Lax'; const secure = getSecureAttribute(sameSite); - return { sameSite, secure }; + const partitioned = isPartitioned && secure; + return { sameSite, secure, partitioned } as const; }; /** @@ -25,7 +31,10 @@ const getCookieAttributes = (): { sameSite: string; secure: boolean } => { * The cookie is used to authenticate FAPI requests and pass * authentication from AP to the app. */ -export const createDevBrowserCookie = (cookieSuffix: string): DevBrowserCookieHandler => { +export const createDevBrowserCookie = ( + cookieSuffix: string, + options: DevBrowserCookieOptions, +): DevBrowserCookieHandler => { const devBrowserCookie = createCookieHandler(DEV_BROWSER_JWT_KEY); const suffixedDevBrowserCookie = createCookieHandler(getSuffixedCookieName(DEV_BROWSER_JWT_KEY, cookieSuffix)); @@ -33,16 +42,30 @@ export const createDevBrowserCookie = (cookieSuffix: string): DevBrowserCookieHa const set = (jwt: string) => { const expires = addYears(Date.now(), 1); - const { sameSite, secure } = getCookieAttributes(); + const { sameSite, secure, partitioned } = getCookieAttributes(options); - suffixedDevBrowserCookie.set(jwt, { expires, sameSite, secure }); - devBrowserCookie.set(jwt, { expires, sameSite, secure }); + // Remove old non-partitioned cookies — the browser treats partitioned and + // non-partitioned cookies with the same name as distinct cookies. + if (partitioned) { + suffixedDevBrowserCookie.remove(); + devBrowserCookie.remove(); + } + + suffixedDevBrowserCookie.set(jwt, { expires, sameSite, secure, partitioned }); + devBrowserCookie.set(jwt, { expires, sameSite, secure, partitioned }); }; const remove = () => { - const attributes = getCookieAttributes(); + const attributes = getCookieAttributes(options); suffixedDevBrowserCookie.remove(attributes); devBrowserCookie.remove(attributes); + + // Also remove non-partitioned variants — the browser treats partitioned and + // non-partitioned cookies with the same name as distinct cookies. + if (attributes.partitioned) { + suffixedDevBrowserCookie.remove(); + devBrowserCookie.remove(); + } }; return { diff --git a/packages/clerk-js/src/core/auth/cookies/session.ts b/packages/clerk-js/src/core/auth/cookies/session.ts index abb91d54677..2e247f57976 100644 --- a/packages/clerk-js/src/core/auth/cookies/session.ts +++ b/packages/clerk-js/src/core/auth/cookies/session.ts @@ -14,11 +14,16 @@ export type SessionCookieHandler = { get: () => string | undefined; }; -const getCookieAttributes = (): { sameSite: string; secure: boolean; partitioned: boolean } => { - const sameSite = __BUILD_VARIANT_CHIPS__ ? 'None' : inCrossOriginIframe() || requiresSameSiteNone() ? 'None' : 'Lax'; +export type SessionCookieOptions = { + usePartitionedCookies: () => boolean; +}; + +const getCookieAttributes = (options: SessionCookieOptions) => { + const isPartitioned = options.usePartitionedCookies(); + const sameSite = isPartitioned || inCrossOriginIframe() || requiresSameSiteNone() ? 'None' : 'Lax'; const secure = getSecureAttribute(sameSite); - const partitioned = __BUILD_VARIANT_CHIPS__ && secure; - return { sameSite, secure, partitioned }; + const partitioned = isPartitioned && secure; + return { sameSite, secure, partitioned } as const; }; /** @@ -26,24 +31,32 @@ const getCookieAttributes = (): { sameSite: string; secure: boolean; partitioned * The cookie is used by the Clerk backend SDKs to identify * the authenticated user. */ -export const createSessionCookie = (cookieSuffix: string): SessionCookieHandler => { +export const createSessionCookie = (cookieSuffix: string, options: SessionCookieOptions): SessionCookieHandler => { const sessionCookie = createCookieHandler(SESSION_COOKIE_NAME); const suffixedSessionCookie = createCookieHandler(getSuffixedCookieName(SESSION_COOKIE_NAME, cookieSuffix)); const remove = () => { - const attributes = getCookieAttributes(); + const attributes = getCookieAttributes(options); sessionCookie.remove(attributes); suffixedSessionCookie.remove(attributes); + + // Also remove non-partitioned variants — the browser treats partitioned and + // non-partitioned cookies with the same name as distinct cookies. + if (attributes.partitioned) { + sessionCookie.remove(); + suffixedSessionCookie.remove(); + } }; const set = (token: string) => { const expires = addYears(Date.now(), 1); - const { sameSite, secure, partitioned } = getCookieAttributes(); + const { sameSite, secure, partitioned } = getCookieAttributes(options); - // If setting Partitioned to true, remove the existing session cookies. - // This is to avoid conflicts with the same cookie name without Partitioned attribute. + // Remove old non-partitioned cookies — the browser treats partitioned and + // non-partitioned cookies with the same name as distinct cookies. if (partitioned) { - remove(); + sessionCookie.remove(); + suffixedSessionCookie.remove(); } sessionCookie.set(token, { expires, sameSite, secure, partitioned }); diff --git a/packages/clerk-js/src/core/auth/devBrowser.ts b/packages/clerk-js/src/core/auth/devBrowser.ts index c8a498f599d..9311e5c8d7a 100644 --- a/packages/clerk-js/src/core/auth/devBrowser.ts +++ b/packages/clerk-js/src/core/auth/devBrowser.ts @@ -5,6 +5,7 @@ import type { ClerkAPIErrorJSON } from '@clerk/shared/types'; import { isDevOrStagingUrl } from '../../utils'; import { clerkErrorDevInitFailed } from '../errors'; import type { FapiClient } from '../fapiClient'; +import type { DevBrowserCookieOptions } from './cookies/devBrowser'; import { createDevBrowserCookie } from './cookies/devBrowser'; export interface DevBrowser { @@ -17,16 +18,24 @@ export interface DevBrowser { setDevBrowserJWT(jwt: string): void; removeDevBrowserJWT(): void; + + refreshCookies(): void; } export type CreateDevBrowserOptions = { frontendApi: string; cookieSuffix: string; fapiClient: FapiClient; + cookieOptions: DevBrowserCookieOptions; }; -export function createDevBrowser({ cookieSuffix, frontendApi, fapiClient }: CreateDevBrowserOptions): DevBrowser { - const devBrowserCookie = createDevBrowserCookie(cookieSuffix); +export function createDevBrowser({ + cookieSuffix, + frontendApi, + fapiClient, + cookieOptions, +}: CreateDevBrowserOptions): DevBrowser { + const devBrowserCookie = createDevBrowserCookie(cookieSuffix, cookieOptions); function getDevBrowserJWT() { return devBrowserCookie.get(); @@ -99,11 +108,19 @@ export function createDevBrowser({ cookieSuffix, frontendApi, fapiClient }: Crea setDevBrowserJWT(data?.id); } + function refreshCookies() { + const jwt = getDevBrowserJWT(); + if (jwt) { + setDevBrowserJWT(jwt); + } + } + return { clear, setup, getDevBrowserJWT, setDevBrowserJWT, removeDevBrowserJWT, + refreshCookies, }; } diff --git a/packages/clerk-js/src/core/resources/Environment.ts b/packages/clerk-js/src/core/resources/Environment.ts index f057787a747..b474760286e 100644 --- a/packages/clerk-js/src/core/resources/Environment.ts +++ b/packages/clerk-js/src/core/resources/Environment.ts @@ -22,6 +22,7 @@ export class Environment extends BaseResource implements EnvironmentResource { displayConfig: DisplayConfigResource = new DisplayConfig(); maintenanceMode: boolean = false; clientDebugMode: boolean = false; + partitionedCookies: boolean = false; pathRoot = '/environment'; userSettings: UserSettingsResource = new UserSettings(); organizationSettings: OrganizationSettingsResource = new OrganizationSettings(); @@ -52,6 +53,7 @@ export class Environment extends BaseResource implements EnvironmentResource { this.displayConfig = new DisplayConfig(data.display_config); this.maintenanceMode = this.withDefault(data.maintenance_mode, this.maintenanceMode); this.clientDebugMode = this.withDefault(data.client_debug_mode, this.clientDebugMode); + this.partitionedCookies = this.withDefault(data.partitioned_cookies, this.partitionedCookies); this.organizationSettings = new OrganizationSettings(data.organization_settings); this.userSettings = new UserSettings(data.user_settings); this.commerceSettings = new CommerceSettings(data.commerce_settings); @@ -94,6 +96,7 @@ export class Environment extends BaseResource implements EnvironmentResource { id: this.id ?? '', maintenance_mode: this.maintenanceMode, client_debug_mode: this.clientDebugMode, + partitioned_cookies: this.partitionedCookies, organization_settings: this.organizationSettings.__internal_toSnapshot(), user_settings: this.userSettings.__internal_toSnapshot(), commerce_settings: this.commerceSettings.__internal_toSnapshot(), diff --git a/packages/clerk-js/src/global.d.ts b/packages/clerk-js/src/global.d.ts index 7751ef82378..44ce8ced094 100644 --- a/packages/clerk-js/src/global.d.ts +++ b/packages/clerk-js/src/global.d.ts @@ -11,7 +11,6 @@ declare const __DEV__: boolean; * Build time feature flags. */ declare const __BUILD_DISABLE_RHC__: string; -declare const __BUILD_VARIANT_CHIPS__: boolean; interface Window { __unstable__onBeforeSetActive: (intent?: 'sign-out') => Promise | void; diff --git a/packages/clerk-js/vitest.config.mts b/packages/clerk-js/vitest.config.mts index c74923a9bfd..75c361e1f71 100644 --- a/packages/clerk-js/vitest.config.mts +++ b/packages/clerk-js/vitest.config.mts @@ -26,7 +26,6 @@ export default defineConfig({ plugins: [react({ jsxRuntime: 'automatic', jsxImportSource: '@emotion/react' }), viteSvgMockPlugin()], define: { __BUILD_DISABLE_RHC__: JSON.stringify(false), - __BUILD_VARIANT_CHIPS__: JSON.stringify(false), __PKG_NAME__: JSON.stringify('@clerk/clerk-js'), __PKG_VERSION__: JSON.stringify('test'), }, @@ -40,7 +39,6 @@ export default defineConfig({ 'src/**/*.d.ts', 'src/**/index.ts', 'src/**/index.browser.ts', - 'src/**/index.chips.browser.ts', 'src/**/index.headless.ts', 'src/**/index.headless.browser.ts', 'src/**/index.legacy.browser.ts', diff --git a/packages/shared/src/types/environment.ts b/packages/shared/src/types/environment.ts index 5a81ea75d8f..528cbafd640 100644 --- a/packages/shared/src/types/environment.ts +++ b/packages/shared/src/types/environment.ts @@ -22,5 +22,6 @@ export interface EnvironmentResource extends ClerkResource { onWindowLocationHost: () => boolean; maintenanceMode: boolean; clientDebugMode: boolean; + partitionedCookies: boolean; __internal_toSnapshot: () => EnvironmentJSONSnapshot; } diff --git a/packages/shared/src/types/json.ts b/packages/shared/src/types/json.ts index 783395c5fa9..ad2107cf069 100644 --- a/packages/shared/src/types/json.ts +++ b/packages/shared/src/types/json.ts @@ -90,6 +90,7 @@ export interface EnvironmentJSON extends ClerkResourceJSON { display_config: DisplayConfigJSON; maintenance_mode: boolean; organization_settings: OrganizationSettingsJSON; + partitioned_cookies?: boolean; user_settings: UserSettingsJSON; protect_config: ProtectConfigJSON; }