UNPKG

@clerk/shared

Version:

Internal package utils used by the Clerk SDKs

1 lines • 26.5 kB
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/keyless/devCache.ts","../../src/keyless/nodeFileStorage.ts","../../src/keyless/service.ts","../../src/keyless/resolveKeysWithKeylessFallback.ts"],"sourcesContent":["import { isDevelopmentEnvironment } from '../utils/runtimeEnvironment';\nimport type { AccountlessApplication, PublicKeylessApplication } from './types';\n\n// 10 minutes in milliseconds\nconst THROTTLE_DURATION_MS = 10 * 60 * 1000;\n\nexport interface ClerkDevCache {\n __cache: Map<string, { expiresAt: number; data?: unknown }>;\n /**\n * Log a message with throttling to prevent spam.\n */\n log: (params: { cacheKey: string; msg: string }) => void;\n /**\n * Run an async callback with caching.\n */\n run: <T>(\n callback: () => Promise<T>,\n options: {\n cacheKey: string;\n onSuccessStale?: number;\n onErrorStale?: number;\n },\n ) => Promise<T | undefined>;\n}\n\ndeclare global {\n var __clerk_internal_keyless_logger: ClerkDevCache | undefined;\n}\n\n/**\n * Creates a development-only cache for keyless mode logging and API calls.\n * This prevents console spam and duplicate API requests.\n *\n * @returns The cache instance or undefined in non-development environments\n */\nexport function createClerkDevCache(): ClerkDevCache | undefined {\n if (!isDevelopmentEnvironment()) {\n return undefined;\n }\n\n if (!globalThis.__clerk_internal_keyless_logger) {\n globalThis.__clerk_internal_keyless_logger = {\n __cache: new Map<string, { expiresAt: number; data?: unknown }>(),\n\n log: function ({ cacheKey, msg }) {\n if (this.__cache.has(cacheKey) && Date.now() < (this.__cache.get(cacheKey)?.expiresAt || 0)) {\n return;\n }\n\n console.log(msg);\n\n this.__cache.set(cacheKey, {\n expiresAt: Date.now() + THROTTLE_DURATION_MS,\n });\n },\n\n run: async function (\n callback,\n { cacheKey, onSuccessStale = THROTTLE_DURATION_MS, onErrorStale = THROTTLE_DURATION_MS },\n ) {\n if (this.__cache.has(cacheKey) && Date.now() < (this.__cache.get(cacheKey)?.expiresAt || 0)) {\n return this.__cache.get(cacheKey)?.data as ReturnType<typeof callback>;\n }\n\n try {\n const result = await callback();\n\n this.__cache.set(cacheKey, {\n expiresAt: Date.now() + onSuccessStale,\n data: result,\n });\n return result;\n } catch (e) {\n this.__cache.set(cacheKey, {\n expiresAt: Date.now() + onErrorStale,\n });\n\n throw e;\n }\n },\n };\n }\n\n return globalThis.__clerk_internal_keyless_logger;\n}\n\n/**\n * Creates the console message shown when running in keyless mode.\n *\n * @param keys - The keyless application keys\n * @returns Formatted console message\n */\nexport function createKeylessModeMessage(keys: AccountlessApplication | PublicKeylessApplication): string {\n return `\\n\\x1b[35m\\n[Clerk]:\\x1b[0m You are running in keyless mode.\\nYou can \\x1b[35mclaim your keys\\x1b[0m by visiting ${keys.claimUrl}\\n`;\n}\n\n/**\n * Creates the console message shown when keys have been claimed.\n *\n * @returns Formatted console message\n */\nexport function createConfirmationMessage(): string {\n return `\\n\\x1b[35m\\n[Clerk]:\\x1b[0m Your application is running with your claimed keys.\\nYou can safely remove the \\x1b[35m.clerk/\\x1b[0m from your project.\\n`;\n}\n\n/**\n * Shared singleton instance of the development cache.\n */\nexport const clerkDevelopmentCache = createClerkDevCache();\n","import type { KeylessStorage } from './service';\n\nconst CLERK_HIDDEN = '.clerk';\nconst CLERK_LOCK = 'clerk.lock';\nconst TEMP_DIR_NAME = '.tmp';\nconst CONFIG_FILE = 'keyless.json';\nconst README_FILE = 'README.md';\n\nexport interface NodeFileStorageOptions {\n /**\n * Function that returns the current working directory.\n * Defaults to process.cwd().\n */\n cwd?: () => string;\n\n /**\n * The framework name for the README message.\n *\n * @example '@clerk/nextjs'\n */\n frameworkPackageName?: string;\n}\n\nexport interface FileSystemAdapter {\n existsSync: (path: string) => boolean;\n readFileSync: (path: string, options: { encoding: BufferEncoding }) => string;\n writeFileSync: (path: string, data: string, options: { encoding: BufferEncoding; mode?: number }) => void;\n appendFileSync: (path: string, data: string) => void;\n mkdirSync: (path: string, options: { recursive: boolean }) => void;\n rmSync: (path: string, options: { force?: boolean; recursive?: boolean }) => void;\n}\n\nexport interface PathAdapter {\n join: (...paths: string[]) => string;\n}\n\n/**\n * Creates a file-based storage adapter for keyless mode.\n * This is used by Node.js-based frameworks (Next.js, TanStack Start, etc.)\n * to persist keyless configuration to the file system.\n *\n * @param fs - Node.js fs module or compatible adapter\n * @param path - Node.js path module or compatible adapter\n * @param options - Configuration options\n * @returns A KeylessStorage implementation\n */\nexport function createNodeFileStorage(\n fs: FileSystemAdapter,\n path: PathAdapter,\n options: NodeFileStorageOptions = {},\n): KeylessStorage {\n const { cwd = () => process.cwd(), frameworkPackageName = '@clerk/shared' } = options;\n\n let inMemoryLock = false;\n\n const getClerkDir = () => path.join(cwd(), CLERK_HIDDEN);\n const getTempDir = () => path.join(getClerkDir(), TEMP_DIR_NAME);\n const getConfigPath = () => path.join(getTempDir(), CONFIG_FILE);\n const getReadmePath = () => path.join(getTempDir(), README_FILE);\n const getLockPath = () => path.join(cwd(), CLERK_LOCK);\n\n const isLocked = (): boolean => inMemoryLock || fs.existsSync(getLockPath());\n\n const lock = (): boolean => {\n if (isLocked()) {\n return false;\n }\n inMemoryLock = true;\n try {\n fs.writeFileSync(getLockPath(), 'This file can be deleted if your app is stuck.', {\n encoding: 'utf8',\n mode: 0o644,\n });\n return true;\n } catch {\n inMemoryLock = false;\n return false;\n }\n };\n\n const unlock = (): void => {\n inMemoryLock = false;\n try {\n if (fs.existsSync(getLockPath())) {\n fs.rmSync(getLockPath(), { force: true });\n }\n } catch {\n // Ignore\n }\n };\n\n const ensureDirectoryExists = () => {\n const tempDir = getTempDir();\n if (!fs.existsSync(tempDir)) {\n fs.mkdirSync(tempDir, { recursive: true });\n }\n };\n\n const updateGitignore = () => {\n const gitignorePath = path.join(cwd(), '.gitignore');\n const entry = `/${CLERK_HIDDEN}/`;\n\n if (!fs.existsSync(gitignorePath)) {\n fs.writeFileSync(gitignorePath, '', { encoding: 'utf8', mode: 0o644 });\n }\n\n const content = fs.readFileSync(gitignorePath, { encoding: 'utf-8' });\n if (!content.includes(entry)) {\n fs.appendFileSync(gitignorePath, `\\n# clerk configuration (can include secrets)\\n${entry}\\n`);\n }\n };\n\n const writeReadme = () => {\n const readme = `## DO NOT COMMIT\nThis directory is auto-generated from \\`${frameworkPackageName}\\` because you are running in Keyless mode.\nAvoid committing the \\`.clerk/\\` directory as it includes the secret key of the unclaimed instance.\n`;\n fs.writeFileSync(getReadmePath(), readme, { encoding: 'utf8', mode: 0o600 });\n };\n\n return {\n read(): string {\n try {\n if (!fs.existsSync(getConfigPath())) {\n return '';\n }\n return fs.readFileSync(getConfigPath(), { encoding: 'utf-8' });\n } catch {\n return '';\n }\n },\n\n write(data: string): void {\n if (!lock()) {\n return;\n }\n try {\n ensureDirectoryExists();\n updateGitignore();\n writeReadme();\n fs.writeFileSync(getConfigPath(), data, { encoding: 'utf8', mode: 0o600 });\n } finally {\n unlock();\n }\n },\n\n remove(): void {\n if (!lock()) {\n return;\n }\n try {\n if (fs.existsSync(getClerkDir())) {\n fs.rmSync(getClerkDir(), { recursive: true, force: true });\n }\n } finally {\n unlock();\n }\n },\n };\n}\n","import { clerkDevelopmentCache, createConfirmationMessage, createKeylessModeMessage } from './devCache';\nimport type { AccountlessApplication } from './types';\n\nconst KEYLESS_SOURCE_FALLBACK = 'javascript';\n// Keep the source compact for BAPI metadata dimensions while covering common framework identifiers.\nconst KEYLESS_SOURCE_MAX_LENGTH = 36;\n\n/**\n * Storage adapter interface for keyless mode.\n * Implementations can use file system, cookies, or other storage mechanisms.\n *\n * Implementations are responsible for their own concurrency handling\n * (e.g., file locking for file-based storage).\n */\nexport interface KeylessStorage {\n /**\n * Reads the stored keyless configuration.\n *\n * @returns The JSON string of the stored config, or empty string if not found.\n */\n read(): string;\n\n /**\n * Writes the keyless configuration to storage.\n *\n * @param data - The JSON string to store.\n */\n write(data: string): void;\n\n /**\n * Removes the keyless configuration from storage.\n */\n remove(): void;\n}\n\n/**\n * API adapter for keyless mode operations.\n * This abstraction allows the service to work without depending on @clerk/backend.\n */\nexport interface KeylessAPI {\n /**\n * Creates a new accountless application.\n *\n * @param requestHeaders - Optional headers to include with the request.\n * @param source - Optional source value to include with the request.\n * @returns The created AccountlessApplication or null if failed.\n */\n createAccountlessApplication(requestHeaders?: Headers, source?: string): Promise<AccountlessApplication | null>;\n\n /**\n * Notifies the backend that onboarding is complete (instance has been claimed).\n *\n * @param requestHeaders - Optional headers to include with the request.\n * @param source - Optional source value to include with the request.\n * @returns The updated AccountlessApplication or null if failed.\n */\n completeOnboarding(requestHeaders?: Headers, source?: string): Promise<AccountlessApplication | null>;\n}\n\n/**\n * Options for creating a keyless service.\n */\nexport interface KeylessServiceOptions {\n /**\n * Storage adapter for reading/writing keyless configuration.\n */\n storage: KeylessStorage;\n\n /**\n * API adapter for keyless operations (create application, complete onboarding).\n */\n api: KeylessAPI;\n\n /**\n * Optional: Framework name for metadata (e.g., 'Next.js', 'TanStack Start').\n */\n framework?: string;\n\n /**\n * Optional: Framework version for metadata.\n */\n frameworkVersion?: string;\n}\n\n/**\n * Result type for key resolution.\n */\nexport interface KeylessResult {\n publishableKey: string | undefined;\n secretKey: string | undefined;\n claimUrl: string | undefined;\n apiKeysUrl: string | undefined;\n}\n\n/**\n * The keyless service interface.\n */\nexport interface KeylessService {\n /**\n * Gets existing keyless keys or creates new ones via the API.\n */\n getOrCreateKeys: () => Promise<AccountlessApplication | null>;\n\n /**\n * Reads existing keyless keys without creating new ones.\n */\n readKeys: () => AccountlessApplication | undefined;\n\n /**\n * Removes the keyless configuration.\n */\n removeKeys: () => void;\n\n /**\n * Notifies the backend that the instance has been claimed/onboarded.\n * This should be called once when the user claims their instance.\n */\n completeOnboarding: () => Promise<AccountlessApplication | null>;\n\n /**\n * Logs a keyless mode message to the console (throttled to once per process).\n */\n logKeylessMessage: (claimUrl: string) => void;\n\n /**\n * Resolves Clerk keys, falling back to keyless mode if configured keys are missing.\n *\n * @param configuredPublishableKey - The publishable key from options or environment\n * @param configuredSecretKey - The secret key from options or environment\n * @returns The resolved keys (either configured or from keyless mode)\n */\n resolveKeysWithKeylessFallback: (\n configuredPublishableKey: string | undefined,\n configuredSecretKey: string | undefined,\n ) => Promise<KeylessResult>;\n}\n\n/**\n * Creates metadata headers for the keyless service.\n */\nfunction createMetadataHeaders(framework?: string, frameworkVersion?: string): Headers {\n const headers = new Headers();\n\n if (framework) {\n headers.set('Clerk-Framework', framework);\n }\n if (frameworkVersion) {\n headers.set('Clerk-Framework-Version', frameworkVersion);\n }\n\n return headers;\n}\n\nfunction createSource(framework?: string): string {\n const source = (framework || KEYLESS_SOURCE_FALLBACK)\n .toLowerCase()\n .replace(/[^a-z0-9._-]+/g, '-')\n .replace(/^-+|-+$/g, '')\n .slice(0, KEYLESS_SOURCE_MAX_LENGTH);\n\n return source || KEYLESS_SOURCE_FALLBACK;\n}\n\n/**\n * Creates a keyless service that handles accountless application creation and storage.\n * This provides a simple API for frameworks to integrate keyless mode.\n *\n * @param options - Configuration for the service including storage and API adapters\n * @returns A keyless service instance\n *\n * @example\n * ```ts\n * import { createKeylessService } from '@clerk/shared/keyless';\n *\n * const keylessService = createKeylessService({\n * storage: createFileStorage(),\n * api: createKeylessAPI({ secretKey }),\n * framework: 'TanStack Start',\n * });\n *\n * const keys = await keylessService.getOrCreateKeys(request);\n * if (keys) {\n * console.log('Publishable Key:', keys.publishableKey);\n * }\n * ```\n */\nexport function createKeylessService(options: KeylessServiceOptions): KeylessService {\n const { storage, api, framework, frameworkVersion } = options;\n\n let hasLoggedKeylessMessage = false;\n const source = createSource(framework);\n\n const safeParseConfig = (): AccountlessApplication | undefined => {\n try {\n const data = storage.read();\n if (!data) {\n return undefined;\n }\n return JSON.parse(data) as AccountlessApplication;\n } catch {\n return undefined;\n }\n };\n\n return {\n async getOrCreateKeys(): Promise<AccountlessApplication | null> {\n // Check for existing config first\n const existingConfig = safeParseConfig();\n if (existingConfig?.publishableKey && existingConfig?.secretKey) {\n return existingConfig;\n }\n\n // Create metadata headers\n const headers = createMetadataHeaders(framework, frameworkVersion);\n\n // Create new keys via the API\n const accountlessApplication = await api.createAccountlessApplication(headers, source);\n\n if (accountlessApplication) {\n storage.write(JSON.stringify(accountlessApplication));\n }\n\n return accountlessApplication;\n },\n\n readKeys(): AccountlessApplication | undefined {\n return safeParseConfig();\n },\n\n removeKeys(): void {\n storage.remove();\n },\n\n async completeOnboarding(): Promise<AccountlessApplication | null> {\n const headers = createMetadataHeaders(framework, frameworkVersion);\n return api.completeOnboarding(headers, source);\n },\n\n logKeylessMessage(claimUrl: string): void {\n if (!hasLoggedKeylessMessage) {\n hasLoggedKeylessMessage = true;\n console.log(`[Clerk]: Running in keyless mode. Claim your keys at: ${claimUrl}`);\n }\n },\n\n async resolveKeysWithKeylessFallback(\n configuredPublishableKey: string | undefined,\n configuredSecretKey: string | undefined,\n ): Promise<KeylessResult> {\n let publishableKey = configuredPublishableKey;\n let secretKey = configuredSecretKey;\n let claimUrl: string | undefined;\n let apiKeysUrl: string | undefined;\n\n try {\n const locallyStoredKeys = safeParseConfig();\n\n // Check if running with claimed keys (configured keys match locally stored keyless keys)\n const runningWithClaimedKeys =\n Boolean(configuredPublishableKey) && configuredPublishableKey === locallyStoredKeys?.publishableKey;\n\n if (runningWithClaimedKeys && locallyStoredKeys) {\n // Complete onboarding when running with claimed keys\n try {\n await clerkDevelopmentCache?.run(() => this.completeOnboarding(), {\n cacheKey: `${locallyStoredKeys.publishableKey}_complete`,\n onSuccessStale: 24 * 60 * 60 * 1000, // 24 hours\n });\n } catch {\n // noop\n }\n\n clerkDevelopmentCache?.log({\n cacheKey: `${locallyStoredKeys.publishableKey}_claimed`,\n msg: createConfirmationMessage(),\n });\n\n return { publishableKey, secretKey, claimUrl, apiKeysUrl };\n }\n\n // In keyless mode, try to read/create keys from the file system\n if (!publishableKey && !secretKey) {\n const keylessApp: AccountlessApplication | null = await this.getOrCreateKeys();\n\n if (keylessApp) {\n publishableKey = keylessApp.publishableKey;\n secretKey = keylessApp.secretKey;\n claimUrl = keylessApp.claimUrl;\n apiKeysUrl = keylessApp.apiKeysUrl;\n\n clerkDevelopmentCache?.log({\n cacheKey: keylessApp.publishableKey,\n msg: createKeylessModeMessage(keylessApp),\n });\n }\n }\n } catch {\n // noop - fall through to return whatever keys we have\n }\n\n return { publishableKey, secretKey, claimUrl, apiKeysUrl };\n },\n };\n}\n","import { clerkDevelopmentCache, createConfirmationMessage, createKeylessModeMessage } from './devCache';\nimport type { KeylessService } from './service';\nimport type { AccountlessApplication } from './types';\n\nexport interface KeylessResult {\n publishableKey: string | undefined;\n secretKey: string | undefined;\n claimUrl: string | undefined;\n apiKeysUrl: string | undefined;\n}\n\n/**\n * Resolves Clerk keys, falling back to keyless mode in development if configured keys are missing.\n *\n * @param configuredPublishableKey - The publishable key from options or environment\n * @param configuredSecretKey - The secret key from options or environment\n * @param keylessService - The keyless service instance (or null if unavailable)\n * @param canUseKeyless - Whether keyless mode is enabled in the current environment\n * @returns The resolved keys (either configured or from keyless mode)\n */\nexport async function resolveKeysWithKeylessFallback(\n configuredPublishableKey: string | undefined,\n configuredSecretKey: string | undefined,\n keylessService: KeylessService | null,\n canUseKeyless: boolean,\n): Promise<KeylessResult> {\n let publishableKey = configuredPublishableKey;\n let secretKey = configuredSecretKey;\n let claimUrl: string | undefined;\n let apiKeysUrl: string | undefined;\n\n if (!canUseKeyless) {\n return { publishableKey, secretKey, claimUrl, apiKeysUrl };\n }\n\n if (!keylessService) {\n return { publishableKey, secretKey, claimUrl, apiKeysUrl };\n }\n\n try {\n const locallyStoredKeys = keylessService.readKeys();\n\n // Check if running with claimed keys (configured keys match locally stored keyless keys)\n const runningWithClaimedKeys =\n Boolean(configuredPublishableKey) && configuredPublishableKey === locallyStoredKeys?.publishableKey;\n\n if (runningWithClaimedKeys && locallyStoredKeys) {\n // Complete onboarding when running with claimed keys\n try {\n await clerkDevelopmentCache?.run(() => keylessService.completeOnboarding(), {\n cacheKey: `${locallyStoredKeys.publishableKey}_complete`,\n onSuccessStale: 24 * 60 * 60 * 1000, // 24 hours\n });\n } catch {\n // noop\n }\n\n clerkDevelopmentCache?.log({\n cacheKey: `${locallyStoredKeys.publishableKey}_claimed`,\n msg: createConfirmationMessage(),\n });\n\n return { publishableKey, secretKey, claimUrl, apiKeysUrl };\n }\n\n // In keyless mode, try to read/create keys from the file system\n if (!publishableKey && !secretKey) {\n const keylessApp: AccountlessApplication | null = await keylessService.getOrCreateKeys();\n\n if (keylessApp) {\n publishableKey = keylessApp.publishableKey;\n secretKey = keylessApp.secretKey;\n claimUrl = keylessApp.claimUrl;\n apiKeysUrl = keylessApp.apiKeysUrl;\n\n clerkDevelopmentCache?.log({\n cacheKey: keylessApp.publishableKey,\n msg: createKeylessModeMessage(keylessApp),\n });\n }\n }\n } catch {\n // noop - fall through to return whatever keys we have\n }\n\n return { publishableKey, secretKey, claimUrl, apiKeysUrl };\n}\n"],"mappings":"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"}