From 1d767d74f1214d6008a53185a3b507e176a2c173 Mon Sep 17 00:00:00 2001 From: Nikos Douvlis Date: Thu, 4 Dec 2025 16:44:14 +0200 Subject: [PATCH 01/41] fix(e2e): update package links in astro preset and metro config --- integration/presets/astro.ts | 2 +- integration/templates/expo-web/metro.config.js | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/integration/presets/astro.ts b/integration/presets/astro.ts index 65cbebff911..a45c421e23e 100644 --- a/integration/presets/astro.ts +++ b/integration/presets/astro.ts @@ -11,7 +11,7 @@ const astroNode = applicationConfig() .addScript('build', 'pnpm build') .addScript('serve', 'pnpm preview') .addDependency('@clerk/astro', linkPackage('astro', 'integration')) - .addDependency('@clerk/shared', linkPackage('types', 'integration')) + .addDependency('@clerk/shared', linkPackage('shared', 'integration')) .addDependency('@clerk/localizations', linkPackage('localizations', 'integration')); const astroStatic = astroNode.clone().setName('astro-hybrid').useTemplate(templates['astro-hybrid']); diff --git a/integration/templates/expo-web/metro.config.js b/integration/templates/expo-web/metro.config.js index 045418d1e79..c0f9eee8d78 100644 --- a/integration/templates/expo-web/metro.config.js +++ b/integration/templates/expo-web/metro.config.js @@ -51,8 +51,8 @@ if (clerkMonorepoPath) { // Explicitly map @clerk packages to their source locations // Point to the root of the package so Metro can properly resolve subpath exports config.resolver.extraNodeModules = { - '@clerk/clerk-react': path.resolve(clerkMonorepoPath, 'packages/react'), - '@clerk/clerk-expo': path.resolve(clerkMonorepoPath, 'packages/expo'), + '@clerk/react': path.resolve(clerkMonorepoPath, 'packages/react'), + '@clerk/expo': path.resolve(clerkMonorepoPath, 'packages/expo'), '@clerk/shared': path.resolve(clerkMonorepoPath, 'packages/shared'), '@clerk/types': path.resolve(clerkMonorepoPath, 'packages/types'), }; @@ -87,7 +87,7 @@ if (clerkMonorepoPath) { ]; // Custom resolver to handle package.json subpath exports for @clerk packages - // This enables Metro to resolve imports like '@clerk/clerk-react/internal' + // This enables Metro to resolve imports like '@clerk/react/internal' const originalResolveRequest = config.resolver.resolveRequest; config.resolver.resolveRequest = (context, moduleName, platform) => { // Check if this is a @clerk package with a subpath From 8d0340db08fa7df0e8449dbff7c477f97778f78b Mon Sep 17 00:00:00 2001 From: Nikos Douvlis Date: Thu, 4 Dec 2025 20:18:25 +0200 Subject: [PATCH 02/41] chore(repo): fix billing error flows --- integration/presets/envs.ts | 5 +- integration/presets/longRunningApps.ts | 3 - integration/testUtils/usersService.ts | 83 ++++++++++++------- integration/tests/billing-hooks.test.ts | 3 +- integration/tests/pricing-table.test.ts | 7 +- package.json | 2 +- .../src/core/resources/BillingCheckout.ts | 1 - packages/clerk-js/src/core/signals.ts | 1 - packages/shared/src/loadScript.ts | 2 - packages/ui/package.json | 3 +- packages/ui/rspack.config.js | 5 +- .../src/components/Checkout/CheckoutPage.tsx | 8 +- packages/ui/src/components/Checkout/parts.tsx | 7 +- .../InviteMembersScreen.tsx | 3 - .../OrganizationMembers.tsx | 2 +- packages/ui/tsconfig.json | 2 +- packages/ui/tsdown.config.mts | 1 + 17 files changed, 83 insertions(+), 55 deletions(-) diff --git a/integration/presets/envs.ts b/integration/presets/envs.ts index 6135840636f..a166fda6228 100644 --- a/integration/presets/envs.ts +++ b/integration/presets/envs.ts @@ -165,9 +165,8 @@ const withSessionTasksResetPassword = base const withBillingJwtV2 = base .clone() .setId('withBillingJwtV2') - .setEnvVariable('private', 'CLERK_API_URL', 'https://api.clerkstage.dev') - .setEnvVariable('private', 'CLERK_SECRET_KEY', instanceKeys.get('with-billing-staging').sk) - .setEnvVariable('public', 'CLERK_PUBLISHABLE_KEY', instanceKeys.get('with-billing-staging').pk); + .setEnvVariable('private', 'CLERK_SECRET_KEY', instanceKeys.get('with-billing').sk) + .setEnvVariable('public', 'CLERK_PUBLISHABLE_KEY', instanceKeys.get('with-billing').pk); const withBilling = base .clone() diff --git a/integration/presets/longRunningApps.ts b/integration/presets/longRunningApps.ts index a14e3c9ef83..4db25199ff1 100644 --- a/integration/presets/longRunningApps.ts +++ b/integration/presets/longRunningApps.ts @@ -42,9 +42,7 @@ export const createLongRunningApps = () => { * Billing apps */ { id: 'withBillingJwtV2.next.appRouter', config: next.appRouter, env: envs.withBillingJwtV2 }, - { id: 'withBilling.next.appRouter', config: next.appRouter, env: envs.withBilling }, { id: 'withBillingJwtV2.vue.vite', config: vue.vite, env: envs.withBillingJwtV2 }, - { id: 'withBilling.vue.vite', config: vue.vite, env: envs.withBilling }, /** * Machine auth apps @@ -68,7 +66,6 @@ export const createLongRunningApps = () => { /** * Various apps - basic flows */ - { id: 'withBilling.astro.node', config: astro.node, env: envs.withBilling }, { id: 'astro.node.withCustomRoles', config: astro.node, env: envs.withCustomRoles }, { id: 'astro.static.withCustomRoles', config: astro.static, env: envs.withCustomRoles }, { id: 'expo.expo-web', config: expo.expoWeb, env: envs.withEmailCodes }, diff --git a/integration/testUtils/usersService.ts b/integration/testUtils/usersService.ts index 52814990c92..eecab30dbf4 100644 --- a/integration/testUtils/usersService.ts +++ b/integration/testUtils/usersService.ts @@ -3,6 +3,19 @@ import { faker } from '@faker-js/faker'; import { hash } from '../models/helpers'; +async function withErrorLogging(operation: string, fn: () => Promise): Promise { + try { + return await fn(); + } catch (e: any) { + console.error(`[usersService] ${operation} failed:`); + console.error(' Status:', e.status); + console.error(' Message:', e.message); + console.error(' Errors:', JSON.stringify(e.errors, null, 2)); + console.error(' Clerk Trace ID:', e.clerkTraceId); + throw e; + } +} + type FakeUserOptions = { /** * A fictional email is an email that contains +clerk_test and can always be verified using 424242 as the OTP. No email will be sent. @@ -126,15 +139,17 @@ export const createUserService = (clerkClient: ClerkClient) => { }; }, createBapiUser: async fakeUser => { - return await clerkClient.users.createUser({ - emailAddress: fakeUser.email !== undefined ? [fakeUser.email] : undefined, - password: fakeUser.password, - firstName: fakeUser.firstName, - lastName: fakeUser.lastName, - phoneNumber: fakeUser.phoneNumber !== undefined ? [fakeUser.phoneNumber] : undefined, - username: fakeUser.username, - skipPasswordRequirement: fakeUser.password === undefined, - }); + return withErrorLogging('createBapiUser', () => + clerkClient.users.createUser({ + emailAddress: fakeUser.email !== undefined ? [fakeUser.email] : undefined, + password: fakeUser.password, + firstName: fakeUser.firstName, + lastName: fakeUser.lastName, + phoneNumber: fakeUser.phoneNumber !== undefined ? [fakeUser.phoneNumber] : undefined, + username: fakeUser.username, + skipPasswordRequirement: fakeUser.password === undefined, + }), + ); }, getOrCreateUser: async fakeUser => { const existingUser = await self.getUser({ email: fakeUser.email }); @@ -147,10 +162,12 @@ export const createUserService = (clerkClient: ClerkClient) => { let id = opts.id; if (!id) { - const { data: users } = await clerkClient.users.getUserList({ - emailAddress: [opts.email], - phoneNumber: [opts.phoneNumber], - }); + const { data: users } = await withErrorLogging('getUserList', () => + clerkClient.users.getUserList({ + emailAddress: [opts.email], + phoneNumber: [opts.phoneNumber], + }), + ); id = users[0]?.id; } @@ -159,12 +176,12 @@ export const createUserService = (clerkClient: ClerkClient) => { return; } - await clerkClient.users.deleteUser(id); + await withErrorLogging('deleteUser', () => clerkClient.users.deleteUser(id)); }, getUser: async (opts: { id?: string; email?: string }) => { if (opts.id) { try { - const user = await clerkClient.users.getUser(opts.id); + const user = await withErrorLogging('getUser', () => clerkClient.users.getUser(opts.id)); return user; } catch (err) { console.log(`Error fetching user "${opts.id}": ${err.message}`); @@ -173,7 +190,9 @@ export const createUserService = (clerkClient: ClerkClient) => { } if (opts.email) { - const { data: users } = await clerkClient.users.getUserList({ emailAddress: [opts.email] }); + const { data: users } = await withErrorLogging('getUserList', () => + clerkClient.users.getUserList({ emailAddress: [opts.email] }), + ); if (users.length > 0) { return users[0]; } else { @@ -186,33 +205,41 @@ export const createUserService = (clerkClient: ClerkClient) => { }, createFakeOrganization: async userId => { const name = faker.animal.dog(); - const organization = await clerkClient.organizations.createOrganization({ - name: faker.animal.dog(), - createdBy: userId, - }); + const organization = await withErrorLogging('createOrganization', () => + clerkClient.organizations.createOrganization({ + name: faker.animal.dog(), + createdBy: userId, + }), + ); return { name, organization, - delete: () => clerkClient.organizations.deleteOrganization(organization.id), + delete: () => + withErrorLogging('deleteOrganization', () => clerkClient.organizations.deleteOrganization(organization.id)), } satisfies FakeOrganization; }, createFakeAPIKey: async (userId: string) => { const TWENTY_MINUTES = 20 * 60; - const apiKey = await clerkClient.apiKeys.create({ - subject: userId, - name: `Integration Test - ${faker.string.uuid()}`, - secondsUntilExpiration: TWENTY_MINUTES, - }); + const apiKey = await withErrorLogging('createAPIKey', () => + clerkClient.apiKeys.create({ + subject: userId, + name: `Integration Test - ${faker.string.uuid()}`, + secondsUntilExpiration: TWENTY_MINUTES, + }), + ); return { apiKey, secret: apiKey.secret ?? '', - revoke: () => clerkClient.apiKeys.revoke({ apiKeyId: apiKey.id, revocationReason: 'For testing purposes' }), + revoke: () => + withErrorLogging('revokeAPIKey', () => + clerkClient.apiKeys.revoke({ apiKeyId: apiKey.id, revocationReason: 'For testing purposes' }), + ), } satisfies FakeAPIKey; }, passwordCompromised: async (userId: string) => { - await clerkClient.users.__experimental_passwordCompromised(userId); + await withErrorLogging('passwordCompromised', () => clerkClient.users.__experimental_passwordCompromised(userId)); }, }; diff --git a/integration/tests/billing-hooks.test.ts b/integration/tests/billing-hooks.test.ts index 48c441e6104..daa474f52a4 100644 --- a/integration/tests/billing-hooks.test.ts +++ b/integration/tests/billing-hooks.test.ts @@ -1,10 +1,9 @@ import { expect, test } from '@playwright/test'; -import { appConfigs } from '../presets'; import type { FakeUser } from '../testUtils'; import { createTestUtils, testAgainstRunningApps } from '../testUtils'; -testAgainstRunningApps({ withEnv: [appConfigs.envs.withBilling] })('billing hooks @billing', ({ app }) => { +testAgainstRunningApps({})('billing hooks @billing', ({ app }) => { test.describe.configure({ mode: 'parallel' }); test.skip(!app.name.includes('next'), 'Skipping: Only runs on next'); diff --git a/integration/tests/pricing-table.test.ts b/integration/tests/pricing-table.test.ts index bdc61418b6c..cc7ea3b5dd4 100644 --- a/integration/tests/pricing-table.test.ts +++ b/integration/tests/pricing-table.test.ts @@ -1,11 +1,10 @@ import type { Locator } from '@playwright/test'; import { expect, test } from '@playwright/test'; -import { appConfigs } from '../presets'; import type { FakeUser } from '../testUtils'; import { createTestUtils, testAgainstRunningApps } from '../testUtils'; -testAgainstRunningApps({ withEnv: [appConfigs.envs.withBilling] })('pricing table @billing', ({ app }) => { +testAgainstRunningApps({})('pricing table @billing', ({ app }) => { test.describe.configure({ mode: 'parallel' }); let fakeUser: FakeUser; @@ -236,6 +235,7 @@ testAgainstRunningApps({ withEnv: [appConfigs.envs.withBilling] })('pricing tabl await u.po.pricingTable.startCheckout({ planSlug: 'plus' }); await u.po.checkout.waitForMounted(); await expect(u.po.page.getByText('Checkout')).toBeVisible(); + await page.pause(); await expect(u.po.page.getByText(/^Add an email address$/i)).toBeVisible(); const newFakeUser = u.services.users.createFakeUser(); @@ -639,7 +639,7 @@ testAgainstRunningApps({ withEnv: [appConfigs.envs.withBilling] })('pricing tabl await fakeUser.deleteIfExists(); }); - test('displays notice then plan cannot change', async ({ page, context }) => { + test('displays notice the plan cannot change', async ({ page, context }) => { const u = createTestUtils({ app, page, context }); const fakeUser = u.services.users.createFakeUser(); @@ -657,7 +657,6 @@ testAgainstRunningApps({ withEnv: [appConfigs.envs.withBilling] })('pricing tabl await u.po.checkout.fillTestCard(); await u.po.checkout.clickPayOrSubscribe(); await expect(u.po.page.getByText('Payment was successful!')).toBeVisible(); - await u.po.checkout.confirmAndContinue(); await u.po.pricingTable.startCheckout({ planSlug: 'pro', shouldSwitch: true, period: 'monthly' }); await u.po.checkout.waitForMounted(); diff --git a/package.json b/package.json index d5ec6d85fb1..94904669e28 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "test:integration:ap-flows": "pnpm test:integration:base --grep @ap-flows", "test:integration:astro": "E2E_APP_ID=astro.* pnpm test:integration:base --grep @astro", "test:integration:base": "pnpm playwright test --config integration/playwright.config.ts", - "test:integration:billing": "E2E_APP_ID=withBilling.* pnpm test:integration:base --grep @billing", + "test:integration:billing": "E2E_DEBUG=1 E2E_APP_ID=withBillingJwtV2.* pnpm test:integration:base --grep @billing", "test:integration:cleanup": "pnpm playwright test --config integration/playwright.cleanup.config.ts", "test:integration:custom": "pnpm test:integration:base --grep @custom", "test:integration:deployment:nextjs": "pnpm playwright test --config integration/playwright.deployments.config.ts", diff --git a/packages/clerk-js/src/core/resources/BillingCheckout.ts b/packages/clerk-js/src/core/resources/BillingCheckout.ts index 0bd0736ebbd..0dbadd220fa 100644 --- a/packages/clerk-js/src/core/resources/BillingCheckout.ts +++ b/packages/clerk-js/src/core/resources/BillingCheckout.ts @@ -109,7 +109,6 @@ export const createSignals = () => { const resource = resourceSignal().resource; const error = errorSignal().error; const fetchStatus = fetchSignal().status; - const errors = errorsToParsedErrors(error, {}); return { errors: errors, fetchStatus, checkout: resource }; }, diff --git a/packages/clerk-js/src/core/signals.ts b/packages/clerk-js/src/core/signals.ts index 2046eca114c..b200154be15 100644 --- a/packages/clerk-js/src/core/signals.ts +++ b/packages/clerk-js/src/core/signals.ts @@ -62,7 +62,6 @@ export function errorsToParsedErrors>( function isFieldError(error: ClerkAPIError): boolean { return 'meta' in error && error.meta && 'paramName' in error.meta && error.meta.paramName !== undefined; } - const hasFieldErrors = error.errors.some(isFieldError); if (hasFieldErrors) { error.errors.forEach(error => { diff --git a/packages/shared/src/loadScript.ts b/packages/shared/src/loadScript.ts index c9fc4a4536d..cd578486066 100644 --- a/packages/shared/src/loadScript.ts +++ b/packages/shared/src/loadScript.ts @@ -36,8 +36,6 @@ export async function loadScript(src = '', opts: LoadScriptOptions): Promise { - console.log('this loaded ', src); - script.remove(); resolve(script); }); diff --git a/packages/ui/package.json b/packages/ui/package.json index 44c4fa809ce..c28f8f99767 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -62,7 +62,8 @@ "showerrors": "tsc", "test:ci": "vitest --maxWorkers=70%", "test:coverage": "vitest --collectCoverage && open coverage/lcov-report/index.html", - "test:disabled": "vitest" + "test:disabled": "vitest", + "type-check": "tsc --noEmit" }, "dependencies": { "@clerk/localizations": "workspace:^", diff --git a/packages/ui/rspack.config.js b/packages/ui/rspack.config.js index fa31862617d..b3129302689 100644 --- a/packages/ui/rspack.config.js +++ b/packages/ui/rspack.config.js @@ -44,6 +44,7 @@ const common = ({ mode, variant }) => { PACKAGE_VERSION: JSON.stringify(packageJSON.version), __PKG_VERSION__: JSON.stringify(packageJSON.version), PACKAGE_NAME: JSON.stringify(packageJSON.name), + __BUILD_DISABLE_RHC__: JSON.stringify(false), }), new rspack.EnvironmentPlugin({ NODE_ENV: mode, @@ -166,7 +167,7 @@ const devConfig = (mode, env) => { rules: [svgLoader(), ...typescriptLoaderDev()], }, plugins: [new ReactRefreshPlugin({ overlay: { sockHost: devUrl.host } })], - devtool: 'eval-cheap-source-map', + devtool: 'eval-source-map', output: { publicPath: `${devUrl.origin}/npm/`, crossOriginLoading: 'anonymous', @@ -175,6 +176,8 @@ const devConfig = (mode, env) => { }, optimization: { minimize: false, + usedExports: false, + providedExports: false, }, devServer: { allowedHosts: ['all'], diff --git a/packages/ui/src/components/Checkout/CheckoutPage.tsx b/packages/ui/src/components/Checkout/CheckoutPage.tsx index 8fd50eabb86..a159848038b 100644 --- a/packages/ui/src/components/Checkout/CheckoutPage.tsx +++ b/packages/ui/src/components/Checkout/CheckoutPage.tsx @@ -61,7 +61,13 @@ const FetchStatus = ({ const internalFetchStatus = useMemo(() => { if (errors.global) { - const errorCodes = errors.global.map(e => e.code); + const errorCodes = errors.global.flatMap(e => { + if (e.isClerkApiResponseError()) { + return e.errors.map(e => e.code); + } + }); + + console.log({ errorCodes }); if (errorCodes.includes('missing_payer_email')) { return 'missing_payer_email'; diff --git a/packages/ui/src/components/Checkout/parts.tsx b/packages/ui/src/components/Checkout/parts.tsx index fa083985990..8a0a882ce59 100644 --- a/packages/ui/src/components/Checkout/parts.tsx +++ b/packages/ui/src/components/Checkout/parts.tsx @@ -41,12 +41,15 @@ export const InvalidPlanScreen = () => { const { planPeriod } = useCheckoutContext(); const { errors } = useCheckout(); - const InvalidPlanError = errors?.global?.find(e => e.code === 'invalid_plan_change'); + const InvalidPlanError = errors?.global + ?.filter(e => e.isClerkApiResponseError()) + .flatMap(e => e.errors) + .find(e => e.code === 'invalid_plan_change'); + if (!InvalidPlanError) { return null; } - // @ts-expect-error - meta is not a property of FieldError const { plan: planFromError, isPlanUpgradePossible } = InvalidPlanError?.meta || {}; return ( diff --git a/packages/ui/src/components/OrganizationProfile/InviteMembersScreen.tsx b/packages/ui/src/components/OrganizationProfile/InviteMembersScreen.tsx index 5d24d2a3641..f6d493b2812 100644 --- a/packages/ui/src/components/OrganizationProfile/InviteMembersScreen.tsx +++ b/packages/ui/src/components/OrganizationProfile/InviteMembersScreen.tsx @@ -1,5 +1,4 @@ import { useOrganization } from '@clerk/shared/react'; -import { runIfFunctionOrReturn } from '@clerk/shared/utils'; import { useCardState, withCardStateProvider } from '@/ui/elements/contexts'; import { FormContainer } from '@/ui/elements/FormContainer'; @@ -7,12 +6,10 @@ import { IconCircle } from '@/ui/elements/IconCircle'; import { SuccessPage } from '@/ui/elements/SuccessPage'; import { useWizard, Wizard } from '../../common'; -import { useOrganizationProfileContext } from '../../contexts'; import { descriptors, Flex, localizationKeys, Text } from '../../customizables'; import { useActionContext } from '../../elements/Action/ActionRoot'; import { Email } from '../../icons'; import { InviteMembersForm } from './InviteMembersForm'; - type InviteMembersScreenProps = { onReset?: () => void; }; diff --git a/packages/ui/src/components/OrganizationProfile/OrganizationMembers.tsx b/packages/ui/src/components/OrganizationProfile/OrganizationMembers.tsx index da882250469..2ce5d4ab645 100644 --- a/packages/ui/src/components/OrganizationProfile/OrganizationMembers.tsx +++ b/packages/ui/src/components/OrganizationProfile/OrganizationMembers.tsx @@ -8,7 +8,7 @@ import { Header } from '@/ui/elements/Header'; import { Tab, TabPanel, TabPanels, Tabs, TabsList } from '@/ui/elements/Tabs'; import { NotificationCountBadge, useProtect } from '../../common'; -import { useEnvironment, useOrganizationProfileContext } from '../../contexts'; +import { useEnvironment } from '../../contexts'; import { Col, descriptors, Flex, localizationKeys } from '../../customizables'; import { Action } from '../../elements/Action'; import { mqu } from '../../styledSystem'; diff --git a/packages/ui/tsconfig.json b/packages/ui/tsconfig.json index 8c4013283ec..b1cdc8add12 100644 --- a/packages/ui/tsconfig.json +++ b/packages/ui/tsconfig.json @@ -29,6 +29,6 @@ "@/ui*": ["./src/*"] } }, - "exclude": ["node_modules", "**/*.test.ts", "**/*.test.tsx", "**/*.spec.ts", "**/*.spec.tsx"], + "exclude": ["node_modules", "**/*.test.ts", "**/*.test.tsx", "**/*.spec.ts", "**/*.spec.tsx", "**/__tests__/**"], "include": ["src", "src/global.d.ts"] } diff --git a/packages/ui/tsdown.config.mts b/packages/ui/tsdown.config.mts index d97ec74fb8e..2a7fdac4473 100644 --- a/packages/ui/tsdown.config.mts +++ b/packages/ui/tsdown.config.mts @@ -20,6 +20,7 @@ export default defineConfig(({ watch }) => { PACKAGE_VERSION: `"${uiPackage.version}"`, __PKG_VERSION__: `"${uiPackage.version}"`, __DEV__: `${watch}`, + __BUILD_DISABLE_RHC__: JSON.stringify(false), }, } satisfies Options; From fbcdd5754f42c49014252eadd1fb061ad39f2064 Mon Sep 17 00:00:00 2001 From: Nikos Douvlis Date: Fri, 5 Dec 2025 13:34:34 +0200 Subject: [PATCH 03/41] refactor(ui,js): remove DevTools resource and integrate enableEnvironmentSetting into Environment resource --- .../clerk-js/src/core/resources/DevTools.ts | 21 ------------------- .../src/core/resources/Environment.ts | 8 +++++++ packages/clerk-js/src/core/resources/index.ts | 1 - packages/shared/src/types/environment.ts | 2 ++ .../EnableOrganizationsPrompt/index.tsx | 2 +- 5 files changed, 11 insertions(+), 23 deletions(-) delete mode 100644 packages/clerk-js/src/core/resources/DevTools.ts diff --git a/packages/clerk-js/src/core/resources/DevTools.ts b/packages/clerk-js/src/core/resources/DevTools.ts deleted file mode 100644 index 9a517858604..00000000000 --- a/packages/clerk-js/src/core/resources/DevTools.ts +++ /dev/null @@ -1,21 +0,0 @@ -import type { ClerkResourceJSON, DevToolsResource, EnableEnvironmentSettingParams } from '@clerk/shared/types'; - -import { BaseResource } from './Base'; - -/** - * @internal - */ -export class DevTools extends BaseResource implements DevToolsResource { - pathRoot = '/dev_tools'; - - protected fromJSON(_data: ClerkResourceJSON | null): this { - return this; - } - - async __internal_enableEnvironmentSetting(params: EnableEnvironmentSettingParams) { - await this._basePatch({ - path: `${this.pathRoot}/enable_environment_setting`, - body: params, - }); - } -} diff --git a/packages/clerk-js/src/core/resources/Environment.ts b/packages/clerk-js/src/core/resources/Environment.ts index f057787a747..5e961e3f354 100644 --- a/packages/clerk-js/src/core/resources/Environment.ts +++ b/packages/clerk-js/src/core/resources/Environment.ts @@ -2,6 +2,7 @@ import type { AuthConfigResource, CommerceSettingsResource, DisplayConfigResource, + EnableEnvironmentSettingParams, EnvironmentJSON, EnvironmentJSONSnapshot, EnvironmentResource, @@ -101,4 +102,11 @@ export class Environment extends BaseResource implements EnvironmentResource { protect_config: this.protectConfig.__internal_toSnapshot(), }; } + + async __internal_enableEnvironmentSetting(params: EnableEnvironmentSettingParams) { + await this._basePatch({ + path: `/dev_tools/enable_environment_setting`, + body: params, + }); + } } diff --git a/packages/clerk-js/src/core/resources/index.ts b/packages/clerk-js/src/core/resources/index.ts index d137d5d588b..b07196edac8 100644 --- a/packages/clerk-js/src/core/resources/index.ts +++ b/packages/clerk-js/src/core/resources/index.ts @@ -1,7 +1,6 @@ export * from './AuthConfig'; export * from './Client'; export * from './DeletedObject'; -export * from './DevTools'; export * from './DisplayConfig'; export * from './EmailAddress'; export * from './Environment'; diff --git a/packages/shared/src/types/environment.ts b/packages/shared/src/types/environment.ts index 5a81ea75d8f..1176bc03226 100644 --- a/packages/shared/src/types/environment.ts +++ b/packages/shared/src/types/environment.ts @@ -1,6 +1,7 @@ import type { APIKeysSettingsResource } from './apiKeysSettings'; import type { AuthConfigResource } from './authConfig'; import type { CommerceSettingsResource } from './commerceSettings'; +import type { EnableEnvironmentSettingParams } from './devtools'; import type { DisplayConfigResource } from './displayConfig'; import type { OrganizationSettingsResource } from './organizationSettings'; import type { ProtectConfigResource } from './protectConfig'; @@ -23,4 +24,5 @@ export interface EnvironmentResource extends ClerkResource { maintenanceMode: boolean; clientDebugMode: boolean; __internal_toSnapshot: () => EnvironmentJSONSnapshot; + __internal_enableEnvironmentSetting: (params: EnableEnvironmentSettingParams) => Promise; } diff --git a/packages/ui/src/components/devPrompts/EnableOrganizationsPrompt/index.tsx b/packages/ui/src/components/devPrompts/EnableOrganizationsPrompt/index.tsx index aab44a915e0..0be43788a0e 100644 --- a/packages/ui/src/components/devPrompts/EnableOrganizationsPrompt/index.tsx +++ b/packages/ui/src/components/devPrompts/EnableOrganizationsPrompt/index.tsx @@ -46,7 +46,7 @@ const EnableOrganizationsPromptInternal = ({ params.organization_allow_personal_accounts = allowPersonalAccount; } - void new DevTools() + void environment .__internal_enableEnvironmentSetting(params) .then(() => { setIsEnabled(true); From b1bd64274ad8b1959a325c3719a9a57094114ef8 Mon Sep 17 00:00:00 2001 From: Nikos Douvlis Date: Fri, 5 Dec 2025 14:03:00 +0200 Subject: [PATCH 04/41] fix(e2e): fix generic tests debg --- .github/workflows/ci.yml | 81 +++++++++---------- .../templates/astro-hybrid/astro.config.mjs | 11 ++- .../templates/astro-node/astro.config.mjs | 12 ++- .../custom-flows-react-vite/src/main.tsx | 5 ++ .../templates/expo-web/app/_layout.tsx | 5 ++ .../src/app/layout.tsx | 8 +- .../(tests)/has-ssr/page.tsx | 9 ++- .../next-app-router/src/app/layout.tsx | 1 + .../src/app/settings/useAuth-has/layout.tsx | 13 ++- .../templates/nuxt-node/nuxt.config.js | 7 ++ integration/templates/react-cra/src/index.tsx | 5 ++ .../react-router-library/src/main.tsx | 9 ++- .../templates/react-router-node/app/root.tsx | 9 ++- integration/templates/react-vite/src/main.tsx | 6 ++ .../src/routes/__root.tsx | 8 +- integration/templates/vue-vite/src/main.ts | 5 ++ package.json | 2 +- .../ui/src/components/SignUp/SignUpStart.tsx | 1 + 18 files changed, 147 insertions(+), 50 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d65f4832ed1..db26916ad50 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -295,54 +295,53 @@ jobs: strategy: fail-fast: false matrix: - test-name: - [ + test-name: [ "generic", - "express", - "ap-flows", - "localhost", - "sessions", - "sessions:staging", - "handshake", - "handshake:staging", - "astro", - "tanstack-react-start", - "vue", - "nuxt", - "react-router", - "custom", + # "express", + # "ap-flows", + # "localhost", + # "sessions", + # "sessions:staging", + # "handshake", + # "handshake:staging", + # "astro", + # "tanstack-react-start", + # "vue", + # "nuxt", + # "react-router", + # "custom", ] test-project: ["chrome"] include: - - test-name: "billing" - test-project: "chrome" - clerk-use-rq: "false" - - test-name: "billing" - test-project: "chrome" - clerk-use-rq: "true" - - test-name: "machine" - test-project: "chrome" - clerk-use-rq: "false" - - test-name: "machine" - test-project: "chrome" - clerk-use-rq: "true" + # - test-name: "billing" + # test-project: "chrome" + # clerk-use-rq: "false" + # - test-name: "billing" + # test-project: "chrome" + # clerk-use-rq: "true" + # - test-name: "machine" + # test-project: "chrome" + # clerk-use-rq: "false" + # - test-name: "machine" + # test-project: "chrome" + # clerk-use-rq: "true" + # - test-name: "nextjs" + # test-project: "chrome" + # next-version: "15" + # clerk-use-rq: "false" + # - test-name: "nextjs" + # test-project: "chrome" + # next-version: "15" + # clerk-use-rq: "true" - test-name: "nextjs" - test-project: "chrome" - next-version: "15" - clerk-use-rq: "false" - - test-name: "nextjs" - test-project: "chrome" - next-version: "15" - clerk-use-rq: "true" - - test-name: "nextjs" - test-project: "chrome" - next-version: "16" - - test-name: "quickstart" - test-project: "chrome" - next-version: "15" - - test-name: "quickstart" test-project: "chrome" next-version: "16" + # - test-name: "quickstart" + # test-project: "chrome" + # next-version: "15" + # - test-name: "quickstart" + # test-project: "chrome" + # next-version: "16" steps: - name: Checkout Repo diff --git a/integration/templates/astro-hybrid/astro.config.mjs b/integration/templates/astro-hybrid/astro.config.mjs index 30ff739e8a3..7c6191881e0 100644 --- a/integration/templates/astro-hybrid/astro.config.mjs +++ b/integration/templates/astro-hybrid/astro.config.mjs @@ -4,7 +4,16 @@ import react from '@astrojs/react'; export default defineConfig({ output: 'hybrid', - integrations: [clerk(), react()], + integrations: [ + clerk({ + appearance: { + layout: { + showOptionalFields: true, + }, + }, + }), + react(), + ], server: { port: Number(process.env.PORT), }, diff --git a/integration/templates/astro-node/astro.config.mjs b/integration/templates/astro-node/astro.config.mjs index 6b08d1babd3..e3a2029f8af 100644 --- a/integration/templates/astro-node/astro.config.mjs +++ b/integration/templates/astro-node/astro.config.mjs @@ -10,7 +10,17 @@ export default defineConfig({ adapter: node({ mode: 'standalone', }), - integrations: [clerk(), react(), tailwind()], + integrations: [ + clerk({ + appearance: { + layout: { + showOptionalFields: true, + }, + }, + }), + react(), + tailwind(), + ], server: { port: Number(process.env.PORT), }, diff --git a/integration/templates/custom-flows-react-vite/src/main.tsx b/integration/templates/custom-flows-react-vite/src/main.tsx index 966d034a194..73adedb709c 100644 --- a/integration/templates/custom-flows-react-vite/src/main.tsx +++ b/integration/templates/custom-flows-react-vite/src/main.tsx @@ -23,6 +23,11 @@ createRoot(document.getElementById('root')!).render( publishableKey={PUBLISHABLE_KEY} clerkJSUrl={import.meta.env.VITE_CLERK_JS_URL as string} clerkUiUrl={import.meta.env.VITE_CLERK_UI_URL as string} + appearance={{ + layout: { + showOptionalFields: true, + }, + }} > diff --git a/integration/templates/expo-web/app/_layout.tsx b/integration/templates/expo-web/app/_layout.tsx index 24295ee033d..6ac8a7865f1 100644 --- a/integration/templates/expo-web/app/_layout.tsx +++ b/integration/templates/expo-web/app/_layout.tsx @@ -10,6 +10,11 @@ export default function RootLayout() { routerReplace={to => router.replace(to)} clerkJSUrl={process.env.EXPO_PUBLIC_CLERK_JS_URL} clerkUiUrl={process.env.EXPO_PUBLIC_CLERK_UI_URL} + appearance={{ + layout: { + showOptionalFields: true, + }, + }} > diff --git a/integration/templates/next-app-router-quickstart/src/app/layout.tsx b/integration/templates/next-app-router-quickstart/src/app/layout.tsx index 29ddd566bdb..3bd3fc7f583 100644 --- a/integration/templates/next-app-router-quickstart/src/app/layout.tsx +++ b/integration/templates/next-app-router-quickstart/src/app/layout.tsx @@ -11,7 +11,13 @@ export const metadata = { export default function RootLayout({ children }: { children: React.ReactNode }) { return ( - + {children} diff --git a/integration/templates/next-app-router/src/app/jwt-v2-organizations/(tests)/has-ssr/page.tsx b/integration/templates/next-app-router/src/app/jwt-v2-organizations/(tests)/has-ssr/page.tsx index a7d7102bb50..9db2b40ece4 100644 --- a/integration/templates/next-app-router/src/app/jwt-v2-organizations/(tests)/has-ssr/page.tsx +++ b/integration/templates/next-app-router/src/app/jwt-v2-organizations/(tests)/has-ssr/page.tsx @@ -3,7 +3,14 @@ import { SSR } from './client'; export default function Page() { return ( - + ); diff --git a/integration/templates/next-app-router/src/app/layout.tsx b/integration/templates/next-app-router/src/app/layout.tsx index 2e56184f39d..e28ac2a59a9 100644 --- a/integration/templates/next-app-router/src/app/layout.tsx +++ b/integration/templates/next-app-router/src/app/layout.tsx @@ -14,6 +14,7 @@ export default function RootLayout({ children }: { children: React.ReactNode }) {children}; + return ( + + {children} + + ); } diff --git a/integration/templates/nuxt-node/nuxt.config.js b/integration/templates/nuxt-node/nuxt.config.js index f60e469817f..ec3f44258ad 100644 --- a/integration/templates/nuxt-node/nuxt.config.js +++ b/integration/templates/nuxt-node/nuxt.config.js @@ -1,5 +1,12 @@ export default defineNuxtConfig({ modules: ['@clerk/nuxt'], + clerk: { + appearance: { + layout: { + showOptionalFields: true, + }, + }, + }, devtools: { enabled: false, }, diff --git a/integration/templates/react-cra/src/index.tsx b/integration/templates/react-cra/src/index.tsx index 5a20abd8759..7d678b4db27 100644 --- a/integration/templates/react-cra/src/index.tsx +++ b/integration/templates/react-cra/src/index.tsx @@ -11,6 +11,11 @@ root.render( publishableKey={process.env.REACT_APP_CLERK_PUBLISHABLE_KEY as string} clerkJSUrl={process.env.REACT_APP_CLERK_JS as string} clerkUiUrl={process.env.REACT_APP_CLERK_UI as string} + appearance={{ + layout: { + showOptionalFields: true, + }, + }} > diff --git a/integration/templates/react-router-library/src/main.tsx b/integration/templates/react-router-library/src/main.tsx index 46ab36679fd..2df30642bf6 100644 --- a/integration/templates/react-router-library/src/main.tsx +++ b/integration/templates/react-router-library/src/main.tsx @@ -10,7 +10,14 @@ const PUBLISHABLE_KEY = import.meta.env.VITE_CLERK_PUBLISHABLE_KEY; createRoot(document.getElementById('root')!).render( - + +
diff --git a/integration/templates/react-vite/src/main.tsx b/integration/templates/react-vite/src/main.tsx index f35d944287b..a95be1e5270 100644 --- a/integration/templates/react-vite/src/main.tsx +++ b/integration/templates/react-vite/src/main.tsx @@ -34,12 +34,18 @@ const Root = () => { clerkUiUrl={import.meta.env.VITE_CLERK_UI_URL as string} routerPush={(to: string) => navigate(to)} routerReplace={(to: string) => navigate(to, { replace: true })} + appearance={{ + layout: { + showOptionalFields: true, + }, + }} experimental={{ persistClient: import.meta.env.VITE_EXPERIMENTAL_PERSIST_CLIENT ? import.meta.env.VITE_EXPERIMENTAL_PERSIST_CLIENT === 'true' : undefined, }} > + here?
); diff --git a/integration/templates/tanstack-react-start/src/routes/__root.tsx b/integration/templates/tanstack-react-start/src/routes/__root.tsx index ecf10d8fcc2..f0a344ad963 100644 --- a/integration/templates/tanstack-react-start/src/routes/__root.tsx +++ b/integration/templates/tanstack-react-start/src/routes/__root.tsx @@ -22,7 +22,13 @@ function RootComponent() { function RootDocument({ children }: { children: React.ReactNode }) { return ( - + diff --git a/integration/templates/vue-vite/src/main.ts b/integration/templates/vue-vite/src/main.ts index d8980dd44a8..81bc03bd41e 100644 --- a/integration/templates/vue-vite/src/main.ts +++ b/integration/templates/vue-vite/src/main.ts @@ -10,6 +10,11 @@ app.use(clerkPlugin, { clerkJSUrl: import.meta.env.VITE_CLERK_JS_URL, clerkUiUrl: import.meta.env.VITE_CLERK_UI_URL, clerkJSVersion: import.meta.env.VITE_CLERK_JS_VERSION, + appearance: { + layout: { + showOptionalFields: true, + }, + }, }); app.use(router); app.mount('#app'); diff --git a/package.json b/package.json index 94904669e28..24304937395 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "test:integration:deployment:nextjs": "pnpm playwright test --config integration/playwright.deployments.config.ts", "test:integration:expo-web:disabled": "E2E_APP_ID=expo.expo-web pnpm test:integration:base --grep @expo-web", "test:integration:express": "E2E_DEBUG=1 E2E_APP_ID=express.* pnpm test:integration:base --grep @express", - "test:integration:generic": "E2E_APP_ID=react.vite.*,next.appRouter.withEmailCodes* pnpm test:integration:base --grep @generic", + "test:integration:generic": "E2E_DEBUG=1 E2E_APP_ID=react.vite.withEmailCodes pnpm test:integration:base --grep @generic integration/tests/sign-up-flow.test.ts", "test:integration:handshake": "DISABLE_WEB_SECURITY=true E2E_APP_1_ENV_KEY=sessions-prod-1 E2E_SESSIONS_APP_1_HOST=multiple-apps-e2e.clerk.app pnpm test:integration:base --grep @handshake", "test:integration:handshake:staging": "DISABLE_WEB_SECURITY=true E2E_APP_1_ENV_KEY=clerkstage-sessions-prod-1 E2E_SESSIONS_APP_1_HOST=clerkstage-sessions-prod-1-e2e.clerk.app pnpm test:integration:base --grep @handshake", "test:integration:localhost": "pnpm test:integration:base --grep @localhost", diff --git a/packages/ui/src/components/SignUp/SignUpStart.tsx b/packages/ui/src/components/SignUp/SignUpStart.tsx index b7f1b73a6f4..dcb3f9aacf5 100644 --- a/packages/ui/src/components/SignUp/SignUpStart.tsx +++ b/packages/ui/src/components/SignUp/SignUpStart.tsx @@ -439,6 +439,7 @@ function SignUpStartInternal(): JSX.Element { legalAccepted={Boolean(formState.legalAccepted.checked) || undefined} /> )} + hello there {shouldShowForm && ( Date: Fri, 5 Dec 2025 18:11:38 +0200 Subject: [PATCH 05/41] chore(shared): backport intelligent retries --- packages/shared/src/loadClerkJsScript.ts | 101 +++++++++++++++++++---- 1 file changed, 87 insertions(+), 14 deletions(-) diff --git a/packages/shared/src/loadClerkJsScript.ts b/packages/shared/src/loadClerkJsScript.ts index e3c096d44f5..7660f5581d9 100644 --- a/packages/shared/src/loadClerkJsScript.ts +++ b/packages/shared/src/loadClerkJsScript.ts @@ -55,6 +55,51 @@ function isClerkGlobalProperlyLoaded(prop: 'Clerk' | '__internal_ClerkUiCtor'): const isClerkProperlyLoaded = () => isClerkGlobalProperlyLoaded('Clerk'); const isClerkUiProperlyLoaded = () => isClerkGlobalProperlyLoaded('__internal_ClerkUiCtor'); +/** + * Checks if an existing script has a request error using Performance API. + * + * @param scriptUrl - The URL of the script to check. + * @returns True if the script has failed to load due to a network/HTTP error. + */ +function hasScriptRequestError(scriptUrl: string): boolean { + if (typeof window === 'undefined' || !window.performance) { + return false; + } + + const entries = performance.getEntriesByName(scriptUrl, 'resource') as PerformanceResourceTiming[]; + + if (entries.length === 0) { + return false; + } + + const scriptEntry = entries[entries.length - 1]; + + // transferSize === 0 with responseEnd === 0 indicates network failure + // transferSize === 0 with responseEnd > 0 might be a 4xx/5xx error or blocked request + if (scriptEntry.transferSize === 0 && scriptEntry.decodedBodySize === 0) { + // If there was no response at all, it's definitely an error + if (scriptEntry.responseEnd === 0) { + return true; + } + // If we got a response but no content, likely an HTTP error (4xx/5xx) + if (scriptEntry.responseEnd > 0 && scriptEntry.responseStart > 0) { + return true; + } + + if ('responseStatus' in scriptEntry) { + const status = (scriptEntry as any).responseStatus; + if (status >= 400) { + return true; + } + if (scriptEntry.responseStatus === 0) { + return true; + } + } + } + + return false; +} + /** * Hotloads the Clerk JS script with robust failure detection. * @@ -88,20 +133,30 @@ export const loadClerkJsScript = async (opts?: LoadClerkJsScriptOptions): Promis return null; } - const existingScript = document.querySelector('script[data-clerk-js-script]'); - - if (existingScript) { - return waitForPredicateWithTimeout(timeout, isClerkProperlyLoaded, rejectWith()); - } - if (!opts?.publishableKey) { errorThrower.throwMissingPublishableKeyError(); return null; } + const scriptUrl = clerkJsScriptUrl(opts); + const existingScript = document.querySelector('script[data-clerk-js-script]'); + + if (existingScript) { + if (hasScriptRequestError(scriptUrl)) { + existingScript.remove(); + } else { + try { + await waitForPredicateWithTimeout(timeout, isClerkProperlyLoaded, rejectWith(), existingScript); + return null; + } catch { + existingScript.remove(); + } + } + } + const loadPromise = waitForPredicateWithTimeout(timeout, isClerkProperlyLoaded, rejectWith()); - loadScript(clerkJsScriptUrl(opts), { + loadScript(scriptUrl, { async: true, crossOrigin: 'anonymous', nonce: opts.nonce, @@ -125,19 +180,30 @@ export const loadClerkUiScript = async (opts?: LoadClerkUiScriptOptions): Promis return null; } - const existingScript = document.querySelector('script[data-clerk-ui-script]'); - - if (existingScript) { - return waitForPredicateWithTimeout(timeout, isClerkUiProperlyLoaded, rejectWith()); - } - if (!opts?.publishableKey) { errorThrower.throwMissingPublishableKeyError(); return null; } + const scriptUrl = clerkUiScriptUrl(opts); + const existingScript = document.querySelector('script[data-clerk-ui-script]'); + + if (existingScript) { + if (hasScriptRequestError(scriptUrl)) { + existingScript.remove(); + } else { + try { + await waitForPredicateWithTimeout(timeout, isClerkUiProperlyLoaded, rejectWith(), existingScript); + return null; + } catch { + existingScript.remove(); + } + } + } + const loadPromise = waitForPredicateWithTimeout(timeout, isClerkUiProperlyLoaded, rejectWith()); - loadScript(clerkUiScriptUrl(opts), { + + loadScript(scriptUrl, { async: true, crossOrigin: 'anonymous', nonce: opts.nonce, @@ -223,6 +289,7 @@ function waitForPredicateWithTimeout( timeoutMs: number, predicate: () => boolean, rejectWith: Error, + existingScript?: HTMLScriptElement, ): Promise { return new Promise((resolve, reject) => { let resolved = false; @@ -232,6 +299,12 @@ function waitForPredicateWithTimeout( clearInterval(pollInterval); }; + // Bail out early if the script fails to load, instead of waiting for the entire timeout + existingScript?.addEventListener('error', () => { + cleanup(timeoutId, pollInterval); + reject(rejectWith); + }); + const checkAndResolve = () => { if (resolved) { return; From 943594bebf54ab622c512eef5b0f8a12985a8f7b Mon Sep 17 00:00:00 2001 From: Nikos Douvlis Date: Fri, 5 Dec 2025 18:11:56 +0200 Subject: [PATCH 06/41] chore(repo): do not build before e2e --- turbo.json | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/turbo.json b/turbo.json index f3dfbc66ba8..aa2cf47bd8c 100644 --- a/turbo.json +++ b/turbo.json @@ -205,13 +205,6 @@ "outputLogs": "new-only" }, "//#test:integration:generic": { - "dependsOn": [ - "@clerk/testing#build", - "@clerk/clerk-js#build", - "@clerk/ui#build", - "@clerk/backend#build", - "@clerk/react#build" - ], "env": ["CLEANUP", "DEBUG", "E2E_*", "INTEGRATION_INSTANCE_KEYS"], "inputs": ["integration/**"], "outputLogs": "new-only" @@ -230,13 +223,6 @@ "outputLogs": "new-only" }, "//#test:integration:nextjs": { - "dependsOn": [ - "@clerk/testing#build", - "@clerk/clerk-js#build", - "@clerk/ui#build", - "@clerk/backend#build", - "@clerk/nextjs#build" - ], "env": ["CLEANUP", "DEBUG", "E2E_*", "INTEGRATION_INSTANCE_KEYS"], "inputs": ["integration/**"], "outputLogs": "new-only" From 8b299cc52b9258e48aa4d6dc2b3b01d327d4bda1 Mon Sep 17 00:00:00 2001 From: Nikos Douvlis Date: Fri, 5 Dec 2025 18:29:22 +0200 Subject: [PATCH 07/41] fix(ci): prevent turbo cache misses in verdaccio step The verdaccio step was setting `CLERK_USE_RQ=${{ matrix.clerk-use-rq }}` which evaluates to an empty string when the matrix variable is undefined. Since `CLERK_*` is in turbo.json's globalEnv, an empty string creates a different cache hash than undefined, causing unnecessary rebuilds. Now CLERK_USE_RQ is only set when explicitly `'true'`, matching the environment of the build-packages job and allowing cache hits. wip --- .github/workflows/ci.yml | 2 +- package.json | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index db26916ad50..9f8110e19b0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -409,7 +409,7 @@ jobs: uses: ./.github/actions/verdaccio with: publish-cmd: | - if [ "$(pnpm config get registry)" = "https://registry.npmjs.org/" ]; then echo 'Error: Using default registry' && exit 1; else CLERK_USE_RQ=${{ matrix.clerk-use-rq }} pnpm turbo build $TURBO_ARGS --only && pnpm changeset publish --no-git-tag --tag integration; fi + if [ "$(pnpm config get registry)" = "https://registry.npmjs.org/" ]; then echo 'Error: Using default registry' && exit 1; else ${{ matrix.clerk-use-rq == 'true' && 'CLERK_USE_RQ=true' || '' }} pnpm turbo build $TURBO_ARGS --only && pnpm changeset publish --no-git-tag --tag integration; fi - name: Edit .npmrc [link-workspace-packages=false] run: sed -i -E 's/link-workspace-packages=(deep|true)/link-workspace-packages=false/' .npmrc diff --git a/package.json b/package.json index 24304937395..c2c1b52b17f 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,8 @@ "test:integration:deployment:nextjs": "pnpm playwright test --config integration/playwright.deployments.config.ts", "test:integration:expo-web:disabled": "E2E_APP_ID=expo.expo-web pnpm test:integration:base --grep @expo-web", "test:integration:express": "E2E_DEBUG=1 E2E_APP_ID=express.* pnpm test:integration:base --grep @express", - "test:integration:generic": "E2E_DEBUG=1 E2E_APP_ID=react.vite.withEmailCodes pnpm test:integration:base --grep @generic integration/tests/sign-up-flow.test.ts", + "test:integration:generic": "E2E_DEBUG=1 E2E_APP_ID=react.vite.*,next.appRouter.withEmailCodes* pnpm test:integration:base --grep @generic integration/tests/sign-up-flow.test.ts", + "test:integration:generic1": "E2E_APP_CLERK_JS=http://localhost:4000/npm/clerk.browser.js E2E_APP_CLERK_UI=http://localhost:4001/npm/ui.browser.js E2E_DEBUG=1 E2E_APP_ID=react.vite.withEmailCodes pnpm test:integration:base --grep @generic", "test:integration:handshake": "DISABLE_WEB_SECURITY=true E2E_APP_1_ENV_KEY=sessions-prod-1 E2E_SESSIONS_APP_1_HOST=multiple-apps-e2e.clerk.app pnpm test:integration:base --grep @handshake", "test:integration:handshake:staging": "DISABLE_WEB_SECURITY=true E2E_APP_1_ENV_KEY=clerkstage-sessions-prod-1 E2E_SESSIONS_APP_1_HOST=clerkstage-sessions-prod-1-e2e.clerk.app pnpm test:integration:base --grep @handshake", "test:integration:localhost": "pnpm test:integration:base --grep @localhost", From c6f611afae73225541fd2dfc912cbcacfae542db Mon Sep 17 00:00:00 2001 From: Nikos Douvlis Date: Fri, 5 Dec 2025 18:45:59 +0200 Subject: [PATCH 08/41] refactor(repo): remove redundant dependencies from integration tests --- .github/workflows/ci.yml | 81 ++++++++++++++-------------- package.json | 3 +- turbo.json | 112 --------------------------------------- 3 files changed, 42 insertions(+), 154 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9f8110e19b0..8a235b5edb4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -295,53 +295,54 @@ jobs: strategy: fail-fast: false matrix: - test-name: [ + test-name: + [ "generic", - # "express", - # "ap-flows", - # "localhost", - # "sessions", - # "sessions:staging", - # "handshake", - # "handshake:staging", - # "astro", - # "tanstack-react-start", - # "vue", - # "nuxt", - # "react-router", - # "custom", + "express", + "ap-flows", + "localhost", + "sessions", + "sessions:staging", + "handshake", + "handshake:staging", + "astro", + "tanstack-react-start", + "vue", + "nuxt", + "react-router", + "custom", ] test-project: ["chrome"] include: - # - test-name: "billing" - # test-project: "chrome" - # clerk-use-rq: "false" - # - test-name: "billing" - # test-project: "chrome" - # clerk-use-rq: "true" - # - test-name: "machine" - # test-project: "chrome" - # clerk-use-rq: "false" - # - test-name: "machine" - # test-project: "chrome" - # clerk-use-rq: "true" - # - test-name: "nextjs" - # test-project: "chrome" - # next-version: "15" - # clerk-use-rq: "false" - # - test-name: "nextjs" - # test-project: "chrome" - # next-version: "15" - # clerk-use-rq: "true" + - test-name: "billing" + test-project: "chrome" + clerk-use-rq: "false" + - test-name: "billing" + test-project: "chrome" + clerk-use-rq: "true" + - test-name: "machine" + test-project: "chrome" + clerk-use-rq: "false" + - test-name: "machine" + test-project: "chrome" + clerk-use-rq: "true" - test-name: "nextjs" + test-project: "chrome" + next-version: "15" + clerk-use-rq: "false" + - test-name: "nextjs" + test-project: "chrome" + next-version: "15" + clerk-use-rq: "true" + - test-name: "nextjs" + test-project: "chrome" + next-version: "16" + - test-name: "quickstart" + test-project: "chrome" + next-version: "15" + - test-name: "quickstart" test-project: "chrome" next-version: "16" - # - test-name: "quickstart" - # test-project: "chrome" - # next-version: "15" - # - test-name: "quickstart" - # test-project: "chrome" - # next-version: "16" steps: - name: Checkout Repo diff --git a/package.json b/package.json index c2c1b52b17f..15c794804e0 100644 --- a/package.json +++ b/package.json @@ -40,8 +40,7 @@ "test:integration:deployment:nextjs": "pnpm playwright test --config integration/playwright.deployments.config.ts", "test:integration:expo-web:disabled": "E2E_APP_ID=expo.expo-web pnpm test:integration:base --grep @expo-web", "test:integration:express": "E2E_DEBUG=1 E2E_APP_ID=express.* pnpm test:integration:base --grep @express", - "test:integration:generic": "E2E_DEBUG=1 E2E_APP_ID=react.vite.*,next.appRouter.withEmailCodes* pnpm test:integration:base --grep @generic integration/tests/sign-up-flow.test.ts", - "test:integration:generic1": "E2E_APP_CLERK_JS=http://localhost:4000/npm/clerk.browser.js E2E_APP_CLERK_UI=http://localhost:4001/npm/ui.browser.js E2E_DEBUG=1 E2E_APP_ID=react.vite.withEmailCodes pnpm test:integration:base --grep @generic", + "test:integration:generic": "E2E_DEBUG=1 E2E_APP_ID=react.vite.*,next.appRouter.withEmailCodes* pnpm test:integration:base --grep @generic", "test:integration:handshake": "DISABLE_WEB_SECURITY=true E2E_APP_1_ENV_KEY=sessions-prod-1 E2E_SESSIONS_APP_1_HOST=multiple-apps-e2e.clerk.app pnpm test:integration:base --grep @handshake", "test:integration:handshake:staging": "DISABLE_WEB_SECURITY=true E2E_APP_1_ENV_KEY=clerkstage-sessions-prod-1 E2E_SESSIONS_APP_1_HOST=clerkstage-sessions-prod-1-e2e.clerk.app pnpm test:integration:base --grep @handshake", "test:integration:localhost": "pnpm test:integration:base --grep @localhost", diff --git a/turbo.json b/turbo.json index aa2cf47bd8c..bc50818ef30 100644 --- a/turbo.json +++ b/turbo.json @@ -228,203 +228,91 @@ "outputLogs": "new-only" }, "//#test:integration:nextjs:canary": { - "dependsOn": [ - "@clerk/testing#build", - "@clerk/clerk-js#build", - "@clerk/ui#build", - "@clerk/backend#build", - "@clerk/nextjs#build" - ], "env": ["CLEANUP", "DEBUG", "E2E_*", "INTEGRATION_INSTANCE_KEYS"], "inputs": ["integration/**"], "outputLogs": "new-only" }, "//#test:integration:quickstart": { - "dependsOn": [ - "@clerk/testing#build", - "@clerk/clerk-js#build", - "@clerk/ui#build", - "@clerk/backend#build", - "@clerk/nextjs#build" - ], "env": ["CLEANUP", "DEBUG", "E2E_*", "INTEGRATION_INSTANCE_KEYS"], "inputs": ["integration/**"], "outputLogs": "new-only" }, "//#test:integration:astro": { - "dependsOn": [ - "@clerk/testing#build", - "@clerk/clerk-js#build", - "@clerk/ui#build", - "@clerk/backend#build", - "@clerk/astro#build" - ], "env": ["CLEANUP", "DEBUG", "E2E_*", "INTEGRATION_INSTANCE_KEYS"], "inputs": ["integration/**"], "outputLogs": "new-only" }, "//#test:integration:localhost": { - "dependsOn": [ - "@clerk/testing#build", - "@clerk/clerk-js#build", - "@clerk/ui#build", - "@clerk/backend#build", - "@clerk/nextjs#build" - ], "env": ["CLEANUP", "DEBUG", "E2E_*", "INTEGRATION_INSTANCE_KEYS", "NODE_EXTRA_CA_CERTS"], "inputs": ["integration/**"], "outputLogs": "new-only" }, "//#test:integration:sessions": { - "dependsOn": [ - "@clerk/testing#build", - "@clerk/clerk-js#build", - "@clerk/ui#build", - "@clerk/backend#build", - "@clerk/nextjs#build" - ], "env": ["CLEANUP", "DEBUG", "DISABLE_WEB_SECURITY", "E2E_*", "INTEGRATION_INSTANCE_KEYS", "NODE_EXTRA_CA_CERTS"], "inputs": ["integration/**"], "outputLogs": "new-only" }, "//#test:integration:sessions:staging": { - "dependsOn": [ - "@clerk/testing#build", - "@clerk/clerk-js#build", - "@clerk/ui#build", - "@clerk/backend#build", - "@clerk/nextjs#build" - ], "env": ["CLEANUP", "DEBUG", "DISABLE_WEB_SECURITY", "E2E_*", "INTEGRATION_INSTANCE_KEYS", "NODE_EXTRA_CA_CERTS"], "inputs": ["integration/**"], "outputLogs": "new-only" }, "//#test:integration:handshake": { - "dependsOn": [ - "@clerk/testing#build", - "@clerk/clerk-js#build", - "@clerk/ui#build", - "@clerk/backend#build", - "@clerk/nextjs#build" - ], "env": ["CLEANUP", "DEBUG", "DISABLE_WEB_SECURITY", "E2E_*", "INTEGRATION_INSTANCE_KEYS", "NODE_EXTRA_CA_CERTS"], "inputs": ["integration/**"], "outputLogs": "new-only" }, "//#test:integration:handshake:staging": { - "dependsOn": [ - "@clerk/testing#build", - "@clerk/clerk-js#build", - "@clerk/ui#build", - "@clerk/backend#build", - "@clerk/nextjs#build" - ], "env": ["CLEANUP", "DEBUG", "DISABLE_WEB_SECURITY", "E2E_*", "INTEGRATION_INSTANCE_KEYS", "NODE_EXTRA_CA_CERTS"], "inputs": ["integration/**"], "outputLogs": "new-only" }, "//#test:integration:expo-web": { - "dependsOn": [ - "@clerk/testing#build", - "@clerk/clerk-js#build", - "@clerk/ui#build", - "@clerk/expo#build", - "@clerk/react#build" - ], "env": ["CLEANUP", "DEBUG", "E2E_*", "INTEGRATION_INSTANCE_KEYS"], "inputs": ["integration/**"], "outputLogs": "new-only" }, "//#test:integration:tanstack-react-start": { - "dependsOn": [ - "@clerk/testing#build", - "@clerk/clerk-js#build", - "@clerk/ui#build", - "@clerk/tanstack-react-start#build", - "@clerk/react#build" - ], "env": ["CLEANUP", "DEBUG", "E2E_*", "INTEGRATION_INSTANCE_KEYS"], "inputs": ["integration/**"], "outputLogs": "new-only" }, "//#test:integration:vue": { - "dependsOn": ["@clerk/testing#build", "@clerk/clerk-js#build", "@clerk/ui#build", "@clerk/vue#build"], "env": ["CLEANUP", "DEBUG", "E2E_*", "INTEGRATION_INSTANCE_KEYS"], "inputs": ["integration/**"], "outputLogs": "new-only" }, "//#test:integration:nuxt": { - "dependsOn": [ - "@clerk/testing#build", - "@clerk/clerk-js#build", - "@clerk/ui#build", - "@clerk/vue#build", - "@clerk/backend#build", - "@clerk/nuxt#build" - ], "env": ["CLEANUP", "DEBUG", "E2E_*", "INTEGRATION_INSTANCE_KEYS"], "inputs": ["integration/**"], "outputLogs": "new-only" }, "//#test:integration:react-router": { - "dependsOn": [ - "@clerk/testing#build", - "@clerk/clerk-js#build", - "@clerk/ui#build", - "@clerk/react-router#build", - "@clerk/backend#build", - "@clerk/react#build" - ], "env": ["CLEANUP", "DEBUG", "E2E_*", "INTEGRATION_INSTANCE_KEYS"], "inputs": ["integration/**"], "outputLogs": "new-only" }, "//#test:integration:billing": { - "dependsOn": [ - "@clerk/testing#build", - "@clerk/clerk-js#build", - "@clerk/ui#build", - "@clerk/backend#build", - "@clerk/nextjs#build", - "@clerk/vue#build" - ], "env": ["CLEANUP", "DEBUG", "E2E_*", "INTEGRATION_INSTANCE_KEYS"], "inputs": ["integration/**"], "outputLogs": "new-only" }, "//#test:integration:machine": { - "dependsOn": [ - "@clerk/testing#build", - "@clerk/clerk-js#build", - "@clerk/ui#build", - "@clerk/backend#build", - "@clerk/nextjs#build", - "@clerk/express#build" - ], "env": ["CLEANUP", "DEBUG", "E2E_*", "INTEGRATION_INSTANCE_KEYS"], "inputs": ["integration/**"], "outputLogs": "new-only" }, "//#test:integration:custom": { - "dependsOn": [ - "@clerk/testing#build", - "@clerk/clerk-js#build", - "@clerk/ui#build", - "@clerk/backend#build", - "@clerk/react#build" - ], "env": ["CLEANUP", "DEBUG", "E2E_*", "INTEGRATION_INSTANCE_KEYS"], "inputs": ["integration/**"], "outputLogs": "new-only" }, "//#typedoc:generate": { - "dependsOn": ["@clerk/nextjs#build", "@clerk/react#build", "@clerk/shared#build"], "inputs": ["tsconfig.typedoc.json", "typedoc.config.mjs"], "outputs": [".typedoc/**"], "outputLogs": "new-only" }, "//#test:typedoc": { - "dependsOn": ["//#typedoc:generate"], "inputs": [".typedoc/**"], "outputLogs": "new-only" } From a9c31c4effe34794de5639c1e56dbd3f4634f410 Mon Sep 17 00:00:00 2001 From: Nikos Douvlis Date: Fri, 5 Dec 2025 19:53:25 +0200 Subject: [PATCH 09/41] simplify m2m tests --- integration/presets/longRunningApps.ts | 6 ------ integration/tests/machine-auth/component.test.ts | 16 +++++++++++----- package.json | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/integration/presets/longRunningApps.ts b/integration/presets/longRunningApps.ts index 4db25199ff1..6a324675730 100644 --- a/integration/presets/longRunningApps.ts +++ b/integration/presets/longRunningApps.ts @@ -44,12 +44,6 @@ export const createLongRunningApps = () => { { id: 'withBillingJwtV2.next.appRouter', config: next.appRouter, env: envs.withBillingJwtV2 }, { id: 'withBillingJwtV2.vue.vite', config: vue.vite, env: envs.withBillingJwtV2 }, - /** - * Machine auth apps - */ - { id: 'withMachine.express.vite', config: express.vite, env: envs.withAPIKeys }, - { id: 'withMachine.next.appRouter', config: next.appRouter, env: envs.withAPIKeys }, - /** * Vite apps - basic flows */ diff --git a/integration/tests/machine-auth/component.test.ts b/integration/tests/machine-auth/component.test.ts index b37527e0f36..d9b308cf355 100644 --- a/integration/tests/machine-auth/component.test.ts +++ b/integration/tests/machine-auth/component.test.ts @@ -1,9 +1,10 @@ import type { Page } from '@playwright/test'; import { expect, test } from '@playwright/test'; +import type { Application } from '../../models/application'; import { appConfigs } from '../../presets'; import type { FakeOrganization, FakeUser } from '../../testUtils'; -import { createTestUtils, testAgainstRunningApps } from '../../testUtils'; +import { createTestUtils } from '../../testUtils'; const mockAPIKeysEnvironmentSettings = async ( page: Page, @@ -27,16 +28,21 @@ const mockAPIKeysEnvironmentSettings = async ( }); }; -testAgainstRunningApps({ - withEnv: [appConfigs.envs.withAPIKeys], - withPattern: ['withMachine.next.appRouter'], -})('api keys component @machine', ({ app }) => { +test.describe('api keys component @machine', () => { test.describe.configure({ mode: 'serial' }); + let app: Application; let fakeAdmin: FakeUser; let fakeOrganization: FakeOrganization; test.beforeAll(async () => { + test.setTimeout(90_000); // Wait for app to be ready + app = await appConfigs.next.appRouter.clone().commit(); + + await app.setup(); + await app.withEnv(appConfigs.envs.withAPIKeys); + await app.dev(); + const u = createTestUtils({ app }); fakeAdmin = u.services.users.createFakeUser(); const admin = await u.services.users.createBapiUser(fakeAdmin); diff --git a/package.json b/package.json index 15c794804e0..fdbcba384eb 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,7 @@ "test:integration:handshake": "DISABLE_WEB_SECURITY=true E2E_APP_1_ENV_KEY=sessions-prod-1 E2E_SESSIONS_APP_1_HOST=multiple-apps-e2e.clerk.app pnpm test:integration:base --grep @handshake", "test:integration:handshake:staging": "DISABLE_WEB_SECURITY=true E2E_APP_1_ENV_KEY=clerkstage-sessions-prod-1 E2E_SESSIONS_APP_1_HOST=clerkstage-sessions-prod-1-e2e.clerk.app pnpm test:integration:base --grep @handshake", "test:integration:localhost": "pnpm test:integration:base --grep @localhost", - "test:integration:machine": "E2E_APP_ID=withMachine.* pnpm test:integration:base --grep @machine", + "test:integration:machine": "E2E_DEBUG=1 pnpm test:integration:base --grep @machine", "test:integration:nextjs": "E2E_APP_ID=next.appRouter.* pnpm test:integration:base --grep @nextjs", "test:integration:nuxt": "E2E_DEBUG=1 E2E_APP_ID=nuxt.node npm run test:integration:base -- --grep @nuxt", "test:integration:quickstart": "E2E_APP_ID=quickstart.* pnpm test:integration:base --grep @quickstart", From b3c9e1baf94b34c538fa74ab08d562ad443d2c84 Mon Sep 17 00:00:00 2001 From: Nikos Douvlis Date: Fri, 5 Dec 2025 19:53:50 +0200 Subject: [PATCH 10/41] refactor(turbo): update dependencies for integration tests Removed redundant dependencies from the generic integration test and added necessary dependencies for various integration tests including nextjs, astro, and others. This ensures all tests have the required builds for proper execution. --- turbo.json | 119 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) diff --git a/turbo.json b/turbo.json index bc50818ef30..74dbac5deaa 100644 --- a/turbo.json +++ b/turbo.json @@ -205,6 +205,13 @@ "outputLogs": "new-only" }, "//#test:integration:generic": { + "dependsOn": [ + "@clerk/testing#build", + "@clerk/clerk-js#build", + "@clerk/ui#build", + "@clerk/backend#build", + "@clerk/react#build" + ], "env": ["CLEANUP", "DEBUG", "E2E_*", "INTEGRATION_INSTANCE_KEYS"], "inputs": ["integration/**"], "outputLogs": "new-only" @@ -228,91 +235,203 @@ "outputLogs": "new-only" }, "//#test:integration:nextjs:canary": { + "dependsOn": [ + "@clerk/testing#build", + "@clerk/clerk-js#build", + "@clerk/ui#build", + "@clerk/backend#build", + "@clerk/nextjs#build" + ], "env": ["CLEANUP", "DEBUG", "E2E_*", "INTEGRATION_INSTANCE_KEYS"], "inputs": ["integration/**"], "outputLogs": "new-only" }, "//#test:integration:quickstart": { + "dependsOn": [ + "@clerk/testing#build", + "@clerk/clerk-js#build", + "@clerk/ui#build", + "@clerk/backend#build", + "@clerk/nextjs#build" + ], "env": ["CLEANUP", "DEBUG", "E2E_*", "INTEGRATION_INSTANCE_KEYS"], "inputs": ["integration/**"], "outputLogs": "new-only" }, "//#test:integration:astro": { + "dependsOn": [ + "@clerk/testing#build", + "@clerk/clerk-js#build", + "@clerk/ui#build", + "@clerk/backend#build", + "@clerk/astro#build" + ], "env": ["CLEANUP", "DEBUG", "E2E_*", "INTEGRATION_INSTANCE_KEYS"], "inputs": ["integration/**"], "outputLogs": "new-only" }, "//#test:integration:localhost": { + "dependsOn": [ + "@clerk/testing#build", + "@clerk/clerk-js#build", + "@clerk/ui#build", + "@clerk/backend#build", + "@clerk/nextjs#build" + ], "env": ["CLEANUP", "DEBUG", "E2E_*", "INTEGRATION_INSTANCE_KEYS", "NODE_EXTRA_CA_CERTS"], "inputs": ["integration/**"], "outputLogs": "new-only" }, "//#test:integration:sessions": { + "dependsOn": [ + "@clerk/testing#build", + "@clerk/clerk-js#build", + "@clerk/ui#build", + "@clerk/backend#build", + "@clerk/nextjs#build" + ], "env": ["CLEANUP", "DEBUG", "DISABLE_WEB_SECURITY", "E2E_*", "INTEGRATION_INSTANCE_KEYS", "NODE_EXTRA_CA_CERTS"], "inputs": ["integration/**"], "outputLogs": "new-only" }, "//#test:integration:sessions:staging": { + "dependsOn": [ + "@clerk/testing#build", + "@clerk/clerk-js#build", + "@clerk/ui#build", + "@clerk/backend#build", + "@clerk/nextjs#build" + ], "env": ["CLEANUP", "DEBUG", "DISABLE_WEB_SECURITY", "E2E_*", "INTEGRATION_INSTANCE_KEYS", "NODE_EXTRA_CA_CERTS"], "inputs": ["integration/**"], "outputLogs": "new-only" }, "//#test:integration:handshake": { + "dependsOn": [ + "@clerk/testing#build", + "@clerk/clerk-js#build", + "@clerk/ui#build", + "@clerk/backend#build", + "@clerk/nextjs#build" + ], "env": ["CLEANUP", "DEBUG", "DISABLE_WEB_SECURITY", "E2E_*", "INTEGRATION_INSTANCE_KEYS", "NODE_EXTRA_CA_CERTS"], "inputs": ["integration/**"], "outputLogs": "new-only" }, "//#test:integration:handshake:staging": { + "dependsOn": [ + "@clerk/testing#build", + "@clerk/clerk-js#build", + "@clerk/ui#build", + "@clerk/backend#build", + "@clerk/nextjs#build" + ], "env": ["CLEANUP", "DEBUG", "DISABLE_WEB_SECURITY", "E2E_*", "INTEGRATION_INSTANCE_KEYS", "NODE_EXTRA_CA_CERTS"], "inputs": ["integration/**"], "outputLogs": "new-only" }, "//#test:integration:expo-web": { + "dependsOn": [ + "@clerk/testing#build", + "@clerk/clerk-js#build", + "@clerk/ui#build", + "@clerk/expo#build", + "@clerk/react#build" + ], "env": ["CLEANUP", "DEBUG", "E2E_*", "INTEGRATION_INSTANCE_KEYS"], "inputs": ["integration/**"], "outputLogs": "new-only" }, "//#test:integration:tanstack-react-start": { + "dependsOn": [ + "@clerk/testing#build", + "@clerk/clerk-js#build", + "@clerk/ui#build", + "@clerk/tanstack-react-start#build", + "@clerk/react#build" + ], "env": ["CLEANUP", "DEBUG", "E2E_*", "INTEGRATION_INSTANCE_KEYS"], "inputs": ["integration/**"], "outputLogs": "new-only" }, "//#test:integration:vue": { + "dependsOn": ["@clerk/testing#build", "@clerk/clerk-js#build", "@clerk/ui#build", "@clerk/vue#build"], "env": ["CLEANUP", "DEBUG", "E2E_*", "INTEGRATION_INSTANCE_KEYS"], "inputs": ["integration/**"], "outputLogs": "new-only" }, "//#test:integration:nuxt": { + "dependsOn": [ + "@clerk/testing#build", + "@clerk/clerk-js#build", + "@clerk/ui#build", + "@clerk/vue#build", + "@clerk/backend#build", + "@clerk/nuxt#build" + ], "env": ["CLEANUP", "DEBUG", "E2E_*", "INTEGRATION_INSTANCE_KEYS"], "inputs": ["integration/**"], "outputLogs": "new-only" }, "//#test:integration:react-router": { + "dependsOn": [ + "@clerk/testing#build", + "@clerk/clerk-js#build", + "@clerk/ui#build", + "@clerk/react-router#build", + "@clerk/backend#build", + "@clerk/react#build" + ], "env": ["CLEANUP", "DEBUG", "E2E_*", "INTEGRATION_INSTANCE_KEYS"], "inputs": ["integration/**"], "outputLogs": "new-only" }, "//#test:integration:billing": { + "dependsOn": [ + "@clerk/testing#build", + "@clerk/clerk-js#build", + "@clerk/ui#build", + "@clerk/backend#build", + "@clerk/nextjs#build", + "@clerk/vue#build" + ], "env": ["CLEANUP", "DEBUG", "E2E_*", "INTEGRATION_INSTANCE_KEYS"], "inputs": ["integration/**"], "outputLogs": "new-only" }, "//#test:integration:machine": { + "dependsOn": [ + "@clerk/testing#build", + "@clerk/clerk-js#build", + "@clerk/ui#build", + "@clerk/backend#build", + "@clerk/nextjs#build", + "@clerk/express#build" + ], "env": ["CLEANUP", "DEBUG", "E2E_*", "INTEGRATION_INSTANCE_KEYS"], "inputs": ["integration/**"], "outputLogs": "new-only" }, "//#test:integration:custom": { + "dependsOn": [ + "@clerk/testing#build", + "@clerk/clerk-js#build", + "@clerk/ui#build", + "@clerk/backend#build", + "@clerk/react#build" + ], "env": ["CLEANUP", "DEBUG", "E2E_*", "INTEGRATION_INSTANCE_KEYS"], "inputs": ["integration/**"], "outputLogs": "new-only" }, "//#typedoc:generate": { + "dependsOn": ["@clerk/nextjs#build", "@clerk/react#build", "@clerk/shared#build"], "inputs": ["tsconfig.typedoc.json", "typedoc.config.mjs"], "outputs": [".typedoc/**"], "outputLogs": "new-only" }, "//#test:typedoc": { + "dependsOn": ["//#typedoc:generate"], "inputs": [".typedoc/**"], "outputLogs": "new-only" } From 8ced7b14dd09d4aa65f76e572052ba035ddda9fc Mon Sep 17 00:00:00 2001 From: Nikos Douvlis Date: Fri, 5 Dec 2025 20:44:36 +0200 Subject: [PATCH 11/41] wip1 --- .github/workflows/ci.yml | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8a235b5edb4..e73059a7354 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -295,22 +295,21 @@ jobs: strategy: fail-fast: false matrix: - test-name: - [ + test-name: [ "generic", "express", - "ap-flows", - "localhost", - "sessions", - "sessions:staging", - "handshake", - "handshake:staging", - "astro", - "tanstack-react-start", - "vue", - "nuxt", - "react-router", - "custom", + # "ap-flows", + # "localhost", + # "sessions", + # "sessions:staging", + # "handshake", + # "handshake:staging", + # "astro", + # "tanstack-react-start", + # "vue", + # "nuxt", + # "react-router", + # "custom", ] test-project: ["chrome"] include: From eefdea22b3d1b0f6942df9b10733ec1a013169a1 Mon Sep 17 00:00:00 2001 From: Nikos Douvlis Date: Fri, 5 Dec 2025 21:24:30 +0200 Subject: [PATCH 12/41] fix(nuxt): support NUXT_PUBLIC_CLERK_JS_URL and NUXT_PUBLIC_CLERK_UI_URL env vars Nuxt converts camelCase runtime config keys to env var names by inserting underscores before uppercase letters. The keys clerkJSUrl/clerkUiUrl were being converted to NUXT_PUBLIC_CLERK_CLERK_J_S_URL which is not what users expect. Renamed the runtime config keys to jsUrl/uiUrl so they correctly map to NUXT_PUBLIC_CLERK_JS_URL and NUXT_PUBLIC_CLERK_UI_URL, then map them back to clerkJSUrl/clerkUiUrl when passing to the Vue plugin. --- .github/workflows/ci.yml | 2 +- integration/presets/envs.ts | 4 +++- packages/nuxt/src/global.d.ts | 13 ++++++++++++- packages/nuxt/src/module.ts | 6 ++++-- packages/nuxt/src/runtime/plugin.ts | 6 +++++- packages/shared/src/loadScript.ts | 1 - 6 files changed, 25 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e73059a7354..eec1d1f9675 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -307,7 +307,7 @@ jobs: # "astro", # "tanstack-react-start", # "vue", - # "nuxt", + "nuxt", # "react-router", # "custom", ] diff --git a/integration/presets/envs.ts b/integration/presets/envs.ts index a166fda6228..43245f0093e 100644 --- a/integration/presets/envs.ts +++ b/integration/presets/envs.ts @@ -65,7 +65,9 @@ const withCustomRoles = base .clone() .setId('withCustomRoles') .setEnvVariable('private', 'CLERK_SECRET_KEY', instanceKeys.get('with-custom-roles').sk) - .setEnvVariable('public', 'CLERK_PUBLISHABLE_KEY', instanceKeys.get('with-custom-roles').pk); + .setEnvVariable('public', 'CLERK_PUBLISHABLE_KEY', instanceKeys.get('with-custom-roles').pk) + .setEnvVariable('public', 'CLERK_JS_URL', constants.E2E_APP_CLERK_JS || 'http://localhost:18211/clerk.browser.js') + .setEnvVariable('public', 'CLERK_UI_URL', constants.E2E_APP_CLERK_UI || 'http://localhost:18212/ui.browser.js'); const withReverification = base .clone() diff --git a/packages/nuxt/src/global.d.ts b/packages/nuxt/src/global.d.ts index 7cde099d9c9..7220a9070ab 100644 --- a/packages/nuxt/src/global.d.ts +++ b/packages/nuxt/src/global.d.ts @@ -16,7 +16,18 @@ declare module 'nuxt/schema' { }; } interface PublicRuntimeConfig { - clerk: PluginOptions; + clerk: Omit & { + /** + * The URL that `@clerk/clerk-js` should be hot-loaded from. + * Supports NUXT_PUBLIC_CLERK_JS_URL env var. + */ + jsUrl?: string; + /** + * The URL that `@clerk/ui` should be hot-loaded from. + * Supports NUXT_PUBLIC_CLERK_UI_URL env var. + */ + uiUrl?: string; + }; } } diff --git a/packages/nuxt/src/module.ts b/packages/nuxt/src/module.ts index 33dc489a690..c5d42b4b6c3 100644 --- a/packages/nuxt/src/module.ts +++ b/packages/nuxt/src/module.ts @@ -64,8 +64,10 @@ export default defineNuxtModule({ signUpForceRedirectUrl: options.signUpForceRedirectUrl, signUpUrl: options.signUpUrl, domain: options.domain, - clerkJSUrl: options.clerkJSUrl, - clerkUiUrl: options.clerkUiUrl, + // Using jsUrl/uiUrl instead of clerkJSUrl/clerkUiUrl to support + // NUXT_PUBLIC_CLERK_JS_URL and NUXT_PUBLIC_CLERK_UI_URL env vars. + jsUrl: options.clerkJSUrl, + uiUrl: options.clerkUiUrl, clerkJSVariant: options.clerkJSVariant, clerkJSVersion: options.clerkJSVersion, isSatellite: options.isSatellite, diff --git a/packages/nuxt/src/runtime/plugin.ts b/packages/nuxt/src/runtime/plugin.ts index 077a2dc019b..8879860afb6 100644 --- a/packages/nuxt/src/runtime/plugin.ts +++ b/packages/nuxt/src/runtime/plugin.ts @@ -17,9 +17,13 @@ export default defineNuxtPlugin(nuxtApp => { } const runtimeConfig = useRuntimeConfig(); + const clerkConfig = runtimeConfig.public.clerk ?? {}; nuxtApp.vueApp.use(clerkPlugin as any, { - ...(runtimeConfig.public.clerk ?? {}), + ...clerkConfig, + // Map jsUrl/uiUrl to clerkJSUrl/clerkUiUrl as expected by the Vue plugin + clerkJSUrl: clerkConfig.jsUrl, + clerkUiUrl: clerkConfig.uiUrl, sdkMetadata: { name: PACKAGE_NAME, version: PACKAGE_VERSION, diff --git a/packages/shared/src/loadScript.ts b/packages/shared/src/loadScript.ts index cd578486066..54e617ebc54 100644 --- a/packages/shared/src/loadScript.ts +++ b/packages/shared/src/loadScript.ts @@ -54,7 +54,6 @@ export async function loadScript(src = '', opts: LoadScriptOptions): Promise { - console.log('nikos 3', _, iterations); return iterations <= 5; }, }); From e4563d76e5ac987c2c6abdaa78e4d35c442b5070 Mon Sep 17 00:00:00 2001 From: Nikos Douvlis Date: Fri, 5 Dec 2025 21:50:44 +0200 Subject: [PATCH 13/41] dont cache --- .github/workflows/ci.yml | 41 +++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index eec1d1f9675..eae08f50444 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -65,9 +65,9 @@ jobs: id: config uses: ./.github/actions/init-blacksmith with: - turbo-signature: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }} - turbo-team: ${{ vars.TURBO_TEAM }} - turbo-token: ${{ secrets.TURBO_TOKEN }} + # turbo-signature: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }} + # turbo-team: ${{ vars.TURBO_TEAM }} + # turbo-token: ${{ secrets.TURBO_TOKEN }} - name: Verify lockfile is deduped run: pnpm dedupe --check @@ -111,10 +111,10 @@ jobs: id: config uses: ./.github/actions/init-blacksmith with: - turbo-signature: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }} + # turbo-signature: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }} turbo-summarize: ${{ env.TURBO_SUMMARIZE }} - turbo-team: ${{ vars.TURBO_TEAM }} - turbo-token: ${{ secrets.TURBO_TOKEN }} + # turbo-team: ${{ vars.TURBO_TEAM }} + # turbo-token: ${{ secrets.TURBO_TOKEN }} - name: Turbo Build run: pnpm turbo build $TURBO_ARGS --only @@ -155,10 +155,10 @@ jobs: id: config uses: ./.github/actions/init-blacksmith with: - turbo-signature: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }} + # turbo-signature: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }} turbo-summarize: ${{ env.TURBO_SUMMARIZE }} - turbo-team: ${{ vars.TURBO_TEAM }} - turbo-token: ${{ secrets.TURBO_TOKEN }} + # turbo-team: ${{ vars.TURBO_TEAM }} + # turbo-token: ${{ secrets.TURBO_TOKEN }} - name: Check size using bundlewatch continue-on-error: true @@ -231,10 +231,10 @@ jobs: with: # Ensures that all builds are cached appropriately with a consistent run name `Unit Tests (20)`. node-version: ${{ matrix.node-version }} - turbo-signature: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }} + # turbo-signature: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }} turbo-summarize: ${{ env.TURBO_SUMMARIZE }} - turbo-team: ${{ vars.TURBO_TEAM }} - turbo-token: ${{ secrets.TURBO_TOKEN }} + # turbo-team: ${{ vars.TURBO_TEAM }} + # turbo-token: ${{ secrets.TURBO_TOKEN }} - name: Rebuild @clerk/shared with CLERK_USE_RQ=true if: ${{ matrix.clerk-use-rq == 'true' }} @@ -280,7 +280,8 @@ jobs: retention-days: 5 integration-tests: - needs: [check-permissions, build-packages] + # needs: [check-permissions, build-packages] + needs: [check-permissions] if: ${{ github.event_name != 'pull_request' || github.event.pull_request.draft == false }} name: Integration Tests (${{ matrix.test-name }}, ${{ matrix.test-project }}${{ matrix.next-version && format(', {0}', matrix.next-version) || '' }}${{ matrix.clerk-use-rq == 'true' && ', RQ' || '' }}) permissions: @@ -354,9 +355,9 @@ jobs: id: config uses: ./.github/actions/init-blacksmith with: - turbo-signature: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }} - turbo-team: ${{ vars.TURBO_TEAM }} - turbo-token: ${{ secrets.TURBO_TOKEN }} + # turbo-signature: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }} + # turbo-team: ${{ vars.TURBO_TEAM }} + # turbo-token: ${{ secrets.TURBO_TOKEN }} playwright-enabled: true - name: Verify jq is installed @@ -422,6 +423,8 @@ jobs: pnpm config set minimum-release-age-exclude @clerk/* pnpm add @clerk/backend + # Install published packages from Verdaccio to test against real npm install scenarios + # rather than local monorepo builds. Validates package structure, dependencies, and entry points. - name: Install @clerk/clerk-js in os temp if: ${{ steps.task-status.outputs.affected == '1' }} working-directory: ${{runner.temp}} @@ -517,10 +520,10 @@ jobs: with: turbo-enabled: true node-version: 22 - turbo-signature: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }} + # turbo-signature: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }} turbo-summarize: ${{ env.TURBO_SUMMARIZE }} - turbo-team: ${{ vars.TURBO_TEAM }} - turbo-token: ${{ secrets.TURBO_TOKEN }} + # turbo-team: ${{ vars.TURBO_TEAM }} + # turbo-token: ${{ secrets.TURBO_TOKEN }} - name: Publish with pkg-pr-new run: pnpm run build && pnpx pkg-pr-new@${{ vars.PKG_PR_NEW_VERSION || '0.0.49' }} publish --compact --pnpm './packages/*' From 13afcb021745f72bef246d924f2b2fd13af37d31 Mon Sep 17 00:00:00 2001 From: Nikos Douvlis Date: Fri, 5 Dec 2025 22:00:14 +0200 Subject: [PATCH 14/41] refactor(turbo): remove redundant dependencies from integration tests --- package.json | 2 +- turbo.json | 132 --------------------------------------------------- 2 files changed, 1 insertion(+), 133 deletions(-) diff --git a/package.json b/package.json index fdbcba384eb..c068833cad3 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ "test:integration:custom": "pnpm test:integration:base --grep @custom", "test:integration:deployment:nextjs": "pnpm playwright test --config integration/playwright.deployments.config.ts", "test:integration:expo-web:disabled": "E2E_APP_ID=expo.expo-web pnpm test:integration:base --grep @expo-web", - "test:integration:express": "E2E_DEBUG=1 E2E_APP_ID=express.* pnpm test:integration:base --grep @express", + "test:integration:express": "E2E_DEBUG=1 E2E_DEBUG=1 E2E_APP_ID=express.* pnpm test:integration:base --grep @express", "test:integration:generic": "E2E_DEBUG=1 E2E_APP_ID=react.vite.*,next.appRouter.withEmailCodes* pnpm test:integration:base --grep @generic", "test:integration:handshake": "DISABLE_WEB_SECURITY=true E2E_APP_1_ENV_KEY=sessions-prod-1 E2E_SESSIONS_APP_1_HOST=multiple-apps-e2e.clerk.app pnpm test:integration:base --grep @handshake", "test:integration:handshake:staging": "DISABLE_WEB_SECURITY=true E2E_APP_1_ENV_KEY=clerkstage-sessions-prod-1 E2E_SESSIONS_APP_1_HOST=clerkstage-sessions-prod-1-e2e.clerk.app pnpm test:integration:base --grep @handshake", diff --git a/turbo.json b/turbo.json index 74dbac5deaa..8ef7b479afc 100644 --- a/turbo.json +++ b/turbo.json @@ -193,38 +193,16 @@ "outputs": [] }, "//#test:integration:ap-flows": { - "dependsOn": [ - "@clerk/testing#build", - "@clerk/clerk-js#build", - "@clerk/ui#build", - "@clerk/backend#build", - "@clerk/nextjs#build" - ], "env": ["CLEANUP", "DEBUG", "E2E_*", "INTEGRATION_INSTANCE_KEYS"], "inputs": ["integration/**"], "outputLogs": "new-only" }, "//#test:integration:generic": { - "dependsOn": [ - "@clerk/testing#build", - "@clerk/clerk-js#build", - "@clerk/ui#build", - "@clerk/backend#build", - "@clerk/react#build" - ], "env": ["CLEANUP", "DEBUG", "E2E_*", "INTEGRATION_INSTANCE_KEYS"], "inputs": ["integration/**"], "outputLogs": "new-only" }, "//#test:integration:express": { - "dependsOn": [ - "@clerk/testing#build", - "@clerk/clerk-js#build", - "@clerk/ui#build", - "@clerk/backend#build", - "@clerk/express#build", - "@clerk/react#build" - ], "env": ["CLEANUP", "DEBUG", "E2E_*", "INTEGRATION_INSTANCE_KEYS"], "inputs": ["integration/**"], "outputLogs": "new-only" @@ -235,191 +213,81 @@ "outputLogs": "new-only" }, "//#test:integration:nextjs:canary": { - "dependsOn": [ - "@clerk/testing#build", - "@clerk/clerk-js#build", - "@clerk/ui#build", - "@clerk/backend#build", - "@clerk/nextjs#build" - ], "env": ["CLEANUP", "DEBUG", "E2E_*", "INTEGRATION_INSTANCE_KEYS"], "inputs": ["integration/**"], "outputLogs": "new-only" }, "//#test:integration:quickstart": { - "dependsOn": [ - "@clerk/testing#build", - "@clerk/clerk-js#build", - "@clerk/ui#build", - "@clerk/backend#build", - "@clerk/nextjs#build" - ], "env": ["CLEANUP", "DEBUG", "E2E_*", "INTEGRATION_INSTANCE_KEYS"], "inputs": ["integration/**"], "outputLogs": "new-only" }, "//#test:integration:astro": { - "dependsOn": [ - "@clerk/testing#build", - "@clerk/clerk-js#build", - "@clerk/ui#build", - "@clerk/backend#build", - "@clerk/astro#build" - ], "env": ["CLEANUP", "DEBUG", "E2E_*", "INTEGRATION_INSTANCE_KEYS"], "inputs": ["integration/**"], "outputLogs": "new-only" }, "//#test:integration:localhost": { - "dependsOn": [ - "@clerk/testing#build", - "@clerk/clerk-js#build", - "@clerk/ui#build", - "@clerk/backend#build", - "@clerk/nextjs#build" - ], "env": ["CLEANUP", "DEBUG", "E2E_*", "INTEGRATION_INSTANCE_KEYS", "NODE_EXTRA_CA_CERTS"], "inputs": ["integration/**"], "outputLogs": "new-only" }, "//#test:integration:sessions": { - "dependsOn": [ - "@clerk/testing#build", - "@clerk/clerk-js#build", - "@clerk/ui#build", - "@clerk/backend#build", - "@clerk/nextjs#build" - ], "env": ["CLEANUP", "DEBUG", "DISABLE_WEB_SECURITY", "E2E_*", "INTEGRATION_INSTANCE_KEYS", "NODE_EXTRA_CA_CERTS"], "inputs": ["integration/**"], "outputLogs": "new-only" }, "//#test:integration:sessions:staging": { - "dependsOn": [ - "@clerk/testing#build", - "@clerk/clerk-js#build", - "@clerk/ui#build", - "@clerk/backend#build", - "@clerk/nextjs#build" - ], "env": ["CLEANUP", "DEBUG", "DISABLE_WEB_SECURITY", "E2E_*", "INTEGRATION_INSTANCE_KEYS", "NODE_EXTRA_CA_CERTS"], "inputs": ["integration/**"], "outputLogs": "new-only" }, "//#test:integration:handshake": { - "dependsOn": [ - "@clerk/testing#build", - "@clerk/clerk-js#build", - "@clerk/ui#build", - "@clerk/backend#build", - "@clerk/nextjs#build" - ], "env": ["CLEANUP", "DEBUG", "DISABLE_WEB_SECURITY", "E2E_*", "INTEGRATION_INSTANCE_KEYS", "NODE_EXTRA_CA_CERTS"], "inputs": ["integration/**"], "outputLogs": "new-only" }, "//#test:integration:handshake:staging": { - "dependsOn": [ - "@clerk/testing#build", - "@clerk/clerk-js#build", - "@clerk/ui#build", - "@clerk/backend#build", - "@clerk/nextjs#build" - ], "env": ["CLEANUP", "DEBUG", "DISABLE_WEB_SECURITY", "E2E_*", "INTEGRATION_INSTANCE_KEYS", "NODE_EXTRA_CA_CERTS"], "inputs": ["integration/**"], "outputLogs": "new-only" }, "//#test:integration:expo-web": { - "dependsOn": [ - "@clerk/testing#build", - "@clerk/clerk-js#build", - "@clerk/ui#build", - "@clerk/expo#build", - "@clerk/react#build" - ], "env": ["CLEANUP", "DEBUG", "E2E_*", "INTEGRATION_INSTANCE_KEYS"], "inputs": ["integration/**"], "outputLogs": "new-only" }, "//#test:integration:tanstack-react-start": { - "dependsOn": [ - "@clerk/testing#build", - "@clerk/clerk-js#build", - "@clerk/ui#build", - "@clerk/tanstack-react-start#build", - "@clerk/react#build" - ], "env": ["CLEANUP", "DEBUG", "E2E_*", "INTEGRATION_INSTANCE_KEYS"], "inputs": ["integration/**"], "outputLogs": "new-only" }, "//#test:integration:vue": { - "dependsOn": ["@clerk/testing#build", "@clerk/clerk-js#build", "@clerk/ui#build", "@clerk/vue#build"], "env": ["CLEANUP", "DEBUG", "E2E_*", "INTEGRATION_INSTANCE_KEYS"], "inputs": ["integration/**"], "outputLogs": "new-only" }, "//#test:integration:nuxt": { - "dependsOn": [ - "@clerk/testing#build", - "@clerk/clerk-js#build", - "@clerk/ui#build", - "@clerk/vue#build", - "@clerk/backend#build", - "@clerk/nuxt#build" - ], "env": ["CLEANUP", "DEBUG", "E2E_*", "INTEGRATION_INSTANCE_KEYS"], "inputs": ["integration/**"], "outputLogs": "new-only" }, "//#test:integration:react-router": { - "dependsOn": [ - "@clerk/testing#build", - "@clerk/clerk-js#build", - "@clerk/ui#build", - "@clerk/react-router#build", - "@clerk/backend#build", - "@clerk/react#build" - ], "env": ["CLEANUP", "DEBUG", "E2E_*", "INTEGRATION_INSTANCE_KEYS"], "inputs": ["integration/**"], "outputLogs": "new-only" }, "//#test:integration:billing": { - "dependsOn": [ - "@clerk/testing#build", - "@clerk/clerk-js#build", - "@clerk/ui#build", - "@clerk/backend#build", - "@clerk/nextjs#build", - "@clerk/vue#build" - ], "env": ["CLEANUP", "DEBUG", "E2E_*", "INTEGRATION_INSTANCE_KEYS"], "inputs": ["integration/**"], "outputLogs": "new-only" }, "//#test:integration:machine": { - "dependsOn": [ - "@clerk/testing#build", - "@clerk/clerk-js#build", - "@clerk/ui#build", - "@clerk/backend#build", - "@clerk/nextjs#build", - "@clerk/express#build" - ], "env": ["CLEANUP", "DEBUG", "E2E_*", "INTEGRATION_INSTANCE_KEYS"], "inputs": ["integration/**"], "outputLogs": "new-only" }, "//#test:integration:custom": { - "dependsOn": [ - "@clerk/testing#build", - "@clerk/clerk-js#build", - "@clerk/ui#build", - "@clerk/backend#build", - "@clerk/react#build" - ], "env": ["CLEANUP", "DEBUG", "E2E_*", "INTEGRATION_INSTANCE_KEYS"], "inputs": ["integration/**"], "outputLogs": "new-only" From 87a3eacd35d74002684fb51ff2a9d86567b62fd6 Mon Sep 17 00:00:00 2001 From: Nikos Douvlis Date: Fri, 5 Dec 2025 22:07:16 +0200 Subject: [PATCH 15/41] fix ci.yml --- .github/workflows/ci.yml | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index eae08f50444..0b5ef139084 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -64,10 +64,10 @@ jobs: - name: Setup id: config uses: ./.github/actions/init-blacksmith - with: - # turbo-signature: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }} - # turbo-team: ${{ vars.TURBO_TEAM }} - # turbo-token: ${{ secrets.TURBO_TOKEN }} + # with: + # turbo-signature: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }} + # turbo-team: ${{ vars.TURBO_TEAM }} + # turbo-token: ${{ secrets.TURBO_TOKEN }} - name: Verify lockfile is deduped run: pnpm dedupe --check @@ -110,11 +110,11 @@ jobs: - name: Setup id: config uses: ./.github/actions/init-blacksmith - with: - # turbo-signature: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }} - turbo-summarize: ${{ env.TURBO_SUMMARIZE }} - # turbo-team: ${{ vars.TURBO_TEAM }} - # turbo-token: ${{ secrets.TURBO_TOKEN }} + # with: + # turbo-signature: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }} + # turbo-summarize: ${{ env.TURBO_SUMMARIZE }} + # turbo-team: ${{ vars.TURBO_TEAM }} + # turbo-token: ${{ secrets.TURBO_TOKEN }} - name: Turbo Build run: pnpm turbo build $TURBO_ARGS --only @@ -154,11 +154,11 @@ jobs: - name: Setup id: config uses: ./.github/actions/init-blacksmith - with: - # turbo-signature: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }} - turbo-summarize: ${{ env.TURBO_SUMMARIZE }} - # turbo-team: ${{ vars.TURBO_TEAM }} - # turbo-token: ${{ secrets.TURBO_TOKEN }} + # with: + # turbo-signature: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }} + # turbo-summarize: ${{ env.TURBO_SUMMARIZE }} + # turbo-team: ${{ vars.TURBO_TEAM }} + # turbo-token: ${{ secrets.TURBO_TOKEN }} - name: Check size using bundlewatch continue-on-error: true @@ -232,7 +232,7 @@ jobs: # Ensures that all builds are cached appropriately with a consistent run name `Unit Tests (20)`. node-version: ${{ matrix.node-version }} # turbo-signature: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }} - turbo-summarize: ${{ env.TURBO_SUMMARIZE }} + # turbo-summarize: ${{ env.TURBO_SUMMARIZE }} # turbo-team: ${{ vars.TURBO_TEAM }} # turbo-token: ${{ secrets.TURBO_TOKEN }} @@ -521,7 +521,7 @@ jobs: turbo-enabled: true node-version: 22 # turbo-signature: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }} - turbo-summarize: ${{ env.TURBO_SUMMARIZE }} + # turbo-summarize: ${{ env.TURBO_SUMMARIZE }} # turbo-team: ${{ vars.TURBO_TEAM }} # turbo-token: ${{ secrets.TURBO_TOKEN }} From 35e8acd2db88369c840a5dbbebaf66236ba87458 Mon Sep 17 00:00:00 2001 From: Nikos Douvlis Date: Fri, 5 Dec 2025 22:22:03 +0200 Subject: [PATCH 16/41] debug artifacts 1 --- .github/workflows/ci.yml | 91 ++++++++++++++++++++++++++-- integration/README.md | 4 +- integration/constants.ts | 4 +- integration/tests/global.teardown.ts | 2 +- 4 files changed, 90 insertions(+), 11 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0b5ef139084..6028a9a5f00 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -320,12 +320,12 @@ jobs: - test-name: "billing" test-project: "chrome" clerk-use-rq: "true" - - test-name: "machine" - test-project: "chrome" - clerk-use-rq: "false" - - test-name: "machine" - test-project: "chrome" - clerk-use-rq: "true" + # - test-name: "machine" + # test-project: "chrome" + # clerk-use-rq: "false" + # - test-name: "machine" + # test-project: "chrome" + # clerk-use-rq: "true" - test-name: "nextjs" test-project: "chrome" next-version: "15" @@ -476,6 +476,7 @@ jobs: timeout-minutes: 25 run: pnpm turbo test:integration:${{ matrix.test-name }} $TURBO_ARGS env: + E2E_CLEANUP: "0" E2E_APP_CLERK_JS_DIR: ${{runner.temp}} E2E_APP_CLERK_UI_DIR: ${{runner.temp}} E2E_CLERK_JS_VERSION: "latest" @@ -488,6 +489,74 @@ jobs: MAILSAC_API_KEY: ${{ secrets.MAILSAC_API_KEY }} NODE_EXTRA_CA_CERTS: ${{ github.workspace }}/integration/certs/rootCA.pem + - name: List temp directory contents + if: ${{ always() }} + run: | + echo "Contents of /tmp:" + ls -la /tmp/ | grep -E '(temp|integration)' || echo "No temp/integration directories found" + if [ -d "/tmp/.temp_integration" ]; then + echo "Contents of /tmp/.temp_integration:" + ls -la /tmp/.temp_integration/ + else + echo "Directory /tmp/.temp_integration does not exist" + fi + + - name: Package integration temp artifacts + if: ${{ cancelled() || failure() }} + continue-on-error: true + run: | + if [ ! -d "/tmp/.temp_integration" ]; then + echo "No temp integration directory found" + exit 0 + fi + + cd /tmp/.temp_integration + + # Create a directory for artifacts to compress + mkdir -p /tmp/integration-artifacts + + # Copy state.json if it exists + if [ -f "state.json" ]; then + cp state.json /tmp/integration-artifacts/ + echo "Copied state.json" + fi + + # Find all long-running app directories and get the most recent for each prefix + for dir in long-running--*; do + if [ ! -d "$dir" ]; then + continue + fi + + # Extract prefix by removing the last two parts (timestamp and hash) + # Pattern: prefix__timestamp__hash + prefix=$(echo "$dir" | sed -E 's/__[^_]+__[^_]+$//') + + # Find the most recent directory with this prefix + most_recent=$(ls -dt ${prefix}__* 2>/dev/null | head -n 1) + + if [ -n "$most_recent" ] && [ ! -d "/tmp/integration-artifacts/$most_recent" ]; then + cp -r "$most_recent" /tmp/integration-artifacts/ + echo "Copied $most_recent (most recent for prefix: $prefix)" + + # Extract timestamp from the directory name to find matching log files + timestamp=$(echo "$most_recent" | sed -E 's/.*__([0-9]+)__[^_]+$/\1/') + + # Copy matching log files (both clerkJs and clerkUi logs) + for log in clerkJsHttpServer.${timestamp}.* clerkUiHttpServer.${timestamp}.*; do + if [ -f "$log" ]; then + cp "$log" /tmp/integration-artifacts/ + echo "Copied log file: $log" + fi + done + fi + done + + # Create compressed archive + cd /tmp + tar -czf integration-debug.tar.gz integration-artifacts/ + echo "Created integration-debug.tar.gz" + ls -lh integration-debug.tar.gz + - name: Upload test-results if: ${{ cancelled() || failure() }} uses: actions/upload-artifact@v4 @@ -496,6 +565,16 @@ jobs: path: integration/test-results retention-days: 1 + - name: Upload integration debug archive + if: ${{ cancelled() || failure() }} + continue-on-error: true + uses: actions/upload-artifact@v4 + with: + name: integration-debug-${{ github.run_id }}-${{ github.run_attempt }}-${{ matrix.test-name }}${{ matrix.next-version && format('-next{0}', matrix.next-version) || '' }}${{ matrix.clerk-use-rq == 'true' && '-rq' || '' }} + path: /tmp/integration-debug.tar.gz + retention-days: 1 + if-no-files-found: ignore + pkg-pr-new: name: Publish with pkg-pr-new if: ${{ github.event_name != 'pull_request' || github.event.pull_request.draft == false }} diff --git a/integration/README.md b/integration/README.md index 64e26f9ac06..68dbfada90d 100644 --- a/integration/README.md +++ b/integration/README.md @@ -75,10 +75,10 @@ Below you can find code snippets for running tests in a specific manner, easily #### Keep temporary site -During E2E runs a temporary site is created in which the template is copied into. If you want to keep the site around, pass the `CLEANUP` environment variable: +During E2E runs a temporary site is created in which the template is copied into. If you want to keep the site around, pass the `E2E_CLEANUP` environment variable: ```shell -CLEANUP=0 pnpm test:integration:base +E2E_CLEANUP=0 pnpm test:integration:base ``` For all available environment variables, check the [`constants.ts`](../integration/constants.ts) file. diff --git a/integration/constants.ts b/integration/constants.ts index 7195880dba2..227d6e267c3 100644 --- a/integration/constants.ts +++ b/integration/constants.ts @@ -38,10 +38,10 @@ export const constants = { */ E2E_APP_CLERK_UI_DIR: process.env.E2E_APP_CLERK_UI_DIR, /** - * If CLEANUP=0 is used, the .tmp_integration directory will not be deleted. + * If E2E_CLEANUP=0 is used, the .tmp_integration directory will not be deleted. * This is useful for debugging locally. */ - CLEANUP: !(process.env.CLEANUP === '0' || process.env.CLEANUP === 'false'), + E2E_CLEANUP: !(process.env.E2E_CLEANUP === '0' || process.env.E2E_CLEANUP === 'false'), DEBUG: process.env.DEBUG === 'true' || process.env.DEBUG === '1', /** * Used with E2E_APP_URL if the tests need to access BAPI. diff --git a/integration/tests/global.teardown.ts b/integration/tests/global.teardown.ts index 00e9296dca5..7445ab191c7 100644 --- a/integration/tests/global.teardown.ts +++ b/integration/tests/global.teardown.ts @@ -12,7 +12,7 @@ setup('teardown long running apps', async () => { await killClerkJsHttpServer(); await killClerkUiHttpServer(); - if (appUrl || !constants.CLEANUP) { + if (appUrl || !constants.E2E_CLEANUP) { // if appUrl is provided, it means that the user is running an app manually console.log('Skipping cleanup'); return; From 48ae4edac15e311995f70cdd2322cd87a4197eb1 Mon Sep 17 00:00:00 2001 From: Nikos Douvlis Date: Fri, 5 Dec 2025 23:16:20 +0200 Subject: [PATCH 17/41] fix(integration): add vite config to express-vite template to fix cicd build The express-vite template was missing a vite.config.ts file, causing Vite to attempt pre-bundling all dependencies including @clerk packages. When esbuild (used by Vite for pre-bundling) tried to bundle @clerk/ui, it couldn't resolve the wildcard exports from @clerk/shared (e.g., @clerk/shared/internal/clerk-js/*), resulting in build failures in CI. This fix adds a vite.config.ts that excludes @clerk packages from optimizeDeps, preventing Vite from attempting to pre-bundle them. These packages are already pre-built and don't need optimization. The issue only manifested in CI because packages were installed from Verdaccio, while locally they're symlinked from the workspace, which has different resolution behavior. --- integration/templates/express-vite/vite.config.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 integration/templates/express-vite/vite.config.ts diff --git a/integration/templates/express-vite/vite.config.ts b/integration/templates/express-vite/vite.config.ts new file mode 100644 index 00000000000..d122332f7d6 --- /dev/null +++ b/integration/templates/express-vite/vite.config.ts @@ -0,0 +1,10 @@ +import { defineConfig } from 'vite'; + +// https://vitejs.dev/config/ +export default defineConfig({ + optimizeDeps: { + // Exclude Clerk packages from pre-bundling to avoid wildcard export resolution issues + // These packages are already pre-built and don't need optimization + exclude: ['@clerk/clerk-js', '@clerk/ui', '@clerk/shared'], + }, +}); From 67de7ae46a9c2d36807431ef21b4491e6b27bd5c Mon Sep 17 00:00:00 2001 From: Nikos Douvlis Date: Fri, 5 Dec 2025 23:30:41 +0200 Subject: [PATCH 18/41] fix(shared): reorder package exports to fix wildcard resolution in esbuild esbuild resolves package exports in order and matches the first pattern that fits. The generic "./*" wildcard was placed before the more specific "./internal/clerk-js/*" wildcard, causing esbuild to incorrectly match and fail to resolve nested paths like "@clerk/shared/internal/clerk-js/errors". This issue only manifested when packages were bundled (e.g., by Vite's dependency optimizer) rather than being symlinked from the workspace. It affected the express-vite integration template which imports @clerk/ui, which in turn imports from @clerk/shared/internal/clerk-js/*. The fix moves "./internal/clerk-js/*" before "./*" so more specific patterns are matched first, following the package exports best practice. Fixes #EXPRESS-VITE-CI --- .../templates/express-vite/vite.config.ts | 10 ---------- packages/shared/package.json | 20 +++++++++---------- 2 files changed, 10 insertions(+), 20 deletions(-) delete mode 100644 integration/templates/express-vite/vite.config.ts diff --git a/integration/templates/express-vite/vite.config.ts b/integration/templates/express-vite/vite.config.ts deleted file mode 100644 index d122332f7d6..00000000000 --- a/integration/templates/express-vite/vite.config.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { defineConfig } from 'vite'; - -// https://vitejs.dev/config/ -export default defineConfig({ - optimizeDeps: { - // Exclude Clerk packages from pre-bundling to avoid wildcard export resolution issues - // These packages are already pre-built and don't need optimization - exclude: ['@clerk/clerk-js', '@clerk/ui', '@clerk/shared'], - }, -}); diff --git a/packages/shared/package.json b/packages/shared/package.json index 82054683a52..c38c2062c9f 100644 --- a/packages/shared/package.json +++ b/packages/shared/package.json @@ -20,6 +20,16 @@ "default": "./dist/runtime/index.js" } }, + "./internal/clerk-js/*": { + "import": { + "types": "./dist/runtime/internal/clerk-js/*.d.mts", + "default": "./dist/runtime/internal/clerk-js/*.mjs" + }, + "require": { + "types": "./dist/runtime/internal/clerk-js/*.d.ts", + "default": "./dist/runtime/internal/clerk-js/*.js" + } + }, "./*": { "import": { "types": "./dist/runtime/*.d.mts", @@ -90,16 +100,6 @@ "default": "./dist/types/index.js" } }, - "./internal/clerk-js/*": { - "import": { - "types": "./dist/runtime/internal/clerk-js/*.d.mts", - "default": "./dist/runtime/internal/clerk-js/*.mjs" - }, - "require": { - "types": "./dist/runtime/internal/clerk-js/*.d.ts", - "default": "./dist/runtime/internal/clerk-js/*.js" - } - }, "./package.json": "./package.json" }, "files": [ From 0e057da55d71f38e1e426034ec9a770ea12266ad Mon Sep 17 00:00:00 2001 From: Nikos Douvlis Date: Fri, 5 Dec 2025 23:40:30 +0200 Subject: [PATCH 19/41] debug artifacts 5 --- .github/workflows/ci.yml | 84 +++++++++++++++++----------------------- 1 file changed, 35 insertions(+), 49 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6028a9a5f00..d6fe09a4033 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -501,7 +501,7 @@ jobs: echo "Directory /tmp/.temp_integration does not exist" fi - - name: Package integration temp artifacts + - name: Print integration logs if: ${{ cancelled() || failure() }} continue-on-error: true run: | @@ -512,51 +512,47 @@ jobs: cd /tmp/.temp_integration - # Create a directory for artifacts to compress - mkdir -p /tmp/integration-artifacts + echo "==========================================" + echo "state.json" + echo "==========================================" + cat state.json 2>/dev/null || echo "not found" + echo "" - # Copy state.json if it exists - if [ -f "state.json" ]; then - cp state.json /tmp/integration-artifacts/ - echo "Copied state.json" + if [ ! -f "state.json" ]; then + exit 0 fi - # Find all long-running app directories and get the most recent for each prefix - for dir in long-running--*; do - if [ ! -d "$dir" ]; then - continue - fi + echo "==========================================" + echo "App Logs from Long Running Apps" + echo "==========================================" + + # Extract app directories from state.json using jq + app_dirs=$(cat state.json | jq -r '.longRunningApps | to_entries[] | .value.appDir' 2>/dev/null) - # Extract prefix by removing the last two parts (timestamp and hash) - # Pattern: prefix__timestamp__hash - prefix=$(echo "$dir" | sed -E 's/__[^_]+__[^_]+$//') - - # Find the most recent directory with this prefix - most_recent=$(ls -dt ${prefix}__* 2>/dev/null | head -n 1) - - if [ -n "$most_recent" ] && [ ! -d "/tmp/integration-artifacts/$most_recent" ]; then - cp -r "$most_recent" /tmp/integration-artifacts/ - echo "Copied $most_recent (most recent for prefix: $prefix)" - - # Extract timestamp from the directory name to find matching log files - timestamp=$(echo "$most_recent" | sed -E 's/.*__([0-9]+)__[^_]+$/\1/') - - # Copy matching log files (both clerkJs and clerkUi logs) - for log in clerkJsHttpServer.${timestamp}.* clerkUiHttpServer.${timestamp}.*; do - if [ -f "$log" ]; then - cp "$log" /tmp/integration-artifacts/ - echo "Copied log file: $log" - fi - done + if [ -z "$app_dirs" ]; then + echo "No app directories found in state.json" + exit 0 + fi + + # For each app directory, print all log files + echo "$app_dirs" | while read -r app_dir; do + if [ -z "$app_dir" ] || [ ! -d "$app_dir" ]; then + continue fi + + echo "" + echo "==========================================" + echo "App: $app_dir" + echo "==========================================" + + # Find and print all log files in the app directory + find "$app_dir" -name "*.log" -type f 2>/dev/null | while read -r log_file; do + echo "" + echo "--- $(basename $log_file) ---" + cat "$log_file" + done done - # Create compressed archive - cd /tmp - tar -czf integration-debug.tar.gz integration-artifacts/ - echo "Created integration-debug.tar.gz" - ls -lh integration-debug.tar.gz - - name: Upload test-results if: ${{ cancelled() || failure() }} uses: actions/upload-artifact@v4 @@ -565,16 +561,6 @@ jobs: path: integration/test-results retention-days: 1 - - name: Upload integration debug archive - if: ${{ cancelled() || failure() }} - continue-on-error: true - uses: actions/upload-artifact@v4 - with: - name: integration-debug-${{ github.run_id }}-${{ github.run_attempt }}-${{ matrix.test-name }}${{ matrix.next-version && format('-next{0}', matrix.next-version) || '' }}${{ matrix.clerk-use-rq == 'true' && '-rq' || '' }} - path: /tmp/integration-debug.tar.gz - retention-days: 1 - if-no-files-found: ignore - pkg-pr-new: name: Publish with pkg-pr-new if: ${{ github.event_name != 'pull_request' || github.event.pull_request.draft == false }} From 7823fe68dfe9518cf6604ec96452bbd4044dcb86 Mon Sep 17 00:00:00 2001 From: Nikos Douvlis Date: Fri, 5 Dec 2025 23:16:20 +0200 Subject: [PATCH 20/41] fix(integration): add vite config to express-vite template to fix cicd build The express-vite template was missing a vite.config.ts file, causing Vite to attempt pre-bundling all dependencies including @clerk packages. When esbuild (used by Vite for pre-bundling) tried to bundle @clerk/ui, it couldn't resolve the wildcard exports from @clerk/shared (e.g., @clerk/shared/internal/clerk-js/*), resulting in build failures in CI. This fix adds a vite.config.ts that excludes @clerk packages from optimizeDeps, preventing Vite from attempting to pre-bundle them. These packages are already pre-built and don't need optimization. The issue only manifested in CI because packages were installed from Verdaccio, while locally they're symlinked from the workspace, which has different resolution behavior. --- integration/templates/express-vite/vite.config.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 integration/templates/express-vite/vite.config.ts diff --git a/integration/templates/express-vite/vite.config.ts b/integration/templates/express-vite/vite.config.ts new file mode 100644 index 00000000000..d122332f7d6 --- /dev/null +++ b/integration/templates/express-vite/vite.config.ts @@ -0,0 +1,10 @@ +import { defineConfig } from 'vite'; + +// https://vitejs.dev/config/ +export default defineConfig({ + optimizeDeps: { + // Exclude Clerk packages from pre-bundling to avoid wildcard export resolution issues + // These packages are already pre-built and don't need optimization + exclude: ['@clerk/clerk-js', '@clerk/ui', '@clerk/shared'], + }, +}); From 093a9f4315395a8a89aef59c808127ec1442f265 Mon Sep 17 00:00:00 2001 From: Nikos Douvlis Date: Fri, 5 Dec 2025 23:30:41 +0200 Subject: [PATCH 21/41] fix(shared): reorder package exports to fix wildcard resolution in esbuild esbuild resolves package exports in order and matches the first pattern that fits. The generic "./*" wildcard was placed before the more specific "./internal/clerk-js/*" wildcard, causing esbuild to incorrectly match and fail to resolve nested paths like "@clerk/shared/internal/clerk-js/errors". This issue only manifested when packages were bundled (e.g., by Vite's dependency optimizer) rather than being symlinked from the workspace. It affected the express-vite integration template which imports @clerk/ui, which in turn imports from @clerk/shared/internal/clerk-js/*. The fix moves "./internal/clerk-js/*" before "./*" so more specific patterns are matched first, following the package exports best practice. Fixes #EXPRESS-VITE-CI --- integration/templates/express-vite/vite.config.ts | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100644 integration/templates/express-vite/vite.config.ts diff --git a/integration/templates/express-vite/vite.config.ts b/integration/templates/express-vite/vite.config.ts deleted file mode 100644 index d122332f7d6..00000000000 --- a/integration/templates/express-vite/vite.config.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { defineConfig } from 'vite'; - -// https://vitejs.dev/config/ -export default defineConfig({ - optimizeDeps: { - // Exclude Clerk packages from pre-bundling to avoid wildcard export resolution issues - // These packages are already pre-built and don't need optimization - exclude: ['@clerk/clerk-js', '@clerk/ui', '@clerk/shared'], - }, -}); From 9ee8ee76d4177296a24c4e4c09447408690762f7 Mon Sep 17 00:00:00 2001 From: Nikos Douvlis Date: Sat, 6 Dec 2025 00:38:50 +0200 Subject: [PATCH 22/41] chore(shared): force rebuild after package.json exports reordering --- packages/shared/src/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts index 82ff1de27e8..ad545eb37a7 100644 --- a/packages/shared/src/index.ts +++ b/packages/shared/src/index.ts @@ -3,3 +3,4 @@ throw new Error( ); export {}; +// Force rebuild for exports reordering From f4817ffb19ab19f79acb6a3d26dcc0d9034b92ed Mon Sep 17 00:00:00 2001 From: Nikos Douvlis Date: Sat, 6 Dec 2025 00:44:48 +0200 Subject: [PATCH 23/41] fix(integration): add vite config to exclude clerk packages from esbuild optimization esbuild (used by Vite's dependency optimizer) does not properly support nested wildcard patterns in package exports like './internal/clerk-js/*'. When @clerk/ui imports from these paths, esbuild fails to resolve them during bundling. Excluding @clerk packages from optimizeDeps prevents Vite from trying to pre-bundle them with esbuild. These packages are already pre-built and don't need optimization. --- integration/templates/express-vite/vite.config.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 integration/templates/express-vite/vite.config.ts diff --git a/integration/templates/express-vite/vite.config.ts b/integration/templates/express-vite/vite.config.ts new file mode 100644 index 00000000000..b471db5ed6c --- /dev/null +++ b/integration/templates/express-vite/vite.config.ts @@ -0,0 +1,11 @@ +import { defineConfig } from 'vite'; + +// https://vitejs.dev/config/ +export default defineConfig({ + optimizeDeps: { + // Exclude Clerk packages from pre-bundling to avoid esbuild issues with + // nested wildcard exports like "@clerk/shared/internal/clerk-js/*" + // These packages are already pre-built and don't need optimization + exclude: ['@clerk/clerk-js', '@clerk/ui', '@clerk/shared'], + }, +}); From 70533f20f0327f6c7a3aceb98efe849f351a2b4a Mon Sep 17 00:00:00 2001 From: Nikos Douvlis Date: Sat, 6 Dec 2025 00:46:45 +0200 Subject: [PATCH 24/41] fix(shared): replace wildcard exports with explicit paths for esbuild compatibility esbuild does not properly support nested wildcard patterns like './internal/clerk-js/*' in package.json exports. Replaced the wildcard with 22 explicit export entries. This ensures esbuild can resolve imports like '@clerk/shared/internal/clerk-js/errors' when bundling @clerk/ui in Vite's dependency optimizer. --- .../templates/express-vite/vite.config.ts | 11 - packages/shared/package.json | 220 +++++++++++++++++- packages/shared/src/index.ts | 2 +- 3 files changed, 216 insertions(+), 17 deletions(-) delete mode 100644 integration/templates/express-vite/vite.config.ts diff --git a/integration/templates/express-vite/vite.config.ts b/integration/templates/express-vite/vite.config.ts deleted file mode 100644 index b471db5ed6c..00000000000 --- a/integration/templates/express-vite/vite.config.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { defineConfig } from 'vite'; - -// https://vitejs.dev/config/ -export default defineConfig({ - optimizeDeps: { - // Exclude Clerk packages from pre-bundling to avoid esbuild issues with - // nested wildcard exports like "@clerk/shared/internal/clerk-js/*" - // These packages are already pre-built and don't need optimization - exclude: ['@clerk/clerk-js', '@clerk/ui', '@clerk/shared'], - }, -}); diff --git a/packages/shared/package.json b/packages/shared/package.json index c38c2062c9f..a5c99641c19 100644 --- a/packages/shared/package.json +++ b/packages/shared/package.json @@ -20,14 +20,224 @@ "default": "./dist/runtime/index.js" } }, - "./internal/clerk-js/*": { + "./internal/clerk-js/completeSignUpFlow": { "import": { - "types": "./dist/runtime/internal/clerk-js/*.d.mts", - "default": "./dist/runtime/internal/clerk-js/*.mjs" + "types": "./dist/runtime/internal/clerk-js/completeSignUpFlow.d.mts", + "default": "./dist/runtime/internal/clerk-js/completeSignUpFlow.mjs" }, "require": { - "types": "./dist/runtime/internal/clerk-js/*.d.ts", - "default": "./dist/runtime/internal/clerk-js/*.js" + "types": "./dist/runtime/internal/clerk-js/completeSignUpFlow.d.ts", + "default": "./dist/runtime/internal/clerk-js/completeSignUpFlow.js" + } + }, + "./internal/clerk-js/componentGuards": { + "import": { + "types": "./dist/runtime/internal/clerk-js/componentGuards.d.mts", + "default": "./dist/runtime/internal/clerk-js/componentGuards.mjs" + }, + "require": { + "types": "./dist/runtime/internal/clerk-js/componentGuards.d.ts", + "default": "./dist/runtime/internal/clerk-js/componentGuards.js" + } + }, + "./internal/clerk-js/constants": { + "import": { + "types": "./dist/runtime/internal/clerk-js/constants.d.mts", + "default": "./dist/runtime/internal/clerk-js/constants.mjs" + }, + "require": { + "types": "./dist/runtime/internal/clerk-js/constants.d.ts", + "default": "./dist/runtime/internal/clerk-js/constants.js" + } + }, + "./internal/clerk-js/email": { + "import": { + "types": "./dist/runtime/internal/clerk-js/email.d.mts", + "default": "./dist/runtime/internal/clerk-js/email.mjs" + }, + "require": { + "types": "./dist/runtime/internal/clerk-js/email.d.ts", + "default": "./dist/runtime/internal/clerk-js/email.js" + } + }, + "./internal/clerk-js/encoders": { + "import": { + "types": "./dist/runtime/internal/clerk-js/encoders.d.mts", + "default": "./dist/runtime/internal/clerk-js/encoders.mjs" + }, + "require": { + "types": "./dist/runtime/internal/clerk-js/encoders.d.ts", + "default": "./dist/runtime/internal/clerk-js/encoders.js" + } + }, + "./internal/clerk-js/errors": { + "import": { + "types": "./dist/runtime/internal/clerk-js/errors.d.mts", + "default": "./dist/runtime/internal/clerk-js/errors.mjs" + }, + "require": { + "types": "./dist/runtime/internal/clerk-js/errors.d.ts", + "default": "./dist/runtime/internal/clerk-js/errors.js" + } + }, + "./internal/clerk-js/hex": { + "import": { + "types": "./dist/runtime/internal/clerk-js/hex.d.mts", + "default": "./dist/runtime/internal/clerk-js/hex.mjs" + }, + "require": { + "types": "./dist/runtime/internal/clerk-js/hex.d.ts", + "default": "./dist/runtime/internal/clerk-js/hex.js" + } + }, + "./internal/clerk-js/injectedWeb3Providers": { + "import": { + "types": "./dist/runtime/internal/clerk-js/injectedWeb3Providers.d.mts", + "default": "./dist/runtime/internal/clerk-js/injectedWeb3Providers.mjs" + }, + "require": { + "types": "./dist/runtime/internal/clerk-js/injectedWeb3Providers.d.ts", + "default": "./dist/runtime/internal/clerk-js/injectedWeb3Providers.js" + } + }, + "./internal/clerk-js/organization": { + "import": { + "types": "./dist/runtime/internal/clerk-js/organization.d.mts", + "default": "./dist/runtime/internal/clerk-js/organization.mjs" + }, + "require": { + "types": "./dist/runtime/internal/clerk-js/organization.d.ts", + "default": "./dist/runtime/internal/clerk-js/organization.js" + } + }, + "./internal/clerk-js/passkeys": { + "import": { + "types": "./dist/runtime/internal/clerk-js/passkeys.d.mts", + "default": "./dist/runtime/internal/clerk-js/passkeys.mjs" + }, + "require": { + "types": "./dist/runtime/internal/clerk-js/passkeys.d.ts", + "default": "./dist/runtime/internal/clerk-js/passkeys.js" + } + }, + "./internal/clerk-js/path": { + "import": { + "types": "./dist/runtime/internal/clerk-js/path.d.mts", + "default": "./dist/runtime/internal/clerk-js/path.mjs" + }, + "require": { + "types": "./dist/runtime/internal/clerk-js/path.d.ts", + "default": "./dist/runtime/internal/clerk-js/path.js" + } + }, + "./internal/clerk-js/queryParams": { + "import": { + "types": "./dist/runtime/internal/clerk-js/queryParams.d.mts", + "default": "./dist/runtime/internal/clerk-js/queryParams.mjs" + }, + "require": { + "types": "./dist/runtime/internal/clerk-js/queryParams.d.ts", + "default": "./dist/runtime/internal/clerk-js/queryParams.js" + } + }, + "./internal/clerk-js/queryStateParams": { + "import": { + "types": "./dist/runtime/internal/clerk-js/queryStateParams.d.mts", + "default": "./dist/runtime/internal/clerk-js/queryStateParams.mjs" + }, + "require": { + "types": "./dist/runtime/internal/clerk-js/queryStateParams.d.ts", + "default": "./dist/runtime/internal/clerk-js/queryStateParams.js" + } + }, + "./internal/clerk-js/querystring": { + "import": { + "types": "./dist/runtime/internal/clerk-js/querystring.d.mts", + "default": "./dist/runtime/internal/clerk-js/querystring.mjs" + }, + "require": { + "types": "./dist/runtime/internal/clerk-js/querystring.d.ts", + "default": "./dist/runtime/internal/clerk-js/querystring.js" + } + }, + "./internal/clerk-js/redirectUrls": { + "import": { + "types": "./dist/runtime/internal/clerk-js/redirectUrls.d.mts", + "default": "./dist/runtime/internal/clerk-js/redirectUrls.mjs" + }, + "require": { + "types": "./dist/runtime/internal/clerk-js/redirectUrls.d.ts", + "default": "./dist/runtime/internal/clerk-js/redirectUrls.js" + } + }, + "./internal/clerk-js/runtime": { + "import": { + "types": "./dist/runtime/internal/clerk-js/runtime.d.mts", + "default": "./dist/runtime/internal/clerk-js/runtime.mjs" + }, + "require": { + "types": "./dist/runtime/internal/clerk-js/runtime.d.ts", + "default": "./dist/runtime/internal/clerk-js/runtime.js" + } + }, + "./internal/clerk-js/sessionTasks": { + "import": { + "types": "./dist/runtime/internal/clerk-js/sessionTasks.d.mts", + "default": "./dist/runtime/internal/clerk-js/sessionTasks.mjs" + }, + "require": { + "types": "./dist/runtime/internal/clerk-js/sessionTasks.d.ts", + "default": "./dist/runtime/internal/clerk-js/sessionTasks.js" + } + }, + "./internal/clerk-js/url": { + "import": { + "types": "./dist/runtime/internal/clerk-js/url.d.mts", + "default": "./dist/runtime/internal/clerk-js/url.mjs" + }, + "require": { + "types": "./dist/runtime/internal/clerk-js/url.d.ts", + "default": "./dist/runtime/internal/clerk-js/url.js" + } + }, + "./internal/clerk-js/user": { + "import": { + "types": "./dist/runtime/internal/clerk-js/user.d.mts", + "default": "./dist/runtime/internal/clerk-js/user.mjs" + }, + "require": { + "types": "./dist/runtime/internal/clerk-js/user.d.ts", + "default": "./dist/runtime/internal/clerk-js/user.js" + } + }, + "./internal/clerk-js/warnings": { + "import": { + "types": "./dist/runtime/internal/clerk-js/warnings.d.mts", + "default": "./dist/runtime/internal/clerk-js/warnings.mjs" + }, + "require": { + "types": "./dist/runtime/internal/clerk-js/warnings.d.ts", + "default": "./dist/runtime/internal/clerk-js/warnings.js" + } + }, + "./internal/clerk-js/web3": { + "import": { + "types": "./dist/runtime/internal/clerk-js/web3.d.mts", + "default": "./dist/runtime/internal/clerk-js/web3.mjs" + }, + "require": { + "types": "./dist/runtime/internal/clerk-js/web3.d.ts", + "default": "./dist/runtime/internal/clerk-js/web3.js" + } + }, + "./internal/clerk-js/windowNavigate": { + "import": { + "types": "./dist/runtime/internal/clerk-js/windowNavigate.d.mts", + "default": "./dist/runtime/internal/clerk-js/windowNavigate.mjs" + }, + "require": { + "types": "./dist/runtime/internal/clerk-js/windowNavigate.d.ts", + "default": "./dist/runtime/internal/clerk-js/windowNavigate.js" } }, "./*": { diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts index ad545eb37a7..48634e86809 100644 --- a/packages/shared/src/index.ts +++ b/packages/shared/src/index.ts @@ -3,4 +3,4 @@ throw new Error( ); export {}; -// Force rebuild for exports reordering +// Force rebuild for explicit exports (replacing wildcard) From 1b192bd1fb39601822d2ccde60b0bef98eff4ed6 Mon Sep 17 00:00:00 2001 From: Nikos Douvlis Date: Sat, 6 Dec 2025 00:57:24 +0200 Subject: [PATCH 25/41] debug artifacts 6 --- .github/workflows/ci.yml | 33 +++++++++++++++++++ integration/templates/react-vite/src/main.tsx | 1 - 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d6fe09a4033..465c874a344 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -551,6 +551,39 @@ jobs: echo "--- $(basename $log_file) ---" cat "$log_file" done + + # Find and print all @clerk package.json files in node_modules (recursively) + echo "" + echo "==========================================" + echo "@clerk packages in node_modules (all)" + echo "==========================================" + + if [ -d "$app_dir/node_modules" ]; then + # Find all @clerk packages recursively in node_modules + clerk_packages=$(find "$app_dir/node_modules" -type d -path "*/node_modules/@clerk/*" -maxdepth 10 2>/dev/null | sort -u) + + if [ -n "$clerk_packages" ]; then + echo "Found @clerk packages:" + echo "$clerk_packages" | while read -r pkg_path; do + echo " - $pkg_path" + done + echo "" + + # Print each package.json + echo "$clerk_packages" | while read -r pkg_path; do + if [ -f "$pkg_path/package.json" ]; then + rel_path=$(echo "$pkg_path" | sed "s|$app_dir/||") + echo "" + echo "--- $rel_path/package.json ---" + cat "$pkg_path/package.json" + fi + done + else + echo "No @clerk packages found in node_modules" + fi + else + echo "No node_modules directory found at: $app_dir/node_modules" + fi done - name: Upload test-results diff --git a/integration/templates/react-vite/src/main.tsx b/integration/templates/react-vite/src/main.tsx index a95be1e5270..6145122c1e6 100644 --- a/integration/templates/react-vite/src/main.tsx +++ b/integration/templates/react-vite/src/main.tsx @@ -45,7 +45,6 @@ const Root = () => { : undefined, }} > - here? ); From 5a4a326f35e59a8554168d30d0b385b121a68858 Mon Sep 17 00:00:00 2001 From: Nikos Douvlis Date: Sat, 6 Dec 2025 01:37:07 +0200 Subject: [PATCH 26/41] fix(ci): use snapshot versions in verdaccio for integration tests Integration tests were failing because packages published to Verdaccio with the 'integration' dist-tag had transitive dependencies (e.g. @clerk/shared from @clerk/ui) that were resolved from npm instead of the local Verdaccio registry. Changed approach to use snapshot versions that don't exist on npm: - Create unique snapshot versions with `changeset version --snapshot ci` - Publish to 'latest' tag instead of 'integration' tag - Removed all 'integration' tag references from integration presets - Simplified linkPackage to return '*' in CI (gets latest snapshot) This ensures all @clerk packages, including transitive dependencies, are installed from the locally published Verdaccio versions. --- .github/actions/verdaccio/action.yml | 6 +- .github/workflows/ci.yml | 2 +- integration/presets/astro.ts | 6 +- integration/presets/custom-flows.ts | 6 +- integration/presets/express.ts | 6 +- integration/presets/react.ts | 6 +- integration/presets/utils.ts | 4 +- packages/shared/package.json | 220 +-------------------------- 8 files changed, 24 insertions(+), 232 deletions(-) diff --git a/.github/actions/verdaccio/action.yml b/.github/actions/verdaccio/action.yml index 13fee03e20a..6764b719d49 100644 --- a/.github/actions/verdaccio/action.yml +++ b/.github/actions/verdaccio/action.yml @@ -75,7 +75,7 @@ runs: - name: Print published Clerk package versions shell: bash run: | - echo "Published @clerk packages under 'integration' tag:" + echo "Published @clerk packages (snapshot versions):" echo "==================================================" packages=( "@clerk/agent-toolkit" @@ -102,6 +102,6 @@ runs: "@clerk/vue" ) for pkg in "${packages[@]}"; do - version=$(pnpm view "$pkg@integration" version 2>/dev/null || echo "not found") - printf "%-35s %s\n" "$pkg@integration:" "$version" + version=$(pnpm view "$pkg" version 2>/dev/null || echo "not found") + printf "%-35s %s\n" "$pkg:" "$version" done diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 465c874a344..9b531d2679c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -410,7 +410,7 @@ jobs: uses: ./.github/actions/verdaccio with: publish-cmd: | - if [ "$(pnpm config get registry)" = "https://registry.npmjs.org/" ]; then echo 'Error: Using default registry' && exit 1; else ${{ matrix.clerk-use-rq == 'true' && 'CLERK_USE_RQ=true' || '' }} pnpm turbo build $TURBO_ARGS --only && pnpm changeset publish --no-git-tag --tag integration; fi + if [ "$(pnpm config get registry)" = "https://registry.npmjs.org/" ]; then echo 'Error: Using default registry' && exit 1; else ${{ matrix.clerk-use-rq == 'true' && 'CLERK_USE_RQ=true' || '' }} pnpm turbo build $TURBO_ARGS --only && GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }} pnpm changeset version --snapshot ci && pnpm changeset publish --no-git-tag --tag latest; fi - name: Edit .npmrc [link-workspace-packages=false] run: sed -i -E 's/link-workspace-packages=(deep|true)/link-workspace-packages=false/' .npmrc diff --git a/integration/presets/astro.ts b/integration/presets/astro.ts index a45c421e23e..e9e310bf5fc 100644 --- a/integration/presets/astro.ts +++ b/integration/presets/astro.ts @@ -10,9 +10,9 @@ const astroNode = applicationConfig() .addScript('dev', 'pnpm dev') .addScript('build', 'pnpm build') .addScript('serve', 'pnpm preview') - .addDependency('@clerk/astro', linkPackage('astro', 'integration')) - .addDependency('@clerk/shared', linkPackage('shared', 'integration')) - .addDependency('@clerk/localizations', linkPackage('localizations', 'integration')); + .addDependency('@clerk/astro', linkPackage('astro')) + .addDependency('@clerk/shared', linkPackage('shared')) + .addDependency('@clerk/localizations', linkPackage('localizations')); const astroStatic = astroNode.clone().setName('astro-hybrid').useTemplate(templates['astro-hybrid']); diff --git a/integration/presets/custom-flows.ts b/integration/presets/custom-flows.ts index efc01e753a9..236967404b8 100644 --- a/integration/presets/custom-flows.ts +++ b/integration/presets/custom-flows.ts @@ -10,9 +10,9 @@ const reactVite = applicationConfig() .addScript('dev', 'pnpm dev') .addScript('build', 'pnpm build') .addScript('serve', 'pnpm preview') - .addDependency('@clerk/react', linkPackage('react', 'integration')) - .addDependency('@clerk/shared', linkPackage('shared', 'integration')) - .addDependency('@clerk/ui', linkPackage('ui', 'integration')); + .addDependency('@clerk/react', linkPackage('react')) + .addDependency('@clerk/shared', linkPackage('shared')) + .addDependency('@clerk/ui', linkPackage('ui')); export const customFlows = { reactVite, diff --git a/integration/presets/express.ts b/integration/presets/express.ts index f68cf904038..3a0ee82f392 100644 --- a/integration/presets/express.ts +++ b/integration/presets/express.ts @@ -10,9 +10,9 @@ const vite = applicationConfig() .addScript('dev', 'pnpm dev') .addScript('build', 'pnpm build') .addScript('serve', 'pnpm start') - .addDependency('@clerk/express', linkPackage('express', 'integration')) - .addDependency('@clerk/clerk-js', linkPackage('clerk-js', 'integration')) - .addDependency('@clerk/ui', linkPackage('ui', 'integration')); + .addDependency('@clerk/express', linkPackage('express')) + .addDependency('@clerk/clerk-js', linkPackage('clerk-js')) + .addDependency('@clerk/ui', linkPackage('ui')); export const express = { vite, diff --git a/integration/presets/react.ts b/integration/presets/react.ts index 1af28ee9b66..863e17b106c 100644 --- a/integration/presets/react.ts +++ b/integration/presets/react.ts @@ -10,9 +10,9 @@ const cra = applicationConfig() .addScript('dev', 'pnpm start') .addScript('build', 'pnpm build') .addScript('serve', 'pnpm start') - .addDependency('@clerk/react', linkPackage('react', 'integration')) - .addDependency('@clerk/shared', linkPackage('shared', 'integration')) - .addDependency('@clerk/ui', linkPackage('ui', 'integration')); + .addDependency('@clerk/react', linkPackage('react')) + .addDependency('@clerk/shared', linkPackage('shared')) + .addDependency('@clerk/ui', linkPackage('ui')); const vite = cra .clone() diff --git a/integration/presets/utils.ts b/integration/presets/utils.ts index d22e39250dd..21672d16b5b 100644 --- a/integration/presets/utils.ts +++ b/integration/presets/utils.ts @@ -3,7 +3,9 @@ import path from 'node:path'; export function linkPackage(pkg: string, tag?: string) { // eslint-disable-next-line turbo/no-undeclared-env-vars if (process.env.CI === 'true') { - return tag || '*'; + // In CI, use '*' to get the latest version from Verdaccio + // which will be the snapshot version we just published + return '*'; } return `link:${path.resolve(process.cwd(), `packages/${pkg}`)}`; diff --git a/packages/shared/package.json b/packages/shared/package.json index a5c99641c19..c38c2062c9f 100644 --- a/packages/shared/package.json +++ b/packages/shared/package.json @@ -20,224 +20,14 @@ "default": "./dist/runtime/index.js" } }, - "./internal/clerk-js/completeSignUpFlow": { + "./internal/clerk-js/*": { "import": { - "types": "./dist/runtime/internal/clerk-js/completeSignUpFlow.d.mts", - "default": "./dist/runtime/internal/clerk-js/completeSignUpFlow.mjs" + "types": "./dist/runtime/internal/clerk-js/*.d.mts", + "default": "./dist/runtime/internal/clerk-js/*.mjs" }, "require": { - "types": "./dist/runtime/internal/clerk-js/completeSignUpFlow.d.ts", - "default": "./dist/runtime/internal/clerk-js/completeSignUpFlow.js" - } - }, - "./internal/clerk-js/componentGuards": { - "import": { - "types": "./dist/runtime/internal/clerk-js/componentGuards.d.mts", - "default": "./dist/runtime/internal/clerk-js/componentGuards.mjs" - }, - "require": { - "types": "./dist/runtime/internal/clerk-js/componentGuards.d.ts", - "default": "./dist/runtime/internal/clerk-js/componentGuards.js" - } - }, - "./internal/clerk-js/constants": { - "import": { - "types": "./dist/runtime/internal/clerk-js/constants.d.mts", - "default": "./dist/runtime/internal/clerk-js/constants.mjs" - }, - "require": { - "types": "./dist/runtime/internal/clerk-js/constants.d.ts", - "default": "./dist/runtime/internal/clerk-js/constants.js" - } - }, - "./internal/clerk-js/email": { - "import": { - "types": "./dist/runtime/internal/clerk-js/email.d.mts", - "default": "./dist/runtime/internal/clerk-js/email.mjs" - }, - "require": { - "types": "./dist/runtime/internal/clerk-js/email.d.ts", - "default": "./dist/runtime/internal/clerk-js/email.js" - } - }, - "./internal/clerk-js/encoders": { - "import": { - "types": "./dist/runtime/internal/clerk-js/encoders.d.mts", - "default": "./dist/runtime/internal/clerk-js/encoders.mjs" - }, - "require": { - "types": "./dist/runtime/internal/clerk-js/encoders.d.ts", - "default": "./dist/runtime/internal/clerk-js/encoders.js" - } - }, - "./internal/clerk-js/errors": { - "import": { - "types": "./dist/runtime/internal/clerk-js/errors.d.mts", - "default": "./dist/runtime/internal/clerk-js/errors.mjs" - }, - "require": { - "types": "./dist/runtime/internal/clerk-js/errors.d.ts", - "default": "./dist/runtime/internal/clerk-js/errors.js" - } - }, - "./internal/clerk-js/hex": { - "import": { - "types": "./dist/runtime/internal/clerk-js/hex.d.mts", - "default": "./dist/runtime/internal/clerk-js/hex.mjs" - }, - "require": { - "types": "./dist/runtime/internal/clerk-js/hex.d.ts", - "default": "./dist/runtime/internal/clerk-js/hex.js" - } - }, - "./internal/clerk-js/injectedWeb3Providers": { - "import": { - "types": "./dist/runtime/internal/clerk-js/injectedWeb3Providers.d.mts", - "default": "./dist/runtime/internal/clerk-js/injectedWeb3Providers.mjs" - }, - "require": { - "types": "./dist/runtime/internal/clerk-js/injectedWeb3Providers.d.ts", - "default": "./dist/runtime/internal/clerk-js/injectedWeb3Providers.js" - } - }, - "./internal/clerk-js/organization": { - "import": { - "types": "./dist/runtime/internal/clerk-js/organization.d.mts", - "default": "./dist/runtime/internal/clerk-js/organization.mjs" - }, - "require": { - "types": "./dist/runtime/internal/clerk-js/organization.d.ts", - "default": "./dist/runtime/internal/clerk-js/organization.js" - } - }, - "./internal/clerk-js/passkeys": { - "import": { - "types": "./dist/runtime/internal/clerk-js/passkeys.d.mts", - "default": "./dist/runtime/internal/clerk-js/passkeys.mjs" - }, - "require": { - "types": "./dist/runtime/internal/clerk-js/passkeys.d.ts", - "default": "./dist/runtime/internal/clerk-js/passkeys.js" - } - }, - "./internal/clerk-js/path": { - "import": { - "types": "./dist/runtime/internal/clerk-js/path.d.mts", - "default": "./dist/runtime/internal/clerk-js/path.mjs" - }, - "require": { - "types": "./dist/runtime/internal/clerk-js/path.d.ts", - "default": "./dist/runtime/internal/clerk-js/path.js" - } - }, - "./internal/clerk-js/queryParams": { - "import": { - "types": "./dist/runtime/internal/clerk-js/queryParams.d.mts", - "default": "./dist/runtime/internal/clerk-js/queryParams.mjs" - }, - "require": { - "types": "./dist/runtime/internal/clerk-js/queryParams.d.ts", - "default": "./dist/runtime/internal/clerk-js/queryParams.js" - } - }, - "./internal/clerk-js/queryStateParams": { - "import": { - "types": "./dist/runtime/internal/clerk-js/queryStateParams.d.mts", - "default": "./dist/runtime/internal/clerk-js/queryStateParams.mjs" - }, - "require": { - "types": "./dist/runtime/internal/clerk-js/queryStateParams.d.ts", - "default": "./dist/runtime/internal/clerk-js/queryStateParams.js" - } - }, - "./internal/clerk-js/querystring": { - "import": { - "types": "./dist/runtime/internal/clerk-js/querystring.d.mts", - "default": "./dist/runtime/internal/clerk-js/querystring.mjs" - }, - "require": { - "types": "./dist/runtime/internal/clerk-js/querystring.d.ts", - "default": "./dist/runtime/internal/clerk-js/querystring.js" - } - }, - "./internal/clerk-js/redirectUrls": { - "import": { - "types": "./dist/runtime/internal/clerk-js/redirectUrls.d.mts", - "default": "./dist/runtime/internal/clerk-js/redirectUrls.mjs" - }, - "require": { - "types": "./dist/runtime/internal/clerk-js/redirectUrls.d.ts", - "default": "./dist/runtime/internal/clerk-js/redirectUrls.js" - } - }, - "./internal/clerk-js/runtime": { - "import": { - "types": "./dist/runtime/internal/clerk-js/runtime.d.mts", - "default": "./dist/runtime/internal/clerk-js/runtime.mjs" - }, - "require": { - "types": "./dist/runtime/internal/clerk-js/runtime.d.ts", - "default": "./dist/runtime/internal/clerk-js/runtime.js" - } - }, - "./internal/clerk-js/sessionTasks": { - "import": { - "types": "./dist/runtime/internal/clerk-js/sessionTasks.d.mts", - "default": "./dist/runtime/internal/clerk-js/sessionTasks.mjs" - }, - "require": { - "types": "./dist/runtime/internal/clerk-js/sessionTasks.d.ts", - "default": "./dist/runtime/internal/clerk-js/sessionTasks.js" - } - }, - "./internal/clerk-js/url": { - "import": { - "types": "./dist/runtime/internal/clerk-js/url.d.mts", - "default": "./dist/runtime/internal/clerk-js/url.mjs" - }, - "require": { - "types": "./dist/runtime/internal/clerk-js/url.d.ts", - "default": "./dist/runtime/internal/clerk-js/url.js" - } - }, - "./internal/clerk-js/user": { - "import": { - "types": "./dist/runtime/internal/clerk-js/user.d.mts", - "default": "./dist/runtime/internal/clerk-js/user.mjs" - }, - "require": { - "types": "./dist/runtime/internal/clerk-js/user.d.ts", - "default": "./dist/runtime/internal/clerk-js/user.js" - } - }, - "./internal/clerk-js/warnings": { - "import": { - "types": "./dist/runtime/internal/clerk-js/warnings.d.mts", - "default": "./dist/runtime/internal/clerk-js/warnings.mjs" - }, - "require": { - "types": "./dist/runtime/internal/clerk-js/warnings.d.ts", - "default": "./dist/runtime/internal/clerk-js/warnings.js" - } - }, - "./internal/clerk-js/web3": { - "import": { - "types": "./dist/runtime/internal/clerk-js/web3.d.mts", - "default": "./dist/runtime/internal/clerk-js/web3.mjs" - }, - "require": { - "types": "./dist/runtime/internal/clerk-js/web3.d.ts", - "default": "./dist/runtime/internal/clerk-js/web3.js" - } - }, - "./internal/clerk-js/windowNavigate": { - "import": { - "types": "./dist/runtime/internal/clerk-js/windowNavigate.d.mts", - "default": "./dist/runtime/internal/clerk-js/windowNavigate.mjs" - }, - "require": { - "types": "./dist/runtime/internal/clerk-js/windowNavigate.d.ts", - "default": "./dist/runtime/internal/clerk-js/windowNavigate.js" + "types": "./dist/runtime/internal/clerk-js/*.d.ts", + "default": "./dist/runtime/internal/clerk-js/*.js" } }, "./*": { From 14acebddca489acf77b240dd6b520f2d5f01858e Mon Sep 17 00:00:00 2001 From: Nikos Douvlis Date: Sat, 6 Dec 2025 01:56:58 +0200 Subject: [PATCH 27/41] enable all --- .github/workflows/ci.yml | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9b531d2679c..90360c9de0b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -296,21 +296,22 @@ jobs: strategy: fail-fast: false matrix: - test-name: [ + test-name: + [ "generic", "express", - # "ap-flows", - # "localhost", - # "sessions", - # "sessions:staging", - # "handshake", - # "handshake:staging", - # "astro", - # "tanstack-react-start", - # "vue", + "ap-flows", + "localhost", + "sessions", + "sessions:staging", + "handshake", + "handshake:staging", + "astro", + "tanstack-react-start", + "vue", "nuxt", - # "react-router", - # "custom", + "react-router", + "custom", ] test-project: ["chrome"] include: @@ -320,12 +321,12 @@ jobs: - test-name: "billing" test-project: "chrome" clerk-use-rq: "true" - # - test-name: "machine" - # test-project: "chrome" - # clerk-use-rq: "false" - # - test-name: "machine" - # test-project: "chrome" - # clerk-use-rq: "true" + - test-name: "machine" + test-project: "chrome" + clerk-use-rq: "false" + - test-name: "machine" + test-project: "chrome" + clerk-use-rq: "true" - test-name: "nextjs" test-project: "chrome" next-version: "15" From 85420d67ecbcae40b40a965a008229aad9f33b6e Mon Sep 17 00:00:00 2001 From: Nikos Douvlis Date: Sat, 6 Dec 2025 11:06:06 +0200 Subject: [PATCH 28/41] chore(repo): drop mailsac from integration tests --- .github/workflows/ci.yml | 1 - .github/workflows/nightly-checks.yml | 1 - integration/.env.local.sample | 1 - integration/README.md | 1 - integration/testUtils/emailService.ts | 2 -- 5 files changed, 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 90360c9de0b..f386df22f1a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -487,7 +487,6 @@ jobs: E2E_CLERK_ENCRYPTION_KEY: ${{ matrix.clerk-encryption-key }} CLERK_USE_RQ: ${{ matrix.clerk-use-rq }} INTEGRATION_INSTANCE_KEYS: ${{ secrets.INTEGRATION_INSTANCE_KEYS }} - MAILSAC_API_KEY: ${{ secrets.MAILSAC_API_KEY }} NODE_EXTRA_CA_CERTS: ${{ github.workspace }}/integration/certs/rootCA.pem - name: List temp directory contents diff --git a/.github/workflows/nightly-checks.yml b/.github/workflows/nightly-checks.yml index f74f87a2e0e..0b0df12a82f 100644 --- a/.github/workflows/nightly-checks.yml +++ b/.github/workflows/nightly-checks.yml @@ -71,7 +71,6 @@ jobs: E2E_REACT_DOM_VERSION: "19.1.0" E2E_REACT_VERSION: "19.1.0" INTEGRATION_INSTANCE_KEYS: ${{ secrets.INTEGRATION_INSTANCE_KEYS }} - MAILSAC_API_KEY: ${{ secrets.MAILSAC_API_KEY }} # Upload test artifacts if tests failed - name: Upload Test Artifacts diff --git a/integration/.env.local.sample b/integration/.env.local.sample index 9505f3baa4c..8fdb1f0151c 100644 --- a/integration/.env.local.sample +++ b/integration/.env.local.sample @@ -1,4 +1,3 @@ -MAILSAC_API_KEY= VERCEL_PROJECT_ID= VERCEL_ORG_ID= VERCEL_TOKEN= diff --git a/integration/README.md b/integration/README.md index 68dbfada90d..ff565b2cce5 100644 --- a/integration/README.md +++ b/integration/README.md @@ -578,7 +578,6 @@ Before writing tests, it's important to understand how Playwright handles test i > [!NOTE] > The test suite also uses these environment variables to run some tests: > -> - `MAILSAC_API_KEY`: Used for [Mailsac](https://mailsac.com/) to retrieve email codes and magic links from temporary email addresses. > - `VERCEL_PROJECT_ID`: Only required if you plan on running deployment tests locally. This is the Vercel project ID, and it points to an application created via the Vercel dashboard. The easiest way to get access to it is by linking a local app to the Vercel project using the Vercel CLI, and then copying the values from the `.vercel` directory. > - `VERCEL_ORG_ID`: The organization that owns the Vercel project. See above for more details. > - `VERCEL_TOKEN`: A personal access token. This corresponds to a real user running the deployment command. Attention: Be extra careful with this token as it can't be scoped to a single Vercel project, meaning that the token has access to every project in the account it belongs to. diff --git a/integration/testUtils/emailService.ts b/integration/testUtils/emailService.ts index 0de10de747b..c1cb085494d 100644 --- a/integration/testUtils/emailService.ts +++ b/integration/testUtils/emailService.ts @@ -12,8 +12,6 @@ export const createEmailService = () => { const fetcher = async (url: string | URL, init?: RequestInit) => { const headers = new Headers(init?.headers || {}); - // eslint-disable-next-line turbo/no-undeclared-env-vars - headers.set('Mailsac-Key', process.env.MAILSAC_API_KEY); return fetch(url, { ...init, headers }); }; From ae3fa0e4fc4388a7f4596891ebcb38760ed609a7 Mon Sep 17 00:00:00 2001 From: Nikos Douvlis Date: Sat, 6 Dec 2025 11:07:47 +0200 Subject: [PATCH 29/41] chore(ci): update react to 19.2.1 for canary tests --- .github/workflows/nightly-checks.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/nightly-checks.yml b/.github/workflows/nightly-checks.yml index 0b0df12a82f..79ea94e5fdf 100644 --- a/.github/workflows/nightly-checks.yml +++ b/.github/workflows/nightly-checks.yml @@ -68,8 +68,8 @@ jobs: E2E_CLERK_UI_VERSION: "latest" E2E_NEXTJS_VERSION: "canary" E2E_NPM_FORCE: "true" - E2E_REACT_DOM_VERSION: "19.1.0" - E2E_REACT_VERSION: "19.1.0" + E2E_REACT_DOM_VERSION: "19.2.1" + E2E_REACT_VERSION: "19.2.1" INTEGRATION_INSTANCE_KEYS: ${{ secrets.INTEGRATION_INSTANCE_KEYS }} # Upload test artifacts if tests failed From 21ff6ec29f8c4c1083530267e8181289eb3ae2ec Mon Sep 17 00:00:00 2001 From: Nikos Douvlis Date: Sat, 6 Dec 2025 11:23:39 +0200 Subject: [PATCH 30/41] feat(e2e): log installed Clerk package versions after setup --- integration/models/application.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/integration/models/application.ts b/integration/models/application.ts index c8a6b2df2aa..c6d30620cd1 100644 --- a/integration/models/application.ts +++ b/integration/models/application.ts @@ -46,6 +46,10 @@ export const application = ( const log = logger.child({ prefix: 'setup' }).info; await run(scripts.setup, { cwd: appDirPath, log }); state.completedSetup = true; + // Print all Clerk package versions (direct and transitive) + const clerkPackagesLog = logger.child({ prefix: 'clerk-packages' }).info; + clerkPackagesLog('Installed Clerk packages:'); + await run('pnpm list "@clerk/*" --depth 100', { cwd: appDirPath, log: clerkPackagesLog }); } }, dev: async (opts: { port?: number; manualStart?: boolean; detached?: boolean; serverUrl?: string } = {}) => { From 09cad28d5ebc885930cc8899eb84d1fad4b669e9 Mon Sep 17 00:00:00 2001 From: Nikos Douvlis Date: Sat, 6 Dec 2025 11:24:38 +0200 Subject: [PATCH 31/41] chore(ci): cleanup debug logging in cicd --- .github/workflows/ci.yml | 92 +++------------------------------------- 1 file changed, 7 insertions(+), 85 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f386df22f1a..fd7311e5b05 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -497,95 +497,17 @@ jobs: if [ -d "/tmp/.temp_integration" ]; then echo "Contents of /tmp/.temp_integration:" ls -la /tmp/.temp_integration/ + echo "Contents of all directories inside /tmp/.temp_integration:" + for dir in /tmp/.temp_integration/*/; do + if [ -d "$dir" ]; then + echo "Directory: $dir" + ls -la "$dir" + fi + done else echo "Directory /tmp/.temp_integration does not exist" fi - - name: Print integration logs - if: ${{ cancelled() || failure() }} - continue-on-error: true - run: | - if [ ! -d "/tmp/.temp_integration" ]; then - echo "No temp integration directory found" - exit 0 - fi - - cd /tmp/.temp_integration - - echo "==========================================" - echo "state.json" - echo "==========================================" - cat state.json 2>/dev/null || echo "not found" - echo "" - - if [ ! -f "state.json" ]; then - exit 0 - fi - - echo "==========================================" - echo "App Logs from Long Running Apps" - echo "==========================================" - - # Extract app directories from state.json using jq - app_dirs=$(cat state.json | jq -r '.longRunningApps | to_entries[] | .value.appDir' 2>/dev/null) - - if [ -z "$app_dirs" ]; then - echo "No app directories found in state.json" - exit 0 - fi - - # For each app directory, print all log files - echo "$app_dirs" | while read -r app_dir; do - if [ -z "$app_dir" ] || [ ! -d "$app_dir" ]; then - continue - fi - - echo "" - echo "==========================================" - echo "App: $app_dir" - echo "==========================================" - - # Find and print all log files in the app directory - find "$app_dir" -name "*.log" -type f 2>/dev/null | while read -r log_file; do - echo "" - echo "--- $(basename $log_file) ---" - cat "$log_file" - done - - # Find and print all @clerk package.json files in node_modules (recursively) - echo "" - echo "==========================================" - echo "@clerk packages in node_modules (all)" - echo "==========================================" - - if [ -d "$app_dir/node_modules" ]; then - # Find all @clerk packages recursively in node_modules - clerk_packages=$(find "$app_dir/node_modules" -type d -path "*/node_modules/@clerk/*" -maxdepth 10 2>/dev/null | sort -u) - - if [ -n "$clerk_packages" ]; then - echo "Found @clerk packages:" - echo "$clerk_packages" | while read -r pkg_path; do - echo " - $pkg_path" - done - echo "" - - # Print each package.json - echo "$clerk_packages" | while read -r pkg_path; do - if [ -f "$pkg_path/package.json" ]; then - rel_path=$(echo "$pkg_path" | sed "s|$app_dir/||") - echo "" - echo "--- $rel_path/package.json ---" - cat "$pkg_path/package.json" - fi - done - else - echo "No @clerk packages found in node_modules" - fi - else - echo "No node_modules directory found at: $app_dir/node_modules" - fi - done - - name: Upload test-results if: ${{ cancelled() || failure() }} uses: actions/upload-artifact@v4 From 03bb52fd5a59dcce6c5cf85e06f633a3182fdc5f Mon Sep 17 00:00:00 2001 From: Nikos Douvlis Date: Sat, 6 Dec 2025 11:24:59 +0200 Subject: [PATCH 32/41] chore(ci): reduce tests --- .github/workflows/ci.yml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fd7311e5b05..20e46a68691 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -318,23 +318,23 @@ jobs: - test-name: "billing" test-project: "chrome" clerk-use-rq: "false" - - test-name: "billing" - test-project: "chrome" - clerk-use-rq: "true" + # - test-name: "billing" + # test-project: "chrome" + # clerk-use-rq: "true" - test-name: "machine" test-project: "chrome" clerk-use-rq: "false" - - test-name: "machine" - test-project: "chrome" - clerk-use-rq: "true" + # - test-name: "machine" + # test-project: "chrome" + # clerk-use-rq: "true" - test-name: "nextjs" test-project: "chrome" next-version: "15" clerk-use-rq: "false" - - test-name: "nextjs" - test-project: "chrome" - next-version: "15" - clerk-use-rq: "true" + # - test-name: "nextjs" + # test-project: "chrome" + # next-version: "15" + # clerk-use-rq: "true" - test-name: "nextjs" test-project: "chrome" next-version: "16" From a76cddd3134f1539c882b4558e6110e8e8ace731 Mon Sep 17 00:00:00 2001 From: Nikos Douvlis Date: Sat, 6 Dec 2025 11:38:07 +0200 Subject: [PATCH 33/41] feat(e2e): fix clerk pkg logging --- integration/models/application.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/integration/models/application.ts b/integration/models/application.ts index c6d30620cd1..2c0288fdb3b 100644 --- a/integration/models/application.ts +++ b/integration/models/application.ts @@ -48,8 +48,8 @@ export const application = ( state.completedSetup = true; // Print all Clerk package versions (direct and transitive) const clerkPackagesLog = logger.child({ prefix: 'clerk-packages' }).info; - clerkPackagesLog('Installed Clerk packages:'); - await run('pnpm list "@clerk/*" --depth 100', { cwd: appDirPath, log: clerkPackagesLog }); + clerkPackagesLog('Installed @clerk/* packages:'); + await run('pnpm list @clerk/* --depth 100', { cwd: appDirPath, log: clerkPackagesLog }); } }, dev: async (opts: { port?: number; manualStart?: boolean; detached?: boolean; serverUrl?: string } = {}) => { From 50e333750234c8e6d3cfb1747361baf5912458f6 Mon Sep 17 00:00:00 2001 From: Nikos Douvlis Date: Sat, 6 Dec 2025 12:03:47 +0200 Subject: [PATCH 34/41] feat(ci): version all pkgs before publishing to verdaccio --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 20e46a68691..d12534c9d34 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -411,7 +411,7 @@ jobs: uses: ./.github/actions/verdaccio with: publish-cmd: | - if [ "$(pnpm config get registry)" = "https://registry.npmjs.org/" ]; then echo 'Error: Using default registry' && exit 1; else ${{ matrix.clerk-use-rq == 'true' && 'CLERK_USE_RQ=true' || '' }} pnpm turbo build $TURBO_ARGS --only && GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }} pnpm changeset version --snapshot ci && pnpm changeset publish --no-git-tag --tag latest; fi + if [ "$(pnpm config get registry)" = "https://registry.npmjs.org/" ]; then echo 'Error: Using default registry' && exit 1; else node ./scripts/snapshot.mjs ci && ${{ matrix.clerk-use-rq == 'true' && 'CLERK_USE_RQ=true' || '' }} pnpm turbo build $TURBO_ARGS --only && pnpm changeset publish --no-git-tag --tag latest; fi - name: Edit .npmrc [link-workspace-packages=false] run: sed -i -E 's/link-workspace-packages=(deep|true)/link-workspace-packages=false/' .npmrc From 0e21635ce6c0aa03954db4b3e37e2c27cb2e9926 Mon Sep 17 00:00:00 2001 From: Nikos Douvlis Date: Sat, 6 Dec 2025 12:18:18 +0200 Subject: [PATCH 35/41] fix(e2e): automatically setup clerk testing tokens in app.dev() Integration tests that create their own applications (using `.clone().commit()`) were failing in CI with "CLERK_FAPI is required" errors. This happened because `setupClerkTestingToken()` needs the CLERK_FAPI environment variable, which is set by calling `clerkSetup()`. Long-running apps automatically call `clerkSetup()` during init, but apps created inline in tests did not. Rather than requiring each test to manually call `clerkSetup()`, moved it into the `Application.dev()` method to run automatically after the server starts. This ensures all applications (both long-running and inline) have proper testing token setup without manual intervention, preventing future test failures and reducing boilerplate. --- integration/models/application.ts | 33 +++++++++++++++++++ .../tests/custom-flows/sign-in.test.ts | 16 --------- .../tests/custom-flows/sign-up.test.ts | 16 --------- 3 files changed, 33 insertions(+), 32 deletions(-) diff --git a/integration/models/application.ts b/integration/models/application.ts index 2c0288fdb3b..c4b2b059a92 100644 --- a/integration/models/application.ts +++ b/integration/models/application.ts @@ -1,5 +1,8 @@ import * as path from 'node:path'; +import { parsePublishableKey } from '@clerk/shared/keys'; +import { clerkSetup } from '@clerk/testing/playwright'; + import { awaitableTreekill, createLogger, fs, getPort, run, waitForIdleProcess, waitForServer } from '../scripts'; import type { ApplicationConfig } from './applicationConfig.js'; import type { EnvironmentConfig } from './environment.js'; @@ -86,6 +89,36 @@ export const application = ( log(`Server started at ${runtimeServerUrl}, pid: ${proc.pid}`); cleanupFns.push(() => awaitableTreekill(proc.pid, 'SIGKILL')); state.serverUrl = runtimeServerUrl; + + // Setup Clerk testing tokens after the server is running + if (state.env) { + try { + const publishableKey = state.env.publicVariables.get('CLERK_PUBLISHABLE_KEY'); + const secretKey = state.env.privateVariables.get('CLERK_SECRET_KEY'); + const apiUrl = state.env.privateVariables.get('CLERK_API_URL'); + + if (publishableKey && secretKey) { + const { instanceType, frontendApi: frontendApiUrl } = parsePublishableKey(publishableKey); + + if (instanceType !== 'development') { + log('Skipping clerkSetup for non-development instance'); + } else { + await clerkSetup({ + publishableKey, + frontendApiUrl, + secretKey, + // @ts-expect-error apiUrl is not a typed option for clerkSetup, but it is accepted at runtime. + apiUrl, + dotenv: false, + }); + log('Clerk testing tokens setup complete'); + } + } + } catch (error) { + logger.warn('Failed to setup Clerk testing tokens:', error); + } + } + return { port, serverUrl: runtimeServerUrl, pid: proc.pid }; }, build: async () => { diff --git a/integration/tests/custom-flows/sign-in.test.ts b/integration/tests/custom-flows/sign-in.test.ts index c8fe5851790..30a34e0d190 100644 --- a/integration/tests/custom-flows/sign-in.test.ts +++ b/integration/tests/custom-flows/sign-in.test.ts @@ -1,5 +1,3 @@ -import { parsePublishableKey } from '@clerk/shared/keys'; -import { clerkSetup } from '@clerk/testing/playwright'; import { expect, test } from '@playwright/test'; import type { Application } from '../../models/application'; @@ -19,20 +17,6 @@ test.describe('Custom Flows Sign In @custom', () => { await app.withEnv(appConfigs.envs.withEmailCodes); await app.dev(); - const publishableKey = appConfigs.envs.withEmailCodes.publicVariables.get('CLERK_PUBLISHABLE_KEY'); - const secretKey = appConfigs.envs.withEmailCodes.privateVariables.get('CLERK_SECRET_KEY'); - const apiUrl = appConfigs.envs.withEmailCodes.privateVariables.get('CLERK_API_URL'); - const { frontendApi: frontendApiUrl } = parsePublishableKey(publishableKey); - - await clerkSetup({ - publishableKey, - frontendApiUrl, - secretKey, - // @ts-expect-error - apiUrl, - dotenv: false, - }); - const u = createTestUtils({ app }); fakeUser = u.services.users.createFakeUser({ fictionalEmail: true, diff --git a/integration/tests/custom-flows/sign-up.test.ts b/integration/tests/custom-flows/sign-up.test.ts index 02e16f02051..f7c16143755 100644 --- a/integration/tests/custom-flows/sign-up.test.ts +++ b/integration/tests/custom-flows/sign-up.test.ts @@ -1,5 +1,3 @@ -import { parsePublishableKey } from '@clerk/shared/keys'; -import { clerkSetup } from '@clerk/testing/playwright'; import { expect, test } from '@playwright/test'; import type { Application } from '../../models/application'; @@ -19,20 +17,6 @@ test.describe('Custom Flows Sign Up @custom', () => { await app.withEnv(appConfigs.envs.withEmailCodes); await app.dev(); - const publishableKey = appConfigs.envs.withEmailCodes.publicVariables.get('CLERK_PUBLISHABLE_KEY'); - const secretKey = appConfigs.envs.withEmailCodes.privateVariables.get('CLERK_SECRET_KEY'); - const apiUrl = appConfigs.envs.withEmailCodes.privateVariables.get('CLERK_API_URL'); - const { frontendApi: frontendApiUrl } = parsePublishableKey(publishableKey); - - await clerkSetup({ - publishableKey, - frontendApiUrl, - secretKey, - // @ts-expect-error - apiUrl, - dotenv: false, - }); - const u = createTestUtils({ app }); fakeUser = u.services.users.createFakeUser({ fictionalEmail: true, From 4a0652037a85dfb5592bd3d287be692ef2152d58 Mon Sep 17 00:00:00 2001 From: Nikos Douvlis Date: Sat, 6 Dec 2025 12:49:10 +0200 Subject: [PATCH 36/41] debug generic --- .github/workflows/ci.yml | 29 +++++++++---------- integration/templates/react-vite/src/main.tsx | 4 +++ package.json | 2 +- packages/ui/src/Components.tsx | 7 +++-- .../ui/src/components/SignUp/SignUpStart.tsx | 6 ++-- .../src/customizables/AppearanceContext.tsx | 13 +++++++-- .../ui/src/customizables/parseAppearance.ts | 11 +++++++ 7 files changed, 50 insertions(+), 22 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d12534c9d34..843f988b7c6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -296,22 +296,21 @@ jobs: strategy: fail-fast: false matrix: - test-name: - [ + test-name: [ "generic", - "express", - "ap-flows", - "localhost", - "sessions", - "sessions:staging", - "handshake", - "handshake:staging", - "astro", - "tanstack-react-start", - "vue", - "nuxt", - "react-router", - "custom", + # "express", + # "ap-flows", + # "localhost", + # "sessions", + # "sessions:staging", + # "handshake", + # "handshake:staging", + # "astro", + # "tanstack-react-start", + # "vue", + # "nuxt", + # "react-router", + # "custom", ] test-project: ["chrome"] include: diff --git a/integration/templates/react-vite/src/main.tsx b/integration/templates/react-vite/src/main.tsx index 6145122c1e6..d8b3b315f0b 100644 --- a/integration/templates/react-vite/src/main.tsx +++ b/integration/templates/react-vite/src/main.tsx @@ -35,6 +35,9 @@ const Root = () => { routerPush={(to: string) => navigate(to)} routerReplace={(to: string) => navigate(to, { replace: true })} appearance={{ + colors: { + colorPrimary: 'red', + }, layout: { showOptionalFields: true, }, @@ -45,6 +48,7 @@ const Root = () => { : undefined, }} > + is this the correct app? ); diff --git a/package.json b/package.json index c068833cad3..72ca33d788b 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "test:integration:deployment:nextjs": "pnpm playwright test --config integration/playwright.deployments.config.ts", "test:integration:expo-web:disabled": "E2E_APP_ID=expo.expo-web pnpm test:integration:base --grep @expo-web", "test:integration:express": "E2E_DEBUG=1 E2E_DEBUG=1 E2E_APP_ID=express.* pnpm test:integration:base --grep @express", - "test:integration:generic": "E2E_DEBUG=1 E2E_APP_ID=react.vite.*,next.appRouter.withEmailCodes* pnpm test:integration:base --grep @generic", + "test:integration:generic": "E2E_DEBUG=1 E2E_APP_ID=react.vite.withEmailCodes pnpm test:integration:base --grep @generic sign-up-flow.test.ts", "test:integration:handshake": "DISABLE_WEB_SECURITY=true E2E_APP_1_ENV_KEY=sessions-prod-1 E2E_SESSIONS_APP_1_HOST=multiple-apps-e2e.clerk.app pnpm test:integration:base --grep @handshake", "test:integration:handshake:staging": "DISABLE_WEB_SECURITY=true E2E_APP_1_ENV_KEY=clerkstage-sessions-prod-1 E2E_SESSIONS_APP_1_HOST=clerkstage-sessions-prod-1-e2e.clerk.app pnpm test:integration:base --grep @handshake", "test:integration:localhost": "pnpm test:integration:base --grep @localhost", diff --git a/packages/ui/src/Components.tsx b/packages/ui/src/Components.tsx index dcf3447aeb4..a26aac0f459 100644 --- a/packages/ui/src/Components.tsx +++ b/packages/ui/src/Components.tsx @@ -17,14 +17,13 @@ import type { UserProfileProps, WaitlistProps, } from '@clerk/shared/types'; - -import type { Appearance } from './internal/appearance'; import { createDeferredPromise } from '@clerk/shared/utils'; import React, { Suspense } from 'react'; import type { AppearanceCascade } from './customizables/parseAppearance'; // NOTE: Using `./hooks` instead of `./hooks/useClerkModalStateParams` will increase the bundle size import { useClerkModalStateParams } from './hooks/useClerkModalStateParams'; +import type { Appearance } from './internal/appearance'; import type { ClerkComponentName } from './lazyModules/components'; import { BlankCaptchaModal, @@ -293,6 +292,10 @@ const Components = (props: ComponentsProps) => { impersonationFab: false, }); + console.log('props.options.appearance', JSON.stringify(props.options.appearance)); + console.log('props.options', JSON.stringify(props.options)); + console.log('state.appearance', JSON.stringify(state.appearance)); + const { googleOneTapModal, signInModal, diff --git a/packages/ui/src/components/SignUp/SignUpStart.tsx b/packages/ui/src/components/SignUp/SignUpStart.tsx index dcb3f9aacf5..cc55d619ee4 100644 --- a/packages/ui/src/components/SignUp/SignUpStart.tsx +++ b/packages/ui/src/components/SignUp/SignUpStart.tsx @@ -37,7 +37,10 @@ function SignUpStartInternal(): JSX.Element { const clerk = useClerk(); const status = useLoadingStatus(); const signUp = useCoreSignUp(); - const { showOptionalFields } = useAppearance().parsedLayout; + const appearance = useAppearance(); + const { showOptionalFields } = appearance.parsedLayout; + console.log('[SignUpStart] useAppearance().parsedLayout', JSON.stringify(appearance.parsedLayout)); + console.log('[SignUpStart] showOptionalFields', showOptionalFields); const { userSettings, authConfig } = useEnvironment(); const { navigate } = useRouter(); const { attributes } = userSettings; @@ -439,7 +442,6 @@ function SignUpStartInternal(): JSX.Element { legalAccepted={Boolean(formState.legalAccepted.checked) || undefined} /> )} - hello there {shouldShowForm && ( ; const AppearanceProvider = (props: AppearanceProviderProps) => { + console.log('[AppearanceProvider] rendering with props:', { + globalAppearance: JSON.stringify(props.globalAppearance), + appearance: JSON.stringify(props.appearance), + appearanceKey: props.appearanceKey, + }); + const ctxValue = useDeepEqualMemo(() => { + console.log('[AppearanceProvider] useDeepEqualMemo factory called'); const value = parseAppearance(props); - + console.log('[AppearanceProvider] parsed value.parsedLayout:', JSON.stringify(value.parsedLayout)); return { value }; - }, [props.appearance, props.globalAppearance]); + }, [props.appearance, props.globalAppearance, props.appearanceKey]); + + console.log('[AppearanceProvider] ctxValue.value.parsedLayout:', JSON.stringify(ctxValue.value.parsedLayout)); return {props.children}; }; diff --git a/packages/ui/src/customizables/parseAppearance.ts b/packages/ui/src/customizables/parseAppearance.ts index 5dffecdfa46..d011f95d6c0 100644 --- a/packages/ui/src/customizables/parseAppearance.ts +++ b/packages/ui/src/customizables/parseAppearance.ts @@ -68,16 +68,27 @@ const defaultCaptchaOptions: ParsedCaptcha = { */ export const parseAppearance = (cascade: AppearanceCascade): ParsedAppearance => { const { globalAppearance, appearance: componentAppearance, appearanceKey } = cascade; + console.log('[parseAppearance] globalAppearance', JSON.stringify(globalAppearance)); + console.log('[parseAppearance] componentAppearance', JSON.stringify(componentAppearance)); + console.log('[parseAppearance] appearanceKey', appearanceKey); const appearanceList: Appearance[] = []; [globalAppearance, globalAppearance?.[appearanceKey as PublicAppearanceTopLevelKey], componentAppearance].forEach(a => expand(a, appearanceList), ); + console.log('[parseAppearance] appearanceList length', appearanceList.length); + console.log( + '[parseAppearance] appearanceList layouts', + appearanceList.map(a => JSON.stringify(a?.layout)), + ); + const parsedInternalTheme = parseVariables(appearanceList); const parsedLayout = parseLayout(appearanceList); const parsedCaptcha = parseCaptcha(appearanceList); + console.log('[parseAppearance] parsedLayout', JSON.stringify(parsedLayout)); + if ( !appearanceList.find(a => { //@ts-expect-error not public api From 917515f5aac32a2497f61bdce01b6f6bbfd6609a Mon Sep 17 00:00:00 2001 From: Nikos Douvlis Date: Sat, 6 Dec 2025 16:57:46 +0200 Subject: [PATCH 37/41] restore disabled testse --- .github/workflows/ci.yml | 37 +++++++++++++++++++------------------ package.json | 2 +- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 843f988b7c6..56d35560f0a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -296,21 +296,22 @@ jobs: strategy: fail-fast: false matrix: - test-name: [ + test-name: + [ "generic", - # "express", - # "ap-flows", - # "localhost", - # "sessions", - # "sessions:staging", - # "handshake", - # "handshake:staging", - # "astro", - # "tanstack-react-start", - # "vue", - # "nuxt", - # "react-router", - # "custom", + "express", + "ap-flows", + "localhost", + "sessions", + "sessions:staging", + "handshake", + "handshake:staging", + "astro", + "tanstack-react-start", + "vue", + "nuxt", + "react-router", + "custom", ] test-project: ["chrome"] include: @@ -330,10 +331,10 @@ jobs: test-project: "chrome" next-version: "15" clerk-use-rq: "false" - # - test-name: "nextjs" - # test-project: "chrome" - # next-version: "15" - # clerk-use-rq: "true" + - test-name: "nextjs" + test-project: "chrome" + next-version: "15" + clerk-use-rq: "true" - test-name: "nextjs" test-project: "chrome" next-version: "16" diff --git a/package.json b/package.json index 72ca33d788b..c068833cad3 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "test:integration:deployment:nextjs": "pnpm playwright test --config integration/playwright.deployments.config.ts", "test:integration:expo-web:disabled": "E2E_APP_ID=expo.expo-web pnpm test:integration:base --grep @expo-web", "test:integration:express": "E2E_DEBUG=1 E2E_DEBUG=1 E2E_APP_ID=express.* pnpm test:integration:base --grep @express", - "test:integration:generic": "E2E_DEBUG=1 E2E_APP_ID=react.vite.withEmailCodes pnpm test:integration:base --grep @generic sign-up-flow.test.ts", + "test:integration:generic": "E2E_DEBUG=1 E2E_APP_ID=react.vite.*,next.appRouter.withEmailCodes* pnpm test:integration:base --grep @generic", "test:integration:handshake": "DISABLE_WEB_SECURITY=true E2E_APP_1_ENV_KEY=sessions-prod-1 E2E_SESSIONS_APP_1_HOST=multiple-apps-e2e.clerk.app pnpm test:integration:base --grep @handshake", "test:integration:handshake:staging": "DISABLE_WEB_SECURITY=true E2E_APP_1_ENV_KEY=clerkstage-sessions-prod-1 E2E_SESSIONS_APP_1_HOST=clerkstage-sessions-prod-1-e2e.clerk.app pnpm test:integration:base --grep @handshake", "test:integration:localhost": "pnpm test:integration:base --grep @localhost", From 960099120a61d391710fa1bf8f2102f3dbb70496 Mon Sep 17 00:00:00 2001 From: Nikos Douvlis Date: Sat, 6 Dec 2025 17:32:00 +0200 Subject: [PATCH 38/41] fix react-router --- integration/templates/react-router-library/src/main.tsx | 4 ++++ integration/templates/react-router-node/app/root.tsx | 2 ++ .../templates/tanstack-react-start/src/routes/__root.tsx | 2 ++ 3 files changed, 8 insertions(+) diff --git a/integration/templates/react-router-library/src/main.tsx b/integration/templates/react-router-library/src/main.tsx index 8c1fd62ded1..82c2ee8e68d 100644 --- a/integration/templates/react-router-library/src/main.tsx +++ b/integration/templates/react-router-library/src/main.tsx @@ -6,12 +6,16 @@ import './index.css'; import App from './App.tsx'; const PUBLISHABLE_KEY = import.meta.env.VITE_CLERK_PUBLISHABLE_KEY; +const CLERK_JS_URL = import.meta.env.VITE_CLERK_JS_URL; +const CLERK_UI_URL = import.meta.env.VITE_CLERK_UI_URL; createRoot(document.getElementById('root')!).render( Date: Sat, 6 Dec 2025 17:46:05 +0200 Subject: [PATCH 39/41] fix astro pkg --- .../src/internal/create-clerk-instance.ts | 62 ++++++++++++------- 1 file changed, 40 insertions(+), 22 deletions(-) diff --git a/packages/astro/src/internal/create-clerk-instance.ts b/packages/astro/src/internal/create-clerk-instance.ts index 73a4473c660..e1cbd520144 100644 --- a/packages/astro/src/internal/create-clerk-instance.ts +++ b/packages/astro/src/internal/create-clerk-instance.ts @@ -36,30 +36,20 @@ function createNavigationHandler( const createClerkInstance = runOnce(createClerkInstanceInternal); async function createClerkInstanceInternal(options?: AstroClerkCreateInstanceParams) { - let clerkJSInstance = window.Clerk; - let clerkUiCtor: Promise | undefined; - - if (!clerkJSInstance) { - // Load both clerk-js and clerk-ui in parallel - const clerkPromise = loadClerkJsScript(options); - clerkUiCtor = options?.clerkUiCtor - ? Promise.resolve(options.clerkUiCtor) - : loadClerkUiScript(options).then(() => { - if (!window.__internal_ClerkUiCtor) { - throw new Error('Failed to download latest Clerk UI. Contact support@clerk.com.'); - } - // After the check, TypeScript knows it's defined - return window.__internal_ClerkUiCtor; - }); - - await clerkPromise; - - if (!window.Clerk) { - throw new Error('Failed to download latest ClerkJS. Contact support@clerk.com.'); - } - clerkJSInstance = window.Clerk; + // Load clerk-js and clerk-ui in parallel. + // Both functions return early if the scripts are already loaded + // (e.g., via middleware-injected script tags in the HTML head). + const clerkJsChunk = getClerkJsEntryChunk(options); + const clerkUiCtor = getClerkUiEntryChunk(options); + + await clerkJsChunk; + + if (!window.Clerk) { + throw new Error('Failed to download latest ClerkJS. Contact support@clerk.com.'); } + const clerkJSInstance = window.Clerk; + if (!$clerk.get()) { $clerk.set(clerkJSInstance); } @@ -110,4 +100,32 @@ function updateClerkOptions(options: AstroClerkUpdateOption void (clerk as any).__internal_updateProps(updateOptions); } +/** + * Loads clerk-js script if not already loaded. + * Returns early if window.Clerk already exists. + */ +async function getClerkJsEntryChunk(options?: AstroClerkCreateInstanceParams): Promise { + await loadClerkJsScript(options); +} + +/** + * Gets the ClerkUI constructor, either from options or by loading the script. + * Returns early if window.__internal_ClerkUiCtor already exists. + */ +async function getClerkUiEntryChunk( + options?: AstroClerkCreateInstanceParams, +): Promise { + if (options?.clerkUiCtor) { + return options.clerkUiCtor; + } + + await loadClerkUiScript(options); + + if (!window.__internal_ClerkUiCtor) { + throw new Error('Failed to download latest Clerk UI. Contact support@clerk.com.'); + } + + return window.__internal_ClerkUiCtor; +} + export { createClerkInstance, updateClerkOptions }; From e383ad4ef3132d95d42fdbd16924619e1dd70576 Mon Sep 17 00:00:00 2001 From: Nikos Douvlis Date: Sat, 6 Dec 2025 18:10:19 +0200 Subject: [PATCH 40/41] make sure that all packages are deployed as snapshots --- .github/workflows/ci.yml | 6 +++++- scripts/snapshot.mjs | 9 +++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 56d35560f0a..e6df4741014 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -406,12 +406,16 @@ jobs: env: CLERK_USE_RQ: true + - name: Version packages for snapshot + if: ${{ steps.task-status.outputs.affected == '1' }} + run: npm run version-packages:snapshot ci + - name: Verdaccio if: ${{ steps.task-status.outputs.affected == '1' }} uses: ./.github/actions/verdaccio with: publish-cmd: | - if [ "$(pnpm config get registry)" = "https://registry.npmjs.org/" ]; then echo 'Error: Using default registry' && exit 1; else node ./scripts/snapshot.mjs ci && ${{ matrix.clerk-use-rq == 'true' && 'CLERK_USE_RQ=true' || '' }} pnpm turbo build $TURBO_ARGS --only && pnpm changeset publish --no-git-tag --tag latest; fi + if [ "$(pnpm config get registry)" = "https://registry.npmjs.org/" ]; then echo 'Error: Using default registry' && exit 1; else ${{ matrix.clerk-use-rq == 'true' && 'CLERK_USE_RQ=true' || '' }} pnpm turbo build $TURBO_ARGS --only && pnpm changeset publish --no-git-tag --tag latest; fi - name: Edit .npmrc [link-workspace-packages=false] run: sed -i -E 's/link-workspace-packages=(deep|true)/link-workspace-packages=false/' .npmrc diff --git a/scripts/snapshot.mjs b/scripts/snapshot.mjs index 138c77b7ea3..57eec8287c2 100755 --- a/scripts/snapshot.mjs +++ b/scripts/snapshot.mjs @@ -25,13 +25,14 @@ try { // this will remove the prerelease versions // but will also clear the changeset .md files await $`pnpm changeset version`; - // generate a temp .md file that indicates that all packages have changes - // in order to force a snapshot release - await $`touch .changeset/snap.md && echo ${snapshot} > .changeset/snap.md`; } catch { - // otherwise, do nothing + // not in pre-release mode, continue } +// Always generate a temp .md file that indicates that all packages have changes +// in order to force a snapshot release of all packages +await $`touch .changeset/snap.md && echo ${snapshot} > .changeset/snap.md`; + const res = await $`pnpm changeset version --snapshot ${prefix}`; const success = !res.stderr.includes('No unreleased changesets found'); From 5d2dcd9eb3c7fc1ab0bf65a55a42afafaa6f29c8 Mon Sep 17 00:00:00 2001 From: Nikos Douvlis Date: Sat, 6 Dec 2025 18:11:04 +0200 Subject: [PATCH 41/41] reenable disabled apps --- .github/workflows/ci.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e6df4741014..a1e59f57d0f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -318,15 +318,15 @@ jobs: - test-name: "billing" test-project: "chrome" clerk-use-rq: "false" - # - test-name: "billing" - # test-project: "chrome" - # clerk-use-rq: "true" + - test-name: "billing" + test-project: "chrome" + clerk-use-rq: "true" - test-name: "machine" test-project: "chrome" clerk-use-rq: "false" - # - test-name: "machine" - # test-project: "chrome" - # clerk-use-rq: "true" + - test-name: "machine" + test-project: "chrome" + clerk-use-rq: "true" - test-name: "nextjs" test-project: "chrome" next-version: "15"