@sylphx/sdk 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/nextjs/index.ts","../../src/nextjs/middleware.ts","../../src/constants.ts","../../src/key-validation.ts","../../src/nextjs/cookies.ts","../../src/nextjs/server.ts","../../../../node_modules/jose/dist/webapi/lib/buffer_utils.js","../../../../node_modules/jose/dist/webapi/lib/base64.js","../../../../node_modules/jose/dist/webapi/util/base64url.js","../../../../node_modules/jose/dist/webapi/util/errors.js","../../../../node_modules/jose/dist/webapi/lib/crypto_key.js","../../../../node_modules/jose/dist/webapi/lib/invalid_key_input.js","../../../../node_modules/jose/dist/webapi/lib/is_key_like.js","../../../../node_modules/jose/dist/webapi/lib/is_disjoint.js","../../../../node_modules/jose/dist/webapi/lib/is_object.js","../../../../node_modules/jose/dist/webapi/lib/check_key_length.js","../../../../node_modules/jose/dist/webapi/lib/jwk_to_key.js","../../../../node_modules/jose/dist/webapi/key/import.js","../../../../node_modules/jose/dist/webapi/lib/validate_crit.js","../../../../node_modules/jose/dist/webapi/lib/validate_algorithms.js","../../../../node_modules/jose/dist/webapi/lib/is_jwk.js","../../../../node_modules/jose/dist/webapi/lib/normalize_key.js","../../../../node_modules/jose/dist/webapi/lib/check_key_type.js","../../../../node_modules/jose/dist/webapi/lib/subtle_dsa.js","../../../../node_modules/jose/dist/webapi/lib/get_sign_verify_key.js","../../../../node_modules/jose/dist/webapi/lib/verify.js","../../../../node_modules/jose/dist/webapi/jws/flattened/verify.js","../../../../node_modules/jose/dist/webapi/jws/compact/verify.js","../../../../node_modules/jose/dist/webapi/lib/jwt_claims_set.js","../../../../node_modules/jose/dist/webapi/jwt/verify.js","../../src/server/index.ts"],"sourcesContent":["/**\n * @sylphx/sdk/nextjs — State of the Art\n *\n * Next.js integration for Sylphx Platform SDK.\n *\n * ONE middleware handles everything:\n * - Auth routes (mounted automatically)\n * - Token refresh (automatic, every request)\n * - Route protection\n * - Cookie management\n *\n * @example\n * ```ts\n * // middleware.ts (or proxy.ts for Next.js 16)\n * import { createSylphxMiddleware } from '@sylphx/sdk/nextjs'\n *\n * export default createSylphxMiddleware({\n * publicRoutes: ['/', '/about', '/pricing'],\n * })\n *\n * export const config = {\n * matcher: ['/((?!_next|.*\\\\..*).*)', '/'],\n * }\n * ```\n *\n * That's it. No /api/auth/* routes needed.\n *\n * @example\n * ```ts\n * // In a Server Component\n * import { auth, currentUser } from '@sylphx/sdk/nextjs'\n *\n * export default async function Page() {\n * const { userId } = await auth()\n * const user = await currentUser()\n *\n * if (!userId) {\n * redirect('/login')\n * }\n *\n * return <div>Hello, {user?.name}</div>\n * }\n * ```\n */\n\n// =============================================================================\n// Middleware — State of the Art (Auth0 v4 / Clerk / Supabase pattern)\n// =============================================================================\n// ONE middleware handles everything. No manual API routes needed.\n\nexport {\n\tcreateSylphxMiddleware,\n\tcreateMatcher,\n\tgetNamespace,\n\ttype SylphxMiddlewareConfig,\n} from \"./middleware\";\n\n// =============================================================================\n// Server-side Auth (for Server Components)\n// =============================================================================\n\nexport {\n\tconfigureServer,\n\tauth,\n\tcurrentUser,\n\tcurrentUserId,\n\thandleCallback,\n\tsignOut,\n\tsyncAuthToCookies,\n\tgetAuthorizationUrl,\n\tgetSessionToken,\n\ttype AuthResult,\n} from \"./server\";\n\n// =============================================================================\n// Cookie Helpers (advanced use only)\n// =============================================================================\n\nexport {\n\tgetCookieNames,\n\tgetAuthCookies,\n\tsetAuthCookies,\n\tclearAuthCookies,\n\tsetAuthCookiesMiddleware,\n\tclearAuthCookiesMiddleware,\n\tisSessionExpired,\n\thasRefreshToken,\n\tparseUserCookie,\n\tSESSION_TOKEN_LIFETIME,\n\tREFRESH_TOKEN_LIFETIME,\n\tSECURE_COOKIE_OPTIONS,\n\tUSER_COOKIE_OPTIONS,\n\ttype UserCookieData,\n\ttype AuthCookiesData,\n} from \"./cookies\";\n\n// Re-export constants needed for token expiry calculations\nexport {\n\tTOKEN_EXPIRY_BUFFER_MS,\n\tSESSION_TOKEN_LIFETIME_MS,\n} from \"../constants\";\n","/**\n * Sylphx Unified Middleware — State of the Art\n *\n * ONE middleware function handles EVERYTHING:\n * - Auth routes (mounted automatically, zero manual API routes)\n * - Token refresh (automatic, every request)\n * - Route protection\n * - Cookie management\n *\n * This follows Auth0 v4 / Clerk / Supabase patterns where middleware\n * handles all auth concerns. Apps don't need to create any /api/auth/* routes.\n *\n * @example\n * ```typescript\n * // middleware.ts (or proxy.ts for Next.js 16)\n * import { createSylphxMiddleware } from '@sylphx/sdk/nextjs'\n *\n * export default createSylphxMiddleware({\n * publicRoutes: ['/', '/about', '/pricing'],\n * })\n *\n * export const config = {\n * matcher: ['/((?!_next|.*\\\\..*).*)', '/'],\n * }\n * ```\n *\n * That's it. No /api/auth/* routes needed.\n */\n\nimport type { NextRequest } from 'next/server'\nimport { NextResponse } from 'next/server'\nimport { DEFAULT_PLATFORM_URL, TOKEN_EXPIRY_BUFFER_MS } from '../constants'\nimport { getCookieNamespace, validateAndSanitizeSecretKey } from '../key-validation'\nimport type { TokenResponse } from '../types'\nimport {\n\tclearAuthCookiesMiddleware,\n\tgetCookieNames,\n\tREFRESH_TOKEN_LIFETIME,\n\tSECURE_COOKIE_OPTIONS,\n\tSESSION_TOKEN_LIFETIME,\n\tsetAuthCookiesMiddleware,\n\tUSER_COOKIE_OPTIONS,\n\ttype UserCookieData,\n} from './cookies'\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport interface SylphxMiddlewareConfig {\n\t/**\n\t * Routes that don't require authentication.\n\t * Supports exact paths and wildcards.\n\t *\n\t * @example ['/', '/about', '/pricing', '/blog/*']\n\t * @default ['/']\n\t */\n\tpublicRoutes?: string[]\n\n\t/**\n\t * Routes that middleware should completely ignore.\n\t * Use for webhooks, static assets, or third-party integrations.\n\t *\n\t * @default []\n\t */\n\tignoredRoutes?: string[]\n\n\t/**\n\t * URL to redirect unauthenticated users.\n\t * @default '/login'\n\t */\n\tsignInUrl?: string\n\n\t/**\n\t * URL to redirect after sign out.\n\t * @default '/'\n\t */\n\tafterSignOutUrl?: string\n\n\t/**\n\t * URL to redirect after successful sign in.\n\t * @default '/dashboard'\n\t */\n\tafterSignInUrl?: string\n\n\t/**\n\t * Auth routes prefix. Routes are mounted at:\n\t * - {prefix}/callback — OAuth callback handler\n\t * - {prefix}/signout — Sign out handler\n\t *\n\t * @default '/auth'\n\t */\n\tauthPrefix?: string\n\n\t/**\n\t * Enable debug logging.\n\t * @default false\n\t */\n\tdebug?: boolean\n\n\t/**\n\t * Secret key for authentication.\n\t * Override to use a programmatic key instead of SYLPHX_SECRET_KEY env var.\n\t *\n\t * Use case: Platform Console uses dynamically generated keys.\n\t *\n\t * @default process.env.SYLPHX_SECRET_KEY\n\t */\n\tsecretKey?: string\n\n\t/**\n\t * Platform URL for API calls.\n\t * Override for self-hosted or same-origin deployments.\n\t *\n\t * @default process.env.SYLPHX_PLATFORM_URL || 'https://sylphx.com'\n\t */\n\tplatformUrl?: string\n\n\t/**\n\t * Callback to add custom headers/logic to responses.\n\t * Called for every non-auth-route request after SDK processing.\n\t *\n\t * Use case: Add security headers, tracking cookies, etc.\n\t *\n\t * @example\n\t * ```typescript\n\t * onResponse: (response, request) => {\n\t * response.headers.set('X-Custom-Header', 'value')\n\t * }\n\t * ```\n\t */\n\tonResponse?: (response: NextResponse, request: NextRequest) => void | Promise<void>\n}\n\n// =============================================================================\n// Helpers\n// =============================================================================\n\n/**\n * Type guard for token response\n */\nfunction isTokenResponse(data: unknown): data is TokenResponse {\n\treturn (\n\t\ttypeof data === 'object' &&\n\t\tdata !== null &&\n\t\t'accessToken' in data &&\n\t\t'refreshToken' in data &&\n\t\t'user' in data &&\n\t\ttypeof (data as TokenResponse).accessToken === 'string' &&\n\t\ttypeof (data as TokenResponse).refreshToken === 'string'\n\t)\n}\n\n/**\n * Decode JWT payload without verification (for expiry check)\n */\nfunction decodeJwtPayload(token: string): { exp?: number; sub?: string } | null {\n\ttry {\n\t\tconst parts = token.split('.')\n\t\tif (parts.length !== 3) return null\n\t\tconst payload = parts[1]\n\t\tconst base64 = payload.replace(/-/g, '+').replace(/_/g, '/')\n\t\tconst jsonPayload = atob(base64)\n\t\treturn JSON.parse(jsonPayload)\n\t} catch {\n\t\treturn null\n\t}\n}\n\n/**\n * Check if token is expired (with 30s buffer)\n */\nfunction isTokenExpired(token: string): boolean {\n\tconst payload = decodeJwtPayload(token)\n\tif (!payload?.exp) return true\n\treturn payload.exp * 1000 < Date.now() + TOKEN_EXPIRY_BUFFER_MS\n}\n\n/**\n * Check if path matches pattern\n */\nfunction matchesPattern(pathname: string, pattern: string): boolean {\n\tif (pattern === pathname) return true\n\tif (pattern.endsWith('/*')) {\n\t\tconst base = pattern.slice(0, -2)\n\t\treturn pathname === base || pathname.startsWith(`${base}/`)\n\t}\n\tif (pattern.endsWith('/**')) {\n\t\tconst base = pattern.slice(0, -3)\n\t\treturn pathname === base || pathname.startsWith(`${base}/`)\n\t}\n\treturn false\n}\n\n/**\n * Check if pathname matches any patterns\n */\nfunction matchesAny(pathname: string, patterns: string[]): boolean {\n\treturn patterns.some((p) => matchesPattern(pathname, p))\n}\n\n// =============================================================================\n// Auth Route Handlers (Mounted in Middleware)\n// =============================================================================\n\ninterface MiddlewareContext {\n\tsecretKey: string\n\tplatformUrl: string\n\tnamespace: string\n\tcookieNames: ReturnType<typeof getCookieNames>\n\tconfig: {\n\t\tpublicRoutes: string[]\n\t\tignoredRoutes: string[]\n\t\tsignInUrl: string\n\t\tafterSignOutUrl: string\n\t\tafterSignInUrl: string\n\t\tauthPrefix: string\n\t\tdebug: boolean\n\t\tonResponse?: (response: NextResponse, request: NextRequest) => void | Promise<void>\n\t}\n\tlog: (msg: string, data?: unknown) => void\n}\n\n/**\n * Handle OAuth callback\n * GET {authPrefix}/callback?code=xxx\n */\nasync function handleCallback(request: NextRequest, ctx: MiddlewareContext): Promise<NextResponse> {\n\tconst { searchParams } = request.nextUrl\n\tconst code = searchParams.get('code')\n\tconst error = searchParams.get('error')\n\tconst errorDescription = searchParams.get('error_description')\n\tconst redirectTo = searchParams.get('redirect_to') || ctx.config.afterSignInUrl\n\n\tctx.log('Callback', { hasCode: !!code, error })\n\n\t// Handle OAuth errors\n\tif (error) {\n\t\tconst url = new URL(ctx.config.signInUrl, request.url)\n\t\turl.searchParams.set('error', error)\n\t\tif (errorDescription) url.searchParams.set('error_description', errorDescription)\n\t\treturn NextResponse.redirect(url)\n\t}\n\n\tif (!code) {\n\t\tconst url = new URL(ctx.config.signInUrl, request.url)\n\t\turl.searchParams.set('error', 'missing_code')\n\t\treturn NextResponse.redirect(url)\n\t}\n\n\ttry {\n\t\t// Exchange code for tokens\n\t\tconst res = await fetch(`${ctx.platformUrl}/api/v1/auth/token`, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: { 'Content-Type': 'application/json' },\n\t\t\tbody: JSON.stringify({\n\t\t\t\tgrant_type: 'authorization_code',\n\t\t\t\tcode,\n\t\t\t\tclient_secret: ctx.secretKey,\n\t\t\t}),\n\t\t})\n\n\t\tif (!res.ok) {\n\t\t\tconst data = (await res.json().catch(() => ({}))) as { error?: string }\n\t\t\tconst url = new URL(ctx.config.signInUrl, request.url)\n\t\t\turl.searchParams.set('error', data.error || 'token_exchange_failed')\n\t\t\treturn NextResponse.redirect(url)\n\t\t}\n\n\t\tconst data: unknown = await res.json()\n\t\tif (!isTokenResponse(data)) {\n\t\t\tconst url = new URL(ctx.config.signInUrl, request.url)\n\t\t\turl.searchParams.set('error', 'invalid_response')\n\t\t\treturn NextResponse.redirect(url)\n\t\t}\n\n\t\t// Success: set cookies and redirect\n\t\tconst successUrl = new URL(redirectTo, request.url)\n\t\tconst response = NextResponse.redirect(successUrl)\n\t\tsetAuthCookiesMiddleware(response, ctx.namespace, data)\n\n\t\tctx.log('Callback success', { redirectTo })\n\t\treturn response\n\t} catch (err) {\n\t\tconsole.error('[Sylphx] Callback error:', err)\n\t\tconst url = new URL(ctx.config.signInUrl, request.url)\n\t\turl.searchParams.set('error', 'internal_error')\n\t\treturn NextResponse.redirect(url)\n\t}\n}\n\n/**\n * Handle sign out\n * GET/POST {authPrefix}/signout\n */\nasync function handleSignOut(request: NextRequest, ctx: MiddlewareContext): Promise<NextResponse> {\n\tctx.log('Signout')\n\n\tconst refreshToken = request.cookies.get(ctx.cookieNames.REFRESH)?.value\n\n\t// Revoke token on platform (best-effort)\n\tif (refreshToken) {\n\t\ttry {\n\t\t\tawait fetch(`${ctx.platformUrl}/api/v1/auth/revoke`, {\n\t\t\t\tmethod: 'POST',\n\t\t\t\theaders: { 'Content-Type': 'application/json' },\n\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\ttoken: refreshToken,\n\t\t\t\t\tclient_secret: ctx.secretKey,\n\t\t\t\t}),\n\t\t\t})\n\t\t} catch {\n\t\t\t// Ignore\n\t\t}\n\t}\n\n\t// Clear cookies and redirect\n\tconst url = new URL(ctx.config.afterSignOutUrl, request.url)\n\tconst response = NextResponse.redirect(url)\n\tclearAuthCookiesMiddleware(response, ctx.namespace)\n\n\tctx.log('Signout complete')\n\treturn response\n}\n\n/**\n * Handle token request (BFF pattern)\n * GET {authPrefix}/token\n *\n * Returns the session token from HttpOnly cookie for use with third-party APIs.\n * This enables the BFF (Backend-for-Frontend) pattern where clients need\n * bearer tokens for external API calls but tokens are stored in HttpOnly cookies.\n */\nfunction handleToken(request: NextRequest, ctx: MiddlewareContext): NextResponse {\n\tctx.log('Token request')\n\n\tconst sessionToken = request.cookies.get(ctx.cookieNames.SESSION)?.value\n\n\tif (!sessionToken) {\n\t\tctx.log('No session token')\n\t\treturn NextResponse.json({ error: 'Not authenticated', accessToken: null }, { status: 401 })\n\t}\n\n\t// Check if token is expired\n\tif (isTokenExpired(sessionToken)) {\n\t\tctx.log('Session token expired')\n\t\treturn NextResponse.json({ error: 'Session expired', accessToken: null }, { status: 401 })\n\t}\n\n\tctx.log('Token returned')\n\treturn NextResponse.json({ accessToken: sessionToken })\n}\n\n/**\n * Refresh tokens server-side\n */\nasync function refreshTokens(\n\trefreshToken: string,\n\tctx: MiddlewareContext,\n): Promise<TokenResponse | null> {\n\tctx.log('Refreshing tokens')\n\n\ttry {\n\t\tconst res = await fetch(`${ctx.platformUrl}/api/v1/auth/token`, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: { 'Content-Type': 'application/json' },\n\t\t\tbody: JSON.stringify({\n\t\t\t\tgrant_type: 'refresh_token',\n\t\t\t\trefresh_token: refreshToken,\n\t\t\t\tclient_secret: ctx.secretKey,\n\t\t\t}),\n\t\t})\n\n\t\tif (!res.ok) {\n\t\t\tctx.log('Refresh failed', res.status)\n\t\t\treturn null\n\t\t}\n\n\t\tconst data: unknown = await res.json()\n\t\tif (!isTokenResponse(data)) {\n\t\t\tctx.log('Invalid refresh response')\n\t\t\treturn null\n\t\t}\n\n\t\tctx.log('Refresh success')\n\t\treturn data\n\t} catch (err) {\n\t\tctx.log('Refresh error', err)\n\t\treturn null\n\t}\n}\n\n// =============================================================================\n// Main Middleware Factory\n// =============================================================================\n\n/**\n * Create Sylphx middleware — State of the Art\n *\n * ONE function handles everything:\n * - Auth routes ({authPrefix}/callback, {authPrefix}/signout)\n * - Token refresh (automatic, every request)\n * - Route protection\n * - Cookie management\n *\n * @example\n * ```typescript\n * // middleware.ts (or proxy.ts for Next.js 16)\n * import { createSylphxMiddleware } from '@sylphx/sdk/nextjs'\n *\n * export default createSylphxMiddleware({\n * publicRoutes: ['/', '/about', '/pricing'],\n * })\n *\n * export const config = {\n * matcher: ['/((?!_next|.*\\\\..*).*)', '/'],\n * }\n * ```\n */\nexport function createSylphxMiddleware(userConfig: SylphxMiddlewareConfig = {}) {\n\t// ==========================================================================\n\t// Configuration (validated at startup, not per-request)\n\t// ==========================================================================\n\n\t// Secret key: prefer config, fallback to env var\n\tconst rawSecretKey = userConfig.secretKey || process.env.SYLPHX_SECRET_KEY\n\tif (!rawSecretKey) {\n\t\tthrow new Error(\n\t\t\t'[Sylphx] Secret key is required.\\n' +\n\t\t\t\t'Either pass secretKey in config or set SYLPHX_SECRET_KEY env var.\\n' +\n\t\t\t\t'Get your key from Sylphx Console → API Keys.',\n\t\t)\n\t}\n\n\tconst secretKey = validateAndSanitizeSecretKey(rawSecretKey)\n\n\t// Platform URL: prefer config, then env var, then default\n\tconst platformUrl = (\n\t\tuserConfig.platformUrl ||\n\t\tprocess.env.SYLPHX_PLATFORM_URL ||\n\t\tDEFAULT_PLATFORM_URL\n\t).trim()\n\n\tconst namespace = getCookieNamespace(secretKey)\n\tconst cookieNames = getCookieNames(namespace)\n\n\tconst config = {\n\t\tpublicRoutes: userConfig.publicRoutes ?? ['/'],\n\t\tignoredRoutes: userConfig.ignoredRoutes ?? [],\n\t\tsignInUrl: userConfig.signInUrl ?? '/login',\n\t\tafterSignOutUrl: userConfig.afterSignOutUrl ?? '/',\n\t\tafterSignInUrl: userConfig.afterSignInUrl ?? '/dashboard',\n\t\tauthPrefix: userConfig.authPrefix ?? '/auth',\n\t\tdebug: userConfig.debug ?? false,\n\t\tonResponse: userConfig.onResponse,\n\t}\n\n\t// Auth routes and sign-in URL are always public\n\tconst publicRoutes = [\n\t\t...config.publicRoutes,\n\t\tconfig.signInUrl,\n\t\t'/signup',\n\t\t`${config.authPrefix}/*`,\n\t]\n\n\tconst log = (msg: string, data?: unknown) => {\n\t\tif (config.debug) {\n\t\t\tconsole.log(`[Sylphx] ${msg}`, data ?? '')\n\t\t}\n\t}\n\n\tconst ctx: MiddlewareContext = {\n\t\tsecretKey,\n\t\tplatformUrl,\n\t\tnamespace,\n\t\tcookieNames,\n\t\tconfig,\n\t\tlog,\n\t}\n\n\t// ==========================================================================\n\t// Middleware Function\n\t// ==========================================================================\n\n\treturn async function middleware(request: NextRequest): Promise<NextResponse> {\n\t\tconst { pathname } = request.nextUrl\n\n\t\tlog(`${request.method} ${pathname}`)\n\n\t\t// ======================================================================\n\t\t// Skip: Ignored routes, static files\n\t\t// ======================================================================\n\n\t\tif (matchesAny(pathname, config.ignoredRoutes)) {\n\t\t\tlog('Ignored route')\n\t\t\treturn NextResponse.next()\n\t\t}\n\n\t\t// Skip files with extensions and Next.js internals\n\t\tif (pathname.includes('.') || pathname.startsWith('/_next')) {\n\t\t\treturn NextResponse.next()\n\t\t}\n\n\t\t// ======================================================================\n\t\t// Auth Routes (Mounted Automatically)\n\t\t// ======================================================================\n\n\t\tif (pathname === `${config.authPrefix}/callback`) {\n\t\t\treturn handleCallback(request, ctx)\n\t\t}\n\n\t\tif (pathname === `${config.authPrefix}/signout`) {\n\t\t\treturn handleSignOut(request, ctx)\n\t\t}\n\n\t\tif (pathname === `${config.authPrefix}/token`) {\n\t\t\treturn handleToken(request, ctx)\n\t\t}\n\n\t\t// ======================================================================\n\t\t// Token Refresh (Every Request)\n\t\t// ======================================================================\n\n\t\tconst sessionToken = request.cookies.get(cookieNames.SESSION)?.value\n\t\tconst refreshToken = request.cookies.get(cookieNames.REFRESH)?.value\n\t\tconst hasValidSession = sessionToken && !isTokenExpired(sessionToken)\n\n\t\tconst response = NextResponse.next()\n\t\tlet isAuthenticated = hasValidSession\n\n\t\t// Session expired + refresh token exists → refresh server-side\n\t\tif (!hasValidSession && refreshToken) {\n\t\t\tlog('Session expired, refreshing')\n\n\t\t\tconst tokens = await refreshTokens(refreshToken, ctx)\n\n\t\t\tif (tokens) {\n\t\t\t\t// Success: update cookies\n\t\t\t\tsetAuthCookiesMiddleware(response, namespace, tokens)\n\t\t\t\tisAuthenticated = true\n\t\t\t} else {\n\t\t\t\t// Failed: clear cookies\n\t\t\t\tclearAuthCookiesMiddleware(response, namespace)\n\t\t\t\tisAuthenticated = false\n\t\t\t}\n\t\t}\n\n\t\t// ======================================================================\n\t\t// Route Protection\n\t\t// ======================================================================\n\n\t\tconst isPublic = matchesAny(pathname, publicRoutes)\n\n\t\t// Protected route + not authenticated → redirect to sign-in\n\t\tif (!isPublic && !isAuthenticated) {\n\t\t\tlog('Redirecting to sign-in')\n\t\t\tconst url = new URL(config.signInUrl, request.url)\n\t\t\turl.searchParams.set('redirect_to', pathname)\n\t\t\treturn NextResponse.redirect(url)\n\t\t}\n\n\t\t// Authenticated + on sign-in page → redirect to dashboard\n\t\tif (isAuthenticated && pathname === config.signInUrl) {\n\t\t\tlog('Redirecting from sign-in to dashboard')\n\t\t\treturn NextResponse.redirect(new URL(config.afterSignInUrl, request.url))\n\t\t}\n\n\t\t// ======================================================================\n\t\t// Custom Response Hook\n\t\t// ======================================================================\n\n\t\tif (config.onResponse) {\n\t\t\tawait config.onResponse(response, request)\n\t\t}\n\n\t\treturn response\n\t}\n}\n\n// =============================================================================\n// Exports\n// =============================================================================\n\n/**\n * Create recommended matcher config\n */\nexport function createMatcher(): { matcher: string[] } {\n\treturn {\n\t\tmatcher: ['/((?!_next|monitoring|.*\\\\..*).*)', '/'],\n\t}\n}\n\n/**\n * Get cookie namespace from secret key (for advanced use)\n */\nexport function getNamespace(secretKey: string): string {\n\treturn getCookieNamespace(validateAndSanitizeSecretKey(secretKey))\n}\n","/**\n * SDK Constants — Single Source of Truth\n *\n * Shared constants used across the SDK. Centralizing these\n * prevents magic number duplication and makes changes easier.\n *\n * IMPORTANT: All time-based constants should be used consistently\n * across the SDK. Never hardcode magic numbers like 30000, 5 * 60 * 1000, etc.\n */\n\n// =============================================================================\n// API Configuration\n// =============================================================================\n\n/** Default platform URL */\nexport const DEFAULT_PLATFORM_URL = 'https://sylphx.com'\n\n/**\n * Canonical environment variable name for the platform URL.\n *\n * SDK modules MUST read from this env var (with SYLPHX_URL as legacy fallback).\n * Centralizing the name prevents the same env var being spelled differently\n * across kv.ts, streams.ts, ai.ts, middleware.ts, and server.ts.\n */\nexport const ENV_PLATFORM_URL = 'SYLPHX_PLATFORM_URL'\n\n/**\n * Legacy environment variable name for the platform URL.\n *\n * Supported as a fallback for older deployments that set SYLPHX_URL.\n * New projects should use SYLPHX_PLATFORM_URL.\n */\nexport const ENV_PLATFORM_URL_LEGACY = 'SYLPHX_URL'\n\n/**\n * Canonical environment variable name for the secret key.\n *\n * All server-side SDK modules read from this env var by default.\n */\nexport const ENV_SECRET_KEY = 'SYLPHX_SECRET_KEY'\n\n/**\n * Resolve the platform URL from environment variables.\n *\n * Priority: explicit value > SYLPHX_PLATFORM_URL > SYLPHX_URL (legacy) > default\n */\nexport function resolvePlatformUrl(explicit?: string): string {\n\treturn (\n\t\texplicit ||\n\t\tprocess.env[ENV_PLATFORM_URL] ||\n\t\tprocess.env[ENV_PLATFORM_URL_LEGACY] ||\n\t\tDEFAULT_PLATFORM_URL\n\t).trim()\n}\n\n/**\n * Resolve the secret key from environment variables.\n *\n * Returns the raw value before validation. Callers should pass the result\n * through `validateAndSanitizeSecretKey()`.\n */\nexport function resolveSecretKey(explicit?: string): string | undefined {\n\treturn explicit || process.env[ENV_SECRET_KEY]\n}\n\n/** @deprecated No longer used for path construction. Use SDK_API_PATH directly. */\nexport const SDK_API_VERSION = 'v1'\n\n/**\n * SDK API base path — legacy path served from main Next.js app.\n *\n * Used when `platformUrl` is set to `https://sylphx.com` (default).\n * Points to the runtime Hono app mounted at /api/app/v1 (via Next.js catch-all).\n *\n * @deprecated Prefer project `ref`-based URL: https://{ref}.api.sylphx.com/v1\n */\nexport const SDK_API_PATH = `/api/app/v1`\n\n/**\n * SDK API path for new subdomain-based SDK server.\n *\n * Used when `ref` is provided to `createConfig`.\n * The full base becomes: https://{ref}.api.sylphx.com + SDK_API_PATH_NEW\n */\nexport const SDK_API_PATH_NEW = `/v1`\n\n/**\n * Default SDK API host for new subdomain-based SDK server.\n * The full URL is built as: https://{ref}.api.sylphx.com/v1\n */\nexport const DEFAULT_SDK_API_HOST = 'api.sylphx.com'\n\n/**\n * Default auth route prefix\n *\n * Used for OAuth callbacks and signout routes.\n * Must match the middleware's authPrefix config.\n */\nexport const DEFAULT_AUTH_PREFIX = '/auth'\n\n/**\n * SDK package version\n *\n * Sent in X-SDK-Version header for debugging and analytics.\n * Update this when releasing new SDK versions.\n */\nexport const SDK_VERSION = '0.1.0'\n\n/**\n * SDK platform identifier\n *\n * Sent in X-SDK-Platform header to identify the runtime environment.\n */\nexport const SDK_PLATFORM =\n\ttypeof window !== 'undefined'\n\t\t? 'browser'\n\t\t: typeof process !== 'undefined' && process.versions?.node\n\t\t\t? 'node'\n\t\t\t: 'unknown'\n\n// =============================================================================\n// Timeouts & Durations\n// =============================================================================\n\n/** Default request timeout in milliseconds (30 seconds) */\nexport const DEFAULT_TIMEOUT_MS = 30_000\n\n/**\n * Token expiry buffer in milliseconds (30 seconds)\n *\n * Refresh tokens this many milliseconds BEFORE they expire\n * to account for network latency and clock skew.\n */\nexport const TOKEN_EXPIRY_BUFFER_MS = 30_000\n\n/**\n * Session token lifetime in seconds (5 minutes)\n *\n * Matches Clerk's short-lived access token pattern.\n * Used for cookie maxAge and React Query staleTime.\n */\nexport const SESSION_TOKEN_LIFETIME_SECONDS = 5 * 60\n\n/** Session token lifetime in milliseconds (for React Query staleTime) */\nexport const SESSION_TOKEN_LIFETIME_MS = SESSION_TOKEN_LIFETIME_SECONDS * 1000\n\n/**\n * Refresh token lifetime in seconds (30 days)\n *\n * Long-lived token for silent refresh.\n */\nexport const REFRESH_TOKEN_LIFETIME_SECONDS = 30 * 24 * 60 * 60\n\n// =============================================================================\n// Feature Flags Cache\n// =============================================================================\n\n/**\n * Feature flags cache TTL in milliseconds (5 minutes)\n *\n * How long to cache flags before fetching fresh values.\n * Matches LaunchDarkly's default streaming connection behavior.\n */\nexport const FLAGS_CACHE_TTL_MS = 5 * 60 * 1000\n\n/**\n * Feature flags stale-while-revalidate window in milliseconds (1 minute)\n *\n * Allow serving stale flags while fetching fresh values.\n */\nexport const FLAGS_STALE_WHILE_REVALIDATE_MS = 60 * 1000\n\n// =============================================================================\n// Retry & Backoff\n// =============================================================================\n\n/** Maximum retry delay for exponential backoff (30 seconds) */\nexport const MAX_RETRY_DELAY_MS = 30_000\n\n/** Base retry delay for exponential backoff (1 second) */\nexport const BASE_RETRY_DELAY_MS = 1_000\n\n/** Maximum number of retries for network requests */\nexport const MAX_RETRIES = 3\n\n// =============================================================================\n// Analytics\n// =============================================================================\n\n/**\n * Analytics session timeout in milliseconds (30 minutes)\n *\n * After this much inactivity, a new session is started.\n */\nexport const ANALYTICS_SESSION_TIMEOUT_MS = 30 * 60 * 1000\n\n// =============================================================================\n// Webhooks\n// =============================================================================\n\n/**\n * Maximum age for webhook signature validation (5 minutes)\n *\n * Reject webhooks with timestamps older than this.\n */\nexport const WEBHOOK_MAX_AGE_MS = 5 * 60 * 1000\n\n/**\n * Clock skew allowance for webhook validation (30 seconds)\n *\n * Allow timestamps this far in the future.\n */\nexport const WEBHOOK_CLOCK_SKEW_MS = 30 * 1000\n\n// =============================================================================\n// PKCE (OAuth)\n// =============================================================================\n\n/**\n * PKCE code verifier TTL in milliseconds (10 minutes)\n *\n * How long the code verifier is stored during OAuth flow.\n */\nexport const PKCE_CODE_TTL_MS = 10 * 60 * 1000\n\n// =============================================================================\n// Jobs\n// =============================================================================\n\n/**\n * Job dead-letter queue retention in milliseconds (7 days)\n */\nexport const JOBS_DLQ_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1000\n\n// =============================================================================\n// Session Replay\n// =============================================================================\n\n/**\n * Maximum session replay recording duration in milliseconds (60 minutes)\n */\nexport const SESSION_REPLAY_MAX_DURATION_MS = 60 * 60 * 1000\n\n/**\n * Session replay upload interval in milliseconds (5 seconds)\n */\nexport const SESSION_REPLAY_UPLOAD_INTERVAL_MS = 5_000\n\n/**\n * Session replay scroll event throttle interval (150 ms)\n */\nexport const SESSION_REPLAY_SCROLL_THROTTLE_MS = 150\n\n/**\n * Session replay media time update throttle interval (800 ms)\n */\nexport const SESSION_REPLAY_MEDIA_THROTTLE_MS = 800\n\n/**\n * Session replay rage click detection window (1 second)\n */\nexport const SESSION_REPLAY_RAGE_CLICK_WINDOW_MS = 1_000\n\n/**\n * Session replay dead click detection timeout (500 ms)\n */\nexport const SESSION_REPLAY_DEAD_CLICK_TIMEOUT_MS = 500\n\n/**\n * Session replay scroll heat detection window (2 seconds)\n */\nexport const SESSION_REPLAY_SCROLL_HEAT_WINDOW_MS = 2_000\n\n/**\n * Session replay status check interval (5 seconds)\n */\nexport const SESSION_REPLAY_STATUS_CHECK_MS = 5_000\n\n// =============================================================================\n// Analytics (Extended)\n// =============================================================================\n\n/**\n * Analytics event flush interval in milliseconds (5 seconds)\n */\nexport const ANALYTICS_FLUSH_INTERVAL_MS = 5_000\n\n/**\n * Analytics maximum text length for autocapture (100 characters)\n */\nexport const ANALYTICS_MAX_TEXT_LENGTH = 100\n\n/**\n * Analytics flush timeout in milliseconds (1 second)\n */\nexport const ANALYTICS_FLUSH_TIMEOUT_MS = 1_000\n\n/**\n * Analytics interval check in milliseconds (1 second)\n */\nexport const ANALYTICS_INTERVAL_CHECK_MS = 1_000\n\n/**\n * Analytics retry base delay in milliseconds (1 second)\n * Exponential backoff: delay = base * 2^retries (with jitter)\n */\nexport const ANALYTICS_RETRY_BASE_DELAY_MS = 1_000\n\n/**\n * Analytics retry max delay in milliseconds (30 seconds)\n */\nexport const ANALYTICS_RETRY_MAX_DELAY_MS = 30_000\n\n/**\n * Analytics retry jitter factor (±20%)\n * Prevents thundering herd when multiple clients retry simultaneously\n */\nexport const ANALYTICS_RETRY_JITTER = 0.2\n\n/**\n * Analytics maximum retries before dropping event (Segment pattern: 10)\n */\nexport const ANALYTICS_MAX_RETRIES = 10\n\n// =============================================================================\n// Feature Flags (Extended)\n// =============================================================================\n\n/**\n * Feature flags exposure deduplication window (1 hour)\n *\n * Prevents duplicate exposure events for A/B tests within this window.\n */\nexport const FLAGS_EXPOSURE_DEDUPE_WINDOW_MS = 60 * 60 * 1000\n\n/**\n * Flag stream initial reconnection delay (1 second)\n */\nexport const FLAGS_STREAM_INITIAL_RECONNECT_MS = 1_000\n\n/**\n * Flag stream maximum reconnection delay (30 seconds)\n */\nexport const FLAGS_STREAM_MAX_RECONNECT_MS = 30_000\n\n/**\n * Flag stream heartbeat timeout (45 seconds)\n */\nexport const FLAGS_STREAM_HEARTBEAT_TIMEOUT_MS = 45_000\n\n/**\n * Flag HTTP polling interval fallback (60 seconds)\n */\nexport const FLAGS_HTTP_POLLING_INTERVAL_MS = 60_000\n\n// =============================================================================\n// Jobs (Extended)\n// =============================================================================\n\n/**\n * Default retry delay sequence for exponential backoff (ms)\n */\nexport const DEFAULT_RETRY_DELAYS_MS = [1_000, 5_000, 15_000, 30_000, 60_000] as const\n\n/**\n * Default job timeout in milliseconds (60 seconds)\n */\nexport const JOB_DEFAULT_TIMEOUT_MS = 60_000\n\n/**\n * Default job status polling interval (2 seconds)\n */\nexport const JOB_POLL_INTERVAL_MS = 2_000\n\n// =============================================================================\n// Storage Keys & Prefixes\n// =============================================================================\n\n/**\n * Storage key prefix for SDK data\n */\nexport const STORAGE_KEY_PREFIX = 'sylphx_'\n\n/**\n * localStorage key for cached feature flags\n */\nexport const FLAGS_CACHE_KEY = 'sylphx_feature_flags'\n\n/**\n * localStorage key for feature flags cache timestamp\n */\nexport const FLAGS_CACHE_TIMESTAMP_KEY = 'sylphx_feature_flags_ts'\n\n/**\n * localStorage key for feature flags overrides\n */\nexport const FLAGS_OVERRIDES_KEY = 'sylphx_feature_flags_overrides'\n\n/**\n * localStorage key for active organization\n */\nexport const ORG_STORAGE_KEY = 'sylphx_active_org'\n\n/**\n * BroadcastChannel name for cross-tab org sync\n */\nexport const ORG_BROADCAST_CHANNEL = 'sylphx_org_sync'\n\n/**\n * Storage prefix for PKCE verifiers\n */\nexport const PKCE_STORAGE_PREFIX = 'sylphx_pkce_'\n\n/**\n * Test key for checking storage availability\n */\nexport const STORAGE_TEST_KEY = '__sylphx_test__'\n\n/**\n * Cookie/storage name for analytics sessions\n */\nexport const ANALYTICS_SESSION_KEY = 'sylphx_session'\n\n/**\n * Default storage key for flags persistence\n */\nexport const FLAGS_STORAGE_KEY = 'sylphx_flags'\n\n// =============================================================================\n// Click ID & Attribution\n// =============================================================================\n\n/**\n * Click ID attribution window in milliseconds (90 days)\n *\n * How long click IDs are stored for conversion attribution.\n */\nexport const CLICK_ID_EXPIRY_MS = 90 * 24 * 60 * 60 * 1000\n\n// =============================================================================\n// React Query Stale Times\n// =============================================================================\n\n/**\n * React Query staleTime for frequently-changing data (1 minute)\n *\n * Use for: real-time metrics, live feeds, active sessions\n */\nexport const STALE_TIME_FREQUENT_MS = 60 * 1_000\n\n/**\n * React Query staleTime for moderately-changing data (2 minutes)\n *\n * Use for: subscriptions, user profiles, preferences\n */\nexport const STALE_TIME_MODERATE_MS = 2 * 60 * 1_000\n\n/**\n * React Query staleTime for stable/config data (5 minutes)\n *\n * Use for: plans, feature flags, app config\n */\nexport const STALE_TIME_STABLE_MS = 5 * 60 * 1_000\n\n/**\n * React Query staleTime for webhook stats (30 seconds)\n */\nexport const STALE_TIME_STATS_MS = 30 * 1_000\n\n// =============================================================================\n// UI Component Timeouts\n// =============================================================================\n\n/**\n * Copy-to-clipboard feedback display duration (2 seconds)\n */\nexport const UI_COPY_FEEDBACK_MS = 2_000\n\n/**\n * Form success message display duration (3 seconds)\n */\nexport const UI_FORM_SUCCESS_MS = 3_000\n\n/**\n * General notification display duration (5 seconds)\n */\nexport const UI_NOTIFICATION_MS = 5_000\n\n/**\n * Prompt auto-show delay (3 seconds)\n */\nexport const UI_PROMPT_DELAY_MS = 3_000\n\n/**\n * Redirect delay after action (3 seconds)\n */\nexport const UI_REDIRECT_DELAY_MS = 3_000\n\n/**\n * Animation out duration (200 ms)\n */\nexport const UI_ANIMATION_OUT_MS = 200\n\n/**\n * Animation in duration (300 ms)\n */\nexport const UI_ANIMATION_IN_MS = 300\n\n// =============================================================================\n// Email & Verification\n// =============================================================================\n\n/**\n * Email resend cooldown tick interval (1 second)\n */\nexport const EMAIL_RESEND_COOLDOWN_TICK_MS = 1_000\n\n/**\n * New user detection threshold (1 minute)\n *\n * Users created within this window are considered \"new\" for signup tracking.\n */\nexport const NEW_USER_THRESHOLD_MS = 60 * 1_000\n\n// =============================================================================\n// Web Vitals Thresholds\n// =============================================================================\n\n/**\n * FCP (First Contentful Paint) \"good\" threshold (1800 ms)\n */\nexport const WEB_VITALS_FCP_GOOD_MS = 1_800\n\n/**\n * FCP (First Contentful Paint) \"poor\" threshold (3000 ms)\n */\nexport const WEB_VITALS_FCP_POOR_MS = 3_000\n\n// =============================================================================\n// Storage Sizes\n// =============================================================================\n\n/**\n * Multipart upload threshold (5 MB)\n *\n * Files larger than this use multipart upload for better reliability.\n */\nexport const STORAGE_MULTIPART_THRESHOLD_BYTES = 5 * 1024 * 1024\n\n/**\n * Default max file size for uploads (5 MB)\n */\nexport const STORAGE_DEFAULT_MAX_SIZE_BYTES = 5 * 1024 * 1024\n\n/**\n * Avatar max file size (2 MB)\n */\nexport const STORAGE_AVATAR_MAX_SIZE_BYTES = 2 * 1024 * 1024\n\n/**\n * Large file max size for file uploads (10 MB)\n */\nexport const STORAGE_LARGE_MAX_SIZE_BYTES = 10 * 1024 * 1024\n\n// =============================================================================\n// Cache TTLs\n// =============================================================================\n\n/**\n * JWK cache TTL (1 hour)\n */\nexport const JWK_CACHE_TTL_MS = 60 * 60 * 1000\n\n// =============================================================================\n// Analytics Event Tracking\n// =============================================================================\n\n/**\n * Max tracked event IDs to keep in memory\n */\nexport const ANALYTICS_MAX_TRACKED_EVENT_IDS = 1000\n\n/**\n * Number of event IDs to keep after cleanup\n */\nexport const ANALYTICS_TRACKED_IDS_KEEP = 500\n\n/**\n * Analytics queue limit before force flush\n */\nexport const ANALYTICS_QUEUE_LIMIT = 100\n\n// =============================================================================\n// Session Replay (Extended)\n// =============================================================================\n\n/**\n * Session replay check interval (1 second)\n */\nexport const SESSION_REPLAY_CHECK_INTERVAL_MS = 1_000\n\n/**\n * Success feedback delay for invite/account actions (1.5 seconds)\n */\nexport const UI_SUCCESS_REDIRECT_MS = 1_500\n\n// =============================================================================\n// String Truncation Limits\n// =============================================================================\n\n/**\n * Max message length for logging (1000 chars)\n */\nexport const LOG_MESSAGE_MAX_LENGTH = 1_000\n\n/**\n * Max DOM snapshot length for debugging (1000 chars)\n */\nexport const DOM_SNAPSHOT_MAX_LENGTH = 1_000\n\n/**\n * Max stack trace length for error tracking (500 chars)\n */\nexport const STACK_TRACE_MAX_LENGTH = 500\n\n/**\n * Google Consent Mode wait for update timeout (500 ms)\n */\nexport const CONSENT_WAIT_FOR_UPDATE_MS = 500\n\n// =============================================================================\n// Time Unit Conversions\n// =============================================================================\n\n/** Milliseconds per minute (60,000) */\nexport const MS_PER_MINUTE = 60_000\n\n/** Milliseconds per hour (3,600,000) */\nexport const MS_PER_HOUR = 3_600_000\n\n/** Milliseconds per day (86,400,000) */\nexport const MS_PER_DAY = 86_400_000\n\n/** Seconds per minute (60) */\nexport const SECONDS_PER_MINUTE = 60\n\n/** Seconds per hour (3,600) */\nexport const SECONDS_PER_HOUR = 3_600\n\n// =============================================================================\n// Z-Index Values\n// =============================================================================\n\n/** Z-index for modal overlays (9999) */\nexport const Z_INDEX_OVERLAY = 9999\n\n/** Z-index for critical overlays like feature gates (99999) */\nexport const Z_INDEX_CRITICAL_OVERLAY = 99999\n\n// =============================================================================\n// API Key Expiry (seconds)\n// =============================================================================\n\n/** API key expiry: 1 day (86,400 seconds) */\nexport const API_KEY_EXPIRY_1_DAY = 86_400\n\n/** API key expiry: 7 days (604,800 seconds) */\nexport const API_KEY_EXPIRY_7_DAYS = 604_800\n\n/** API key expiry: 30 days (2,592,000 seconds) */\nexport const API_KEY_EXPIRY_30_DAYS = 2_592_000\n\n/** API key expiry: 90 days (7,776,000 seconds) */\nexport const API_KEY_EXPIRY_90_DAYS = 7_776_000\n\n/** API key expiry: 1 year (31,536,000 seconds) */\nexport const API_KEY_EXPIRY_1_YEAR = 31_536_000\n\n// =============================================================================\n// Web Vitals Thresholds (Google standards)\n// =============================================================================\n\n/** LCP (Largest Contentful Paint) \"good\" threshold (2500 ms) */\nexport const WEB_VITALS_LCP_GOOD_MS = 2_500\n\n/** LCP (Largest Contentful Paint) \"poor\" threshold (4000 ms) */\nexport const WEB_VITALS_LCP_POOR_MS = 4_000\n\n/** INP (Interaction to Next Paint) \"good\" threshold (200 ms) */\nexport const WEB_VITALS_INP_GOOD_MS = 200\n\n/** INP (Interaction to Next Paint) \"poor\" threshold (500 ms) */\nexport const WEB_VITALS_INP_POOR_MS = 500\n\n/** TTFB (Time to First Byte) \"good\" threshold (800 ms) */\nexport const WEB_VITALS_TTFB_GOOD_MS = 800\n\n/** TTFB (Time to First Byte) \"poor\" threshold (1800 ms) */\nexport const WEB_VITALS_TTFB_POOR_MS = 1_800\n\n// =============================================================================\n// Security\n// =============================================================================\n\n/** Minimum password length (NIST SP 800-63B recommends 12+) */\nexport const MIN_PASSWORD_LENGTH = 12\n\n// =============================================================================\n// AI\n// =============================================================================\n\n/** Default context window for AI models (4096 tokens) */\nexport const DEFAULT_CONTEXT_WINDOW = 4_096\n\n// =============================================================================\n// Circuit Breaker (AWS/Resilience4j pattern)\n// =============================================================================\n\n/**\n * Circuit breaker failure threshold\n *\n * Number of failures in the window before circuit opens.\n */\nexport const CIRCUIT_BREAKER_FAILURE_THRESHOLD = 5\n\n/**\n * Circuit breaker failure window in milliseconds (10 seconds)\n *\n * Time window for counting failures.\n */\nexport const CIRCUIT_BREAKER_WINDOW_MS = 10_000\n\n/**\n * Circuit breaker open duration in milliseconds (30 seconds)\n *\n * How long the circuit stays open before allowing a test request.\n */\nexport const CIRCUIT_BREAKER_OPEN_DURATION_MS = 30_000\n\n// =============================================================================\n// ETag Cache (HTTP conditional requests)\n// =============================================================================\n\n/**\n * Maximum ETag cache entries\n *\n * LRU eviction when exceeded.\n */\nexport const ETAG_CACHE_MAX_ENTRIES = 100\n\n/**\n * ETag cache TTL in milliseconds (5 minutes)\n *\n * How long cached responses are valid.\n */\nexport const ETAG_CACHE_TTL_MS = 5 * 60 * 1000\n","/**\n * API Key Validation — Single Source of Truth\n *\n * OAuth 2.0 standard key validation for Sylphx Platform.\n * ALL key validation, sanitization, and environment detection logic lives here.\n *\n * Principles:\n * 1. Fail fast - Invalid input rejected immediately with clear errors\n * 2. Helpful errors - Tell users exactly what's wrong and how to fix it\n * 3. Development warnings - Warn about issues that would fail in production\n * 4. No silent fixes - Transparency over convenience (but warn + continue)\n * 5. Single Source of Truth - All key logic in one place\n *\n * Key Formats (OAuth 2.0 Standard):\n * - App ID: app_(dev|stg|prod)_[identifier] — Public identifier (like OAuth client_id)\n * - Secret Key: sk_(dev|stg|prod)_[identifier] — Server-side only (like OAuth client_secret)\n *\n * Identifier Types:\n * - Customer apps: 32 hex chars\n * - Platform apps: platform_{app-slug} (e.g., platform_sylphx-console)\n */\n\n// =============================================================================\n// Types\n// =============================================================================\n\n/** Environment type derived from key prefix */\nexport type EnvironmentType = \"development\" | \"staging\" | \"production\";\n\n/** Key type - appId (public) or secret (server) */\nexport type KeyType = \"appId\" | \"secret\";\n\n/** Validation result with clear error information */\nexport interface KeyValidationResult {\n\t/** Whether the key is valid (possibly after sanitization) */\n\tvalid: boolean;\n\t/** The sanitized key to use (only if valid) */\n\tsanitizedKey: string;\n\t/** Detected key type */\n\tkeyType?: KeyType;\n\t/** Detected environment */\n\tenvironment?: EnvironmentType;\n\t/** Error message if invalid */\n\terror?: string;\n\t/** Warning message if key was auto-fixed */\n\twarning?: string;\n\t/** Detected issues for debugging */\n\tissues?: string[];\n}\n\n// =============================================================================\n// Patterns — Strict Format Validation\n// =============================================================================\n\n/**\n * App ID pattern: app_(dev|stg|prod)_[identifier]\n * - Prefix: app_ (application identifier, public)\n * - Environment: dev, stg, or prod (NO typos allowed)\n * - Suffix: alphanumeric with underscores/hyphens (hex for apps, or internal identifiers)\n */\nconst APP_ID_PATTERN = /^app_(dev|stg|prod)_[a-z0-9_-]+$/;\n\n/**\n * Secret key pattern: sk_(dev|stg|prod)_[identifier]\n * - Prefix: sk_ (secret key)\n * - Environment: dev, stg, or prod (NO typos allowed)\n * - Suffix: alphanumeric with underscores/hyphens (hex for apps, or internal identifiers)\n */\nconst SECRET_KEY_PATTERN = /^sk_(dev|stg|prod)_[a-z0-9_-]+$/;\n\n/** Environment prefix to type mapping */\nconst ENV_PREFIX_MAP: Record<string, EnvironmentType> = {\n\tdev: \"development\",\n\tstg: \"staging\",\n\tprod: \"production\",\n};\n\n// =============================================================================\n// Core Validation Functions\n// =============================================================================\n\n/**\n * Detect common issues with a key (whitespace, newlines, etc.)\n */\nfunction detectKeyIssues(key: string): string[] {\n\tconst issues: string[] = [];\n\tif (key !== key.trim()) issues.push(\"whitespace\");\n\tif (key.includes(\"\\n\")) issues.push(\"newline\");\n\tif (key.includes(\"\\r\")) issues.push(\"carriage-return\");\n\tif (key.includes(\" \")) issues.push(\"space\");\n\tif (key !== key.toLowerCase()) issues.push(\"uppercase-chars\");\n\treturn issues;\n}\n\n/**\n * Create a helpful warning message for keys that needed sanitization\n */\nfunction createSanitizationWarning(\n\tkeyType: KeyType,\n\tissues: string[],\n\tenvVarName: string,\n): string {\n\tconst keyTypeName = keyType === \"appId\" ? \"App ID\" : \"Secret Key\";\n\treturn (\n\t\t`[Sylphx] ${keyTypeName} contains ${issues.join(\", \")}. ` +\n\t\t`This is commonly caused by Vercel CLI's 'env pull' command.\\n\\n` +\n\t\t`To fix permanently:\\n` +\n\t\t`1. Go to Vercel Dashboard → Your Project → Settings → Environment Variables\\n` +\n\t\t`2. Edit ${envVarName}\\n` +\n\t\t`3. Remove any trailing whitespace or newline characters\\n` +\n\t\t`4. Redeploy your application\\n\\n` +\n\t\t`The SDK will automatically sanitize the key, but fixing the source is recommended.`\n\t);\n}\n\n/**\n * Create a helpful error message for invalid keys\n */\nfunction createInvalidKeyError(\n\tkeyType: KeyType,\n\tkey: string,\n\tenvVarName: string,\n): string {\n\tconst prefix = keyType === \"appId\" ? \"app\" : \"sk\";\n\tconst maskedKey = key.length > 20 ? `${key.slice(0, 20)}...` : key;\n\tconst formatHint = `${prefix}_(dev|stg|prod)_[identifier]`;\n\tconst keyTypeName = keyType === \"appId\" ? \"App ID\" : \"Secret Key\";\n\n\treturn (\n\t\t`[Sylphx] Invalid ${keyTypeName} format.\\n\\n` +\n\t\t`Expected format: ${formatHint}\\n` +\n\t\t`Received: \"${maskedKey}\"\\n\\n` +\n\t\t`Please check your ${envVarName} environment variable.\\n` +\n\t\t`You can find your keys in the Sylphx Console → API Keys.\\n\\n` +\n\t\t`Common issues:\\n` +\n\t\t`• Key has uppercase characters (must be lowercase)\\n` +\n\t\t`• Key has wrong prefix (App ID: app_, Secret Key: sk_)\\n` +\n\t\t`• Key has invalid environment (must be dev, stg, or prod)\\n` +\n\t\t`• Key was copied with extra whitespace`\n\t);\n}\n\n/**\n * Extract environment from a validated key\n */\nfunction extractEnvironment(key: string): EnvironmentType | undefined {\n\t// Match app_ or sk_ prefix followed by environment\n\tconst match = key.match(/^(?:app|sk)_(dev|stg|prod)_/);\n\tif (!match) return undefined;\n\treturn ENV_PREFIX_MAP[match[1]];\n}\n\n/**\n * Internal: Generic key validation logic for specific key types\n */\nfunction validateKeyForType(\n\tkey: string | undefined | null,\n\tkeyType: KeyType,\n\tpattern: RegExp,\n\tenvVarName: string,\n): KeyValidationResult {\n\tconst keyTypeName = keyType === \"appId\" ? \"App ID\" : \"Secret Key\";\n\n\t// Check if key is provided\n\tif (!key) {\n\t\treturn {\n\t\t\tvalid: false,\n\t\t\tsanitizedKey: \"\",\n\t\t\terror:\n\t\t\t\t`[Sylphx] ${keyTypeName} is required. ` +\n\t\t\t\t`Set ${envVarName} in your environment variables.`,\n\t\t\tissues: [\"missing\"],\n\t\t};\n\t}\n\n\t// Detect issues before validation\n\tconst issues = detectKeyIssues(key);\n\n\t// Check if key matches expected format exactly\n\tif (pattern.test(key)) {\n\t\treturn {\n\t\t\tvalid: true,\n\t\t\tsanitizedKey: key,\n\t\t\tkeyType,\n\t\t\tenvironment: extractEnvironment(key),\n\t\t\tissues: [],\n\t\t};\n\t}\n\n\t// Key doesn't match - try sanitization (trim + lowercase)\n\tconst sanitized = key.trim().toLowerCase();\n\n\tif (pattern.test(sanitized)) {\n\t\t// Sanitization fixes the issue\n\t\treturn {\n\t\t\tvalid: true,\n\t\t\tsanitizedKey: sanitized,\n\t\t\tkeyType,\n\t\t\tenvironment: extractEnvironment(sanitized),\n\t\t\twarning: createSanitizationWarning(keyType, issues, envVarName),\n\t\t\tissues,\n\t\t};\n\t}\n\n\t// Sanitization doesn't fix it - key format is genuinely wrong\n\treturn {\n\t\tvalid: false,\n\t\tsanitizedKey: \"\",\n\t\terror: createInvalidKeyError(keyType, key, envVarName),\n\t\tissues: [...issues, \"invalid-format\"],\n\t};\n}\n\n// =============================================================================\n// Public API — App ID (formerly Publishable Key)\n// =============================================================================\n\n/**\n * Validate an App ID and return detailed results\n *\n * @example\n * ```typescript\n * const result = validateAppId(process.env.NEXT_PUBLIC_SYLPHX_APP_ID)\n * if (!result.valid) {\n * throw new Error(result.error)\n * }\n * if (result.warning) {\n * console.warn(result.warning)\n * }\n * ```\n */\nexport function validateAppId(\n\tkey: string | undefined | null,\n): KeyValidationResult {\n\treturn validateKeyForType(\n\t\tkey,\n\t\t\"appId\",\n\t\tAPP_ID_PATTERN,\n\t\t\"NEXT_PUBLIC_SYLPHX_APP_ID\",\n\t);\n}\n\n/**\n * Validate and sanitize App ID, logging warnings\n *\n * @throws Error if the key is invalid and cannot be sanitized\n * @returns The sanitized App ID\n */\nexport function validateAndSanitizeAppId(\n\tkey: string | undefined | null,\n): string {\n\tconst result = validateAppId(key);\n\n\tif (!result.valid) {\n\t\tthrow new Error(result.error);\n\t}\n\n\tif (result.warning) {\n\t\tconsole.warn(result.warning);\n\t}\n\n\treturn result.sanitizedKey;\n}\n\n// =============================================================================\n// Public API — Secret Keys\n// =============================================================================\n\n/**\n * Validate a secret key and return detailed results\n *\n * @example\n * ```typescript\n * const result = validateSecretKey(process.env.SYLPHX_SECRET_KEY)\n * if (!result.valid) {\n * throw new Error(result.error)\n * }\n * ```\n */\nexport function validateSecretKey(\n\tkey: string | undefined | null,\n): KeyValidationResult {\n\treturn validateKeyForType(\n\t\tkey,\n\t\t\"secret\",\n\t\tSECRET_KEY_PATTERN,\n\t\t\"SYLPHX_SECRET_KEY\",\n\t);\n}\n\n/**\n * Validate and sanitize secret key, logging warnings\n *\n * @throws Error if the key is invalid and cannot be sanitized\n * @returns The sanitized secret key\n */\nexport function validateAndSanitizeSecretKey(\n\tkey: string | undefined | null,\n): string {\n\tconst result = validateSecretKey(key);\n\n\tif (!result.valid) {\n\t\tthrow new Error(result.error);\n\t}\n\n\tif (result.warning) {\n\t\tconsole.warn(result.warning);\n\t}\n\n\treturn result.sanitizedKey;\n}\n\n// =============================================================================\n// Public API — Environment Detection (SSOT)\n// =============================================================================\n\n/**\n * Detect environment type from any key (App ID or Secret Key)\n *\n * @example\n * ```typescript\n * detectEnvironment('sk_dev_abc123') // 'development'\n * detectEnvironment('app_prod_xyz789') // 'production'\n * detectEnvironment('sk_stg_qwe456') // 'staging'\n * ```\n *\n * @throws Error if key format is invalid\n */\nexport function detectEnvironment(key: string): EnvironmentType {\n\t// Validate and sanitize first\n\tconst sanitized = key.trim().toLowerCase();\n\n\t// Check both key types\n\tif (sanitized.startsWith(\"sk_\")) {\n\t\tconst result = validateSecretKey(sanitized);\n\t\tif (!result.valid) {\n\t\t\tthrow new Error(result.error);\n\t\t}\n\t\treturn result.environment!;\n\t}\n\n\tif (sanitized.startsWith(\"app_\")) {\n\t\tconst result = validateAppId(sanitized);\n\t\tif (!result.valid) {\n\t\t\tthrow new Error(result.error);\n\t\t}\n\t\treturn result.environment!;\n\t}\n\n\tthrow new Error(\n\t\t`[Sylphx] Invalid key format. Key must start with 'sk_' (secret) or 'app_' (App ID).`,\n\t);\n}\n\n/**\n * Check if running in development environment based on key\n */\nexport function isDevelopmentKey(key: string): boolean {\n\treturn detectEnvironment(key) === \"development\";\n}\n\n/**\n * Check if running in production environment based on key\n */\nexport function isProductionKey(key: string): boolean {\n\treturn detectEnvironment(key) === \"production\";\n}\n\n// =============================================================================\n// Public API — Cookie Namespace (SSOT)\n// =============================================================================\n\n/**\n * Get the cookie namespace for a given secret key\n *\n * Used by auth middleware to namespace cookies per environment.\n * This prevents dev/staging/prod cookies from conflicting.\n *\n * @example\n * ```typescript\n * getCookieNamespace('sk_dev_abc123') // 'sylphx_dev'\n * getCookieNamespace('sk_prod_xyz789') // 'sylphx_prod'\n * ```\n */\nexport function getCookieNamespace(secretKey: string): string {\n\tconst env = detectEnvironment(secretKey);\n\tconst shortEnv =\n\t\tenv === \"development\" ? \"dev\" : env === \"staging\" ? \"stg\" : \"prod\";\n\treturn `sylphx_${shortEnv}`;\n}\n\n// =============================================================================\n// Public API — Key Type Detection\n// =============================================================================\n\n/**\n * Detect the type of key (App ID or Secret Key)\n *\n * @returns 'appId', 'secret', or null if unknown\n */\nexport function detectKeyType(key: string): KeyType | null {\n\tconst sanitized = key.trim().toLowerCase();\n\tif (sanitized.startsWith(\"app_\")) return \"appId\";\n\tif (sanitized.startsWith(\"sk_\")) return \"secret\";\n\treturn null;\n}\n\n/**\n * Check if a key is an App ID\n */\nexport function isAppId(key: string): boolean {\n\treturn detectKeyType(key) === \"appId\";\n}\n\n/**\n * Check if a key is a secret key\n */\nexport function isSecretKey(key: string): boolean {\n\treturn detectKeyType(key) === \"secret\";\n}\n\n/**\n * Validate any key (auto-detects type)\n *\n * Use this when you accept either App ID or Secret Key.\n * The function auto-detects the key type and validates accordingly.\n *\n * @example\n * ```typescript\n * const result = validateKey(process.env.SYLPHX_SECRET_KEY)\n * if (!result.valid) {\n * throw new Error(result.error)\n * }\n * const sanitizedKey = result.sanitizedKey\n * ```\n */\nexport function validateKey(\n\tkey: string | undefined | null,\n): KeyValidationResult {\n\tconst keyType = key ? detectKeyType(key) : null;\n\n\tif (keyType === \"appId\") {\n\t\treturn validateAppId(key);\n\t}\n\tif (keyType === \"secret\") {\n\t\treturn validateSecretKey(key);\n\t}\n\n\t// Unknown key type - return detailed error\n\treturn {\n\t\tvalid: false,\n\t\tsanitizedKey: \"\",\n\t\terror: key\n\t\t\t? `Invalid key format. Keys must start with 'app_' (App ID) or 'sk_' (Secret Key), followed by environment (dev/stg/prod) and identifier. Got: ${key.slice(0, 20)}...`\n\t\t\t: \"API key is required but was not provided.\",\n\t\tissues: key ? [\"invalid_format\"] : [\"missing\"],\n\t};\n}\n\n/**\n * Validate any key and return sanitized version (throws on error)\n *\n * Use this when you need the key value and want to throw on invalid input.\n */\nexport function validateAndSanitizeKey(key: string | undefined | null): string {\n\tconst result = validateKey(key);\n\tif (!result.valid) {\n\t\tthrow new Error(result.error);\n\t}\n\tif (result.warning) {\n\t\tconsole.warn(`[Sylphx] ${result.warning}`);\n\t}\n\treturn result.sanitizedKey;\n}\n\n// =============================================================================\n// Public API — Runtime Environment Detection\n// =============================================================================\n\n/**\n * Check if we're in development mode (based on NODE_ENV or hostname)\n */\nexport function isDevelopmentRuntime(): boolean {\n\tif (typeof process !== \"undefined\" && process.env) {\n\t\treturn process.env.NODE_ENV === \"development\";\n\t}\n\tif (typeof window !== \"undefined\") {\n\t\treturn (\n\t\t\twindow.location.hostname === \"localhost\" ||\n\t\t\twindow.location.hostname === \"127.0.0.1\"\n\t\t);\n\t}\n\treturn false;\n}\n","/**\n * Cookie Management for Next.js — Single Source of Truth\n *\n * Architecture: Cookie-Centric Auth (Clerk Pattern)\n * ================================================\n *\n * ALL auth state lives in cookies. Zero localStorage for auth.\n *\n * Cookie Structure:\n * - __sylphx_{namespace}_session — HttpOnly JWT, 5 min (access token)\n * - __sylphx_{namespace}_refresh — HttpOnly, 30 days (refresh token)\n * - __sylphx_{namespace}_user — JS-readable, 5 min (user data for client hydration)\n *\n * Benefits:\n * 1. Single Source of Truth — no server/client state divergence\n * 2. XSS-safe — tokens never accessible to JavaScript\n * 3. Cross-tab sync — cookies shared across tabs automatically\n * 4. SSR works — auth() in Server Components reads cookies directly\n *\n * Security:\n * - Short token lifetime (5 min) like Clerk\n * - Server-side refresh in middleware\n * - SameSite=Lax for CSRF protection\n */\n\nimport { cookies } from \"next/headers\";\nimport {\n\tREFRESH_TOKEN_LIFETIME_SECONDS,\n\tSESSION_TOKEN_LIFETIME_SECONDS,\n\tTOKEN_EXPIRY_BUFFER_MS,\n} from \"../constants\";\nimport type { TokenResponse, User, UserCookieData } from \"../types\";\n\n// Re-export UserCookieData for consumers of this module\nexport type { UserCookieData };\n\n// =============================================================================\n// Cookie Name Generator\n// =============================================================================\n\n/**\n * Get cookie names for a given namespace\n *\n * Namespace is derived from the secret key environment (dev/stg/prod).\n * This prevents cookies from different environments colliding.\n *\n * @example\n * getCookieNames('sylphx_prod')\n * // Returns:\n * // {\n * // SESSION: '__sylphx_prod_session',\n * // REFRESH: '__sylphx_prod_refresh',\n * // USER: '__sylphx_prod_user',\n * // }\n */\nexport function getCookieNames(namespace: string) {\n\treturn {\n\t\t/** HttpOnly JWT access token (5 min) */\n\t\tSESSION: `__${namespace}_session`,\n\t\t/** HttpOnly refresh token (30 days) */\n\t\tREFRESH: `__${namespace}_refresh`,\n\t\t/** JS-readable user data for client hydration (5 min) */\n\t\tUSER: `__${namespace}_user`,\n\t};\n}\n\n// =============================================================================\n// Cookie Options\n// =============================================================================\n\n/**\n * Session token lifetime (5 minutes like Clerk)\n */\nexport const SESSION_TOKEN_LIFETIME = SESSION_TOKEN_LIFETIME_SECONDS;\n\n/**\n * Refresh token lifetime (30 days)\n */\nexport const REFRESH_TOKEN_LIFETIME = REFRESH_TOKEN_LIFETIME_SECONDS;\n\n/**\n * Cookie options for HttpOnly tokens (session, refresh)\n *\n * Security features:\n * - httpOnly: true — Not accessible via JavaScript (XSS protection)\n * - secure: true in production — Only sent over HTTPS\n * - sameSite: 'lax' — CSRF protection while allowing navigation\n */\nexport const SECURE_COOKIE_OPTIONS = {\n\thttpOnly: true,\n\tsecure: process.env.NODE_ENV === \"production\",\n\tsameSite: \"lax\" as const,\n\tpath: \"/\",\n};\n\n/**\n * Cookie options for JS-readable user cookie\n *\n * This cookie contains only user info (no tokens) and enables:\n * - Client-side hydration without loading states\n * - Cross-tab sync via cookie visibility\n */\nexport const USER_COOKIE_OPTIONS = {\n\thttpOnly: false, // Readable by client JS for hydration\n\tsecure: process.env.NODE_ENV === \"production\",\n\tsameSite: \"lax\" as const,\n\tpath: \"/\",\n};\n\n// =============================================================================\n// Types\n// =============================================================================\n\n/**\n * Auth cookies data returned by getAuthCookies\n */\nexport interface AuthCookiesData {\n\t/** Access token from SESSION cookie (HttpOnly) */\n\tsessionToken: string | null;\n\t/** Refresh token from REFRESH cookie (HttpOnly) */\n\trefreshToken: string | null;\n\t/** User data from USER cookie (JS-readable) */\n\tuser: User | null;\n\t/** Expiry timestamp from USER cookie */\n\texpiresAt: number | null;\n}\n\n// =============================================================================\n// Cookie Operations\n// =============================================================================\n\n/**\n * Get auth cookies from the request\n *\n * Used by auth() to read current auth state.\n */\nexport async function getAuthCookies(\n\tnamespace: string,\n): Promise<AuthCookiesData> {\n\tconst cookieStore = await cookies();\n\tconst names = getCookieNames(namespace);\n\n\tconst sessionToken = cookieStore.get(names.SESSION)?.value || null;\n\tconst refreshToken = cookieStore.get(names.REFRESH)?.value || null;\n\tconst userCookieValue = cookieStore.get(names.USER)?.value || null;\n\n\tlet user: User | null = null;\n\tlet expiresAt: number | null = null;\n\n\tif (userCookieValue) {\n\t\ttry {\n\t\t\tconst parsed: UserCookieData = JSON.parse(userCookieValue);\n\t\t\tuser = parsed.user;\n\t\t\texpiresAt = parsed.expiresAt;\n\t\t} catch {\n\t\t\t// Invalid JSON, treat as no user\n\t\t\tuser = null;\n\t\t\texpiresAt = null;\n\t\t}\n\t}\n\n\treturn { sessionToken, refreshToken, user, expiresAt };\n}\n\n/**\n * Set auth cookies from token response\n *\n * Sets all three cookies:\n * - SESSION: HttpOnly access token (5 min)\n * - REFRESH: HttpOnly refresh token (30 days)\n * - USER: JS-readable user data (5 min)\n *\n * @param namespace - Cookie namespace (e.g., 'sylphx_prod')\n * @param response - Token response from auth endpoint\n * @param options - Optional: custom expiresIn override\n */\nexport async function setAuthCookies(\n\tnamespace: string,\n\tresponse: TokenResponse,\n\toptions?: { sessionLifetime?: number },\n): Promise<void> {\n\tconst cookieStore = await cookies();\n\tconst names = getCookieNames(namespace);\n\n\t// Use custom session lifetime or default (5 min)\n\tconst sessionLifetime = options?.sessionLifetime ?? SESSION_TOKEN_LIFETIME;\n\tconst expiresAt = Date.now() + sessionLifetime * 1000;\n\n\t// SESSION cookie - HttpOnly access token\n\tcookieStore.set(names.SESSION, response.accessToken, {\n\t\t...SECURE_COOKIE_OPTIONS,\n\t\tmaxAge: sessionLifetime,\n\t});\n\n\t// REFRESH cookie - HttpOnly refresh token (30 days)\n\tcookieStore.set(names.REFRESH, response.refreshToken, {\n\t\t...SECURE_COOKIE_OPTIONS,\n\t\tmaxAge: REFRESH_TOKEN_LIFETIME,\n\t});\n\n\t// USER cookie - JS-readable for client hydration\n\tconst userData: UserCookieData = {\n\t\tuser: response.user,\n\t\texpiresAt,\n\t};\n\tcookieStore.set(names.USER, JSON.stringify(userData), {\n\t\t...USER_COOKIE_OPTIONS,\n\t\tmaxAge: sessionLifetime,\n\t});\n}\n\n/**\n * Clear all auth cookies\n *\n * Call on sign out to remove all auth state.\n */\nexport async function clearAuthCookies(namespace: string): Promise<void> {\n\tconst cookieStore = await cookies();\n\tconst names = getCookieNames(namespace);\n\n\tcookieStore.delete(names.SESSION);\n\tcookieStore.delete(names.REFRESH);\n\tcookieStore.delete(names.USER);\n}\n\n/**\n * Check if session is expired\n *\n * Uses a 30 second buffer to account for network latency.\n */\nexport async function isSessionExpired(namespace: string): Promise<boolean> {\n\tconst { expiresAt } = await getAuthCookies(namespace);\n\tif (!expiresAt) return true;\n\t// 30 second buffer\n\treturn expiresAt < Date.now() + TOKEN_EXPIRY_BUFFER_MS;\n}\n\n/**\n * Check if we have a refresh token (can potentially refresh)\n */\nexport async function hasRefreshToken(namespace: string): Promise<boolean> {\n\tconst { refreshToken } = await getAuthCookies(namespace);\n\treturn !!refreshToken;\n}\n\n// =============================================================================\n// Middleware Cookie Helpers (for NextResponse)\n// =============================================================================\n// Middleware uses NextResponse.cookies, not next/headers cookies()\n\nimport type { NextResponse } from \"next/server\";\n\n/**\n * Set auth cookies on a NextResponse (for middleware use)\n *\n * Unlike setAuthCookies() which uses next/headers, this works with NextResponse.\n * Use this in middleware where you need to modify cookies on the response.\n */\nexport function setAuthCookiesMiddleware(\n\tresponse: NextResponse,\n\tnamespace: string,\n\ttokens: TokenResponse,\n): void {\n\tconst names = getCookieNames(namespace);\n\tconst expiresAt = Date.now() + SESSION_TOKEN_LIFETIME * 1000;\n\n\t// SESSION cookie - HttpOnly access token\n\tresponse.cookies.set(names.SESSION, tokens.accessToken, {\n\t\t...SECURE_COOKIE_OPTIONS,\n\t\tmaxAge: SESSION_TOKEN_LIFETIME,\n\t});\n\n\t// REFRESH cookie - HttpOnly refresh token\n\tresponse.cookies.set(names.REFRESH, tokens.refreshToken, {\n\t\t...SECURE_COOKIE_OPTIONS,\n\t\tmaxAge: REFRESH_TOKEN_LIFETIME,\n\t});\n\n\t// USER cookie - JS-readable for client hydration\n\tconst userData: UserCookieData = {\n\t\tuser: tokens.user,\n\t\texpiresAt,\n\t};\n\tresponse.cookies.set(names.USER, JSON.stringify(userData), {\n\t\t...USER_COOKIE_OPTIONS,\n\t\tmaxAge: SESSION_TOKEN_LIFETIME,\n\t});\n}\n\n/**\n * Clear auth cookies on a NextResponse (for middleware use)\n */\nexport function clearAuthCookiesMiddleware(\n\tresponse: NextResponse,\n\tnamespace: string,\n): void {\n\tconst names = getCookieNames(namespace);\n\tresponse.cookies.delete(names.SESSION);\n\tresponse.cookies.delete(names.REFRESH);\n\tresponse.cookies.delete(names.USER);\n}\n\n/**\n * Parse user cookie value (for client-side use)\n */\nexport function parseUserCookie(value: string): UserCookieData | null {\n\ttry {\n\t\treturn JSON.parse(value) as UserCookieData;\n\t} catch {\n\t\treturn null;\n\t}\n}\n","/**\n * Server-side Auth Helpers for Next.js\n *\n * Use in Server Components and API Routes.\n *\n * Architecture: Cookie-Centric Single Source of Truth\n * ===================================================\n *\n * All auth state lives in cookies. The auth() function reads\n * from HttpOnly cookies and refreshes if needed.\n *\n * Cookie Structure:\n * - __sylphx_{namespace}_session — HttpOnly JWT (5 min)\n * - __sylphx_{namespace}_refresh — HttpOnly refresh token (30 days)\n * - __sylphx_{namespace}_user — JS-readable user data (5 min)\n */\n\nimport { cache } from 'react'\nimport { DEFAULT_PLATFORM_URL, TOKEN_EXPIRY_BUFFER_MS } from '../constants'\nimport {\n\tgetCookieNamespace as getCookieNamespaceFromKey,\n\tvalidateAndSanitizeAppId,\n\tvalidateAndSanitizeSecretKey,\n} from '../key-validation'\nimport { verifyAccessToken } from '../server'\nimport type { TokenResponse, User } from '../types'\nimport { clearAuthCookies, getAuthCookies, setAuthCookies } from './cookies'\n\n// =============================================================================\n// Type Guards\n// =============================================================================\n\n/** Type guard for token response */\nfunction isTokenResponse(data: unknown): data is TokenResponse {\n\treturn (\n\t\ttypeof data === 'object' &&\n\t\tdata !== null &&\n\t\t'accessToken' in data &&\n\t\t'refreshToken' in data &&\n\t\t'user' in data &&\n\t\ttypeof (data as TokenResponse).accessToken === 'string' &&\n\t\ttypeof (data as TokenResponse).refreshToken === 'string'\n\t)\n}\n\n// =============================================================================\n// Configuration\n// =============================================================================\n\n// Configuration for server helpers (auto-configured from env vars)\nlet serverConfig: { secretKey: string; platformUrl: string } | null = null\n\n/**\n * Configure the SDK for server-side usage\n *\n * NOTE: This is optional! The SDK auto-configures from environment variables:\n * - SYLPHX_SECRET_KEY (required)\n * - SYLPHX_PLATFORM_URL (optional, defaults to https://sylphx.com)\n *\n * Use this only if you need to override the default configuration.\n *\n * @example\n * ```ts\n * // Optional: Override default configuration\n * import { configureServer } from '@sylphx/sdk/nextjs'\n *\n * configureServer({\n * secretKey: process.env.SYLPHX_SECRET_KEY!,\n * platformUrl: 'https://custom.sylphx.com',\n * })\n * ```\n */\nexport function configureServer(config: { secretKey: string; platformUrl?: string }) {\n\t// Validate and sanitize secret key using SSOT\n\tconst secretKey = validateAndSanitizeSecretKey(config.secretKey)\n\tserverConfig = {\n\t\tsecretKey,\n\t\tplatformUrl: (config.platformUrl || DEFAULT_PLATFORM_URL).trim(),\n\t}\n}\n\n/**\n * Get server configuration\n *\n * Auto-configures from environment variables if not explicitly configured.\n * This follows the Clerk/Auth0 pattern where SDK auto-initializes from env vars.\n */\nfunction getConfig(): { secretKey: string; platformUrl: string } | null {\n\t// Return cached config if already set\n\tif (serverConfig) {\n\t\treturn serverConfig\n\t}\n\n\t// Auto-configure from environment variables (Clerk/Auth0 pattern)\n\tconst rawSecretKey = process.env.SYLPHX_SECRET_KEY\n\tif (!rawSecretKey) {\n\t\t// No secret key configured - cannot authenticate\n\t\t// This is expected for public pages that don't need auth\n\t\treturn null\n\t}\n\n\ttry {\n\t\tconst secretKey = validateAndSanitizeSecretKey(rawSecretKey)\n\t\tconst platformUrl = (process.env.SYLPHX_PLATFORM_URL || DEFAULT_PLATFORM_URL).trim()\n\n\t\t// Cache the auto-configured settings\n\t\tserverConfig = { secretKey, platformUrl }\n\t\treturn serverConfig\n\t} catch (error) {\n\t\t// Invalid secret key format - log warning and return null\n\t\tconsole.warn('[Sylphx] Invalid SYLPHX_SECRET_KEY format:', error)\n\t\treturn null\n\t}\n}\n\n/**\n * Derive a stable cookie namespace from the secret key prefix.\n * Uses the SSOT getCookieNamespace function from key-validation.\n */\nfunction getCookieNamespace(): string {\n\tconst config = getConfig()\n\tif (!config) return 'sylphx'\n\treturn getCookieNamespaceFromKey(config.secretKey)\n}\n\n// =============================================================================\n// Auth Types\n// =============================================================================\n\n/**\n * Auth state returned by auth()\n */\nexport interface AuthResult {\n\tuserId: string | null\n\tuser: User | null\n\t/** Session token (for internal use only - not exposed to client) */\n\tsessionToken: string | null\n}\n\n// =============================================================================\n// Core Auth Function\n// =============================================================================\n\n/**\n * Get the current auth state (memoized per request)\n *\n * This is the primary way to check authentication in Server Components.\n * It reads from HttpOnly cookies and refreshes if needed.\n *\n * @example\n * ```ts\n * // In a Server Component\n * import { auth } from '@sylphx/platform-sdk/nextjs'\n *\n * export default async function Dashboard() {\n * const { userId, user } = await auth()\n *\n * if (!userId) {\n * redirect('/login')\n * }\n *\n * return <div>Hello, {user?.name}</div>\n * }\n * ```\n */\nexport const auth = cache(async (): Promise<AuthResult> => {\n\tconst config = getConfig()\n\n\t// SDK not configured - return unauthenticated state\n\tif (!config) {\n\t\treturn { userId: null, user: null, sessionToken: null }\n\t}\n\n\tconst namespace = getCookieNamespace()\n\tconst { sessionToken, refreshToken, user, expiresAt } = await getAuthCookies(namespace)\n\n\t// No tokens at all\n\tif (!sessionToken && !refreshToken) {\n\t\treturn { userId: null, user: null, sessionToken: null }\n\t}\n\n\t// Session token exists and not expired (with 30 second buffer)\n\tif (sessionToken && expiresAt && expiresAt > Date.now() + TOKEN_EXPIRY_BUFFER_MS) {\n\t\t// Verify token is valid\n\t\ttry {\n\t\t\tconst payload = await verifyAccessToken(sessionToken, config)\n\t\t\treturn {\n\t\t\t\tuserId: payload.sub,\n\t\t\t\tuser: user || {\n\t\t\t\t\tid: payload.sub,\n\t\t\t\t\temail: payload.email,\n\t\t\t\t\tname: payload.name || null,\n\t\t\t\t\timage: payload.picture || null,\n\t\t\t\t\temailVerified: payload.email_verified,\n\t\t\t\t},\n\t\t\t\tsessionToken,\n\t\t\t}\n\t\t} catch {\n\t\t\t// Token verification failed - treat as expired\n\t\t}\n\t}\n\n\t// Session expired but have refresh token + user data from cookie\n\t// NOTE: We don't refresh here because cookies can only be modified in Route Handlers.\n\t// The middleware handles token refresh. If we get here during SSR with expired session\n\t// but valid user cookie, we trust the user cookie (it was set when tokens were valid).\n\tif (refreshToken && user && expiresAt) {\n\t\t// User cookie hasn't expired yet (same lifetime as session)\n\t\tif (expiresAt > Date.now()) {\n\t\t\treturn {\n\t\t\t\tuserId: user.id,\n\t\t\t\tuser,\n\t\t\t\tsessionToken: sessionToken || null, // May be expired, but user data is valid\n\t\t\t}\n\t\t}\n\t}\n\n\t// No valid session - return unauthenticated\n\t// NOTE: We don't clear cookies here because cookies can only be modified in Route Handlers.\n\t// The middleware will clear invalid cookies on next request.\n\treturn { userId: null, user: null, sessionToken: null }\n})\n\n// =============================================================================\n// Convenience Functions\n// =============================================================================\n\n/**\n * Get the current user (null if not logged in)\n *\n * @example\n * ```ts\n * import { currentUser } from '@sylphx/platform-sdk/nextjs'\n *\n * export default async function Header() {\n * const user = await currentUser()\n * if (!user) return <SignIn />\n * return <span>Hello, {user.name}</span>\n * }\n * ```\n */\nexport async function currentUser(): Promise<User | null> {\n\tconst { user } = await auth()\n\treturn user\n}\n\n/**\n * Get the current user ID (null if not logged in)\n */\nexport async function currentUserId(): Promise<string | null> {\n\tconst { userId } = await auth()\n\treturn userId\n}\n\n// =============================================================================\n// OAuth Callback Handler\n// =============================================================================\n\n/**\n * Handle OAuth callback - exchange code for tokens and set cookies\n *\n * NOTE: With createSylphxMiddleware(), this is handled automatically.\n * You don't need to create manual /api/auth/* routes.\n *\n * This function is exported for advanced use cases where you need\n * custom callback handling outside of the middleware flow.\n *\n * @example\n * ```ts\n * // Using middleware (recommended - zero manual routes)\n * import { createSylphxMiddleware } from '@sylphx/sdk/nextjs'\n * export default createSylphxMiddleware({ publicRoutes: ['/', '/about'] })\n *\n * // Middleware automatically handles /auth/callback\n * ```\n */\nexport async function handleCallback(code: string): Promise<User> {\n\tconst config = getConfig()\n\tif (!config) {\n\t\tthrow new Error('Sylphx SDK not configured. Set SYLPHX_SECRET_KEY environment variable.')\n\t}\n\n\tconst response = await fetch(`${config.platformUrl}/api/v1/auth/token`, {\n\t\tmethod: 'POST',\n\t\theaders: { 'Content-Type': 'application/json' },\n\t\tbody: JSON.stringify({\n\t\t\tgrant_type: 'authorization_code',\n\t\t\tcode,\n\t\t\tclient_secret: config.secretKey,\n\t\t}),\n\t})\n\n\tif (!response.ok) {\n\t\tconst errorData = (await response.json().catch(() => ({ error: 'Token exchange failed' }))) as {\n\t\t\terror?: string\n\t\t}\n\t\tthrow new Error(errorData.error || 'Token exchange failed')\n\t}\n\n\tconst data: unknown = await response.json()\n\tif (!isTokenResponse(data)) {\n\t\tthrow new Error('Invalid token response format')\n\t}\n\n\tconst namespace = getCookieNamespace()\n\tawait setAuthCookies(namespace, data)\n\n\treturn data.user\n}\n\n// =============================================================================\n// Sign Out\n// =============================================================================\n\n/**\n * Sign out - clear cookies and optionally revoke token\n *\n * NOTE: With createSylphxMiddleware(), signout is handled automatically\n * at /auth/signout. No manual route needed.\n *\n * This function is exported for advanced use cases.\n *\n * @example\n * ```ts\n * // Using middleware (recommended)\n * // Navigate users to /auth/signout - middleware handles everything\n * <a href=\"/auth/signout\">Sign Out</a>\n * ```\n */\nexport async function signOut(): Promise<void> {\n\tconst config = getConfig()\n\n\t// SDK not configured - nothing to sign out from\n\tif (!config) {\n\t\treturn\n\t}\n\n\tconst namespace = getCookieNamespace()\n\tconst { refreshToken } = await getAuthCookies(namespace)\n\n\t// Revoke token on platform\n\tif (refreshToken) {\n\t\ttry {\n\t\t\tawait fetch(`${config.platformUrl}/api/v1/auth/revoke`, {\n\t\t\t\tmethod: 'POST',\n\t\t\t\theaders: { 'Content-Type': 'application/json' },\n\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\ttoken: refreshToken,\n\t\t\t\t\tclient_secret: config.secretKey,\n\t\t\t\t}),\n\t\t\t})\n\t\t} catch {\n\t\t\t// Ignore revocation errors\n\t\t}\n\t}\n\n\t// Clear all auth cookies\n\tawait clearAuthCookies(namespace)\n}\n\n// =============================================================================\n// Token Sync (Server Action)\n// =============================================================================\n\n/**\n * Sync tokens to cookies (server action)\n *\n * NOTE: With createSylphxMiddleware(), OAuth callbacks are handled\n * automatically at /auth/callback. This function is rarely needed.\n *\n * Use only for edge cases like custom OAuth providers not going\n * through the standard flow.\n */\nexport async function syncAuthToCookies(tokens: TokenResponse): Promise<void> {\n\t'use server'\n\tconst namespace = getCookieNamespace()\n\tawait setAuthCookies(namespace, tokens)\n}\n\n// =============================================================================\n// Authorization URL\n// =============================================================================\n\n/**\n * Get authorization URL for OAuth redirect\n */\nexport function getAuthorizationUrl(options?: {\n\tredirectUri?: string\n\tmode?: 'login' | 'signup'\n\tstate?: string\n\tappId?: string\n}): string {\n\tconst config = getConfig()\n\tif (!config) {\n\t\tthrow new Error('Sylphx SDK not configured. Set SYLPHX_SECRET_KEY environment variable.')\n\t}\n\n\tconst rawClientId = options?.appId || process.env.NEXT_PUBLIC_SYLPHX_APP_ID\n\tif (!rawClientId) {\n\t\tthrow new Error('App ID is required for authorization URL. Set NEXT_PUBLIC_SYLPHX_APP_ID.')\n\t}\n\n\t// Validate and sanitize app ID using SSOT\n\tconst clientId = validateAndSanitizeAppId(rawClientId)\n\n\tconst params = new URLSearchParams({\n\t\tclient_id: clientId,\n\t\tredirect_uri: options?.redirectUri || '/',\n\t\tresponse_type: 'code',\n\t})\n\n\tif (options?.mode === 'signup') {\n\t\tparams.set('mode', 'signup')\n\t}\n\n\tif (options?.state) {\n\t\tparams.set('state', options.state)\n\t}\n\n\treturn `${config.platformUrl}/auth/authorize?${params}`\n}\n\n// =============================================================================\n// Session Token Access (BFF Pattern)\n// =============================================================================\n\n/**\n * Get the current session token for API calls\n *\n * This is for apps that need to call third-party APIs with the session token.\n * For same-origin API calls, cookies are sent automatically.\n *\n * @example\n * ```ts\n * // In an API route that needs to call external APIs\n * import { getSessionToken } from '@sylphx/platform-sdk/nextjs'\n *\n * export async function GET() {\n * const token = await getSessionToken()\n * if (!token) {\n * return new Response('Unauthorized', { status: 401 })\n * }\n *\n * // Call third-party API\n * const response = await fetch('https://api.example.com/data', {\n * headers: { Authorization: `Bearer ${token}` }\n * })\n * // ...\n * }\n * ```\n */\nexport async function getSessionToken(): Promise<string | null> {\n\tconst { sessionToken } = await auth()\n\treturn sessionToken\n}\n","export const encoder = new TextEncoder();\nexport const decoder = new TextDecoder();\nconst MAX_INT32 = 2 ** 32;\nexport function concat(...buffers) {\n const size = buffers.reduce((acc, { length }) => acc + length, 0);\n const buf = new Uint8Array(size);\n let i = 0;\n for (const buffer of buffers) {\n buf.set(buffer, i);\n i += buffer.length;\n }\n return buf;\n}\nfunction writeUInt32BE(buf, value, offset) {\n if (value < 0 || value >= MAX_INT32) {\n throw new RangeError(`value must be >= 0 and <= ${MAX_INT32 - 1}. Received ${value}`);\n }\n buf.set([value >>> 24, value >>> 16, value >>> 8, value & 0xff], offset);\n}\nexport function uint64be(value) {\n const high = Math.floor(value / MAX_INT32);\n const low = value % MAX_INT32;\n const buf = new Uint8Array(8);\n writeUInt32BE(buf, high, 0);\n writeUInt32BE(buf, low, 4);\n return buf;\n}\nexport function uint32be(value) {\n const buf = new Uint8Array(4);\n writeUInt32BE(buf, value);\n return buf;\n}\nexport function encode(string) {\n const bytes = new Uint8Array(string.length);\n for (let i = 0; i < string.length; i++) {\n const code = string.charCodeAt(i);\n if (code > 127) {\n throw new TypeError('non-ASCII string encountered in encode()');\n }\n bytes[i] = code;\n }\n return bytes;\n}\n","export function encodeBase64(input) {\n if (Uint8Array.prototype.toBase64) {\n return input.toBase64();\n }\n const CHUNK_SIZE = 0x8000;\n const arr = [];\n for (let i = 0; i < input.length; i += CHUNK_SIZE) {\n arr.push(String.fromCharCode.apply(null, input.subarray(i, i + CHUNK_SIZE)));\n }\n return btoa(arr.join(''));\n}\nexport function decodeBase64(encoded) {\n if (Uint8Array.fromBase64) {\n return Uint8Array.fromBase64(encoded);\n }\n const binary = atob(encoded);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n return bytes;\n}\n","import { encoder, decoder } from '../lib/buffer_utils.js';\nimport { encodeBase64, decodeBase64 } from '../lib/base64.js';\nexport function decode(input) {\n if (Uint8Array.fromBase64) {\n return Uint8Array.fromBase64(typeof input === 'string' ? input : decoder.decode(input), {\n alphabet: 'base64url',\n });\n }\n let encoded = input;\n if (encoded instanceof Uint8Array) {\n encoded = decoder.decode(encoded);\n }\n encoded = encoded.replace(/-/g, '+').replace(/_/g, '/');\n try {\n return decodeBase64(encoded);\n }\n catch {\n throw new TypeError('The input to be decoded is not correctly encoded.');\n }\n}\nexport function encode(input) {\n let unencoded = input;\n if (typeof unencoded === 'string') {\n unencoded = encoder.encode(unencoded);\n }\n if (Uint8Array.prototype.toBase64) {\n return unencoded.toBase64({ alphabet: 'base64url', omitPadding: true });\n }\n return encodeBase64(unencoded).replace(/=/g, '').replace(/\\+/g, '-').replace(/\\//g, '_');\n}\n","export class JOSEError extends Error {\n static code = 'ERR_JOSE_GENERIC';\n code = 'ERR_JOSE_GENERIC';\n constructor(message, options) {\n super(message, options);\n this.name = this.constructor.name;\n Error.captureStackTrace?.(this, this.constructor);\n }\n}\nexport class JWTClaimValidationFailed extends JOSEError {\n static code = 'ERR_JWT_CLAIM_VALIDATION_FAILED';\n code = 'ERR_JWT_CLAIM_VALIDATION_FAILED';\n claim;\n reason;\n payload;\n constructor(message, payload, claim = 'unspecified', reason = 'unspecified') {\n super(message, { cause: { claim, reason, payload } });\n this.claim = claim;\n this.reason = reason;\n this.payload = payload;\n }\n}\nexport class JWTExpired extends JOSEError {\n static code = 'ERR_JWT_EXPIRED';\n code = 'ERR_JWT_EXPIRED';\n claim;\n reason;\n payload;\n constructor(message, payload, claim = 'unspecified', reason = 'unspecified') {\n super(message, { cause: { claim, reason, payload } });\n this.claim = claim;\n this.reason = reason;\n this.payload = payload;\n }\n}\nexport class JOSEAlgNotAllowed extends JOSEError {\n static code = 'ERR_JOSE_ALG_NOT_ALLOWED';\n code = 'ERR_JOSE_ALG_NOT_ALLOWED';\n}\nexport class JOSENotSupported extends JOSEError {\n static code = 'ERR_JOSE_NOT_SUPPORTED';\n code = 'ERR_JOSE_NOT_SUPPORTED';\n}\nexport class JWEDecryptionFailed extends JOSEError {\n static code = 'ERR_JWE_DECRYPTION_FAILED';\n code = 'ERR_JWE_DECRYPTION_FAILED';\n constructor(message = 'decryption operation failed', options) {\n super(message, options);\n }\n}\nexport class JWEInvalid extends JOSEError {\n static code = 'ERR_JWE_INVALID';\n code = 'ERR_JWE_INVALID';\n}\nexport class JWSInvalid extends JOSEError {\n static code = 'ERR_JWS_INVALID';\n code = 'ERR_JWS_INVALID';\n}\nexport class JWTInvalid extends JOSEError {\n static code = 'ERR_JWT_INVALID';\n code = 'ERR_JWT_INVALID';\n}\nexport class JWKInvalid extends JOSEError {\n static code = 'ERR_JWK_INVALID';\n code = 'ERR_JWK_INVALID';\n}\nexport class JWKSInvalid extends JOSEError {\n static code = 'ERR_JWKS_INVALID';\n code = 'ERR_JWKS_INVALID';\n}\nexport class JWKSNoMatchingKey extends JOSEError {\n static code = 'ERR_JWKS_NO_MATCHING_KEY';\n code = 'ERR_JWKS_NO_MATCHING_KEY';\n constructor(message = 'no applicable key found in the JSON Web Key Set', options) {\n super(message, options);\n }\n}\nexport class JWKSMultipleMatchingKeys extends JOSEError {\n [Symbol.asyncIterator];\n static code = 'ERR_JWKS_MULTIPLE_MATCHING_KEYS';\n code = 'ERR_JWKS_MULTIPLE_MATCHING_KEYS';\n constructor(message = 'multiple matching keys found in the JSON Web Key Set', options) {\n super(message, options);\n }\n}\nexport class JWKSTimeout extends JOSEError {\n static code = 'ERR_JWKS_TIMEOUT';\n code = 'ERR_JWKS_TIMEOUT';\n constructor(message = 'request timed out', options) {\n super(message, options);\n }\n}\nexport class JWSSignatureVerificationFailed extends JOSEError {\n static code = 'ERR_JWS_SIGNATURE_VERIFICATION_FAILED';\n code = 'ERR_JWS_SIGNATURE_VERIFICATION_FAILED';\n constructor(message = 'signature verification failed', options) {\n super(message, options);\n }\n}\n","const unusable = (name, prop = 'algorithm.name') => new TypeError(`CryptoKey does not support this operation, its ${prop} must be ${name}`);\nconst isAlgorithm = (algorithm, name) => algorithm.name === name;\nfunction getHashLength(hash) {\n return parseInt(hash.name.slice(4), 10);\n}\nfunction getNamedCurve(alg) {\n switch (alg) {\n case 'ES256':\n return 'P-256';\n case 'ES384':\n return 'P-384';\n case 'ES512':\n return 'P-521';\n default:\n throw new Error('unreachable');\n }\n}\nfunction checkUsage(key, usage) {\n if (usage && !key.usages.includes(usage)) {\n throw new TypeError(`CryptoKey does not support this operation, its usages must include ${usage}.`);\n }\n}\nexport function checkSigCryptoKey(key, alg, usage) {\n switch (alg) {\n case 'HS256':\n case 'HS384':\n case 'HS512': {\n if (!isAlgorithm(key.algorithm, 'HMAC'))\n throw unusable('HMAC');\n const expected = parseInt(alg.slice(2), 10);\n const actual = getHashLength(key.algorithm.hash);\n if (actual !== expected)\n throw unusable(`SHA-${expected}`, 'algorithm.hash');\n break;\n }\n case 'RS256':\n case 'RS384':\n case 'RS512': {\n if (!isAlgorithm(key.algorithm, 'RSASSA-PKCS1-v1_5'))\n throw unusable('RSASSA-PKCS1-v1_5');\n const expected = parseInt(alg.slice(2), 10);\n const actual = getHashLength(key.algorithm.hash);\n if (actual !== expected)\n throw unusable(`SHA-${expected}`, 'algorithm.hash');\n break;\n }\n case 'PS256':\n case 'PS384':\n case 'PS512': {\n if (!isAlgorithm(key.algorithm, 'RSA-PSS'))\n throw unusable('RSA-PSS');\n const expected = parseInt(alg.slice(2), 10);\n const actual = getHashLength(key.algorithm.hash);\n if (actual !== expected)\n throw unusable(`SHA-${expected}`, 'algorithm.hash');\n break;\n }\n case 'Ed25519':\n case 'EdDSA': {\n if (!isAlgorithm(key.algorithm, 'Ed25519'))\n throw unusable('Ed25519');\n break;\n }\n case 'ML-DSA-44':\n case 'ML-DSA-65':\n case 'ML-DSA-87': {\n if (!isAlgorithm(key.algorithm, alg))\n throw unusable(alg);\n break;\n }\n case 'ES256':\n case 'ES384':\n case 'ES512': {\n if (!isAlgorithm(key.algorithm, 'ECDSA'))\n throw unusable('ECDSA');\n const expected = getNamedCurve(alg);\n const actual = key.algorithm.namedCurve;\n if (actual !== expected)\n throw unusable(expected, 'algorithm.namedCurve');\n break;\n }\n default:\n throw new TypeError('CryptoKey does not support this operation');\n }\n checkUsage(key, usage);\n}\nexport function checkEncCryptoKey(key, alg, usage) {\n switch (alg) {\n case 'A128GCM':\n case 'A192GCM':\n case 'A256GCM': {\n if (!isAlgorithm(key.algorithm, 'AES-GCM'))\n throw unusable('AES-GCM');\n const expected = parseInt(alg.slice(1, 4), 10);\n const actual = key.algorithm.length;\n if (actual !== expected)\n throw unusable(expected, 'algorithm.length');\n break;\n }\n case 'A128KW':\n case 'A192KW':\n case 'A256KW': {\n if (!isAlgorithm(key.algorithm, 'AES-KW'))\n throw unusable('AES-KW');\n const expected = parseInt(alg.slice(1, 4), 10);\n const actual = key.algorithm.length;\n if (actual !== expected)\n throw unusable(expected, 'algorithm.length');\n break;\n }\n case 'ECDH': {\n switch (key.algorithm.name) {\n case 'ECDH':\n case 'X25519':\n break;\n default:\n throw unusable('ECDH or X25519');\n }\n break;\n }\n case 'PBES2-HS256+A128KW':\n case 'PBES2-HS384+A192KW':\n case 'PBES2-HS512+A256KW':\n if (!isAlgorithm(key.algorithm, 'PBKDF2'))\n throw unusable('PBKDF2');\n break;\n case 'RSA-OAEP':\n case 'RSA-OAEP-256':\n case 'RSA-OAEP-384':\n case 'RSA-OAEP-512': {\n if (!isAlgorithm(key.algorithm, 'RSA-OAEP'))\n throw unusable('RSA-OAEP');\n const expected = parseInt(alg.slice(9), 10) || 1;\n const actual = getHashLength(key.algorithm.hash);\n if (actual !== expected)\n throw unusable(`SHA-${expected}`, 'algorithm.hash');\n break;\n }\n default:\n throw new TypeError('CryptoKey does not support this operation');\n }\n checkUsage(key, usage);\n}\n","function message(msg, actual, ...types) {\n types = types.filter(Boolean);\n if (types.length > 2) {\n const last = types.pop();\n msg += `one of type ${types.join(', ')}, or ${last}.`;\n }\n else if (types.length === 2) {\n msg += `one of type ${types[0]} or ${types[1]}.`;\n }\n else {\n msg += `of type ${types[0]}.`;\n }\n if (actual == null) {\n msg += ` Received ${actual}`;\n }\n else if (typeof actual === 'function' && actual.name) {\n msg += ` Received function ${actual.name}`;\n }\n else if (typeof actual === 'object' && actual != null) {\n if (actual.constructor?.name) {\n msg += ` Received an instance of ${actual.constructor.name}`;\n }\n }\n return msg;\n}\nexport const invalidKeyInput = (actual, ...types) => message('Key must be ', actual, ...types);\nexport const withAlg = (alg, actual, ...types) => message(`Key for the ${alg} algorithm must be `, actual, ...types);\n","export function assertCryptoKey(key) {\n if (!isCryptoKey(key)) {\n throw new Error('CryptoKey instance expected');\n }\n}\nexport const isCryptoKey = (key) => {\n if (key?.[Symbol.toStringTag] === 'CryptoKey')\n return true;\n try {\n return key instanceof CryptoKey;\n }\n catch {\n return false;\n }\n};\nexport const isKeyObject = (key) => key?.[Symbol.toStringTag] === 'KeyObject';\nexport const isKeyLike = (key) => isCryptoKey(key) || isKeyObject(key);\n","export function isDisjoint(...headers) {\n const sources = headers.filter(Boolean);\n if (sources.length === 0 || sources.length === 1) {\n return true;\n }\n let acc;\n for (const header of sources) {\n const parameters = Object.keys(header);\n if (!acc || acc.size === 0) {\n acc = new Set(parameters);\n continue;\n }\n for (const parameter of parameters) {\n if (acc.has(parameter)) {\n return false;\n }\n acc.add(parameter);\n }\n }\n return true;\n}\n","const isObjectLike = (value) => typeof value === 'object' && value !== null;\nexport function isObject(input) {\n if (!isObjectLike(input) || Object.prototype.toString.call(input) !== '[object Object]') {\n return false;\n }\n if (Object.getPrototypeOf(input) === null) {\n return true;\n }\n let proto = input;\n while (Object.getPrototypeOf(proto) !== null) {\n proto = Object.getPrototypeOf(proto);\n }\n return Object.getPrototypeOf(input) === proto;\n}\n","export function checkKeyLength(alg, key) {\n if (alg.startsWith('RS') || alg.startsWith('PS')) {\n const { modulusLength } = key.algorithm;\n if (typeof modulusLength !== 'number' || modulusLength < 2048) {\n throw new TypeError(`${alg} requires key modulusLength to be 2048 bits or larger`);\n }\n }\n}\n","import { JOSENotSupported } from '../util/errors.js';\nfunction subtleMapping(jwk) {\n let algorithm;\n let keyUsages;\n switch (jwk.kty) {\n case 'AKP': {\n switch (jwk.alg) {\n case 'ML-DSA-44':\n case 'ML-DSA-65':\n case 'ML-DSA-87':\n algorithm = { name: jwk.alg };\n keyUsages = jwk.priv ? ['sign'] : ['verify'];\n break;\n default:\n throw new JOSENotSupported('Invalid or unsupported JWK \"alg\" (Algorithm) Parameter value');\n }\n break;\n }\n case 'RSA': {\n switch (jwk.alg) {\n case 'PS256':\n case 'PS384':\n case 'PS512':\n algorithm = { name: 'RSA-PSS', hash: `SHA-${jwk.alg.slice(-3)}` };\n keyUsages = jwk.d ? ['sign'] : ['verify'];\n break;\n case 'RS256':\n case 'RS384':\n case 'RS512':\n algorithm = { name: 'RSASSA-PKCS1-v1_5', hash: `SHA-${jwk.alg.slice(-3)}` };\n keyUsages = jwk.d ? ['sign'] : ['verify'];\n break;\n case 'RSA-OAEP':\n case 'RSA-OAEP-256':\n case 'RSA-OAEP-384':\n case 'RSA-OAEP-512':\n algorithm = {\n name: 'RSA-OAEP',\n hash: `SHA-${parseInt(jwk.alg.slice(-3), 10) || 1}`,\n };\n keyUsages = jwk.d ? ['decrypt', 'unwrapKey'] : ['encrypt', 'wrapKey'];\n break;\n default:\n throw new JOSENotSupported('Invalid or unsupported JWK \"alg\" (Algorithm) Parameter value');\n }\n break;\n }\n case 'EC': {\n switch (jwk.alg) {\n case 'ES256':\n algorithm = { name: 'ECDSA', namedCurve: 'P-256' };\n keyUsages = jwk.d ? ['sign'] : ['verify'];\n break;\n case 'ES384':\n algorithm = { name: 'ECDSA', namedCurve: 'P-384' };\n keyUsages = jwk.d ? ['sign'] : ['verify'];\n break;\n case 'ES512':\n algorithm = { name: 'ECDSA', namedCurve: 'P-521' };\n keyUsages = jwk.d ? ['sign'] : ['verify'];\n break;\n case 'ECDH-ES':\n case 'ECDH-ES+A128KW':\n case 'ECDH-ES+A192KW':\n case 'ECDH-ES+A256KW':\n algorithm = { name: 'ECDH', namedCurve: jwk.crv };\n keyUsages = jwk.d ? ['deriveBits'] : [];\n break;\n default:\n throw new JOSENotSupported('Invalid or unsupported JWK \"alg\" (Algorithm) Parameter value');\n }\n break;\n }\n case 'OKP': {\n switch (jwk.alg) {\n case 'Ed25519':\n case 'EdDSA':\n algorithm = { name: 'Ed25519' };\n keyUsages = jwk.d ? ['sign'] : ['verify'];\n break;\n case 'ECDH-ES':\n case 'ECDH-ES+A128KW':\n case 'ECDH-ES+A192KW':\n case 'ECDH-ES+A256KW':\n algorithm = { name: jwk.crv };\n keyUsages = jwk.d ? ['deriveBits'] : [];\n break;\n default:\n throw new JOSENotSupported('Invalid or unsupported JWK \"alg\" (Algorithm) Parameter value');\n }\n break;\n }\n default:\n throw new JOSENotSupported('Invalid or unsupported JWK \"kty\" (Key Type) Parameter value');\n }\n return { algorithm, keyUsages };\n}\nexport async function jwkToKey(jwk) {\n if (!jwk.alg) {\n throw new TypeError('\"alg\" argument is required when \"jwk.alg\" is not present');\n }\n const { algorithm, keyUsages } = subtleMapping(jwk);\n const keyData = { ...jwk };\n if (keyData.kty !== 'AKP') {\n delete keyData.alg;\n }\n delete keyData.use;\n return crypto.subtle.importKey('jwk', keyData, algorithm, jwk.ext ?? (jwk.d || jwk.priv ? false : true), jwk.key_ops ?? keyUsages);\n}\n","import { decode as decodeBase64URL } from '../util/base64url.js';\nimport { fromSPKI, fromPKCS8, fromX509 } from '../lib/asn1.js';\nimport { jwkToKey } from '../lib/jwk_to_key.js';\nimport { JOSENotSupported } from '../util/errors.js';\nimport { isObject } from '../lib/is_object.js';\nexport async function importSPKI(spki, alg, options) {\n if (typeof spki !== 'string' || spki.indexOf('-----BEGIN PUBLIC KEY-----') !== 0) {\n throw new TypeError('\"spki\" must be SPKI formatted string');\n }\n return fromSPKI(spki, alg, options);\n}\nexport async function importX509(x509, alg, options) {\n if (typeof x509 !== 'string' || x509.indexOf('-----BEGIN CERTIFICATE-----') !== 0) {\n throw new TypeError('\"x509\" must be X.509 formatted string');\n }\n return fromX509(x509, alg, options);\n}\nexport async function importPKCS8(pkcs8, alg, options) {\n if (typeof pkcs8 !== 'string' || pkcs8.indexOf('-----BEGIN PRIVATE KEY-----') !== 0) {\n throw new TypeError('\"pkcs8\" must be PKCS#8 formatted string');\n }\n return fromPKCS8(pkcs8, alg, options);\n}\nexport async function importJWK(jwk, alg, options) {\n if (!isObject(jwk)) {\n throw new TypeError('JWK must be an object');\n }\n let ext;\n alg ??= jwk.alg;\n ext ??= options?.extractable ?? jwk.ext;\n switch (jwk.kty) {\n case 'oct':\n if (typeof jwk.k !== 'string' || !jwk.k) {\n throw new TypeError('missing \"k\" (Key Value) Parameter value');\n }\n return decodeBase64URL(jwk.k);\n case 'RSA':\n if ('oth' in jwk && jwk.oth !== undefined) {\n throw new JOSENotSupported('RSA JWK \"oth\" (Other Primes Info) Parameter value is not supported');\n }\n return jwkToKey({ ...jwk, alg, ext });\n case 'AKP': {\n if (typeof jwk.alg !== 'string' || !jwk.alg) {\n throw new TypeError('missing \"alg\" (Algorithm) Parameter value');\n }\n if (alg !== undefined && alg !== jwk.alg) {\n throw new TypeError('JWK alg and alg option value mismatch');\n }\n return jwkToKey({ ...jwk, ext });\n }\n case 'EC':\n case 'OKP':\n return jwkToKey({ ...jwk, alg, ext });\n default:\n throw new JOSENotSupported('Unsupported \"kty\" (Key Type) Parameter value');\n }\n}\n","import { JOSENotSupported, JWEInvalid, JWSInvalid } from '../util/errors.js';\nexport function validateCrit(Err, recognizedDefault, recognizedOption, protectedHeader, joseHeader) {\n if (joseHeader.crit !== undefined && protectedHeader?.crit === undefined) {\n throw new Err('\"crit\" (Critical) Header Parameter MUST be integrity protected');\n }\n if (!protectedHeader || protectedHeader.crit === undefined) {\n return new Set();\n }\n if (!Array.isArray(protectedHeader.crit) ||\n protectedHeader.crit.length === 0 ||\n protectedHeader.crit.some((input) => typeof input !== 'string' || input.length === 0)) {\n throw new Err('\"crit\" (Critical) Header Parameter MUST be an array of non-empty strings when present');\n }\n let recognized;\n if (recognizedOption !== undefined) {\n recognized = new Map([...Object.entries(recognizedOption), ...recognizedDefault.entries()]);\n }\n else {\n recognized = recognizedDefault;\n }\n for (const parameter of protectedHeader.crit) {\n if (!recognized.has(parameter)) {\n throw new JOSENotSupported(`Extension Header Parameter \"${parameter}\" is not recognized`);\n }\n if (joseHeader[parameter] === undefined) {\n throw new Err(`Extension Header Parameter \"${parameter}\" is missing`);\n }\n if (recognized.get(parameter) && protectedHeader[parameter] === undefined) {\n throw new Err(`Extension Header Parameter \"${parameter}\" MUST be integrity protected`);\n }\n }\n return new Set(protectedHeader.crit);\n}\n","export function validateAlgorithms(option, algorithms) {\n if (algorithms !== undefined &&\n (!Array.isArray(algorithms) || algorithms.some((s) => typeof s !== 'string'))) {\n throw new TypeError(`\"${option}\" option must be an array of strings`);\n }\n if (!algorithms) {\n return undefined;\n }\n return new Set(algorithms);\n}\n","import { isObject } from './is_object.js';\nexport const isJWK = (key) => isObject(key) && typeof key.kty === 'string';\nexport const isPrivateJWK = (key) => key.kty !== 'oct' &&\n ((key.kty === 'AKP' && typeof key.priv === 'string') || typeof key.d === 'string');\nexport const isPublicJWK = (key) => key.kty !== 'oct' && key.d === undefined && key.priv === undefined;\nexport const isSecretJWK = (key) => key.kty === 'oct' && typeof key.k === 'string';\n","import { isJWK } from './is_jwk.js';\nimport { decode } from '../util/base64url.js';\nimport { jwkToKey } from './jwk_to_key.js';\nimport { isCryptoKey, isKeyObject } from './is_key_like.js';\nlet cache;\nconst handleJWK = async (key, jwk, alg, freeze = false) => {\n cache ||= new WeakMap();\n let cached = cache.get(key);\n if (cached?.[alg]) {\n return cached[alg];\n }\n const cryptoKey = await jwkToKey({ ...jwk, alg });\n if (freeze)\n Object.freeze(key);\n if (!cached) {\n cache.set(key, { [alg]: cryptoKey });\n }\n else {\n cached[alg] = cryptoKey;\n }\n return cryptoKey;\n};\nconst handleKeyObject = (keyObject, alg) => {\n cache ||= new WeakMap();\n let cached = cache.get(keyObject);\n if (cached?.[alg]) {\n return cached[alg];\n }\n const isPublic = keyObject.type === 'public';\n const extractable = isPublic ? true : false;\n let cryptoKey;\n if (keyObject.asymmetricKeyType === 'x25519') {\n switch (alg) {\n case 'ECDH-ES':\n case 'ECDH-ES+A128KW':\n case 'ECDH-ES+A192KW':\n case 'ECDH-ES+A256KW':\n break;\n default:\n throw new TypeError('given KeyObject instance cannot be used for this algorithm');\n }\n cryptoKey = keyObject.toCryptoKey(keyObject.asymmetricKeyType, extractable, isPublic ? [] : ['deriveBits']);\n }\n if (keyObject.asymmetricKeyType === 'ed25519') {\n if (alg !== 'EdDSA' && alg !== 'Ed25519') {\n throw new TypeError('given KeyObject instance cannot be used for this algorithm');\n }\n cryptoKey = keyObject.toCryptoKey(keyObject.asymmetricKeyType, extractable, [\n isPublic ? 'verify' : 'sign',\n ]);\n }\n switch (keyObject.asymmetricKeyType) {\n case 'ml-dsa-44':\n case 'ml-dsa-65':\n case 'ml-dsa-87': {\n if (alg !== keyObject.asymmetricKeyType.toUpperCase()) {\n throw new TypeError('given KeyObject instance cannot be used for this algorithm');\n }\n cryptoKey = keyObject.toCryptoKey(keyObject.asymmetricKeyType, extractable, [\n isPublic ? 'verify' : 'sign',\n ]);\n }\n }\n if (keyObject.asymmetricKeyType === 'rsa') {\n let hash;\n switch (alg) {\n case 'RSA-OAEP':\n hash = 'SHA-1';\n break;\n case 'RS256':\n case 'PS256':\n case 'RSA-OAEP-256':\n hash = 'SHA-256';\n break;\n case 'RS384':\n case 'PS384':\n case 'RSA-OAEP-384':\n hash = 'SHA-384';\n break;\n case 'RS512':\n case 'PS512':\n case 'RSA-OAEP-512':\n hash = 'SHA-512';\n break;\n default:\n throw new TypeError('given KeyObject instance cannot be used for this algorithm');\n }\n if (alg.startsWith('RSA-OAEP')) {\n return keyObject.toCryptoKey({\n name: 'RSA-OAEP',\n hash,\n }, extractable, isPublic ? ['encrypt'] : ['decrypt']);\n }\n cryptoKey = keyObject.toCryptoKey({\n name: alg.startsWith('PS') ? 'RSA-PSS' : 'RSASSA-PKCS1-v1_5',\n hash,\n }, extractable, [isPublic ? 'verify' : 'sign']);\n }\n if (keyObject.asymmetricKeyType === 'ec') {\n const nist = new Map([\n ['prime256v1', 'P-256'],\n ['secp384r1', 'P-384'],\n ['secp521r1', 'P-521'],\n ]);\n const namedCurve = nist.get(keyObject.asymmetricKeyDetails?.namedCurve);\n if (!namedCurve) {\n throw new TypeError('given KeyObject instance cannot be used for this algorithm');\n }\n if (alg === 'ES256' && namedCurve === 'P-256') {\n cryptoKey = keyObject.toCryptoKey({\n name: 'ECDSA',\n namedCurve,\n }, extractable, [isPublic ? 'verify' : 'sign']);\n }\n if (alg === 'ES384' && namedCurve === 'P-384') {\n cryptoKey = keyObject.toCryptoKey({\n name: 'ECDSA',\n namedCurve,\n }, extractable, [isPublic ? 'verify' : 'sign']);\n }\n if (alg === 'ES512' && namedCurve === 'P-521') {\n cryptoKey = keyObject.toCryptoKey({\n name: 'ECDSA',\n namedCurve,\n }, extractable, [isPublic ? 'verify' : 'sign']);\n }\n if (alg.startsWith('ECDH-ES')) {\n cryptoKey = keyObject.toCryptoKey({\n name: 'ECDH',\n namedCurve,\n }, extractable, isPublic ? [] : ['deriveBits']);\n }\n }\n if (!cryptoKey) {\n throw new TypeError('given KeyObject instance cannot be used for this algorithm');\n }\n if (!cached) {\n cache.set(keyObject, { [alg]: cryptoKey });\n }\n else {\n cached[alg] = cryptoKey;\n }\n return cryptoKey;\n};\nexport async function normalizeKey(key, alg) {\n if (key instanceof Uint8Array) {\n return key;\n }\n if (isCryptoKey(key)) {\n return key;\n }\n if (isKeyObject(key)) {\n if (key.type === 'secret') {\n return key.export();\n }\n if ('toCryptoKey' in key && typeof key.toCryptoKey === 'function') {\n try {\n return handleKeyObject(key, alg);\n }\n catch (err) {\n if (err instanceof TypeError) {\n throw err;\n }\n }\n }\n let jwk = key.export({ format: 'jwk' });\n return handleJWK(key, jwk, alg);\n }\n if (isJWK(key)) {\n if (key.k) {\n return decode(key.k);\n }\n return handleJWK(key, key, alg, true);\n }\n throw new Error('unreachable');\n}\n","import { withAlg as invalidKeyInput } from './invalid_key_input.js';\nimport { isKeyLike } from './is_key_like.js';\nimport * as jwk from './is_jwk.js';\nconst tag = (key) => key?.[Symbol.toStringTag];\nconst jwkMatchesOp = (alg, key, usage) => {\n if (key.use !== undefined) {\n let expected;\n switch (usage) {\n case 'sign':\n case 'verify':\n expected = 'sig';\n break;\n case 'encrypt':\n case 'decrypt':\n expected = 'enc';\n break;\n }\n if (key.use !== expected) {\n throw new TypeError(`Invalid key for this operation, its \"use\" must be \"${expected}\" when present`);\n }\n }\n if (key.alg !== undefined && key.alg !== alg) {\n throw new TypeError(`Invalid key for this operation, its \"alg\" must be \"${alg}\" when present`);\n }\n if (Array.isArray(key.key_ops)) {\n let expectedKeyOp;\n switch (true) {\n case usage === 'sign' || usage === 'verify':\n case alg === 'dir':\n case alg.includes('CBC-HS'):\n expectedKeyOp = usage;\n break;\n case alg.startsWith('PBES2'):\n expectedKeyOp = 'deriveBits';\n break;\n case /^A\\d{3}(?:GCM)?(?:KW)?$/.test(alg):\n if (!alg.includes('GCM') && alg.endsWith('KW')) {\n expectedKeyOp = usage === 'encrypt' ? 'wrapKey' : 'unwrapKey';\n }\n else {\n expectedKeyOp = usage;\n }\n break;\n case usage === 'encrypt' && alg.startsWith('RSA'):\n expectedKeyOp = 'wrapKey';\n break;\n case usage === 'decrypt':\n expectedKeyOp = alg.startsWith('RSA') ? 'unwrapKey' : 'deriveBits';\n break;\n }\n if (expectedKeyOp && key.key_ops?.includes?.(expectedKeyOp) === false) {\n throw new TypeError(`Invalid key for this operation, its \"key_ops\" must include \"${expectedKeyOp}\" when present`);\n }\n }\n return true;\n};\nconst symmetricTypeCheck = (alg, key, usage) => {\n if (key instanceof Uint8Array)\n return;\n if (jwk.isJWK(key)) {\n if (jwk.isSecretJWK(key) && jwkMatchesOp(alg, key, usage))\n return;\n throw new TypeError(`JSON Web Key for symmetric algorithms must have JWK \"kty\" (Key Type) equal to \"oct\" and the JWK \"k\" (Key Value) present`);\n }\n if (!isKeyLike(key)) {\n throw new TypeError(invalidKeyInput(alg, key, 'CryptoKey', 'KeyObject', 'JSON Web Key', 'Uint8Array'));\n }\n if (key.type !== 'secret') {\n throw new TypeError(`${tag(key)} instances for symmetric algorithms must be of type \"secret\"`);\n }\n};\nconst asymmetricTypeCheck = (alg, key, usage) => {\n if (jwk.isJWK(key)) {\n switch (usage) {\n case 'decrypt':\n case 'sign':\n if (jwk.isPrivateJWK(key) && jwkMatchesOp(alg, key, usage))\n return;\n throw new TypeError(`JSON Web Key for this operation must be a private JWK`);\n case 'encrypt':\n case 'verify':\n if (jwk.isPublicJWK(key) && jwkMatchesOp(alg, key, usage))\n return;\n throw new TypeError(`JSON Web Key for this operation must be a public JWK`);\n }\n }\n if (!isKeyLike(key)) {\n throw new TypeError(invalidKeyInput(alg, key, 'CryptoKey', 'KeyObject', 'JSON Web Key'));\n }\n if (key.type === 'secret') {\n throw new TypeError(`${tag(key)} instances for asymmetric algorithms must not be of type \"secret\"`);\n }\n if (key.type === 'public') {\n switch (usage) {\n case 'sign':\n throw new TypeError(`${tag(key)} instances for asymmetric algorithm signing must be of type \"private\"`);\n case 'decrypt':\n throw new TypeError(`${tag(key)} instances for asymmetric algorithm decryption must be of type \"private\"`);\n }\n }\n if (key.type === 'private') {\n switch (usage) {\n case 'verify':\n throw new TypeError(`${tag(key)} instances for asymmetric algorithm verifying must be of type \"public\"`);\n case 'encrypt':\n throw new TypeError(`${tag(key)} instances for asymmetric algorithm encryption must be of type \"public\"`);\n }\n }\n};\nexport function checkKeyType(alg, key, usage) {\n switch (alg.substring(0, 2)) {\n case 'A1':\n case 'A2':\n case 'di':\n case 'HS':\n case 'PB':\n symmetricTypeCheck(alg, key, usage);\n break;\n default:\n asymmetricTypeCheck(alg, key, usage);\n }\n}\n","import { JOSENotSupported } from '../util/errors.js';\nexport function subtleAlgorithm(alg, algorithm) {\n const hash = `SHA-${alg.slice(-3)}`;\n switch (alg) {\n case 'HS256':\n case 'HS384':\n case 'HS512':\n return { hash, name: 'HMAC' };\n case 'PS256':\n case 'PS384':\n case 'PS512':\n return { hash, name: 'RSA-PSS', saltLength: parseInt(alg.slice(-3), 10) >> 3 };\n case 'RS256':\n case 'RS384':\n case 'RS512':\n return { hash, name: 'RSASSA-PKCS1-v1_5' };\n case 'ES256':\n case 'ES384':\n case 'ES512':\n return { hash, name: 'ECDSA', namedCurve: algorithm.namedCurve };\n case 'Ed25519':\n case 'EdDSA':\n return { name: 'Ed25519' };\n case 'ML-DSA-44':\n case 'ML-DSA-65':\n case 'ML-DSA-87':\n return { name: alg };\n default:\n throw new JOSENotSupported(`alg ${alg} is not supported either by JOSE or your javascript runtime`);\n }\n}\n","import { checkSigCryptoKey } from './crypto_key.js';\nimport { invalidKeyInput } from './invalid_key_input.js';\nexport async function getSigKey(alg, key, usage) {\n if (key instanceof Uint8Array) {\n if (!alg.startsWith('HS')) {\n throw new TypeError(invalidKeyInput(key, 'CryptoKey', 'KeyObject', 'JSON Web Key'));\n }\n return crypto.subtle.importKey('raw', key, { hash: `SHA-${alg.slice(-3)}`, name: 'HMAC' }, false, [usage]);\n }\n checkSigCryptoKey(key, alg, usage);\n return key;\n}\n","import { subtleAlgorithm } from './subtle_dsa.js';\nimport { checkKeyLength } from './check_key_length.js';\nimport { getSigKey } from './get_sign_verify_key.js';\nexport async function verify(alg, key, signature, data) {\n const cryptoKey = await getSigKey(alg, key, 'verify');\n checkKeyLength(alg, cryptoKey);\n const algorithm = subtleAlgorithm(alg, cryptoKey.algorithm);\n try {\n return await crypto.subtle.verify(algorithm, cryptoKey, signature, data);\n }\n catch {\n return false;\n }\n}\n","import { decode as b64u } from '../../util/base64url.js';\nimport { verify } from '../../lib/verify.js';\nimport { JOSEAlgNotAllowed, JWSInvalid, JWSSignatureVerificationFailed } from '../../util/errors.js';\nimport { concat, encoder, decoder, encode } from '../../lib/buffer_utils.js';\nimport { isDisjoint } from '../../lib/is_disjoint.js';\nimport { isObject } from '../../lib/is_object.js';\nimport { checkKeyType } from '../../lib/check_key_type.js';\nimport { validateCrit } from '../../lib/validate_crit.js';\nimport { validateAlgorithms } from '../../lib/validate_algorithms.js';\nimport { normalizeKey } from '../../lib/normalize_key.js';\nexport async function flattenedVerify(jws, key, options) {\n if (!isObject(jws)) {\n throw new JWSInvalid('Flattened JWS must be an object');\n }\n if (jws.protected === undefined && jws.header === undefined) {\n throw new JWSInvalid('Flattened JWS must have either of the \"protected\" or \"header\" members');\n }\n if (jws.protected !== undefined && typeof jws.protected !== 'string') {\n throw new JWSInvalid('JWS Protected Header incorrect type');\n }\n if (jws.payload === undefined) {\n throw new JWSInvalid('JWS Payload missing');\n }\n if (typeof jws.signature !== 'string') {\n throw new JWSInvalid('JWS Signature missing or incorrect type');\n }\n if (jws.header !== undefined && !isObject(jws.header)) {\n throw new JWSInvalid('JWS Unprotected Header incorrect type');\n }\n let parsedProt = {};\n if (jws.protected) {\n try {\n const protectedHeader = b64u(jws.protected);\n parsedProt = JSON.parse(decoder.decode(protectedHeader));\n }\n catch {\n throw new JWSInvalid('JWS Protected Header is invalid');\n }\n }\n if (!isDisjoint(parsedProt, jws.header)) {\n throw new JWSInvalid('JWS Protected and JWS Unprotected Header Parameter names must be disjoint');\n }\n const joseHeader = {\n ...parsedProt,\n ...jws.header,\n };\n const extensions = validateCrit(JWSInvalid, new Map([['b64', true]]), options?.crit, parsedProt, joseHeader);\n let b64 = true;\n if (extensions.has('b64')) {\n b64 = parsedProt.b64;\n if (typeof b64 !== 'boolean') {\n throw new JWSInvalid('The \"b64\" (base64url-encode payload) Header Parameter must be a boolean');\n }\n }\n const { alg } = joseHeader;\n if (typeof alg !== 'string' || !alg) {\n throw new JWSInvalid('JWS \"alg\" (Algorithm) Header Parameter missing or invalid');\n }\n const algorithms = options && validateAlgorithms('algorithms', options.algorithms);\n if (algorithms && !algorithms.has(alg)) {\n throw new JOSEAlgNotAllowed('\"alg\" (Algorithm) Header Parameter value not allowed');\n }\n if (b64) {\n if (typeof jws.payload !== 'string') {\n throw new JWSInvalid('JWS Payload must be a string');\n }\n }\n else if (typeof jws.payload !== 'string' && !(jws.payload instanceof Uint8Array)) {\n throw new JWSInvalid('JWS Payload must be a string or an Uint8Array instance');\n }\n let resolvedKey = false;\n if (typeof key === 'function') {\n key = await key(parsedProt, jws);\n resolvedKey = true;\n }\n checkKeyType(alg, key, 'verify');\n const data = concat(jws.protected !== undefined ? encode(jws.protected) : new Uint8Array(), encode('.'), typeof jws.payload === 'string'\n ? b64\n ? encode(jws.payload)\n : encoder.encode(jws.payload)\n : jws.payload);\n let signature;\n try {\n signature = b64u(jws.signature);\n }\n catch {\n throw new JWSInvalid('Failed to base64url decode the signature');\n }\n const k = await normalizeKey(key, alg);\n const verified = await verify(alg, k, signature, data);\n if (!verified) {\n throw new JWSSignatureVerificationFailed();\n }\n let payload;\n if (b64) {\n try {\n payload = b64u(jws.payload);\n }\n catch {\n throw new JWSInvalid('Failed to base64url decode the payload');\n }\n }\n else if (typeof jws.payload === 'string') {\n payload = encoder.encode(jws.payload);\n }\n else {\n payload = jws.payload;\n }\n const result = { payload };\n if (jws.protected !== undefined) {\n result.protectedHeader = parsedProt;\n }\n if (jws.header !== undefined) {\n result.unprotectedHeader = jws.header;\n }\n if (resolvedKey) {\n return { ...result, key: k };\n }\n return result;\n}\n","import { flattenedVerify } from '../flattened/verify.js';\nimport { JWSInvalid } from '../../util/errors.js';\nimport { decoder } from '../../lib/buffer_utils.js';\nexport async function compactVerify(jws, key, options) {\n if (jws instanceof Uint8Array) {\n jws = decoder.decode(jws);\n }\n if (typeof jws !== 'string') {\n throw new JWSInvalid('Compact JWS must be a string or Uint8Array');\n }\n const { 0: protectedHeader, 1: payload, 2: signature, length } = jws.split('.');\n if (length !== 3) {\n throw new JWSInvalid('Invalid Compact JWS');\n }\n const verified = await flattenedVerify({ payload, protected: protectedHeader, signature }, key, options);\n const result = { payload: verified.payload, protectedHeader: verified.protectedHeader };\n if (typeof key === 'function') {\n return { ...result, key: verified.key };\n }\n return result;\n}\n","import { JWTClaimValidationFailed, JWTExpired, JWTInvalid } from '../util/errors.js';\nimport { encoder, decoder } from './buffer_utils.js';\nimport { isObject } from './is_object.js';\nconst epoch = (date) => Math.floor(date.getTime() / 1000);\nconst minute = 60;\nconst hour = minute * 60;\nconst day = hour * 24;\nconst week = day * 7;\nconst year = day * 365.25;\nconst REGEX = /^(\\+|\\-)? ?(\\d+|\\d+\\.\\d+) ?(seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)(?: (ago|from now))?$/i;\nexport function secs(str) {\n const matched = REGEX.exec(str);\n if (!matched || (matched[4] && matched[1])) {\n throw new TypeError('Invalid time period format');\n }\n const value = parseFloat(matched[2]);\n const unit = matched[3].toLowerCase();\n let numericDate;\n switch (unit) {\n case 'sec':\n case 'secs':\n case 'second':\n case 'seconds':\n case 's':\n numericDate = Math.round(value);\n break;\n case 'minute':\n case 'minutes':\n case 'min':\n case 'mins':\n case 'm':\n numericDate = Math.round(value * minute);\n break;\n case 'hour':\n case 'hours':\n case 'hr':\n case 'hrs':\n case 'h':\n numericDate = Math.round(value * hour);\n break;\n case 'day':\n case 'days':\n case 'd':\n numericDate = Math.round(value * day);\n break;\n case 'week':\n case 'weeks':\n case 'w':\n numericDate = Math.round(value * week);\n break;\n default:\n numericDate = Math.round(value * year);\n break;\n }\n if (matched[1] === '-' || matched[4] === 'ago') {\n return -numericDate;\n }\n return numericDate;\n}\nfunction validateInput(label, input) {\n if (!Number.isFinite(input)) {\n throw new TypeError(`Invalid ${label} input`);\n }\n return input;\n}\nconst normalizeTyp = (value) => {\n if (value.includes('/')) {\n return value.toLowerCase();\n }\n return `application/${value.toLowerCase()}`;\n};\nconst checkAudiencePresence = (audPayload, audOption) => {\n if (typeof audPayload === 'string') {\n return audOption.includes(audPayload);\n }\n if (Array.isArray(audPayload)) {\n return audOption.some(Set.prototype.has.bind(new Set(audPayload)));\n }\n return false;\n};\nexport function validateClaimsSet(protectedHeader, encodedPayload, options = {}) {\n let payload;\n try {\n payload = JSON.parse(decoder.decode(encodedPayload));\n }\n catch {\n }\n if (!isObject(payload)) {\n throw new JWTInvalid('JWT Claims Set must be a top-level JSON object');\n }\n const { typ } = options;\n if (typ &&\n (typeof protectedHeader.typ !== 'string' ||\n normalizeTyp(protectedHeader.typ) !== normalizeTyp(typ))) {\n throw new JWTClaimValidationFailed('unexpected \"typ\" JWT header value', payload, 'typ', 'check_failed');\n }\n const { requiredClaims = [], issuer, subject, audience, maxTokenAge } = options;\n const presenceCheck = [...requiredClaims];\n if (maxTokenAge !== undefined)\n presenceCheck.push('iat');\n if (audience !== undefined)\n presenceCheck.push('aud');\n if (subject !== undefined)\n presenceCheck.push('sub');\n if (issuer !== undefined)\n presenceCheck.push('iss');\n for (const claim of new Set(presenceCheck.reverse())) {\n if (!(claim in payload)) {\n throw new JWTClaimValidationFailed(`missing required \"${claim}\" claim`, payload, claim, 'missing');\n }\n }\n if (issuer &&\n !(Array.isArray(issuer) ? issuer : [issuer]).includes(payload.iss)) {\n throw new JWTClaimValidationFailed('unexpected \"iss\" claim value', payload, 'iss', 'check_failed');\n }\n if (subject && payload.sub !== subject) {\n throw new JWTClaimValidationFailed('unexpected \"sub\" claim value', payload, 'sub', 'check_failed');\n }\n if (audience &&\n !checkAudiencePresence(payload.aud, typeof audience === 'string' ? [audience] : audience)) {\n throw new JWTClaimValidationFailed('unexpected \"aud\" claim value', payload, 'aud', 'check_failed');\n }\n let tolerance;\n switch (typeof options.clockTolerance) {\n case 'string':\n tolerance = secs(options.clockTolerance);\n break;\n case 'number':\n tolerance = options.clockTolerance;\n break;\n case 'undefined':\n tolerance = 0;\n break;\n default:\n throw new TypeError('Invalid clockTolerance option type');\n }\n const { currentDate } = options;\n const now = epoch(currentDate || new Date());\n if ((payload.iat !== undefined || maxTokenAge) && typeof payload.iat !== 'number') {\n throw new JWTClaimValidationFailed('\"iat\" claim must be a number', payload, 'iat', 'invalid');\n }\n if (payload.nbf !== undefined) {\n if (typeof payload.nbf !== 'number') {\n throw new JWTClaimValidationFailed('\"nbf\" claim must be a number', payload, 'nbf', 'invalid');\n }\n if (payload.nbf > now + tolerance) {\n throw new JWTClaimValidationFailed('\"nbf\" claim timestamp check failed', payload, 'nbf', 'check_failed');\n }\n }\n if (payload.exp !== undefined) {\n if (typeof payload.exp !== 'number') {\n throw new JWTClaimValidationFailed('\"exp\" claim must be a number', payload, 'exp', 'invalid');\n }\n if (payload.exp <= now - tolerance) {\n throw new JWTExpired('\"exp\" claim timestamp check failed', payload, 'exp', 'check_failed');\n }\n }\n if (maxTokenAge) {\n const age = now - payload.iat;\n const max = typeof maxTokenAge === 'number' ? maxTokenAge : secs(maxTokenAge);\n if (age - tolerance > max) {\n throw new JWTExpired('\"iat\" claim timestamp check failed (too far in the past)', payload, 'iat', 'check_failed');\n }\n if (age < 0 - tolerance) {\n throw new JWTClaimValidationFailed('\"iat\" claim timestamp check failed (it should be in the past)', payload, 'iat', 'check_failed');\n }\n }\n return payload;\n}\nexport class JWTClaimsBuilder {\n #payload;\n constructor(payload) {\n if (!isObject(payload)) {\n throw new TypeError('JWT Claims Set MUST be an object');\n }\n this.#payload = structuredClone(payload);\n }\n data() {\n return encoder.encode(JSON.stringify(this.#payload));\n }\n get iss() {\n return this.#payload.iss;\n }\n set iss(value) {\n this.#payload.iss = value;\n }\n get sub() {\n return this.#payload.sub;\n }\n set sub(value) {\n this.#payload.sub = value;\n }\n get aud() {\n return this.#payload.aud;\n }\n set aud(value) {\n this.#payload.aud = value;\n }\n set jti(value) {\n this.#payload.jti = value;\n }\n set nbf(value) {\n if (typeof value === 'number') {\n this.#payload.nbf = validateInput('setNotBefore', value);\n }\n else if (value instanceof Date) {\n this.#payload.nbf = validateInput('setNotBefore', epoch(value));\n }\n else {\n this.#payload.nbf = epoch(new Date()) + secs(value);\n }\n }\n set exp(value) {\n if (typeof value === 'number') {\n this.#payload.exp = validateInput('setExpirationTime', value);\n }\n else if (value instanceof Date) {\n this.#payload.exp = validateInput('setExpirationTime', epoch(value));\n }\n else {\n this.#payload.exp = epoch(new Date()) + secs(value);\n }\n }\n set iat(value) {\n if (value === undefined) {\n this.#payload.iat = epoch(new Date());\n }\n else if (value instanceof Date) {\n this.#payload.iat = validateInput('setIssuedAt', epoch(value));\n }\n else if (typeof value === 'string') {\n this.#payload.iat = validateInput('setIssuedAt', epoch(new Date()) + secs(value));\n }\n else {\n this.#payload.iat = validateInput('setIssuedAt', value);\n }\n }\n}\n","import { compactVerify } from '../jws/compact/verify.js';\nimport { validateClaimsSet } from '../lib/jwt_claims_set.js';\nimport { JWTInvalid } from '../util/errors.js';\nexport async function jwtVerify(jwt, key, options) {\n const verified = await compactVerify(jwt, key, options);\n if (verified.protectedHeader.crit?.includes('b64') && verified.protectedHeader.b64 === false) {\n throw new JWTInvalid('JWTs MUST NOT use unencoded payload');\n }\n const payload = validateClaimsSet(verified.protectedHeader, verified.payload, options);\n const result = { payload, protectedHeader: verified.protectedHeader };\n if (typeof key === 'function') {\n return { ...result, key: verified.key };\n }\n return result;\n}\n","/**\n * Sylphx Server SDK\n *\n * Server-side operations using REST API for type safety.\n * Uses Secret Key for authentication - NEVER expose this to client-side.\n *\n * @example\n * ```typescript\n * import { createServerClient, verifyWebhook } from '@sylphx/sdk/server'\n *\n * const client = createServerClient({\n * secretKey: process.env.SYLPHX_SECRET_KEY!,\n * })\n *\n * // REST API calls\n * const { data: plans } = await client.GET('/billing/plans')\n * const { data: user } = await client.GET('/user/profile')\n * ```\n */\n\nimport { importJWK, type JWTPayload, jwtVerify } from 'jose'\nimport { JWK_CACHE_TTL_MS, WEBHOOK_CLOCK_SKEW_MS, WEBHOOK_MAX_AGE_MS } from '../constants'\nimport {\n\tcreateDynamicRestClient,\n\tcreateRestClient,\n\ttype RestClient,\n\ttype RestClientConfig,\n} from '../rest-client'\nimport type { AccessTokenPayload } from '../types'\n\n// Re-export key validation utilities from SSOT\nexport {\n\t// Environment detection\n\tdetectEnvironment,\n\t// Key type detection\n\tdetectKeyType,\n\t// Types\n\ttype EnvironmentType,\n\t// Cookie namespace\n\tgetCookieNamespace,\n\tisAppId,\n\tisDevelopmentKey,\n\t// Runtime detection\n\tisDevelopmentRuntime,\n\tisProductionKey,\n\tisSecretKey,\n\ttype KeyType,\n\ttype KeyValidationResult,\n\tvalidateAndSanitizeAppId,\n\tvalidateAndSanitizeKey,\n\tvalidateAndSanitizeSecretKey,\n\t// App ID validation\n\tvalidateAppId,\n\t// Generic key validation (auto-detects type)\n\tvalidateKey,\n\t// Secret key validation\n\tvalidateSecretKey,\n} from '../key-validation'\n\n// Internal import for local use (import separately to avoid hoisting issues)\nimport {\n\tdetectEnvironment as _detectEnvironment,\n\tvalidateAndSanitizeAppId,\n\tvalidateAndSanitizeSecretKey,\n} from '../key-validation'\n\n// ============================================================================\n// Configuration\n// ============================================================================\n\n// Note: EnvironmentType, detectEnvironment, isDevelopmentKey, isProductionKey\n// are re-exported from '../key-validation' (SSOT)\n\nexport interface ServerConfig {\n\t/**\n\t * Your Secret Key (keep secure, server-only)\n\t *\n\t * The secret key IS the app identity — no separate app ID needed.\n\t * Use environment-specific keys for proper isolation:\n\t * - Development: sk_dev_xxx (relaxed rate limits, test mode)\n\t * - Staging: sk_stg_xxx (test mode, production-like settings)\n\t * - Production: sk_prod_xxx (strict settings, live data)\n\t */\n\tsecretKey: string\n\t/** Platform URL (defaults to https://sylphx.com) */\n\tplatformUrl?: string\n\t/** Optional cache TTL in seconds. Default: 60 */\n\trevalidate?: number\n}\n\n// ============================================================================\n// Server Client\n// ============================================================================\n\n/**\n * Create a Server Client for platform operations.\n *\n * Uses REST API for type-safe API calls.\n * The secret key identifies the app — no separate app ID needed.\n *\n * @example\n * ```typescript\n * const client = createServerClient({\n * secretKey: process.env.SYLPHX_SECRET_KEY!,\n * })\n *\n * // Billing\n * const { data: plans } = await client.GET('/billing/plans')\n * const { data: subscription } = await client.GET('/billing/subscription')\n *\n * // Analytics\n * await client.POST('/analytics/track', {\n * body: { events: [{ event: 'purchase', properties: { amount: 99 } }] }\n * })\n * ```\n */\nexport function createServerClient(config: ServerConfig): RestClient {\n\t// Validate and sanitize secret key using SSOT\n\tconst secretKey = validateAndSanitizeSecretKey(config.secretKey)\n\n\treturn createRestClient({\n\t\tsecretKey,\n\t\tplatformUrl: config.platformUrl?.trim(),\n\t})\n}\n\n/**\n * Create a Server Client with user context (access token)\n */\nexport function createAuthenticatedServerClient(\n\tconfig: ServerConfig,\n\taccessToken: string,\n): RestClient {\n\treturn createDynamicRestClient({\n\t\tsecretKey: config.secretKey,\n\t\tplatformUrl: config.platformUrl,\n\t\tgetAccessToken: () => accessToken,\n\t})\n}\n\n// ============================================================================\n// JWT Verification\n// ============================================================================\n\n/** JWKS Response structure */\ninterface JwksResponse {\n\tkeys: JsonWebKey[]\n}\n\n/** Type guard to validate JWKS response */\nfunction isJwksResponse(data: unknown): data is JwksResponse {\n\treturn (\n\t\ttypeof data === 'object' &&\n\t\tdata !== null &&\n\t\t'keys' in data &&\n\t\tArray.isArray((data as JwksResponse).keys)\n\t)\n}\n\n/** Type guard to validate AccessTokenPayload */\nfunction isAccessTokenPayload(payload: JWTPayload): payload is JWTPayload & AccessTokenPayload {\n\treturn (\n\t\ttypeof payload.sub === 'string' &&\n\t\ttypeof payload.email === 'string' &&\n\t\ttypeof payload.app_id === 'string' &&\n\t\ttypeof payload.iat === 'number' &&\n\t\ttypeof payload.exp === 'number'\n\t)\n}\n\n// Cache for JWKS\nlet jwksCache: { keys: JsonWebKey[]; expiresAt: number } | null = null\n\n/**\n * Fetch JWKS from the platform\n */\nexport async function getJwks(platformUrl = DEFAULT_PLATFORM_URL): Promise<JsonWebKey[]> {\n\tconst now = Date.now()\n\n\tif (jwksCache && jwksCache.expiresAt > now) {\n\t\treturn jwksCache.keys\n\t}\n\n\tconst response = await fetch(`${platformUrl}/api/v1/auth/.well-known/jwks.json`)\n\tif (!response.ok) {\n\t\tthrow new Error('Failed to fetch JWKS')\n\t}\n\n\tconst data: unknown = await response.json()\n\tif (!isJwksResponse(data)) {\n\t\tthrow new Error('Invalid JWKS response format')\n\t}\n\n\tjwksCache = {\n\t\tkeys: data.keys,\n\t\texpiresAt: now + JWK_CACHE_TTL_MS, // Cache for 1 hour\n\t}\n\n\treturn data.keys\n}\n\n/**\n * Verify an access token from the platform\n */\nexport async function verifyAccessToken(\n\ttoken: string,\n\toptions: {\n\t\tsecretKey?: string\n\t\tplatformUrl?: string\n\t},\n): Promise<AccessTokenPayload> {\n\tconst platformUrl = options.platformUrl || DEFAULT_PLATFORM_URL\n\tconst keys = await getJwks(platformUrl)\n\n\tif (!keys.length) {\n\t\tthrow new Error('No keys in JWKS')\n\t}\n\n\t// Try each key until one works.\n\t// Audience validation is handled by the platform when tokens are issued —\n\t// the SDK verifies cryptographic signature and issuer only.\n\tlet lastError: Error | null = null\n\tfor (const key of keys) {\n\t\ttry {\n\t\t\tconst jwk = await importJWK(key, 'RS256')\n\t\t\tconst { payload } = await jwtVerify(token, jwk, {\n\t\t\t\tissuer: platformUrl,\n\t\t\t})\n\n\t\t\t// Validate payload structure at runtime\n\t\t\tif (!isAccessTokenPayload(payload)) {\n\t\t\t\tthrow new Error('Invalid token payload structure')\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tsub: payload.sub,\n\t\t\t\temail: payload.email,\n\t\t\t\tname: payload.name,\n\t\t\t\tpicture: payload.picture,\n\t\t\t\temail_verified: payload.email_verified,\n\t\t\t\tapp_id: payload.app_id,\n\t\t\t\trole: payload.role,\n\t\t\t\tiat: payload.iat,\n\t\t\t\texp: payload.exp,\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tlastError = err as Error\n\t\t}\n\t}\n\n\tthrow lastError || new Error('Token verification failed')\n}\n\n// ============================================================================\n// Webhook Signature Verification\n// ============================================================================\n\nexport interface WebhookPayload {\n\tevent: string\n\tdata: unknown\n\ttimestamp: number\n\tid: string\n}\n\nexport interface WebhookVerifyResult {\n\tvalid: boolean\n\tpayload?: WebhookPayload\n\terror?: string\n}\n\nexport interface WebhookVerifyOptions {\n\t/** Maximum age of webhook in milliseconds (default: 5 minutes) */\n\tmaxAge?: number\n\t/** Allow clock skew in milliseconds (default: 30 seconds) */\n\tclockSkew?: number\n}\n\n/**\n * Verify webhook signature from Sylphx Platform\n *\n * The platform sends `X-Webhook-Signature` in `t={unix_seconds},v1={hmac_hex}`\n * format. This function accepts either:\n * - The raw header value (auto-parsed)\n * - Pre-extracted `signature` + `timestamp` strings\n *\n * @example\n * ```typescript\n * import { verifyWebhook } from '@sylphx/sdk/server'\n *\n * export async function POST(request: Request) {\n * const body = await request.text()\n * const result = await verifyWebhook({\n * payload: body,\n * signatureHeader: request.headers.get('x-webhook-signature'),\n * secret: process.env.SYLPHX_SECRET_KEY!,\n * })\n *\n * if (!result.valid) {\n * return new Response('Invalid signature', { status: 401 })\n * }\n *\n * console.log('Received webhook:', result.payload)\n * }\n * ```\n */\nexport async function verifyWebhook(options: {\n\tpayload: string\n\t/** Raw X-Webhook-Signature header value: \"t={seconds},v1={hex}\" */\n\tsignatureHeader?: string | null\n\t/** Pre-extracted HMAC hex (if parsing header yourself) */\n\tsignature?: string | null\n\t/** Pre-extracted timestamp in unix seconds (if parsing header yourself) */\n\ttimestamp?: string | null\n\tsecret: string\n\tverifyOptions?: WebhookVerifyOptions\n}): Promise<WebhookVerifyResult> {\n\tconst { payload, secret, verifyOptions = {} } = options\n\tconst { maxAge = WEBHOOK_MAX_AGE_MS, clockSkew = WEBHOOK_CLOCK_SKEW_MS } = verifyOptions\n\n\t// Parse the combined header format: \"t={seconds},v1={hex}\"\n\tlet signatureHex = options.signature ?? null\n\tlet timestampStr = options.timestamp ?? null\n\n\tif (options.signatureHeader) {\n\t\tconst tMatch = options.signatureHeader.match(/t=(\\d+)/)\n\t\tconst vMatch = options.signatureHeader.match(/v1=([a-f0-9]+)/)\n\t\tif (tMatch) timestampStr = tMatch[1]\n\t\tif (vMatch) signatureHex = vMatch[1]\n\t}\n\n\tif (!signatureHex) {\n\t\treturn { valid: false, error: 'Missing signature' }\n\t}\n\tif (!timestampStr) {\n\t\treturn { valid: false, error: 'Missing timestamp' }\n\t}\n\n\tconst webhookTimeSeconds = Number.parseInt(timestampStr, 10)\n\tif (Number.isNaN(webhookTimeSeconds)) {\n\t\treturn { valid: false, error: 'Invalid timestamp format' }\n\t}\n\n\t// Convert seconds → milliseconds for comparison with Date.now()\n\tconst webhookTimeMs = webhookTimeSeconds * 1000\n\tconst now = Date.now()\n\tconst age = now - webhookTimeMs\n\n\tif (age > maxAge) {\n\t\treturn { valid: false, error: `Webhook too old: ${age}ms` }\n\t}\n\n\tif (age < -clockSkew) {\n\t\treturn { valid: false, error: 'Webhook timestamp is in the future' }\n\t}\n\n\t// Reconstruct the signed payload: \"{seconds}.{body}\"\n\tconst signedPayload = `${timestampStr}.${payload}`\n\n\ttry {\n\t\tconst expectedSignature = await computeHmacSha256(signedPayload, secret)\n\n\t\tif (!timingSafeEqual(signatureHex, expectedSignature)) {\n\t\t\treturn { valid: false, error: 'Invalid signature' }\n\t\t}\n\n\t\tconst parsedPayload = JSON.parse(payload) as WebhookPayload\n\t\treturn { valid: true, payload: parsedPayload }\n\t} catch (error) {\n\t\treturn {\n\t\t\tvalid: false,\n\t\t\terror: error instanceof Error ? error.message : 'Verification failed',\n\t\t}\n\t}\n}\n\nasync function computeHmacSha256(message: string, secret: string): Promise<string> {\n\tconst encoder = new TextEncoder()\n\tconst keyData = encoder.encode(secret)\n\tconst messageData = encoder.encode(message)\n\n\tconst cryptoKey = await crypto.subtle.importKey(\n\t\t'raw',\n\t\tkeyData,\n\t\t{ name: 'HMAC', hash: 'SHA-256' },\n\t\tfalse,\n\t\t['sign'],\n\t)\n\n\tconst signature = await crypto.subtle.sign('HMAC', cryptoKey, messageData)\n\treturn Buffer.from(signature).toString('hex')\n}\n\nfunction timingSafeEqual(a: string, b: string): boolean {\n\t// Compare against b if lengths match, otherwise compare a against itself.\n\t// This prevents timing side-channel leaks: the loop always runs a.length\n\t// iterations regardless of whether lengths match, so an attacker cannot\n\t// infer b's length from response time.\n\tconst target = a.length === b.length ? b : a\n\tlet result = a.length ^ b.length // Non-zero if lengths differ\n\tfor (let i = 0; i < a.length; i++) {\n\t\tresult |= a.charCodeAt(i) ^ target.charCodeAt(i)\n\t}\n\treturn result === 0\n}\n\n/**\n * Create a webhook handler with automatic verification\n *\n * @example\n * ```typescript\n * import { createWebhookHandler } from '@sylphx/sdk/server'\n *\n * const handler = createWebhookHandler({\n * secret: process.env.SYLPHX_SECRET_KEY!,\n * handlers: {\n * 'user.created': async (data) => {\n * console.log('New user:', data)\n * },\n * 'subscription.updated': async (data) => {\n * console.log('Subscription changed:', data)\n * },\n * },\n * })\n *\n * export { handler as POST }\n * ```\n */\nexport function createWebhookHandler(config: {\n\tsecret: string\n\thandlers: Record<string, (data: unknown) => Promise<void> | void>\n\tverifyOptions?: WebhookVerifyOptions\n}): (request: Request) => Promise<Response> {\n\treturn async (request: Request) => {\n\t\tconst signatureHeader = request.headers.get('x-webhook-signature')\n\t\tconst body = await request.text()\n\n\t\tconst result = await verifyWebhook({\n\t\t\tpayload: body,\n\t\t\tsignatureHeader,\n\t\t\tsecret: config.secret,\n\t\t\tverifyOptions: config.verifyOptions,\n\t\t})\n\n\t\tif (!result.valid) {\n\t\t\treturn new Response(JSON.stringify({ error: result.error }), {\n\t\t\t\tstatus: 401,\n\t\t\t\theaders: { 'Content-Type': 'application/json' },\n\t\t\t})\n\t\t}\n\n\t\tif (!result.payload) {\n\t\t\treturn new Response(JSON.stringify({ error: 'Missing payload' }), {\n\t\t\t\tstatus: 400,\n\t\t\t\theaders: { 'Content-Type': 'application/json' },\n\t\t\t})\n\t\t}\n\n\t\tconst { event, data } = result.payload\n\t\tconst handler = config.handlers[event]\n\n\t\tif (!handler) {\n\t\t\treturn new Response(JSON.stringify({ received: true, handled: false }), {\n\t\t\t\tstatus: 200,\n\t\t\t\theaders: { 'Content-Type': 'application/json' },\n\t\t\t})\n\t\t}\n\n\t\ttry {\n\t\t\tawait handler(data)\n\t\t\treturn new Response(JSON.stringify({ received: true, handled: true }), {\n\t\t\t\tstatus: 200,\n\t\t\t\theaders: { 'Content-Type': 'application/json' },\n\t\t\t})\n\t\t} catch (error) {\n\t\t\treturn new Response(\n\t\t\t\tJSON.stringify({\n\t\t\t\t\terror: 'Handler failed',\n\t\t\t\t\tmessage: error instanceof Error ? error.message : 'Unknown error',\n\t\t\t\t}),\n\t\t\t\t{\n\t\t\t\t\tstatus: 500,\n\t\t\t\t\theaders: { 'Content-Type': 'application/json' },\n\t\t\t\t},\n\t\t\t)\n\t\t}\n\t}\n}\n\n// Re-export types\nexport type { RestClient, RestClientConfig as ServerClientConfig }\n\n// ============================================================================\n// Server-Side Data Fetching — Shared Infrastructure\n// ============================================================================\n\nimport { DEFAULT_PLATFORM_URL, SDK_API_PATH } from '../constants'\n\n/** Common options for authenticated SDK fetch — secret key identifies the app */\ninterface AuthenticatedFetchOptions {\n\t/** Secret key for authentication (sk_dev_xxx, sk_stg_xxx, sk_prod_xxx) */\n\tsecretKey: string\n\t/** Platform URL (defaults to https://sylphx.com) */\n\tplatformUrl?: string\n\t/** Optional cache TTL in seconds. Default: 60 */\n\trevalidate?: number\n}\n\n/**\n * Options for public endpoints that only need an App ID (public key).\n * The App ID IS the app identity — no separate key needed.\n */\ninterface PublicFetchOptions {\n\t/** App ID (app_dev_xxx, app_stg_xxx, app_prod_xxx) — identifies the app */\n\tappId: string\n\t/** Platform URL (defaults to https://sylphx.com) */\n\tplatformUrl?: string\n\t/** Optional cache TTL in seconds. Default: 60 */\n\trevalidate?: number\n}\n\n/**\n * Fetch config data with NO CACHE.\n *\n * Config data (OAuth providers, plans, flags) must reflect admin changes immediately.\n * Using `cache: 'no-store'` ensures every request hits the origin.\n *\n * The API endpoint itself returns Cache-Control headers for CDN caching (60s),\n * but the Next.js Data Cache is bypassed to ensure fresh data on each SSR.\n *\n * Trade-off: Slightly higher latency per request, but config is always fresh.\n * This is the industry standard (Clerk, Auth0, Firebase) for auth config.\n */\nasync function cachedFetch<T>(params: {\n\turl: string\n\theaders?: Record<string, string>\n\tfallback: T\n\tlabel: string\n\trevalidate?: number\n}): Promise<T> {\n\tconst { url, headers, fallback, label, revalidate = 60 } = params\n\n\ttry {\n\t\tconst response = await fetch(url, {\n\t\t\theaders,\n\t\t\t// @ts-expect-error - Next.js extended fetch option\n\t\t\tnext: { revalidate }, // Next.js Data Cache with TTL\n\t\t})\n\n\t\tif (!response.ok) {\n\t\t\tconsole.warn(`[Sylphx] Failed to fetch ${label}:`, response.status)\n\t\t\treturn fallback\n\t\t}\n\n\t\tconst data = await response.json()\n\t\treturn (data as T) ?? fallback\n\t} catch (error) {\n\t\tconsole.warn(`[Sylphx] Failed to fetch ${label}:`, error)\n\t\treturn fallback\n\t}\n}\n\n/**\n * Sanitize options using SSOT key validation\n * Validates secretKey format and trims platformUrl\n */\nfunction sanitizeOptions<T extends AuthenticatedFetchOptions>(options: T): T {\n\treturn {\n\t\t...options,\n\t\tsecretKey: validateAndSanitizeSecretKey(options.secretKey),\n\t\tplatformUrl: (options.platformUrl ?? DEFAULT_PLATFORM_URL).trim(),\n\t}\n}\n\n/** Build authenticated headers for SDK API calls — secret key identifies the app */\nfunction sdkHeaders(secretKey: string): Record<string, string> {\n\treturn { 'x-app-secret': secretKey }\n}\n\n// ============================================================================\n// OAuth Providers (Server-Side)\n// ============================================================================\n\nimport type { OAuthProvider } from '@sylphx/ui'\nexport type { OAuthProvider }\n\n/** OAuth provider with display name */\nexport interface OAuthProviderInfo {\n\tid: OAuthProvider\n\tname: string\n}\n\n/**\n * Get enabled OAuth providers for an app (server-side)\n *\n * The App ID identifies the app via `X-App-Id` header.\n *\n * @example\n * ```tsx\n * const providers = await getOAuthProviders({\n * appId: process.env.NEXT_PUBLIC_SYLPHX_APP_ID!,\n * })\n * ```\n */\nexport async function getOAuthProviders(options: PublicFetchOptions): Promise<OAuthProvider[]> {\n\tconst data = await fetchOAuthProviders(options)\n\treturn (data.providers || []).map((p) => p.id)\n}\n\n/**\n * Get enabled OAuth providers with full info (server-side)\n */\nexport async function getOAuthProvidersWithInfo(\n\toptions: PublicFetchOptions,\n): Promise<OAuthProviderInfo[]> {\n\tconst data = await fetchOAuthProviders(options)\n\treturn data.providers || []\n}\n\n/** Shared fetch for OAuth providers — App ID header identifies the app */\nasync function fetchOAuthProviders(\n\toptions: PublicFetchOptions,\n): Promise<{ providers: OAuthProviderInfo[] }> {\n\tconst baseURL = (options.platformUrl ?? DEFAULT_PLATFORM_URL).trim()\n\t// Validate and sanitize App ID - logs warning if key contains whitespace\n\tconst appId = validateAndSanitizeAppId(options.appId)\n\n\treturn cachedFetch<{ providers: OAuthProviderInfo[] }>({\n\t\turl: `${baseURL}/api/auth/providers`,\n\t\theaders: { 'X-App-Id': appId },\n\t\tfallback: { providers: [] },\n\t\tlabel: 'OAuth providers',\n\t})\n}\n\n// ============================================================================\n// Plans (Server-Side)\n// ============================================================================\n\nimport type { Plan } from '../billing'\nexport type { Plan }\n\n/**\n * Get subscription plans for an app (server-side)\n *\n * Note: Prefer using `getAppConfig()` which fetches all config in parallel.\n * This function is used internally by `getAppConfig()`.\n */\nexport async function getPlans(options: AuthenticatedFetchOptions): Promise<Plan[]> {\n\tconst { secretKey, platformUrl = DEFAULT_PLATFORM_URL } = sanitizeOptions(options)\n\n\treturn cachedFetch<Plan[]>({\n\t\turl: `${platformUrl}${SDK_API_PATH}/billing/plans`,\n\t\theaders: sdkHeaders(secretKey),\n\t\tfallback: [],\n\t\tlabel: 'plans',\n\t})\n}\n\n// ============================================================================\n// Consent Types (Server-Side)\n// ============================================================================\n\nimport type { ConsentType } from '../consent'\nexport type { ConsentType }\n\n/**\n * Get consent types for an app (server-side)\n *\n * Note: Prefer using `getAppConfig()` which fetches all config in parallel.\n * This function is used internally by `getAppConfig()`.\n */\nexport async function getConsentTypes(options: AuthenticatedFetchOptions): Promise<ConsentType[]> {\n\tconst { secretKey, platformUrl = DEFAULT_PLATFORM_URL } = sanitizeOptions(options)\n\n\treturn cachedFetch<ConsentType[]>({\n\t\turl: `${platformUrl}${SDK_API_PATH}/consent/types`,\n\t\theaders: sdkHeaders(secretKey),\n\t\tfallback: [],\n\t\tlabel: 'consent types',\n\t})\n}\n\n// ============================================================================\n// Feature Flags (Server-Side)\n// ============================================================================\n\n/** Feature flag definition for SSR */\nexport interface FeatureFlagDefinition {\n\tkey: string\n\tname: string\n\tdescription: string | null\n\tenabled: boolean\n\trolloutPercentage: number\n\ttargetPremiumOnly: boolean\n\ttargetAdminOnly: boolean\n}\n\n/**\n * Get feature flag definitions for an app (server-side)\n *\n * Returns flag definitions. Evaluation (rollout, targeting) happens\n * client-side using the LocalEvaluator with user context.\n *\n * @example\n * ```tsx\n * import { getFeatureFlags } from '@sylphx/sdk/server'\n *\n * export default async function RootLayout({ children }) {\n * const flags = await getFeatureFlags({\n * secretKey: process.env.SYLPHX_SECRET_KEY!,\n * })\n * return <FeatureFlagsProvider initialFlags={flags}>{children}</FeatureFlagsProvider>\n * }\n * ```\n */\nexport async function getFeatureFlags(\n\toptions: AuthenticatedFetchOptions,\n): Promise<FeatureFlagDefinition[]> {\n\tconst { secretKey, platformUrl = DEFAULT_PLATFORM_URL } = sanitizeOptions(options)\n\n\treturn cachedFetch<FeatureFlagDefinition[]>({\n\t\turl: `${platformUrl}${SDK_API_PATH}/flags`,\n\t\theaders: sdkHeaders(secretKey),\n\t\tfallback: [],\n\t\tlabel: 'feature flags',\n\t})\n}\n\n// ============================================================================\n// App Metadata (Server-Side)\n// ============================================================================\n\n/** App metadata returned by /api/sdk/app */\nexport interface AppMetadata {\n\tid: string\n\tname: string\n\tslug: string\n}\n\n/**\n * Get app metadata (server-side)\n *\n * @internal Used by getAppConfig() - rarely called directly\n */\nexport async function getAppMetadata(options: AuthenticatedFetchOptions): Promise<AppMetadata> {\n\tconst { secretKey, platformUrl = DEFAULT_PLATFORM_URL } = sanitizeOptions(options)\n\n\treturn cachedFetch<AppMetadata>({\n\t\turl: `${platformUrl}${SDK_API_PATH}/app`,\n\t\theaders: sdkHeaders(secretKey),\n\t\tfallback: { id: '', name: '', slug: '' },\n\t\tlabel: 'app metadata',\n\t})\n}\n\n// ============================================================================\n// AppConfig — Server-First Configuration\n// ============================================================================\n// The recommended way to initialize the SDK. Fetches all config data in parallel\n// from Server Components, then passes it to SylphxProvider as a required prop.\n\nimport type { AppConfig, OAuthProviderInfo as OAuthProviderInfoType } from '../types'\nexport type { AppConfig }\n\n/**\n * Options for getAppConfig()\n */\nexport interface GetAppConfigOptions {\n\t/** Secret key for authenticated endpoints (plans, flags, consent types) */\n\tsecretKey: string\n\t/** App ID for public endpoints (OAuth providers) - identifies your app */\n\tappId: string\n\t/** Platform URL (defaults to https://sylphx.com) */\n\tplatformUrl?: string\n\t/** Optional cache TTL in seconds. Default: 60 */\n\trevalidate?: number\n}\n\n/**\n * Get complete app configuration for the SDK (server-side)\n *\n * This is the **recommended** way to initialize the Sylphx SDK. It fetches all\n * configuration data in a single call from a Server Component, eliminating the\n * need for client-side config fetching and the associated loading states.\n *\n * Returns:\n * - plans: Subscription plans for billing\n * - consentTypes: GDPR/CCPA consent configuration\n * - oauthProviders: Enabled OAuth providers for auth\n * - featureFlags: Feature flag definitions for client-side evaluation\n * - app: App metadata (id, name, slug)\n * - fetchedAt: ISO timestamp for cache debugging\n *\n * @example\n * ```tsx\n * // app/layout.tsx (Server Component)\n * import { getAppConfig } from '@sylphx/sdk/server'\n *\n * export default async function RootLayout({ children }) {\n * const config = await getAppConfig({\n * secretKey: process.env.SYLPHX_SECRET_KEY!,\n * appId: process.env.NEXT_PUBLIC_SYLPHX_APP_ID!,\n * })\n *\n * return (\n * <html>\n * <body>\n * <SylphxProvider\n * config={config}\n * appId={process.env.NEXT_PUBLIC_SYLPHX_APP_ID!}\n * >\n * {children}\n * </SylphxProvider>\n * </body>\n * </html>\n * )\n * }\n * ```\n */\nexport async function getAppConfig(options: GetAppConfigOptions): Promise<AppConfig> {\n\tconst { secretKey, appId, platformUrl } = options\n\n\t// Fetch all config data in parallel for optimal performance\n\tconst [plans, consentTypes, oauthProviders, featureFlags, app] = await Promise.all([\n\t\tgetPlans({ secretKey, platformUrl }),\n\t\tgetConsentTypes({ secretKey, platformUrl }),\n\t\tgetOAuthProvidersWithInfo({ appId, platformUrl }),\n\t\tgetFeatureFlags({ secretKey, platformUrl }),\n\t\tgetAppMetadata({ secretKey, platformUrl }),\n\t])\n\n\treturn {\n\t\tplans,\n\t\tconsentTypes,\n\t\toauthProviders: oauthProviders as OAuthProviderInfoType[],\n\t\tfeatureFlags,\n\t\tapp,\n\t\tfetchedAt: new Date().toISOString(),\n\t}\n}\n\n// ============================================================================\n// Referral Leaderboard (Server-Side)\n// ============================================================================\n\n/** Referral leaderboard entry */\nexport interface ReferralLeaderboardEntry {\n\trank: number\n\tuserId: string\n\t/** Masked username for privacy */\n\tname: string\n\t/** Number of successful referrals */\n\treferrals: number\n\tisCurrentUser: boolean\n}\n\n/** Referral leaderboard result */\nexport interface ReferralLeaderboardResult {\n\tentries: ReferralLeaderboardEntry[]\n\ttotal: number\n\tperiod: 'all' | 'month' | 'week'\n}\n\n/**\n * Get referral leaderboard for an app (server-side)\n *\n * @example\n * ```tsx\n * import { getReferralLeaderboard } from '@sylphx/sdk/server'\n *\n * export default async function ReferralsPage() {\n * const leaderboard = await getReferralLeaderboard({\n * secretKey: process.env.SYLPHX_SECRET_KEY!,\n * limit: 10,\n * period: 'month',\n * })\n * return <ReferralLeaderboard initialData={leaderboard} />\n * }\n * ```\n */\nexport async function getReferralLeaderboard(\n\toptions: AuthenticatedFetchOptions & {\n\t\tlimit?: number\n\t\tperiod?: 'all' | 'month' | 'week'\n\t},\n): Promise<ReferralLeaderboardResult> {\n\tconst {\n\t\tsecretKey,\n\t\tplatformUrl = DEFAULT_PLATFORM_URL,\n\t\tlimit = 10,\n\t\tperiod = 'all',\n\t} = sanitizeOptions(options)\n\n\tconst url = new URL(`${platformUrl}${SDK_API_PATH}/referrals/leaderboard`)\n\turl.searchParams.set('limit', String(limit))\n\turl.searchParams.set('period', period)\n\n\treturn cachedFetch<ReferralLeaderboardResult>({\n\t\turl: url.toString(),\n\t\theaders: sdkHeaders(secretKey),\n\t\tfallback: { entries: [], total: 0, period },\n\t\tlabel: 'referral leaderboard',\n\t})\n}\n\n// ============================================================================\n// Engagement Leaderboard (Server-Side)\n// ============================================================================\n\n/** Engagement leaderboard entry */\nexport interface EngagementLeaderboardEntry {\n\trank: number\n\tuserId: string\n\tname: string\n\tscore: number\n\tisCurrentUser: boolean\n}\n\n/** Engagement leaderboard result */\nexport interface EngagementLeaderboardResult {\n\tleaderboardId: string\n\tentries: EngagementLeaderboardEntry[]\n\tperiod: string\n\tresetTime: string | null\n\tuserEntry: EngagementLeaderboardEntry | null\n}\n\n/**\n * Get engagement leaderboard for an app (server-side)\n *\n * @example\n * ```tsx\n * import { getEngagementLeaderboard } from '@sylphx/sdk/server'\n *\n * export default async function LeaderboardPage() {\n * const leaderboard = await getEngagementLeaderboard({\n * secretKey: process.env.SYLPHX_SECRET_KEY!,\n * leaderboardId: 'high-scores',\n * })\n * return <Leaderboard initialData={leaderboard} />\n * }\n * ```\n */\nexport async function getEngagementLeaderboard(\n\toptions: AuthenticatedFetchOptions & {\n\t\tleaderboardId: string\n\t\tlimit?: number\n\t},\n): Promise<EngagementLeaderboardResult> {\n\tconst {\n\t\tsecretKey,\n\t\tleaderboardId,\n\t\tplatformUrl = DEFAULT_PLATFORM_URL,\n\t\tlimit = 10,\n\t} = sanitizeOptions(options)\n\n\tconst url = new URL(\n\t\t`${platformUrl}${SDK_API_PATH}/engagement/leaderboards/${encodeURIComponent(leaderboardId)}`,\n\t)\n\turl.searchParams.set('limit', String(limit))\n\n\treturn cachedFetch<EngagementLeaderboardResult>({\n\t\turl: url.toString(),\n\t\theaders: sdkHeaders(secretKey),\n\t\tfallback: {\n\t\t\tleaderboardId,\n\t\t\tentries: [],\n\t\t\tperiod: 'all',\n\t\t\tresetTime: null,\n\t\t\tuserEntry: null,\n\t\t},\n\t\tlabel: 'engagement leaderboard',\n\t})\n}\n\n// ============================================================================\n// Database Connection (Server-Side)\n// ============================================================================\n\n/** Database connection info returned by Platform */\nexport interface DatabaseConnectionInfo {\n\tconnectionString: string\n\tdatabaseName: string\n\troleName: string | null\n\tstatus: 'provisioning' | 'ready' | 'suspended' | 'failed' | 'deleted'\n}\n\n/** Database status info */\nexport interface DatabaseStatusInfo {\n\tstatus: 'provisioning' | 'ready' | 'suspended' | 'failed' | 'deleted' | 'not_provisioned'\n\tregion: string | null\n\tpgVersion: number | null\n\tdatabaseName: string | null\n}\n\n/**\n * Get database connection string from Platform (server-side)\n *\n * Use this when your app's database is provisioned by the Sylphx Platform.\n * The connection string is securely stored on Platform and retrieved at startup.\n *\n * **Note:** This requires NEON_API_KEY and PLATFORM_ENCRYPTION_KEY to be\n * configured on the Platform, and your app's database to be provisioned.\n *\n * @example\n * ```typescript\n * import { getDatabaseConnection } from '@sylphx/sdk/server'\n *\n * // In your database initialization\n * const dbInfo = await getDatabaseConnection({\n * secretKey: process.env.SYLPHX_SECRET_KEY!,\n * })\n *\n * if (dbInfo) {\n * const pool = new Pool({ connectionString: dbInfo.connectionString })\n * }\n * ```\n */\nexport async function getDatabaseConnection(\n\toptions: AuthenticatedFetchOptions,\n): Promise<DatabaseConnectionInfo | null> {\n\tconst { secretKey, platformUrl = DEFAULT_PLATFORM_URL } = sanitizeOptions(options)\n\n\ttry {\n\t\tconst response = await fetch(`${platformUrl}${SDK_API_PATH}/database/connection-string`, {\n\t\t\theaders: sdkHeaders(secretKey),\n\t\t\tcache: 'no-store', // Always fetch fresh connection string\n\t\t})\n\n\t\tif (!response.ok) {\n\t\t\t// 404 means database not provisioned - return null\n\t\t\tif (response.status === 404) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\t// 412 means database not ready (provisioning, suspended, failed)\n\t\t\tif (response.status === 412) {\n\t\t\t\tconsole.warn('[Sylphx] Database not ready:', await response.text())\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconsole.warn('[Sylphx] Failed to fetch database connection:', response.status)\n\t\t\treturn null\n\t\t}\n\n\t\treturn (await response.json()) as DatabaseConnectionInfo\n\t} catch (error) {\n\t\tconsole.warn('[Sylphx] Failed to fetch database connection:', error)\n\t\treturn null\n\t}\n}\n\n/**\n * Get database status from Platform (server-side)\n *\n * Use this to check if your app's database is provisioned and ready.\n *\n * @example\n * ```typescript\n * import { getDatabaseStatus } from '@sylphx/sdk/server'\n *\n * const status = await getDatabaseStatus({\n * secretKey: process.env.SYLPHX_SECRET_KEY!,\n * })\n *\n * if (status?.status === 'ready') {\n * // Database is ready to use\n * }\n * ```\n */\nexport async function getDatabaseStatus(\n\toptions: AuthenticatedFetchOptions,\n): Promise<DatabaseStatusInfo> {\n\tconst { secretKey, platformUrl = DEFAULT_PLATFORM_URL } = sanitizeOptions(options)\n\n\treturn cachedFetch<DatabaseStatusInfo>({\n\t\turl: `${platformUrl}${SDK_API_PATH}/database/status`,\n\t\theaders: sdkHeaders(secretKey),\n\t\tfallback: {\n\t\t\tstatus: 'not_provisioned',\n\t\t\tregion: null,\n\t\t\tpgVersion: null,\n\t\t\tdatabaseName: null,\n\t\t},\n\t\tlabel: 'database status',\n\t})\n}\n\nexport type {\n\tAIClient,\n\tAIClientOptions,\n\tChatCompletionChunk,\n\tChatCompletionOptions,\n\tChatCompletionResponse,\n\tChatCompletionStreamOptions,\n\tChatMessage,\n\tEmbeddingOptions,\n\tEmbeddingResponse,\n\tModelInfo,\n\tModelsResponse,\n} from './ai'\n// AI Client\nexport { createAI, getAI } from './ai'\nexport type {\n\tKvClient,\n\tKvClientOptions,\n\tKvRateLimitResult,\n\tKvSetOptions,\n\tKvZMember,\n} from './kv'\n// KV (Key-Value Store)\nexport { createKv, getKv } from './kv'\nexport type {\n\tChannelHelper,\n\tStreamHistoryOptions,\n\tStreamMessage,\n\tStreamsClient,\n\tStreamsClientOptions,\n} from './streams'\n// Streams (Real-time Pub/Sub)\nexport { createStreams, getStreams } from './streams'\n"],"mappings":"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","names":["handleCallback","data","message","message","isTokenResponse","getCookieNamespace","handleCallback"]}