From 7bc1648ebc917537b0619d09f1bf24577b3e393f Mon Sep 17 00:00:00 2001 From: Nikos Douvlis Date: Wed, 12 Nov 2025 15:15:52 +0200 Subject: [PATCH 1/2] feat(astro): Support clerk/ui - Updated the createClerkInstance function to load Clerk UI and Clerk JS scripts in parallel. - Introduced a new type for Clerk UI constructor in the global scope. - Modified CI workflow to include the "astro" test case in the matrix. --- .github/workflows/ci.yml | 5 ++-- .../src/integration/create-integration.ts | 3 --- .../src/internal/create-clerk-instance.ts | 23 +++++++++++++++++-- .../internal/merge-env-vars-with-params.ts | 2 ++ packages/astro/src/types.ts | 13 ++++++++++- 5 files changed, 38 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e6480e42454..049229db459 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -294,7 +294,8 @@ jobs: strategy: fail-fast: false matrix: - test-name: [ + test-name: + [ "generic", "express", "ap-flows", @@ -303,7 +304,7 @@ jobs: "sessions:staging", "handshake", "handshake:staging", - # "astro", + "astro", "tanstack-react-start", "vue", "nuxt", diff --git a/packages/astro/src/integration/create-integration.ts b/packages/astro/src/integration/create-integration.ts index dcfa9b115f3..e8902271a96 100644 --- a/packages/astro/src/integration/create-integration.ts +++ b/packages/astro/src/integration/create-integration.ts @@ -11,9 +11,6 @@ const buildEnvVarFromOption = (valueToBeStored: unknown, envName: keyof Internal }; type HotloadAstroClerkIntegrationParams = AstroClerkIntegrationParams & { - clerkJSUrl?: string; - clerkJSVariant?: 'headless' | ''; - clerkJSVersion?: string; enableEnvSchema?: boolean; }; diff --git a/packages/astro/src/internal/create-clerk-instance.ts b/packages/astro/src/internal/create-clerk-instance.ts index e5c18399f41..b1e6ef64197 100644 --- a/packages/astro/src/internal/create-clerk-instance.ts +++ b/packages/astro/src/internal/create-clerk-instance.ts @@ -1,5 +1,10 @@ -import { loadClerkJsScript, setClerkJsLoadingErrorPackageName } from '@clerk/shared/loadClerkJsScript'; +import { + loadClerkJsScript, + loadClerkUiScript, + setClerkJsLoadingErrorPackageName, +} from '@clerk/shared/loadClerkJsScript'; import type { ClerkOptions } from '@clerk/shared/types'; +import type { ClerkUiConstructor } from '@clerk/shared/ui'; import { $clerkStore } from '../stores/external'; import { $clerk, $csrState } from '../stores/internal'; @@ -31,8 +36,20 @@ const createClerkInstance = runOnce(createClerkInstanceInternal); async function createClerkInstanceInternal(options?: AstroClerkCreateInstanceParams) { let clerkJSInstance = window.Clerk; + let clerkUiCtor: Promise | undefined; + if (!clerkJSInstance) { - await loadClerkJsScript(options); + // Load both clerk-js and clerk-ui in parallel + const clerkPromise = loadClerkJsScript(options); + clerkUiCtor = loadClerkUiScript(options).then(() => { + if (!window.__unstable_ClerkUiCtor) { + throw new Error('Failed to download latest Clerk UI. Contact support@clerk.com.'); + } + // After the check, TypeScript knows it's defined + return window.__unstable_ClerkUiCtor; + }); + + await clerkPromise; if (!window.Clerk) { throw new Error('Failed to download latest ClerkJS. Contact support@clerk.com.'); @@ -48,6 +65,8 @@ async function createClerkInstanceInternal(options?: AstroClerkCreateInstancePar routerPush: createNavigationHandler(window.history.pushState.bind(window.history)), routerReplace: createNavigationHandler(window.history.replaceState.bind(window.history)), ...options, + // Pass the clerk-ui constructor promise to clerk.load() + clerkUiCtor, }; return clerkJSInstance diff --git a/packages/astro/src/internal/merge-env-vars-with-params.ts b/packages/astro/src/internal/merge-env-vars-with-params.ts index c5498c1e0da..18805a0c99d 100644 --- a/packages/astro/src/internal/merge-env-vars-with-params.ts +++ b/packages/astro/src/internal/merge-env-vars-with-params.ts @@ -14,6 +14,7 @@ const mergeEnvVarsWithParams = (params?: AstroClerkIntegrationParams & { publish domain: paramDomain, publishableKey: paramPublishableKey, telemetry: paramTelemetry, + clerkUiUrl: paramClerkUiUrl, ...rest } = params || {}; @@ -24,6 +25,7 @@ const mergeEnvVarsWithParams = (params?: AstroClerkIntegrationParams & { publish proxyUrl: paramProxy || import.meta.env.PUBLIC_CLERK_PROXY_URL, domain: paramDomain || import.meta.env.PUBLIC_CLERK_DOMAIN, publishableKey: paramPublishableKey || import.meta.env.PUBLIC_CLERK_PUBLISHABLE_KEY || '', + clerkUiUrl: paramClerkUiUrl || import.meta.env.PUBLIC_CLERK_UI_URL, telemetry: paramTelemetry || { disabled: isTruthy(import.meta.env.PUBLIC_CLERK_TELEMETRY_DISABLED), debug: isTruthy(import.meta.env.PUBLIC_CLERK_TELEMETRY_DEBUG), diff --git a/packages/astro/src/types.ts b/packages/astro/src/types.ts index ad47cedbd99..ed3b0313799 100644 --- a/packages/astro/src/types.ts +++ b/packages/astro/src/types.ts @@ -6,6 +6,7 @@ import type { ProtectProps, Without, } from '@clerk/shared/types'; +import type { ClerkUiConstructor } from '@clerk/shared/ui'; type AstroClerkUpdateOptions = Pick; @@ -20,8 +21,17 @@ type AstroClerkIntegrationParams = Without< | 'routerPush' | 'polling' | 'touchSession' + | 'clerkUiCtor' > & - MultiDomainAndOrProxyPrimitives; + MultiDomainAndOrProxyPrimitives & { + clerkJSUrl?: string; + clerkJSVariant?: 'headless' | ''; + clerkJSVersion?: string; + /** + * The URL that `@clerk/ui` should be hot-loaded from. + */ + clerkUiUrl?: string; + }; type AstroClerkCreateInstanceParams = AstroClerkIntegrationParams & { publishableKey: string }; @@ -42,6 +52,7 @@ declare global { __astro_clerk_component_props: Map>>; __astro_clerk_function_props: Map>>; Clerk: BrowserClerk; + __unstable_ClerkUiCtor?: ClerkUiConstructor; } } From 9e57fe09634fa22445b78b2a5483505853094b1f Mon Sep 17 00:00:00 2001 From: Nikos Douvlis Date: Sun, 16 Nov 2025 11:59:09 +0200 Subject: [PATCH 2/2] feat(ci): Use @integration tag for verdaccio publishing In certain cases, the published versions in verdaccio didnt match the version ranges requested by the e2e template apps. Our verdaccio config allows proxying to npm so that some suites can install prev pkg versions (v4) so instead of falling completely, the apps were installing npm versions instead of the local ones. During the cicd setup step, versioning runs before publishing so verdaccio gets the new versions. Some templates require previous version ranges and because of the npm-pass-through config we use, they get the live pkgs and not the local ones To fix the above and make the whole flow more predictable, I introduced a integration tag. All local pkgs get published to @integration in verdaccio and the e2e templates can now request @integration instead of @latest or @5 - @integration ensures that they get the verdaccio version no matter the semver range - Enhanced the `linkPackage` function to accept an optional tag parameter for better package linking. - Updated integration presets to use the new `linkPackage` functionality, ensuring dependencies are linked correctly for integration testing. - Added new environment variable support in the `mergeEnvVarsWithParams` function for improved configuration options. --- .github/workflows/ci.yml | 3 ++- integration/presets/custom-flows.ts | 6 +++--- integration/presets/react.ts | 6 +++--- integration/presets/utils.ts | 4 ++-- packages/astro/src/internal/merge-env-vars-with-params.ts | 6 ++++++ 5 files changed, 16 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 049229db459..92e809b9150 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -404,7 +404,8 @@ 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; fi + 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 + - 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/custom-flows.ts b/integration/presets/custom-flows.ts index fcae3cb8ddc..f816de17057 100644 --- a/integration/presets/custom-flows.ts +++ b/integration/presets/custom-flows.ts @@ -1,4 +1,3 @@ -import { constants } from '../constants'; import { applicationConfig } from '../models/applicationConfig'; import { templates } from '../templates'; import { linkPackage } from './utils'; @@ -11,8 +10,9 @@ const reactVite = applicationConfig() .addScript('dev', 'pnpm dev') .addScript('build', 'pnpm build') .addScript('serve', 'pnpm preview') - .addDependency('@clerk/react', constants.E2E_CLERK_JS_VERSION || linkPackage('react')) - .addDependency('@clerk/themes', constants.E2E_CLERK_JS_VERSION || linkPackage('themes')); + .addDependency('@clerk/react', linkPackage('react', 'integration')) + .addDependency('@clerk/shared', linkPackage('shared', 'integration')) + .addDependency('@clerk/themes', linkPackage('themes', 'integration')); export const customFlows = { reactVite, diff --git a/integration/presets/react.ts b/integration/presets/react.ts index 9a3344fa553..d2ea6b0861c 100644 --- a/integration/presets/react.ts +++ b/integration/presets/react.ts @@ -1,4 +1,3 @@ -import { constants } from '../constants'; import { applicationConfig } from '../models/applicationConfig'; import { templates } from '../templates'; import { linkPackage } from './utils'; @@ -11,8 +10,9 @@ const cra = applicationConfig() .addScript('dev', 'pnpm start') .addScript('build', 'pnpm build') .addScript('serve', 'pnpm start') - .addDependency('@clerk/react', constants.E2E_CLERK_JS_VERSION || linkPackage('react')) - .addDependency('@clerk/themes', constants.E2E_CLERK_JS_VERSION || linkPackage('themes')); + .addDependency('@clerk/react', linkPackage('react', 'integration')) + .addDependency('@clerk/shared', linkPackage('shared', 'integration')) + .addDependency('@clerk/themes', linkPackage('themes', 'integration')); const vite = cra .clone() diff --git a/integration/presets/utils.ts b/integration/presets/utils.ts index f7831c39663..d22e39250dd 100644 --- a/integration/presets/utils.ts +++ b/integration/presets/utils.ts @@ -1,9 +1,9 @@ import path from 'node:path'; -export function linkPackage(pkg: string) { +export function linkPackage(pkg: string, tag?: string) { // eslint-disable-next-line turbo/no-undeclared-env-vars if (process.env.CI === 'true') { - return '*'; + return tag || '*'; } return `link:${path.resolve(process.cwd(), `packages/${pkg}`)}`; diff --git a/packages/astro/src/internal/merge-env-vars-with-params.ts b/packages/astro/src/internal/merge-env-vars-with-params.ts index 18805a0c99d..dea24762b16 100644 --- a/packages/astro/src/internal/merge-env-vars-with-params.ts +++ b/packages/astro/src/internal/merge-env-vars-with-params.ts @@ -14,7 +14,10 @@ const mergeEnvVarsWithParams = (params?: AstroClerkIntegrationParams & { publish domain: paramDomain, publishableKey: paramPublishableKey, telemetry: paramTelemetry, + clerkJSUrl: paramClerkJSUrl, clerkUiUrl: paramClerkUiUrl, + clerkJSVariant: paramClerkJSVariant, + clerkJSVersion: paramClerkJSVersion, ...rest } = params || {}; @@ -26,6 +29,9 @@ const mergeEnvVarsWithParams = (params?: AstroClerkIntegrationParams & { publish domain: paramDomain || import.meta.env.PUBLIC_CLERK_DOMAIN, publishableKey: paramPublishableKey || import.meta.env.PUBLIC_CLERK_PUBLISHABLE_KEY || '', clerkUiUrl: paramClerkUiUrl || import.meta.env.PUBLIC_CLERK_UI_URL, + clerkJSUrl: paramClerkJSUrl || import.meta.env.PUBLIC_CLERK_JS_URL, + clerkJSVariant: paramClerkJSVariant || import.meta.env.PUBLIC_CLERK_JS_VARIANT, + clerkJSVersion: paramClerkJSVersion || import.meta.env.PUBLIC_CLERK_JS_VERSION, telemetry: paramTelemetry || { disabled: isTruthy(import.meta.env.PUBLIC_CLERK_TELEMETRY_DISABLED), debug: isTruthy(import.meta.env.PUBLIC_CLERK_TELEMETRY_DEBUG),