-
Notifications
You must be signed in to change notification settings - Fork 436
feat(astro): Add support for keyless mode #7812
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
9546d96
517a815
3bc54de
2ed5c1a
f07722e
a14541b
3b9cc57
813e17e
1d79e23
eaa509f
c5cbbe8
5268f12
e6d87ac
0b4fe75
a77202e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| "@clerk/astro": minor | ||
| --- | ||
|
|
||
| Introduce Keyless quickstart for Astro. This allows the Clerk SDK to be used without having to sign up and paste your keys manually. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| import { test } from '@playwright/test'; | ||
|
|
||
| import type { Application } from '../../models/application'; | ||
| import { appConfigs } from '../../presets'; | ||
| import { | ||
| testClaimedAppWithMissingKeys, | ||
| testKeylessRemovedAfterEnvAndRestart, | ||
| testToggleCollapsePopoverAndClaim, | ||
| } from '../../testUtils/keylessHelpers'; | ||
|
|
||
| const commonSetup = appConfigs.astro.node.clone(); | ||
|
|
||
| test.describe('Keyless mode @astro', () => { | ||
| test.describe.configure({ mode: 'serial' }); | ||
| test.setTimeout(90_000); | ||
|
|
||
| test.use({ | ||
| extraHTTPHeaders: { | ||
| 'x-vercel-protection-bypass': process.env.VERCEL_AUTOMATION_BYPASS_SECRET || '', | ||
| }, | ||
| }); | ||
|
|
||
| let app: Application; | ||
| let dashboardUrl = 'https://dashboard.clerk.com/'; | ||
|
|
||
| test.beforeAll(async () => { | ||
| app = await commonSetup.commit(); | ||
| await app.setup(); | ||
| await app.withEnv(appConfigs.envs.withKeyless); | ||
| if (appConfigs.envs.withKeyless.privateVariables.get('CLERK_API_URL')?.includes('clerkstage')) { | ||
| dashboardUrl = 'https://dashboard.clerkstage.dev/'; | ||
| } | ||
| await app.dev(); | ||
| }); | ||
|
|
||
| test.afterAll(async () => { | ||
| await app?.teardown(); | ||
| }); | ||
|
|
||
| test('Toggle collapse popover and claim.', async ({ page, context }) => { | ||
| await testToggleCollapsePopoverAndClaim({ page, context, app, dashboardUrl, framework: 'astro' }); | ||
| }); | ||
|
|
||
| test('Lands on claimed application with missing explicit keys, expanded by default, click to get keys from dashboard.', async ({ | ||
| page, | ||
| context, | ||
| }) => { | ||
| await testClaimedAppWithMissingKeys({ page, context, app, dashboardUrl }); | ||
| }); | ||
|
|
||
| test('Keyless popover is removed after adding keys to .env and restarting.', async ({ page, context }) => { | ||
| await testKeylessRemovedAfterEnvAndRestart({ page, context, app }); | ||
| }); | ||
| }); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -21,6 +21,7 @@ interface InternalEnv { | |
| readonly PUBLIC_CLERK_SIGN_UP_URL?: string; | ||
| readonly PUBLIC_CLERK_TELEMETRY_DISABLED?: string; | ||
| readonly PUBLIC_CLERK_TELEMETRY_DEBUG?: string; | ||
| readonly PUBLIC_CLERK_KEYLESS_DISABLED?: string; | ||
| } | ||
|
Comment on lines
+24
to
25
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Missing type definitions for keyless URL environment variables. The 🐛 Proposed fix readonly PUBLIC_CLERK_TELEMETRY_DEBUG?: string;
readonly PUBLIC_CLERK_KEYLESS_DISABLED?: string;
+ readonly PUBLIC_CLERK_KEYLESS_CLAIM_URL?: string;
+ readonly PUBLIC_CLERK_KEYLESS_API_KEYS_URL?: string;
}🤖 Prompt for AI Agents |
||
|
|
||
| interface ImportMeta { | ||
|
|
@@ -30,6 +31,9 @@ interface ImportMeta { | |
| declare namespace App { | ||
| interface Locals { | ||
| runtime: { env: InternalEnv }; | ||
| keylessClaimUrl?: string; | ||
| keylessApiKeysUrl?: string; | ||
| keylessPublishableKey?: string; | ||
| } | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -166,7 +166,7 @@ function createIntegration<Params extends HotloadAstroClerkIntegrationParams>() | |
|
|
||
| function createClerkEnvSchema() { | ||
| return { | ||
| PUBLIC_CLERK_PUBLISHABLE_KEY: envField.string({ context: 'client', access: 'public' }), | ||
| PUBLIC_CLERK_PUBLISHABLE_KEY: envField.string({ context: 'client', access: 'public', optional: true }), | ||
| PUBLIC_CLERK_SIGN_IN_URL: envField.string({ context: 'client', access: 'public', optional: true }), | ||
| PUBLIC_CLERK_SIGN_UP_URL: envField.string({ context: 'client', access: 'public', optional: true }), | ||
| PUBLIC_CLERK_IS_SATELLITE: envField.boolean({ context: 'client', access: 'public', optional: true }), | ||
|
|
@@ -179,7 +179,20 @@ function createClerkEnvSchema() { | |
| PUBLIC_CLERK_PREFETCH_UI: envField.string({ context: 'client', access: 'public', optional: true }), | ||
| PUBLIC_CLERK_TELEMETRY_DISABLED: envField.boolean({ context: 'client', access: 'public', optional: true }), | ||
| PUBLIC_CLERK_TELEMETRY_DEBUG: envField.boolean({ context: 'client', access: 'public', optional: true }), | ||
| CLERK_SECRET_KEY: envField.string({ context: 'server', access: 'secret' }), | ||
| PUBLIC_CLERK_KEYLESS_CLAIM_URL: envField.string({ | ||
| context: 'client', | ||
| access: 'public', | ||
| optional: true, | ||
| url: true, | ||
| }), | ||
| PUBLIC_CLERK_KEYLESS_API_KEYS_URL: envField.string({ | ||
| context: 'client', | ||
| access: 'public', | ||
| optional: true, | ||
| url: true, | ||
| }), | ||
|
Comment on lines
+182
to
+193
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are these used? |
||
| PUBLIC_CLERK_KEYLESS_DISABLED: envField.boolean({ context: 'client', access: 'public', optional: true }), | ||
| CLERK_SECRET_KEY: envField.string({ context: 'server', access: 'secret', optional: true }), | ||
| CLERK_MACHINE_SECRET_KEY: envField.string({ context: 'server', access: 'secret', optional: true }), | ||
| CLERK_JWT_KEY: envField.string({ context: 'server', access: 'secret', optional: true }), | ||
| }; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| import { createNodeFileStorage, type KeylessStorage } from '@clerk/shared/keyless'; | ||
|
|
||
| export type { KeylessStorage }; | ||
|
|
||
| export interface FileStorageOptions { | ||
| cwd?: () => string; | ||
| } | ||
|
|
||
| /** | ||
| * Creates a file-based storage adapter for keyless mode. | ||
| * Uses dynamic imports to avoid bundler issues with edge runtimes. | ||
| */ | ||
| export async function createFileStorage(options: FileStorageOptions = {}): Promise<KeylessStorage> { | ||
| const { cwd = () => process.cwd() } = options; | ||
|
|
||
| try { | ||
| const [fs, path] = await Promise.all([import('node:fs'), import('node:path')]); | ||
|
|
||
| return createNodeFileStorage(fs, path, { | ||
| cwd, | ||
| frameworkPackageName: '@clerk/astro', | ||
| }); | ||
| } catch { | ||
| throw new Error( | ||
| 'Keyless mode requires a Node.js runtime with file system access. ' + | ||
| 'Set PUBLIC_CLERK_KEYLESS_DISABLED=1 or CLERK_KEYLESS_DISABLED=1 to disable keyless mode.', | ||
| ); | ||
|
Comment on lines
+24
to
+27
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should gracefully degrade here, not hard error. |
||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.