@sylphx/sdk 0.5.0 → 0.7.0

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/connection-url.ts","../src/constants.ts","../src/errors.ts","../src/config.ts","../src/debug.ts","../src/rest-client.ts","../src/key-validation.ts","../src/auth.ts","../src/admin.ts","../src/analytics.ts","../src/ai.ts","../src/billing.ts","../src/storage.ts","../src/lib/notifications/service-worker.ts","../src/notifications.ts","../src/lib/triggers/index.ts","../src/lib/tasks/handler.ts","../src/lib/tasks/api-functions.ts","../src/flags.ts","../src/webhooks.ts","../src/email.ts","../src/consent.ts","../src/referrals.ts","../src/lib/engagement/types.ts","../src/engagement.ts","../src/orgs.ts","../src/permissions.ts","../src/roles.ts","../src/secrets.ts","../src/search.ts","../src/database.ts","../src/kv.ts","../src/realtime.ts","../src/deploy.ts","../src/monitoring.ts","../src/sandbox.ts","../src/workers.ts"],"sourcesContent":["/**\n * Sylphx Connection URL Parser — SDK Self-Contained Copy\n *\n * Implements the canonical connection string format defined in ADR-055 §5.\n * This is a self-contained copy for SDK package independence (no app imports).\n *\n * Format:\n * sylphx://{credential}@{slug}.{domain}[:port][/v{version}]\n *\n * Examples:\n * sylphx://pk_prod_f19e5cdc3cc54f7ff81bdc26ec5bfbad@bold-river-a1b2c3.sylphx.com\n * sylphx://sk_prod_5120bfeb5120bfeb5120bfeb5120bfeb@bold-river-a1b2c3.sylphx.com/v1\n * sylphx://pk_dev_abc12345abc12345abc12345abc12345@calm-peak-z9x4d5.sylphx.dev\n *\n * Invariants:\n * - Protocol is always `sylphx:` (no exceptions)\n * - Credential matches `(pk|sk)_(dev|stg|prod|prev)_[a-f0-9]{32,64}`\n * - Host's first DNS label is the resource slug (validated by slug regex)\n * - `apiBaseUrl` is always HTTPS, with `/v{version}` appended (default `v1`)\n *\n * Parsing uses the WHATWG `URL` constructor — custom regex parsing is banned\n * because it is notoriously brittle (ADR-055 §5.3).\n */\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport type ConnectionCredentialType = 'pk' | 'sk'\nexport type ConnectionEnv = 'dev' | 'stg' | 'prod' | 'prev'\n\nexport interface ParsedConnectionUrl {\n\t/** Full credential string, e.g. `pk_prod_f19e...` */\n\treadonly credential: string\n\t/** Credential kind — `pk` (publishable) or `sk` (secret) */\n\treadonly credentialType: ConnectionCredentialType\n\t/** Target environment encoded in the credential */\n\treadonly env: ConnectionEnv\n\t/** First DNS label of the host — the resource slug (e.g. `bold-river-a1b2c3`) */\n\treadonly slug: string\n\t/** Full host including port when present (e.g. `bold-river-a1b2c3.sylphx.com`) */\n\treadonly host: string\n\t/** Ready-to-use SDK base URL, always HTTPS (e.g. `https://bold-river-a1b2c3.sylphx.com/v1`) */\n\treadonly apiBaseUrl: string\n}\n\n// ============================================================================\n// Constants\n// ============================================================================\n\nconst SYLPHX_PROTOCOL = 'sylphx:'\nconst DEFAULT_VERSION = 'v1'\n\n/**\n * Credential format — opaque token with type, env, and hex payload.\n * Hex payload is 32–64 chars to accommodate both 128-bit and 256-bit secrets.\n */\nexport const CREDENTIAL_REGEX = /^(pk|sk)_(dev|stg|prod|prev)_[a-f0-9]{32,64}$/\n\n/** Version segment, e.g. `v1`, `v2`, `v10`. */\nconst VERSION_REGEX = /^v[0-9]+$/\n\n/**\n * Slug validation regex — RFC 1035 DNS label.\n * Lowercase letters, numbers, and hyphens; must start and end with alnum.\n * Length 1–63.\n */\nconst SLUG_REGEX = /^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/\n\n// ============================================================================\n// Errors\n// ============================================================================\n\nexport class InvalidConnectionUrlError extends Error {\n\treadonly code = 'INVALID_CONNECTION_URL' as const\n\n\tconstructor(message: string) {\n\t\tsuper(message)\n\t\tthis.name = 'InvalidConnectionUrlError'\n\t\tObject.setPrototypeOf(this, InvalidConnectionUrlError.prototype)\n\t}\n}\n\n// ============================================================================\n// Internal helpers\n// ============================================================================\n\nfunction fail(reason: string): never {\n\tthrow new InvalidConnectionUrlError(`Invalid Sylphx connection URL: ${reason}`)\n}\n\nfunction parseCredential(raw: string): {\n\tcredentialType: ConnectionCredentialType\n\tenv: ConnectionEnv\n} {\n\tconst match = CREDENTIAL_REGEX.exec(raw)\n\tif (!match) {\n\t\tfail(`credential must match (pk|sk)_(dev|stg|prod|prev)_[a-f0-9]{32,64}, got \"${raw}\"`)\n\t}\n\treturn {\n\t\tcredentialType: match[1] as ConnectionCredentialType,\n\t\tenv: match[2] as ConnectionEnv,\n\t}\n}\n\nfunction validateSlug(candidate: string): string {\n\tif (!candidate || candidate.length > 63 || !SLUG_REGEX.test(candidate)) {\n\t\tfail(`slug \"${candidate}\" is not a valid DNS label (lowercase alnum + hyphens, 1-63 chars)`)\n\t}\n\treturn candidate\n}\n\n// ============================================================================\n// Public API\n// ============================================================================\n\n/**\n * Parse a Sylphx connection URL into its structured components.\n *\n * Throws `InvalidConnectionUrlError` on any structural problem.\n */\nexport function parseConnectionUrl(url: string): ParsedConnectionUrl {\n\tif (typeof url !== 'string' || url.length === 0) {\n\t\tfail('url must be a non-empty string')\n\t}\n\n\tlet parsed: URL\n\ttry {\n\t\tparsed = new URL(url)\n\t} catch {\n\t\tfail(`not a valid URL: \"${url}\"`)\n\t}\n\n\tif (parsed.protocol !== SYLPHX_PROTOCOL) {\n\t\tfail(`protocol must be \"sylphx:\", got \"${parsed.protocol}\"`)\n\t}\n\n\t// URL parses `sylphx://cred@host/path` but places `cred` in `username` only\n\t// when the authority is parsed. For non-special schemes, browsers/Node parse\n\t// the authority uniformly — we defensively read both `username` and `host`.\n\tconst credential = decodeURIComponent(parsed.username)\n\tif (!credential) {\n\t\tfail('missing credential (expected `sylphx://<credential>@<host>`)')\n\t}\n\tif (parsed.password) {\n\t\tfail('connection URL must not contain a password component')\n\t}\n\n\tconst { credentialType, env } = parseCredential(credential)\n\n\tconst host = parsed.host\n\tif (!host) {\n\t\tfail('missing host')\n\t}\n\n\t// Extract slug from the first DNS label\n\tconst hostname = parsed.hostname\n\tconst firstDot = hostname.indexOf('.')\n\tif (firstDot <= 0) {\n\t\tfail(`host \"${hostname}\" must contain at least one dot (slug.domain)`)\n\t}\n\tconst slugCandidate = hostname.slice(0, firstDot)\n\tconst domainSuffix = hostname.slice(firstDot + 1)\n\tif (!domainSuffix) {\n\t\tfail(`host \"${hostname}\" has empty domain suffix`)\n\t}\n\tconst slug = validateSlug(slugCandidate)\n\n\t// Path is either empty, `/`, or `/v{N}`\n\tconst rawPath = parsed.pathname.replace(/^\\/+/, '').replace(/\\/+$/, '')\n\tlet version = DEFAULT_VERSION\n\tif (rawPath !== '') {\n\t\tif (!VERSION_REGEX.test(rawPath)) {\n\t\t\tfail(`path \"${parsed.pathname}\" must be empty or match /v{N}`)\n\t\t}\n\t\tversion = rawPath\n\t}\n\n\tif (parsed.search) {\n\t\tfail('connection URL must not contain a query string')\n\t}\n\tif (parsed.hash) {\n\t\tfail('connection URL must not contain a fragment')\n\t}\n\n\tconst apiBaseUrl = `https://${host}/${version}`\n\n\treturn {\n\t\tcredential,\n\t\tcredentialType,\n\t\tenv,\n\t\tslug,\n\t\thost,\n\t\tapiBaseUrl,\n\t}\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/**\n * Canonical environment variable name for the client connection URL.\n *\n * Format: sylphx://pk_prod_{hex}@slug.sylphx.com\n * Browser-safe (publishable key only).\n */\nexport const ENV_URL = 'SYLPHX_URL'\n\n/**\n * Canonical environment variable name for the Next.js public connection URL.\n *\n * Same format as ENV_URL, browser-safe.\n */\nexport const ENV_PUBLIC_URL = 'NEXT_PUBLIC_SYLPHX_URL'\n\n/**\n * Canonical environment variable name for the server secret connection URL.\n *\n * Format: sylphx://sk_prod_{hex}@slug.sylphx.com\n * Server-side only — never expose to client.\n */\nexport const ENV_SECRET_URL = 'SYLPHX_SECRET_URL'\n\n/**\n * @deprecated Use ENV_SECRET_URL. Kept for migration error messages only.\n */\nexport const ENV_SECRET_KEY = 'SYLPHX_SECRET_KEY'\n\n/**\n * Resolve the connection URL from environment variables.\n *\n * Checks SYLPHX_URL first, then NEXT_PUBLIC_SYLPHX_URL.\n */\nexport function resolveUrl(explicit?: string): string | undefined {\n\treturn explicit || process.env[ENV_URL] || process.env[ENV_PUBLIC_URL]\n}\n\n/**\n * Resolve the secret connection URL from environment variables.\n */\nexport function resolveSecretUrl(explicit?: string): string | undefined {\n\treturn explicit || process.env[ENV_SECRET_URL]\n}\n\n/**\n * SDK API path for the per-project subdomain-based SDK server.\n *\n * The full base URL is built as: https://{ref}.api.sylphx.com/v1\n */\nexport const SDK_API_PATH = `/v1`\nexport const SDK_API_VERSION = 'v1'\n\n/**\n * Default SDK API host.\n *\n * Management API: https://api.sylphx.com/v1/*\n * BaaS/SDK API: https://{ref}.api.sylphx.com/v1/*\n */\nexport const DEFAULT_SDK_API_HOST = 'api.sylphx.com'\nexport const DEFAULT_PLATFORM_URL = 'https://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.5.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 * Sylphx SDK Error Classes\n *\n * Typed error classes for better error handling and debugging.\n * Compatible with tRPC error codes and provides rich context.\n *\n * @example\n * ```typescript\n * import { SylphxError, isRetryableError, getErrorMessage } from '@sylphx/sdk'\n *\n * try {\n * await sylphx.auth.login.mutate({ email, password })\n * } catch (error) {\n * if (error instanceof SylphxError) {\n * console.log(error.code) // 'UNAUTHORIZED'\n * console.log(error.isRetryable) // false\n * }\n * if (isRetryableError(error)) {\n * // Safe to retry\n * }\n * }\n * ```\n */\n\nimport { BASE_RETRY_DELAY_MS, DEFAULT_TIMEOUT_MS, MAX_RETRY_DELAY_MS } from './constants'\n\n// ============================================================================\n// Error Codes (aligned with tRPC and HTTP semantics)\n// ============================================================================\n\nexport type SylphxErrorCode =\n\t// Client errors (4xx)\n\t| 'BAD_REQUEST' // 400 - Invalid input\n\t| 'UNAUTHORIZED' // 401 - Not authenticated\n\t| 'FORBIDDEN' // 403 - Not authorized\n\t| 'NOT_FOUND' // 404 - Resource not found\n\t| 'CONFLICT' // 409 - Resource conflict (e.g., duplicate)\n\t| 'PAYLOAD_TOO_LARGE' // 413 - Request too large\n\t| 'UNPROCESSABLE_ENTITY' // 422 - Validation failed\n\t| 'TOO_MANY_REQUESTS' // 429 - Rate limited\n\t| 'QUOTA_EXCEEDED' // 402/429 - Quota/plan limit exceeded\n\t// Server errors (5xx)\n\t| 'INTERNAL_SERVER_ERROR' // 500 - Server error\n\t| 'NOT_IMPLEMENTED' // 501 - Feature not available\n\t| 'BAD_GATEWAY' // 502 - Upstream error\n\t| 'SERVICE_UNAVAILABLE' // 503 - Temporarily unavailable\n\t| 'GATEWAY_TIMEOUT' // 504 - Upstream timeout\n\t// Network/Client errors\n\t| 'NETWORK_ERROR' // Network failure\n\t| 'TIMEOUT' // Request timeout\n\t| 'ABORTED' // Request aborted\n\t// SDK-specific\n\t| 'PARSE_ERROR' // JSON/response parse error\n\t| 'UNKNOWN' // Unknown error\n\n/**\n * Simplified semantic error codes (DX-friendly aliases).\n * Maps to the more granular SylphxErrorCode internally.\n *\n * @example\n * ```ts\n * if (SylphxError.isRateLimited(err)) {\n * console.log(`Retry after ${err.retryAfter}s`)\n * }\n * ```\n */\nexport type ErrorCode =\n\t| 'UNAUTHORIZED'\n\t| 'FORBIDDEN'\n\t| 'NOT_FOUND'\n\t| 'RATE_LIMITED'\n\t| 'QUOTA_EXCEEDED'\n\t| 'VALIDATION_ERROR'\n\t| 'NETWORK_ERROR'\n\t| 'UPSTREAM_ERROR'\n\t| 'INTERNAL_ERROR'\n\n/**\n * HTTP status code mapping for error codes\n */\nexport const ERROR_CODE_STATUS: Record<SylphxErrorCode, number> = {\n\tBAD_REQUEST: 400,\n\tUNAUTHORIZED: 401,\n\tFORBIDDEN: 403,\n\tNOT_FOUND: 404,\n\tCONFLICT: 409,\n\tPAYLOAD_TOO_LARGE: 413,\n\tUNPROCESSABLE_ENTITY: 422,\n\tTOO_MANY_REQUESTS: 429,\n\tQUOTA_EXCEEDED: 402,\n\tINTERNAL_SERVER_ERROR: 500,\n\tNOT_IMPLEMENTED: 501,\n\tBAD_GATEWAY: 502,\n\tSERVICE_UNAVAILABLE: 503,\n\tGATEWAY_TIMEOUT: 504,\n\tNETWORK_ERROR: 0,\n\tTIMEOUT: 0,\n\tABORTED: 0,\n\tPARSE_ERROR: 0,\n\tUNKNOWN: 0,\n}\n\n/**\n * Retryable error codes (safe to retry automatically)\n */\nexport const RETRYABLE_CODES: Set<SylphxErrorCode> = new Set([\n\t'NETWORK_ERROR',\n\t'TIMEOUT',\n\t'BAD_GATEWAY',\n\t'SERVICE_UNAVAILABLE',\n\t'GATEWAY_TIMEOUT',\n\t'TOO_MANY_REQUESTS', // With backoff\n\t'INTERNAL_SERVER_ERROR', // Sometimes transient\n])\n\n// ============================================================================\n// Error Classes\n// ============================================================================\n\nexport interface SylphxErrorOptions {\n\t/** Error code for programmatic handling */\n\tcode?: SylphxErrorCode\n\t/** HTTP status code (inferred from code if not provided) */\n\tstatus?: number\n\t/** Additional context data */\n\tdata?: Record<string, unknown>\n\t/** Original error that caused this */\n\tcause?: Error\n\t/** Retry-After header value (seconds) for rate limiting */\n\tretryAfter?: number\n}\n\n/**\n * Base error class for all Sylphx SDK errors\n *\n * @example\n * ```typescript\n * throw new SylphxError('Invalid email format', {\n * code: 'BAD_REQUEST',\n * data: { field: 'email' }\n * })\n * ```\n */\nexport class SylphxError extends Error {\n\t/** Error code for programmatic handling */\n\treadonly code: SylphxErrorCode\n\n\t/** HTTP status code */\n\treadonly status: number\n\n\t/** Additional context data */\n\treadonly data?: Record<string, unknown>\n\n\t/** Whether this error is safe to retry */\n\treadonly isRetryable: boolean\n\n\t/** Retry-After value in seconds (for rate limiting) */\n\treadonly retryAfter?: number\n\n\t/** Timestamp when error occurred */\n\treadonly timestamp: Date\n\n\tconstructor(message: string, options: SylphxErrorOptions = {}) {\n\t\tsuper(message, { cause: options.cause })\n\t\tthis.name = 'SylphxError'\n\t\tthis.code = options.code ?? 'UNKNOWN'\n\t\tthis.status = options.status ?? ERROR_CODE_STATUS[this.code]\n\t\tthis.data = options.data\n\t\tthis.isRetryable = RETRYABLE_CODES.has(this.code)\n\t\tthis.retryAfter = options.retryAfter\n\t\tthis.timestamp = new Date()\n\n\t\t// Maintain proper stack trace in V8\n\t\tif (Error.captureStackTrace) {\n\t\t\tError.captureStackTrace(this, SylphxError)\n\t\t}\n\t}\n\n\t// ============================================================================\n\t// Static Type Guards (DX helpers)\n\t// ============================================================================\n\n\t/**\n\t * Check if error is a rate-limit error (429 Too Many Requests)\n\t */\n\tstatic isRateLimited(err: unknown): err is SylphxError & { code: 'TOO_MANY_REQUESTS' } {\n\t\treturn err instanceof SylphxError && err.code === 'TOO_MANY_REQUESTS'\n\t}\n\n\t/**\n\t * Check if error is an account lockout error (too many failed login attempts).\n\t * When true, `error.data?.lockoutUntil` contains the ISO 8601 timestamp when the lockout expires.\n\t */\n\tstatic isAccountLocked(\n\t\terr: unknown,\n\t): err is SylphxError & { code: 'TOO_MANY_REQUESTS'; data: { lockoutUntil: string | null } } {\n\t\treturn (\n\t\t\terr instanceof SylphxError &&\n\t\t\terr.code === 'TOO_MANY_REQUESTS' &&\n\t\t\terr.data?.code === 'ACCOUNT_LOCKED'\n\t\t)\n\t}\n\n\t/**\n\t * Check if error is a quota exceeded error (plan limit reached)\n\t */\n\tstatic isQuotaExceeded(err: unknown): err is SylphxError & { code: 'QUOTA_EXCEEDED' } {\n\t\treturn err instanceof SylphxError && err.code === 'QUOTA_EXCEEDED'\n\t}\n\n\t/**\n\t * Check if error is an authentication error (401 Unauthorized)\n\t */\n\tstatic isUnauthorized(err: unknown): err is SylphxError & { code: 'UNAUTHORIZED' } {\n\t\treturn err instanceof SylphxError && err.code === 'UNAUTHORIZED'\n\t}\n\n\t/**\n\t * Check if error is a not-found error (404 Not Found)\n\t */\n\tstatic isNotFound(err: unknown): err is SylphxError & { code: 'NOT_FOUND' } {\n\t\treturn err instanceof SylphxError && err.code === 'NOT_FOUND'\n\t}\n\n\t/**\n\t * Check if error is an authorization error (403 Forbidden)\n\t */\n\tstatic isForbidden(err: unknown): err is SylphxError & { code: 'FORBIDDEN' } {\n\t\treturn err instanceof SylphxError && err.code === 'FORBIDDEN'\n\t}\n\n\t/**\n\t * Check if error is a validation error (422 Unprocessable Entity)\n\t */\n\tstatic isValidationError(err: unknown): err is SylphxError & { code: 'UNPROCESSABLE_ENTITY' } {\n\t\treturn err instanceof SylphxError && err.code === 'UNPROCESSABLE_ENTITY'\n\t}\n\n\t/**\n\t * Check if error is a network error (no response received)\n\t */\n\tstatic isNetworkError(err: unknown): err is SylphxError & { code: 'NETWORK_ERROR' } {\n\t\treturn err instanceof SylphxError && err.code === 'NETWORK_ERROR'\n\t}\n\n\t/**\n\t * Check if error is an upstream/gateway error (502/504)\n\t */\n\tstatic isUpstreamError(err: unknown): err is SylphxError {\n\t\treturn (\n\t\t\terr instanceof SylphxError &&\n\t\t\t(err.code === 'BAD_GATEWAY' ||\n\t\t\t\terr.code === 'GATEWAY_TIMEOUT' ||\n\t\t\t\terr.code === 'SERVICE_UNAVAILABLE')\n\t\t)\n\t}\n\n\t/**\n\t * Convert to JSON-serializable object\n\t */\n\ttoJSON(): Record<string, unknown> {\n\t\treturn {\n\t\t\tname: this.name,\n\t\t\tmessage: this.message,\n\t\t\tcode: this.code,\n\t\t\tstatus: this.status,\n\t\t\tdata: this.data,\n\t\t\tisRetryable: this.isRetryable,\n\t\t\tretryAfter: this.retryAfter,\n\t\t\ttimestamp: this.timestamp.toISOString(),\n\t\t}\n\t}\n}\n\n/**\n * Network-related errors (no response received)\n */\nexport class NetworkError extends SylphxError {\n\tconstructor(message = 'Network request failed', options?: Omit<SylphxErrorOptions, 'code'>) {\n\t\tsuper(message, { ...options, code: 'NETWORK_ERROR' })\n\t\tthis.name = 'NetworkError'\n\t}\n}\n\n/**\n * Request timeout errors\n */\nexport class TimeoutError extends SylphxError {\n\t/** Timeout duration in milliseconds */\n\treadonly timeout: number\n\n\tconstructor(timeout: number, options?: Omit<SylphxErrorOptions, 'code'>) {\n\t\tsuper(`Request timed out after ${timeout}ms`, {\n\t\t\t...options,\n\t\t\tcode: 'TIMEOUT',\n\t\t})\n\t\tthis.name = 'TimeoutError'\n\t\tthis.timeout = timeout\n\t}\n}\n\n/**\n * Authentication errors (401)\n */\nexport class AuthenticationError extends SylphxError {\n\tconstructor(message = 'Authentication required', options?: Omit<SylphxErrorOptions, 'code'>) {\n\t\tsuper(message, { ...options, code: 'UNAUTHORIZED' })\n\t\tthis.name = 'AuthenticationError'\n\t}\n}\n\n/**\n * Authorization errors (403)\n */\nexport class AuthorizationError extends SylphxError {\n\tconstructor(message = 'Permission denied', options?: Omit<SylphxErrorOptions, 'code'>) {\n\t\tsuper(message, { ...options, code: 'FORBIDDEN' })\n\t\tthis.name = 'AuthorizationError'\n\t}\n}\n\n/**\n * Validation errors (422)\n */\nexport class ValidationError extends SylphxError {\n\t/** Field-specific errors */\n\treadonly fieldErrors?: Record<string, string[]>\n\n\tconstructor(\n\t\tmessage: string,\n\t\toptions?: Omit<SylphxErrorOptions, 'code'> & {\n\t\t\tfieldErrors?: Record<string, string[]>\n\t\t},\n\t) {\n\t\tsuper(message, { ...options, code: 'UNPROCESSABLE_ENTITY' })\n\t\tthis.name = 'ValidationError'\n\t\tthis.fieldErrors = options?.fieldErrors\n\t}\n\n\t/**\n\t * Get error message for a specific field\n\t */\n\tgetFieldError(field: string): string | undefined {\n\t\treturn this.fieldErrors?.[field]?.[0]\n\t}\n}\n\n/**\n * Rate limit metadata (Stripe SDK pattern)\n */\nexport interface RateLimitInfo {\n\t/** Maximum requests allowed in window */\n\tlimit?: number\n\t/** Remaining requests in current window */\n\tremaining?: number\n\t/** Unix timestamp (seconds) when limit resets */\n\tresetAt?: number\n\t/** Seconds until limit resets (Retry-After header) */\n\tretryAfter?: number\n}\n\n/**\n * Rate limit errors (429)\n *\n * Provides full rate limit metadata for consumer apps to implement\n * proper backoff UI (countdown timers, retry buttons, etc.)\n *\n * @example\n * ```typescript\n * try {\n * await sendEmail(config, options)\n * } catch (error) {\n * if (error instanceof RateLimitError) {\n * const waitSeconds = error.retryAfter ?? 60\n * console.log(`Rate limited. Retry after ${waitSeconds}s`)\n * console.log(`Remaining: ${error.remaining}/${error.limit}`)\n * console.log(`Resets at: ${new Date(error.resetAt! * 1000)}`)\n * }\n * }\n * ```\n */\nexport class RateLimitError extends SylphxError {\n\t/** Maximum requests allowed in window */\n\treadonly limit?: number\n\n\t/** Remaining requests in current window */\n\treadonly remaining?: number\n\n\t/** Unix timestamp (seconds) when limit resets */\n\treadonly resetAt?: number\n\n\tconstructor(\n\t\tmessage = 'Too many requests',\n\t\toptions?: Omit<SylphxErrorOptions, 'code'> & RateLimitInfo,\n\t) {\n\t\tsuper(message, { ...options, code: 'TOO_MANY_REQUESTS' })\n\t\tthis.name = 'RateLimitError'\n\t\tthis.limit = options?.limit\n\t\tthis.remaining = options?.remaining\n\t\tthis.resetAt = options?.resetAt\n\t}\n\n\t/**\n\t * Get Date when rate limit resets\n\t */\n\tgetResetDate(): Date | undefined {\n\t\treturn this.resetAt ? new Date(this.resetAt * 1000) : undefined\n\t}\n\n\t/**\n\t * Get human-readable retry message\n\t */\n\tgetRetryMessage(): string {\n\t\tif (this.retryAfter) {\n\t\t\treturn `Please retry after ${this.retryAfter} seconds`\n\t\t}\n\t\tif (this.resetAt) {\n\t\t\tconst seconds = Math.max(0, this.resetAt - Math.floor(Date.now() / 1000))\n\t\t\treturn `Rate limit resets in ${seconds} seconds`\n\t\t}\n\t\treturn 'Please wait before retrying'\n\t}\n}\n\n/**\n * Resource not found errors (404)\n */\nexport class NotFoundError extends SylphxError {\n\t/** Type of resource that wasn't found */\n\treadonly resourceType?: string\n\n\t/** ID of the resource that wasn't found */\n\treadonly resourceId?: string\n\n\tconstructor(\n\t\tmessage = 'Resource not found',\n\t\toptions?: Omit<SylphxErrorOptions, 'code'> & {\n\t\t\tresourceType?: string\n\t\t\tresourceId?: string\n\t\t},\n\t) {\n\t\tsuper(message, { ...options, code: 'NOT_FOUND' })\n\t\tthis.name = 'NotFoundError'\n\t\tthis.resourceType = options?.resourceType\n\t\tthis.resourceId = options?.resourceId\n\t}\n}\n\n// ============================================================================\n// Utility Functions\n// ============================================================================\n\n/**\n * Check if an error is a Sylphx SDK error\n */\nexport function isSylphxError(error: unknown): error is SylphxError {\n\treturn error instanceof SylphxError\n}\n\n/**\n * Check if an error is safe to retry\n */\nexport function isRetryableError(error: unknown): boolean {\n\tif (error instanceof SylphxError) {\n\t\treturn error.isRetryable\n\t}\n\n\t// Check for network errors\n\tif (error instanceof Error) {\n\t\tconst message = error.message.toLowerCase()\n\t\tconst name = error.name.toLowerCase()\n\n\t\t// Network errors\n\t\tif (name === 'typeerror' && message.includes('fetch')) return true\n\t\tif (name === 'networkerror') return true\n\n\t\t// Timeout patterns\n\t\tif (message.includes('timeout')) return true\n\t\tif (message.includes('timed out')) return true\n\n\t\t// Connection errors\n\t\tif (message.includes('econnrefused')) return true\n\t\tif (message.includes('econnreset')) return true\n\t\tif (message.includes('socket')) return true\n\n\t\t// Server errors that might be transient\n\t\tif (message.includes('502')) return true\n\t\tif (message.includes('503')) return true\n\t\tif (message.includes('504')) return true\n\t}\n\n\treturn false\n}\n\n/**\n * Extract error message from any error type\n */\nexport function getErrorMessage(error: unknown): string {\n\tif (error instanceof Error) {\n\t\treturn error.message\n\t}\n\tif (typeof error === 'string') {\n\t\treturn error\n\t}\n\treturn 'An unknown error occurred'\n}\n\n/**\n * Get error code from any error type\n */\nexport function getErrorCode(error: unknown): SylphxErrorCode {\n\tif (error instanceof SylphxError) {\n\t\treturn error.code\n\t}\n\treturn 'UNKNOWN'\n}\n\n/**\n * Convert any error to SylphxError\n */\nexport function toSylphxError(error: unknown): SylphxError {\n\tif (error instanceof SylphxError) {\n\t\treturn error\n\t}\n\n\tif (error instanceof Error) {\n\t\t// Try to infer error type from message/name\n\t\tconst message = error.message.toLowerCase()\n\t\tconst name = error.name.toLowerCase()\n\n\t\t// Network errors\n\t\tif (name === 'typeerror' && message.includes('fetch')) {\n\t\t\treturn new NetworkError(error.message, { cause: error })\n\t\t}\n\t\tif (name === 'aborterror' || message.includes('aborted')) {\n\t\t\treturn new SylphxError(error.message, { code: 'ABORTED', cause: error })\n\t\t}\n\n\t\t// Timeout\n\t\tif (message.includes('timeout')) {\n\t\t\treturn new TimeoutError(DEFAULT_TIMEOUT_MS, { cause: error })\n\t\t}\n\n\t\t// HTTP status codes in message\n\t\tif (message.includes('401') || message.includes('unauthorized')) {\n\t\t\treturn new AuthenticationError(error.message, { cause: error })\n\t\t}\n\t\tif (message.includes('403') || message.includes('forbidden')) {\n\t\t\treturn new AuthorizationError(error.message, { cause: error })\n\t\t}\n\t\tif (message.includes('404') || message.includes('not found')) {\n\t\t\treturn new NotFoundError(error.message, { cause: error })\n\t\t}\n\t\tif (message.includes('429') || message.includes('rate limit')) {\n\t\t\treturn new RateLimitError(error.message, { cause: error })\n\t\t}\n\n\t\treturn new SylphxError(error.message, { cause: error })\n\t}\n\n\treturn new SylphxError(getErrorMessage(error))\n}\n\n/**\n * Calculate exponential backoff delay with jitter\n *\n * @param attempt - Retry attempt number (0-indexed)\n * @param baseDelay - Base delay in milliseconds (default: 1000)\n * @param maxDelay - Maximum delay in milliseconds (default: 30000)\n * @returns Delay in milliseconds with jitter\n */\nexport function exponentialBackoff(\n\tattempt: number,\n\tbaseDelay = BASE_RETRY_DELAY_MS,\n\tmaxDelay = MAX_RETRY_DELAY_MS,\n): number {\n\t// Calculate exponential delay: baseDelay * 2^attempt\n\tconst exponentialDelay = baseDelay * 2 ** attempt\n\n\t// Cap at maxDelay\n\tconst cappedDelay = Math.min(exponentialDelay, maxDelay)\n\n\t// Add jitter (±25% randomness)\n\tconst jitter = cappedDelay * 0.25 * (Math.random() * 2 - 1)\n\n\treturn Math.round(cappedDelay + jitter)\n}\n","/**\n * SDK Configuration — ADR-055 Connection URL API\n *\n * v0.5.0: The primary entry point is `createClient(url)` which accepts\n * a `sylphx://` connection URL. The old `createConfig({ ref, publicKey })`\n * API is removed.\n *\n * @example\n * ```typescript\n * import { createClient } from '@sylphx/sdk'\n *\n * const sylphx = createClient(process.env.SYLPHX_URL!)\n * // Parses: sylphx://pk_prod_{hex}@bold-river-a1b2c3.sylphx.com\n * ```\n */\n\nimport {\n\tCREDENTIAL_REGEX,\n\tInvalidConnectionUrlError,\n\ttype ParsedConnectionUrl,\n\tparseConnectionUrl,\n} from './connection-url'\nimport { DEFAULT_TIMEOUT_MS } from './constants'\nimport {\n\tNetworkError,\n\tRateLimitError,\n\tSylphxError,\n\ttype SylphxErrorCode,\n\tTimeoutError,\n} from './errors'\n\nexport type { ParsedConnectionUrl } from './connection-url'\n// Re-export connection URL types for consumers\nexport { InvalidConnectionUrlError } from './connection-url'\n\n// =============================================================================\n// Legacy format detection — produces clear migration errors\n// =============================================================================\n\n/** Matches old ADR-021 format: pk_{env}_{ref12}_{hex} or sk_{env}_{ref12}_{hex} (4 underscore segments) */\nconst LEGACY_EMBEDDED_REF_PATTERN = /^(pk|sk)_(dev|stg|prod|prev)_[a-z0-9]{12}_[a-f0-9]+$/\n\n/** Matches old app_* format: app_{env}_{anything} */\nconst LEGACY_APP_KEY_PATTERN = /^app_(dev|stg|prod|prev)_/\n\nconst MIGRATION_MESSAGE =\n\t'API key format has changed. Use a sylphx:// connection URL instead.\\n\\n' +\n\t'New format: sylphx://pk_prod_{hex}@your-slug.sylphx.com\\n\\n' +\n\t'Generate new credentials from the Sylphx Console → Your App → Environments.\\n' +\n\t'See https://docs.sylphx.com/migration for details.'\n\n/**\n * Detect legacy key formats and throw a helpful migration error.\n */\nfunction rejectLegacyKeyFormat(input: string): void {\n\tconst trimmed = input.trim().toLowerCase()\n\n\tif (LEGACY_APP_KEY_PATTERN.test(trimmed)) {\n\t\tthrow new SylphxError(`[Sylphx] ${MIGRATION_MESSAGE}`, { code: 'BAD_REQUEST' })\n\t}\n\n\tif (LEGACY_EMBEDDED_REF_PATTERN.test(trimmed)) {\n\t\tthrow new SylphxError(`[Sylphx] ${MIGRATION_MESSAGE}`, { code: 'BAD_REQUEST' })\n\t}\n}\n\n// =============================================================================\n// Config types\n// =============================================================================\n\n/**\n * SDK Configuration object — immutable, frozen.\n *\n * Created by `createClient()` or `createServerClient()`.\n * Passed to all pure SDK functions (`track()`, `signIn()`, etc.).\n */\nexport interface SylphxConfig {\n\t/** The credential string (pk_* or sk_*) */\n\treadonly credential: string\n\t/** Credential type: 'pk' (publishable) or 'sk' (secret) */\n\treadonly credentialType: 'pk' | 'sk'\n\t/** Target environment: dev, stg, prod, or prev */\n\treadonly env: 'dev' | 'stg' | 'prod' | 'prev'\n\t/** Resource slug (first DNS label), e.g. 'bold-river-a1b2c3' */\n\treadonly slug: string\n\t/** Pre-computed API base URL, e.g. 'https://bold-river-a1b2c3.sylphx.com/v1' */\n\treadonly baseUrl: string\n\t/** Optional access token for authenticated requests */\n\treadonly accessToken?: string\n\t/**\n\t * Secret key — populated when credentialType is 'sk'.\n\t * Backward-compatible alias for `credential` when credential is sk_*.\n\t */\n\treadonly secretKey?: string\n\t/**\n\t * Publishable key — populated when credentialType is 'pk'.\n\t * Backward-compatible alias for `credential` when credential is pk_*.\n\t */\n\treadonly publicKey?: string\n\t/**\n\t * @deprecated Use `slug`. Backward-compatible alias.\n\t */\n\treadonly ref: string\n}\n\n/**\n * Explicit components input — alternative to connection URL string.\n *\n * For multi-tenant apps or cases where components are stored separately.\n */\nexport interface SylphxClientInput {\n\t/** Resource slug, e.g. 'bold-river-a1b2c3' */\n\tslug?: string\n\t/** Publishable key (pk_*) — client-safe */\n\tpublicKey?: string\n\t/** Secret key (sk_*) — server-side only */\n\tsecretKey?: string\n\t/** Optional access token */\n\taccessToken?: string\n\t/** API domain override (default: sylphx.com) */\n\tdomain?: string\n\t/**\n\t * @deprecated Use `slug`. Accepted for backward compatibility during migration.\n\t */\n\tref?: string\n\t/**\n\t * @deprecated Use `domain`. Accepted for backward compatibility during migration.\n\t */\n\tplatformUrl?: string\n}\n\n/**\n * Build a frozen SylphxConfig with backward-compat fields (secretKey, publicKey, ref).\n */\nfunction freezeConfig(opts: {\n\tcredential: string\n\tcredentialType: 'pk' | 'sk'\n\tenv: 'dev' | 'stg' | 'prod' | 'prev'\n\tslug: string\n\tbaseUrl: string\n\taccessToken?: string\n}): SylphxConfig {\n\treturn Object.freeze({\n\t\tcredential: opts.credential,\n\t\tcredentialType: opts.credentialType,\n\t\tenv: opts.env,\n\t\tslug: opts.slug,\n\t\tbaseUrl: opts.baseUrl,\n\t\taccessToken: opts.accessToken,\n\t\t// Backward-compat aliases\n\t\tsecretKey: opts.credentialType === 'sk' ? opts.credential : undefined,\n\t\tpublicKey: opts.credentialType === 'pk' ? opts.credential : undefined,\n\t\tref: opts.slug,\n\t})\n}\n\n// =============================================================================\n// createClient — primary entry point (ADR-055)\n// =============================================================================\n\n/**\n * Create a Sylphx client from a connection URL or explicit components.\n *\n * This is the primary SDK entry point for client-side (browser) usage.\n * Accepts a `sylphx://` connection URL or an explicit components object.\n *\n * @example Connection URL (recommended)\n * ```typescript\n * const sylphx = createClient(process.env.NEXT_PUBLIC_SYLPHX_URL!)\n * // Parses: sylphx://pk_prod_{hex}@bold-river-a1b2c3.sylphx.com\n * ```\n *\n * @example Explicit components\n * ```typescript\n * const sylphx = createClient({\n * slug: 'bold-river-a1b2c3',\n * publicKey: 'pk_prod_f19e...',\n * })\n * ```\n */\nexport function createClient(input: string | SylphxClientInput): SylphxConfig {\n\tif (typeof input === 'string') {\n\t\treturn createConfigFromUrl(input)\n\t}\n\treturn createConfigFromComponents(input)\n}\n\n/**\n * Create a Sylphx server client from a connection URL or explicit components.\n *\n * Equivalent to `createClient()` but validates that a secret key (sk_*) is provided.\n * Use this for server-side operations that require elevated permissions.\n *\n * @example Connection URL (recommended)\n * ```typescript\n * const sylphx = createServerClient(process.env.SYLPHX_SECRET_URL!)\n * // Parses: sylphx://sk_prod_{hex}@bold-river-a1b2c3.sylphx.com\n * ```\n *\n * @example Explicit components\n * ```typescript\n * const sylphx = createServerClient({\n * slug: 'bold-river-a1b2c3',\n * secretKey: 'sk_prod_5120...',\n * })\n * ```\n */\nexport function createServerClient(input: string | SylphxClientInput): SylphxConfig {\n\tconst config = createClient(input)\n\n\tif (config.credentialType !== 'sk') {\n\t\tthrow new SylphxError(\n\t\t\t'[Sylphx] createServerClient() requires a secret key (sk_*). ' +\n\t\t\t\t'Use a SYLPHX_SECRET_URL with an sk_ credential, or pass { secretKey } in the components object.',\n\t\t\t{ code: 'BAD_REQUEST' },\n\t\t)\n\t}\n\n\treturn config\n}\n\n// =============================================================================\n// Internal construction\n// =============================================================================\n\nfunction createConfigFromUrl(url: string): SylphxConfig {\n\tif (!url || typeof url !== 'string') {\n\t\tthrow new SylphxError(\n\t\t\t'[Sylphx] Connection URL is required. Set SYLPHX_URL or NEXT_PUBLIC_SYLPHX_URL environment variable.\\n\\n' +\n\t\t\t\t'Format: sylphx://pk_prod_{hex}@your-slug.sylphx.com',\n\t\t\t{ code: 'BAD_REQUEST' },\n\t\t)\n\t}\n\n\tconst trimmed = url.trim()\n\n\t// Detect legacy key formats passed as the URL string\n\trejectLegacyKeyFormat(trimmed)\n\n\t// If someone passes a bare key instead of a URL, give a helpful error\n\tif (!trimmed.startsWith('sylphx://')) {\n\t\t// Check if it looks like a new-format bare credential\n\t\tif (CREDENTIAL_REGEX.test(trimmed)) {\n\t\t\tthrow new SylphxError(\n\t\t\t\t'[Sylphx] Received a bare credential instead of a connection URL.\\n\\n' +\n\t\t\t\t\t'Wrap it in a connection URL: sylphx://<credential>@<slug>.sylphx.com\\n' +\n\t\t\t\t\t'Or use createClient({ slug, publicKey }) for explicit components.',\n\t\t\t\t{ code: 'BAD_REQUEST' },\n\t\t\t)\n\t\t}\n\t\tthrow new SylphxError(\n\t\t\t`[Sylphx] Invalid connection URL — must start with \"sylphx://\". Got: \"${trimmed.slice(0, 30)}...\"`,\n\t\t\t{ code: 'BAD_REQUEST' },\n\t\t)\n\t}\n\n\tlet parsed: ParsedConnectionUrl\n\ttry {\n\t\tparsed = parseConnectionUrl(trimmed)\n\t} catch (err) {\n\t\tif (err instanceof InvalidConnectionUrlError) {\n\t\t\tthrow new SylphxError(err.message, { code: 'BAD_REQUEST', cause: err })\n\t\t}\n\t\tthrow err\n\t}\n\n\treturn freezeConfig({\n\t\tcredential: parsed.credential,\n\t\tcredentialType: parsed.credentialType,\n\t\tenv: parsed.env,\n\t\tslug: parsed.slug,\n\t\tbaseUrl: parsed.apiBaseUrl,\n\t})\n}\n\nfunction createConfigFromComponents(input: SylphxClientInput): SylphxConfig {\n\tconst credential = input.secretKey || input.publicKey\n\tif (!credential) {\n\t\tthrow new SylphxError('[Sylphx] Either publicKey or secretKey must be provided.', {\n\t\t\tcode: 'BAD_REQUEST',\n\t\t})\n\t}\n\n\t// Accept deprecated `ref` as fallback for `slug` during migration\n\tconst resolvedSlug = input.slug || input.ref\n\n\tif (!resolvedSlug) {\n\t\tthrow new SylphxError('[Sylphx] slug is required when using explicit components.', {\n\t\t\tcode: 'BAD_REQUEST',\n\t\t})\n\t}\n\n\t// Try to validate as ADR-055 credential first; if invalid, check for legacy\n\tconst trimmedCred = credential.trim().toLowerCase()\n\n\tif (CREDENTIAL_REGEX.test(trimmedCred)) {\n\t\t// New-format credential (ADR-055): pk_{env}_{hex} or sk_{env}_{hex}\n\t\tconst match = CREDENTIAL_REGEX.exec(trimmedCred)!\n\t\tconst credentialType = match[1] as 'pk' | 'sk'\n\t\tconst env = match[2] as 'dev' | 'stg' | 'prod' | 'prev'\n\n\t\tconst slug = resolvedSlug.trim().toLowerCase()\n\t\tconst domain = input.domain?.trim() || 'sylphx.com'\n\t\tconst baseUrl = `https://${slug}.${domain}/v1`\n\n\t\treturn freezeConfig({\n\t\t\tcredential: trimmedCred,\n\t\t\tcredentialType,\n\t\t\tenv,\n\t\t\tslug,\n\t\t\tbaseUrl,\n\t\t\taccessToken: input.accessToken,\n\t\t})\n\t}\n\n\t// Backward compat: accept old-format keys (pk_{env}_{ref}_{hex} or sk_{env}_{ref}_{hex})\n\t// These have 4 underscore-delimited segments. Extract env from segment 1.\n\tconst parts = trimmedCred.split('_')\n\tconst prefix = parts[0] as 'pk' | 'sk'\n\tif ((prefix === 'pk' || prefix === 'sk') && parts.length >= 3) {\n\t\tconst envSegment = parts[1]\n\t\tconst validEnvs = ['dev', 'stg', 'prod', 'prev']\n\t\tconst env = validEnvs.includes(envSegment)\n\t\t\t? (envSegment as 'dev' | 'stg' | 'prod' | 'prev')\n\t\t\t: 'prod'\n\n\t\tconst slug = resolvedSlug.trim().toLowerCase()\n\t\t// Accept deprecated platformUrl for base URL construction\n\t\tlet baseUrl: string\n\t\tif (input.platformUrl) {\n\t\t\tconst platform = input.platformUrl.trim().replace(/\\/$/, '')\n\t\t\tbaseUrl = platform.includes('/v1') ? platform : `${platform}/v1`\n\t\t} else {\n\t\t\tconst domain = input.domain?.trim() || 'api.sylphx.com'\n\t\t\tbaseUrl = `https://${slug}.${domain}/v1`\n\t\t}\n\n\t\treturn freezeConfig({\n\t\t\tcredential: trimmedCred,\n\t\t\tcredentialType: prefix,\n\t\t\tenv,\n\t\t\tslug,\n\t\t\tbaseUrl,\n\t\t\taccessToken: input.accessToken,\n\t\t})\n\t}\n\n\tthrow new SylphxError(\n\t\t`[Sylphx] Invalid credential format. Expected (pk|sk)_(dev|stg|prod|prev)_[a-f0-9]{32,64}. Got: \"${trimmedCred.slice(0, 30)}...\"`,\n\t\t{ code: 'BAD_REQUEST' },\n\t)\n}\n\n// =============================================================================\n// Config utilities\n// =============================================================================\n\n/**\n * Create a new config with an updated access token.\n *\n * Returns a new frozen config — does not mutate the original.\n *\n * @example\n * ```typescript\n * const authenticatedConfig = withToken(config, 'access_token_here')\n * ```\n */\nexport function withToken(config: SylphxConfig, accessToken: string): SylphxConfig {\n\treturn Object.freeze({\n\t\t...config,\n\t\taccessToken,\n\t})\n}\n\n// =============================================================================\n// Backward compatibility — createConfig (deprecated, will be removed)\n// =============================================================================\n\n/**\n * @deprecated Use `createClient()` or `createServerClient()` instead.\n * This function is kept temporarily for migration but will be removed.\n */\nexport type SylphxConfigInput = string | SylphxClientInput\n\n/**\n * @deprecated Use `createClient()` instead. See ADR-055.\n */\nexport const createConfig = createClient\n\n// =============================================================================\n// Request helpers — internal SDK plumbing\n// =============================================================================\n\n/**\n * Map HTTP status code to SylphxErrorCode\n */\nfunction httpStatusToErrorCode(status: number): SylphxErrorCode {\n\tswitch (status) {\n\t\tcase 400:\n\t\t\treturn 'BAD_REQUEST'\n\t\tcase 401:\n\t\t\treturn 'UNAUTHORIZED'\n\t\tcase 403:\n\t\t\treturn 'FORBIDDEN'\n\t\tcase 404:\n\t\t\treturn 'NOT_FOUND'\n\t\tcase 409:\n\t\t\treturn 'CONFLICT'\n\t\tcase 413:\n\t\t\treturn 'PAYLOAD_TOO_LARGE'\n\t\tcase 422:\n\t\t\treturn 'UNPROCESSABLE_ENTITY'\n\t\tcase 429:\n\t\t\treturn 'TOO_MANY_REQUESTS'\n\t\tcase 500:\n\t\t\treturn 'INTERNAL_SERVER_ERROR'\n\t\tcase 501:\n\t\t\treturn 'NOT_IMPLEMENTED'\n\t\tcase 502:\n\t\t\treturn 'BAD_GATEWAY'\n\t\tcase 503:\n\t\t\treturn 'SERVICE_UNAVAILABLE'\n\t\tcase 504:\n\t\t\treturn 'GATEWAY_TIMEOUT'\n\t\tdefault:\n\t\t\treturn status >= 500 ? 'INTERNAL_SERVER_ERROR' : 'BAD_REQUEST'\n\t}\n}\n\n/**\n * Internal: Build headers for API requests.\n *\n * Sends the credential as `x-app-secret` header.\n */\nexport function buildHeaders(config: SylphxConfig): Record<string, string> {\n\tconst headers: Record<string, string> = {\n\t\t'Content-Type': 'application/json',\n\t}\n\n\tif (config.credential) {\n\t\theaders['x-app-secret'] = config.credential\n\t}\n\tif (config.accessToken) {\n\t\theaders.Authorization = `Bearer ${config.accessToken}`\n\t}\n\n\treturn headers\n}\n\n/**\n * Internal: Build REST API URL.\n *\n * Appends path to the pre-computed base URL.\n */\nexport function buildApiUrl(config: SylphxConfig, path: string): string {\n\tconst base = config.baseUrl.replace(/\\/$/, '')\n\tconst cleanPath = path.startsWith('/') ? path : `/${path}`\n\treturn `${base}${cleanPath}`\n}\n\n/**\n * Internal: Call REST API endpoint.\n *\n * Features:\n * - Request timeout (default 30s) prevents infinite hangs\n * - Proper HTTP status code mapping to error codes\n * - Safe JSON parsing with error handling\n * - Idempotency key support (Stripe pattern)\n */\nexport async function callApi<TOutput>(\n\tconfig: SylphxConfig,\n\tpath: string,\n\toptions: {\n\t\tmethod?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'\n\t\tbody?: unknown\n\t\tquery?: Record<string, string | number | boolean | undefined>\n\t\ttimeout?: number\n\t\tsignal?: AbortSignal\n\t\tidempotencyKey?: string\n\t\theaders?: Record<string, string>\n\t} = {},\n): Promise<TOutput> {\n\tconst {\n\t\tmethod = 'GET',\n\t\tbody,\n\t\tquery,\n\t\ttimeout = DEFAULT_TIMEOUT_MS,\n\t\tsignal,\n\t\tidempotencyKey,\n\t\theaders: extraHeaders,\n\t} = options\n\n\tlet url = buildApiUrl(config, path)\n\n\t// Add query parameters\n\tif (query) {\n\t\tconst params = new URLSearchParams()\n\t\tfor (const [key, value] of Object.entries(query)) {\n\t\t\tif (value !== undefined) {\n\t\t\t\tparams.set(key, String(value))\n\t\t\t}\n\t\t}\n\t\tconst queryString = params.toString()\n\t\tif (queryString) {\n\t\t\turl += `?${queryString}`\n\t\t}\n\t}\n\n\t// Create AbortController for timeout\n\tconst controller = new AbortController()\n\tconst timeoutId = setTimeout(() => controller.abort(), timeout)\n\n\t// Combine user signal with timeout signal\n\tconst combinedSignal = signal ? AbortSignal.any([signal, controller.signal]) : controller.signal\n\n\tconst headers = buildHeaders(config)\n\n\t// Add idempotency key header for safe retries (Stripe pattern)\n\tif (idempotencyKey) {\n\t\theaders['Idempotency-Key'] = idempotencyKey\n\t}\n\n\t// Merge user-supplied headers\n\tif (extraHeaders) {\n\t\tfor (const [k, v] of Object.entries(extraHeaders)) {\n\t\t\theaders[k] = v\n\t\t}\n\t}\n\n\tconst fetchOptions: RequestInit = {\n\t\tmethod,\n\t\theaders,\n\t\tsignal: combinedSignal,\n\t}\n\n\tif (body) {\n\t\tfetchOptions.body = JSON.stringify(body)\n\t}\n\n\tlet response: Response\n\ttry {\n\t\tresponse = await fetch(url, fetchOptions)\n\t} catch (error) {\n\t\tclearTimeout(timeoutId)\n\n\t\t// Handle abort/timeout\n\t\tif (error instanceof Error) {\n\t\t\tif (error.name === 'AbortError') {\n\t\t\t\t// Check if it was our timeout or user cancellation\n\t\t\t\tif (controller.signal.aborted && !signal?.aborted) {\n\t\t\t\t\tthrow new TimeoutError(timeout)\n\t\t\t\t}\n\t\t\t\tthrow new SylphxError('Request aborted', {\n\t\t\t\t\tcode: 'ABORTED',\n\t\t\t\t\tcause: error,\n\t\t\t\t})\n\t\t\t}\n\t\t\t// Network errors\n\t\t\tthrow new NetworkError(error.message, { cause: error })\n\t\t}\n\t\tthrow new NetworkError('Network request failed')\n\t} finally {\n\t\tclearTimeout(timeoutId)\n\t}\n\n\tif (!response.ok) {\n\t\tconst errorBody = await response.text().catch(() => '')\n\t\tlet errorMessage = 'Request failed'\n\t\tlet errorData: Record<string, unknown> | undefined\n\n\t\t// Safe JSON parsing\n\t\tif (errorBody) {\n\t\t\ttry {\n\t\t\t\tconst parsed = JSON.parse(errorBody) as {\n\t\t\t\t\terror?: { message?: string }\n\t\t\t\t\tmessage?: string\n\t\t\t\t}\n\t\t\t\terrorMessage = parsed.error?.message ?? parsed.message ?? errorMessage\n\t\t\t\terrorData = parsed.error as Record<string, unknown> | undefined\n\t\t\t} catch {\n\t\t\t\terrorMessage = response.statusText || errorMessage\n\t\t\t}\n\t\t}\n\n\t\tconst errorCode = httpStatusToErrorCode(response.status)\n\n\t\t// Extract rate limit headers (Stripe SDK pattern)\n\t\tconst retryAfterHeader = response.headers.get('Retry-After')\n\t\tconst rateLimitLimit = response.headers.get('X-RateLimit-Limit')\n\t\tconst rateLimitRemaining = response.headers.get('X-RateLimit-Remaining')\n\t\tconst rateLimitReset = response.headers.get('X-RateLimit-Reset')\n\n\t\tconst retryAfter = retryAfterHeader ? Number.parseInt(retryAfterHeader, 10) : undefined\n\n\t\t// Use specialized RateLimitError for 429 responses\n\t\tif (response.status === 429) {\n\t\t\tthrow new RateLimitError(errorMessage || 'Too many requests', {\n\t\t\t\tstatus: response.status,\n\t\t\t\tdata: errorData,\n\t\t\t\tretryAfter,\n\t\t\t\tlimit: rateLimitLimit ? Number.parseInt(rateLimitLimit, 10) : undefined,\n\t\t\t\tremaining: rateLimitRemaining ? Number.parseInt(rateLimitRemaining, 10) : undefined,\n\t\t\t\tresetAt: rateLimitReset ? Number.parseInt(rateLimitReset, 10) : undefined,\n\t\t\t})\n\t\t}\n\n\t\tthrow new SylphxError(errorMessage, {\n\t\t\tcode: errorCode,\n\t\t\tstatus: response.status,\n\t\t\tdata: errorData,\n\t\t\tretryAfter,\n\t\t})\n\t}\n\n\t// Handle empty responses (204 No Content)\n\tconst text = await response.text()\n\tif (!text) {\n\t\treturn {} as TOutput\n\t}\n\n\t// Safe JSON parsing for response body\n\ttry {\n\t\treturn JSON.parse(text) as TOutput\n\t} catch (error) {\n\t\tthrow new SylphxError('Failed to parse response', {\n\t\t\tcode: 'PARSE_ERROR',\n\t\t\tcause: error instanceof Error ? error : undefined,\n\t\t\tdata: { body: text.slice(0, 200) },\n\t\t})\n\t}\n}\n","/**\n * SDK Debug Mode\n *\n * Centralized debug logging for the SDK.\n *\n * Enable via:\n * - Browser: `localStorage.setItem('sylphx_debug', 'true')`\n * - Node.js: `SYLPHX_DEBUG=true`\n *\n * Debug messages are namespaced with [Sylphx] prefix for easy filtering.\n */\n\n// ============================================================================\n// Debug Configuration\n// ============================================================================\n\n/** Storage key for browser-side debug toggle */\nconst DEBUG_STORAGE_KEY = 'sylphx_debug'\n\n/**\n * Check if debug mode is enabled\n *\n * Checks multiple sources in order:\n * 1. localStorage (browser)\n * 2. SYLPHX_DEBUG environment variable\n * 3. NODE_ENV === 'development' with explicit opt-in\n */\nfunction isDebugEnabled(): boolean {\n\t// Browser environment\n\tif (typeof window !== 'undefined' && typeof localStorage !== 'undefined') {\n\t\ttry {\n\t\t\treturn localStorage.getItem(DEBUG_STORAGE_KEY) === 'true'\n\t\t} catch {\n\t\t\t// localStorage may be blocked in some contexts\n\t\t\treturn false\n\t\t}\n\t}\n\n\t// Node.js environment\n\tif (typeof process !== 'undefined' && process.env) {\n\t\treturn process.env.SYLPHX_DEBUG === 'true'\n\t}\n\n\treturn false\n}\n\n// Cache the debug state to avoid repeated localStorage/env checks\nlet debugModeCache: boolean | null = null\n\n/**\n * Whether debug mode is currently enabled\n *\n * Cached after first access for performance.\n */\nexport function getDebugMode(): boolean {\n\tif (debugModeCache === null) {\n\t\tdebugModeCache = isDebugEnabled()\n\t}\n\treturn debugModeCache\n}\n\n/**\n * Reset debug mode cache (for testing)\n */\nexport function resetDebugModeCache(): void {\n\tdebugModeCache = null\n}\n\n// ============================================================================\n// Debug Logging\n// ============================================================================\n\n/** Debug log categories */\nexport type DebugCategory =\n\t| 'auth'\n\t| 'api'\n\t| 'analytics'\n\t| 'flags'\n\t| 'storage'\n\t| 'cache'\n\t| 'token'\n\t| 'webhook'\n\t| 'error'\n\n/**\n * Log a debug message with category prefix\n *\n * @example\n * ```ts\n * debugLog('auth', 'Token refreshed', { expiresIn: 300 })\n * // [Sylphx auth] Token refreshed { expiresIn: 300 }\n * ```\n */\nexport function debugLog(category: DebugCategory, message: string, data?: unknown): void {\n\tif (!getDebugMode()) return\n\n\tconst prefix = `[Sylphx ${category}]`\n\n\tif (data !== undefined) {\n\t\tconsole.log(prefix, message, data)\n\t} else {\n\t\tconsole.log(prefix, message)\n\t}\n}\n\n/**\n * Log a debug warning with category prefix\n */\nexport function debugWarn(category: DebugCategory, message: string, data?: unknown): void {\n\tif (!getDebugMode()) return\n\n\tconst prefix = `[Sylphx ${category}]`\n\n\tif (data !== undefined) {\n\t\tconsole.warn(prefix, message, data)\n\t} else {\n\t\tconsole.warn(prefix, message)\n\t}\n}\n\n/**\n * Log a debug error with category prefix\n *\n * Note: This always logs when debug mode is enabled, regardless of error severity.\n * Production error tracking should use the error tracking service, not this.\n */\nexport function debugError(category: DebugCategory, message: string, error?: unknown): void {\n\tif (!getDebugMode()) return\n\n\tconst prefix = `[Sylphx ${category}]`\n\n\tif (error !== undefined) {\n\t\tconsole.error(prefix, message, error)\n\t} else {\n\t\tconsole.error(prefix, message)\n\t}\n}\n\n// ============================================================================\n// Performance Timing\n// ============================================================================\n\n/**\n * Create a debug timer for measuring operation duration\n *\n * @example\n * ```ts\n * const timer = debugTimer('api', 'Fetching user profile')\n * // ... operation ...\n * timer.end() // Logs duration if debug mode enabled\n * ```\n */\nexport function debugTimer(category: DebugCategory, operation: string): { end: () => void } {\n\tif (!getDebugMode()) {\n\t\treturn { end: () => {} }\n\t}\n\n\tconst start = performance.now()\n\n\treturn {\n\t\tend() {\n\t\t\tconst duration = performance.now() - start\n\t\t\tdebugLog(category, `${operation} completed`, {\n\t\t\t\tdurationMs: Math.round(duration),\n\t\t\t})\n\t\t},\n\t}\n}\n\n// ============================================================================\n// Browser Console Helpers\n// ============================================================================\n\n/**\n * Enable debug mode from browser console\n *\n * Call this in the browser console to enable debug logging:\n * ```js\n * window.__sylphx?.enableDebug()\n * ```\n */\nexport function enableDebug(): void {\n\tif (typeof localStorage === 'undefined') {\n\t\tconsole.warn('[Sylphx] Debug mode can only be enabled in browser environments')\n\t\treturn\n\t}\n\n\ttry {\n\t\tlocalStorage.setItem(DEBUG_STORAGE_KEY, 'true')\n\t\tdebugModeCache = true\n\t\tconsole.log('[Sylphx] Debug mode enabled. Refresh the page to see debug logs.')\n\t} catch (e) {\n\t\tconsole.warn('[Sylphx] Failed to enable debug mode:', e)\n\t}\n}\n\n/**\n * Disable debug mode from browser console\n */\nexport function disableDebug(): void {\n\tif (typeof localStorage === 'undefined') {\n\t\tconsole.warn('[Sylphx] Debug mode can only be disabled in browser environments')\n\t\treturn\n\t}\n\n\ttry {\n\t\tlocalStorage.removeItem(DEBUG_STORAGE_KEY)\n\t\tdebugModeCache = false\n\t\tconsole.log('[Sylphx] Debug mode disabled.')\n\t} catch (e) {\n\t\tconsole.warn('[Sylphx] Failed to disable debug mode:', e)\n\t}\n}\n\n// ============================================================================\n// Global Window Helper (Browser Only)\n// ============================================================================\n\n/**\n * Install debug helpers on window.__sylphx\n *\n * This is called automatically when the SDK is loaded in the browser,\n * providing developers easy console access to debug utilities.\n */\nexport function installGlobalDebugHelpers(): void {\n\tif (typeof window === 'undefined') return\n\n\t// Use type assertion to extend window\n\tconst w = window as typeof window & {\n\t\t__sylphx?: {\n\t\t\tenableDebug: typeof enableDebug\n\t\t\tdisableDebug: typeof disableDebug\n\t\t\tisDebugEnabled: typeof getDebugMode\n\t\t}\n\t}\n\n\tw.__sylphx = {\n\t\tenableDebug,\n\t\tdisableDebug,\n\t\tisDebugEnabled: getDebugMode,\n\t}\n}\n","/**\n * REST Client for Sylphx Platform\n *\n * Type-safe REST API client using openapi-fetch with full type inference\n * from OpenAPI specification. No tRPC dependencies.\n *\n * @example\n * ```typescript\n * import { createRestClient } from '@sylphx/sdk'\n *\n * const client = createRestClient({\n * secretKey: process.env.SYLPHX_SECRET_KEY!,\n * })\n *\n * // Full type inference from OpenAPI\n * const { data: user } = await client.GET('/auth/me')\n * const { data: plans } = await client.GET('/billing/plans')\n * const { data: result } = await client.POST('/auth/login', {\n * body: { email, password }\n * })\n * ```\n */\n\nimport createClient, { type Middleware } from 'openapi-fetch'\nimport {\n\tBASE_RETRY_DELAY_MS,\n\tCIRCUIT_BREAKER_FAILURE_THRESHOLD,\n\tCIRCUIT_BREAKER_OPEN_DURATION_MS,\n\tCIRCUIT_BREAKER_WINDOW_MS,\n\tDEFAULT_SDK_API_HOST,\n\tDEFAULT_TIMEOUT_MS,\n\tETAG_CACHE_MAX_ENTRIES,\n\tETAG_CACHE_TTL_MS,\n\tMAX_RETRY_DELAY_MS,\n\tSDK_API_PATH,\n\tSDK_PLATFORM,\n\tSDK_VERSION,\n} from './constants'\nimport { exponentialBackoff } from './errors'\nimport type { paths } from './generated/api'\nimport { validateAndSanitizeSecretKey } from './key-validation'\n\n// Re-export types for consumers\nexport type { paths }\n\n/**\n * Retry configuration for automatic request retries\n */\nexport interface RetryConfig {\n\t/** Maximum number of retries (default: 3) */\n\tmaxRetries?: number\n\t/** Base delay in milliseconds (default: 1000) */\n\tbaseDelay?: number\n\t/** Maximum delay in milliseconds (default: 30000) */\n\tmaxDelay?: number\n\t/** Custom function to determine if error is retryable */\n\tshouldRetry?: (status: number, attempt: number) => boolean\n\t/** Request timeout in milliseconds (default: 30000) */\n\ttimeout?: number\n}\n\n/**\n * Request deduplication configuration\n */\nexport interface DeduplicationConfig {\n\t/** Enable request deduplication (default: true) */\n\tenabled?: boolean\n\t/** HTTP methods to deduplicate (default: ['GET']) */\n\tmethods?: ('GET' | 'POST' | 'PUT' | 'DELETE')[]\n}\n\n/**\n * Circuit breaker configuration (AWS/Resilience4j pattern)\n *\n * Prevents cascade failures by fast-failing when service is unhealthy.\n * States: CLOSED (normal) → OPEN (failing) → HALF_OPEN (testing)\n */\nexport interface CircuitBreakerConfig {\n\t/** Enable circuit breaker (default: true) */\n\tenabled?: boolean\n\t/** Number of failures before opening circuit (default: 5) */\n\tfailureThreshold?: number\n\t/** Time window for counting failures in ms (default: 10000) */\n\twindowMs?: number\n\t/** How long circuit stays open in ms (default: 30000) */\n\topenDurationMs?: number\n\t/** Custom function to determine if response is a failure */\n\tisFailure?: (status: number) => boolean\n}\n\n/**\n * ETag/Conditional request configuration (HTTP caching pattern)\n *\n * Enables HTTP conditional requests with If-None-Match header\n * to avoid re-downloading unchanged data (saves bandwidth).\n */\nexport interface ETagConfig {\n\t/** Enable ETag caching (default: true for GET requests) */\n\tenabled?: boolean\n\t/** Maximum cache entries (default: 100) */\n\tmaxEntries?: number\n\t/** Cache TTL in milliseconds (default: 5 minutes) */\n\tttlMs?: number\n}\n\n/**\n * Configuration for the REST client\n *\n * The app key identifies the app — no separate app ID needed.\n */\nexport interface RestClientConfig {\n\t/**\n\t * Your app key — identifies the app and environment.\n\t *\n\t * Accepts either:\n\t * - Secret key (sk_dev_, sk_stg_, sk_prod_) — full access, server-side only\n\t * - Publishable key (app_dev_, app_stg_, app_prod_) — limited access, safe for client\n\t */\n\tsecretKey: string\n\t/** Platform URL (default: https://sylphx.com) */\n\tplatformUrl?: string\n\t/** Retry configuration (default: 3 retries with exponential backoff) */\n\tretry?: RetryConfig | false\n\t/**\n\t * Request deduplication configuration (default: enabled for GET)\n\t *\n\t * Prevents duplicate concurrent requests for the same resource.\n\t * When multiple components request the same data simultaneously,\n\t * only one API call is made and the result is shared.\n\t */\n\tdeduplication?: DeduplicationConfig | false\n\t/**\n\t * Circuit breaker configuration (default: enabled)\n\t *\n\t * Prevents cascade failures by fast-failing when service is unhealthy.\n\t * Opens after 5 failures in 10s, stays open for 30s, then allows test request.\n\t */\n\tcircuitBreaker?: CircuitBreakerConfig | false\n\t/**\n\t * ETag caching configuration (default: enabled for GET)\n\t *\n\t * Uses HTTP conditional requests to avoid re-downloading unchanged data.\n\t * Saves bandwidth by returning 304 Not Modified when content hasn't changed.\n\t */\n\tetag?: ETagConfig | false\n}\n\n/**\n * Dynamic configuration that can change at runtime (e.g., access token)\n */\nexport interface RestDynamicConfig {\n\t/** Your secret key (sk_* or app_*) — identifies the app */\n\tsecretKey?: string\n\t/** Platform URL (default: https://sylphx.com) */\n\tplatformUrl?: string\n\t/** Get the current access token (called on each request) */\n\tgetAccessToken?: () => string | null | undefined\n\t/** Retry configuration (default: 3 retries with exponential backoff) */\n\tretry?: RetryConfig | false\n\t/** Request deduplication configuration (default: enabled for GET) */\n\tdeduplication?: DeduplicationConfig | false\n\t/** Circuit breaker configuration (default: enabled) */\n\tcircuitBreaker?: CircuitBreakerConfig | false\n\t/** ETag caching configuration (default: enabled for GET) */\n\tetag?: ETagConfig | false\n}\n\n/**\n * Create auth middleware that adds app credentials, access token, and SDK headers\n */\nfunction createAuthMiddleware(config: RestDynamicConfig): Middleware {\n\treturn {\n\t\tasync onRequest({ request }) {\n\t\t\t// Add SDK identification headers for debugging and analytics\n\t\t\trequest.headers.set('X-SDK-Version', SDK_VERSION)\n\t\t\trequest.headers.set('X-SDK-Platform', SDK_PLATFORM)\n\n\t\t\t// Add secret key if provided — identifies the app\n\t\t\tif (config.secretKey) {\n\t\t\t\trequest.headers.set('x-app-secret', config.secretKey)\n\t\t\t}\n\n\t\t\t// Add access token if available\n\t\t\tconst token = config.getAccessToken?.()\n\t\t\tif (token) {\n\t\t\t\trequest.headers.set('Authorization', `Bearer ${token}`)\n\t\t\t}\n\n\t\t\treturn request\n\t\t},\n\t}\n}\n\n/**\n * Check if a status code is retryable\n */\nfunction isRetryableStatus(status: number): boolean {\n\treturn status >= 500 || status === 429\n}\n\n// ============================================================================\n// Request Deduplication (React Query/SWR pattern)\n// ============================================================================\n\n/**\n * In-flight request tracking for deduplication\n *\n * When the same request is made multiple times concurrently,\n * we return the existing promise instead of making a new request.\n * This prevents duplicate API calls and improves efficiency.\n */\nconst inFlightRequests = new Map<string, Promise<Response>>()\n\n/**\n * Generate a unique key for a request (for deduplication)\n */\nasync function getRequestKey(request: Request): Promise<string> {\n\tconst body = request.body ? await request.clone().text() : ''\n\treturn `${request.method}:${request.url}:${body}`\n}\n\n/**\n * Create request deduplication middleware (React Query/SWR pattern)\n *\n * Features:\n * - Deduplicates concurrent identical requests\n * - Only applies to GET requests by default (safe to dedupe)\n * - POST/PUT/DELETE are always executed (mutations must run)\n * - Cleans up in-flight tracking after completion\n *\n * @param config - Whether to enable deduplication (default: GET only)\n */\nfunction createDeduplicationMiddleware(\n\tconfig: { enabled?: boolean; methods?: ('GET' | 'POST' | 'PUT' | 'DELETE')[] } = {},\n): Middleware {\n\tconst { enabled = true, methods = ['GET'] } = config\n\n\tif (!enabled) {\n\t\treturn {\n\t\t\tasync onRequest({ request }) {\n\t\t\t\treturn request\n\t\t\t},\n\t\t}\n\t}\n\n\treturn {\n\t\tasync onRequest({ request }) {\n\t\t\t// Only dedupe specified methods (default: GET only)\n\t\t\tif (!methods.includes(request.method as 'GET')) {\n\t\t\t\treturn request\n\t\t\t}\n\n\t\t\tconst key = await getRequestKey(request)\n\n\t\t\t// Check if there's an in-flight request\n\t\t\tconst existing = inFlightRequests.get(key)\n\t\t\tif (existing) {\n\t\t\t\t// Return a new Request that will be handled specially in onResponse\n\t\t\t\tconst deduped = request.clone()\n\t\t\t\t;(deduped as unknown as { _dedupKey: string })._dedupKey = key\n\t\t\t\treturn deduped\n\t\t\t}\n\t\t\t// Mark request key (so onResponse knows to track it)\n\t\t\t;(request as unknown as { _dedupKey: string })._dedupKey = key\n\t\t\treturn request\n\t\t},\n\t\tasync onResponse({ request, response }) {\n\t\t\tconst key = (request as unknown as { _dedupKey?: string })._dedupKey\n\t\t\tif (!key) return response\n\n\t\t\t// If there's already an in-flight request, wait for it\n\t\t\tconst existing = inFlightRequests.get(key)\n\t\t\tif (existing && inFlightRequests.get(key) !== undefined) {\n\t\t\t\t// Another request is in flight, clone its response\n\t\t\t\tconst cachedResponse = await existing\n\t\t\t\treturn cachedResponse.clone()\n\t\t\t}\n\n\t\t\t// This is the first request, track it\n\t\t\tconst responsePromise = Promise.resolve(response.clone())\n\t\t\tinFlightRequests.set(key, responsePromise)\n\n\t\t\t// Clean up after response is consumed\n\t\t\tresponsePromise.finally(() => {\n\t\t\t\t// Small delay to allow concurrent requests to find the cached response\n\t\t\t\tsetTimeout(() => inFlightRequests.delete(key), 100)\n\t\t\t})\n\n\t\t\treturn response\n\t\t},\n\t}\n}\n\n// ============================================================================\n// Circuit Breaker (AWS/Resilience4j pattern)\n// ============================================================================\n\n/**\n * Circuit breaker state machine\n *\n * CLOSED: Normal operation, requests pass through\n * OPEN: Service unhealthy, all requests fast-fail\n * HALF_OPEN: Testing recovery, allows one request\n */\nexport type CircuitState = 'CLOSED' | 'OPEN' | 'HALF_OPEN'\n\n/**\n * Error thrown when circuit is open\n */\nexport class CircuitBreakerOpenError extends Error {\n\treadonly remainingMs: number\n\n\tconstructor(remainingMs: number) {\n\t\tsuper(`Circuit breaker is open. Retry after ${Math.ceil(remainingMs / 1000)}s`)\n\t\tthis.name = 'CircuitBreakerOpenError'\n\t\tthis.remainingMs = remainingMs\n\t}\n}\n\n/**\n * Circuit breaker instance with state management\n */\ninterface CircuitBreaker {\n\tstate: CircuitState\n\tfailures: number[]\n\topenedAt: number | null\n\tconfig: Required<CircuitBreakerConfig>\n}\n\n/**\n * Create a fresh circuit breaker instance.\n *\n * Each REST client gets its own instance — no shared module-level singleton.\n * This prevents cross-client state bleed and makes testing reliable.\n */\nfunction createCircuitBreakerInstance(config: CircuitBreakerConfig = {}): CircuitBreaker {\n\treturn {\n\t\tstate: 'CLOSED',\n\t\tfailures: [],\n\t\topenedAt: null,\n\t\tconfig: {\n\t\t\tenabled: config.enabled ?? true,\n\t\t\tfailureThreshold: config.failureThreshold ?? CIRCUIT_BREAKER_FAILURE_THRESHOLD,\n\t\t\twindowMs: config.windowMs ?? CIRCUIT_BREAKER_WINDOW_MS,\n\t\t\topenDurationMs: config.openDurationMs ?? CIRCUIT_BREAKER_OPEN_DURATION_MS,\n\t\t\tisFailure: config.isFailure ?? ((status) => status >= 500 || status === 429),\n\t\t},\n\t}\n}\n\n/**\n * Record a failure and potentially open the circuit\n */\nfunction recordFailure(cb: CircuitBreaker): void {\n\tconst now = Date.now()\n\n\t// Remove old failures outside the window\n\tcb.failures = cb.failures.filter((t) => now - t < cb.config.windowMs)\n\n\t// Add new failure\n\tcb.failures.push(now)\n\n\t// Check if threshold exceeded\n\tif (cb.failures.length >= cb.config.failureThreshold) {\n\t\tcb.state = 'OPEN'\n\t\tcb.openedAt = now\n\t}\n}\n\n/**\n * Record a success and potentially close the circuit\n */\nfunction recordSuccess(cb: CircuitBreaker): void {\n\tif (cb.state === 'HALF_OPEN') {\n\t\t// Test request succeeded, close the circuit\n\t\tcb.state = 'CLOSED'\n\t\tcb.failures = []\n\t\tcb.openedAt = null\n\t}\n}\n\n/**\n * Check if circuit should allow request\n */\nfunction shouldAllowRequest(cb: CircuitBreaker): {\n\tallowed: boolean\n\tremainingMs?: number\n} {\n\tconst now = Date.now()\n\n\tswitch (cb.state) {\n\t\tcase 'CLOSED':\n\t\t\treturn { allowed: true }\n\n\t\tcase 'OPEN': {\n\t\t\tconst elapsed = now - (cb.openedAt ?? now)\n\t\t\tif (elapsed >= cb.config.openDurationMs) {\n\t\t\t\t// Timeout expired, transition to half-open\n\t\t\t\tcb.state = 'HALF_OPEN'\n\t\t\t\treturn { allowed: true }\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tallowed: false,\n\t\t\t\tremainingMs: cb.config.openDurationMs - elapsed,\n\t\t\t}\n\t\t}\n\n\t\tcase 'HALF_OPEN':\n\t\t\t// Only allow one test request at a time\n\t\t\t// In production, you'd use a flag to track if test is in progress\n\t\t\treturn { allowed: true }\n\n\t\tdefault:\n\t\t\treturn { allowed: true }\n\t}\n}\n\n/**\n * Create circuit breaker middleware (AWS/Resilience4j pattern)\n *\n * Features:\n * - Fast-fails when service is unhealthy (prevents cascade failures)\n * - Auto-recovery with half-open state for testing\n * - Configurable failure threshold and timeout\n * - Only counts server errors (5xx) and rate limits (429)\n * - Per-client instance: no shared module-level state\n */\nfunction createCircuitBreakerMiddleware(\n\tconfig: CircuitBreakerConfig | false | undefined,\n): Middleware {\n\tif (config === false) {\n\t\treturn {\n\t\t\tasync onRequest({ request }) {\n\t\t\t\treturn request\n\t\t\t},\n\t\t}\n\t}\n\n\t// Create a fresh circuit breaker per client (not a module-level singleton)\n\tconst cb = createCircuitBreakerInstance(config ?? {})\n\n\t// Track for deprecated getCircuitBreakerState() / resetCircuitBreaker() test helpers\n\t_lastCircuitBreaker = cb\n\n\treturn {\n\t\tasync onRequest({ request }) {\n\t\t\tif (!cb.config.enabled) {\n\t\t\t\treturn request\n\t\t\t}\n\n\t\t\tconst check = shouldAllowRequest(cb)\n\t\t\tif (!check.allowed) {\n\t\t\t\tthrow new CircuitBreakerOpenError(check.remainingMs!)\n\t\t\t}\n\n\t\t\treturn request\n\t\t},\n\t\tasync onResponse({ response }) {\n\t\t\tif (!cb.config.enabled) {\n\t\t\t\treturn response\n\t\t\t}\n\n\t\t\tif (cb.config.isFailure(response.status)) {\n\t\t\t\trecordFailure(cb)\n\t\t\t} else {\n\t\t\t\trecordSuccess(cb)\n\t\t\t}\n\n\t\t\treturn response\n\t\t},\n\t}\n}\n\n/**\n * Module-level reference to the most recently created circuit breaker.\n *\n * Used ONLY by the deprecated `getCircuitBreakerState()` / `resetCircuitBreaker()`\n * helpers (kept for backward compatibility with test suites).\n *\n * Production code should use `client.circuitBreaker.getState()` / `.reset()`\n * from the client object returned by `createRestClient()`.\n */\nlet _lastCircuitBreaker: CircuitBreaker | null = null\n\n/**\n * @deprecated Prefer creating a new `createRestClient()` for isolated state in tests.\n * Resets the most recently created circuit breaker and clears the reference,\n * so `getCircuitBreakerState()` returns null until the next client is created.\n */\nexport function resetCircuitBreaker(): void {\n\tif (_lastCircuitBreaker) {\n\t\t_lastCircuitBreaker.state = 'CLOSED'\n\t\t_lastCircuitBreaker.failures = []\n\t\t_lastCircuitBreaker.openedAt = null\n\t}\n\t_lastCircuitBreaker = null\n}\n\n/**\n * @deprecated Prefer `client.circuitBreaker.getState()` for per-instance state.\n * Returns state of the most recently created circuit breaker (test helper only).\n */\nexport function getCircuitBreakerState(): {\n\tstate: CircuitState\n\tfailures: number\n\topenedAt: number | null\n} | null {\n\tif (!_lastCircuitBreaker) return null\n\treturn {\n\t\tstate: _lastCircuitBreaker.state,\n\t\tfailures: _lastCircuitBreaker.failures.length,\n\t\topenedAt: _lastCircuitBreaker.openedAt,\n\t}\n}\n\n// ============================================================================\n// ETag Cache (HTTP conditional requests)\n// ============================================================================\n\n/**\n * Cached response entry with ETag\n */\ninterface ETagCacheEntry {\n\tetag: string\n\tbody: string\n\ttimestamp: number\n}\n\n/**\n * ETag cache with LRU eviction\n */\nconst etagCache = new Map<string, ETagCacheEntry>()\n\n/**\n * Generate cache key for request\n */\nfunction getETagCacheKey(request: Request): string {\n\treturn `${request.method}:${request.url}`\n}\n\n/**\n * Evict oldest entries when cache is full\n */\nfunction evictOldEntries(maxEntries: number, ttlMs: number): void {\n\tconst now = Date.now()\n\n\t// First, remove expired entries\n\tfor (const [key, entry] of etagCache) {\n\t\tif (now - entry.timestamp > ttlMs) {\n\t\t\tetagCache.delete(key)\n\t\t}\n\t}\n\n\t// If still over limit, remove oldest entries (LRU)\n\tif (etagCache.size > maxEntries) {\n\t\tconst entries = Array.from(etagCache.entries())\n\t\tentries.sort((a, b) => a[1].timestamp - b[1].timestamp)\n\n\t\tconst toRemove = entries.slice(0, entries.length - maxEntries)\n\t\tfor (const [key] of toRemove) {\n\t\t\tetagCache.delete(key)\n\t\t}\n\t}\n}\n\n/**\n * Create ETag middleware for HTTP conditional requests\n *\n * Features:\n * - Caches responses with ETag headers\n * - Sends If-None-Match on subsequent requests\n * - Returns cached response on 304 Not Modified\n * - LRU eviction when cache is full\n * - TTL-based expiration\n */\nfunction createETagMiddleware(config: ETagConfig | false | undefined): Middleware {\n\tif (config === false) {\n\t\treturn {\n\t\t\tasync onRequest({ request }) {\n\t\t\t\treturn request\n\t\t\t},\n\t\t}\n\t}\n\n\tconst {\n\t\tenabled = true,\n\t\tmaxEntries = ETAG_CACHE_MAX_ENTRIES,\n\t\tttlMs = ETAG_CACHE_TTL_MS,\n\t} = config ?? {}\n\n\tif (!enabled) {\n\t\treturn {\n\t\t\tasync onRequest({ request }) {\n\t\t\t\treturn request\n\t\t\t},\n\t\t}\n\t}\n\n\treturn {\n\t\tasync onRequest({ request }) {\n\t\t\t// Only cache GET requests\n\t\t\tif (request.method !== 'GET') {\n\t\t\t\treturn request\n\t\t\t}\n\n\t\t\tconst cacheKey = getETagCacheKey(request)\n\t\t\tconst cached = etagCache.get(cacheKey)\n\n\t\t\tif (cached) {\n\t\t\t\t// Check TTL\n\t\t\t\tif (Date.now() - cached.timestamp > ttlMs) {\n\t\t\t\t\tetagCache.delete(cacheKey)\n\t\t\t\t} else {\n\t\t\t\t\t// Add If-None-Match header\n\t\t\t\t\trequest.headers.set('If-None-Match', cached.etag)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn request\n\t\t},\n\t\tasync onResponse({ request, response }) {\n\t\t\t// Only cache GET requests\n\t\t\tif (request.method !== 'GET') {\n\t\t\t\treturn response\n\t\t\t}\n\n\t\t\tconst cacheKey = getETagCacheKey(request)\n\n\t\t\t// Handle 304 Not Modified\n\t\t\tif (response.status === 304) {\n\t\t\t\tconst cached = etagCache.get(cacheKey)\n\t\t\t\tif (cached) {\n\t\t\t\t\t// Update timestamp (LRU)\n\t\t\t\t\tcached.timestamp = Date.now()\n\n\t\t\t\t\t// Return cached response with original body\n\t\t\t\t\treturn new Response(cached.body, {\n\t\t\t\t\t\tstatus: 200,\n\t\t\t\t\t\theaders: response.headers,\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t\t// No cache, return original response\n\t\t\t\treturn response\n\t\t\t}\n\n\t\t\t// Cache successful responses with ETag\n\t\t\tif (response.ok) {\n\t\t\t\tconst etag = response.headers.get('ETag')\n\t\t\t\tif (etag) {\n\t\t\t\t\t// Clone response to read body (can only read once)\n\t\t\t\t\tconst cloned = response.clone()\n\t\t\t\t\tconst body = await cloned.text()\n\n\t\t\t\t\t// Evict old entries if needed\n\t\t\t\t\tevictOldEntries(maxEntries, ttlMs)\n\n\t\t\t\t\t// Cache the response\n\t\t\t\t\tetagCache.set(cacheKey, {\n\t\t\t\t\t\tetag,\n\t\t\t\t\t\tbody,\n\t\t\t\t\t\ttimestamp: Date.now(),\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn response\n\t\t},\n\t}\n}\n\n/**\n * Clear ETag cache (for testing)\n */\nexport function clearETagCache(): void {\n\tetagCache.clear()\n}\n\n/**\n * Get ETag cache stats (for monitoring)\n */\nexport function getETagCacheStats(): { size: number; entries: string[] } {\n\treturn {\n\t\tsize: etagCache.size,\n\t\tentries: Array.from(etagCache.keys()),\n\t}\n}\n\n// ============================================================================\n// Retry Middleware\n// ============================================================================\n\n/**\n * Per-request body storage for retry middleware.\n *\n * Using a WeakMap<Request, string | null> ensures each request has its own\n * stored body, preventing race conditions when multiple concurrent requests\n * use the same client instance.\n *\n * WeakMap keys are garbage-collected when the Request object is GC'd,\n * so no manual cleanup is needed.\n */\nconst retryBodyMap = new WeakMap<Request, string | null>()\n\n/**\n * Create retry middleware with exponential backoff and timeout\n *\n * Features:\n * - Request timeout (default 30s) prevents infinite hangs\n * - Exponential backoff with jitter for retries\n * - Respects Retry-After header for rate limiting\n * - Per-request body storage (WeakMap) — safe for concurrent requests\n */\nfunction createRetryMiddleware(retryConfig: RetryConfig | false | undefined): Middleware {\n\tif (retryConfig === false) {\n\t\t// No-op middleware - just passes through\n\t\treturn {\n\t\t\tasync onResponse({ response }) {\n\t\t\t\treturn response\n\t\t\t},\n\t\t}\n\t}\n\n\tconst {\n\t\tmaxRetries = 3,\n\t\tbaseDelay = BASE_RETRY_DELAY_MS,\n\t\tmaxDelay = MAX_RETRY_DELAY_MS,\n\t\tshouldRetry = isRetryableStatus,\n\t\ttimeout = DEFAULT_TIMEOUT_MS,\n\t} = retryConfig ?? {}\n\n\treturn {\n\t\tasync onRequest({ request }) {\n\t\t\t// Read body before it's consumed, store per-request in WeakMap\n\t\t\tconst body = request.body ? await request.clone().text() : null\n\n\t\t\t// Add timeout signal\n\t\t\tconst controller = new AbortController()\n\t\t\tsetTimeout(() => controller.abort(), timeout)\n\n\t\t\tconst newRequest = new Request(request.url, {\n\t\t\t\tmethod: request.method,\n\t\t\t\theaders: request.headers,\n\t\t\t\tbody,\n\t\t\t\tsignal: controller.signal,\n\t\t\t})\n\n\t\t\t// Associate body with this specific request object (concurrent-safe)\n\t\t\tretryBodyMap.set(newRequest, body)\n\n\t\t\treturn newRequest\n\t\t},\n\t\tasync onResponse({ response, request }) {\n\t\t\t// Retrieve body for this specific request (not shared across requests)\n\t\t\tconst originalBody = retryBodyMap.get(request) ?? null\n\n\t\t\tlet attempt = 0\n\t\t\tlet currentResponse = response\n\n\t\t\t// Check if we need to retry using the shouldRetry callback\n\t\t\twhile (attempt < maxRetries && shouldRetry(currentResponse.status, attempt)) {\n\t\t\t\tconst retryAfter = currentResponse.headers.get('Retry-After')\n\t\t\t\tconst delay = retryAfter\n\t\t\t\t\t? Number.parseInt(retryAfter, 10) * 1000\n\t\t\t\t\t: exponentialBackoff(attempt, baseDelay, maxDelay)\n\n\t\t\t\tawait new Promise((resolve) => setTimeout(resolve, delay))\n\t\t\t\tattempt++\n\n\t\t\t\t// Create timeout for retry\n\t\t\t\tconst controller = new AbortController()\n\t\t\t\tconst timeoutId = setTimeout(() => controller.abort(), timeout)\n\n\t\t\t\ttry {\n\t\t\t\t\t// Reconstruct request with per-request stored body and new signal\n\t\t\t\t\tconst retryRequest = new Request(request.url, {\n\t\t\t\t\t\tmethod: request.method,\n\t\t\t\t\t\theaders: request.headers,\n\t\t\t\t\t\tbody: originalBody,\n\t\t\t\t\t\tsignal: controller.signal,\n\t\t\t\t\t})\n\n\t\t\t\t\tconst newResponse = await fetch(retryRequest)\n\t\t\t\t\tclearTimeout(timeoutId)\n\n\t\t\t\t\t// If successful or non-retryable client error, return\n\t\t\t\t\tif (newResponse.ok || !shouldRetry(newResponse.status, attempt)) {\n\t\t\t\t\t\tretryBodyMap.delete(request) // cleanup\n\t\t\t\t\t\treturn newResponse\n\t\t\t\t\t}\n\n\t\t\t\t\tcurrentResponse = newResponse\n\t\t\t\t} catch (error) {\n\t\t\t\t\tclearTimeout(timeoutId)\n\t\t\t\t\t// On network/timeout error during retry, continue to next attempt\n\t\t\t\t\tif (attempt >= maxRetries) {\n\t\t\t\t\t\tretryBodyMap.delete(request) // cleanup\n\t\t\t\t\t\tthrow error\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tretryBodyMap.delete(request) // cleanup\n\t\t\treturn currentResponse\n\t\t},\n\t}\n}\n\n/**\n * Create a type-safe REST API client\n *\n * Uses openapi-fetch with full type inference from OpenAPI specification.\n * All endpoints, inputs, and outputs are automatically typed.\n * Includes automatic retry with exponential backoff for transient failures.\n *\n * @example\n * ```typescript\n * const client = createRestClient({\n * secretKey: process.env.SYLPHX_SECRET_KEY!,\n * })\n *\n * // GET requests\n * const { data: user } = await client.GET('/auth/me')\n * const { data: plans } = await client.GET('/billing/plans')\n *\n * // POST requests\n * const { data: result } = await client.POST('/auth/login', {\n * body: { email: 'test@example.com', password: 'secret' }\n * })\n * ```\n */\n/**\n * Validate and sanitize REST client configuration (SSOT helper)\n */\nfunction validateClientConfig(config: { secretKey?: string; platformUrl?: string }) {\n\treturn {\n\t\tsecretKey: validateAndSanitizeSecretKey(config.secretKey),\n\t\tbaseUrl: (config.platformUrl || `https://${DEFAULT_SDK_API_HOST}`).trim(),\n\t}\n}\n\nexport function createRestClient(config: RestClientConfig) {\n\tconst { secretKey, baseUrl } = validateClientConfig(config)\n\n\tconst client = createClient<paths>({\n\t\tbaseUrl: `${baseUrl}${SDK_API_PATH}`,\n\t\theaders: {\n\t\t\t'Content-Type': 'application/json',\n\t\t\t'x-app-secret': secretKey,\n\t\t},\n\t})\n\n\t// Add deduplication middleware first (before other middleware)\n\tif (config.deduplication !== false) {\n\t\tclient.use(createDeduplicationMiddleware(config.deduplication))\n\t}\n\n\t// Add circuit breaker middleware (before retry)\n\tif (config.circuitBreaker !== false) {\n\t\tclient.use(createCircuitBreakerMiddleware(config.circuitBreaker))\n\t}\n\n\t// Add ETag caching middleware (before retry, for HTTP conditional requests)\n\tif (config.etag !== false) {\n\t\tclient.use(createETagMiddleware(config.etag))\n\t}\n\n\t// Add retry middleware (last, so it can retry after circuit allows)\n\tclient.use(createRetryMiddleware(config.retry))\n\n\treturn client\n}\n\n/**\n * Create a dynamic REST client with runtime token injection\n *\n * Use this when you need to inject an access token that may change.\n * Tokens should be read from HttpOnly cookies via a server endpoint,\n * never from localStorage (XSS vulnerability).\n *\n * @example\n * ```typescript\n * // Server-side usage\n * const client = createDynamicRestClient({\n * secretKey: process.env.SYLPHX_SECRET_KEY!,\n * getAccessToken: async () => (await cookies()).get('session')?.value,\n * })\n * ```\n */\nexport function createDynamicRestClient(config: RestDynamicConfig) {\n\tconst { secretKey, baseUrl } = validateClientConfig(config)\n\n\t// Create validated config for middleware\n\tconst validatedConfig: RestDynamicConfig = {\n\t\t...config,\n\t\tsecretKey,\n\t\tplatformUrl: baseUrl,\n\t}\n\n\tconst client = createClient<paths>({\n\t\tbaseUrl: `${baseUrl}${SDK_API_PATH}`,\n\t\theaders: {\n\t\t\t'Content-Type': 'application/json',\n\t\t},\n\t})\n\n\t// Add deduplication middleware first (before other middleware)\n\tif (config.deduplication !== false) {\n\t\tclient.use(createDeduplicationMiddleware(config.deduplication))\n\t}\n\n\t// Add auth middleware (runs on each request)\n\tclient.use(createAuthMiddleware(validatedConfig))\n\n\t// Add circuit breaker middleware (before retry)\n\tif (config.circuitBreaker !== false) {\n\t\tclient.use(createCircuitBreakerMiddleware(config.circuitBreaker))\n\t}\n\n\t// Add ETag caching middleware (before retry, for HTTP conditional requests)\n\tif (config.etag !== false) {\n\t\tclient.use(createETagMiddleware(config.etag))\n\t}\n\n\t// Add retry middleware (last, so it can retry after circuit allows)\n\tclient.use(createRetryMiddleware(config.retry))\n\n\treturn client\n}\n\n/**\n * Type for the REST client instance\n */\nexport type RestClient = ReturnType<typeof createRestClient>\nexport type DynamicRestClient = ReturnType<typeof createDynamicRestClient>\n\n/**\n * Check if a REST response has an error\n */\nexport function hasError<T, E>(response: {\n\tdata?: T\n\terror?: E\n}): response is {\n\tdata: undefined\n\terror: E\n} {\n\treturn response.error !== undefined\n}\n\n/**\n * Extract error message from REST error response\n */\nexport function getRestErrorMessage(error: unknown): string {\n\tif (error && typeof error === 'object' && 'error' in error) {\n\t\tconst err = error as { error?: { message?: string } }\n\t\treturn err.error?.message ?? 'An unknown error occurred'\n\t}\n\tif (error instanceof Error) {\n\t\treturn error.message\n\t}\n\treturn 'An unknown error occurred'\n}\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 (ADR-021):\n * - Publishable key: pk_(dev|stg|prod)_{ref}_{32hex} — client-safe (new)\n * - Secret Key: sk_(dev|stg|prod)_{ref}_{64hex} — server-side only\n *\n * Legacy Key Formats (backward-compat):\n * - App ID (old): app_(dev|stg|prod)_[identifier] — Public identifier\n *\n * Special Internal Formats (NOT rotated):\n * - Console bootstrap: app_prod_platform_{slug} / sk_prod_platform_{slug}\n */\n\n// =============================================================================\n// Types\n// =============================================================================\n\n/** Environment type derived from key prefix */\nexport type EnvironmentType = 'development' | 'staging' | 'production'\n\n/** Key type - publicKey (pk_*), appId (legacy app_*), or secret (sk_*) */\nexport type KeyType = 'publicKey' | '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 * Publishable key pattern (ADR-021): pk_(dev|stg|prod)_{ref}_{32hex}\n * - Prefix: pk_ (publishable key, safe for client)\n * - Environment: dev, stg, or prod\n * - Ref: 12-char base36 project ref\n * - Token: 32 hex chars (128-bit random)\n *\n * Example: pk_prod_2dubco39o9so_f19e5cdc3cc54f7ff81bdc26ec5bfbad\n */\nconst PUBLIC_KEY_PATTERN = /^pk_(dev|stg|prod)_[a-z0-9]{12}_[a-f0-9]{32}$/\n\n/**\n * Legacy App ID pattern: app_(dev|stg|prod)_[identifier]\n * - Prefix: app_ (application identifier, public) — legacy format, backward-compat\n * - Environment: dev, stg, or prod\n * - Suffix: alphanumeric with underscores/hyphens (hex for apps, or internal identifiers)\n *\n * Accepts both legacy app_* format and ADR-021 pk_* publishable keys.\n * pk_{env}_{ref}_{hex} is the standard customer key — Customer Zero uses it as appId.\n */\nconst APP_ID_PATTERN = /^(app|pk)_(dev|stg|prod|prev)_[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\n * - Suffix: alphanumeric with underscores/hyphens\n *\n * Accepts both old format (sk_prod_{64hex}) and new format (sk_prod_{ref}_{64hex}).\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(keyType: KeyType, issues: string[], envVarName: string): 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(keyType: KeyType, key: string, envVarName: string): string {\n\tconst maskedKey = key.length > 20 ? `${key.slice(0, 20)}...` : key\n\tconst formatHint =\n\t\tkeyType === 'appId' ? 'pk_(dev|stg|prod)_{ref}_{hex} or app_(dev|stg|prod)_[id]' : 'sk_(dev|stg|prod)_{ref}_{hex}'\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: pk_ or 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 pk_, app_, or sk_ prefix followed by environment\n\tconst match = key.match(/^(?:app|pk|sk)_(dev|stg|prod|prev)_/)\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 — Publishable Key (ADR-021: pk_*) and legacy App ID (app_*)\n// =============================================================================\n\n/**\n * Validate an ADR-021 publishable key (pk_*).\n *\n * @example\n * ```typescript\n * const result = validatePublicKey(process.env.NEXT_PUBLIC_SYLPHX_KEY)\n * if (!result.valid) throw new Error(result.error)\n * ```\n */\nexport function validatePublicKey(key: string | undefined | null): KeyValidationResult {\n\treturn validateKeyForType(key, 'publicKey', PUBLIC_KEY_PATTERN, 'NEXT_PUBLIC_SYLPHX_KEY')\n}\n\n/**\n * Validate and sanitize a publishable key, throwing on invalid input.\n */\nexport function validateAndSanitizePublicKey(key: string | undefined | null): string {\n\tconst result = validatePublicKey(key)\n\tif (!result.valid) throw new Error(result.error)\n\tif (result.warning) console.warn(result.warning)\n\treturn result.sanitizedKey\n}\n\n/**\n * Validate a legacy App ID (app_*) and return detailed results.\n *\n * @deprecated Use validatePublicKey() for new pk_* keys (ADR-021).\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(key: string | undefined | null): KeyValidationResult {\n\treturn validateKeyForType(key, 'appId', APP_ID_PATTERN, 'NEXT_PUBLIC_SYLPHX_APP_ID')\n}\n\n/**\n * Validate and sanitize App ID, logging warnings.\n *\n * @deprecated Use validateAndSanitizePublicKey() for new pk_* keys (ADR-021).\n * @throws Error if the key is invalid and cannot be sanitized\n * @returns The sanitized App ID\n */\nexport function validateAndSanitizeAppId(key: string | undefined | null): 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(key: string | undefined | null): KeyValidationResult {\n\treturn validateKeyForType(key, 'secret', SECRET_KEY_PATTERN, 'SYLPHX_SECRET_KEY')\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(key: string | undefined | null): 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 all key types (ADR-021 and legacy)\n\tif (sanitized.startsWith('pk_')) {\n\t\tconst result = validatePublicKey(sanitized)\n\t\tif (!result.valid) throw new Error(result.error)\n\t\treturn result.environment!\n\t}\n\n\tif (sanitized.startsWith('sk_')) {\n\t\tconst result = validateSecretKey(sanitized)\n\t\tif (!result.valid) throw new Error(result.error)\n\t\treturn result.environment!\n\t}\n\n\tif (sanitized.startsWith('app_')) {\n\t\tconst result = validateAppId(sanitized)\n\t\tif (!result.valid) throw new Error(result.error)\n\t\treturn result.environment!\n\t}\n\n\tthrow new Error(\n\t\t`[Sylphx] Invalid key format. Key must start with 'pk_' (publishable), 'sk_' (secret), or 'app_' (legacy 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 = env === '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.\n *\n * @returns 'publicKey' (pk_*), 'appId' (legacy app_*), 'secret' (sk_*), or null if unknown\n */\nexport function detectKeyType(key: string): KeyType | null {\n\tconst sanitized = key.trim().toLowerCase()\n\tif (sanitized.startsWith('pk_')) return 'publicKey'\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 a publishable/public key (pk_* or legacy app_*)\n */\nexport function isPublishableKey(key: string): boolean {\n\tconst t = detectKeyType(key)\n\treturn t === 'publicKey' || t === 'appId'\n}\n\n/**\n * Check if a key is an App ID (legacy app_* format)\n *\n * @deprecated Use isPublishableKey() to also accept new pk_* keys\n */\nexport function isAppId(key: string): boolean {\n\treturn detectKeyType(key) === 'appId'\n}\n\n/**\n * Check if a key is a secret key (sk_*)\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(key: string | undefined | null): KeyValidationResult {\n\tconst keyType = key ? detectKeyType(key) : null\n\n\tif (keyType === 'publicKey') {\n\t\treturn validatePublicKey(key)\n\t}\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 'pk_' (publishable), 'app_' (legacy), or 'sk_' (secret), followed by environment (dev/stg/prod). 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 window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1'\n\t}\n\treturn false\n}\n","/**\n * Auth Functions\n *\n * Pure functions for authentication - no hidden state.\n * Each function takes config as the first parameter.\n *\n * Uses REST API at /api/sdk/auth/* for all operations.\n *\n * Types are derived from the OpenAPI spec (generated/api.d.ts).\n * Run `bun run generate:types:local` to regenerate after API changes.\n */\n\nimport { buildApiUrl, callApi, type SylphxConfig } from './config'\nimport type { components } from './generated/api'\nimport type { User } from './types'\n\n// ============================================================================\n// Types (re-exported from generated OpenAPI spec)\n// ============================================================================\n\nexport type LoginRequest = components['schemas']['LoginRequest']\nexport type LoginResponse = components['schemas']['LoginResponse']\nexport type RegisterRequest = components['schemas']['RegisterRequest']\nexport type RegisterResponse = components['schemas']['RegisterResponse']\n// AuthTokensResponse.user uses '& Record<string, never>' (sealed) which blocks extra User fields.\n// Override user field to be compatible with the SDK's broader User type.\nexport type TokenResponse = Omit<components['schemas']['AuthTokensResponse'], 'user'> & {\n\tuser: User\n}\nexport type TwoFactorVerifyRequest = components['schemas']['TwoFactorVerifyRequest']\n// UserFullProfile — backend returns emailVerified but it's missing from the OpenAPI schema\n// (Zod schema in profile.ts needs updating). Add it manually until the schema is fixed.\nexport type MeResponse = components['schemas']['UserFullProfile'] & { emailVerified?: boolean }\n\n// SDK-specific types (not directly from API schema)\n/**\n * Token introspection result (RFC 7662)\n */\nexport interface TokenIntrospectionResult {\n\t/** Whether the token is active/valid */\n\tactive: boolean\n\t/** Token type (access_token or refresh_token) */\n\ttoken_type?: 'access_token' | 'refresh_token'\n\t/** User ID */\n\tsub?: string\n\t/** User email */\n\temail?: string\n\t/** User name */\n\tname?: string\n\t/** App ID */\n\tclient_id?: string\n\t/** Audience */\n\taud?: string\n\t/** Issuer */\n\tiss?: string\n\t/** Expiration time (Unix timestamp) */\n\texp?: number\n\t/** Issued at time (Unix timestamp) */\n\tiat?: number\n\t/** User role */\n\trole?: string\n\t/** Email verification status */\n\temail_verified?: boolean\n}\n\n/**\n * Token revocation options\n */\nexport interface RevokeTokenOptions {\n\t/** Revoke all tokens for a user in this app */\n\trevokeAll?: boolean\n\t/** User ID (required when revoking all) */\n\tuserId?: string\n}\n\n// SDK-specific types (not in generated API)\nexport interface SessionResult {\n\tuser: {\n\t\tid: string\n\t\temail: string\n\t\tname: string | null\n\t\timage: string | null\n\t\temailVerified: boolean\n\t} | null\n}\n\n/**\n * Extended registration input with metadata and invitation token support.\n * Use extendedSignUp() when you need to pass metadata or an invitation token.\n */\nexport interface RegisterInput {\n\temail: string\n\tpassword: string\n\tname?: string\n\tmetadata?: Record<string, unknown>\n\tinvitationToken?: string\n}\n\n/**\n * Org context claims present in org-scoped tokens (after switch-org).\n *\n * The JWT carries the role key only. Permissions are resolved server-side\n * via Redis-cached role→permissions lookup (WorkOS pattern). This keeps\n * tokens small and ensures permission changes take effect without token refresh.\n */\nexport interface OrgTokenPayload {\n\torg_id: string\n\torg_slug: string\n\t/** RBAC role key (e.g. \"hr_manager\", \"admin\"). Permissions resolved server-side. */\n\torg_role: string\n}\n\n/**\n * Invite a user request payload.\n */\nexport interface InviteUserRequest {\n\temail: string\n\tmetadata?: Record<string, unknown>\n\tredirectUrl?: string\n}\n\n/**\n * Response from inviteUser.\n */\nexport interface InviteUserResponse {\n\tinvitationToken: string\n\texpiresAt: string\n}\n\n// ============================================================================\n// Functions\n// ============================================================================\n\n/**\n * Sign in with email and password\n *\n * @example\n * ```typescript\n * const result = await signIn(config, { email: 'user@example.com', password: 'secret' })\n * if (result.requiresTwoFactor) {\n * // Handle 2FA flow\n * } else {\n * // Save tokens\n * const authenticatedConfig = withToken(config, result.accessToken!)\n * }\n * ```\n */\nexport async function signIn(config: SylphxConfig, input: LoginRequest): Promise<LoginResponse> {\n\treturn callApi<LoginResponse>(config, '/auth/login', {\n\t\tmethod: 'POST',\n\t\tbody: input,\n\t})\n}\n\n/**\n * Sign up with email and password\n *\n * @example\n * ```typescript\n * const result = await signUp(config, {\n * email: 'user@example.com',\n * password: 'secret',\n * name: 'John Doe',\n * })\n * // User needs to verify email\n * ```\n */\nexport async function signUp(\n\tconfig: SylphxConfig,\n\tinput: RegisterRequest,\n): Promise<RegisterResponse> {\n\treturn callApi<RegisterResponse>(config, '/auth/register', {\n\t\tmethod: 'POST',\n\t\tbody: input,\n\t})\n}\n\n/**\n * Sign out (revoke tokens)\n *\n * @example\n * ```typescript\n * await signOut(config)\n * ```\n */\nexport async function signOut(config: SylphxConfig): Promise<void> {\n\tawait callApi<void>(config, '/auth/logout', { method: 'POST' })\n}\n\n/**\n * Refresh access token\n *\n * @example\n * ```typescript\n * const tokens = await refreshToken(config, refreshTokenString)\n * const newConfig = withToken(config, tokens.accessToken)\n * ```\n */\nexport async function refreshToken(config: SylphxConfig, token: string): Promise<TokenResponse> {\n\treturn callApi<TokenResponse>(config, '/auth/token', {\n\t\tmethod: 'POST',\n\t\tbody: {\n\t\t\tgrant_type: 'refresh_token',\n\t\t\trefresh_token: token,\n\t\t\tclient_secret: config.secretKey,\n\t\t},\n\t})\n}\n\n/**\n * Verify email with token\n *\n * @example\n * ```typescript\n * await verifyEmail(config, token)\n * ```\n */\nexport async function verifyEmail(config: SylphxConfig, token: string): Promise<void> {\n\tawait callApi<void>(config, '/auth/verify-email', {\n\t\tmethod: 'POST',\n\t\tbody: { token },\n\t})\n}\n\n/**\n * Request password reset email\n *\n * @example\n * ```typescript\n * await forgotPassword(config, 'user@example.com')\n * ```\n */\nexport async function forgotPassword(config: SylphxConfig, email: string): Promise<void> {\n\tawait callApi<{ success: boolean }>(config, '/auth/forgot-password', {\n\t\tmethod: 'POST',\n\t\tbody: { email },\n\t})\n}\n\n/**\n * Reset password with token\n *\n * @example\n * ```typescript\n * await resetPassword(config, { token, password: 'newpassword' })\n * ```\n */\nexport async function resetPassword(\n\tconfig: SylphxConfig,\n\tinput: { token: string; password: string },\n): Promise<void> {\n\tawait callApi<{ success: boolean }>(config, '/auth/reset-password', {\n\t\tmethod: 'POST',\n\t\tbody: { token: input.token, newPassword: input.password },\n\t})\n}\n\n/**\n * Get current session (requires authenticated config)\n *\n * @example\n * ```typescript\n * const session = await getSession(authenticatedConfig)\n * if (session.user) {\n * console.log(`Logged in as ${session.user.email}`)\n * }\n * ```\n */\nexport async function getSession(config: SylphxConfig): Promise<SessionResult> {\n\tif (!config.accessToken) {\n\t\treturn { user: null }\n\t}\n\n\ttry {\n\t\tconst user = await callApi<SessionResult['user']>(config, '/auth/me')\n\t\treturn { user }\n\t} catch {\n\t\treturn { user: null }\n\t}\n}\n\n/**\n * Verify 2FA code (when signIn returns requiresTwoFactor: true)\n *\n * @example\n * ```typescript\n * const result = await signIn(config, credentials)\n * if (result.requiresTwoFactor) {\n * const tokens = await verifyTwoFactor(config, result.userId!, code)\n * }\n * ```\n */\nexport async function verifyTwoFactor(\n\tconfig: SylphxConfig,\n\tuserId: string,\n\tcode: string,\n): Promise<TokenResponse> {\n\treturn callApi<TokenResponse>(config, '/auth/verify-2fa', {\n\t\tmethod: 'POST',\n\t\tbody: { userId, code },\n\t})\n}\n\n/**\n * Introspect a token to check its validity (RFC 7662)\n *\n * Use this to verify token status without decoding. Essential for:\n * - Checking if a token has been revoked\n * - Validating tokens at the edge\n * - Security-critical operations\n *\n * @example\n * ```typescript\n * const result = await introspectToken(config, accessToken)\n * if (!result.active) {\n * // Token is invalid, revoked, or expired\n * await refreshTokens()\n * }\n * ```\n */\nexport async function introspectToken(\n\tconfig: SylphxConfig,\n\ttoken: string,\n\ttokenTypeHint?: 'access_token' | 'refresh_token',\n): Promise<TokenIntrospectionResult> {\n\tconst response = await fetch(buildApiUrl(config, '/auth/introspect'), {\n\t\tmethod: 'POST',\n\t\theaders: {\n\t\t\t'Content-Type': 'application/json',\n\t\t\t// RFC 7662 §2: server-to-server call — authenticate with secret key\n\t\t\t'x-app-secret': config.secretKey ?? '',\n\t\t},\n\t\tbody: JSON.stringify({\n\t\t\ttoken,\n\t\t\ttoken_type_hint: tokenTypeHint,\n\t\t}),\n\t})\n\n\tif (!response.ok) {\n\t\t// Per RFC 7662, errors should return inactive\n\t\treturn { active: false }\n\t}\n\n\treturn response.json()\n}\n\n/**\n * Revoke a token (RFC 7009)\n *\n * Use cases:\n * - Sign out user from specific device\n * - Security response to compromised token\n * - User-initiated session termination\n *\n * @example\n * ```typescript\n * // Revoke single refresh token\n * await revokeToken(config, refreshToken)\n *\n * // Revoke all tokens for a user (logout everywhere)\n * await revokeToken(config, '', { revokeAll: true, userId: 'user-123' })\n * ```\n */\nexport async function revokeToken(\n\tconfig: SylphxConfig,\n\ttoken: string,\n\toptions?: RevokeTokenOptions,\n): Promise<void> {\n\tawait fetch(buildApiUrl(config, '/auth/revoke'), {\n\t\tmethod: 'POST',\n\t\theaders: { 'Content-Type': 'application/json' },\n\t\tbody: JSON.stringify({\n\t\t\ttoken: options?.revokeAll ? undefined : token,\n\t\t\tclient_secret: config.secretKey,\n\t\t\tuser_id: options?.userId,\n\t\t\trevoke_all: options?.revokeAll,\n\t\t}),\n\t})\n\t// Per RFC 7009, always succeeds (200 OK)\n}\n\n/**\n * Revoke all tokens for a user (logout from all devices)\n *\n * Convenience wrapper around revokeToken with revokeAll option.\n *\n * @example\n * ```typescript\n * // After password change, revoke all sessions\n * await revokeAllTokens(config, userId)\n * ```\n */\nexport async function revokeAllTokens(config: SylphxConfig, userId: string): Promise<void> {\n\tawait revokeToken(config, '', { revokeAll: true, userId })\n}\n\n/**\n * Sign up with extended input (metadata + invitation token support).\n *\n * Use this instead of signUp() when you need to:\n * - Pass metadata on registration (e.g., org context, role, referral info)\n * - Register with an invitation token\n *\n * @example\n * ```typescript\n * const result = await extendedSignUp(config, {\n * email: 'user@example.com',\n * password: 'secret',\n * name: 'John Doe',\n * metadata: { orgId: 'org-123', role: 'employee' },\n * invitationToken: 'inv_...',\n * })\n * ```\n */\nexport async function extendedSignUp(\n\tconfig: SylphxConfig,\n\tinput: RegisterInput,\n): Promise<RegisterResponse> {\n\treturn callApi<RegisterResponse>(config, '/auth/register', {\n\t\tmethod: 'POST',\n\t\tbody: input,\n\t})\n}\n\n/**\n * Invite a user to sign up for this project.\n * Server-side only (requires secretKey).\n * Sends an email invitation; user signs up via signUp() or extendedSignUp() with the invitation token.\n *\n * @example\n * ```typescript\n * const invite = await inviteUser(config, {\n * email: 'newemployee@company.com',\n * metadata: { role: 'employee', orgId: 'org-123' },\n * redirectUrl: 'https://app.example.com/signup',\n * })\n * console.log(invite.invitationToken, invite.expiresAt)\n * ```\n */\nexport async function inviteUser(\n\tconfig: SylphxConfig,\n\tinput: InviteUserRequest,\n): Promise<InviteUserResponse> {\n\treturn callApi<InviteUserResponse>(config, '/auth/invite', {\n\t\tmethod: 'POST',\n\t\tbody: input,\n\t})\n}\n\n/**\n * Exchange current user token for an org-scoped token.\n * The returned access_token JWT includes org_id, org_slug, org_role claims.\n *\n * @example\n * const tokens = await switchOrg(withToken(config, currentToken), 'org_xxx')\n */\nexport async function switchOrg(config: SylphxConfig, orgId: string): Promise<TokenResponse> {\n\treturn callApi<TokenResponse>(config, '/auth/switch-org', {\n\t\tmethod: 'POST',\n\t\tbody: JSON.stringify({ orgId }),\n\t})\n}\n","/**\n * Admin Functions — Server-side user management\n * Requires secretKey (PLATFORM_TOKEN). Never use on client-side.\n */\nimport { callApi, type SylphxConfig } from './config'\n\nexport interface AdminUser {\n\tid: string\n\temail: string\n\tname: string | null\n\timage: string | null\n\temailVerified: boolean\n\trole: string\n\tstatus: 'active' | 'suspended' | 'deleted'\n\tmetadata: Record<string, unknown> | null\n\tfirstSeenAt: string\n\tlastActiveAt: string\n\tcreatedAt: string\n}\n\nexport interface ListUsersOptions {\n\temail?: string\n\tstatus?: 'active' | 'suspended'\n\tlimit?: number\n\toffset?: number\n}\n\nexport interface ListUsersResult {\n\tusers: AdminUser[]\n\ttotal: number\n\tlimit: number\n\toffset: number\n}\n\n/**\n * List users in this project (paginated).\n * Server-side only (requires secretKey).\n *\n * @example\n * ```typescript\n * const { users, total } = await listUsers(config, { status: 'active', limit: 20 })\n * ```\n */\nexport async function listUsers(\n\tconfig: SylphxConfig,\n\topts?: ListUsersOptions,\n): Promise<ListUsersResult> {\n\tconst params = new URLSearchParams()\n\tif (opts?.email) params.set('email', opts.email)\n\tif (opts?.status) params.set('status', opts.status)\n\tif (opts?.limit) params.set('limit', String(opts.limit))\n\tif (opts?.offset) params.set('offset', String(opts.offset))\n\tconst qs = params.toString()\n\treturn callApi<ListUsersResult>(config, `/admin/users${qs ? `?${qs}` : ''}`)\n}\n\n/**\n * Get a single user by ID.\n * Server-side only (requires secretKey).\n */\nexport async function getUser(config: SylphxConfig, userId: string): Promise<AdminUser> {\n\treturn callApi<AdminUser>(config, `/admin/users/${userId}`)\n}\n\n/**\n * Look up a user by email address. Returns null if not found.\n * Server-side only (requires secretKey).\n *\n * @example\n * ```typescript\n * const user = await getUserByEmail(config, 'user@example.com')\n * if (!user) console.log('User not found')\n * ```\n */\nexport async function getUserByEmail(\n\tconfig: SylphxConfig,\n\temail: string,\n): Promise<AdminUser | null> {\n\tconst result = await listUsers(config, { email, limit: 1 })\n\treturn result.users[0] ?? null\n}\n\n/**\n * Update a user's profile fields.\n * Server-side only (requires secretKey).\n *\n * @example\n * ```typescript\n * const updated = await updateUser(config, userId, { role: 'admin', name: 'Jane' })\n * ```\n */\nexport async function updateUser(\n\tconfig: SylphxConfig,\n\tuserId: string,\n\tinput: { name?: string; metadata?: Record<string, unknown>; role?: string },\n): Promise<AdminUser> {\n\treturn callApi<AdminUser>(config, `/admin/users/${userId}`, {\n\t\tmethod: 'PUT',\n\t\tbody: input,\n\t})\n}\n\n/**\n * Update only the metadata for a user (merge-style update).\n * Server-side only (requires secretKey).\n *\n * @example\n * ```typescript\n * await updateUserMetadata(config, userId, { employeeId: 'EMP-001', department: 'Engineering' })\n * ```\n */\nexport async function updateUserMetadata(\n\tconfig: SylphxConfig,\n\tuserId: string,\n\tmetadata: Record<string, unknown>,\n): Promise<AdminUser> {\n\treturn callApi<AdminUser>(config, `/admin/users/${userId}/metadata`, {\n\t\tmethod: 'PUT',\n\t\tbody: metadata,\n\t})\n}\n\n/**\n * Suspend a user account.\n * Server-side only (requires secretKey).\n *\n * @example\n * ```typescript\n * await suspendUser(config, userId, 'Violation of terms of service')\n * ```\n */\nexport async function suspendUser(\n\tconfig: SylphxConfig,\n\tuserId: string,\n\treason?: string,\n): Promise<void> {\n\tawait callApi<void>(config, `/admin/users/${userId}/suspend`, {\n\t\tmethod: 'POST',\n\t\tbody: { reason },\n\t})\n}\n\n/**\n * Delete a user account.\n * Server-side only (requires secretKey).\n *\n * @example\n * ```typescript\n * await deleteUser(config, userId)\n * ```\n */\nexport async function deleteUser(config: SylphxConfig, userId: string): Promise<void> {\n\tawait callApi<void>(config, `/admin/users/${userId}/delete`, {\n\t\tmethod: 'POST',\n\t})\n}\n","/**\n * Analytics Functions\n *\n * Pure functions for event tracking - no hidden state.\n * Events are sent directly to the platform.\n *\n * Types are derived from the OpenAPI spec (generated/api.d.ts).\n * Run `bun run generate:types:local` to regenerate after API changes.\n */\n\nimport { callApi, type SylphxConfig } from './config'\nimport type { components } from './generated/api'\n\n// ============================================================================\n// Types (re-exported from generated OpenAPI spec)\n// ============================================================================\n\nexport type TrackEventItem = components['schemas']['TrackEvent']\nexport type BatchTrackRequest = components['schemas']['BatchTrackRequest']\nexport type BatchTrackResponse = components['schemas']['BatchTrackResponse']\nexport type ConversionData = components['schemas']['ConversionData']\n\n// SDK-specific types for convenience\nexport interface TrackInput {\n\t/** Event name */\n\tevent: string\n\t/** Event properties */\n\tproperties?: Record<string, unknown>\n\t/** User ID (optional, for server-side tracking) */\n\tuserId?: string\n\t/** Anonymous ID (for tracking before user signs in) */\n\tanonymousId?: string\n\t/** Timestamp (defaults to now) */\n\ttimestamp?: string\n}\n\nexport interface PageInput {\n\t/** Page name or title */\n\tname: string\n\t/** Page properties */\n\tproperties?: Record<string, unknown>\n\t/** User ID (optional) */\n\tuserId?: string\n\t/** Anonymous ID */\n\tanonymousId?: string\n}\n\nexport interface IdentifyInput {\n\t/** User ID */\n\tuserId: string\n\t/** User traits */\n\ttraits?: Record<string, unknown>\n\t/** Anonymous ID to link */\n\tanonymousId?: string\n}\n\nexport interface BatchEvent {\n\ttype: 'track' | 'page' | 'identify'\n\tevent?: string\n\tname?: string\n\tuserId?: string\n\tanonymousId?: string\n\tproperties?: Record<string, unknown>\n\ttraits?: Record<string, unknown>\n\ttimestamp?: string\n}\n\n// ============================================================================\n// Functions\n// ============================================================================\n\n/**\n * Track a custom event\n *\n * @example\n * ```typescript\n * await track(config, {\n * event: 'purchase_completed',\n * properties: { amount: 99.99, currency: 'USD' },\n * userId: 'user-123',\n * })\n * ```\n */\nexport async function track(config: SylphxConfig, input: TrackInput): Promise<void> {\n\tawait callApi(config, '/analytics/track', {\n\t\tmethod: 'POST',\n\t\tbody: {\n\t\t\tevent: input.event,\n\t\t\tproperties: input.properties ?? {},\n\t\t\tuserId: input.userId,\n\t\t\tanonymousId: input.anonymousId,\n\t\t\ttimestamp: input.timestamp ?? new Date().toISOString(),\n\t\t},\n\t})\n}\n\n/**\n * Track a page view\n *\n * @example\n * ```typescript\n * await page(config, {\n * name: 'Home',\n * properties: { path: '/', referrer: document.referrer },\n * })\n * ```\n */\nexport async function page(config: SylphxConfig, input: PageInput): Promise<void> {\n\tawait callApi(config, '/analytics/page', {\n\t\tmethod: 'POST',\n\t\tbody: {\n\t\t\tname: input.name,\n\t\t\tproperties: input.properties ?? {},\n\t\t\tuserId: input.userId,\n\t\t\tanonymousId: input.anonymousId,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t},\n\t})\n}\n\n/**\n * Identify a user with traits\n *\n * @example\n * ```typescript\n * await identify(config, {\n * userId: 'user-123',\n * traits: { email: 'user@example.com', plan: 'pro' },\n * anonymousId: 'anon-456', // Links anonymous activity to user\n * })\n * ```\n */\nexport async function identify(config: SylphxConfig, input: IdentifyInput): Promise<void> {\n\tawait callApi(config, '/analytics/identify', {\n\t\tmethod: 'POST',\n\t\tbody: {\n\t\t\tuserId: input.userId,\n\t\t\ttraits: input.traits ?? {},\n\t\t\tanonymousId: input.anonymousId,\n\t\t},\n\t})\n}\n\n/**\n * Send multiple events in a single request (batch)\n *\n * @example\n * ```typescript\n * await trackBatch(config, [\n * { type: 'track', event: 'item_viewed', properties: { id: '1' } },\n * { type: 'track', event: 'item_added', properties: { id: '1' } },\n * { type: 'track', event: 'checkout_started' },\n * ])\n * ```\n */\nexport async function trackBatch(config: SylphxConfig, events: BatchEvent[]): Promise<void> {\n\tawait callApi(config, '/analytics/batch', {\n\t\tmethod: 'POST',\n\t\tbody: {\n\t\t\tevents: events.map((e) => ({\n\t\t\t\tevent: e.type === 'track' ? e.event : e.type === 'page' ? `$pageview` : '$identify',\n\t\t\t\tproperties: {\n\t\t\t\t\t...e.properties,\n\t\t\t\t\t...(e.type === 'page' && e.name ? { name: e.name } : {}),\n\t\t\t\t\t...(e.type === 'identify' && e.traits ? { traits: e.traits } : {}),\n\t\t\t\t},\n\t\t\t\tuserId: e.userId,\n\t\t\t\tanonymousId: e.anonymousId,\n\t\t\t\ttimestamp: e.timestamp ?? new Date().toISOString(),\n\t\t\t})),\n\t\t},\n\t})\n}\n\n// ============================================================================\n// Convenience Functions\n// ============================================================================\n\n/**\n * Generate a random anonymous ID (Segment pattern: pure UUID)\n *\n * Uses UUID v4 format without timestamp component to prevent collision risk\n * in high-traffic applications where multiple users might generate IDs at\n * the same millisecond.\n *\n * @example\n * ```typescript\n * const anonId = generateAnonymousId()\n * await track(config, { event: 'page_view', anonymousId: anonId })\n * ```\n */\nexport function generateAnonymousId(): string {\n\t// Use crypto.randomUUID if available (standard UUID v4)\n\tif (typeof crypto !== 'undefined' && crypto.randomUUID) {\n\t\treturn crypto.randomUUID()\n\t}\n\t// Fallback for older browsers: generate UUID v4 manually\n\treturn 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {\n\t\tconst r = (Math.random() * 16) | 0\n\t\tconst v = c === 'x' ? r : (r & 0x3) | 0x8\n\t\treturn v.toString(16)\n\t})\n}\n\n/**\n * Create a tracker bound to a specific config\n *\n * For convenience when making many calls with the same config.\n * This is optional - you can always use the individual functions.\n *\n * @example\n * ```typescript\n * const analytics = createTracker(config)\n *\n * // No need to pass config each time\n * analytics.track('event', { prop: 'value' })\n * analytics.page('Home')\n * analytics.identify('user-123', { email: 'user@example.com' })\n * ```\n */\nexport function createTracker(config: SylphxConfig, defaultAnonymousId?: string) {\n\tconst anonymousId = defaultAnonymousId ?? generateAnonymousId()\n\n\treturn {\n\t\ttrack: (event: string, properties?: Record<string, unknown>, userId?: string) =>\n\t\t\ttrack(config, { event, properties, userId, anonymousId }),\n\n\t\tpage: (name: string, properties?: Record<string, unknown>, userId?: string) =>\n\t\t\tpage(config, { name, properties, userId, anonymousId }),\n\n\t\tidentify: (userId: string, traits?: Record<string, unknown>) =>\n\t\t\tidentify(config, { userId, traits, anonymousId }),\n\n\t\tbatch: (events: BatchEvent[]) =>\n\t\t\ttrackBatch(\n\t\t\t\tconfig,\n\t\t\t\tevents.map((e) => ({\n\t\t\t\t\t...e,\n\t\t\t\t\tanonymousId: e.anonymousId ?? anonymousId,\n\t\t\t\t})),\n\t\t\t),\n\n\t\t/** Get the anonymous ID for this tracker */\n\t\tgetAnonymousId: () => anonymousId,\n\t}\n}\n","/**\n * AI Functions\n *\n * Pure functions for AI completions - Vercel AI SDK style.\n * Direct API calls with natural tree-shaking.\n *\n * Types are derived from the OpenAPI spec (generated/api.d.ts).\n * Run `bun run generate:types:local` to regenerate after API changes.\n */\n\nimport { buildApiUrl, buildHeaders, type SylphxConfig } from './config'\nimport { SylphxError } from './errors'\nimport type { components } from './generated/api'\n\n// ============================================================================\n// Types (re-exported from generated OpenAPI spec)\n// ============================================================================\n\nexport type AIUsageResponse = components['schemas']['GetUsageResponse']\nexport type AIRateLimitResponse = components['schemas']['GetRateLimitResponse']\nexport type AIModelsResponse = components['schemas']['GetModelsResponse']\nexport type AIModel = components['schemas']['AIModel']\n\n// ============================================================================\n// SDK-specific Types (OpenAI-compatible chat format)\n// ============================================================================\n\nexport interface ChatMessage {\n\trole: 'system' | 'user' | 'assistant' | 'tool'\n\tcontent: string | ContentPart[]\n\tname?: string\n\ttool_call_id?: string\n\ttool_calls?: ToolCall[]\n\t/** Timestamp for UI display */\n\ttimestamp?: Date\n}\n\nexport interface ContentPart {\n\ttype: 'text' | 'image_url'\n\ttext?: string\n\timage_url?: { url: string; detail?: 'auto' | 'low' | 'high' }\n}\n\nexport interface ToolCall {\n\tid: string\n\ttype: 'function'\n\tfunction: { name: string; arguments: string }\n}\n\nexport interface Tool {\n\ttype: 'function'\n\tfunction: {\n\t\tname: string\n\t\tdescription?: string\n\t\tparameters?: Record<string, unknown>\n\t}\n}\n\nexport interface ChatInput {\n\t/** Model ID (e.g., 'gpt-4o', 'claude-sonnet-4-20250514') */\n\tmodel: string\n\t/** Messages */\n\tmessages: ChatMessage[]\n\t/** Temperature (0-2) */\n\ttemperature?: number\n\t/** Max tokens to generate */\n\tmaxTokens?: number\n\t/** Top P sampling */\n\ttopP?: number\n\t/** Frequency penalty */\n\tfrequencyPenalty?: number\n\t/** Presence penalty */\n\tpresencePenalty?: number\n\t/** Stop sequences */\n\tstop?: string[]\n\t/** Tools for function calling */\n\ttools?: Tool[]\n\t/** Tool choice */\n\ttoolChoice?: 'auto' | 'none' | { type: 'function'; function: { name: string } }\n}\n\nexport interface ChatResult {\n\tid: string\n\tmodel: string\n\tchoices: Array<{\n\t\tindex: number\n\t\tmessage: {\n\t\t\trole: 'assistant'\n\t\t\tcontent: string | null\n\t\t\ttool_calls?: ToolCall[]\n\t\t}\n\t\tfinishReason: 'stop' | 'length' | 'tool_calls' | 'content_filter' | null\n\t}>\n\tusage: {\n\t\tpromptTokens: number\n\t\tcompletionTokens: number\n\t\ttotalTokens: number\n\t}\n}\n\nexport interface ChatStreamChunk {\n\tid: string\n\tmodel: string\n\tchoices: Array<{\n\t\tindex: number\n\t\tdelta: {\n\t\t\trole?: 'assistant'\n\t\t\tcontent?: string\n\t\t\ttool_calls?: ToolCall[]\n\t\t}\n\t\tfinishReason: 'stop' | 'length' | 'tool_calls' | 'content_filter' | null\n\t}>\n}\n\nexport interface EmbedInput {\n\t/** Model ID (e.g., 'text-embedding-3-small') */\n\tmodel: string\n\t/** Text(s) to embed */\n\tinput: string | string[]\n\t/** Dimensions (for models that support it) */\n\tdimensions?: number\n}\n\nexport interface EmbedResult {\n\tmodel: string\n\tdata: Array<{\n\t\tindex: number\n\t\tembedding: number[]\n\t}>\n\tusage: {\n\t\tpromptTokens: number\n\t\ttotalTokens: number\n\t}\n}\n\n// ============================================================================\n// Functions\n// ============================================================================\n\n/**\n * Create a chat completion\n *\n * @example\n * ```typescript\n * const response = await chat(config, {\n * model: 'gpt-4o',\n * messages: [\n * { role: 'system', content: 'You are a helpful assistant.' },\n * { role: 'user', content: 'Hello!' },\n * ],\n * })\n *\n * console.log(response.choices[0].message.content)\n * ```\n */\nexport async function chat(config: SylphxConfig, input: ChatInput): Promise<ChatResult> {\n\tconst response = await fetch(buildApiUrl(config, '/chat/completions'), {\n\t\tmethod: 'POST',\n\t\theaders: {\n\t\t\t...buildHeaders(config),\n\t\t\tAuthorization: `Bearer ${config.secretKey}`,\n\t\t},\n\t\tbody: JSON.stringify({\n\t\t\tmodel: input.model,\n\t\t\tmessages: input.messages,\n\t\t\ttemperature: input.temperature,\n\t\t\tmax_tokens: input.maxTokens,\n\t\t\ttop_p: input.topP,\n\t\t\tfrequency_penalty: input.frequencyPenalty,\n\t\t\tpresence_penalty: input.presencePenalty,\n\t\t\tstop: input.stop,\n\t\t\ttools: input.tools,\n\t\t\ttool_choice: input.toolChoice,\n\t\t}),\n\t})\n\n\tif (!response.ok) {\n\t\tconst error = await response.json().catch(() => ({ error: { message: 'Chat request failed' } }))\n\t\tthrow new SylphxError(error?.error?.message ?? 'Chat request failed', {\n\t\t\tcode: 'BAD_REQUEST',\n\t\t})\n\t}\n\n\tconst data = await response.json()\n\n\treturn {\n\t\tid: data.id,\n\t\tmodel: data.model,\n\t\tchoices: data.choices.map((c: Record<string, unknown>) => ({\n\t\t\tindex: c.index as number,\n\t\t\tmessage: {\n\t\t\t\trole: 'assistant' as const,\n\t\t\t\tcontent: (c.message as Record<string, unknown>)?.content as string | null,\n\t\t\t\ttool_calls: (c.message as Record<string, unknown>)?.tool_calls as ToolCall[] | undefined,\n\t\t\t},\n\t\t\tfinishReason: c.finish_reason as ChatResult['choices'][0]['finishReason'],\n\t\t})),\n\t\tusage: {\n\t\t\tpromptTokens: data.usage.prompt_tokens,\n\t\t\tcompletionTokens: data.usage.completion_tokens,\n\t\t\ttotalTokens: data.usage.total_tokens,\n\t\t},\n\t}\n}\n\n/**\n * Create a streaming chat completion\n *\n * @example\n * ```typescript\n * const stream = chatStream(config, {\n * model: 'gpt-4o',\n * messages: [{ role: 'user', content: 'Write a poem' }],\n * })\n *\n * for await (const chunk of stream) {\n * process.stdout.write(chunk.choices[0].delta.content ?? '')\n * }\n * ```\n */\nexport function chatStream(config: SylphxConfig, input: ChatInput): AsyncIterable<ChatStreamChunk> {\n\treturn {\n\t\t[Symbol.asyncIterator]: async function* () {\n\t\t\tconst response = await fetch(buildApiUrl(config, '/chat/completions'), {\n\t\t\t\tmethod: 'POST',\n\t\t\t\theaders: {\n\t\t\t\t\t...buildHeaders(config),\n\t\t\t\t\tAuthorization: `Bearer ${config.secretKey}`,\n\t\t\t\t},\n\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\tmodel: input.model,\n\t\t\t\t\tmessages: input.messages,\n\t\t\t\t\ttemperature: input.temperature,\n\t\t\t\t\tmax_tokens: input.maxTokens,\n\t\t\t\t\ttop_p: input.topP,\n\t\t\t\t\tfrequency_penalty: input.frequencyPenalty,\n\t\t\t\t\tpresence_penalty: input.presencePenalty,\n\t\t\t\t\tstop: input.stop,\n\t\t\t\t\ttools: input.tools,\n\t\t\t\t\ttool_choice: input.toolChoice,\n\t\t\t\t\tstream: true,\n\t\t\t\t}),\n\t\t\t})\n\n\t\t\tif (!response.ok) {\n\t\t\t\tconst error = await response\n\t\t\t\t\t.json()\n\t\t\t\t\t.catch(() => ({ error: { message: 'Stream request failed' } }))\n\t\t\t\tthrow new SylphxError(error?.error?.message ?? 'Stream request failed', {\n\t\t\t\t\tcode: 'BAD_REQUEST',\n\t\t\t\t})\n\t\t\t}\n\n\t\t\tconst reader = response.body?.getReader()\n\t\t\tif (!reader) {\n\t\t\t\tthrow new SylphxError('No response body', {\n\t\t\t\t\tcode: 'INTERNAL_SERVER_ERROR',\n\t\t\t\t})\n\t\t\t}\n\n\t\t\tconst decoder = new TextDecoder()\n\t\t\tlet buffer = ''\n\n\t\t\ttry {\n\t\t\t\twhile (true) {\n\t\t\t\t\tconst { done, value } = await reader.read()\n\t\t\t\t\tif (done) break\n\n\t\t\t\t\tbuffer += decoder.decode(value, { stream: true })\n\t\t\t\t\tconst lines = buffer.split('\\n')\n\t\t\t\t\tbuffer = lines.pop() ?? ''\n\n\t\t\t\t\tfor (const line of lines) {\n\t\t\t\t\t\tif (line.startsWith('data: ')) {\n\t\t\t\t\t\t\tconst data = line.slice(6).trim()\n\t\t\t\t\t\t\tif (data === '[DONE]') return\n\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tconst chunk = JSON.parse(data)\n\t\t\t\t\t\t\t\tyield {\n\t\t\t\t\t\t\t\t\tid: chunk.id ?? '',\n\t\t\t\t\t\t\t\t\tmodel: chunk.model ?? input.model,\n\t\t\t\t\t\t\t\t\tchoices: (chunk.choices ?? []).map((c: Record<string, unknown>) => ({\n\t\t\t\t\t\t\t\t\t\tindex: typeof c.index === 'number' ? c.index : 0,\n\t\t\t\t\t\t\t\t\t\tdelta: {\n\t\t\t\t\t\t\t\t\t\t\trole: (c.delta as Record<string, unknown>)?.role as 'assistant' | undefined,\n\t\t\t\t\t\t\t\t\t\t\tcontent: (c.delta as Record<string, unknown>)?.content as string | undefined,\n\t\t\t\t\t\t\t\t\t\t\ttool_calls: (c.delta as Record<string, unknown>)?.tool_calls as\n\t\t\t\t\t\t\t\t\t\t\t\t| ToolCall[]\n\t\t\t\t\t\t\t\t\t\t\t\t| undefined,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\tfinishReason:\n\t\t\t\t\t\t\t\t\t\t\t(c.finish_reason as ChatStreamChunk['choices'][0]['finishReason']) ?? null,\n\t\t\t\t\t\t\t\t\t})),\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\t// Skip malformed JSON\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} finally {\n\t\t\t\treader.releaseLock()\n\t\t\t}\n\t\t},\n\t}\n}\n\n/**\n * Create embeddings\n *\n * @example\n * ```typescript\n * const result = await embed(config, {\n * model: 'text-embedding-3-small',\n * input: ['Hello world', 'Goodbye world'],\n * })\n *\n * console.log(result.data[0].embedding) // [0.123, -0.456, ...]\n * ```\n */\nexport async function embed(config: SylphxConfig, input: EmbedInput): Promise<EmbedResult> {\n\tconst response = await fetch(buildApiUrl(config, '/embeddings'), {\n\t\tmethod: 'POST',\n\t\theaders: {\n\t\t\t...buildHeaders(config),\n\t\t\tAuthorization: `Bearer ${config.secretKey}`,\n\t\t},\n\t\tbody: JSON.stringify({\n\t\t\tmodel: input.model,\n\t\t\tinput: input.input,\n\t\t\tdimensions: input.dimensions,\n\t\t}),\n\t})\n\n\tif (!response.ok) {\n\t\tconst error = await response\n\t\t\t.json()\n\t\t\t.catch(() => ({ error: { message: 'Embedding request failed' } }))\n\t\tthrow new SylphxError(error?.error?.message ?? 'Embedding request failed', {\n\t\t\tcode: 'BAD_REQUEST',\n\t\t})\n\t}\n\n\tconst data = await response.json()\n\n\treturn {\n\t\tmodel: data.model,\n\t\tdata: data.data,\n\t\tusage: {\n\t\t\tpromptTokens: data.usage.prompt_tokens,\n\t\t\ttotalTokens: data.usage.total_tokens,\n\t\t},\n\t}\n}\n\n// ============================================================================\n// Convenience Functions\n// ============================================================================\n\n/**\n * Simple text completion (convenience wrapper)\n *\n * @example\n * ```typescript\n * const text = await complete(config, 'gpt-4o', 'Explain quantum computing in one sentence.')\n * ```\n */\nexport async function complete(\n\tconfig: SylphxConfig,\n\tmodel: string,\n\tprompt: string,\n\toptions?: Omit<ChatInput, 'model' | 'messages'>,\n): Promise<string> {\n\tconst response = await chat(config, {\n\t\tmodel,\n\t\tmessages: [{ role: 'user', content: prompt }],\n\t\t...options,\n\t})\n\treturn response.choices[0]?.message.content ?? ''\n}\n\n/**\n * Stream text to string (collects all chunks)\n *\n * @example\n * ```typescript\n * const text = await streamToString(config, {\n * model: 'gpt-4o',\n * messages: [{ role: 'user', content: 'Write a haiku' }],\n * })\n * ```\n */\nexport async function streamToString(config: SylphxConfig, input: ChatInput): Promise<string> {\n\tlet result = ''\n\tfor await (const chunk of chatStream(config, input)) {\n\t\tresult += chunk.choices[0]?.delta.content ?? ''\n\t}\n\treturn result\n}\n","/**\n * Billing Functions\n *\n * Pure functions for billing and subscriptions.\n * Uses REST API at /api/sdk/billing/* for all operations.\n *\n * Types are derived from the OpenAPI spec (generated/api.d.ts).\n * Run `bun run generate:types:local` to regenerate after API changes.\n */\n\nimport { callApi, type SylphxConfig } from './config'\nimport type { components } from './generated/api'\n\n// ============================================================================\n// Types (re-exported from generated OpenAPI spec)\n// ============================================================================\n\nexport type Plan = components['schemas']['BillingPlan']\nexport type Subscription = components['schemas']['BillingSubscriptionResponse']\nexport type CheckoutRequest = components['schemas']['BillingCheckoutRequest']\nexport type CheckoutResponse = components['schemas']['BillingCheckoutResponse']\nexport type PortalRequest = components['schemas']['BillingPortalRequest']\nexport type PortalResponse = components['schemas']['BillingPortalResponse']\nexport type BalanceResponse = components['schemas']['BillingBalanceResponse']\nexport type UsageResponse = components['schemas']['BillingUsageResponse']\n\n// ============================================================================\n// Functions\n// ============================================================================\n\n/**\n * Get available plans\n *\n * @example\n * ```typescript\n * const plans = await getPlans(config)\n * plans.forEach(plan => console.log(plan.name, plan.priceMonthly))\n * ```\n */\nexport async function getPlans(config: SylphxConfig): Promise<Plan[]> {\n\treturn callApi<Plan[]>(config, '/billing/plans')\n}\n\n/**\n * Get user's subscription\n *\n * @example\n * ```typescript\n * const sub = await getSubscription(config, 'user-123')\n * if (sub?.status === 'active') {\n * console.log(`Active plan: ${sub.planSlug}`)\n * }\n * ```\n */\nexport async function getSubscription(\n\tconfig: SylphxConfig,\n\tuserId: string,\n): Promise<Subscription | null> {\n\treturn callApi<Subscription | null>(config, '/billing/subscription', {\n\t\tquery: { userId },\n\t})\n}\n\n/**\n * Create a checkout session\n *\n * @example\n * ```typescript\n * const { checkoutUrl } = await createCheckout(config, {\n * userId: 'user-123',\n * planSlug: 'pro',\n * interval: 'monthly',\n * successUrl: 'https://myapp.com/success',\n * cancelUrl: 'https://myapp.com/pricing',\n * })\n *\n * window.location.href = checkoutUrl\n * ```\n */\nexport async function createCheckout(\n\tconfig: SylphxConfig,\n\tinput: CheckoutRequest,\n): Promise<CheckoutResponse> {\n\treturn callApi<CheckoutResponse>(config, '/billing/checkout', {\n\t\tmethod: 'POST',\n\t\tbody: input,\n\t})\n}\n\n/**\n * Create a billing portal session\n *\n * @example\n * ```typescript\n * const { portalUrl } = await createPortalSession(config, {\n * userId: 'user-123',\n * returnUrl: window.location.href,\n * })\n *\n * window.location.href = portalUrl\n * ```\n */\nexport async function createPortalSession(\n\tconfig: SylphxConfig,\n\tinput: PortalRequest,\n): Promise<PortalResponse> {\n\treturn callApi<PortalResponse>(config, '/billing/portal', {\n\t\tmethod: 'POST',\n\t\tbody: input,\n\t})\n}\n\n/**\n * Get billing balance (credits, etc.)\n *\n * @example\n * ```typescript\n * const balance = await getBillingBalance(config)\n * console.log(`Balance: ${balance.balance.currentFormatted}`)\n * ```\n */\nexport async function getBillingBalance(config: SylphxConfig): Promise<BalanceResponse> {\n\treturn callApi<BalanceResponse>(config, '/billing/balance')\n}\n\n/**\n * Get billing usage\n *\n * @example\n * ```typescript\n * const usage = await getBillingUsage(config, { month: '2024-01' })\n * ```\n */\nexport async function getBillingUsage(\n\tconfig: SylphxConfig,\n\toptions?: { month?: string },\n): Promise<UsageResponse> {\n\treturn callApi<UsageResponse>(config, '/billing/usage', {\n\t\tquery: options?.month ? { month: options.month } : undefined,\n\t})\n}\n","/**\n * Storage Functions\n *\n * Pure functions for file storage operations.\n *\n * ## Industry Patterns Implemented\n * - AbortController cancellation (Vercel Blob pattern)\n * - Exponential backoff with jitter (AWS S3 pattern: 5 retries, 1s base)\n * - Concurrent chunk uploads (Vercel pattern: 3 concurrent)\n *\n * Types are derived from the OpenAPI spec (generated/api.d.ts).\n * Run `bun run generate:types:local` to regenerate after API changes.\n */\n\nimport { buildApiUrl, buildHeaders, callApi, type SylphxConfig } from './config'\nimport { BASE_RETRY_DELAY_MS, MAX_RETRY_DELAY_MS } from './constants'\nimport { SylphxError } from './errors'\nimport type { components } from './generated/api'\n\n// Re-export types from SSOT\nexport type {\n\tUploadOptions,\n\tUploadProgressEvent,\n\tUploadResult,\n} from './lib/storage/types'\n\nimport type { UploadProgressEvent, UploadResult } from './lib/storage/types'\n\n// ============================================================================\n// Types (re-exported from generated OpenAPI spec)\n// ============================================================================\n\nexport type StorageFile = components['schemas']['FileInfo']\nexport type UploadUrlRequest = components['schemas']['UploadUrlRequest']\nexport type UploadUrlResponse = components['schemas']['UploadUrlResponse']\n\n// ============================================================================\n// Upload Retry Configuration (AWS S3 Pattern)\n// ============================================================================\n\nconst UPLOAD_RETRY_CONFIG = {\n\t/** Maximum number of retry attempts (AWS S3 pattern) */\n\tmaxRetries: 5,\n\t/** Base delay in milliseconds */\n\tbaseDelayMs: BASE_RETRY_DELAY_MS,\n\t/** Maximum delay cap in milliseconds */\n\tmaxDelayMs: MAX_RETRY_DELAY_MS,\n\t/** Jitter type: 'full' for full jitter (AWS recommended) */\n\tjitter: 'full' as const,\n}\n\n/**\n * Calculate exponential backoff delay with full jitter (AWS pattern)\n * Formula: random(0, min(cap, base * 2 ^ attempt))\n */\nfunction calculateBackoffDelay(attempt: number): number {\n\tconst { baseDelayMs, maxDelayMs } = UPLOAD_RETRY_CONFIG\n\tconst exponentialDelay = baseDelayMs * 2 ** attempt\n\tconst cappedDelay = Math.min(exponentialDelay, maxDelayMs)\n\t// Full jitter: random value between 0 and cappedDelay\n\treturn Math.random() * cappedDelay\n}\n\n/**\n * Sleep for a specified duration, respecting AbortSignal\n */\nasync function sleep(ms: number, signal?: AbortSignal): Promise<void> {\n\treturn new Promise((resolve, reject) => {\n\t\tif (signal?.aborted) {\n\t\t\treject(new DOMException('Upload aborted', 'AbortError'))\n\t\t\treturn\n\t\t}\n\n\t\tconst timeoutId = setTimeout(resolve, ms)\n\n\t\tsignal?.addEventListener(\n\t\t\t'abort',\n\t\t\t() => {\n\t\t\t\tclearTimeout(timeoutId)\n\t\t\t\treject(new DOMException('Upload aborted', 'AbortError'))\n\t\t\t},\n\t\t\t{ once: true },\n\t\t)\n\t})\n}\n\n/**\n * Check if an error is retryable (network errors, 5xx, 429)\n */\nfunction isRetryableError(error: unknown): boolean {\n\tif (error instanceof DOMException && error.name === 'AbortError') {\n\t\treturn false // Never retry aborted requests\n\t}\n\tif (error instanceof TypeError) {\n\t\treturn true // Network errors\n\t}\n\tif (error instanceof Error && 'status' in error) {\n\t\tconst status = (error as { status: number }).status\n\t\treturn status >= 500 || status === 429 // Server errors or rate limiting\n\t}\n\treturn false\n}\n\n// ============================================================================\n// Types (SDK-specific)\n// ============================================================================\n\nexport interface FileUploadOptions {\n\t/** Folder path */\n\tpath?: string\n\t/** File type (file, avatar, etc.) */\n\ttype?: 'file' | 'avatar'\n\t/** User ID (for avatar uploads) */\n\tuserId?: string\n\t/** Progress callback */\n\tonProgress?: (event: UploadProgressEvent) => void\n\t/**\n\t * Enable multipart upload for large files.\n\t * - `true`: Always use multipart upload\n\t * - `false`: Never use multipart upload\n\t * - `'auto'` (default): Auto-enable for files > 5MB\n\t *\n\t * Multipart uploads support files up to 5TB with better\n\t * reliability for large files.\n\t */\n\tmultipart?: boolean | 'auto'\n\t/**\n\t * AbortSignal to cancel the upload.\n\t * Vercel Blob pattern - enables cancellation of in-progress uploads.\n\t *\n\t * @example\n\t * ```typescript\n\t * const controller = new AbortController()\n\t * // Cancel after 30 seconds\n\t * setTimeout(() => controller.abort(), 30000)\n\t * await uploadFile(config, file, { signal: controller.signal })\n\t * ```\n\t */\n\tsignal?: AbortSignal\n\t/**\n\t * Idempotency key for safe retries (Stripe pattern)\n\t *\n\t * Prevents duplicate uploads if the same request is retried.\n\t * Use a unique key per logical upload operation.\n\t *\n\t * @example `upload-${userId}-${fileName}-${fileHash}`\n\t */\n\tidempotencyKey?: string\n}\n\nexport interface FileInfo {\n\tid: string\n\turl: string\n\tname: string\n\tsize: number\n\tcontentType: string\n\tisPrivate: boolean\n\tcreatedAt: string\n}\n\nexport interface SignedUrlOptions {\n\t/** Expiration in seconds (default: 3600, max: 604800 = 7 days) */\n\texpiresIn?: number\n\t/** Force download (attachment) vs inline display (default: attachment) */\n\tdisposition?: 'attachment' | 'inline'\n\t/** Restrict access to specific user */\n\tuserId?: string\n}\n\nexport interface SignedUrlResult {\n\t/** The signed download URL */\n\turl: string\n\t/** When the URL expires (ISO string) */\n\texpiresAt: string\n\t/** File metadata */\n\tfile: {\n\t\tid: string\n\t\tfilename: string\n\t\tmimeType: string\n\t\tsizeBytes: number\n\t\tisPrivate: boolean\n\t}\n}\n\n// ============================================================================\n// Functions\n// ============================================================================\n\n/**\n * Upload a file to storage\n *\n * Uses client-side upload for optimal performance (direct to CDN).\n *\n * ## Industry-Standard Features\n * - **Cancellation**: AbortController support (Vercel Blob pattern)\n * - **Retry**: Exponential backoff with jitter (AWS S3 pattern: 5 retries)\n * - **Progress**: Real-time upload progress tracking\n *\n * ## File Size Limits\n * - Standard uploads: up to 500MB\n * - For files > 500MB: use React hooks with `multipart: true` (supports up to 5TB)\n *\n * ## Multipart Uploads\n * For large files (> 5MB), multipart uploads provide:\n * - Better reliability with chunked uploads\n * - Resumable upload capability\n * - Progress tracking per chunk\n *\n * Use the `multipart` option or React hooks for large files:\n * ```typescript\n * // React hooks (recommended for large files)\n * const { upload } = useStorage()\n * await upload(file, { multipart: true })\n * ```\n *\n * @example\n * ```typescript\n * const file = new File(['Hello'], 'hello.txt', { type: 'text/plain' })\n * const result = await uploadFile(config, file, {\n * path: 'documents',\n * onProgress: (e) => console.log(`${e.progress}%`),\n * })\n *\n * console.log(result.url)\n * ```\n *\n * @example Cancellation\n * ```typescript\n * const controller = new AbortController()\n * setTimeout(() => controller.abort(), 30000) // Cancel after 30s\n *\n * try {\n * await uploadFile(config, file, { signal: controller.signal })\n * } catch (e) {\n * if (e.name === 'AbortError') {\n * console.log('Upload cancelled')\n * }\n * }\n * ```\n */\nexport async function uploadFile(\n\tconfig: SylphxConfig,\n\tfile: File,\n\toptions?: FileUploadOptions,\n): Promise<UploadResult> {\n\tconst { signal } = options ?? {}\n\n\t// Check if already aborted\n\tif (signal?.aborted) {\n\t\tthrow new DOMException('Upload aborted', 'AbortError')\n\t}\n\n\t// Get upload token from platform (with retry)\n\tlet tokenResponse: Response | null = null\n\tlet lastError: Error | null = null\n\n\tfor (let attempt = 0; attempt <= UPLOAD_RETRY_CONFIG.maxRetries; attempt++) {\n\t\ttry {\n\t\t\ttokenResponse = await fetch(buildApiUrl(config, '/storage/upload'), {\n\t\t\t\tmethod: 'POST',\n\t\t\t\theaders: buildHeaders(config),\n\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\tfilename: file.name,\n\t\t\t\t\tcontentType: file.type,\n\t\t\t\t\tsize: file.size,\n\t\t\t\t\tpath: options?.path,\n\t\t\t\t\ttype: options?.type ?? 'file',\n\t\t\t\t\tuserId: options?.userId,\n\t\t\t\t}),\n\t\t\t\tsignal,\n\t\t\t})\n\n\t\t\tif (tokenResponse.ok) {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\t// Check if error is retryable\n\t\t\tif (tokenResponse.status >= 500 || tokenResponse.status === 429) {\n\t\t\t\tif (attempt < UPLOAD_RETRY_CONFIG.maxRetries) {\n\t\t\t\t\tconst delay = calculateBackoffDelay(attempt)\n\t\t\t\t\tawait sleep(delay, signal)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Non-retryable error\n\t\t\tconst error = await tokenResponse\n\t\t\t\t.json()\n\t\t\t\t.catch(() => ({ message: 'Failed to get upload token' }))\n\t\t\tthrow new SylphxError(error.message ?? 'Failed to get upload token', {\n\t\t\t\tcode: 'BAD_REQUEST',\n\t\t\t})\n\t\t} catch (error) {\n\t\t\tif (error instanceof DOMException && error.name === 'AbortError') {\n\t\t\t\tthrow error // Don't retry aborted requests\n\t\t\t}\n\n\t\t\tlastError = error instanceof Error ? error : new Error(String(error))\n\n\t\t\tif (isRetryableError(error) && attempt < UPLOAD_RETRY_CONFIG.maxRetries) {\n\t\t\t\tconst delay = calculateBackoffDelay(attempt)\n\t\t\t\tawait sleep(delay, signal)\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tthrow lastError\n\t\t}\n\t}\n\n\tif (!tokenResponse?.ok) {\n\t\tthrow (\n\t\t\tlastError ??\n\t\t\tnew SylphxError('Failed to get upload token after retries', {\n\t\t\t\tcode: 'BAD_REQUEST',\n\t\t\t})\n\t\t)\n\t}\n\n\tconst { uploadUrl, publicUrl } = await tokenResponse.json()\n\n\t// Upload directly to storage with retry\n\treturn executeUploadWithRetry(file, uploadUrl, publicUrl, options)\n}\n\n/**\n * Execute the actual upload with retry logic\n */\nasync function executeUploadWithRetry(\n\tfile: File,\n\tuploadUrl: string,\n\tpublicUrl: string,\n\toptions?: FileUploadOptions,\n): Promise<UploadResult> {\n\tconst { signal } = options ?? {}\n\tlet lastError: Error | null = null\n\n\tfor (let attempt = 0; attempt <= UPLOAD_RETRY_CONFIG.maxRetries; attempt++) {\n\t\ttry {\n\t\t\treturn await executeUpload(file, uploadUrl, publicUrl, options)\n\t\t} catch (error) {\n\t\t\tif (error instanceof DOMException && error.name === 'AbortError') {\n\t\t\t\tthrow error // Don't retry aborted requests\n\t\t\t}\n\n\t\t\tlastError = error instanceof Error ? error : new Error(String(error))\n\n\t\t\tif (isRetryableError(error) && attempt < UPLOAD_RETRY_CONFIG.maxRetries) {\n\t\t\t\tconst delay = calculateBackoffDelay(attempt)\n\t\t\t\tawait sleep(delay, signal)\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tthrow lastError\n\t\t}\n\t}\n\n\tthrow lastError ?? new Error('Upload failed after retries')\n}\n\n/**\n * Execute a single upload attempt with XHR (for progress tracking)\n */\nfunction executeUpload(\n\tfile: File,\n\tuploadUrl: string,\n\tpublicUrl: string,\n\toptions?: FileUploadOptions,\n): Promise<UploadResult> {\n\tconst { signal, onProgress } = options ?? {}\n\n\treturn new Promise<UploadResult>((resolve, reject) => {\n\t\tconst xhr = new XMLHttpRequest()\n\n\t\t// Handle abort signal\n\t\tconst handleAbort = () => {\n\t\t\txhr.abort()\n\t\t\treject(new DOMException('Upload aborted', 'AbortError'))\n\t\t}\n\n\t\tif (signal?.aborted) {\n\t\t\treject(new DOMException('Upload aborted', 'AbortError'))\n\t\t\treturn\n\t\t}\n\n\t\tsignal?.addEventListener('abort', handleAbort, { once: true })\n\n\t\txhr.upload.addEventListener('progress', (event) => {\n\t\t\tif (event.lengthComputable && onProgress) {\n\t\t\t\tonProgress({\n\t\t\t\t\tloaded: event.loaded,\n\t\t\t\t\ttotal: event.total,\n\t\t\t\t\tprogress: Math.round((event.loaded / event.total) * 100),\n\t\t\t\t})\n\t\t\t}\n\t\t})\n\n\t\txhr.addEventListener('load', () => {\n\t\t\tsignal?.removeEventListener('abort', handleAbort)\n\n\t\t\tif (xhr.status >= 200 && xhr.status < 300) {\n\t\t\t\tresolve({\n\t\t\t\t\turl: publicUrl,\n\t\t\t\t\tpathname: options?.path ? `${options.path}/${file.name}` : file.name,\n\t\t\t\t\tcontentType: file.type,\n\t\t\t\t\tsize: file.size,\n\t\t\t\t})\n\t\t\t} else {\n\t\t\t\tconst error = new Error(`Upload failed with status ${xhr.status}`) as Error & {\n\t\t\t\t\tstatus: number\n\t\t\t\t}\n\t\t\t\terror.status = xhr.status\n\t\t\t\treject(error)\n\t\t\t}\n\t\t})\n\n\t\txhr.addEventListener('error', () => {\n\t\t\tsignal?.removeEventListener('abort', handleAbort)\n\t\t\treject(new TypeError('Network error during upload'))\n\t\t})\n\n\t\txhr.addEventListener('abort', () => {\n\t\t\tsignal?.removeEventListener('abort', handleAbort)\n\t\t\treject(new DOMException('Upload aborted', 'AbortError'))\n\t\t})\n\n\t\txhr.open('PUT', uploadUrl)\n\t\txhr.setRequestHeader('Content-Type', file.type)\n\t\txhr.send(file)\n\t})\n}\n\n/**\n * Upload a user avatar\n *\n * @example\n * ```typescript\n * const avatar = await uploadAvatar(config, file, 'user-123')\n * console.log(avatar.url)\n * ```\n */\nexport async function uploadAvatar(\n\tconfig: SylphxConfig,\n\tfile: File,\n\tuserId: string,\n\toptions?: Pick<FileUploadOptions, 'onProgress'>,\n): Promise<UploadResult> {\n\treturn uploadFile(config, file, {\n\t\t...options,\n\t\ttype: 'avatar',\n\t\tuserId,\n\t})\n}\n\n/**\n * Delete a file\n *\n * @example\n * ```typescript\n * await deleteFile(config, 'file-123')\n * ```\n */\nexport async function deleteFile(config: SylphxConfig, fileId: string): Promise<void> {\n\tawait callApi(config, `/storage/files/${fileId}`, { method: 'DELETE' })\n}\n\n/**\n * Get a file's URL by ID\n *\n * @example\n * ```typescript\n * const url = await getFileUrl(config, 'file-123')\n * ```\n */\nexport async function getFileUrl(config: SylphxConfig, fileId: string): Promise<string> {\n\tconst data = await callApi<{ url: string }>(config, `/storage/files/${fileId}`, { method: 'GET' })\n\treturn data.url\n}\n\n/**\n * Get file info by ID\n *\n * @example\n * ```typescript\n * const info = await getFileInfo(config, 'file-123')\n * console.log(info.name, info.size)\n * ```\n */\nexport async function getFileInfo(config: SylphxConfig, fileId: string): Promise<FileInfo> {\n\treturn callApi<FileInfo>(config, `/storage/files/${fileId}`, {\n\t\tmethod: 'GET',\n\t})\n}\n\n/**\n * Generate a signed URL for accessing a private file\n *\n * Signed URLs provide time-limited access to private files without\n * exposing permanent URLs. Useful for:\n * - Secure document downloads\n * - Private media streaming\n * - Temporary file sharing\n *\n * @example\n * ```typescript\n * // Generate a download URL valid for 1 hour\n * const { url, expiresAt } = await getSignedUrl(config, 'file-123')\n *\n * // Generate an inline preview URL valid for 5 minutes\n * const preview = await getSignedUrl(config, 'file-123', {\n * expiresIn: 300,\n * disposition: 'inline',\n * })\n *\n * // Restrict access to a specific user\n * const userOnly = await getSignedUrl(config, 'file-123', {\n * userId: 'user-456',\n * })\n * ```\n */\nexport async function getSignedUrl(\n\tconfig: SylphxConfig,\n\tfileId: string,\n\toptions?: SignedUrlOptions,\n): Promise<SignedUrlResult> {\n\treturn callApi<SignedUrlResult>(config, '/storage/signed-url', {\n\t\tmethod: 'POST',\n\t\tbody: {\n\t\t\tfileId,\n\t\t\t...options,\n\t\t},\n\t})\n}\n","/**\n * Push Notification Service Worker Template\n *\n * This module provides a service worker implementation for handling\n * push notifications. Apps should copy or import this into their\n * service worker file.\n *\n * ## Industry Patterns Implemented (OneSignal/FCM)\n * - Push event handling with notification display\n * - Notification click with deep link navigation\n * - Notification close tracking\n * - Token refresh handling\n * - Background sync for offline actions\n *\n * ## Usage\n *\n * Create a service worker file in your app's public directory:\n *\n * ```typescript\n * // public/sw.ts or src/service-worker.ts\n * import { initPushServiceWorker } from '@sylphx/platform-sdk/notifications'\n *\n * initPushServiceWorker({\n * defaultIcon: '/icon-192.png',\n * defaultBadge: '/badge-72.png',\n * onNotificationClick: (data) => {\n * // Custom click handling\n * console.log('Notification clicked:', data)\n * },\n * })\n * ```\n */\n\n/**\n * Service Worker type definitions\n * These are minimal type definitions for Service Worker APIs.\n * Full types available with `lib: [\"WebWorker\"]` in tsconfig.\n */\ninterface PushEventData {\n\tjson(): unknown\n\ttext(): string\n}\n\ninterface PushEvent extends ExtendableEvent {\n\tdata: PushEventData | null\n}\n\ninterface NotificationEvent extends ExtendableEvent {\n\tnotification: Notification & {\n\t\tdata?: Record<string, unknown>\n\t\tclose(): void\n\t}\n\taction?: string\n}\n\ninterface WindowClient {\n\turl: string\n\tfocus(): Promise<WindowClient>\n}\n\ninterface Clients {\n\tmatchAll(options: { type: 'window'; includeUncontrolled: boolean }): Promise<WindowClient[]>\n\topenWindow(url: string): Promise<WindowClient | null>\n\tclaim(): Promise<void>\n}\n\ninterface ExtendableEvent extends Event {\n\twaitUntil(promise: Promise<unknown>): void\n}\n\ninterface ServiceWorkerRegistration {\n\tshowNotification(title: string, options?: NotificationOptions): Promise<void>\n}\n\ninterface ServiceWorkerGlobalScopeSubset {\n\treadonly registration: ServiceWorkerRegistration\n\treadonly clients: Clients\n\taddEventListener(type: 'push', listener: (event: PushEvent) => void): void\n\taddEventListener(\n\t\ttype: 'notificationclick' | 'notificationclose',\n\t\tlistener: (event: NotificationEvent) => void,\n\t): void\n\taddEventListener(type: 'activate', listener: (event: ExtendableEvent) => void): void\n}\n\ndeclare const self: ServiceWorkerGlobalScopeSubset\n\n/**\n * Notification payload from Sylphx platform\n */\nexport interface PushNotificationPayload {\n\t/** Notification title */\n\ttitle: string\n\t/** Notification body text */\n\tbody: string\n\t/** Icon URL (optional, falls back to default) */\n\ticon?: string\n\t/** Badge URL for Android (optional) */\n\tbadge?: string\n\t/** Image URL for expanded notification (optional) */\n\timage?: string\n\t/** Click action URL (optional) */\n\turl?: string\n\t/** Action buttons (optional) */\n\tactions?: Array<{\n\t\taction: string\n\t\ttitle: string\n\t\ticon?: string\n\t}>\n\t/** Custom data payload */\n\tdata?: Record<string, unknown>\n\t/** Notification tag for grouping (optional) */\n\ttag?: string\n\t/** Whether to require interaction (optional) */\n\trequireInteraction?: boolean\n\t/** Vibration pattern (optional) */\n\tvibrate?: number[]\n\t/** Silent notification (optional) */\n\tsilent?: boolean\n}\n\n/**\n * Service worker configuration options\n */\nexport interface PushServiceWorkerConfig {\n\t/** Default icon for notifications without an icon */\n\tdefaultIcon?: string\n\t/** Default badge for notifications without a badge */\n\tdefaultBadge?: string\n\t/** Called when notification is clicked */\n\tonNotificationClick?: (data: PushNotificationPayload) => void\n\t/** Called when notification is closed without clicking */\n\tonNotificationClose?: (data: PushNotificationPayload) => void\n\t/** Platform API URL for analytics/token refresh */\n\tplatformUrl?: string\n\t/** App ID for API calls */\n\tappId?: string\n}\n\n/**\n * Initialize push notification handling in service worker\n *\n * Call this in your service worker file to enable push notification handling.\n *\n * NOTE: This function should only be called from within a service worker context.\n * The types are loosely defined to work in both browser and service worker contexts.\n *\n * @example\n * ```typescript\n * // In your service worker (e.g., public/sw.ts)\n * initPushServiceWorker({\n * defaultIcon: '/icon-192.png',\n * defaultBadge: '/badge-72.png',\n * })\n * ```\n */\nexport function initPushServiceWorker(config: PushServiceWorkerConfig = {}): void {\n\tconst { defaultIcon, defaultBadge, onNotificationClick, onNotificationClose } = config\n\n\t// Handle push events (when notification arrives)\n\tself.addEventListener('push', (event) => {\n\t\tif (!event.data) {\n\t\t\tconsole.warn('[Sylphx SW] Push event received without data')\n\t\t\treturn\n\t\t}\n\n\t\tlet payload: PushNotificationPayload\n\t\ttry {\n\t\t\tpayload = event.data.json() as PushNotificationPayload\n\t\t} catch {\n\t\t\t// Fallback for plain text payloads\n\t\t\tpayload = {\n\t\t\t\ttitle: 'Notification',\n\t\t\t\tbody: event.data.text(),\n\t\t\t}\n\t\t}\n\n\t\t// Build notification options (compatible with both browser and SW contexts)\n\t\tconst notificationOptions = {\n\t\t\tbody: payload.body,\n\t\t\ticon: payload.icon || defaultIcon,\n\t\t\tbadge: payload.badge || defaultBadge,\n\t\t\timage: payload.image,\n\t\t\tdata: {\n\t\t\t\t...payload.data,\n\t\t\t\turl: payload.url,\n\t\t\t\t_sylphxPayload: payload,\n\t\t\t},\n\t\t\ttag: payload.tag,\n\t\t\trequireInteraction: payload.requireInteraction ?? false,\n\t\t\tvibrate: payload.vibrate,\n\t\t\tsilent: payload.silent ?? false,\n\t\t\tactions: payload.actions,\n\t\t}\n\n\t\tevent.waitUntil(self.registration.showNotification(payload.title, notificationOptions))\n\t})\n\n\t// Handle notification click events\n\tself.addEventListener('notificationclick', (event) => {\n\t\tevent.notification.close()\n\n\t\tconst data = event.notification.data\n\t\tconst payload = data?._sylphxPayload as PushNotificationPayload | undefined\n\t\tconst url = data?.url as string | undefined\n\n\t\t// Call custom handler if provided\n\t\tif (onNotificationClick && payload) {\n\t\t\tonNotificationClick(payload)\n\t\t}\n\n\t\t// Handle action button clicks\n\t\tif (event.action) {\n\t\t\t// Custom action handling\n\t\t\tconsole.log('[Sylphx SW] Action clicked:', event.action)\n\t\t}\n\n\t\t// Navigate to URL if provided\n\t\tif (url) {\n\t\t\tevent.waitUntil(\n\t\t\t\tself.clients.matchAll({ type: 'window', includeUncontrolled: true }).then((clientList) => {\n\t\t\t\t\t// Try to focus an existing window with this URL\n\t\t\t\t\tfor (const client of clientList) {\n\t\t\t\t\t\tif (client.url === url && 'focus' in client) {\n\t\t\t\t\t\t\treturn client.focus()\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t// Open a new window if no existing window found\n\t\t\t\t\treturn self.clients.openWindow(url)\n\t\t\t\t}),\n\t\t\t)\n\t\t}\n\t})\n\n\t// Handle notification close events (for analytics)\n\tself.addEventListener('notificationclose', (event) => {\n\t\tconst data = event.notification.data\n\t\tconst payload = data?._sylphxPayload as PushNotificationPayload | undefined\n\n\t\tif (onNotificationClose && payload) {\n\t\t\tonNotificationClose(payload)\n\t\t}\n\t})\n\n\t// Handle service worker activation\n\tself.addEventListener('activate', (event) => {\n\t\tevent.waitUntil(\n\t\t\t// Claim all clients immediately\n\t\t\tself.clients.claim(),\n\t\t)\n\t})\n\n\tconsole.log('[Sylphx SW] Push notification service worker initialized')\n}\n\n/**\n * Helper to create a simple service worker script content\n *\n * For apps that want to dynamically generate their service worker,\n * this returns the JavaScript content as a string.\n *\n * @example\n * ```typescript\n * // In a route handler\n * export function GET() {\n * const content = createServiceWorkerScript({\n * defaultIcon: '/icon-192.png',\n * })\n * return new Response(content, {\n * headers: { 'Content-Type': 'application/javascript' },\n * })\n * }\n * ```\n */\nexport function createServiceWorkerScript(config: PushServiceWorkerConfig = {}): string {\n\tconst { defaultIcon = '/icon-192.png', defaultBadge = '/badge-72.png' } = config\n\n\treturn `\n// Sylphx Push Notification Service Worker\n// Auto-generated - do not edit directly\n\nconst DEFAULT_ICON = '${defaultIcon}';\nconst DEFAULT_BADGE = '${defaultBadge}';\n\nself.addEventListener('push', (event) => {\n if (!event.data) return;\n\n let payload;\n try {\n payload = event.data.json();\n } catch {\n payload = { title: 'Notification', body: event.data.text() };\n }\n\n const options = {\n body: payload.body,\n icon: payload.icon || DEFAULT_ICON,\n badge: payload.badge || DEFAULT_BADGE,\n image: payload.image,\n data: { ...payload.data, url: payload.url },\n tag: payload.tag,\n requireInteraction: payload.requireInteraction || false,\n vibrate: payload.vibrate,\n silent: payload.silent || false,\n actions: payload.actions,\n };\n\n event.waitUntil(\n self.registration.showNotification(payload.title, options)\n );\n});\n\nself.addEventListener('notificationclick', (event) => {\n event.notification.close();\n const url = event.notification.data?.url;\n\n if (url) {\n event.waitUntil(\n clients.matchAll({ type: 'window', includeUncontrolled: true }).then((clientList) => {\n for (const client of clientList) {\n if (client.url === url && 'focus' in client) {\n return client.focus();\n }\n }\n if (clients.openWindow) {\n return clients.openWindow(url);\n }\n })\n );\n }\n});\n\nself.addEventListener('activate', (event) => {\n event.waitUntil(clients.claim());\n});\n\nconsole.log('[Sylphx SW] Push notification service worker active');\n`.trim()\n}\n\n/**\n * Register the service worker from the client side\n *\n * Call this in your app's entry point to register the service worker.\n *\n * @example\n * ```typescript\n * // In your app's entry point (e.g., _app.tsx or layout.tsx)\n * import { registerPushServiceWorker } from '@sylphx/platform-sdk/notifications'\n *\n * useEffect(() => {\n * registerPushServiceWorker('/sw.js')\n * }, [])\n * ```\n */\nexport async function registerPushServiceWorker(\n\tswPath = '/sw.js',\n): Promise<ServiceWorkerRegistration | null> {\n\tif (typeof window === 'undefined') return null\n\tif (!('serviceWorker' in navigator)) {\n\t\tconsole.warn('[Sylphx] Service workers not supported')\n\t\treturn null\n\t}\n\n\ttry {\n\t\tconst registration = await navigator.serviceWorker.register(swPath)\n\t\tconsole.log('[Sylphx] Service worker registered:', registration.scope)\n\t\treturn registration\n\t} catch (error) {\n\t\tconsole.error('[Sylphx] Service worker registration failed:', error)\n\t\treturn null\n\t}\n}\n","/**\n * Notifications Functions\n *\n * Pure functions for push notifications.\n *\n * Types are derived from the OpenAPI spec (generated/api.d.ts).\n * Run `bun run generate:types:local` to regenerate after API changes.\n */\n\nimport { callApi, type SylphxConfig } from './config'\nimport type { components } from './generated/api'\n\n// ============================================================================\n// Types (re-exported from generated OpenAPI spec)\n// ============================================================================\n\nexport type RegisterPushRequest = components['schemas']['RegisterPushBody']\nexport type RegisterPushResponse = components['schemas']['RegisterPushResponse']\nexport type UnregisterPushRequest = components['schemas']['UnregisterPushBody']\nexport type PushPreferencesResponse = components['schemas']['GetPushPreferencesResponse']\nexport type InAppMessage = components['schemas']['InAppMessage']\nexport type InAppMessagesResponse = components['schemas']['GetMessagesResponse']\nexport type MobileConfigResponse = components['schemas']['GetMobileConfigResponse']\nexport type MobileDevice = components['schemas']['MobileDevice']\n\n// SDK-specific types for convenience\nexport interface PushSubscription {\n\tendpoint: string\n\tkeys: {\n\t\tp256dh: string\n\t\tauth: string\n\t}\n}\n\nexport interface PushNotification {\n\ttitle: string\n\tbody: string\n\ticon?: string\n\turl?: string\n}\n\n// ============================================================================\n// Functions\n// ============================================================================\n\n/**\n * Register a push subscription\n *\n * @example\n * ```typescript\n * // Get subscription from browser\n * const registration = await navigator.serviceWorker.ready\n * const sub = await registration.pushManager.subscribe({\n * userVisibleOnly: true,\n * applicationServerKey: vapidPublicKey,\n * })\n *\n * // Register with platform\n * await registerPush(config, {\n * endpoint: sub.endpoint,\n * keys: {\n * p256dh: sub.toJSON().keys!.p256dh,\n * auth: sub.toJSON().keys!.auth,\n * },\n * })\n * ```\n */\nexport async function registerPush(\n\tconfig: SylphxConfig,\n\tsubscription: PushSubscription,\n): Promise<void> {\n\tawait callApi(config, '/notifications/register', {\n\t\tmethod: 'POST',\n\t\tbody: { subscription },\n\t})\n}\n\n/**\n * Unregister a push subscription\n *\n * @example\n * ```typescript\n * await unregisterPush(config, subscription.endpoint)\n * ```\n */\nexport async function unregisterPush(config: SylphxConfig, endpoint: string): Promise<void> {\n\tawait callApi(config, '/notifications/unregister', {\n\t\tmethod: 'POST',\n\t\tbody: { endpoint },\n\t})\n}\n\n/**\n * Send a push notification to a user (admin only)\n *\n * @example\n * ```typescript\n * await sendPush(config, 'user-123', {\n * title: 'New message',\n * body: 'You have a new message',\n * url: '/messages',\n * })\n * ```\n */\nexport async function sendPush(\n\tconfig: SylphxConfig,\n\tuserId: string,\n\tnotification: PushNotification,\n): Promise<{ sentTo: number; expired: number }> {\n\treturn callApi(config, '/notifications/send', {\n\t\tmethod: 'POST',\n\t\tbody: { userId, ...notification },\n\t})\n}\n\n/**\n * Get push notification preferences\n *\n * @example\n * ```typescript\n * const prefs = await getPushPreferences(config)\n * ```\n */\nexport async function getPushPreferences(\n\tconfig: SylphxConfig,\n): Promise<{ enabled: boolean; categories: Record<string, boolean> }> {\n\treturn callApi(config, '/notifications/preferences', { method: 'GET' })\n}\n\n/**\n * Update push notification preferences\n *\n * @example\n * ```typescript\n * await updatePushPreferences(config, {\n * enabled: true,\n * categories: { marketing: false, updates: true },\n * })\n * ```\n */\nexport async function updatePushPreferences(\n\tconfig: SylphxConfig,\n\tpreferences: { enabled?: boolean; categories?: Record<string, boolean> },\n): Promise<void> {\n\tawait callApi(config, '/notifications/preferences', {\n\t\tmethod: 'PUT',\n\t\tbody: preferences,\n\t})\n}\n","/**\n * Triggers Client (ADR-040)\n *\n * Unified scheduling + event dispatch API.\n * Create cron schedules and event triggers that dispatch to Tasks, Runs, or HTTP URLs.\n *\n * ## Usage\n *\n * ### Cron → Task\n * ```typescript\n * import { createConfig, TriggersClient } from '@sylphx/sdk'\n * const config = createConfig({ secretKey: process.env.SYLPHX_SECRET_KEY!, ref: 'my-project' })\n *\n * const trigger = await TriggersClient.create(config, {\n * name: 'daily-cleanup',\n * source: { type: 'cron', expression: '0 2 * * *' },\n * target: { type: 'task', taskName: 'daily-cleanup' },\n * })\n * ```\n *\n * ### Event → Task (fires when event is published via publishEvent)\n * ```typescript\n * const trigger = await TriggersClient.create(config, {\n * name: 'welcome-email-on-signup',\n * source: { type: 'event', eventName: 'user.signup' },\n * target: { type: 'task', taskName: 'send-welcome-email' },\n * })\n * // Publish from your app:\n * await TriggersClient.publishEvent(config, 'user.signup', { userId: '123' })\n * ```\n *\n * ### Cron → HTTP URL (any language, no code required)\n * ```typescript\n * const trigger = await TriggersClient.create(config, {\n * name: 'nightly-backup',\n * source: { type: 'cron', expression: '0 3 * * *' },\n * target: { type: 'http', url: 'https://myapp.com/api/backup', payload: { type: 'full' } },\n * })\n * ```\n */\n\nimport type { SylphxConfig } from '../../config'\nimport { callApi } from '../../config'\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport type TriggerTargetType = 'task' | 'run' | 'http'\nexport type TriggerSourceType = 'cron' | 'event'\nexport type TriggerStatus = 'active' | 'paused' | 'deleted'\n\nexport interface TaskTarget {\n\ttype: 'task'\n\ttaskName: string\n\thandlerPath?: string\n\tpayload?: Record<string, unknown>\n}\n\nexport interface HttpTarget {\n\ttype: 'http'\n\turl: string\n\tmethod?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'\n\theaders?: Record<string, string>\n\tpayload?: Record<string, unknown>\n}\n\nexport interface RunTarget {\n\ttype: 'run'\n\timage: string\n\tcommand: string[]\n\tresources?: { cpu?: string; memory?: string }\n}\n\nexport type TriggerTarget = TaskTarget | HttpTarget | RunTarget\n\nexport interface CronSource {\n\ttype: 'cron'\n\texpression: string\n}\n\nexport interface EventSource {\n\ttype: 'event'\n\t/** The event name to listen for. e.g. 'user.signup', 'order.paid' */\n\teventName: string\n}\n\nexport type TriggerSource = CronSource | EventSource\n\nexport interface CreateTriggerOptions {\n\tname?: string\n\tsource: TriggerSource\n\ttarget: TriggerTarget\n\tpaused?: boolean\n\t/** Idempotency key — prevents duplicate trigger creation per project+environment */\n\tidempotencyKey?: string\n}\n\nexport interface UpdateTriggerOptions {\n\tname?: string\n\tsource?: TriggerSource\n\tpaused?: boolean\n}\n\nexport interface Trigger {\n\tid: string\n\tname: string\n\ttargetType: TriggerTargetType\n\tsourceType: TriggerSourceType\n\tcronExpression: string | null\n\teventName: string | null\n\thandlerPath: string | null\n\tcallbackUrl: string | null\n\tpayload: unknown\n\tstatus: TriggerStatus\n\tnextRunAt: string | null\n\tlastRunAt: string | null\n\tcreatedAt: string\n\tupdatedAt: string\n}\n\nexport interface ListTriggersResult {\n\ttriggers: Trigger[]\n}\n\nexport interface PublishEventResult {\n\tdispatched: number\n\teventName: string\n}\n\n// ============================================================================\n// Client\n// ============================================================================\n\nexport class TriggersClient {\n\t/** Create a new trigger (cron or event source, task/run/http target) */\n\tstatic async create(config: SylphxConfig, options: CreateTriggerOptions): Promise<Trigger> {\n\t\treturn callApi<Trigger>(config, '/triggers', {\n\t\t\tmethod: 'POST',\n\t\t\tbody: options,\n\t\t})\n\t}\n\n\t/** List all triggers for the project */\n\tstatic async list(config: SylphxConfig): Promise<ListTriggersResult> {\n\t\treturn callApi<ListTriggersResult>(config, '/triggers')\n\t}\n\n\t/** Get a trigger by ID */\n\tstatic async get(config: SylphxConfig, triggerId: string): Promise<Trigger> {\n\t\treturn callApi<Trigger>(config, `/triggers/${triggerId}`)\n\t}\n\n\t/** Update a trigger */\n\tstatic async update(\n\t\tconfig: SylphxConfig,\n\t\ttriggerId: string,\n\t\toptions: UpdateTriggerOptions,\n\t): Promise<Trigger> {\n\t\treturn callApi<Trigger>(config, `/triggers/${triggerId}`, {\n\t\t\tmethod: 'PATCH',\n\t\t\tbody: options,\n\t\t})\n\t}\n\n\t/** Delete a trigger */\n\tstatic async delete(config: SylphxConfig, triggerId: string): Promise<{ success: boolean }> {\n\t\treturn callApi<{ success: boolean }>(config, `/triggers/${triggerId}`, { method: 'DELETE' })\n\t}\n\n\t/** Pause a trigger */\n\tstatic async pause(config: SylphxConfig, triggerId: string): Promise<Trigger> {\n\t\treturn callApi<Trigger>(config, `/triggers/${triggerId}/pause`, { method: 'POST' })\n\t}\n\n\t/** Resume a paused trigger */\n\tstatic async resume(config: SylphxConfig, triggerId: string): Promise<Trigger> {\n\t\treturn callApi<Trigger>(config, `/triggers/${triggerId}/resume`, { method: 'POST' })\n\t}\n\n\t/** Fire a trigger immediately (one-shot, regardless of schedule) */\n\tstatic async fire(\n\t\tconfig: SylphxConfig,\n\t\ttriggerId: string,\n\t): Promise<{ success: boolean; message: string }> {\n\t\treturn callApi<{ success: boolean; message: string }>(config, `/triggers/${triggerId}/fire`, {\n\t\t\tmethod: 'POST',\n\t\t})\n\t}\n\n\t/**\n\t * Publish an event — dispatches all active event triggers matching the event name.\n\t *\n\t * @example\n\t * ```typescript\n\t * await TriggersClient.publishEvent(config, 'user.signup', { userId: '123', plan: 'pro' })\n\t * ```\n\t */\n\t/**\n\t * Publish an event — dispatches all active event triggers matching the event name.\n\t * Endpoint: POST /triggers/events\n\t *\n\t * @example\n\t * ```typescript\n\t * await TriggersClient.publishEvent(config, 'user.signup', { userId: '123', plan: 'pro' })\n\t * ```\n\t */\n\tstatic async publishEvent(\n\t\tconfig: SylphxConfig,\n\t\teventName: string,\n\t\tpayload?: Record<string, unknown>,\n\t): Promise<PublishEventResult> {\n\t\treturn callApi<PublishEventResult>(config, '/triggers/events', {\n\t\t\tmethod: 'POST',\n\t\t\tbody: { eventName, payload: payload ?? {} },\n\t\t})\n\t}\n}\n","/**\n * Tasks Handler\n *\n * Server-side endpoint factory for user task definitions.\n * Implements the Sylphx stateless-replay model:\n *\n * 1. Platform dispatches POST to the app's /api/tasks endpoint.\n * 2. The handler replays from the beginning.\n * 3. Completed steps hit a cache and return immediately.\n * 4. The first uncached step executes, then throws StepCompleteSignal.\n * 5. The platform saves the result and re-dispatches.\n * 6. After all steps complete the handler returns normally.\n *\n * @example\n * ```typescript\n * // app/api/tasks/route.ts\n * import { sylphx } from '@/lib/sylphx'\n *\n * const sendEmail = sylphx.tasks.define('send-email', async (payload, { step }) => {\n * const validated = await step.run('validate', () => validateEmail(payload.to))\n * await step.sleep('cool-down', '5 minutes')\n * return step.run('send', () => sendEmail(validated))\n * })\n *\n * export const { GET, POST } = sylphx.tasks.handler([sendEmail])\n * ```\n */\n\nimport { createHmac, timingSafeEqual } from 'node:crypto'\nimport type { NativeStepContext, NativeTaskDefinition } from './types'\n\n// ============================================================================\n// Signals (control flow via throw)\n// ============================================================================\n\n/**\n * Thrown by step.run() when a step's result is not yet cached.\n * The handler aborts; the platform saves the result and re-dispatches.\n */\nexport class StepCompleteSignal {\n\treadonly _isStepCompleteSignal = true\n\n\tconstructor(\n\t\tpublic readonly stepName: string,\n\t\tpublic readonly result: unknown,\n\t) {}\n}\n\n/**\n * Thrown by step.sleep() when the sleep is not yet resolved.\n * The handler aborts; the platform waits and re-dispatches.\n */\nexport class StepSleepSignal {\n\treadonly _isStepSleepSignal = true\n\n\tconstructor(\n\t\tpublic readonly stepName: string,\n\t\tpublic readonly duration: string,\n\t) {}\n}\n\n/**\n * Thrown by step.waitForEvent() when the event has not yet been received.\n * The handler aborts; the platform persists the wait record.\n * When the event arrives (via TriggersClient.publishEvent()), the platform\n * resolves the wait and re-dispatches with the event payload in context.waits.\n */\nexport class StepWaitEventSignal {\n\treadonly _isStepWaitEventSignal = true\n\n\tconstructor(\n\t\tpublic readonly stepName: string,\n\t\tpublic readonly eventName: string,\n\t\tpublic readonly options: {\n\t\t\t/** Timeout duration, e.g. '24h', '7d'. Task fails if event not received in time. */\n\t\t\ttimeout?: string\n\t\t\t/** Optional JSON filter — only resolve if event payload matches */\n\t\t\tfilter?: Record<string, unknown>\n\t\t} = {},\n\t) {}\n}\n\n// ============================================================================\n// Step context factory\n// ============================================================================\n\n/**\n * Build the step proxy for a single handler invocation.\n *\n * @param completedSteps Map of stepName → cached result\n * @param resolvedWaits Map of stepName → wait result (sleep = undefined, event = event payload)\n */\nexport function createStepContext(\n\tcompletedSteps: Map<string, unknown>,\n\tresolvedWaits: Map<string, unknown>,\n): NativeStepContext {\n\treturn {\n\t\t/**\n\t\t * Execute a named step.\n\t\t *\n\t\t * - If cached: return the cached value immediately (replay).\n\t\t * - If not cached: execute fn, then throw StepCompleteSignal with the result.\n\t\t */\n\t\tasync run<T>(name: string, fn: () => T | Promise<T>): Promise<T> {\n\t\t\tif (completedSteps.has(name)) {\n\t\t\t\treturn completedSteps.get(name) as T\n\t\t\t}\n\n\t\t\tconst result = await fn()\n\t\t\tthrow new StepCompleteSignal(name, result)\n\t\t},\n\n\t\t/**\n\t\t * Sleep for the given duration.\n\t\t *\n\t\t * - If resolved (platform woke us up): return immediately.\n\t\t * - If not resolved: throw StepSleepSignal to pause execution.\n\t\t */\n\t\tasync sleep(name: string, duration: string): Promise<void> {\n\t\t\tif (resolvedWaits.has(name)) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tthrow new StepSleepSignal(name, duration)\n\t\t},\n\n\t\t/**\n\t\t * Pause execution until a named event is published via TriggersClient.publishEvent().\n\t\t *\n\t\t * - If event already arrived (platform re-dispatched with result): return event payload.\n\t\t * - If not yet arrived: throw StepWaitEventSignal to pause execution.\n\t\t *\n\t\t * @param name Step identifier (unique within handler).\n\t\t * @param eventName The event name to listen for (e.g. 'user.approved').\n\t\t * @param options Optional timeout ('24h', '7d') and payload filter.\n\t\t *\n\t\t * @example Human-in-the-loop approval\n\t\t * ```typescript\n\t\t * const approval = await step.waitForEvent('wait-approval', 'order.approved', {\n\t\t * timeout: '48h',\n\t\t * filter: { orderId: payload.orderId },\n\t\t * })\n\t\t * if (!approval) throw new Error('Approval timed out')\n\t\t * await sendConfirmation(approval.approvedBy)\n\t\t * ```\n\t\t */\n\t\tasync waitForEvent<T = unknown>(\n\t\t\tname: string,\n\t\t\teventName: string,\n\t\t\toptions: { timeout?: string; filter?: Record<string, unknown> } = {},\n\t\t): Promise<T | null> {\n\t\t\tif (resolvedWaits.has(name)) {\n\t\t\t\t// Platform resolved the wait — return the event payload (null if timed out)\n\t\t\t\treturn (resolvedWaits.get(name) as T | null) ?? null\n\t\t\t}\n\n\t\t\tthrow new StepWaitEventSignal(name, eventName, options)\n\t\t},\n\t}\n}\n\n// ============================================================================\n// Signature verification\n// ============================================================================\n\n/**\n * Constant-time HMAC-SHA256 signature verification.\n * Accepts both raw hex and 'sha256={hex}' formats.\n */\nexport function verifySignature(body: string, signature: string, secret: string): boolean {\n\ttry {\n\t\tconst hmac = createHmac('sha256', secret).update(body, 'utf8').digest('hex')\n\t\tconst normalised = signature.replace(/^sha256=/, '')\n\n\t\tconst expected = Buffer.from(hmac, 'hex')\n\t\tconst provided = Buffer.from(normalised, 'hex')\n\n\t\tif (expected.length !== provided.length) return false\n\t\treturn timingSafeEqual(expected, provided)\n\t} catch {\n\t\treturn false\n\t}\n}\n\n// ============================================================================\n// Request / response types\n// ============================================================================\n\ninterface DispatchStepEntry {\n\tname: string\n\tresult: unknown\n\tcompletedAt: string\n}\n\ninterface DispatchWaitEntry {\n\tname: string\n\tresolvedAt: string\n\tresult?: unknown\n}\n\ninterface DispatchContext {\n\tattempt: number\n\tsteps: DispatchStepEntry[]\n\twaits: DispatchWaitEntry[]\n}\n\ninterface DispatchBody {\n\ttaskRunId: string\n\ttaskName: string\n\tpayload: unknown\n\tcontext: DispatchContext\n}\n\n// ============================================================================\n// Handler factory\n// ============================================================================\n\nexport interface TasksHandlerOptions {\n\t/** Platform signing secret. If not set, signature verification is skipped. */\n\tsigningSecret?: string\n}\n\nexport interface TasksHandlerResult {\n\tGET: (req: Request) => Promise<Response>\n\tPOST: (req: Request) => Promise<Response>\n}\n\n/**\n * Create a Next.js-compatible route handler for a list of task definitions.\n *\n * @example\n * ```typescript\n * export const { GET, POST } = createTasksHandler([sendEmail, processOrder])\n * ```\n */\nexport function createTasksHandler(\n\ttaskDefs: NativeTaskDefinition[],\n\toptions: TasksHandlerOptions = {},\n): TasksHandlerResult {\n\tconst taskMap = new Map<string, NativeTaskDefinition>()\n\tfor (const def of taskDefs) {\n\t\ttaskMap.set(def.name, def)\n\t}\n\n\t// GET: health/discovery — returns registered task names\n\tconst GET = async (_req: Request): Promise<Response> => {\n\t\treturn Response.json({\n\t\t\tok: true,\n\t\t\ttasks: Array.from(taskMap.keys()),\n\t\t})\n\t}\n\n\t// POST: dispatch handler\n\tconst POST = async (req: Request): Promise<Response> => {\n\t\t// ------------------------------------------------------------------\n\t\t// 1. Read raw body as text\n\t\t// ------------------------------------------------------------------\n\t\tlet rawBody: string\n\t\ttry {\n\t\t\trawBody = await req.text()\n\t\t} catch {\n\t\t\treturn Response.json(\n\t\t\t\t{ status: 'error', message: 'Failed to read request body' },\n\t\t\t\t{ status: 400 },\n\t\t\t)\n\t\t}\n\n\t\t// ------------------------------------------------------------------\n\t\t// 2. Verify signature if configured\n\t\t// ------------------------------------------------------------------\n\t\tconst signingSecret =\n\t\t\toptions.signingSecret ??\n\t\t\tprocess.env.SYLPHX_SIGNING_SECRET ??\n\t\t\tprocess.env.SYLPHX_SECRET_KEY ??\n\t\t\t''\n\n\t\tif (signingSecret) {\n\t\t\tconst signature = req.headers.get('x-sylphx-signature') ?? ''\n\t\t\tif (!signature) {\n\t\t\t\treturn Response.json(\n\t\t\t\t\t{ status: 'error', message: 'Missing X-Sylphx-Signature header' },\n\t\t\t\t\t{ status: 401 },\n\t\t\t\t)\n\t\t\t}\n\n\t\t\tif (!verifySignature(rawBody, signature, signingSecret)) {\n\t\t\t\treturn Response.json({ status: 'error', message: 'Invalid signature' }, { status: 401 })\n\t\t\t}\n\t\t}\n\n\t\t// ------------------------------------------------------------------\n\t\t// 3. Parse body\n\t\t// ------------------------------------------------------------------\n\t\tlet dispatch: DispatchBody\n\t\ttry {\n\t\t\tdispatch = JSON.parse(rawBody) as DispatchBody\n\t\t} catch {\n\t\t\treturn Response.json(\n\t\t\t\t{ status: 'error', message: 'Request body is not valid JSON' },\n\t\t\t\t{ status: 400 },\n\t\t\t)\n\t\t}\n\n\t\tconst { taskName, payload, context } = dispatch\n\n\t\tif (!taskName || typeof taskName !== 'string') {\n\t\t\treturn Response.json(\n\t\t\t\t{ status: 'error', message: 'Missing or invalid \"taskName\" field' },\n\t\t\t\t{ status: 400 },\n\t\t\t)\n\t\t}\n\n\t\t// ------------------------------------------------------------------\n\t\t// 4. Find task definition\n\t\t// ------------------------------------------------------------------\n\t\tconst taskDef = taskMap.get(taskName)\n\t\tif (!taskDef) {\n\t\t\treturn Response.json(\n\t\t\t\t{\n\t\t\t\t\tstatus: 'error',\n\t\t\t\t\tmessage: `Task \"${taskName}\" not found. Registered tasks: ${Array.from(taskMap.keys()).join(', ')}`,\n\t\t\t\t},\n\t\t\t\t{ status: 404 },\n\t\t\t)\n\t\t}\n\n\t\t// ------------------------------------------------------------------\n\t\t// 5. Build step context from dispatch context\n\t\t// ------------------------------------------------------------------\n\t\tconst completedSteps = new Map<string, unknown>()\n\t\tfor (const step of context?.steps ?? []) {\n\t\t\tcompletedSteps.set(step.name, step.result)\n\t\t}\n\n\t\t// resolvedWaits: stepName → result (sleep=undefined, event=payload, timeout=null)\n\t\tconst resolvedWaits = new Map<string, unknown>()\n\t\tfor (const wait of context?.waits ?? []) {\n\t\t\tresolvedWaits.set(wait.name, wait.result ?? undefined)\n\t\t}\n\n\t\tconst stepCtx = createStepContext(completedSteps, resolvedWaits)\n\n\t\t// ------------------------------------------------------------------\n\t\t// 6. Invoke the handler\n\t\t// ------------------------------------------------------------------\n\t\ttry {\n\t\t\tconst result = await taskDef.handler(payload, { step: stepCtx })\n\n\t\t\t// Handler returned normally → task is complete\n\t\t\treturn Response.json({ status: 'complete', result })\n\t\t} catch (err: unknown) {\n\t\t\t// ------------------------------------------------------------------\n\t\t\t// 7a. Step completed — save result and re-dispatch\n\t\t\t// ------------------------------------------------------------------\n\t\t\tif (err instanceof StepCompleteSignal || (err as StepCompleteSignal)?._isStepCompleteSignal) {\n\t\t\t\tconst signal = err as StepCompleteSignal\n\t\t\t\treturn Response.json({\n\t\t\t\t\tstatus: 'step_complete',\n\t\t\t\t\tstepName: signal.stepName,\n\t\t\t\t\tresult: signal.result,\n\t\t\t\t})\n\t\t\t}\n\n\t\t\t// ------------------------------------------------------------------\n\t\t\t// 7b. Step sleep — create wait record\n\t\t\t// ------------------------------------------------------------------\n\t\t\tif (err instanceof StepSleepSignal || (err as StepSleepSignal)?._isStepSleepSignal) {\n\t\t\t\tconst signal = err as StepSleepSignal\n\t\t\t\treturn Response.json({\n\t\t\t\t\tstatus: 'step_sleep',\n\t\t\t\t\tstepName: signal.stepName,\n\t\t\t\t\tduration: signal.duration,\n\t\t\t\t})\n\t\t\t}\n\n\t\t\t// ------------------------------------------------------------------\n\t\t\t// 7c. Step waitForEvent — suspend until named event arrives\n\t\t\t// ------------------------------------------------------------------\n\t\t\tif (err instanceof StepWaitEventSignal || (err as StepWaitEventSignal)?._isStepWaitEventSignal) {\n\t\t\t\tconst signal = err as StepWaitEventSignal\n\t\t\t\treturn Response.json({\n\t\t\t\t\tstatus: 'step_wait_event',\n\t\t\t\t\tstepName: signal.stepName,\n\t\t\t\t\teventName: signal.eventName,\n\t\t\t\t\ttimeout: signal.options.timeout ?? null,\n\t\t\t\t\tfilter: signal.options.filter ?? null,\n\t\t\t\t})\n\t\t\t}\n\n\t\t\t// ------------------------------------------------------------------\n\t\t\t// 7d. Unexpected error\n\t\t\t// ------------------------------------------------------------------\n\t\t\tconst message = err instanceof Error ? err.message : String(err)\n\t\t\tconsole.error(`[sylphx/tasks] Task \"${taskName}\" threw an error:`, err)\n\t\t\treturn Response.json(\n\t\t\t\t{\n\t\t\t\t\tstatus: 'error',\n\t\t\t\t\tmessage,\n\t\t\t\t\tretriable: true,\n\t\t\t\t},\n\t\t\t\t{ status: 500 },\n\t\t\t)\n\t\t}\n\t}\n\n\treturn { GET, POST }\n}\n","/**\n * Task API Functions\n *\n * Standalone functions for scheduling tasks and managing crons via the Sylphx API.\n * These are backward-compat exports preserved from the pre-refactor tasks.ts.\n */\n\nimport { callApi, type SylphxConfig } from '../../config'\nimport type { CronSchedule } from './types'\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface TaskInput {\n\t/** Callback URL to call when task executes */\n\tcallbackUrl: string\n\t/** Task name/type */\n\tname?: string\n\t/** Task type for categorization */\n\ttype?: string\n\t/** Task payload sent to callback */\n\tpayload?: Record<string, unknown>\n\t/** HTTP method for callback (default: POST) */\n\tmethod?: 'GET' | 'POST' | 'PUT' | 'DELETE'\n\t/** Additional headers for callback */\n\theaders?: Record<string, string>\n\t/** Delay before executing (in seconds, max 604800 = 7 days) */\n\tdelay?: number\n\t/** Schedule for later (ISO timestamp) */\n\tscheduledFor?: string\n\t/** Number of retries on failure (0-5, default: 3) */\n\tretries?: number\n\t/** Request timeout in seconds (1-300, default: 30) */\n\ttimeout?: number\n\t/**\n\t * Idempotency key for safe retries (Stripe/Inngest pattern).\n\t *\n\t * When provided, prevents duplicate task execution if the same\n\t * key is used within a 24-hour window.\n\t */\n\tidempotencyKey?: string\n}\n\nexport interface TaskResult {\n\t/** Task ID */\n\ttaskId: string\n\t/** QStash message ID */\n\tmessageId?: string\n\t/** Scheduled execution time */\n\tscheduledFor?: string\n}\n\nexport interface TaskStatus {\n\tid: string\n\tname?: string\n\tstatus: 'pending' | 'queued' | 'running' | 'completed' | 'failed' | 'cancelled'\n\tpayload?: Record<string, unknown>\n\tresult?: unknown\n\terror?: string\n\tcreatedAt: string\n\tqueuedAt?: string\n\tstartedAt?: string\n\tcompletedAt?: string\n}\n\nexport interface CronInput {\n\t/** Callback URL to call on each cron trigger */\n\tcallbackUrl: string\n\t/** Cron expression (e.g., '0 0 * * *' for daily at midnight) */\n\tcron: string\n\t/** Task name (required, max 200 chars) */\n\tname: string\n\t/** Task type for categorization */\n\ttype?: string\n\t/** Task payload sent to callback */\n\tpayload?: Record<string, unknown>\n\t/** HTTP method for callback (default: POST) */\n\tmethod?: 'GET' | 'POST' | 'PUT' | 'DELETE'\n\t/** Additional headers for callback */\n\theaders?: Record<string, string>\n\t/** Number of retries on failure (0-5, default: 3) */\n\tretries?: number\n\t/** Start in paused state */\n\tpaused?: boolean\n\t/**\n\t * Idempotency key for safe cron creation.\n\t *\n\t * When provided, prevents duplicate cron schedule creation if\n\t * the same key is used.\n\t */\n\tidempotencyKey?: string\n}\n\n// ============================================================================\n// Functions\n// ============================================================================\n\n/**\n * Schedule a one-time task for execution\n */\nexport async function scheduleTask(config: SylphxConfig, input: TaskInput): Promise<TaskResult> {\n\treturn callApi<TaskResult>(config, '/tasks/schedule', {\n\t\tmethod: 'POST',\n\t\tbody: input,\n\t})\n}\n\n/**\n * Get a task's status by ID\n */\nexport async function getTask(config: SylphxConfig, taskId: string): Promise<TaskStatus> {\n\treturn callApi<TaskStatus>(config, `/tasks/${taskId}`, { method: 'GET' })\n}\n\n/**\n * Cancel a pending task\n */\nexport async function cancelTask(config: SylphxConfig, taskId: string): Promise<boolean> {\n\tconst result = await callApi<{ success: boolean }>(config, `/tasks/${taskId}/cancel`, {\n\t\tmethod: 'POST',\n\t})\n\treturn result.success\n}\n\n/**\n * List tasks with optional filters\n */\nexport async function listTasks(\n\tconfig: SylphxConfig,\n\toptions?: { status?: TaskStatus['status']; limit?: number; offset?: number },\n): Promise<{ tasks: TaskStatus[]; total: number }> {\n\treturn callApi(config, '/tasks', {\n\t\tmethod: 'GET',\n\t\tquery: options as Record<string, string | number | undefined>,\n\t})\n}\n\n/**\n * Create a recurring cron task\n */\nexport async function createCron(config: SylphxConfig, input: CronInput): Promise<CronSchedule> {\n\treturn callApi<CronSchedule>(config, '/tasks/cron', {\n\t\tmethod: 'POST',\n\t\tbody: input,\n\t})\n}\n\n/**\n * Pause a cron schedule\n */\nexport async function pauseCron(config: SylphxConfig, scheduleId: string): Promise<boolean> {\n\tconst result = await callApi<{ success: boolean }>(config, `/tasks/cron/${scheduleId}/pause`, {\n\t\tmethod: 'POST',\n\t})\n\treturn result.success\n}\n\n/**\n * Resume a cron schedule\n */\nexport async function resumeCron(config: SylphxConfig, scheduleId: string): Promise<boolean> {\n\tconst result = await callApi<{ success: boolean }>(config, `/tasks/cron/${scheduleId}/resume`, {\n\t\tmethod: 'POST',\n\t})\n\treturn result.success\n}\n\n/**\n * Delete a cron schedule\n */\nexport async function deleteCron(config: SylphxConfig, scheduleId: string): Promise<boolean> {\n\tconst result = await callApi<{ success: boolean }>(config, `/tasks/cron/${scheduleId}`, {\n\t\tmethod: 'DELETE',\n\t})\n\treturn result.success\n}\n","/**\n * Feature Flags Functions\n *\n * Pure functions for feature flag evaluation.\n *\n * Pattern: LaunchDarkly/Statsig server-side evaluation\n * - Server-side: POST /flags/evaluate with context\n * - Returns evaluated results (enabled/disabled for this context)\n *\n * Types are derived from the OpenAPI spec (generated/api.d.ts).\n * Run `bun run generate:types:local` to regenerate after API changes.\n */\n\nimport { callApi, type SylphxConfig } from './config'\n\n// ============================================================================\n// Types (SDK-specific - no direct API schema for flag results)\n// ============================================================================\n\nexport interface FlagResult {\n\t/** Flag key */\n\tkey: string\n\t/** Whether the flag is enabled for this context */\n\tenabled: boolean\n\t/** Variant value (for multivariate flags) */\n\tvariant?: string\n\t/** Reason for the evaluation result */\n\treason?: string\n\t/** Additional payload data */\n\tpayload?: Record<string, unknown>\n}\n\nexport interface FlagContext {\n\t/** User ID for consistent targeting */\n\tuserId?: string\n\t/** Anonymous ID for pre-auth targeting */\n\tanonymousId?: string\n\t/** User properties for targeting rules (plan, isAdmin, etc.) */\n\tproperties?: Record<string, unknown>\n}\n\n/** Response from the evaluate endpoint */\ninterface EvaluateFlagsResponse {\n\tdata: Record<string, FlagResult>\n}\n\n// ============================================================================\n// Functions\n// ============================================================================\n\n/**\n * Check a single feature flag (server-side evaluation)\n *\n * Uses POST /flags/evaluate for consistent, server-side targeting.\n * The server evaluates rollout percentage, premium targeting, etc.\n *\n * @example\n * ```typescript\n * const flag = await checkFlag(config, 'new-checkout', {\n * userId: 'user-123',\n * properties: { plan: 'pro' },\n * })\n *\n * if (flag.enabled) {\n * // Show new checkout\n * }\n * ```\n */\nexport async function checkFlag(\n\tconfig: SylphxConfig,\n\tflagKey: string,\n\tcontext?: FlagContext,\n): Promise<FlagResult> {\n\tconst response = await callApi<EvaluateFlagsResponse>(config, '/flags/evaluate', {\n\t\tmethod: 'POST',\n\t\tbody: {\n\t\t\tcontext: {\n\t\t\t\tuserId: context?.userId,\n\t\t\t\tanonymousId: context?.anonymousId,\n\t\t\t\tproperties: context?.properties,\n\t\t\t},\n\t\t\tkeys: [flagKey],\n\t\t},\n\t})\n\n\t// Return the evaluated flag, or a disabled default if not found\n\treturn (\n\t\tresponse.data[flagKey] ?? {\n\t\t\tkey: flagKey,\n\t\t\tenabled: false,\n\t\t\treason: 'flag_not_found',\n\t\t}\n\t)\n}\n\n/**\n * Get multiple feature flags at once (batch evaluation)\n *\n * Evaluates all requested flags in a single API call.\n * More efficient than calling checkFlag() multiple times.\n *\n * @example\n * ```typescript\n * const flags = await getFlags(config, ['new-checkout', 'dark-mode', 'ai-features'], {\n * userId: 'user-123',\n * })\n *\n * if (flags['new-checkout'].enabled) {\n * // Show new checkout\n * }\n * ```\n */\nexport async function getFlags(\n\tconfig: SylphxConfig,\n\tflagKeys: string[],\n\tcontext?: FlagContext,\n): Promise<Record<string, FlagResult>> {\n\tconst response = await callApi<EvaluateFlagsResponse>(config, '/flags/evaluate', {\n\t\tmethod: 'POST',\n\t\tbody: {\n\t\t\tcontext: {\n\t\t\t\tuserId: context?.userId,\n\t\t\t\tanonymousId: context?.anonymousId,\n\t\t\t\tproperties: context?.properties,\n\t\t\t},\n\t\t\tkeys: flagKeys,\n\t\t},\n\t})\n\n\treturn response.data\n}\n\n/**\n * Get all feature flags for a context (bootstrap)\n *\n * Evaluates ALL flags for the app in a single API call.\n * Useful for bootstrapping the flag state on app load.\n *\n * @example\n * ```typescript\n * // Bootstrap all flags on app load\n * const allFlags = await getAllFlags(config, { userId: 'user-123' })\n *\n * // Use throughout the app\n * if (allFlags['new-checkout']?.enabled) {\n * // Show new checkout\n * }\n * ```\n */\nexport async function getAllFlags(\n\tconfig: SylphxConfig,\n\tcontext?: FlagContext,\n): Promise<Record<string, FlagResult>> {\n\tconst response = await callApi<EvaluateFlagsResponse>(config, '/flags/evaluate', {\n\t\tmethod: 'POST',\n\t\tbody: {\n\t\t\tcontext: {\n\t\t\t\tuserId: context?.userId,\n\t\t\t\tanonymousId: context?.anonymousId,\n\t\t\t\tproperties: context?.properties,\n\t\t\t},\n\t\t\t// Omit keys to get all flags\n\t\t},\n\t})\n\n\treturn response.data\n}\n\n/**\n * Check if a flag is enabled (boolean helper)\n *\n * @example\n * ```typescript\n * if (await isEnabled(config, 'new-checkout', { userId: 'user-123' })) {\n * // Show new checkout\n * }\n * ```\n */\nexport async function isEnabled(\n\tconfig: SylphxConfig,\n\tflagKey: string,\n\tcontext?: FlagContext,\n): Promise<boolean> {\n\tconst flag = await checkFlag(config, flagKey, context)\n\treturn flag.enabled\n}\n\n/**\n * Get flag variant (for A/B tests)\n *\n * @example\n * ```typescript\n * const variant = await getVariant(config, 'checkout-experiment', {\n * userId: 'user-123',\n * })\n *\n * switch (variant) {\n * case 'control':\n * // Show original checkout\n * break\n * case 'variant-a':\n * // Show variant A\n * break\n * case 'variant-b':\n * // Show variant B\n * break\n * }\n * ```\n */\nexport async function getVariant(\n\tconfig: SylphxConfig,\n\tflagKey: string,\n\tcontext?: FlagContext,\n): Promise<string | undefined> {\n\tconst flag = await checkFlag(config, flagKey, context)\n\treturn flag.variant\n}\n\n/**\n * Get flag payload (for remote config)\n *\n * @example\n * ```typescript\n * const payload = await getFlagPayload<{ maxItems: number }>(config, 'cart-config', {\n * userId: 'user-123',\n * })\n *\n * console.log(payload?.maxItems) // 10\n * ```\n */\nexport async function getFlagPayload<T extends Record<string, unknown>>(\n\tconfig: SylphxConfig,\n\tflagKey: string,\n\tcontext?: FlagContext,\n): Promise<T | undefined> {\n\tconst flag = await checkFlag(config, flagKey, context)\n\treturn flag.payload as T | undefined\n}\n","/**\n * Webhooks Functions\n *\n * Pure functions for webhook configuration and delivery management.\n *\n * Types are derived from the OpenAPI spec (generated/api.d.ts).\n * Run `bun run generate:types:local` to regenerate after API changes.\n */\n\nimport { callApi, type SylphxConfig } from './config'\nimport type { components } from './generated/api'\n\n// ============================================================================\n// Types (re-exported from generated OpenAPI spec)\n// ============================================================================\n\nexport type WebhookConfigResponse = components['schemas']['GetConfigResponse']\nexport type WebhookEnvironmentConfig = components['schemas']['WebhookEnvironmentConfig']\nexport type UpdateWebhookConfigRequest = components['schemas']['UpdateConfigRequest']\nexport type UpdateWebhookConfigResponse = components['schemas']['UpdateConfigResponse']\nexport type ListWebhookDeliveriesResponse = components['schemas']['ListDeliveriesResponse']\nexport type WebhookDelivery = components['schemas']['WebhookDelivery']\nexport type ReplayDeliveryResponse = components['schemas']['ReplayDeliveryResponse']\nexport type WebhookStatsResponse = components['schemas']['WebhookStatsResponse']\n\n// SDK-specific types for convenience\nexport interface WebhookEnvironment {\n\tid: string\n\tname: string\n\twebhookUrl: string | null\n\twebhookSecret?: string | null\n\thasSecret?: boolean\n\tevents?: string[]\n\tcreatedAt: string\n\tupdatedAt: string | null\n}\n\nexport interface WebhookConfig {\n\tenvironments: WebhookEnvironment[]\n\tsupportedEvents?: string[]\n\tenabled?: boolean\n\turl?: string | null\n\tsecret?: string | null\n\tevents?: string[]\n}\n\nexport interface WebhookConfigUpdate {\n\tenvironmentId: string\n\twebhookUrl: string | null\n}\n\nexport interface WebhookDeliveriesResult {\n\tdeliveries: WebhookDelivery[]\n\ttotal: number\n\thasMore: boolean\n}\n\nexport interface WebhookStats {\n\t// Summary totals\n\ttotal: number\n\tdelivered: number\n\tfailed: number\n\tpending: number\n\tdeliveryRate: number\n\tavgLatencyMs: number | null\n\t// Extended stats (for UI)\n\tperiod?: string\n\ttotals?: {\n\t\ttotal: number\n\t\tdelivered: number\n\t\tfailed: number\n\t\tpending: number\n\t\tdeliveryRate: number | string\n\t}\n\tbyEvent?: Array<{ event: string; count: number }>\n\tbyStatus?: Array<{ status: string; count: number }>\n}\n\nexport interface ListDeliveriesOptions {\n\tenvironmentId?: string\n\tstatus?: 'pending' | 'queued' | 'delivered' | 'failed'\n\tlimit?: number\n\toffset?: number\n}\n\n// ============================================================================\n// Functions\n// ============================================================================\n\n/**\n * Get webhook configuration for the app\n *\n * @example\n * ```typescript\n * const config = await getWebhookConfig(sylphxConfig)\n * console.log(config.environments)\n * ```\n */\nexport async function getWebhookConfig(config: SylphxConfig): Promise<WebhookConfig> {\n\treturn callApi(config, '/webhooks/config', { method: 'GET' })\n}\n\n/**\n * Update webhook URL for an environment\n *\n * @example\n * ```typescript\n * await updateWebhookConfig(config, {\n * environmentId: 'env-123',\n * webhookUrl: 'https://myapp.com/webhooks',\n * })\n * ```\n */\nexport async function updateWebhookConfig(\n\tconfig: SylphxConfig,\n\tdata: WebhookConfigUpdate,\n): Promise<void> {\n\treturn callApi(config, '/webhooks/config', { method: 'PUT', body: data })\n}\n\n/**\n * Get webhook delivery history\n *\n * @example\n * ```typescript\n * const { deliveries, total } = await getWebhookDeliveries(config, {\n * status: 'failed',\n * limit: 20,\n * })\n * ```\n */\nexport async function getWebhookDeliveries(\n\tconfig: SylphxConfig,\n\toptions?: ListDeliveriesOptions,\n): Promise<WebhookDeliveriesResult> {\n\treturn callApi(config, '/webhooks/deliveries', {\n\t\tmethod: 'GET',\n\t\tquery: options as Record<string, string | number | undefined>,\n\t})\n}\n\n/**\n * Get a single webhook delivery by ID\n *\n * @example\n * ```typescript\n * const delivery = await getWebhookDelivery(config, 'del-123')\n * console.log(delivery.payload)\n * ```\n */\nexport async function getWebhookDelivery(\n\tconfig: SylphxConfig,\n\tdeliveryId: string,\n): Promise<WebhookDelivery> {\n\treturn callApi(config, `/webhooks/deliveries/${deliveryId}`, {\n\t\tmethod: 'GET',\n\t})\n}\n\n/**\n * Replay a failed webhook delivery\n *\n * @example\n * ```typescript\n * await replayWebhookDelivery(config, 'del-123')\n * ```\n */\nexport async function replayWebhookDelivery(\n\tconfig: SylphxConfig,\n\tdeliveryId: string,\n): Promise<void> {\n\treturn callApi(config, `/webhooks/deliveries/${deliveryId}/replay`, {\n\t\tmethod: 'POST',\n\t})\n}\n\n/**\n * Get webhook statistics\n *\n * @example\n * ```typescript\n * const stats = await getWebhookStats(config)\n * console.log(`Delivery rate: ${stats.deliveryRate}%`)\n * ```\n */\nexport async function getWebhookStats(\n\tconfig: SylphxConfig,\n\tenvironmentId?: string,\n): Promise<WebhookStats> {\n\treturn callApi(config, '/webhooks/stats', {\n\t\tmethod: 'GET',\n\t\tquery: environmentId ? { environmentId } : undefined,\n\t})\n}\n","/**\n * Email Functions\n *\n * Pure functions for transactional email operations.\n *\n * Types are derived from the OpenAPI spec (generated/api.d.ts).\n * Run `bun run generate:types:local` to regenerate after API changes.\n */\n\nimport { callApi, type SylphxConfig } from './config'\nimport type { components } from './generated/api'\n\n// ============================================================================\n// Types (re-exported from generated OpenAPI spec)\n// ============================================================================\n\nexport type SendEmailRequest = components['schemas']['SendEmailRequest']\nexport type SendEmailResponse = components['schemas']['SendEmailResponse']\nexport type SendTemplatedEmailRequest = components['schemas']['SendTemplatedEmailRequest']\nexport type SendTemplatedEmailResponse = components['schemas']['SendEmailResponse']\nexport type SendToUserRequest = components['schemas']['SendEmailToUserRequest']\nexport type SendToUserResponse = components['schemas']['SendEmailResponse']\nexport type NewsletterSubscribeRequest = components['schemas']['NewsletterSubscribeRequest']\nexport type NewsletterSubscribeResponse = components['schemas']['NewsletterSubscribeResponse']\n\n// SDK-specific types for convenience\nexport interface SendEmailOptions {\n\t/** Recipient email address */\n\tto: string\n\t/** Email subject line */\n\tsubject: string\n\t/** HTML content */\n\thtml: string\n\t/** Plain text content (optional fallback) */\n\ttext?: string\n\t/** Reply-to address */\n\treplyTo?: string\n\t/**\n\t * Sender email address (must be from a verified domain).\n\t * Falls back to the app environment default, then the platform FROM_EMAIL.\n\t *\n\t * @example `support@yourdomain.com`\n\t */\n\tfromEmail?: string\n\t/**\n\t * Sender display name (used together with fromEmail).\n\t *\n\t * @example `Acme Support`\n\t */\n\tfromName?: string\n\t/**\n\t * Idempotency key for safe retries (Stripe pattern)\n\t *\n\t * When provided, prevents duplicate email sends if the same request\n\t * is retried within 24 hours. Use a unique key per logical operation.\n\t *\n\t * @example `welcome-email-${userId}`\n\t */\n\tidempotencyKey?: string\n\t/**\n\t * Custom email headers passed directly to the provider.\n\t * Use for email threading (In-Reply-To, References) or other RFC 5322 headers.\n\t * Do not override From, To, or Subject here.\n\t *\n\t * @example `{ 'In-Reply-To': '<abc@cubeage.com>', References: '<abc@cubeage.com>' }`\n\t */\n\theaders?: Record<string, string>\n}\n\nexport interface SendTemplatedEmailOptions {\n\t/** Template name: 'welcome', 'verification', 'password_reset', 'security_alert' */\n\ttemplate: 'welcome' | 'verification' | 'password_reset' | 'security_alert'\n\t/** Recipient email address */\n\tto: string\n\t/** Template variables */\n\tdata?: Record<string, unknown>\n\t/**\n\t * Idempotency key for safe retries (Stripe pattern)\n\t *\n\t * @example `verification-email-${userId}`\n\t */\n\tidempotencyKey?: string\n}\n\nexport interface SendToUserOptions {\n\t/** User ID to send to */\n\tuserId: string\n\t/** Email subject line */\n\tsubject: string\n\t/** HTML content */\n\thtml: string\n\t/** Plain text content (optional fallback) */\n\ttext?: string\n\t/**\n\t * Idempotency key for safe retries (Stripe pattern)\n\t *\n\t * @example `notification-${userId}-${Date.now()}`\n\t */\n\tidempotencyKey?: string\n}\n\nexport interface ScheduleEmailOptions {\n\t/** Recipient email address */\n\tto: string\n\t/** Recipient name (optional) */\n\ttoName?: string\n\t/** Email subject line */\n\tsubject: string\n\t/** HTML content */\n\thtml?: string\n\t/** Plain text content */\n\ttext?: string\n\t/** Reply-to address */\n\treplyTo?: string\n\t/** From email (defaults to app's configured sender) */\n\tfromEmail?: string\n\t/** From name */\n\tfromName?: string\n\t/** ISO timestamp for when to send */\n\tscheduledFor: string\n\t/** Template key for templated emails */\n\ttemplateKey?: string\n\t/** Template variables */\n\ttemplateData?: Record<string, unknown>\n\t/** Idempotency key to prevent duplicates */\n\tidempotencyKey?: string\n\t/** Custom metadata */\n\tmetadata?: Record<string, unknown>\n}\n\nexport interface ScheduledEmail {\n\tid: string\n\tto: string\n\ttoName: string | null\n\tsubject: string\n\tstatus: 'pending' | 'queued' | 'sent' | 'cancelled' | 'failed'\n\tscheduledFor: string\n\tsentAt: string | null\n\tcreatedAt: string\n}\n\nexport interface ScheduledEmailsResult {\n\temails: ScheduledEmail[]\n\ttotal: number\n\thasMore: boolean\n}\n\nexport interface ScheduledEmailStats {\n\ttotal: number\n\tpending: number\n\tqueued: number\n\tsent: number\n\tcancelled: number\n\tfailed: number\n}\n\nexport interface ListScheduledEmailsOptions {\n\tstatus?: 'pending' | 'queued' | 'sent' | 'cancelled' | 'failed' | 'all'\n\tlimit?: number\n\toffset?: number\n}\n\nexport interface SendResult {\n\tid: string\n\tsuccess: boolean\n}\n\n// ============================================================================\n// Functions\n// ============================================================================\n\n/**\n * Check if email service is configured for the app\n *\n * @example\n * ```typescript\n * const configured = await isEmailConfigured(config)\n * if (!configured) console.log('Please configure email settings')\n * ```\n */\nexport async function isEmailConfigured(config: SylphxConfig): Promise<boolean> {\n\treturn callApi(config, '/email/configured', { method: 'GET' })\n}\n\n/**\n * Send a custom email\n *\n * @example\n * ```typescript\n * const result = await sendEmail(config, {\n * to: 'user@example.com',\n * subject: 'Hello!',\n * html: '<p>Welcome to our app!</p>',\n * idempotencyKey: `welcome-${userId}`, // Safe retry\n * })\n * ```\n */\nexport async function sendEmail(\n\tconfig: SylphxConfig,\n\toptions: SendEmailOptions,\n): Promise<SendResult> {\n\tconst { idempotencyKey, ...body } = options\n\treturn callApi(config, '/email/send', {\n\t\tmethod: 'POST',\n\t\tbody,\n\t\tidempotencyKey,\n\t})\n}\n\n/**\n * Send a templated email\n *\n * @example\n * ```typescript\n * await sendTemplatedEmail(config, {\n * template: 'welcome',\n * to: 'user@example.com',\n * data: { name: 'John' },\n * idempotencyKey: `welcome-${userId}`, // Safe retry\n * })\n * ```\n */\nexport async function sendTemplatedEmail(\n\tconfig: SylphxConfig,\n\toptions: SendTemplatedEmailOptions,\n): Promise<SendResult> {\n\tconst { idempotencyKey, ...body } = options\n\treturn callApi(config, '/email/send-templated', {\n\t\tmethod: 'POST',\n\t\tbody,\n\t\tidempotencyKey,\n\t})\n}\n\n/**\n * Send email to a user by their ID\n *\n * @example\n * ```typescript\n * await sendEmailToUser(config, {\n * userId: 'user-123',\n * subject: 'Account Update',\n * html: '<p>Your account has been updated.</p>',\n * idempotencyKey: `update-${userId}-${timestamp}`, // Safe retry\n * })\n * ```\n */\nexport async function sendEmailToUser(\n\tconfig: SylphxConfig,\n\toptions: SendToUserOptions,\n): Promise<SendResult> {\n\tconst { idempotencyKey, ...body } = options\n\treturn callApi(config, '/email/send-to-user', {\n\t\tmethod: 'POST',\n\t\tbody,\n\t\tidempotencyKey,\n\t})\n}\n\n/**\n * Schedule an email for future delivery\n *\n * @example\n * ```typescript\n * const scheduled = await scheduleEmail(config, {\n * to: 'user@example.com',\n * subject: 'Reminder',\n * html: '<p>Don\\'t forget!</p>',\n * scheduledFor: new Date(Date.now() + 86400000).toISOString(), // 24 hours\n * })\n * ```\n */\nexport async function scheduleEmail(\n\tconfig: SylphxConfig,\n\toptions: ScheduleEmailOptions,\n): Promise<ScheduledEmail> {\n\treturn callApi(config, '/email/schedule', { method: 'POST', body: options })\n}\n\n/**\n * List scheduled emails\n *\n * @example\n * ```typescript\n * const { emails, total } = await listScheduledEmails(config, {\n * status: 'pending',\n * limit: 20,\n * })\n * ```\n */\nexport async function listScheduledEmails(\n\tconfig: SylphxConfig,\n\toptions?: ListScheduledEmailsOptions,\n): Promise<ScheduledEmailsResult> {\n\treturn callApi(config, '/email/scheduled', {\n\t\tmethod: 'GET',\n\t\tquery: options as Record<string, string | number | undefined>,\n\t})\n}\n\n/**\n * Get a scheduled email by ID\n *\n * @example\n * ```typescript\n * const email = await getScheduledEmail(config, 'email-123')\n * console.log(email.status)\n * ```\n */\nexport async function getScheduledEmail(\n\tconfig: SylphxConfig,\n\temailId: string,\n): Promise<ScheduledEmail> {\n\treturn callApi(config, `/email/scheduled/${emailId}`, { method: 'GET' })\n}\n\n/**\n * Cancel a scheduled email\n *\n * @example\n * ```typescript\n * await cancelScheduledEmail(config, 'email-123')\n * ```\n */\nexport async function cancelScheduledEmail(config: SylphxConfig, emailId: string): Promise<void> {\n\treturn callApi(config, `/email/scheduled/${emailId}/cancel`, {\n\t\tmethod: 'POST',\n\t})\n}\n\n/**\n * Reschedule an email\n *\n * @example\n * ```typescript\n * await rescheduleEmail(config, 'email-123', new Date(Date.now() + 3600000).toISOString())\n * ```\n */\nexport async function rescheduleEmail(\n\tconfig: SylphxConfig,\n\temailId: string,\n\tscheduledFor: string,\n): Promise<ScheduledEmail> {\n\treturn callApi(config, `/email/scheduled/${emailId}/reschedule`, {\n\t\tmethod: 'POST',\n\t\tbody: { scheduledFor },\n\t})\n}\n\n/**\n * Get scheduled email statistics\n *\n * @example\n * ```typescript\n * const stats = await getScheduledEmailStats(config)\n * console.log(`${stats.pending} emails pending`)\n * ```\n */\nexport async function getScheduledEmailStats(config: SylphxConfig): Promise<ScheduledEmailStats> {\n\treturn callApi(config, '/email/scheduled/stats', { method: 'GET' })\n}\n\n// ============================================================================\n// Email Domain Management\n// ============================================================================\n\n/**\n * DNS record required for domain verification\n */\nexport interface DnsRecord {\n\t/** DNS record type */\n\ttype: 'MX' | 'TXT' | 'CNAME'\n\t/** DNS record name (hostname) */\n\tname: string\n\t/** DNS record value */\n\tvalue: string\n\t/** MX priority (only for MX records) */\n\tpriority?: number\n\t/** TTL in seconds */\n\tttl: number\n}\n\n/**\n * A registered custom sending domain\n */\nexport interface EmailDomain {\n\tid: string\n\tdomain: string\n\tstatus: 'pending' | 'verifying' | 'verified' | 'failed'\n\tdefaultFromEmail: string | null\n\tdefaultFromName: string | null\n\tdnsRecords: DnsRecord[]\n\tcreatedAt: string\n\tverifiedAt: string | null\n}\n\nexport interface RegisterEmailDomainOptions {\n\t/** Default from address for this domain (e.g. support@cubeage.com) */\n\tdefaultFromEmail?: string\n\t/** Default sender display name (e.g. Cubeage Support) */\n\tdefaultFromName?: string\n}\n\nexport interface SetDefaultEmailDomainOptions {\n\t/** Override the default from address */\n\tdefaultFromEmail?: string\n\t/** Override the default sender name */\n\tdefaultFromName?: string\n}\n\n/**\n * Register a custom sending domain\n *\n * Enables email sending for this domain. Returns DNS records to add to your DNS provider.\n * After adding DNS records, call verifyEmailDomain to confirm ownership.\n *\n * @example\n * ```typescript\n * const domain = await registerEmailDomain(config, 'cubeage.com', {\n * defaultFromEmail: 'support@cubeage.com',\n * defaultFromName: 'Cubeage Support',\n * })\n * console.log('Add these DNS records:', domain.dnsRecords)\n * ```\n */\nexport async function registerEmailDomain(\n\tconfig: SylphxConfig,\n\tdomain: string,\n\topts?: RegisterEmailDomainOptions,\n): Promise<EmailDomain> {\n\treturn callApi(config, '/email/domains', {\n\t\tmethod: 'POST',\n\t\tbody: { domain, ...opts },\n\t})\n}\n\n/**\n * List all custom sending domains for this app\n *\n * @example\n * ```typescript\n * const { domains } = await listEmailDomains(config)\n * for (const d of domains) {\n * console.log(d.domain, d.status)\n * }\n * ```\n */\nexport async function listEmailDomains(config: SylphxConfig): Promise<{ domains: EmailDomain[] }> {\n\treturn callApi(config, '/email/domains', { method: 'GET' })\n}\n\n/**\n * Get a specific domain by ID\n *\n * @example\n * ```typescript\n * const domain = await getEmailDomain(config, 'domain-uuid')\n * console.log(domain.dnsRecords)\n * ```\n */\nexport async function getEmailDomain(config: SylphxConfig, domainId: string): Promise<EmailDomain> {\n\treturn callApi(config, `/email/domains/${domainId}`, { method: 'GET' })\n}\n\n/**\n * Delete a custom sending domain\n *\n * Disables email sending for this domain and removes DKIM signing configuration.\n *\n * @example\n * ```typescript\n * await deleteEmailDomain(config, 'domain-uuid')\n * ```\n */\nexport async function deleteEmailDomain(config: SylphxConfig, domainId: string): Promise<void> {\n\treturn callApi(config, `/email/domains/${domainId}`, { method: 'DELETE' })\n}\n\n/**\n * Trigger DNS verification for a domain\n *\n * Checks if your DNS records have propagated. Status changes to 'verified' when DKIM is confirmed.\n * Status changes to 'verified' on success or 'failed' on error.\n *\n * @example\n * ```typescript\n * const domain = await verifyEmailDomain(config, 'domain-uuid')\n * if (domain.status === 'verified') {\n * console.log('Domain verified!')\n * }\n * ```\n */\nexport async function verifyEmailDomain(\n\tconfig: SylphxConfig,\n\tdomainId: string,\n): Promise<EmailDomain> {\n\treturn callApi(config, `/email/domains/${domainId}/verify`, {\n\t\tmethod: 'POST',\n\t})\n}\n\n/**\n * Set a domain as the default sender for this app\n *\n * @example\n * ```typescript\n * const domain = await setDefaultEmailDomain(config, 'domain-uuid', {\n * defaultFromEmail: 'support@cubeage.com',\n * defaultFromName: 'Cubeage Support',\n * })\n * ```\n */\nexport async function setDefaultEmailDomain(\n\tconfig: SylphxConfig,\n\tdomainId: string,\n\topts?: SetDefaultEmailDomainOptions,\n): Promise<EmailDomain> {\n\treturn callApi(config, `/email/domains/${domainId}/set-default`, {\n\t\tmethod: 'POST',\n\t\tbody: opts ?? {},\n\t})\n}\n","/**\n * Consent Functions\n *\n * Pure functions for GDPR/CCPA consent management.\n *\n * ## Architecture (ADR-004)\n *\n * Consent uses **Inline Defaults + Auto-Discovery + Console Override**:\n * - Code provides optional inline defaults when checking consent\n * - Platform auto-discovers/creates consent types when first referenced\n * - Console can override names, descriptions, requirements without deployment\n *\n * Types are derived from the OpenAPI spec (generated/api.d.ts).\n * Run `bun run generate:types:local` to regenerate after API changes.\n *\n * @example\n * ```typescript\n * import { hasConsent, getUserConsents, setConsents } from '@sylphx/sdk'\n *\n * // Check consent with inline defaults (auto-discovered if doesn't exist)\n * if (await hasConsent(config, 'analytics', { userId: 'user-123' }, {\n * name: 'Analytics Cookies',\n * description: 'Help us understand how visitors use our site',\n * category: 'analytics',\n * required: false,\n * })) {\n * track('pageview')\n * }\n *\n * // Get user's current consents\n * const consents = await getUserConsents(config, { userId: 'user-123' })\n *\n * // Set specific consents\n * await setConsents(config, {\n * userId: 'user-123',\n * consents: { analytics: true, marketing: false }\n * })\n * ```\n */\n\nimport { callApi, type SylphxConfig } from './config'\nimport type { components } from './generated/api'\n\n// ============================================================================\n// Types (re-exported from generated OpenAPI spec)\n// ============================================================================\n\nexport type ConsentType = components['schemas']['ConsentType']\nexport type UserConsent = components['schemas']['UserConsent']\nexport type SetConsentRequest = components['schemas']['SetConsentsRequest']\nexport type SetConsentResponse = components['schemas']['SetConsentsResponse']\n\n// SDK-specific types (not directly from API schema)\n/** Consent category for grouping */\nexport type ConsentCategory = 'necessary' | 'analytics' | 'marketing' | 'functional' | 'preferences'\n\nexport interface SetConsentsInput {\n\t/** User ID (optional for anonymous users) */\n\tuserId?: string\n\t/** Anonymous ID (for guest users) */\n\tanonymousId?: string\n\t/** Consent settings by type slug */\n\tconsents: Record<string, boolean>\n}\n\nexport interface LinkAnonymousConsentsInput {\n\t/** The authenticated user ID to link to */\n\tuserId: string\n\t/** The anonymous ID whose consents should be linked */\n\tanonymousId: string\n}\n\nexport interface GetConsentHistoryInput {\n\t/** User ID (for authenticated users) */\n\tuserId?: string\n\t/** Anonymous ID (for anonymous users) */\n\tanonymousId?: string\n\t/** Maximum records to return (default: 50) */\n\tlimit?: number\n\t/**\n\t * Opaque pagination cursor returned by a previous response.\n\t * Omit (or pass undefined) to fetch the first page.\n\t */\n\tcursor?: string\n}\n\n/** A single consent change history entry */\nexport interface ConsentHistoryEntry {\n\t/** Unique entry ID */\n\tid: string\n\t/** Consent type slug (e.g., 'analytics') */\n\tconsentType: string\n\t/** Display name of the consent type */\n\tconsentTypeName: string\n\t/** Previous consent state (null = initial consent) */\n\tpreviousGranted: boolean | null\n\t/** New consent state */\n\tnewGranted: boolean\n\t/** Source of the change (banner, settings, api) */\n\tsource: string\n\t/** Reason for change (user_action, policy_update, etc.) */\n\treason: string | null\n\t/** ISO timestamp when change occurred */\n\tcreatedAt: string\n}\n\nexport interface ConsentHistoryResult {\n\t/** List of consent change entries */\n\tentries: ConsentHistoryEntry[]\n\t/**\n\t * Opaque cursor for the next page. Pass as `cursor` to the next call.\n\t * Null when this is the last page.\n\t */\n\tnextCursor: string | null\n\t/** Whether there are more entries */\n\thasMore: boolean\n}\n\nexport interface GetConsentsInput {\n\t/** User ID (optional for anonymous users) */\n\tuserId?: string\n\t/** Anonymous ID (for guest users) */\n\tanonymousId?: string\n}\n\n/**\n * Inline defaults for consent purpose auto-discovery\n *\n * @example\n * ```typescript\n * await hasConsent(config, 'analytics', { userId: 'user-123' }, {\n * name: 'Analytics Cookies',\n * description: 'Help us understand how visitors use our site',\n * category: 'analytics',\n * required: false,\n * })\n * ```\n */\nexport interface ConsentPurposeDefaults {\n\t/** Display name */\n\tname?: string\n\t/** Description */\n\tdescription?: string\n\t/** Category */\n\tcategory?: ConsentCategory\n\t/** Whether consent is required (always granted) */\n\trequired?: boolean\n\t/** Whether enabled by default */\n\tdefaultEnabled?: boolean\n\t/** Sort order in UI */\n\tsortOrder?: number\n}\n\n// ============================================================================\n// Functions\n// ============================================================================\n\n/**\n * Get all consent types configured for the app\n *\n * Returns GDPR-standard defaults if none configured.\n *\n * @example\n * ```typescript\n * const types = await getConsentTypes(config)\n * types.forEach(t => console.log(`${t.name}: ${t.required ? 'Required' : 'Optional'}`))\n * ```\n */\nexport async function getConsentTypes(config: SylphxConfig): Promise<ConsentType[]> {\n\treturn callApi(config, '/consent/types', { method: 'GET' })\n}\n\n/**\n * Check if user has granted consent for a specific purpose\n *\n * If the consent type doesn't exist, it will be auto-discovered with the provided defaults.\n * Console can override any values without deployment.\n *\n * @param config - SDK configuration\n * @param purposeSlug - Consent purpose slug (e.g., 'analytics', 'marketing')\n * @param input - User identification (userId or anonymousId)\n * @param defaults - Optional inline defaults for auto-discovery\n * @returns Whether consent is granted\n *\n * @example\n * ```typescript\n * // Check analytics consent with inline defaults\n * if (await hasConsent(config, 'analytics', { userId: 'user-123' }, {\n * name: 'Analytics Cookies',\n * description: 'Help us understand how visitors use our site',\n * category: 'analytics',\n * required: false,\n * })) {\n * track('pageview')\n * }\n *\n * // Required consent always returns true\n * const hasNecessary = await hasConsent(config, 'necessary', { userId }, {\n * name: 'Essential Cookies',\n * description: 'Required for the website to function',\n * category: 'necessary',\n * required: true,\n * })\n * ```\n */\nexport async function hasConsent(\n\tconfig: SylphxConfig,\n\tpurposeSlug: string,\n\tinput: GetConsentsInput,\n\tdefaults?: ConsentPurposeDefaults,\n): Promise<boolean> {\n\treturn callApi(config, '/consent/check', {\n\t\tmethod: 'POST',\n\t\tbody: { purposeSlug, ...input, defaults },\n\t})\n}\n\n/**\n * Get user's current consent settings\n *\n * @example\n * ```typescript\n * // For authenticated user\n * const consents = await getUserConsents(config, { userId: 'user-123' })\n *\n * // For anonymous user\n * const consents = await getUserConsents(config, { anonymousId: 'anon-456' })\n * ```\n */\nexport async function getUserConsents(\n\tconfig: SylphxConfig,\n\tinput: GetConsentsInput,\n): Promise<UserConsent[]> {\n\treturn callApi(config, '/consent/user', {\n\t\tmethod: 'GET',\n\t\tquery: input as Record<string, string | undefined>,\n\t})\n}\n\n/**\n * Set user's consent preferences\n *\n * @example\n * ```typescript\n * await setConsents(config, {\n * userId: 'user-123',\n * consents: {\n * analytics: true,\n * marketing: false,\n * },\n * })\n * ```\n */\nexport async function setConsents(config: SylphxConfig, input: SetConsentsInput): Promise<void> {\n\treturn callApi(config, '/consent/set', { method: 'POST', body: input })\n}\n\n/**\n * Accept all consent types\n *\n * @example\n * ```typescript\n * await acceptAllConsents(config, { userId: 'user-123' })\n * ```\n */\nexport async function acceptAllConsents(\n\tconfig: SylphxConfig,\n\tinput: GetConsentsInput,\n): Promise<void> {\n\treturn callApi(config, '/consent/accept-all', {\n\t\tmethod: 'POST',\n\t\tbody: input,\n\t})\n}\n\n/**\n * Decline all optional consent types (keeps required ones)\n *\n * @example\n * ```typescript\n * await declineOptionalConsents(config, { anonymousId: 'anon-456' })\n * ```\n */\nexport async function declineOptionalConsents(\n\tconfig: SylphxConfig,\n\tinput: GetConsentsInput,\n): Promise<void> {\n\treturn callApi(config, '/consent/decline-optional', {\n\t\tmethod: 'POST',\n\t\tbody: input,\n\t})\n}\n\n/**\n * Link anonymous user's consents to authenticated user\n *\n * Call this after user signs up/logs in to merge their anonymous consent history.\n *\n * @example\n * ```typescript\n * await linkAnonymousConsents(config, {\n * userId: 'user-123',\n * anonymousId: 'anon-456',\n * })\n * ```\n */\nexport async function linkAnonymousConsents(\n\tconfig: SylphxConfig,\n\tinput: LinkAnonymousConsentsInput,\n): Promise<void> {\n\treturn callApi(config, '/consent/link-anonymous', {\n\t\tmethod: 'POST',\n\t\tbody: input,\n\t})\n}\n\n/**\n * Get consent change history for GDPR audit trail\n *\n * Returns a paginated list of all consent state changes for a user.\n * Required for GDPR compliance - provides complete audit trail of consent decisions.\n *\n * @example\n * ```typescript\n * // Get consent history for authenticated user (first page)\n * const history = await getConsentHistory(config, { userId: 'user-123', limit: 20 })\n * history.entries.forEach(entry => {\n * console.log(`${entry.consentType}: ${entry.previousGranted} → ${entry.newGranted}`)\n * })\n *\n * // Fetch next page using the cursor\n * if (history.nextCursor) {\n * const page2 = await getConsentHistory(config, {\n * userId: 'user-123',\n * limit: 20,\n * cursor: history.nextCursor,\n * })\n * }\n * ```\n */\nexport async function getConsentHistory(\n\tconfig: SylphxConfig,\n\tinput: GetConsentHistoryInput,\n): Promise<ConsentHistoryResult> {\n\treturn callApi(config, '/consent/history', {\n\t\tmethod: 'GET',\n\t\tquery: {\n\t\t\tuserId: input.userId,\n\t\t\tanonymousId: input.anonymousId,\n\t\t\tlimit: input.limit?.toString(),\n\t\t\tcursor: input.cursor,\n\t\t},\n\t})\n}\n","/**\n * Referrals Functions\n *\n * Pure functions for referral code management and tracking.\n *\n * ## Architecture (ADR-004)\n *\n * Referrals uses **Inline Defaults + Auto-Discovery + Console Override**:\n * - Code provides optional inline defaults when redeeming referral codes\n * - Platform uses defaults if no Console override exists\n * - Console can override reward values without deployment\n *\n * Types are derived from the OpenAPI spec (generated/api.d.ts).\n * Run `bun run generate:types:local` to regenerate after API changes.\n *\n * @example\n * ```typescript\n * import { redeemReferralCode } from '@sylphx/sdk'\n *\n * // Redeem with inline defaults (overridable in Console)\n * const result = await redeemReferralCode(config, {\n * code: 'ABC123',\n * userId: 'new-user-456',\n * }, {\n * referrerReward: { type: 'premium_trial', days: 7 },\n * refereeReward: { type: 'premium_trial', days: 7 },\n * })\n * ```\n */\n\nimport { callApi, type SylphxConfig } from './config'\nimport type { components } from './generated/api'\n\n// ============================================================================\n// Types (re-exported from generated OpenAPI spec)\n// ============================================================================\n\nexport type ReferralCodeResponse = components['schemas']['GetCodeResponse']\nexport type RegenerateCodeResponse = components['schemas']['RegenerateCodeResponse']\nexport type ReferralStatsResponse = components['schemas']['GetStatsResponse']\nexport type RedeemReferralRequest = components['schemas']['RedeemRequest']\nexport type RedeemReferralResponse = components['schemas']['RedeemResponse']\nexport type ReferralRewardDefaults = components['schemas']['ReferralRewardDefaults']\nexport type ReferralRewardConfig = components['schemas']['ReferralRewardConfig']\nexport type LeaderboardResponse = components['schemas']['LeaderboardResponse']\nexport type LeaderboardEntry = components['schemas']['LeaderboardEntry']\n\n// SDK-specific types for convenience\nexport interface ReferralCode {\n\tcode: string\n\tcreatedAt: string\n}\n\nexport interface ReferralStats {\n\t/** User's referral code */\n\tcode: string\n\t/** Total referrals made */\n\ttotalReferrals: number\n\t/** Successful (redeemed) referrals */\n\tsuccessfulReferrals: number\n\t/** Pending referrals */\n\tpendingReferrals: number\n\t/** Total rewards earned */\n\ttotalRewards: number\n}\n\ntype LeaderboardPeriod = 'all' | 'month' | 'week'\n\nexport interface LeaderboardResult {\n\t/** Time period for the leaderboard */\n\tperiod?: LeaderboardPeriod\n\tentries: LeaderboardEntry[]\n\t/** Current user's position (may not be in top entries) */\n\tcurrentUserRank: number | null\n\t/** Total participants */\n\ttotalParticipants: number\n}\n\nexport interface RedeemReferralInput {\n\t/** Referral code to redeem */\n\tcode: string\n\t/** User ID of the person redeeming (optional for anonymous) */\n\tuserId?: string\n}\n\nexport interface RedeemResult {\n\tsuccess: boolean\n\t/** Reward type - platform types or app-specific types */\n\trewardType: 'points' | 'premium_trial' | 'discount' | 'credit' | (string & {})\n\treferredReward?: Record<string, unknown>\n\treferrerReward?: Record<string, unknown>\n}\n\nexport interface LeaderboardOptions {\n\t/** Number of entries to return (default: 10) */\n\tlimit?: number\n}\n\n// ============================================================================\n// Functions\n// ============================================================================\n\n/**\n * Get current user's referral code\n *\n * Creates one if it doesn't exist.\n *\n * @example\n * ```typescript\n * const { code } = await getMyReferralCode(config, 'user-123')\n * console.log(`Share your code: ${code}`)\n * ```\n */\nexport async function getMyReferralCode(\n\tconfig: SylphxConfig,\n\tuserId: string,\n): Promise<ReferralCode> {\n\treturn callApi(config, '/referrals/code', {\n\t\tmethod: 'GET',\n\t\tquery: { userId },\n\t})\n}\n\n/**\n * Get referral statistics for a user\n *\n * @example\n * ```typescript\n * const stats = await getReferralStats(config, 'user-123')\n * console.log(`${stats.successfulReferrals} successful referrals`)\n * ```\n */\nexport async function getReferralStats(\n\tconfig: SylphxConfig,\n\tuserId: string,\n): Promise<ReferralStats> {\n\treturn callApi(config, '/referrals/stats', {\n\t\tmethod: 'GET',\n\t\tquery: { userId },\n\t})\n}\n\n/**\n * Redeem a referral code\n *\n * If the referral program rewards aren't configured in Console, the provided\n * defaults will be used. Console can override any values without deployment.\n *\n * @param config - SDK configuration\n * @param input - Referral redemption input (code, userId)\n * @param defaults - Optional inline defaults for reward configuration\n *\n * @example\n * ```typescript\n * // Basic redemption (uses Console-configured rewards)\n * const result = await redeemReferralCode(config, {\n * code: 'ABC123',\n * userId: 'new-user-456',\n * })\n *\n * // With inline defaults (auto-discovered if not in Console)\n * const result = await redeemReferralCode(config, {\n * code: 'ABC123',\n * userId: 'new-user-456',\n * }, {\n * referrerReward: { type: 'premium_trial', days: 7 },\n * refereeReward: { type: 'premium_trial', days: 7 },\n * })\n *\n * if (result.success) {\n * console.log(`Reward: ${result.reward?.type}`)\n * }\n * ```\n */\nexport async function redeemReferralCode(\n\tconfig: SylphxConfig,\n\tinput: RedeemReferralInput,\n\tdefaults?: ReferralRewardDefaults,\n): Promise<RedeemResult> {\n\treturn callApi(config, '/referrals/redeem', {\n\t\tmethod: 'POST',\n\t\tbody: { ...input, defaults },\n\t})\n}\n\n/**\n * Get referral leaderboard\n *\n * @example\n * ```typescript\n * const { entries, currentUserRank } = await getReferralLeaderboard(config, 'user-123')\n *\n * entries.forEach(e => {\n * console.log(`#${e.rank} ${e.displayName}: ${e.completedReferrals} referrals`)\n * })\n * ```\n */\nexport async function getReferralLeaderboard(\n\tconfig: SylphxConfig,\n\tuserId: string,\n\toptions?: LeaderboardOptions,\n): Promise<LeaderboardResult> {\n\treturn callApi(config, '/referrals/leaderboard', {\n\t\tmethod: 'GET',\n\t\tquery: { userId, ...options } as Record<string, string | number | undefined>,\n\t})\n}\n\n/**\n * Regenerate user's referral code\n *\n * Use this if the current code has been compromised or user wants a fresh start.\n *\n * @example\n * ```typescript\n * const { code } = await regenerateReferralCode(config, 'user-123')\n * console.log(`New code: ${code}`)\n * ```\n */\nexport async function regenerateReferralCode(\n\tconfig: SylphxConfig,\n\tuserId: string,\n): Promise<ReferralCode> {\n\treturn callApi(config, '/referrals/code/regenerate', {\n\t\tmethod: 'POST',\n\t\tbody: { userId },\n\t})\n}\n","/**\n * Engagement Service Types\n *\n * Core types for streaks, leaderboards, and achievements.\n *\n * ## Architecture (ADR-004)\n *\n * Engagement uses **Inline Defaults + Auto-Discovery + Console Override**:\n * - Code provides optional inline defaults when calling APIs\n * - Platform auto-discovers/creates entities when first referenced\n * - Console can override names, descriptions, values without deployment\n */\n\n// ============================================================================\n// Streaks\n// ============================================================================\n\n/** Streak activity frequency */\nexport type StreakFrequency = 'daily' | 'weekly' | 'custom'\n\n/** Streak definition (auto-discovered or from Console) */\nexport interface StreakDefinition {\n\t/** Unique identifier */\n\tid: string\n\t/** Display name */\n\tname: string\n\t/** Description */\n\tdescription?: string\n\t/** Activity frequency */\n\tfrequency: StreakFrequency\n\t/** Grace period in hours (default: 0) */\n\tgracePeriodHours?: number\n\t/** Whether streak resets on miss (default: true) */\n\tresetOnMiss?: boolean\n\t/** Maximum streak value (optional cap) */\n\tmaxValue?: number\n\t/** Custom interval in hours (only for 'custom' frequency) */\n\tcustomIntervalHours?: number\n}\n\n/** User's streak state (from platform) */\nexport interface StreakState {\n\t/** Streak definition ID */\n\tstreakId: string\n\t/** Current streak count */\n\tcurrent: number\n\t/** Longest streak ever */\n\tlongest: number\n\t/** Last activity timestamp */\n\tlastActivityAt: string | null\n\t/** When current streak will expire */\n\texpiresAt: string | null\n\t/** Whether streak can be recovered (within grace period) */\n\tcanRecover: boolean\n\t/** Time remaining until expiry in ms */\n\ttimeRemainingMs: number | null\n\t/** User's timezone preference for streak expiry (IANA timezone, e.g., 'America/New_York') */\n\tuserTimezone: string | null\n}\n\n/** Activity recording input */\nexport interface RecordActivityInput {\n\t/** Streak ID */\n\tstreakId: string\n\t/** User's IANA timezone (e.g., 'America/New_York') for calculating streak expiry at user's local midnight */\n\tuserTimezone?: string\n\t/** Optional metadata */\n\tmetadata?: Record<string, unknown>\n\t/**\n\t * Idempotency key for safe retries (Stripe pattern)\n\t *\n\t * Prevents duplicate streak recordings if the same request is retried.\n\t * Use a unique key per logical activity (e.g., `streak-${userId}-${date}`).\n\t */\n\tidempotencyKey?: string\n}\n\n/** Activity recording result */\nexport interface RecordActivityResult {\n\t/** Updated streak state */\n\tstreak: StreakState\n\t/** Whether this activity extended the streak */\n\textended: boolean\n\t/** Whether a new personal best was achieved */\n\tnewPersonalBest: boolean\n\t/** Previous streak value (for animation) */\n\tpreviousValue: number\n}\n\n// ============================================================================\n// Leaderboards\n// ============================================================================\n\n/** Leaderboard sort direction */\nexport type LeaderboardSortDirection = 'asc' | 'desc'\n\n/** Leaderboard reset period */\nexport type LeaderboardResetPeriod = 'hourly' | 'daily' | 'weekly' | 'monthly' | 'never'\n\n/** Score aggregation method */\nexport type LeaderboardAggregation = 'max' | 'sum' | 'latest' | 'count' | 'min' | 'avg'\n\n/** Leaderboard definition (auto-discovered or from Console) */\nexport interface LeaderboardDefinition {\n\t/** Unique identifier */\n\tid: string\n\t/** Display name */\n\tname: string\n\t/** Description */\n\tdescription?: string\n\t/** Sort direction (desc = higher is better) */\n\tsortDirection: LeaderboardSortDirection\n\t/** Reset period */\n\tresetPeriod: LeaderboardResetPeriod\n\t/** How to aggregate multiple scores from same user */\n\taggregation: LeaderboardAggregation\n\t/** Default privacy for entries */\n\tdefaultPrivacy?: 'public' | 'friends' | 'anonymous'\n\t/** Maximum entries to keep per period */\n\tmaxEntries?: number\n}\n\n/** Leaderboard entry */\nexport interface LeaderboardEntry {\n\t/** Rank (1-indexed) */\n\trank: number\n\t/** User ID (may be null for anonymous) */\n\tuserId: string | null\n\t/** Display name */\n\tdisplayName: string\n\t/** Avatar URL */\n\tavatarUrl: string | null\n\t/** Score/value */\n\tvalue: number\n\t/** Whether this is the current user */\n\tisCurrentUser: boolean\n\t/** Entry metadata */\n\tmetadata?: Record<string, unknown>\n\t/** When the score was submitted */\n\tsubmittedAt: string\n}\n\n/** Leaderboard query options */\nexport interface LeaderboardQueryOptions {\n\t/** Number of entries to return (default: 10) */\n\tlimit?: number\n\t/** Offset for pagination */\n\toffset?: number\n\t/** Include surrounding entries for current user */\n\tincludeSurrounding?: boolean\n\t/** Number of surrounding entries (default: 2) */\n\tsurroundingCount?: number\n}\n\n/** Leaderboard query result */\nexport interface LeaderboardResult {\n\t/** Leaderboard definition ID */\n\tleaderboardId: string\n\t/** Period (for periodic leaderboards) */\n\tperiod?: string\n\t/** Entries (top N or paginated) */\n\tentries: LeaderboardEntry[]\n\t/** Current user's entry (may not be in top entries) */\n\tcurrentUserEntry: LeaderboardEntry | null\n\t/** Entries surrounding the current user (when includeSurrounding=true and user is outside main entries) */\n\tsurroundingEntries?: LeaderboardEntry[]\n\t/** Total participants */\n\ttotalParticipants: number\n\t/** Next reset time (for periodic leaderboards) */\n\tnextResetAt: string | null\n}\n\n/** Score submission input */\nexport interface SubmitScoreInput {\n\t/** Leaderboard ID */\n\tleaderboardId: string\n\t/** Score value */\n\tvalue: number\n\t/** Optional metadata */\n\tmetadata?: Record<string, unknown>\n}\n\n/** Score submission result */\nexport interface SubmitScoreResult {\n\t/** Whether submission was accepted */\n\taccepted: boolean\n\t/** New rank (if in leaderboard) */\n\trank: number | null\n\t/** Previous best (if any) */\n\tpreviousBest: number | null\n\t/** Whether this is a new personal best */\n\tnewPersonalBest: boolean\n\t/** Rank change (positive = improved) */\n\trankChange: number | null\n}\n\n// ============================================================================\n// Achievements\n// ============================================================================\n\n/** Achievement type */\nexport type AchievementType = 'standard' | 'hidden' | 'incremental'\n\n/** Achievement tier */\nexport type AchievementTier = 'bronze' | 'silver' | 'gold' | 'platinum' | 'diamond'\n\n/** Achievement category */\nexport type AchievementCategory = string // App-defined\n\n/** Achievement criteria operator */\nexport type CriteriaOperator = 'eq' | 'ne' | 'gt' | 'gte' | 'lt' | 'lte' | 'in' | 'contains'\n\n/** Single criterion */\nexport interface AchievementCriterion {\n\t/** Property to check (e.g., 'event', 'count', 'streak.daily') */\n\tproperty: string\n\t/** Comparison operator */\n\toperator: CriteriaOperator\n\t/** Value to compare against */\n\tvalue: string | number | boolean | string[] | number[]\n}\n\n/** Achievement criteria (AND logic within, OR between arrays) */\nexport interface AchievementCriteria {\n\t/** Event name to track (for event-based achievements) */\n\tevent?: string\n\t/** Required count of events */\n\tcount?: number\n\t/** Additional conditions */\n\tconditions?: AchievementCriterion[]\n}\n\n/** Achievement definition (auto-discovered or from Console) */\nexport interface AchievementDefinition {\n\t/** Unique identifier */\n\tid: string\n\t/** Display name */\n\tname: string\n\t/** Description (shown before unlock) */\n\tdescription: string\n\t/** Description shown after unlock (optional) */\n\tunlockedDescription?: string\n\t/** Achievement type */\n\ttype: AchievementType\n\t/** Tier/rarity */\n\ttier: AchievementTier\n\t/** Category (app-defined) */\n\tcategory: AchievementCategory\n\t/** Icon (Iconify name or URL) */\n\ticon: string\n\t/** Points awarded */\n\tpoints?: number\n\t/** Unlock criteria */\n\tcriteria: AchievementCriteria\n\t/** Target value for incremental achievements */\n\ttarget?: number\n\t/** Whether to show in list before unlock */\n\tsecret?: boolean\n\t/** Order in list */\n\torder?: number\n}\n\n/** User's achievement state */\nexport interface UserAchievement {\n\t/** Achievement definition ID */\n\tachievementId: string\n\t/** Whether unlocked */\n\tunlocked: boolean\n\t/** Unlock timestamp */\n\tunlockedAt: string | null\n\t/** Progress (for incremental) */\n\tprogress: number\n\t/** Target (for incremental) */\n\ttarget: number | null\n\t/** Progress percentage (0-100) */\n\tprogressPercent: number\n}\n\n/** Achievement unlock event */\nexport interface AchievementUnlockEvent {\n\t/** Achievement definition */\n\tachievement: AchievementDefinition\n\t/** User achievement state */\n\tuserAchievement: UserAchievement\n\t/** Whether this is a new unlock (vs already unlocked) */\n\tisNew: boolean\n}\n\n// ============================================================================\n// Engagement Config (from Platform)\n// ============================================================================\n\n/** Complete engagement configuration (fetched from platform) */\ninterface EngagementConfig {\n\t/** Streak definitions */\n\tstreaks?: StreakDefinition[]\n\t/** Leaderboard definitions */\n\tleaderboards?: LeaderboardDefinition[]\n\t/** Achievement definitions */\n\tachievements?: AchievementDefinition[]\n\t/** Achievement categories (for UI grouping) */\n\tachievementCategories?: {\n\t\tid: string\n\t\tname: string\n\t\ticon?: string\n\t\torder?: number\n\t}[]\n}\n\n// ============================================================================\n// Tier Metadata (for UI)\n// ============================================================================\n\nexport const ACHIEVEMENT_TIER_CONFIG = {\n\tbronze: { color: '#CD7F32', points: 10 },\n\tsilver: { color: '#C0C0C0', points: 25 },\n\tgold: { color: '#FFD700', points: 50 },\n\tplatinum: { color: '#00CED1', points: 100 },\n\tdiamond: { color: '#B9F2FF', points: 200 },\n} as const\n\n// ============================================================================\n// Inline Defaults (Auto-Discovery)\n// ============================================================================\n// These types define the optional inline defaults that can be passed when\n// calling engagement functions. If the entity doesn't exist, the platform\n// will auto-create it with these defaults. Console can override any values.\n\n/**\n * Inline defaults for streak auto-discovery\n *\n * @example\n * ```typescript\n * await recordStreakActivity(config, { streakId: 'daily-login' }, userId, {\n * name: 'Daily Login',\n * frequency: 'daily',\n * gracePeriodHours: 12,\n * })\n * ```\n */\nexport interface StreakDefaults {\n\t/** Display name */\n\tname?: string\n\t/** Description */\n\tdescription?: string\n\t/** Activity frequency */\n\tfrequency?: StreakFrequency\n\t/** Grace period in hours (default: 0) */\n\tgracePeriodHours?: number\n\t/** Whether streak resets on miss (default: true) */\n\tresetOnMiss?: boolean\n\t/** Maximum streak value (optional cap) */\n\tmaxValue?: number\n\t/** Custom interval in hours (only for 'custom' frequency) */\n\tcustomIntervalHours?: number\n}\n\n/**\n * Inline defaults for leaderboard auto-discovery\n *\n * @example\n * ```typescript\n * await submitScore(config, { leaderboardId: 'high-scores', value: 1500 }, userId, {\n * name: 'High Scores',\n * sortDirection: 'desc',\n * resetPeriod: 'weekly',\n * })\n * ```\n */\nexport interface LeaderboardDefaults {\n\t/** Display name */\n\tname?: string\n\t/** Description */\n\tdescription?: string\n\t/** Sort direction (desc = higher is better) */\n\tsortDirection?: LeaderboardSortDirection\n\t/** Reset period */\n\tresetPeriod?: LeaderboardResetPeriod\n\t/** How to aggregate multiple scores from same user */\n\taggregation?: LeaderboardAggregation\n\t/** Maximum entries to keep per period */\n\tmaxEntries?: number\n}\n\n/**\n * Inline defaults for achievement auto-discovery\n *\n * @example\n * ```typescript\n * await unlockAchievement(config, 'first-purchase', userId, {\n * name: 'First Purchase',\n * description: 'Made your first purchase',\n * points: 100,\n * tier: 'bronze',\n * })\n * ```\n */\nexport interface AchievementDefaults {\n\t/** Display name */\n\tname?: string\n\t/** Description (shown before unlock) */\n\tdescription?: string\n\t/** Description shown after unlock */\n\tunlockedDescription?: string\n\t/** Achievement type */\n\ttype?: AchievementType\n\t/** Tier/rarity */\n\ttier?: AchievementTier\n\t/** Category (app-defined) */\n\tcategory?: AchievementCategory\n\t/** Icon (Iconify name or URL) */\n\ticon?: string\n\t/** Points awarded */\n\tpoints?: number\n\t/** Target value for incremental achievements */\n\ttarget?: number\n\t/** Whether to show in list before unlock */\n\tsecret?: boolean\n}\n","/**\n * Engagement Functions\n *\n * Pure functions for streaks, leaderboards, and achievements.\n *\n * ## Architecture (ADR-004)\n *\n * Engagement uses **Inline Defaults + Auto-Discovery + Console Override**:\n * - Code provides optional inline defaults when calling functions\n * - Platform auto-discovers/creates entities when first referenced\n * - Console can override names, descriptions, values without deployment\n *\n * @example\n * ```typescript\n * import { unlockAchievement, recordStreakActivity, submitScore } from '@sylphx/sdk'\n *\n * // Unlock achievement with inline defaults (auto-discovered if doesn't exist)\n * await unlockAchievement(config, 'first-win', userId, {\n * name: 'First Win',\n * description: 'Won your first game',\n * points: 100,\n * tier: 'bronze',\n * })\n *\n * // Record streak activity with inline defaults\n * await recordStreakActivity(config, { streakId: 'daily-login' }, userId, {\n * name: 'Daily Login',\n * frequency: 'daily',\n * gracePeriodHours: 12,\n * })\n *\n * // Submit leaderboard score with inline defaults\n * await submitScore(config, { leaderboardId: 'high-scores', value: 1500 }, userId, {\n * name: 'High Scores',\n * sortDirection: 'desc',\n * resetPeriod: 'weekly',\n * })\n * ```\n */\n\nimport { callApi, type SylphxConfig } from './config'\n\n// Re-export types from types file\nexport type {\n\tAchievementCategory,\n\tAchievementCriteria,\n\tAchievementCriterion,\n\t// Achievements\n\tAchievementDefinition,\n\tAchievementTier,\n\tAchievementType,\n\tAchievementUnlockEvent,\n\tCriteriaOperator,\n\tLeaderboardAggregation,\n\t// Leaderboards\n\tLeaderboardDefinition,\n\tLeaderboardEntry,\n\tLeaderboardQueryOptions,\n\tLeaderboardResetPeriod,\n\tLeaderboardResult,\n\tLeaderboardSortDirection,\n\tRecordActivityInput,\n\tRecordActivityResult,\n\t// Streaks\n\tStreakDefinition,\n\tStreakFrequency,\n\tStreakState,\n\tSubmitScoreInput,\n\tSubmitScoreResult,\n\tUserAchievement,\n} from './lib/engagement/types'\n\nexport { ACHIEVEMENT_TIER_CONFIG } from './lib/engagement/types'\n\n// ============================================================================\n// Streak Functions\n// ============================================================================\n\nimport type {\n\tRecordActivityInput,\n\tRecordActivityResult,\n\tStreakDefaults,\n\tStreakState,\n} from './lib/engagement/types'\n\n/**\n * Get current streak state for a user\n *\n * @example\n * ```typescript\n * const streak = await getStreak(config, 'daily-challenge', userId)\n * console.log(`Current streak: ${streak.current}`)\n * console.log(`Expires in: ${streak.timeRemainingMs}ms`)\n * ```\n */\nexport async function getStreak(\n\tconfig: SylphxConfig,\n\tstreakId: string,\n\tuserId: string,\n): Promise<StreakState> {\n\treturn callApi(config, '/engagement/streaks/get', {\n\t\tmethod: 'GET',\n\t\tquery: { streakId, userId },\n\t})\n}\n\n/**\n * Get all streak states for a user\n *\n * @example\n * ```typescript\n * const streaks = await getAllStreaks(config, userId)\n * for (const streak of streaks) {\n * console.log(`${streak.streakId}: ${streak.current}`)\n * }\n * ```\n */\nexport async function getAllStreaks(config: SylphxConfig, userId: string): Promise<StreakState[]> {\n\treturn callApi(config, '/engagement/streaks', {\n\t\tmethod: 'GET',\n\t\tquery: { userId },\n\t})\n}\n\n/**\n * Record an activity to extend/maintain a streak\n *\n * If the streak doesn't exist, it will be auto-discovered with the provided defaults.\n * Console can override any values without deployment.\n *\n * @param config - SDK configuration\n * @param input - Activity input (streakId required)\n * @param userId - User ID\n * @param defaults - Optional inline defaults for auto-discovery\n *\n * @example\n * ```typescript\n * const result = await recordStreakActivity(config, {\n * streakId: 'daily-challenge',\n * }, userId, {\n * name: 'Daily Challenge',\n * frequency: 'daily',\n * gracePeriodHours: 12,\n * })\n *\n * if (result.extended) {\n * console.log(`Streak extended to ${result.streak.current}!`)\n * }\n * if (result.newPersonalBest) {\n * console.log('New personal best!')\n * }\n * ```\n */\nexport async function recordStreakActivity(\n\tconfig: SylphxConfig,\n\tinput: RecordActivityInput,\n\tuserId: string,\n\tdefaults?: StreakDefaults,\n): Promise<RecordActivityResult> {\n\tconst { idempotencyKey, ...inputBody } = input\n\treturn callApi(config, '/engagement/streaks/record', {\n\t\tmethod: 'POST',\n\t\tbody: { ...inputBody, userId, defaults },\n\t\tidempotencyKey,\n\t})\n}\n\n/**\n * Recover a streak within grace period (may require payment/reward)\n *\n * @example\n * ```typescript\n * const result = await recoverStreak(config, 'daily-challenge', userId)\n * if (result.success) {\n * console.log(`Streak recovered at ${result.streak.current}`)\n * }\n * ```\n */\nexport async function recoverStreak(\n\tconfig: SylphxConfig,\n\tstreakId: string,\n\tuserId: string,\n): Promise<{ success: boolean; streak: StreakState }> {\n\treturn callApi(config, '/engagement/streaks/recover', {\n\t\tmethod: 'POST',\n\t\tbody: { streakId, userId },\n\t})\n}\n\n// ============================================================================\n// Leaderboard Functions\n// ============================================================================\n\nimport type {\n\tLeaderboardDefaults,\n\tLeaderboardQueryOptions,\n\tLeaderboardResult,\n\tSubmitScoreInput,\n\tSubmitScoreResult,\n} from './lib/engagement/types'\n\n/**\n * Get leaderboard entries\n *\n * @example\n * ```typescript\n * const result = await getLeaderboard(config, 'high-scores', userId, {\n * limit: 10,\n * includeSurrounding: true,\n * })\n *\n * for (const entry of result.entries) {\n * console.log(`#${entry.rank} ${entry.displayName}: ${entry.value}`)\n * }\n *\n * if (result.currentUserEntry) {\n * console.log(`Your rank: #${result.currentUserEntry.rank}`)\n * }\n * ```\n */\nexport async function getLeaderboard(\n\tconfig: SylphxConfig,\n\tleaderboardId: string,\n\tuserId: string | null,\n\toptions?: LeaderboardQueryOptions,\n): Promise<LeaderboardResult> {\n\treturn callApi(config, '/engagement/leaderboards/get', {\n\t\tmethod: 'GET',\n\t\tquery: { leaderboardId, userId: userId ?? undefined, ...options } as Record<\n\t\t\tstring,\n\t\t\tstring | number | boolean | undefined\n\t\t>,\n\t})\n}\n\n/**\n * Submit a score to a leaderboard\n *\n * If the leaderboard doesn't exist, it will be auto-discovered with the provided defaults.\n * Console can override any values without deployment.\n *\n * @param config - SDK configuration\n * @param input - Score submission input (leaderboardId, value required)\n * @param userId - User ID\n * @param defaults - Optional inline defaults for auto-discovery\n *\n * @example\n * ```typescript\n * const result = await submitScore(config, {\n * leaderboardId: 'high-scores',\n * value: 1500,\n * metadata: { level: 'hard' },\n * }, userId, {\n * name: 'High Scores',\n * sortDirection: 'desc',\n * resetPeriod: 'weekly',\n * aggregation: 'max',\n * })\n *\n * if (result.newPersonalBest) {\n * console.log('New personal best!')\n * }\n * if (result.rank !== null) {\n * console.log(`Ranked #${result.rank}`)\n * }\n * ```\n */\nexport async function submitScore(\n\tconfig: SylphxConfig,\n\tinput: SubmitScoreInput,\n\tuserId: string,\n\tdefaults?: LeaderboardDefaults,\n): Promise<SubmitScoreResult> {\n\treturn callApi(config, '/engagement/leaderboards/submit', {\n\t\tmethod: 'POST',\n\t\tbody: { ...input, userId, defaults },\n\t})\n}\n\n/**\n * Get user's rank on a leaderboard (even if not in top entries)\n *\n * @example\n * ```typescript\n * const rank = await getUserRank(config, 'high-scores', userId)\n * if (rank) {\n * console.log(`You are ranked #${rank.rank} with score ${rank.value}`)\n * }\n * ```\n */\nexport async function getUserLeaderboardRank(\n\tconfig: SylphxConfig,\n\tleaderboardId: string,\n\tuserId: string,\n): Promise<{ rank: number; value: number } | null> {\n\treturn callApi(config, '/engagement/leaderboards/rank', {\n\t\tmethod: 'GET',\n\t\tquery: { leaderboardId, userId },\n\t})\n}\n\n// ============================================================================\n// Achievement Functions\n// ============================================================================\n\nimport type {\n\tAchievementDefaults,\n\tAchievementUnlockEvent,\n\tUserAchievement,\n} from './lib/engagement/types'\n\n/**\n * Get all achievements with user progress\n *\n * @example\n * ```typescript\n * const achievements = await getAchievements(config, userId)\n *\n * const unlocked = achievements.filter(a => a.unlocked)\n * console.log(`${unlocked.length} achievements unlocked`)\n *\n * const inProgress = achievements.filter(a => !a.unlocked && a.progress > 0)\n * for (const a of inProgress) {\n * console.log(`${a.achievementId}: ${a.progress}/${a.target}`)\n * }\n * ```\n */\nexport async function getAchievements(\n\tconfig: SylphxConfig,\n\tuserId: string,\n): Promise<UserAchievement[]> {\n\treturn callApi(config, '/engagement/achievements', {\n\t\tmethod: 'GET',\n\t\tquery: { userId },\n\t})\n}\n\n/**\n * Get a single achievement with user progress\n *\n * @example\n * ```typescript\n * const achievement = await getAchievement(config, 'first-win', userId)\n * if (achievement?.unlocked) {\n * console.log(`Unlocked at ${achievement.unlockedAt}`)\n * }\n * ```\n */\nexport async function getAchievement(\n\tconfig: SylphxConfig,\n\tachievementId: string,\n\tuserId: string,\n): Promise<UserAchievement | null> {\n\treturn callApi(config, '/engagement/achievements/get', {\n\t\tmethod: 'GET',\n\t\tquery: { achievementId, userId },\n\t})\n}\n\n/**\n * Manually unlock an achievement\n *\n * If the achievement doesn't exist, it will be auto-discovered with the provided defaults.\n * Console can override any values without deployment.\n *\n * @param config - SDK configuration\n * @param achievementId - Achievement ID\n * @param userId - User ID\n * @param defaults - Optional inline defaults for auto-discovery\n *\n * @example\n * ```typescript\n * const result = await unlockAchievement(config, 'first-purchase', userId, {\n * name: 'First Purchase',\n * description: 'Made your first purchase',\n * points: 100,\n * tier: 'bronze',\n * })\n * if (result.isNew) {\n * showAchievementToast(result.achievement)\n * }\n * ```\n */\nexport async function unlockAchievement(\n\tconfig: SylphxConfig,\n\tachievementId: string,\n\tuserId: string,\n\tdefaults?: AchievementDefaults,\n): Promise<AchievementUnlockEvent> {\n\treturn callApi(config, '/engagement/achievements/unlock', {\n\t\tmethod: 'POST',\n\t\tbody: { achievementId, userId, defaults },\n\t})\n}\n\n/**\n * Increment progress on an incremental achievement\n *\n * If the achievement doesn't exist, it will be auto-discovered with the provided defaults.\n * Console can override any values without deployment.\n *\n * @param config - SDK configuration\n * @param achievementId - Achievement ID\n * @param amount - Amount to increment\n * @param userId - User ID\n * @param defaults - Optional inline defaults for auto-discovery\n *\n * @example\n * ```typescript\n * // User collected an item\n * const result = await incrementAchievementProgress(config, 'collector-100', 1, userId, {\n * name: 'Collector',\n * description: 'Collect 100 items',\n * type: 'incremental',\n * target: 100,\n * tier: 'silver',\n * })\n *\n * if (result.unlocked) {\n * console.log('Achievement unlocked!')\n * } else {\n * console.log(`Progress: ${result.progress}/${result.target}`)\n * }\n * ```\n */\nexport async function incrementAchievementProgress(\n\tconfig: SylphxConfig,\n\tachievementId: string,\n\tamount: number,\n\tuserId: string,\n\tdefaults?: AchievementDefaults,\n): Promise<UserAchievement> {\n\treturn callApi(config, '/engagement/achievements/progress', {\n\t\tmethod: 'POST',\n\t\tbody: { achievementId, amount, userId, defaults },\n\t})\n}\n\n/**\n * Get total achievement points for a user\n *\n * @example\n * ```typescript\n * const points = await getAchievementPoints(config, userId)\n * console.log(`Total points: ${points.total}`)\n * console.log(`This month: ${points.thisMonth}`)\n * ```\n */\nexport async function getAchievementPoints(\n\tconfig: SylphxConfig,\n\tuserId: string,\n): Promise<{ total: number; thisMonth: number; rank: number | null }> {\n\treturn callApi(config, '/engagement/achievements/points', {\n\t\tmethod: 'GET',\n\t\tquery: { userId },\n\t})\n}\n","/**\n * Organization Functions\n *\n * Pure functions for organization management - no hidden state.\n * Each function takes config as the first parameter.\n *\n * Uses REST API at /api/sdk/orgs/* for all operations.\n *\n * Types are derived from the OpenAPI spec (generated/api.d.ts).\n * Run `bun run generate:types:local` to regenerate after API changes.\n */\n\nimport { callApi, type SylphxConfig } from './config'\nimport type { components } from './generated/api'\n\n// ============================================================================\n// Types (re-exported from generated OpenAPI spec)\n// ============================================================================\n\nexport type Organization = components['schemas']['Organization']\nexport type OrganizationMember = components['schemas']['OrgMember']\nexport type OrganizationInvitation = components['schemas']['OrgInvitation']\nexport type OrganizationMembership = components['schemas']['MembershipInfo']\nexport type OrgRole = components['schemas']['OrgMember']['role']\nexport type CreateOrgInput = components['schemas']['CreateOrgRequest']\nexport type UpdateOrgInput = components['schemas']['UpdateOrgRequest']\nexport type InviteMemberInput = components['schemas']['InviteMemberRequest']\n\n// ============================================================================\n// Organization CRUD\n// ============================================================================\n\n/**\n * Get all organizations the current user belongs to\n *\n * @example\n * ```typescript\n * const { organizations } = await getOrganizations(config)\n * ```\n */\nexport async function getOrganizations(\n\tconfig: SylphxConfig,\n): Promise<{ organizations: Organization[] }> {\n\treturn callApi<{ organizations: Organization[] }>(config, '/orgs')\n}\n\n/**\n * Get organization by ID or slug\n *\n * @example\n * ```typescript\n * const { organization, membership } = await getOrganization(config, 'my-org')\n * ```\n */\nexport async function getOrganization(\n\tconfig: SylphxConfig,\n\torgIdOrSlug: string,\n): Promise<{\n\torganization: Organization\n\tmembership: OrganizationMembership | null\n}> {\n\treturn callApi<{\n\t\torganization: Organization\n\t\tmembership: OrganizationMembership | null\n\t}>(config, `/orgs/${orgIdOrSlug}`)\n}\n\n/**\n * Create a new organization\n *\n * @example\n * ```typescript\n * const { organization } = await createOrganization(config, {\n * name: 'My Company',\n * slug: 'my-company',\n * })\n * ```\n */\nexport async function createOrganization(\n\tconfig: SylphxConfig,\n\tinput: CreateOrgInput,\n): Promise<{ organization: Organization }> {\n\treturn callApi<{ organization: Organization }>(config, '/orgs', {\n\t\tmethod: 'POST',\n\t\tbody: input,\n\t})\n}\n\n/**\n * Update an organization\n *\n * @example\n * ```typescript\n * const { organization } = await updateOrganization(config, 'my-org', {\n * name: 'New Name',\n * })\n * ```\n */\nexport async function updateOrganization(\n\tconfig: SylphxConfig,\n\torgIdOrSlug: string,\n\tinput: UpdateOrgInput,\n): Promise<{ organization: Organization }> {\n\treturn callApi<{ organization: Organization }>(config, `/orgs/${orgIdOrSlug}`, {\n\t\tmethod: 'PUT',\n\t\tbody: input,\n\t})\n}\n\n/**\n * Delete an organization\n *\n * Requires super_admin role.\n *\n * @example\n * ```typescript\n * await deleteOrganization(config, 'my-org')\n * ```\n */\nexport async function deleteOrganization(\n\tconfig: SylphxConfig,\n\torgIdOrSlug: string,\n): Promise<{ success: boolean }> {\n\treturn callApi<{ success: boolean }>(config, `/orgs/${orgIdOrSlug}`, {\n\t\tmethod: 'DELETE',\n\t})\n}\n\n// ============================================================================\n// Members\n// ============================================================================\n\n/**\n * Get organization members\n *\n * @example\n * ```typescript\n * const { members } = await getOrganizationMembers(config, 'my-org')\n * ```\n */\nexport async function getOrganizationMembers(\n\tconfig: SylphxConfig,\n\torgIdOrSlug: string,\n): Promise<{ members: OrganizationMember[] }> {\n\treturn callApi<{ members: OrganizationMember[] }>(config, `/orgs/${orgIdOrSlug}/members`)\n}\n\n/**\n * Invite a member to an organization\n *\n * Requires admin or super_admin role.\n *\n * @example\n * ```typescript\n * const { invitation } = await inviteOrganizationMember(config, 'my-org', {\n * email: 'user@example.com',\n * role: 'developer',\n * })\n * ```\n */\nexport async function inviteOrganizationMember(\n\tconfig: SylphxConfig,\n\torgIdOrSlug: string,\n\tinput: InviteMemberInput,\n): Promise<{ invitation: OrganizationInvitation }> {\n\treturn callApi<{ invitation: OrganizationInvitation }>(\n\t\tconfig,\n\t\t`/orgs/${orgIdOrSlug}/members/invite`,\n\t\t{\n\t\t\tmethod: 'POST',\n\t\t\tbody: input,\n\t\t},\n\t)\n}\n\n/**\n * Update a member's role\n *\n * Requires admin or super_admin role.\n *\n * @example\n * ```typescript\n * const { member } = await updateOrganizationMemberRole(config, 'my-org', userId, 'admin')\n * ```\n */\nexport async function updateOrganizationMemberRole(\n\tconfig: SylphxConfig,\n\torgIdOrSlug: string,\n\tmemberId: string,\n\trole: OrgRole,\n): Promise<{ member: OrganizationMember }> {\n\treturn callApi<{ member: OrganizationMember }>(\n\t\tconfig,\n\t\t`/orgs/${orgIdOrSlug}/members/${memberId}/role`,\n\t\t{\n\t\t\tmethod: 'PUT',\n\t\t\tbody: { role },\n\t\t},\n\t)\n}\n\n/**\n * Remove a member from an organization\n *\n * Requires admin or super_admin role.\n *\n * @example\n * ```typescript\n * await removeOrganizationMember(config, 'my-org', userId)\n * ```\n */\nexport async function removeOrganizationMember(\n\tconfig: SylphxConfig,\n\torgIdOrSlug: string,\n\tmemberId: string,\n): Promise<{ success: boolean }> {\n\treturn callApi<{ success: boolean }>(config, `/orgs/${orgIdOrSlug}/members/${memberId}`, {\n\t\tmethod: 'DELETE',\n\t})\n}\n\n/**\n * Leave an organization\n *\n * @example\n * ```typescript\n * await leaveOrganization(config, 'my-org')\n * ```\n */\nexport async function leaveOrganization(\n\tconfig: SylphxConfig,\n\torgIdOrSlug: string,\n): Promise<{ success: boolean }> {\n\treturn callApi<{ success: boolean }>(config, `/orgs/${orgIdOrSlug}/leave`, {\n\t\tmethod: 'POST',\n\t})\n}\n\n// ============================================================================\n// Invitations\n// ============================================================================\n\n/**\n * Get pending invitations for an organization\n *\n * Requires admin or super_admin role.\n *\n * @example\n * ```typescript\n * const { invitations } = await getOrganizationInvitations(config, 'my-org')\n * ```\n */\nexport async function getOrganizationInvitations(\n\tconfig: SylphxConfig,\n\torgIdOrSlug: string,\n): Promise<{ invitations: OrganizationInvitation[] }> {\n\treturn callApi<{ invitations: OrganizationInvitation[] }>(\n\t\tconfig,\n\t\t`/orgs/${orgIdOrSlug}/invitations`,\n\t)\n}\n\n/**\n * Accept an organization invitation\n *\n * @example\n * ```typescript\n * const { organization } = await acceptOrganizationInvitation(config, invitationToken)\n * ```\n */\nexport async function acceptOrganizationInvitation(\n\tconfig: SylphxConfig,\n\ttoken: string,\n): Promise<{ organization: Organization }> {\n\treturn callApi<{ organization: Organization }>(config, '/orgs/invitations/accept', {\n\t\tmethod: 'POST',\n\t\tbody: { token },\n\t})\n}\n\n/**\n * Revoke a pending invitation\n *\n * Requires admin or super_admin role.\n *\n * @example\n * ```typescript\n * await revokeOrganizationInvitation(config, 'my-org', invitationId)\n * ```\n */\nexport async function revokeOrganizationInvitation(\n\tconfig: SylphxConfig,\n\torgIdOrSlug: string,\n\tinvitationId: string,\n): Promise<{ success: boolean }> {\n\treturn callApi<{ success: boolean }>(config, `/orgs/${orgIdOrSlug}/invitations/${invitationId}`, {\n\t\tmethod: 'DELETE',\n\t})\n}\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\n/**\n * Check if user has a specific role or higher in the organization\n */\nexport function hasRole(membership: OrganizationMembership | null, minimumRole: OrgRole): boolean {\n\tif (!membership) return false\n\n\tconst roleHierarchy: OrgRole[] = [\n\t\t'viewer',\n\t\t'analytics',\n\t\t'developer',\n\t\t'billing',\n\t\t'admin',\n\t\t'super_admin',\n\t]\n\n\tconst userRoleIndex = roleHierarchy.indexOf(membership.role)\n\tconst requiredRoleIndex = roleHierarchy.indexOf(minimumRole)\n\n\treturn userRoleIndex >= requiredRoleIndex\n}\n\n/**\n * Check if user can manage members (invite, remove, change roles)\n */\nexport function canManageMembers(membership: OrganizationMembership | null): boolean {\n\treturn hasRole(membership, 'admin')\n}\n\n/**\n * Check if user can manage organization settings\n */\nexport function canManageSettings(membership: OrganizationMembership | null): boolean {\n\treturn hasRole(membership, 'admin')\n}\n\n/**\n * Check if user can delete the organization\n */\nexport function canDeleteOrganization(membership: OrganizationMembership | null): boolean {\n\treturn hasRole(membership, 'super_admin')\n}\n","/**\n * Permission Functions\n *\n * Pure functions for permission management — no hidden state.\n * Each function takes config as the first parameter.\n *\n * Uses REST API at /permissions/* for project-scoped operations.\n * Uses REST API at /orgs/{orgId}/members/{memberId}/permissions for member checks.\n *\n * Types are self-contained (not dependent on generated OpenAPI spec) because\n * the RBAC routes were added after the last spec generation.\n */\n\nimport { callApi, type SylphxConfig } from './config'\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * A permission definition within a project.\n *\n * Permissions are the atomic building blocks of RBAC roles.\n * They use colon-separated keys (e.g. \"org:members:read\", \"payroll:approve\").\n */\nexport interface Permission {\n\t/** Prefixed permission ID (e.g. \"perm_xxx\") */\n\tid: string\n\t/** Unique key within the project (e.g. \"org:members:read\") */\n\tkey: string\n\t/** Human-readable name */\n\tname: string\n\t/** Optional description */\n\tdescription: string | null\n\t/** Whether this is a system-defined permission (immutable) */\n\tisSystem: boolean\n\t/** ISO 8601 creation timestamp */\n\tcreatedAt: string\n}\n\n/**\n * Input for creating a custom permission.\n */\nexport interface CreatePermissionInput {\n\t/** Unique key — colon-separated lowercase segments (e.g. \"org:leave:approve\") */\n\tkey: string\n\t/** Human-readable name */\n\tname: string\n\t/** Optional description */\n\tdescription?: string\n}\n\n/**\n * Resolved permissions for a member, including their assigned role.\n */\nexport interface MemberPermissionsResult {\n\t/** Prefixed user ID of the member */\n\tmemberId: string\n\t/** Assigned role (null if no role assigned) */\n\trole: { key: string; name: string } | null\n\t/** Flattened, deduplicated permission keys from all assigned roles */\n\tpermissions: string[]\n}\n\n// ============================================================================\n// Permission CRUD (project-scoped, requires secretKey)\n// ============================================================================\n\n/**\n * List all permissions for the current project.\n *\n * Returns both system-defined and custom permissions.\n * Requires a secret key (server-side only).\n *\n * @example\n * ```typescript\n * const { permissions } = await listPermissions(config)\n * console.log(permissions.map(p => p.key))\n * // ['org:members:read', 'org:members:manage', 'payroll:view', ...]\n * ```\n */\nexport async function listPermissions(\n\tconfig: SylphxConfig,\n): Promise<{ permissions: Permission[] }> {\n\treturn callApi<{ permissions: Permission[] }>(config, '/permissions')\n}\n\n/**\n * Create a custom permission for the project.\n *\n * Permission keys must be colon-separated lowercase segments\n * (e.g. \"org:leave:approve\", \"payroll:run\").\n * Requires a secret key (server-side only).\n *\n * @example\n * ```typescript\n * const { permission } = await createPermission(config, {\n * key: 'payroll:approve',\n * name: 'Approve Payroll',\n * description: 'Can approve payroll runs for the organization',\n * })\n * ```\n */\nexport async function createPermission(\n\tconfig: SylphxConfig,\n\tinput: CreatePermissionInput,\n): Promise<{ permission: Permission }> {\n\treturn callApi<{ permission: Permission }>(config, '/permissions', {\n\t\tmethod: 'POST',\n\t\tbody: input,\n\t})\n}\n\n/**\n * Delete a custom permission by key.\n *\n * System permissions cannot be deleted.\n * Role-permission assignments are removed automatically via cascading delete.\n * Requires a secret key (server-side only).\n *\n * @example\n * ```typescript\n * const { success } = await deletePermission(config, 'payroll:approve')\n * ```\n */\nexport async function deletePermission(\n\tconfig: SylphxConfig,\n\tpermissionKey: string,\n): Promise<{ success: boolean }> {\n\treturn callApi<{ success: boolean }>(config, `/permissions/${permissionKey}`, {\n\t\tmethod: 'DELETE',\n\t})\n}\n\n// ============================================================================\n// Member Permissions (org-scoped, requires accessToken)\n// ============================================================================\n\n/**\n * Get a member's resolved permissions within an organization.\n *\n * Returns the flattened, deduplicated set of permission keys from all\n * roles assigned to the member. Also returns their current role info.\n * Requires the caller to be a member of the same organization.\n *\n * @example\n * ```typescript\n * const result = await getMemberPermissions(config, 'my-org', 'usr_abc123')\n * console.log(result.permissions)\n * // ['org:members:read', 'payroll:view', 'payroll:approve']\n * console.log(result.role)\n * // { key: 'hr_manager', name: 'HR Manager' }\n * ```\n */\nexport async function getMemberPermissions(\n\tconfig: SylphxConfig,\n\torgIdOrSlug: string,\n\tmemberId: string,\n): Promise<MemberPermissionsResult> {\n\treturn callApi<MemberPermissionsResult>(\n\t\tconfig,\n\t\t`/orgs/${orgIdOrSlug}/members/${memberId}/permissions`,\n\t)\n}\n\n// ============================================================================\n// Pure Helpers (no API calls — client-side permission checks)\n// ============================================================================\n\n/**\n * Check if a permission set includes a specific permission.\n *\n * Pure function — no API call. Use with permissions from JWT claims\n * (org_permissions) or from getMemberPermissions().\n *\n * @example\n * ```typescript\n * const permissions = ['org:members:read', 'payroll:view']\n * hasPermission(permissions, 'payroll:view') // true\n * hasPermission(permissions, 'payroll:approve') // false\n * ```\n */\nexport function hasPermission(permissions: string[], required: string): boolean {\n\treturn permissions.includes(required)\n}\n\n/**\n * Check if a permission set includes ANY of the required permissions.\n *\n * Pure function — no API call. Returns true if at least one of the\n * required permissions is present.\n *\n * @example\n * ```typescript\n * const permissions = ['org:members:read', 'payroll:view']\n * hasAnyPermission(permissions, ['payroll:view', 'payroll:approve']) // true\n * hasAnyPermission(permissions, ['admin:full', 'super:admin']) // false\n * ```\n */\nexport function hasAnyPermission(permissions: string[], required: string[]): boolean {\n\treturn required.some((perm) => permissions.includes(perm))\n}\n\n/**\n * Check if a permission set includes ALL of the required permissions.\n *\n * Pure function — no API call. Returns true only if every required\n * permission is present.\n *\n * @example\n * ```typescript\n * const permissions = ['org:members:read', 'payroll:view', 'payroll:approve']\n * hasAllPermissions(permissions, ['payroll:view', 'payroll:approve']) // true\n * hasAllPermissions(permissions, ['payroll:view', 'admin:full']) // false\n * ```\n */\nexport function hasAllPermissions(permissions: string[], required: string[]): boolean {\n\treturn required.every((perm) => permissions.includes(perm))\n}\n","/**\n * Role Functions\n *\n * Pure functions for role management — no hidden state.\n * Each function takes config as the first parameter.\n *\n * Uses REST API at /roles/* for project-scoped operations.\n * Uses REST API at /orgs/{orgId}/members/{memberId}/assign-role for assignment.\n *\n * Types are self-contained (not dependent on generated OpenAPI spec) because\n * the RBAC routes were added after the last spec generation.\n */\n\nimport { callApi, type SylphxConfig } from './config'\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * A role definition within a project.\n *\n * Roles bundle permissions into named groups that can be assigned to\n * organization members (e.g. \"HR Manager\", \"Payroll Admin\").\n */\nexport interface Role {\n\t/** Prefixed role ID (e.g. \"role_xxx\") */\n\tid: string\n\t/** Unique key within the project (e.g. \"hr_manager\") */\n\tkey: string\n\t/** Human-readable name */\n\tname: string\n\t/** Optional description */\n\tdescription: string | null\n\t/** Whether this is a system-defined role (metadata immutable) */\n\tisSystem: boolean\n\t/** Whether this role is automatically assigned to new org members */\n\tisDefault: boolean\n\t/** Display order (lower = higher priority) */\n\tsortOrder: number\n\t/** Permission keys assigned to this role */\n\tpermissions: string[]\n\t/** ISO 8601 creation timestamp */\n\tcreatedAt: string\n\t/** ISO 8601 update timestamp (present on roles route response) */\n\tupdatedAt?: string\n}\n\n/**\n * Input for creating a custom role.\n */\nexport interface CreateRoleInput {\n\t/** Unique key — lowercase alphanumeric with underscores (e.g. \"hr_manager\") */\n\tkey: string\n\t/** Human-readable name */\n\tname: string\n\t/** Optional description */\n\tdescription?: string\n\t/** Permission keys to assign to this role */\n\tpermissions?: string[]\n\t/** Whether to auto-assign to new org members */\n\tisDefault?: boolean\n\t/** Display order (lower = higher priority) */\n\tsortOrder?: number\n}\n\n/**\n * Input for updating an existing role.\n *\n * System role metadata (name, description) is immutable, but their\n * permissions can be changed.\n */\nexport interface UpdateRoleInput {\n\t/** Human-readable name (ignored for system roles) */\n\tname?: string\n\t/** Description (ignored for system roles) */\n\tdescription?: string | null\n\t/** Permission keys to assign (replaces existing) */\n\tpermissions?: string[]\n\t/** Whether to auto-assign to new org members */\n\tisDefault?: boolean\n\t/** Display order */\n\tsortOrder?: number\n}\n\n// ============================================================================\n// Role CRUD (project-scoped, requires secretKey)\n// ============================================================================\n\n/**\n * List all roles for the current project.\n *\n * Returns both system-defined and custom roles, each with their\n * assigned permission keys. Requires a secret key (server-side only).\n *\n * @example\n * ```typescript\n * const { roles } = await listRoles(config)\n * for (const role of roles) {\n * console.log(`${role.name}: ${role.permissions.join(', ')}`)\n * }\n * ```\n */\nexport async function listRoles(config: SylphxConfig): Promise<{ roles: Role[] }> {\n\treturn callApi<{ roles: Role[] }>(config, '/roles')\n}\n\n/**\n * Get a single role by key, including its assigned permission keys.\n *\n * Requires a secret key (server-side only).\n *\n * @example\n * ```typescript\n * const { role } = await getRole(config, 'hr_manager')\n * console.log(role.permissions)\n * // ['org:members:read', 'payroll:view', 'payroll:approve']\n * ```\n */\nexport async function getRole(config: SylphxConfig, roleKey: string): Promise<{ role: Role }> {\n\treturn callApi<{ role: Role }>(config, `/roles/${roleKey}`)\n}\n\n/**\n * Create a custom role with optional permission assignments.\n *\n * Role keys must be lowercase alphanumeric with underscores\n * (e.g. \"hr_manager\", \"payroll_admin\").\n * Requires a secret key (server-side only).\n *\n * @example\n * ```typescript\n * const { role } = await createRole(config, {\n * key: 'hr_manager',\n * name: 'HR Manager',\n * description: 'Can manage employees and approve leave',\n * permissions: ['org:members:read', 'leave:approve', 'payroll:view'],\n * })\n * ```\n */\nexport async function createRole(\n\tconfig: SylphxConfig,\n\tinput: CreateRoleInput,\n): Promise<{ role: Role }> {\n\t// Map SDK field names to API field names\n\tconst body: Record<string, unknown> = {\n\t\tkey: input.key,\n\t\tname: input.name,\n\t}\n\tif (input.description !== undefined) body.description = input.description\n\tif (input.permissions !== undefined) body.permissionKeys = input.permissions\n\tif (input.isDefault !== undefined) body.isDefault = input.isDefault\n\tif (input.sortOrder !== undefined) body.sortOrder = input.sortOrder\n\n\treturn callApi<{ role: Role }>(config, '/roles', {\n\t\tmethod: 'POST',\n\t\tbody,\n\t})\n}\n\n/**\n * Update a role's metadata and/or permission assignments.\n *\n * System role metadata (name, description) is immutable, but their\n * permissions can be changed. Passing `permissions` replaces the\n * entire permission set for the role.\n * Requires a secret key (server-side only).\n *\n * @example\n * ```typescript\n * const { role } = await updateRole(config, 'hr_manager', {\n * permissions: ['org:members:read', 'org:members:manage', 'leave:approve'],\n * })\n * ```\n */\nexport async function updateRole(\n\tconfig: SylphxConfig,\n\troleKey: string,\n\tinput: UpdateRoleInput,\n): Promise<{ role: Role }> {\n\t// Map SDK field names to API field names\n\tconst body: Record<string, unknown> = {}\n\tif (input.name !== undefined) body.name = input.name\n\tif (input.description !== undefined) body.description = input.description\n\tif (input.permissions !== undefined) body.permissionKeys = input.permissions\n\tif (input.isDefault !== undefined) body.isDefault = input.isDefault\n\tif (input.sortOrder !== undefined) body.sortOrder = input.sortOrder\n\n\treturn callApi<{ role: Role }>(config, `/roles/${roleKey}`, {\n\t\tmethod: 'PUT',\n\t\tbody,\n\t})\n}\n\n/**\n * Delete a custom role by key.\n *\n * System roles cannot be deleted. Roles with active member assignments\n * cannot be deleted — reassign members first.\n * Requires a secret key (server-side only).\n *\n * @example\n * ```typescript\n * const { success } = await deleteRole(config, 'hr_manager')\n * ```\n */\nexport async function deleteRole(\n\tconfig: SylphxConfig,\n\troleKey: string,\n): Promise<{ success: boolean }> {\n\treturn callApi<{ success: boolean }>(config, `/roles/${roleKey}`, {\n\t\tmethod: 'DELETE',\n\t})\n}\n\n// ============================================================================\n// Member Role Assignment (org-scoped, requires accessToken)\n// ============================================================================\n\n/**\n * Assign an RBAC role to an organization member.\n *\n * Replaces any existing role assignment (single-role mode).\n * Requires admin access to the organization.\n *\n * @example\n * ```typescript\n * const { success } = await assignMemberRole(config, 'my-org', 'usr_abc123', 'hr_manager')\n * ```\n */\nexport async function assignMemberRole(\n\tconfig: SylphxConfig,\n\torgIdOrSlug: string,\n\tmemberId: string,\n\troleKey: string,\n): Promise<{ success: boolean }> {\n\treturn callApi<{ success: boolean }>(\n\t\tconfig,\n\t\t`/orgs/${orgIdOrSlug}/members/${memberId}/assign-role`,\n\t\t{\n\t\t\tmethod: 'PUT',\n\t\t\tbody: { roleKey },\n\t\t},\n\t)\n}\n","/**\n * Secrets SDK\n *\n * Secure secrets management for applications.\n * Secrets are encrypted at rest with AES-256-GCM.\n *\n * @example\n * ```typescript\n * import { createConfig, getSecret, getSecrets, listSecretKeys } from '@sylphx/sdk'\n *\n * const config = createConfig({\n * secretKey: process.env.SYLPHX_SECRET_KEY!,\n * })\n *\n * // Get a single secret\n * const dbUrl = await getSecret(config, { key: 'DATABASE_URL' })\n * console.log(dbUrl.value) // postgres://...\n *\n * // Get multiple secrets at once\n * const secrets = await getSecrets(config, {\n * keys: ['DATABASE_URL', 'API_KEY', 'JWT_SECRET']\n * })\n * console.log(secrets.DATABASE_URL) // postgres://...\n *\n * // List all secret keys (without values)\n * const keys = await listSecretKeys(config)\n * keys.forEach(k => console.log(k.key, k.description))\n * ```\n */\n\nimport { callApi, type SylphxConfig } from './config'\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface GetSecretInput {\n\t/** Secret key (uppercase, underscores allowed) */\n\tkey: string\n\t/** Optional environment ID override */\n\tenvironmentId?: string\n}\n\nexport interface GetSecretResult {\n\t/** Secret key */\n\tkey: string\n\t/** Decrypted secret value */\n\tvalue: string\n\t/** Version number */\n\tversion: string\n}\n\nexport interface GetSecretsInput {\n\t/** Array of secret keys to retrieve */\n\tkeys: string[]\n\t/** Optional environment ID override */\n\tenvironmentId?: string\n}\n\n/** Map of key -> decrypted value */\nexport type GetSecretsResult = Record<string, string>\n\nexport interface ListSecretKeysInput {\n\t/** Optional environment ID filter */\n\tenvironmentId?: string\n}\n\nexport interface SecretKeyInfo {\n\t/** Secret key name */\n\tkey: string\n\t/** Human-readable description */\n\tdescription: string | null\n\t/** Current version */\n\tversion: string\n\t/** Whether this is environment-specific */\n\tisEnvironmentSpecific: boolean\n}\n\n// ============================================================================\n// Functions\n// ============================================================================\n\n/**\n * Get a single secret value by key.\n *\n * @param config - SDK configuration\n * @param input - Secret key and optional environment ID\n * @returns Decrypted secret value\n * @throws Error if secret not found or access denied\n *\n * @example\n * ```typescript\n * const secret = await getSecret(config, { key: 'DATABASE_URL' })\n * const dbConnection = createPool(secret.value)\n * ```\n */\nexport async function getSecret(\n\tconfig: SylphxConfig,\n\tinput: GetSecretInput,\n): Promise<GetSecretResult> {\n\treturn callApi<GetSecretResult>(config, '/secrets/get', {\n\t\tmethod: 'POST',\n\t\tbody: {\n\t\t\tkey: input.key,\n\t\t\tenvironmentId: input.environmentId,\n\t\t},\n\t})\n}\n\n/**\n * Get multiple secrets at once.\n *\n * More efficient than multiple getSecret calls.\n *\n * @param config - SDK configuration\n * @param input - Array of secret keys\n * @returns Map of key -> decrypted value\n *\n * @example\n * ```typescript\n * const secrets = await getSecrets(config, {\n * keys: ['DATABASE_URL', 'REDIS_URL', 'JWT_SECRET']\n * })\n *\n * const db = createPool(secrets.DATABASE_URL)\n * const redis = createClient(secrets.REDIS_URL)\n * ```\n */\nexport async function getSecrets(\n\tconfig: SylphxConfig,\n\tinput: GetSecretsInput,\n): Promise<GetSecretsResult> {\n\treturn callApi<GetSecretsResult>(config, '/secrets/getMany', {\n\t\tmethod: 'POST',\n\t\tbody: {\n\t\t\tkeys: input.keys,\n\t\t\tenvironmentId: input.environmentId,\n\t\t},\n\t})\n}\n\n/**\n * List all secret keys (without values).\n *\n * Useful for showing available secrets in UI or debugging.\n *\n * @param config - SDK configuration\n * @param input - Optional environment filter\n * @returns Array of secret key info\n *\n * @example\n * ```typescript\n * const keys = await listSecretKeys(config)\n * console.log('Available secrets:')\n * keys.forEach(k => console.log(` ${k.key}: ${k.description}`))\n * ```\n */\nexport async function listSecretKeys(\n\tconfig: SylphxConfig,\n\tinput: ListSecretKeysInput = {},\n): Promise<SecretKeyInfo[]> {\n\treturn callApi<SecretKeyInfo[]>(config, '/secrets/listKeys', {\n\t\tmethod: 'GET',\n\t\tquery: input.environmentId ? { environmentId: input.environmentId } : undefined,\n\t})\n}\n\n/**\n * Check if a secret exists without retrieving its value.\n *\n * @param config - SDK configuration\n * @param key - Secret key to check\n * @returns true if the secret exists\n *\n * @example\n * ```typescript\n * if (await hasSecret(config, 'STRIPE_SECRET_KEY')) {\n * // Stripe is configured, enable payment features\n * }\n * ```\n */\nexport async function hasSecret(config: SylphxConfig, key: string): Promise<boolean> {\n\ttry {\n\t\tconst keys = await listSecretKeys(config)\n\t\treturn keys.some((k) => k.key === key)\n\t} catch {\n\t\treturn false\n\t}\n}\n\n/**\n * Get all secrets for an environment as an object.\n *\n * Useful for loading all secrets into process.env at startup.\n *\n * @param config - SDK configuration\n * @param environmentId - Optional environment ID\n * @returns Object with all secrets\n *\n * @example\n * ```typescript\n * // Load all secrets into process.env at app startup\n * const secrets = await getAllSecrets(config)\n * Object.assign(process.env, secrets)\n * ```\n */\nexport async function getAllSecrets(\n\tconfig: SylphxConfig,\n\tenvironmentId?: string,\n): Promise<GetSecretsResult> {\n\tconst keys = await listSecretKeys(config, { environmentId })\n\tif (keys.length === 0) {\n\t\treturn {}\n\t}\n\treturn getSecrets(config, { keys: keys.map((k) => k.key), environmentId })\n}\n","/**\n * Search SDK\n *\n * State-of-the-art search with full-text, semantic, and hybrid modes.\n * Powered by PostgreSQL tsvector + pgvector.\n *\n * @example\n * ```typescript\n * import { createConfig, indexDocument, search, batchIndex } from '@sylphx/sdk'\n *\n * const config = createConfig({\n * secretKey: process.env.SYLPHX_SECRET_KEY!,\n * })\n *\n * // Index a document\n * await indexDocument(config, {\n * content: 'How to reset your password...',\n * title: 'Password Reset Guide',\n * namespace: 'help-articles',\n * category: 'account',\n * tags: ['password', 'security'],\n * })\n *\n * // Search (hybrid mode by default)\n * const results = await search(config, {\n * query: 'forgot my login credentials',\n * namespace: 'help-articles',\n * searchType: 'hybrid',\n * highlight: true,\n * })\n *\n * results.results.forEach(r => console.log(r.title, r.score, r.highlight))\n * ```\n */\n\nimport { callApi, type SylphxConfig } from './config'\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface IndexDocumentInput {\n\t/** Document title (weighted higher in search) */\n\ttitle?: string\n\t/** Document content to index */\n\tcontent: string\n\t/** Namespace for data isolation (e.g., 'products', 'articles') */\n\tnamespace?: string\n\t/** External document ID (your system's ID) */\n\texternalId?: string\n\t/** URL or path */\n\turl?: string\n\t/** Searchable metadata */\n\tmetadata?: Record<string, unknown>\n\t/** Category facet for filtering */\n\tcategory?: string\n\t/** Type facet for filtering */\n\ttype?: string\n\t/** Tags facet for filtering */\n\ttags?: string[]\n\t/** Language for full-text search (default: english) */\n\tlanguage?: string\n\t/** Skip embedding generation (for keyword-only search) */\n\tskipEmbedding?: boolean\n\t/** Embedding model to use */\n\tembeddingModel?: string\n}\n\nexport interface IndexDocumentResult {\n\t/** Generated document ID */\n\tid: string\n\t/** External ID if provided */\n\texternalId: string | null\n\t/** Namespace */\n\tnamespace: string\n}\n\nexport interface BatchIndexInput {\n\t/** Documents to index (max 100) */\n\tdocuments: Array<{\n\t\ttitle?: string\n\t\tcontent: string\n\t\texternalId?: string\n\t\turl?: string\n\t\tmetadata?: Record<string, unknown>\n\t\tcategory?: string\n\t\ttype?: string\n\t\ttags?: string[]\n\t}>\n\t/** Namespace for all documents */\n\tnamespace?: string\n\t/** Language for full-text search */\n\tlanguage?: string\n\t/** Skip embedding generation */\n\tskipEmbedding?: boolean\n\t/** Embedding model to use */\n\tembeddingModel?: string\n}\n\nexport interface BatchIndexResult {\n\t/** Number of documents indexed */\n\tindexed: number\n\t/** Generated document IDs */\n\tids: string[]\n}\n\nexport type SearchType = 'keyword' | 'semantic' | 'hybrid'\n\nexport interface SearchInput {\n\t/** Search query text */\n\tquery: string\n\t/** Namespace to search within */\n\tnamespace?: string\n\t/** Search type: keyword, semantic, or hybrid (default) */\n\tsearchType?: SearchType\n\t/** Maximum results to return (default: 10, max: 100) */\n\tlimit?: number\n\t/** Offset for pagination */\n\toffset?: number\n\t/** Minimum similarity threshold (0-1) for semantic search */\n\tminSimilarity?: number\n\t/** Enable typo tolerance (default: true) */\n\ttypoTolerance?: boolean\n\t/** Language for full-text search */\n\tlanguage?: string\n\t/** Facet filters */\n\tfilters?: {\n\t\tcategory?: string\n\t\ttype?: string\n\t\ttags?: string[]\n\t\tmetadata?: Record<string, unknown>\n\t}\n\t/** Include highlighted snippets (default: true) */\n\thighlight?: boolean\n\t/** Embedding model for semantic search */\n\tembeddingModel?: string\n\t/** Track this query for analytics (default: true) */\n\ttrackQuery?: boolean\n\t/** Session ID for analytics */\n\tsessionId?: string\n\t/** User ID for analytics */\n\tuserId?: string\n}\n\nexport interface SearchResultItem {\n\t/** Document ID */\n\tid: string\n\t/** External ID if set */\n\texternalId: string | null\n\t/** Document title */\n\ttitle: string | null\n\t/** Document content */\n\tcontent: string\n\t/** Document URL */\n\turl: string | null\n\t/** Document metadata */\n\tmetadata: Record<string, unknown> | null\n\t/** Category facet */\n\tcategory: string | null\n\t/** Type facet */\n\ttype: string | null\n\t/** Tags facet */\n\ttags: string[] | null\n\t/** Combined score */\n\tscore: number\n\t/** Keyword search score (if hybrid) */\n\tkeywordScore?: number\n\t/** Semantic search score (if hybrid) */\n\tsemanticScore?: number\n\t/** Highlighted snippet (if enabled) */\n\thighlight?: string\n}\n\nexport interface SearchResponse {\n\t/** Search results */\n\tresults: SearchResultItem[]\n\t/** Total results found */\n\ttotal: number\n\t/** Original query */\n\tquery: string\n\t/** Search type used */\n\tsearchType: SearchType\n\t/** Query processing time in ms */\n\tlatencyMs: number\n}\n\nexport interface GetFacetsInput {\n\t/** Namespace to get facets from */\n\tnamespace?: string\n\t/** Facets to retrieve */\n\tfacets?: Array<'category' | 'type' | 'tags'>\n\t/** Filter facets by category or type */\n\tfilters?: {\n\t\tcategory?: string\n\t\ttype?: string\n\t}\n}\n\nexport interface FacetsResponse {\n\tfacets: {\n\t\tcategory?: Array<{ value: string; count: number }>\n\t\ttype?: Array<{ value: string; count: number }>\n\t\ttags?: Array<{ value: string; count: number }>\n\t}\n}\n\nexport interface DeleteDocumentInput {\n\t/** Document ID to delete */\n\tid?: string\n\t/** Or delete by external ID */\n\texternalId?: string\n\t/** Namespace (required if using externalId) */\n\tnamespace?: string\n}\n\nexport interface UpsertDocumentInput extends IndexDocumentInput {\n\t/** External ID is required for upsert */\n\texternalId: string\n}\n\nexport interface UpsertDocumentResult extends IndexDocumentResult {\n\t/** Whether the document was created (true) or updated (false) */\n\tcreated: boolean\n}\n\nexport interface SearchStatsResult {\n\t/** Total documents indexed */\n\ttotalDocuments: number\n\t/** Documents with embeddings */\n\tdocumentsWithEmbedding: number\n\t/** Documents by namespace */\n\tbyNamespace: Array<{ namespace: string; count: number }>\n}\n\nexport interface TrackClickInput {\n\t/** Search query ID */\n\tqueryId: string\n\t/** Clicked document ID */\n\tdocumentId: string\n\t/** Position in results (1-indexed) */\n\tposition: number\n}\n\n// ============================================================================\n// Functions\n// ============================================================================\n\n/**\n * Index a document for search.\n *\n * Automatically generates tsvector for full-text search and\n * optional embedding for semantic search.\n *\n * @param config - SDK configuration\n * @param input - Document to index\n * @returns Indexed document info\n *\n * @example\n * ```typescript\n * const result = await indexDocument(config, {\n * title: 'Getting Started Guide',\n * content: 'Welcome to our platform...',\n * namespace: 'docs',\n * category: 'tutorials',\n * tags: ['beginner', 'setup'],\n * })\n * ```\n */\nexport async function indexDocument(\n\tconfig: SylphxConfig,\n\tinput: IndexDocumentInput,\n): Promise<IndexDocumentResult> {\n\treturn callApi<IndexDocumentResult>(config, '/search/index', {\n\t\tmethod: 'POST',\n\t\tbody: {\n\t\t\ttitle: input.title,\n\t\t\tcontent: input.content,\n\t\t\tnamespace: input.namespace ?? 'default',\n\t\t\texternalId: input.externalId,\n\t\t\turl: input.url,\n\t\t\tmetadata: input.metadata,\n\t\t\tcategory: input.category,\n\t\t\ttype: input.type,\n\t\t\ttags: input.tags,\n\t\t\tlanguage: input.language ?? 'english',\n\t\t\tskipEmbedding: input.skipEmbedding ?? false,\n\t\t\tembeddingModel: input.embeddingModel ?? 'openai/text-embedding-3-small',\n\t\t},\n\t})\n}\n\n/**\n * Index multiple documents in a single batch.\n *\n * More efficient than multiple indexDocument calls.\n * Max 100 documents per batch.\n *\n * @param config - SDK configuration\n * @param input - Documents to index\n * @returns Batch index result\n *\n * @example\n * ```typescript\n * const result = await batchIndex(config, {\n * namespace: 'products',\n * documents: products.map(p => ({\n * title: p.name,\n * content: p.description,\n * externalId: p.id,\n * category: p.category,\n * }))\n * })\n * console.log(`Indexed ${result.indexed} products`)\n * ```\n */\nexport async function batchIndex(\n\tconfig: SylphxConfig,\n\tinput: BatchIndexInput,\n): Promise<BatchIndexResult> {\n\treturn callApi<BatchIndexResult>(config, '/search/batchIndex', {\n\t\tmethod: 'POST',\n\t\tbody: {\n\t\t\tdocuments: input.documents,\n\t\t\tnamespace: input.namespace ?? 'default',\n\t\t\tlanguage: input.language ?? 'english',\n\t\t\tskipEmbedding: input.skipEmbedding ?? false,\n\t\t\tembeddingModel: input.embeddingModel ?? 'openai/text-embedding-3-small',\n\t\t},\n\t})\n}\n\n/**\n * Search documents.\n *\n * Supports three search modes:\n * - `keyword`: Full-text search with typo tolerance\n * - `semantic`: AI-powered vector search\n * - `hybrid`: Combined ranking (default, best results)\n *\n * @param config - SDK configuration\n * @param input - Search query and options\n * @returns Search results with scores\n *\n * @example\n * ```typescript\n * // Hybrid search (recommended)\n * const results = await search(config, {\n * query: 'how to change email address',\n * namespace: 'help',\n * searchType: 'hybrid',\n * highlight: true,\n * })\n *\n * results.results.forEach(r => {\n * console.log(`[${r.score.toFixed(3)}] ${r.title}`)\n * console.log(r.highlight)\n * })\n * ```\n */\nexport async function search(config: SylphxConfig, input: SearchInput): Promise<SearchResponse> {\n\treturn callApi<SearchResponse>(config, '/search/search', {\n\t\tmethod: 'POST',\n\t\tbody: {\n\t\t\tquery: input.query,\n\t\t\tnamespace: input.namespace ?? 'default',\n\t\t\tsearchType: input.searchType ?? 'hybrid',\n\t\t\tlimit: input.limit ?? 10,\n\t\t\toffset: input.offset ?? 0,\n\t\t\tminSimilarity: input.minSimilarity,\n\t\t\ttypoTolerance: input.typoTolerance ?? true,\n\t\t\tlanguage: input.language ?? 'english',\n\t\t\tfilters: input.filters,\n\t\t\thighlight: input.highlight ?? true,\n\t\t\tembeddingModel: input.embeddingModel ?? 'openai/text-embedding-3-small',\n\t\t\ttrackQuery: input.trackQuery ?? true,\n\t\t\tsessionId: input.sessionId,\n\t\t\tuserId: input.userId,\n\t\t},\n\t})\n}\n\n/**\n * Get facet counts for filtering.\n *\n * Returns counts of documents by category, type, and tags.\n *\n * @param config - SDK configuration\n * @param input - Facet options\n * @returns Facet counts\n *\n * @example\n * ```typescript\n * const facets = await getFacets(config, {\n * namespace: 'products',\n * facets: ['category', 'type'],\n * })\n *\n * facets.facets.category?.forEach(f => {\n * console.log(`${f.value}: ${f.count} products`)\n * })\n * ```\n */\nexport async function getFacets(\n\tconfig: SylphxConfig,\n\tinput: GetFacetsInput = {},\n): Promise<FacetsResponse> {\n\treturn callApi<FacetsResponse>(config, '/search/getFacets', {\n\t\tmethod: 'POST',\n\t\tbody: {\n\t\t\tnamespace: input.namespace ?? 'default',\n\t\t\tfacets: input.facets ?? ['category', 'type'],\n\t\t\tfilters: input.filters,\n\t\t},\n\t})\n}\n\n/**\n * Delete a document from the search index.\n *\n * @param config - SDK configuration\n * @param input - Document ID or external ID\n * @returns Deletion result\n *\n * @example\n * ```typescript\n * // Delete by internal ID\n * await deleteDocument(config, { id: 'doc-uuid-123' })\n *\n * // Delete by external ID\n * await deleteDocument(config, {\n * externalId: 'product-456',\n * namespace: 'products'\n * })\n * ```\n */\nexport async function deleteDocument(\n\tconfig: SylphxConfig,\n\tinput: DeleteDocumentInput,\n): Promise<{ deleted: number }> {\n\treturn callApi<{ deleted: number }>(config, '/search/delete', {\n\t\tmethod: 'POST',\n\t\tbody: {\n\t\t\tid: input.id,\n\t\t\texternalId: input.externalId,\n\t\t\tnamespace: input.namespace ?? 'default',\n\t\t},\n\t})\n}\n\n/**\n * Upsert a document (insert or update by externalId).\n *\n * If a document with the same externalId exists, it will be replaced.\n * Otherwise, a new document is created.\n *\n * @param config - SDK configuration\n * @param input - Document to upsert (externalId required)\n * @returns Upsert result\n *\n * @example\n * ```typescript\n * const result = await upsertDocument(config, {\n * externalId: 'product-123',\n * title: 'Updated Product Name',\n * content: 'New description...',\n * namespace: 'products',\n * })\n * console.log(result.created ? 'Created' : 'Updated')\n * ```\n */\nexport async function upsertDocument(\n\tconfig: SylphxConfig,\n\tinput: UpsertDocumentInput,\n): Promise<UpsertDocumentResult> {\n\treturn callApi<UpsertDocumentResult>(config, '/search/upsert', {\n\t\tmethod: 'POST',\n\t\tbody: {\n\t\t\ttitle: input.title,\n\t\t\tcontent: input.content,\n\t\t\tnamespace: input.namespace ?? 'default',\n\t\t\texternalId: input.externalId,\n\t\t\turl: input.url,\n\t\t\tmetadata: input.metadata,\n\t\t\tcategory: input.category,\n\t\t\ttype: input.type,\n\t\t\ttags: input.tags,\n\t\t\tlanguage: input.language ?? 'english',\n\t\t\tskipEmbedding: input.skipEmbedding ?? false,\n\t\t\tembeddingModel: input.embeddingModel ?? 'openai/text-embedding-3-small',\n\t\t},\n\t})\n}\n\n/**\n * Get search index statistics.\n *\n * @param config - SDK configuration\n * @param namespace - Optional namespace filter\n * @returns Index statistics\n *\n * @example\n * ```typescript\n * const stats = await getSearchStats(config)\n * console.log(`Total docs: ${stats.totalDocuments}`)\n * console.log(`With embeddings: ${stats.documentsWithEmbedding}`)\n * ```\n */\nexport async function getSearchStats(\n\tconfig: SylphxConfig,\n\tnamespace?: string,\n): Promise<SearchStatsResult> {\n\treturn callApi<SearchStatsResult>(config, '/search/getStats', {\n\t\tmethod: 'POST',\n\t\tbody: { namespace },\n\t})\n}\n\n/**\n * Track a click on a search result.\n *\n * Use this to improve search quality over time.\n *\n * @param config - SDK configuration\n * @param input - Click information\n * @returns Success status\n *\n * @example\n * ```typescript\n * await trackClick(config, {\n * queryId: searchResponse.queryId,\n * documentId: clickedResult.id,\n * position: 3,\n * })\n * ```\n */\nexport async function trackClick(\n\tconfig: SylphxConfig,\n\tinput: TrackClickInput,\n): Promise<{ success: boolean }> {\n\treturn callApi<{ success: boolean }>(config, '/search/trackClick', {\n\t\tmethod: 'POST',\n\t\tbody: input,\n\t})\n}\n","/**\n * Database Functions\n *\n * Pure functions for retrieving Platform-provisioned database connection strings.\n * Server-side only (requires secret key `sk_*`).\n *\n * The Platform provisions a PostgreSQL database for each app and encrypts\n * the connection string. These functions retrieve and decrypt the connection\n * string at startup, so your app never needs to store it.\n *\n * @example\n * ```ts\n * import { createConfig, getDatabaseConnectionString } from '@sylphx/sdk'\n *\n * const config = createConfig({ secretKey: process.env.SYLPHX_SECRET_KEY! })\n * const { connectionString } = await getDatabaseConnectionString(config)\n *\n * const pool = new Pool({ connectionString })\n * ```\n */\n\nimport { callApi, type SylphxConfig } from './config'\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport type DatabaseStatus =\n\t| 'provisioning'\n\t| 'ready'\n\t| 'suspended'\n\t| 'failed'\n\t| 'deleted'\n\t| 'not_provisioned'\n\nexport interface DatabaseConnectionInfo {\n\t/** Decrypted PostgreSQL connection string */\n\tconnectionString: string\n\t/** Database name */\n\tdatabaseName: string\n\t/** Database role/user name */\n\troleName: string | null\n\t/** Database provisioning status */\n\tstatus: Exclude<DatabaseStatus, 'not_provisioned'>\n}\n\nexport interface DatabaseStatusInfo {\n\t/** Current database status */\n\tstatus: DatabaseStatus\n\t/** Provisioned region */\n\tregion: string | null\n\t/** PostgreSQL major version */\n\tpgVersion: number | null\n\t/** Database name */\n\tdatabaseName: string | null\n}\n\n// ============================================================================\n// Functions\n// ============================================================================\n\n/**\n * Get the provisioned PostgreSQL connection string for this app.\n *\n * Requires secret key authentication (server-side only).\n * The connection string is decrypted on the Platform and returned in plaintext.\n *\n * @throws `NOT_FOUND` if no database has been provisioned for this app\n * @throws `UNPROCESSABLE_ENTITY` if database is not yet ready\n *\n * @example\n * ```ts\n * const { connectionString } = await getDatabaseConnectionString(config)\n * const pool = new Pool({ connectionString })\n * ```\n */\nexport async function getDatabaseConnectionString(\n\tconfig: SylphxConfig,\n): Promise<DatabaseConnectionInfo> {\n\treturn callApi<DatabaseConnectionInfo>(config, '/sdk/database/connection-string', {\n\t\tmethod: 'GET',\n\t})\n}\n\n/**\n * Get the current status of the provisioned database.\n *\n * Use this to check if the database is ready before attempting to connect.\n * Requires secret key authentication (server-side only).\n *\n * @example\n * ```ts\n * const { status } = await getDatabaseStatus(config)\n * if (status === 'ready') {\n * // Connect to database\n * }\n * ```\n */\nexport async function getDatabaseStatus(config: SylphxConfig): Promise<DatabaseStatusInfo> {\n\treturn callApi<DatabaseStatusInfo>(config, '/sdk/database/status', {\n\t\tmethod: 'GET',\n\t})\n}\n","/**\n * KV (Key-Value Store) Functions\n *\n * Pure functions for distributed key-value storage backed by Redis.\n * Supports strings, hashes, lists, sorted sets, and built-in rate limiting.\n *\n * Keys are automatically namespaced per app, so no key collisions occur\n * between different apps on the same Platform.\n *\n * @example\n * ```ts\n * import { createConfig, kvSet, kvGet, kvDelete } from '@sylphx/sdk'\n *\n * const config = createConfig({ secretKey: process.env.SYLPHX_SECRET_KEY! })\n *\n * // Basic key-value operations\n * await kvSet(config, { key: 'user:123', value: { name: 'Alice' }, ex: 3600 })\n * const user = await kvGet(config, 'user:123')\n * await kvDelete(config, 'user:123')\n * ```\n */\n\nimport { callApi, type SylphxConfig } from './config'\nimport type { KvRateLimitResult, KvSetOptions, KvZMember } from './kv-types'\n\n// Re-export shared types\nexport type { KvRateLimitResult, KvSetOptions, KvZMember } from './kv-types'\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface KvSetRequest extends KvSetOptions {\n\t/** Key to store */\n\tkey: string\n\t/** Value to store (any JSON-serializable value) */\n\tvalue: unknown\n}\n\nexport interface KvMsetRequest {\n\t/** Key-value pairs to set in a single atomic operation */\n\tentries: Array<{ key: string; value: unknown }>\n}\n\nexport interface KvMgetRequest {\n\t/** Keys to retrieve */\n\tkeys: string[]\n}\n\nexport interface KvHsetRequest {\n\t/** Hash key */\n\tkey: string\n\t/** Field-value pairs to set on the hash */\n\tfields: Record<string, unknown>\n}\n\nexport interface KvHgetRequest {\n\t/** Hash key */\n\tkey: string\n\t/** Field to get */\n\tfield: string\n}\n\nexport interface KvHgetallRequest {\n\t/** Hash key */\n\tkey: string\n}\n\nexport interface KvLpushRequest {\n\t/** List key */\n\tkey: string\n\t/** Values to prepend (left push) */\n\tvalues: unknown[]\n}\n\nexport interface KvLrangeRequest {\n\t/** List key */\n\tkey: string\n\t/** Start index (0-based, negative counts from end) */\n\tstart: number\n\t/** Stop index (inclusive, negative counts from end) */\n\tstop: number\n}\n\nexport interface KvZaddRequest {\n\t/** Sorted set key */\n\tkey: string\n\t/** Members with scores to add */\n\tmembers: KvZMember[]\n}\n\nexport interface KvZrangeRequest {\n\t/** Sorted set key */\n\tkey: string\n\t/** Start index or score */\n\tstart: number | string\n\t/** Stop index or score */\n\tstop: number | string\n\t/** Return scores alongside members */\n\twithScores?: boolean\n\t/** Reverse order */\n\trev?: boolean\n\t/** Treat start/stop as scores (BYSCORE) */\n\tbyScore?: boolean\n}\n\nexport interface KvIncrRequest {\n\t/** Key to increment */\n\tkey: string\n\t/** Amount to increment by (default: 1) */\n\tby?: number\n}\n\nexport interface KvExpireRequest {\n\t/** Key to set expiry on */\n\tkey: string\n\t/** TTL in seconds */\n\tseconds: number\n}\n\nexport interface KvRateLimitRequest {\n\t/** Rate limit identifier (e.g., userId, IP) */\n\tidentifier: string\n\t/** Maximum requests allowed in the window */\n\tlimit: number\n\t/** Window duration in seconds */\n\twindow: number\n}\n\n// ============================================================================\n// Functions — Basic Operations\n// ============================================================================\n\n/**\n * Set a key-value pair, with optional TTL and conditional flags.\n *\n * @example\n * ```ts\n * // Simple set\n * await kvSet(config, { key: 'session:abc', value: { userId: '123' }, ex: 86400 })\n *\n * // Set only if not exists (NX)\n * await kvSet(config, { key: 'lock:task', value: '1', ex: 30, nx: true })\n * ```\n */\nexport async function kvSet(config: SylphxConfig, request: KvSetRequest): Promise<{ ok: boolean }> {\n\treturn callApi<{ ok: boolean }>(config, '/sdk/kv/set', {\n\t\tmethod: 'POST',\n\t\tbody: request,\n\t})\n}\n\n/**\n * Get a value by key.\n *\n * Returns `null` if the key does not exist or has expired.\n *\n * @example\n * ```ts\n * const session = await kvGet<{ userId: string }>(config, 'session:abc')\n * if (session) {\n * console.log(session.userId)\n * }\n * ```\n */\nexport async function kvGet<T = unknown>(config: SylphxConfig, key: string): Promise<T | null> {\n\tconst result = await callApi<{ value: T | null }>(\n\t\tconfig,\n\t\t`/sdk/kv/get/${encodeURIComponent(key)}`,\n\t\t{ method: 'GET' },\n\t)\n\treturn result.value\n}\n\n/**\n * Delete one or more keys.\n *\n * @example\n * ```ts\n * const { deleted } = await kvDelete(config, 'session:abc')\n * console.log(`Deleted ${deleted} keys`)\n * ```\n */\nexport async function kvDelete(config: SylphxConfig, key: string): Promise<{ deleted: number }> {\n\treturn callApi<{ deleted: number }>(config, `/sdk/kv/delete/${encodeURIComponent(key)}`, {\n\t\tmethod: 'DELETE',\n\t})\n}\n\n/**\n * Check if a key exists.\n *\n * @example\n * ```ts\n * const { exists } = await kvExists(config, 'session:abc')\n * ```\n */\nexport async function kvExists(config: SylphxConfig, key: string): Promise<{ exists: boolean }> {\n\treturn callApi<{ exists: boolean }>(config, `/sdk/kv/exists/${encodeURIComponent(key)}`, {\n\t\tmethod: 'GET',\n\t})\n}\n\n/**\n * Set expiry on an existing key.\n *\n * @example\n * ```ts\n * await kvExpire(config, { key: 'session:abc', seconds: 3600 })\n * ```\n */\nexport async function kvExpire(\n\tconfig: SylphxConfig,\n\trequest: KvExpireRequest,\n): Promise<{ ok: boolean }> {\n\treturn callApi<{ ok: boolean }>(config, '/sdk/kv/expire', {\n\t\tmethod: 'POST',\n\t\tbody: request,\n\t})\n}\n\n/**\n * Increment a numeric value.\n *\n * @example\n * ```ts\n * const { value } = await kvIncr(config, { key: 'page:views', by: 1 })\n * ```\n */\nexport async function kvIncr(\n\tconfig: SylphxConfig,\n\trequest: KvIncrRequest,\n): Promise<{ value: number }> {\n\treturn callApi<{ value: number }>(config, '/sdk/kv/incr', {\n\t\tmethod: 'POST',\n\t\tbody: request,\n\t})\n}\n\n// ============================================================================\n// Functions — Bulk Operations\n// ============================================================================\n\n/**\n * Set multiple key-value pairs atomically.\n */\nexport async function kvMset(\n\tconfig: SylphxConfig,\n\trequest: KvMsetRequest,\n): Promise<{ ok: boolean }> {\n\treturn callApi<{ ok: boolean }>(config, '/sdk/kv/mset', {\n\t\tmethod: 'POST',\n\t\tbody: request,\n\t})\n}\n\n/**\n * Get multiple values by keys in a single request.\n *\n * Returns `null` for keys that don't exist.\n */\nexport async function kvMget<T = unknown>(\n\tconfig: SylphxConfig,\n\trequest: KvMgetRequest,\n): Promise<Array<T | null>> {\n\tconst result = await callApi<{ values: Array<T | null> }>(config, '/sdk/kv/mget', {\n\t\tmethod: 'POST',\n\t\tbody: request,\n\t})\n\treturn result.values\n}\n\n// ============================================================================\n// Functions — Hash Operations\n// ============================================================================\n\n/**\n * Set fields on a hash key.\n *\n * @example\n * ```ts\n * await kvHset(config, { key: 'user:123', fields: { name: 'Alice', age: 30 } })\n * ```\n */\nexport async function kvHset(\n\tconfig: SylphxConfig,\n\trequest: KvHsetRequest,\n): Promise<{ count: number }> {\n\treturn callApi<{ count: number }>(config, '/sdk/kv/hset', {\n\t\tmethod: 'POST',\n\t\tbody: request,\n\t})\n}\n\n/**\n * Get a single field from a hash key.\n */\nexport async function kvHget<T = unknown>(\n\tconfig: SylphxConfig,\n\trequest: KvHgetRequest,\n): Promise<T | null> {\n\tconst result = await callApi<{ value: T | null }>(config, '/sdk/kv/hget', {\n\t\tmethod: 'POST',\n\t\tbody: request,\n\t})\n\treturn result.value\n}\n\n/**\n * Get all fields from a hash key.\n */\nexport async function kvHgetall<T extends Record<string, unknown> = Record<string, unknown>>(\n\tconfig: SylphxConfig,\n\trequest: KvHgetallRequest,\n): Promise<T | null> {\n\tconst result = await callApi<{ value: T | null }>(config, '/sdk/kv/hgetall', {\n\t\tmethod: 'POST',\n\t\tbody: request,\n\t})\n\treturn result.value\n}\n\n// ============================================================================\n// Functions — List Operations\n// ============================================================================\n\n/**\n * Left-push values onto a list.\n *\n * @example\n * ```ts\n * const { length } = await kvLpush(config, { key: 'events', values: [event] })\n * ```\n */\nexport async function kvLpush(\n\tconfig: SylphxConfig,\n\trequest: KvLpushRequest,\n): Promise<{ length: number }> {\n\treturn callApi<{ length: number }>(config, '/sdk/kv/lpush', {\n\t\tmethod: 'POST',\n\t\tbody: request,\n\t})\n}\n\n/**\n * Get a range of elements from a list.\n *\n * @example\n * ```ts\n * // Get last 10 events\n * const items = await kvLrange(config, { key: 'events', start: 0, stop: 9 })\n * ```\n */\nexport async function kvLrange<T = unknown>(\n\tconfig: SylphxConfig,\n\trequest: KvLrangeRequest,\n): Promise<T[]> {\n\tconst result = await callApi<{ items: T[] }>(config, '/sdk/kv/lrange', {\n\t\tmethod: 'POST',\n\t\tbody: request,\n\t})\n\treturn result.items\n}\n\n// ============================================================================\n// Functions — Sorted Set Operations\n// ============================================================================\n\n/**\n * Add members to a sorted set.\n *\n * @example\n * ```ts\n * // Add to leaderboard\n * await kvZadd(config, {\n * key: 'leaderboard',\n * members: [{ member: 'user:123', score: 1500 }],\n * })\n * ```\n */\nexport async function kvZadd(\n\tconfig: SylphxConfig,\n\trequest: KvZaddRequest,\n): Promise<{ added: number }> {\n\treturn callApi<{ added: number }>(config, '/sdk/kv/zadd', {\n\t\tmethod: 'POST',\n\t\tbody: request,\n\t})\n}\n\n/**\n * Get a range of members from a sorted set.\n *\n * @example\n * ```ts\n * // Get top 10 leaderboard entries\n * const entries = await kvZrange(config, {\n * key: 'leaderboard',\n * start: 0,\n * stop: 9,\n * rev: true,\n * withScores: true,\n * })\n * ```\n */\nexport async function kvZrange(\n\tconfig: SylphxConfig,\n\trequest: KvZrangeRequest,\n): Promise<Array<{ member: string; score?: number }>> {\n\tconst result = await callApi<{\n\t\tmembers: Array<{ member: string; score?: number }>\n\t}>(config, '/sdk/kv/zrange', {\n\t\tmethod: 'POST',\n\t\tbody: request,\n\t})\n\treturn result.members\n}\n\n// ============================================================================\n// Functions — Rate Limiting\n// ============================================================================\n\n/**\n * Check and consume a rate limit token using Redis sliding window.\n *\n * This is a built-in rate limiter — no external service needed.\n *\n * @example\n * ```ts\n * // 10 requests per 60 seconds per user\n * const result = await kvRateLimit(config, {\n * identifier: `user:${userId}`,\n * limit: 10,\n * window: 60,\n * })\n *\n * if (!result.success) {\n * return Response.json({ error: 'Rate limit exceeded' }, { status: 429 })\n * }\n * ```\n */\nexport async function kvRateLimit(\n\tconfig: SylphxConfig,\n\trequest: KvRateLimitRequest,\n): Promise<KvRateLimitResult> {\n\treturn callApi<KvRateLimitResult>(config, '/sdk/kv/ratelimit', {\n\t\tmethod: 'POST',\n\t\tbody: request,\n\t})\n}\n\n// ============================================================================\n// Functions — Scan / Iteration\n// ============================================================================\n\nexport interface KvScanOptions {\n\t/** Key pattern to match (e.g. 'user:*'). Defaults to '*' (all keys). */\n\tpattern?: string\n\t/** Cursor for pagination. Use '0' to start a new scan (default). */\n\tcursor?: string\n\t/** Hint to Redis for how many keys to return per iteration (1–1000). Default: 100. */\n\tcount?: number\n}\n\nexport interface KvScanResult {\n\t/** Keys matching the pattern (namespace prefix stripped). */\n\tkeys: string[]\n\t/** Cursor for the next page. Pass this as `cursor` in the next call. */\n\tnextCursor: string\n\t/** True when the full keyspace has been scanned (nextCursor is '0'). */\n\tdone: boolean\n}\n\n/**\n * Scan keys matching a pattern using Redis SCAN (cursor-based pagination).\n *\n * Unlike `KEYS`, SCAN is safe to use in production — it iterates incrementally.\n * Call repeatedly with the returned `nextCursor` until `done` is true.\n *\n * @example\n * ```ts\n * // Iterate all user keys\n * let cursor = '0'\n * do {\n * const result = await kvScan(config, { pattern: 'user:*', cursor })\n * for (const key of result.keys) console.log(key)\n * cursor = result.nextCursor\n * } while (!result.done)\n * ```\n */\nexport async function kvScan(config: SylphxConfig, options?: KvScanOptions): Promise<KvScanResult> {\n\treturn callApi<KvScanResult>(config, '/sdk/kv/scan', {\n\t\tmethod: 'GET',\n\t\tquery: {\n\t\t\t...(options?.pattern !== undefined && { pattern: options.pattern }),\n\t\t\t...(options?.cursor !== undefined && { cursor: options.cursor }),\n\t\t\t...(options?.count !== undefined && { count: String(options.count) }),\n\t\t},\n\t})\n}\n\n// ============================================================================\n// Convenience — JSON helpers\n// ============================================================================\n\n/**\n * Get a JSON value by key. Automatically parses the stored JSON string.\n *\n * Returns `null` if the key does not exist or has expired.\n *\n * @example\n * ```ts\n * const profile = await kvGetJSON<UserProfile>(config, 'user:123:profile')\n * if (profile) console.log(profile.name)\n * ```\n */\nexport async function kvGetJSON<T = unknown>(config: SylphxConfig, key: string): Promise<T | null> {\n\tconst raw = await kvGet<string>(config, key)\n\tif (raw === null) return null\n\ttry {\n\t\treturn JSON.parse(raw) as T\n\t} catch {\n\t\treturn null\n\t}\n}\n\n/**\n * Set a JSON value by key. Automatically serializes the value to JSON.\n *\n * @example\n * ```ts\n * await kvSetJSON(config, 'user:123:profile', { name: 'Alice', plan: 'pro' }, { ex: 3600 })\n * ```\n */\nexport async function kvSetJSON<T>(\n\tconfig: SylphxConfig,\n\tkey: string,\n\tvalue: T,\n\toptions?: KvSetOptions,\n): Promise<{ ok: boolean }> {\n\treturn kvSet(config, { key, value: JSON.stringify(value), ...options })\n}\n","/**\n * Realtime Functions\n *\n * Pure functions for real-time messaging via Redis Streams.\n * Supports channel-based pub/sub with SSE delivery to browsers.\n *\n * @example\n * ```ts\n * import { createConfig, realtimeEmit } from '@sylphx/sdk'\n *\n * // Server: emit events to connected clients\n * const config = createConfig({ secretKey: process.env.SYLPHX_SECRET_KEY! })\n * await realtimeEmit(config, {\n * channel: 'orders',\n * event: 'order.created',\n * data: { orderId: '123', amount: 99 },\n * })\n * ```\n */\n\nimport { callApi, type SylphxConfig } from './config'\nimport type { StreamMessage } from './realtime-types'\n\n// Re-export shared types\nexport type { StreamMessage } from './realtime-types'\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface RealtimeEmitRequest {\n\t/** Channel to emit the event to */\n\tchannel: string\n\t/** Event type/name */\n\tevent: string\n\t/** Event data (any JSON-serializable value) */\n\tdata: unknown\n}\n\nexport interface RealtimeEmitResponse {\n\t/** Stream entry ID */\n\tid: string\n\t/** Channel the event was emitted to */\n\tchannel: string\n}\n\nexport interface RealtimeHistoryRequest {\n\t/** Channel to get history for */\n\tchannel: string\n\t/** Maximum number of messages to return (default: 50) */\n\tlimit?: number\n\t/** Return messages after this stream entry ID */\n\tafter?: string\n}\n\nexport interface RealtimeHistoryResponse {\n\t/** List of historical messages */\n\tmessages: StreamMessage[]\n}\n\n// ============================================================================\n// Functions\n// ============================================================================\n\n/**\n * Emit an event to a realtime channel.\n *\n * All clients subscribed to the channel (via `useRealtime` hook or SSE)\n * will receive the event instantly.\n *\n * @example\n * ```ts\n * // Notify all clients watching a document\n * await realtimeEmit(config, {\n * channel: `doc:${documentId}`,\n * event: 'doc.updated',\n * data: { updatedBy: userId, timestamp: Date.now() },\n * })\n * ```\n */\nexport async function realtimeEmit(\n\tconfig: SylphxConfig,\n\trequest: RealtimeEmitRequest,\n): Promise<RealtimeEmitResponse> {\n\treturn callApi<RealtimeEmitResponse>(config, '/sdk/realtime/emit', {\n\t\tmethod: 'POST',\n\t\tbody: request,\n\t})\n}\n\n/**\n * Get historical messages from a channel.\n *\n * Useful for initializing state when a client first connects,\n * or for resuming from a known stream position.\n *\n * @example\n * ```ts\n * // Get last 20 messages when a user joins a chat\n * const { messages } = await getRealtimeHistory(config, {\n * channel: 'chat:general',\n * limit: 20,\n * })\n * ```\n */\nexport async function getRealtimeHistory(\n\tconfig: SylphxConfig,\n\trequest: RealtimeHistoryRequest,\n): Promise<RealtimeHistoryResponse> {\n\tconst params = new URLSearchParams()\n\tparams.set('channel', request.channel)\n\tif (request.limit !== undefined) params.set('limit', String(request.limit))\n\tif (request.after !== undefined) params.set('after', request.after)\n\n\treturn callApi<RealtimeHistoryResponse>(config, `/sdk/realtime/history?${params.toString()}`, {\n\t\tmethod: 'GET',\n\t})\n}\n","/**\n * Deploy Functions\n *\n * Pure functions for managing app deployments, environment variables,\n * and custom domains via the Platform Deploy API.\n *\n * Requires secret key authentication (`sk_*`).\n *\n * @example\n * ```ts\n * import { createConfig, triggerDeploy, getDeployStatus } from '@sylphx/sdk'\n *\n * const config = createConfig({ secretKey: process.env.SYLPHX_SECRET_KEY! })\n *\n * // Trigger a deployment\n * const deploy = await triggerDeploy(config, { envId: 'env_prod_xxx' })\n *\n * // Poll for completion\n * const status = await getDeployStatus(config, deploy.envId)\n * console.log(status.status) // 'building' | 'deploying' | 'success' | 'failed'\n * ```\n */\n\nimport { callApi, type SylphxConfig } from './config'\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport type DeployStatus = 'queued' | 'building' | 'deploying' | 'success' | 'failed' | 'cancelled'\n\nexport interface DeployInfo {\n\t/** Deployment ID */\n\tdeploymentId: string\n\t/** Environment ID */\n\tenvId: string\n\t/** Current deployment status */\n\tstatus: DeployStatus\n\t/** Deployment URL */\n\turl?: string\n\t/** Git commit SHA */\n\tcommitSha?: string\n\t/** Git branch */\n\tbranch?: string\n\t/** Deployment started at (ISO timestamp) */\n\tstartedAt?: string\n\t/** Deployment completed at (ISO timestamp) */\n\tcompletedAt?: string\n\t/** Error message if failed */\n\terror?: string\n}\n\nexport interface TriggerDeployRequest {\n\t/** Environment ID to deploy */\n\tenvId: string\n\t/** Force rebuild without cache */\n\tforceRebuild?: boolean\n}\n\nexport interface RollbackDeployRequest {\n\t/** Environment ID to rollback */\n\tenvId: string\n\t/** Deployment ID to rollback to */\n\tdeploymentId: string\n}\n\nexport interface EnvVar {\n\t/** Environment variable key */\n\tkey: string\n\t/** Environment variable value */\n\tvalue: string\n\t/** Whether value is sensitive (masked in logs) */\n\tsensitive?: boolean\n}\n\nexport interface SetEnvVarRequest {\n\t/** Environment variable key */\n\tkey: string\n\t/** Environment variable value */\n\tvalue: string\n\t/** Whether value is sensitive/secret */\n\tsensitive?: boolean\n}\n\nexport interface DeployHistoryResponse {\n\t/** List of past deployments */\n\tdeployments: DeployInfo[]\n}\n\nexport interface BuildLog {\n\t/** Log line text */\n\ttext: string\n\t/** Log timestamp (ISO) */\n\ttimestamp?: string\n\t/** Log level */\n\tlevel?: 'info' | 'warn' | 'error'\n}\n\nexport interface BuildLogHistoryResponse {\n\t/** Log lines */\n\tlogs: BuildLog[]\n}\n\n// ============================================================================\n// Functions — Deployments\n// ============================================================================\n\n/**\n * Trigger a new deployment for an environment.\n *\n * @example\n * ```ts\n * const deploy = await triggerDeploy(config, { envId: 'env_prod_xxx' })\n * console.log(`Deployment ${deploy.deploymentId} started`)\n * ```\n */\nexport async function triggerDeploy(\n\tconfig: SylphxConfig,\n\trequest: TriggerDeployRequest,\n): Promise<DeployInfo> {\n\treturn callApi<DeployInfo>(config, `/sdk/deploy/trigger/${encodeURIComponent(request.envId)}`, {\n\t\tmethod: 'POST',\n\t\tbody: request.forceRebuild !== undefined ? { forceRebuild: request.forceRebuild } : undefined,\n\t})\n}\n\n/**\n * Get the current deployment status for an environment.\n *\n * @example\n * ```ts\n * const { status } = await getDeployStatus(config, 'env_prod_xxx')\n * if (status === 'success') {\n * console.log('Deployment succeeded!')\n * }\n * ```\n */\nexport async function getDeployStatus(config: SylphxConfig, envId: string): Promise<DeployInfo> {\n\treturn callApi<DeployInfo>(config, `/sdk/deploy/status/${encodeURIComponent(envId)}`, {\n\t\tmethod: 'GET',\n\t})\n}\n\n/**\n * Get deployment history for an environment.\n *\n * @example\n * ```ts\n * const { deployments } = await getDeployHistory(config, 'env_prod_xxx')\n * const lastDeploy = deployments[0]\n * ```\n */\nexport async function getDeployHistory(\n\tconfig: SylphxConfig,\n\tenvId: string,\n): Promise<DeployHistoryResponse> {\n\treturn callApi<DeployHistoryResponse>(\n\t\tconfig,\n\t\t`/sdk/deploy/history/${encodeURIComponent(envId)}`,\n\t\t{ method: 'GET' },\n\t)\n}\n\n/**\n * Rollback an environment to a previous deployment.\n *\n * @example\n * ```ts\n * await rollbackDeploy(config, {\n * envId: 'env_prod_xxx',\n * deploymentId: 'dep_abc123',\n * })\n * ```\n */\nexport async function rollbackDeploy(\n\tconfig: SylphxConfig,\n\trequest: RollbackDeployRequest,\n): Promise<DeployInfo> {\n\treturn callApi<DeployInfo>(config, `/sdk/deploy/rollback/${encodeURIComponent(request.envId)}`, {\n\t\tmethod: 'POST',\n\t\tbody: { deploymentId: request.deploymentId },\n\t})\n}\n\n/**\n * Get stored build log history for an environment.\n *\n * For live log streaming during an active build, use the SSE endpoint\n * directly or the `useDeployLogs` React hook.\n *\n * @example\n * ```ts\n * const { logs } = await getBuildLogHistory(config, 'env_prod_xxx')\n * for (const log of logs) {\n * console.log(log.text)\n * }\n * ```\n */\nexport async function getBuildLogHistory(\n\tconfig: SylphxConfig,\n\tenvId: string,\n): Promise<BuildLogHistoryResponse> {\n\treturn callApi<BuildLogHistoryResponse>(\n\t\tconfig,\n\t\t`/sdk/deploy/logs/${encodeURIComponent(envId)}/history`,\n\t\t{ method: 'GET' },\n\t)\n}\n\n// ============================================================================\n// Functions — Environment Variables\n// ============================================================================\n\n/**\n * List environment variables for a deployment environment.\n *\n * Sensitive values are masked in the response.\n *\n * @example\n * ```ts\n * const envVars = await listEnvVars(config, 'env_prod_xxx')\n * ```\n */\nexport async function listEnvVars(config: SylphxConfig, envId: string): Promise<EnvVar[]> {\n\tconst result = await callApi<{ envVars: EnvVar[] }>(\n\t\tconfig,\n\t\t`/sdk/deploy/envvars/${encodeURIComponent(envId)}`,\n\t\t{ method: 'GET' },\n\t)\n\treturn result.envVars\n}\n\n/**\n * Set (create or update) an environment variable.\n *\n * @example\n * ```ts\n * await setEnvVar(config, 'env_prod_xxx', {\n * key: 'DATABASE_URL',\n * value: 'postgresql://...',\n * sensitive: true,\n * })\n * ```\n */\nexport async function setEnvVar(\n\tconfig: SylphxConfig,\n\tenvId: string,\n\trequest: SetEnvVarRequest,\n): Promise<EnvVar> {\n\treturn callApi<EnvVar>(config, `/sdk/deploy/envvars/${encodeURIComponent(envId)}`, {\n\t\tmethod: 'POST',\n\t\tbody: request,\n\t})\n}\n\n/**\n * Delete an environment variable.\n *\n * @example\n * ```ts\n * await deleteEnvVar(config, 'env_prod_xxx', 'DATABASE_URL')\n * ```\n */\nexport async function deleteEnvVar(\n\tconfig: SylphxConfig,\n\tenvId: string,\n\tkey: string,\n): Promise<{ deleted: boolean }> {\n\treturn callApi<{ deleted: boolean }>(\n\t\tconfig,\n\t\t`/sdk/deploy/envvars/${encodeURIComponent(envId)}/${encodeURIComponent(key)}`,\n\t\t{ method: 'DELETE' },\n\t)\n}\n","/**\n * Monitoring Functions\n *\n * Pure functions for error tracking and log capture.\n * Works client-side and server-side.\n *\n * ## Industry Patterns\n * - **Error grouping via fingerprinting** — Same error only billed once (Sentry pattern)\n * - **Adaptive sampling** — Automatic sample rate adjustment based on quota usage\n * - **Breadcrumb trails** — Contextual trail leading to errors\n *\n * @example\n * ```ts\n * import { createConfig, captureException, captureMessage } from '@sylphx/sdk'\n *\n * const config = createConfig({ appId: process.env.NEXT_PUBLIC_SYLPHX_APP_ID! })\n *\n * // Capture errors\n * try {\n * await riskyOperation()\n * } catch (err) {\n * await captureException(config, err as Error)\n * }\n *\n * // Capture log messages\n * await captureMessage(config, 'User completed onboarding', { level: 'info' })\n * ```\n */\n\nimport { callApi, type SylphxConfig } from './config'\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport type MonitoringSeverity = 'fatal' | 'error' | 'warning' | 'info'\n\nexport interface ExceptionFrame {\n\t/** Source filename */\n\tfilename?: string\n\t/** Function name */\n\tfunction?: string\n\t/** Line number */\n\tlineno?: number\n\t/** Column number */\n\tcolno?: number\n}\n\nexport interface ExceptionValue {\n\t/** Exception class/type (e.g., \"TypeError\") */\n\ttype: string\n\t/** Exception message */\n\tvalue: string\n\t/** Stack trace frames (innermost first) */\n\tstacktrace?: { frames?: ExceptionFrame[] }\n}\n\nexport interface Breadcrumb {\n\t/** Breadcrumb type (e.g., \"navigation\", \"http\", \"ui.click\") */\n\ttype?: string\n\t/** Log level */\n\tlevel?: MonitoringSeverity\n\t/** Breadcrumb message */\n\tmessage?: string\n\t/** Breadcrumb data */\n\tdata?: Record<string, unknown>\n\t/** Unix timestamp (seconds) */\n\ttimestamp?: number\n}\n\nexport interface CaptureExceptionRequest {\n\t/** Exception value(s) — first is primary, rest are chained causes */\n\texception: { values: ExceptionValue[] }\n\t/** Severity level (default: \"error\") */\n\tlevel?: MonitoringSeverity\n\t/** Current page route */\n\troute?: string\n\t/** User agent string */\n\tuserAgent?: string\n\t/** App release version */\n\trelease?: string\n\t/** Environment name (e.g., \"production\", \"staging\") */\n\tenvironment?: string\n\t/** Custom tags for filtering */\n\ttags?: Record<string, string>\n\t/** Extra context data */\n\textra?: Record<string, unknown>\n\t/** Breadcrumb trail leading to the error */\n\tbreadcrumbs?: Breadcrumb[]\n\t/** Custom fingerprint for grouping (overrides automatic grouping) */\n\tfingerprint?: string[]\n}\n\nexport interface CaptureMessageRequest {\n\t/** Log message */\n\tmessage: string\n\t/** Severity level (default: \"info\") */\n\tlevel?: MonitoringSeverity\n\t/** Current page route */\n\troute?: string\n\t/** App release version */\n\trelease?: string\n\t/** Custom tags for filtering */\n\ttags?: Record<string, string>\n\t/** Extra context data */\n\textra?: Record<string, unknown>\n}\n\nexport interface MonitoringResponse {\n\t/** Internal event ID */\n\teventId: string\n\t/** Whether this is a new unique error (true = billed, false = duplicate = free) */\n\tisNewError: boolean\n\t/** Current quota usage percentage (0-100+). Present when >= 50%. */\n\tquotaUsage?: number\n\t/**\n\t * Recommended client-side sample rate (0.0-1.0).\n\t * Reduce your error capture rate to this value when quota is high.\n\t * Present when quotaUsage >= 50%.\n\t */\n\trecommendedSampleRate?: number\n}\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\n/**\n * Convert a native Error object to ExceptionValue format.\n */\nfunction errorToExceptionValue(error: Error): ExceptionValue {\n\tconst frames: ExceptionFrame[] = []\n\n\tif (error.stack) {\n\t\t// Parse V8/SpiderMonkey style stack traces\n\t\tconst lines = error.stack.split('\\n').slice(1)\n\t\tfor (const line of lines) {\n\t\t\t// V8: \" at functionName (file:line:col)\"\n\t\t\tconst v8Match = line.match(/^\\s+at\\s+(.+?)\\s+\\((.+):(\\d+):(\\d+)\\)$/)\n\t\t\tif (v8Match) {\n\t\t\t\tframes.push({\n\t\t\t\t\tfunction: v8Match[1],\n\t\t\t\t\tfilename: v8Match[2],\n\t\t\t\t\tlineno: Number(v8Match[3]),\n\t\t\t\t\tcolno: Number(v8Match[4]),\n\t\t\t\t})\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\t// V8 (no function): \" at file:line:col\"\n\t\t\tconst v8AnonMatch = line.match(/^\\s+at\\s+(.+):(\\d+):(\\d+)$/)\n\t\t\tif (v8AnonMatch) {\n\t\t\t\tframes.push({\n\t\t\t\t\tfilename: v8AnonMatch[1],\n\t\t\t\t\tlineno: Number(v8AnonMatch[2]),\n\t\t\t\t\tcolno: Number(v8AnonMatch[3]),\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t}\n\n\treturn {\n\t\ttype: error.name || 'Error',\n\t\tvalue: error.message,\n\t\tstacktrace: frames.length > 0 ? { frames } : undefined,\n\t}\n}\n\n// ============================================================================\n// Functions\n// ============================================================================\n\n/**\n * Capture an exception for error tracking.\n *\n * Errors with the same fingerprint are grouped automatically.\n * Duplicate occurrences of the same error are FREE (only new unique\n * errors count against your quota).\n *\n * @example\n * ```ts\n * try {\n * await processPayment(amount)\n * } catch (err) {\n * const result = await captureException(config, err as Error, {\n * tags: { paymentProvider: 'stripe' },\n * extra: { amount, userId },\n * })\n * }\n * ```\n */\nexport async function captureException(\n\tconfig: SylphxConfig,\n\terror: Error,\n\toptions: Omit<CaptureExceptionRequest, 'exception'> = {},\n): Promise<MonitoringResponse> {\n\tconst exceptionValue = errorToExceptionValue(error)\n\tconst request: CaptureExceptionRequest = {\n\t\t...options,\n\t\texception: { values: [exceptionValue] },\n\t}\n\treturn callApi<MonitoringResponse>(config, '/sdk/monitoring/exception', {\n\t\tmethod: 'POST',\n\t\tbody: request,\n\t})\n}\n\n/**\n * Capture an exception with full control over the exception payload.\n *\n * Use this for structured exception capture with custom types, chained\n * causes, or when not working with native Error objects.\n */\nexport async function captureExceptionRaw(\n\tconfig: SylphxConfig,\n\trequest: CaptureExceptionRequest,\n): Promise<MonitoringResponse> {\n\treturn callApi<MonitoringResponse>(config, '/sdk/monitoring/exception', {\n\t\tmethod: 'POST',\n\t\tbody: request,\n\t})\n}\n\n/**\n * Capture a log message for monitoring.\n *\n * Like `captureException` but for non-error events (warnings, info, etc.).\n * Messages with the same content are grouped automatically.\n *\n * @example\n * ```ts\n * // Info log\n * await captureMessage(config, 'Payment webhook received', {\n * level: 'info',\n * tags: { provider: 'stripe', event: 'payment.succeeded' },\n * })\n *\n * // Warning\n * await captureMessage(config, 'Slow query detected', {\n * level: 'warning',\n * extra: { queryMs: 2400, query: sql },\n * })\n * ```\n */\nexport async function captureMessage(\n\tconfig: SylphxConfig,\n\tmessage: string,\n\toptions: Omit<CaptureMessageRequest, 'message'> = {},\n): Promise<MonitoringResponse> {\n\tconst request: CaptureMessageRequest = { ...options, message }\n\treturn callApi<MonitoringResponse>(config, '/sdk/monitoring/message', {\n\t\tmethod: 'POST',\n\t\tbody: request,\n\t})\n}\n","/**\n * Sandbox Client\n *\n * Ephemeral compute sandbox API — SOTA direct-connection design.\n *\n * ## Architecture\n *\n * POST /sandboxes → Platform provisions sandbox, waits for pod readiness,\n * returns { endpoint, token }. All subsequent exec/files/pty operations\n * go DIRECTLY to the sandbox exec-server — Platform is not in the data path.\n *\n * ```\n * SDK.create() ──→ Platform API (lifecycle only)\n * ↓ returns endpoint + token\n * SDK.exec() ──→ sandbox exec-server (direct, SSE stream)\n * SDK.files ──→ sandbox exec-server (direct, REST)\n * SDK.pty() ──→ sandbox exec-server (direct, WebSocket)\n * ```\n *\n * ## Usage\n *\n * ```typescript\n * import { createConfig, SandboxClient } from '@sylphx/sdk'\n *\n * const config = createConfig({ secretKey: process.env.SYLPHX_SECRET_KEY!, ref: 'your-ref' })\n *\n * // Create sandbox (Platform waits for pod ready before returning)\n * const sandbox = await SandboxClient.create(config)\n *\n * // Stream exec output in real-time\n * for await (const event of sandbox.exec(['npm', 'install'])) {\n * if (event.type === 'stdout') process.stdout.write(event.data)\n * if (event.type === 'exit') console.log('exit', event.exitCode)\n * }\n *\n * // File operations\n * await sandbox.files.write('/workspace/app.py', 'print(\"hello\")')\n * const content = await sandbox.files.read('/workspace/output.txt')\n *\n * // Terminate when done\n * await sandbox.terminate()\n * ```\n *\n * ## Auth\n * Requires sk_* secret key (server-side only).\n */\n\nimport { callApi, type SylphxConfig } from './config'\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport interface SandboxOptions {\n\t/** Docker image (must be in registry.sylphx.com). Omit to use env default. */\n\timage?: string\n\t/** Idle timeout in ms before auto-termination (default: 300_000 = 5 min) */\n\tidleTimeoutMs?: number\n\t/** Storage size in GiB (enables persistent PVC; default: disabled) */\n\tstorageGi?: number\n\t/** CPU/memory resource spec */\n\tresources?: {\n\t\trequests?: { cpu?: string; memory?: string }\n\t\tlimits?: { cpu?: string; memory?: string }\n\t}\n\t/** Environment variables injected into the sandbox container */\n\tenv?: Record<string, string>\n\t/**\n\t * Shared volume mounts from org-level managed volumes.\n\t * Requires ReadWriteMany volumes (CephFS). Multiple sandboxes can mount\n\t * the same volume for shared filesystem access.\n\t */\n\tvolumeMounts?: Array<{\n\t\t/** Volume resource ID (from `sylphx volumes list`) */\n\t\tvolumeId: string\n\t\t/** Absolute path inside the container (e.g. \"/shared\") */\n\t\tmountPath: string\n\t\t/** Optional sub-path within the volume */\n\t\tsubPath?: string\n\t\t/** Read-only mount (default: false) */\n\t\treadOnly?: boolean\n\t}>\n}\n\n/** SSE event emitted by sandbox.exec() */\nexport type ExecEvent =\n\t| { type: 'stdout'; data: string }\n\t| { type: 'stderr'; data: string }\n\t| { type: 'exit'; exitCode: number; durationMs: number; timedOut?: boolean }\n\t| { type: 'error'; message: string }\n\n/** Non-streaming exec result (all output collected, returned at once) */\nexport interface ExecResult {\n\tstdout: string\n\tstderr: string\n\texitCode: number\n\tdurationMs: number\n}\n\n/** @deprecated Use ExecResult */\nexport type CommandResult = ExecResult\n\n/** @deprecated File operations are now handled by SandboxFiles class */\nexport interface SandboxFile {\n\tpath: string\n\tcontent: string\n\tencoding?: 'utf8' | 'base64'\n}\n\nexport interface ExecOptions {\n\tcwd?: string\n\tenv?: Record<string, string>\n\ttimeout?: number\n\tstdin?: string\n}\n\n// =============================================================================\n// Process API Types\n// =============================================================================\n\nexport interface ProcessStartOptions {\n\t/** Command + args (e.g. ['npm', 'install']) */\n\tcommand: string[]\n\t/** Working directory */\n\tcwd?: string\n\t/** Environment variables */\n\tenv?: Record<string, string>\n\t/** Hard timeout in seconds (0 = no timeout) */\n\ttimeoutSeconds?: number\n\t/** Open stdin pipe for writing */\n\tstdin?: boolean\n}\n\nexport interface ProcessInfo {\n\tid: string\n\tpid: number\n\tcommand: string[]\n\tcwd: string\n\tstatus: 'running' | 'exited' | 'killed' | 'timeout'\n\texitCode: number | null\n\tsignal: string | null\n\tstartedAt: string\n\texitedAt: string | null\n\tdurationMs: number | null\n\tstdout: string\n\tstderr: string\n}\n\nexport interface ProcessSummary {\n\tid: string\n\tpid: number\n\tcommand: string[]\n\tstatus: 'running' | 'exited' | 'killed' | 'timeout'\n\texitCode: number | null\n\tstartedAt: string\n\texitedAt: string | null\n\tdurationMs: number | null\n}\n\n/** SSE event from a process stream */\nexport type ProcessEvent =\n\t| { type: 'stdout'; pid: number; data: string }\n\t| { type: 'stderr'; pid: number; data: string }\n\t| { type: 'exit'; pid: number; exitCode: number }\n\n// =============================================================================\n// Watch API Types\n// =============================================================================\n\nexport interface WatchOptions {\n\t/** Path to watch (relative to /workspace or absolute) */\n\tpath: string\n\t/** Watch subdirectories recursively (default: true) */\n\trecursive?: boolean\n\t/** Additional patterns to ignore */\n\tignore?: string[]\n}\n\nexport interface WatchEntry {\n\tpath: string\n\trecursive: boolean\n\tcreatedAt: string\n}\n\n/** File change event delivered via SSE /events stream */\nexport interface FileEvent {\n\ttype: 'file'\n\tpath: string\n\tevent: 'created' | 'modified' | 'deleted'\n}\n\nexport interface SandboxRecord {\n\tid: string\n\tstatus: 'starting' | 'running' | 'idle' | 'terminated' | 'error'\n\timage: string\n\t/** Public HTTPS endpoint: https://sbx-xxx.sandboxes.sylphx.app */\n\tendpoint: string | null\n\t/** Per-sandbox RS256 JWT for direct exec-server authentication */\n\ttoken: string | null\n\tprojectId: string\n\tidleTimeoutMs: number\n\tcreatedAt: string\n\tstartedAt: string | null\n\texpiresAt: string | null\n\tterminatedAt: string | null\n}\n\n// =============================================================================\n// Files namespace\n// =============================================================================\n\nexport class SandboxFiles {\n\tconstructor(\n\t\tprivate readonly endpoint: string,\n\t\tprivate readonly token: string,\n\t) {}\n\n\tprivate authHeader(): Record<string, string> {\n\t\treturn { Authorization: `Bearer ${this.token}` }\n\t}\n\n\t/** Write a file to the sandbox filesystem. */\n\tasync write(\n\t\tpath: string,\n\t\tcontent: string | Buffer,\n\t\tencoding: 'utf8' | 'base64' = 'utf8',\n\t): Promise<void> {\n\t\tconst contentStr = Buffer.isBuffer(content) ? content.toString('base64') : content\n\t\tconst effectiveEncoding = Buffer.isBuffer(content) ? 'base64' : encoding\n\n\t\tconst res = await fetch(`${this.endpoint}/files`, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: { ...this.authHeader(), 'Content-Type': 'application/json' },\n\t\t\tbody: JSON.stringify({ path, content: contentStr, encoding: effectiveEncoding }),\n\t\t})\n\t\tif (!res.ok) throw new Error(`files.write failed: ${await res.text()}`)\n\t}\n\n\t/** Read a file from the sandbox filesystem. Returns content as string. */\n\tasync read(path: string): Promise<string> {\n\t\tconst res = await fetch(`${this.endpoint}/files?path=${encodeURIComponent(path)}`, {\n\t\t\theaders: this.authHeader(),\n\t\t})\n\t\tif (!res.ok) throw new Error(`files.read failed: ${await res.text()}`)\n\t\tconst data = (await res.json()) as { content: string }\n\t\treturn data.content\n\t}\n\n\t/** Delete a file from the sandbox filesystem. */\n\tasync delete(path: string): Promise<void> {\n\t\tconst res = await fetch(`${this.endpoint}/files?path=${encodeURIComponent(path)}`, {\n\t\t\tmethod: 'DELETE',\n\t\t\theaders: this.authHeader(),\n\t\t})\n\t\tif (!res.ok) throw new Error(`files.delete failed: ${await res.text()}`)\n\t}\n\n\t/** List files in a directory. */\n\tasync list(path = '/'): Promise<string[]> {\n\t\tconst res = await fetch(`${this.endpoint}/list?path=${encodeURIComponent(path)}`, {\n\t\t\theaders: this.authHeader(),\n\t\t})\n\t\tif (!res.ok) throw new Error(`files.list failed: ${await res.text()}`)\n\t\tconst data = (await res.json()) as { files: string[] }\n\t\treturn data.files\n\t}\n}\n\n// =============================================================================\n// Process namespace\n// =============================================================================\n\nexport class SandboxProcesses {\n\tconstructor(\n\t\tprivate readonly endpoint: string,\n\t\tprivate readonly token: string,\n\t) {}\n\n\tprivate authHeader(): Record<string, string> {\n\t\treturn { Authorization: `Bearer ${this.token}` }\n\t}\n\n\t/** Spawn a new tracked process. Returns processId + pid immediately. */\n\tasync start(opts: ProcessStartOptions): Promise<{ id: string; pid: number }> {\n\t\tconst res = await fetch(`${this.endpoint}/process/start`, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: { ...this.authHeader(), 'Content-Type': 'application/json' },\n\t\t\tbody: JSON.stringify(opts),\n\t\t})\n\t\tif (!res.ok) throw new Error(`process.start failed: ${await res.text()}`)\n\t\treturn (await res.json()) as { id: string; pid: number }\n\t}\n\n\t/** List all tracked processes. */\n\tasync list(): Promise<ProcessSummary[]> {\n\t\tconst res = await fetch(`${this.endpoint}/process/list`, {\n\t\t\theaders: this.authHeader(),\n\t\t})\n\t\tif (!res.ok) throw new Error(`process.list failed: ${await res.text()}`)\n\t\treturn (await res.json()) as ProcessSummary[]\n\t}\n\n\t/** Get full process info including buffered output. */\n\tasync get(processId: string): Promise<ProcessInfo> {\n\t\tconst res = await fetch(`${this.endpoint}/process/${processId}`, {\n\t\t\theaders: this.authHeader(),\n\t\t})\n\t\tif (!res.ok) throw new Error(`process.get failed: ${await res.text()}`)\n\t\treturn (await res.json()) as ProcessInfo\n\t}\n\n\t/** Send a signal to a process. */\n\tasync kill(processId: string, signal: string = 'SIGTERM'): Promise<void> {\n\t\tconst res = await fetch(`${this.endpoint}/process/${processId}/kill`, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: { ...this.authHeader(), 'Content-Type': 'application/json' },\n\t\t\tbody: JSON.stringify({ signal }),\n\t\t})\n\t\tif (!res.ok) throw new Error(`process.kill failed: ${await res.text()}`)\n\t}\n\n\t/** Write to process stdin. */\n\tasync writeStdin(processId: string, data: string): Promise<void> {\n\t\tconst res = await fetch(`${this.endpoint}/process/${processId}/input`, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: { ...this.authHeader(), 'Content-Type': 'application/json' },\n\t\t\tbody: JSON.stringify({ data }),\n\t\t})\n\t\tif (!res.ok) throw new Error(`process.writeStdin failed: ${await res.text()}`)\n\t}\n\n\t/**\n\t * Wait for a process to complete and return its final info.\n\t * Polls every 500ms until status is no longer 'running'.\n\t *\n\t * For real-time output, use stream() instead.\n\t */\n\tasync wait(processId: string, timeoutMs = 300_000): Promise<ProcessInfo> {\n\t\tconst deadline = Date.now() + timeoutMs\n\t\twhile (Date.now() < deadline) {\n\t\t\tconst info = await this.get(processId)\n\t\t\tif (info.status !== 'running') return info\n\t\t\tawait new Promise((r) => setTimeout(r, 500))\n\t\t}\n\t\tthrow new Error(`Timed out waiting for process ${processId} to complete (${timeoutMs}ms)`)\n\t}\n\n\t/** Stream process output as async iterable SSE events. */\n\tasync *stream(processId: string): AsyncGenerator<ProcessEvent> {\n\t\tconst res = await fetch(\n\t\t\t`${this.endpoint}/process/${processId}/stream`,\n\t\t\t{ headers: this.authHeader() },\n\t\t)\n\t\tif (!res.ok) throw new Error(`process.stream failed: ${await res.text()}`)\n\t\tif (!res.body) throw new Error('process.stream: no response body')\n\n\t\tconst decoder = new TextDecoder()\n\t\tconst reader = res.body.getReader()\n\t\tlet buffer = ''\n\n\t\ttry {\n\t\t\twhile (true) {\n\t\t\t\tconst { done, value } = await reader.read()\n\t\t\t\tif (done) break\n\t\t\t\tbuffer += decoder.decode(value, { stream: true })\n\t\t\t\tconst lines = buffer.split('\\n')\n\t\t\t\tbuffer = lines.pop() ?? ''\n\t\t\t\tfor (const line of lines) {\n\t\t\t\t\tif (line.startsWith('data: ')) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst event = JSON.parse(line.slice(6)) as ProcessEvent\n\t\t\t\t\t\t\tyield event\n\t\t\t\t\t\t\tif (event.type === 'exit') return\n\t\t\t\t\t\t} catch { /* skip malformed */ }\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} finally {\n\t\t\treader.releaseLock()\n\t\t}\n\t}\n}\n\n// =============================================================================\n// Watch namespace\n// =============================================================================\n\nexport class SandboxWatch {\n\tconstructor(\n\t\tprivate readonly endpoint: string,\n\t\tprivate readonly token: string,\n\t) {}\n\n\tprivate authHeader(): Record<string, string> {\n\t\treturn { Authorization: `Bearer ${this.token}` }\n\t}\n\n\t/** Start watching a path. Events delivered via sandbox.events() SSE stream. */\n\tasync add(opts: WatchOptions): Promise<WatchEntry> {\n\t\tconst res = await fetch(`${this.endpoint}/watch`, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: { ...this.authHeader(), 'Content-Type': 'application/json' },\n\t\t\tbody: JSON.stringify(opts),\n\t\t})\n\t\tif (!res.ok) throw new Error(`watch.add failed: ${await res.text()}`)\n\t\treturn (await res.json()) as WatchEntry\n\t}\n\n\t/** List active watches. */\n\tasync list(): Promise<WatchEntry[]> {\n\t\tconst res = await fetch(`${this.endpoint}/watch`, {\n\t\t\theaders: this.authHeader(),\n\t\t})\n\t\tif (!res.ok) throw new Error(`watch.list failed: ${await res.text()}`)\n\t\tconst data = (await res.json()) as { watches: WatchEntry[] }\n\t\treturn data.watches\n\t}\n\n\t/** Stop watching a path. */\n\tasync remove(path: string): Promise<void> {\n\t\tconst res = await fetch(`${this.endpoint}/watch?path=${encodeURIComponent(path)}`, {\n\t\t\tmethod: 'DELETE',\n\t\t\theaders: this.authHeader(),\n\t\t})\n\t\tif (!res.ok) throw new Error(`watch.remove failed: ${await res.text()}`)\n\t}\n}\n\n// =============================================================================\n// SandboxClient\n// =============================================================================\n\nexport class SandboxClient {\n\treadonly id: string\n\tprivate readonly config: SylphxConfig\n\n\t/** Public endpoint from Platform (may be null for sandboxes from pool pre-v2) */\n\treadonly endpoint: string | null\n\t/** Per-sandbox JWT for direct exec-server auth */\n\treadonly token: string | null\n\n\t/** File operations (direct to exec-server) */\n\treadonly files: SandboxFiles | null\n\n\t/** Concurrent process management (direct to exec-server) */\n\treadonly processes: SandboxProcesses | null\n\n\t/** Filesystem watch management (direct to exec-server) */\n\treadonly watch: SandboxWatch | null\n\n\tprivate constructor(\n\t\tid: string,\n\t\tconfig: SylphxConfig,\n\t\tendpoint: string | null,\n\t\ttoken: string | null,\n\t) {\n\t\tthis.id = id\n\t\tthis.config = config\n\t\tthis.endpoint = endpoint\n\t\tthis.token = token\n\t\tthis.files = endpoint && token ? new SandboxFiles(endpoint, token) : null\n\t\tthis.processes = endpoint && token ? new SandboxProcesses(endpoint, token) : null\n\t\tthis.watch = endpoint && token ? new SandboxWatch(endpoint, token) : null\n\t}\n\n\t// ---------------------------------------------------------------------------\n\t// Factory\n\t// ---------------------------------------------------------------------------\n\n\t/**\n\t * Create a new sandbox.\n\t *\n\t * Platform provisions the K8s pod, waits for readiness, and returns\n\t * { endpoint, token } once the sandbox is fully ready to accept traffic.\n\t * No client-side polling required.\n\t */\n\tstatic async create(config: SylphxConfig, options?: SandboxOptions): Promise<SandboxClient> {\n\t\tconst record = await callApi<SandboxRecord>(config, '/sandboxes', {\n\t\t\tmethod: 'POST',\n\t\t\tbody: {\n\t\t\t\timage: options?.image,\n\t\t\t\tidleTimeoutMs: options?.idleTimeoutMs ?? 300_000,\n\t\t\t\tresources: options?.resources,\n\t\t\t\tenv: options?.env,\n\t\t\t\tstorage:\n\t\t\t\t\toptions?.storageGi !== undefined\n\t\t\t\t\t\t? { enabled: true, sizeGi: options.storageGi }\n\t\t\t\t\t\t: undefined,\n\t\t\t\tvolumeMounts: options?.volumeMounts,\n\t\t\t},\n\t\t})\n\n\t\treturn new SandboxClient(record.id, config, record.endpoint, record.token)\n\t}\n\n\t/**\n\t * Reconnect to an existing sandbox by ID.\n\t * Fetches the current status to get the endpoint + token.\n\t */\n\tstatic async fromId(config: SylphxConfig, sandboxId: string): Promise<SandboxClient> {\n\t\tconst record = await callApi<SandboxRecord>(config, `/sandboxes/${sandboxId}`, {\n\t\t\tmethod: 'GET',\n\t\t})\n\t\treturn new SandboxClient(record.id, config, record.endpoint, record.token)\n\t}\n\n\t// ---------------------------------------------------------------------------\n\t// Lifecycle\n\t// ---------------------------------------------------------------------------\n\n\tasync getStatus(): Promise<SandboxRecord> {\n\t\treturn callApi<SandboxRecord>(this.config, `/sandboxes/${this.id}`, { method: 'GET' })\n\t}\n\n\tasync terminate(): Promise<void> {\n\t\tawait callApi<{ success: boolean }>(this.config, `/sandboxes/${this.id}`, { method: 'DELETE' })\n\t}\n\n\t// ---------------------------------------------------------------------------\n\t// Exec — SSE streaming (primary)\n\t// ---------------------------------------------------------------------------\n\n\t/**\n\t * Execute a command and stream output as async iterable SSE events.\n\t *\n\t * **Stateless mode**: each exec() call runs in an isolated bash invocation.\n\t * Shell state (CWD changes, exported env vars, functions) is NOT preserved\n\t * between calls.\n\t *\n\t * For state-preserving execution (CWD, env), use `run()` which runs in the\n\t * persistent active shell and returns the result once complete.\n\t *\n\t * For streaming + state-preserving (advanced), combine `sandbox.events()` with `run()`:\n\t * ```typescript\n\t * const eventStream = sandbox.events({ type: 'stdout' })\n\t * sandbox.run(['npm', 'install']) // don't await yet\n\t * for await (const ev of eventStream) { ... }\n\t * ```\n\t *\n\t * @example\n\t * ```typescript\n\t * for await (const event of sandbox.exec(['npm', 'install'])) {\n\t * if (event.type === 'stdout') process.stdout.write(event.data)\n\t * if (event.type === 'exit') console.log('Done:', event.exitCode)\n\t * }\n\t * ```\n\t */\n\tasync *exec(command: string[], options?: ExecOptions): AsyncGenerator<ExecEvent> {\n\t\tthis.assertDirect()\n\n\t\t// POST /exec with stateless:true, stream:true → exec-server returns SSE response.\n\t\t// 'stateless' runs in an isolated bash process (not the active shell).\n\t\t// Without stateless:true, /exec runs in the active shell and returns JSON — not SSE.\n\t\tconst res = await fetch(`${this.endpoint!}/exec`, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: {\n\t\t\t\tAuthorization: `Bearer ${this.token!}`,\n\t\t\t\t'Content-Type': 'application/json',\n\t\t\t},\n\t\t\tbody: JSON.stringify({ command, ...options, stateless: true, stream: true }),\n\t\t})\n\n\t\tif (!res.ok) {\n\t\t\tthrow new Error(`exec failed (${res.status}): ${await res.text()}`)\n\t\t}\n\t\tif (!res.body) throw new Error('exec: no response body')\n\n\t\t// Parse SSE stream\n\t\tconst decoder = new TextDecoder()\n\t\tconst reader = res.body.getReader()\n\t\tlet buffer = ''\n\n\t\ttry {\n\t\t\twhile (true) {\n\t\t\t\tconst { done, value } = await reader.read()\n\t\t\t\tif (done) break\n\n\t\t\t\tbuffer += decoder.decode(value, { stream: true })\n\t\t\t\tconst lines = buffer.split('\\n')\n\t\t\t\tbuffer = lines.pop() ?? '' // Keep incomplete last line\n\n\t\t\t\tfor (const line of lines) {\n\t\t\t\t\tif (line.startsWith('data: ')) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst event = JSON.parse(line.slice(6)) as ExecEvent\n\t\t\t\t\t\t\tyield event\n\t\t\t\t\t\t\tif (event.type === 'exit' || event.type === 'error') return\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t// Malformed SSE data — skip\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} finally {\n\t\t\treader.releaseLock()\n\t\t}\n\t}\n\n\t/**\n\t * Execute a command and collect all output (non-streaming).\n\t * Convenience wrapper over exec() for simple use cases.\n\t *\n\t * For long-running commands, prefer exec() to stream output incrementally.\n\t */\n\tasync run(command: string[], options?: ExecOptions): Promise<ExecResult> {\n\t\tlet stdout = ''\n\t\tlet stderr = ''\n\t\tlet exitCode = 1\n\t\tlet durationMs = 0\n\n\t\tfor await (const event of this.exec(command, options)) {\n\t\t\tif (event.type === 'stdout') stdout += event.data\n\t\t\telse if (event.type === 'stderr') stderr += event.data\n\t\t\telse if (event.type === 'exit') {\n\t\t\t\texitCode = event.exitCode\n\t\t\t\tdurationMs = event.durationMs\n\t\t\t}\n\t\t}\n\n\t\treturn { stdout, stderr, exitCode, durationMs }\n\t}\n\n\t// ---------------------------------------------------------------------------\n\t// Events — Unified SSE stream\n\t// ---------------------------------------------------------------------------\n\n\t/**\n\t * Subscribe to the unified event stream (SSE).\n\t *\n\t * Receives all sandbox events: stdout, stderr, exit, port, file, shell, resource.\n\t * Filter by type/pid/shellId using query params.\n\t *\n\t * @example\n\t * ```typescript\n\t * for await (const event of sandbox.events({ type: 'file' })) {\n\t * console.log('File changed:', event.path, event.event)\n\t * }\n\t * ```\n\t */\n\tasync *events(filter?: {\n\t\ttype?: 'stdout' | 'stderr' | 'exit' | 'port' | 'file' | 'shell' | 'resource'\n\t\tpid?: number\n\t\tshellId?: string\n\t}): AsyncGenerator<Record<string, unknown>> {\n\t\tthis.assertDirect()\n\n\t\tconst params = new URLSearchParams()\n\t\tif (filter?.type) params.set('type', filter.type)\n\t\tif (filter?.pid !== undefined) params.set('pid', String(filter.pid))\n\t\tif (filter?.shellId) params.set('shellId', filter.shellId)\n\n\t\tconst qs = params.toString()\n\t\tconst url = `${this.endpoint!}/events${qs ? `?${qs}` : ''}`\n\n\t\tconst res = await fetch(url, {\n\t\t\theaders: { Authorization: `Bearer ${this.token!}` },\n\t\t})\n\n\t\tif (!res.ok) throw new Error(`events failed (${res.status}): ${await res.text()}`)\n\t\tif (!res.body) throw new Error('events: no response body')\n\n\t\tconst decoder = new TextDecoder()\n\t\tconst reader = res.body.getReader()\n\t\tlet buffer = ''\n\n\t\ttry {\n\t\t\twhile (true) {\n\t\t\t\tconst { done, value } = await reader.read()\n\t\t\t\tif (done) break\n\t\t\t\tbuffer += decoder.decode(value, { stream: true })\n\t\t\t\tconst lines = buffer.split('\\n')\n\t\t\t\tbuffer = lines.pop() ?? ''\n\t\t\t\tfor (const line of lines) {\n\t\t\t\t\tif (line.startsWith('data: ')) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tyield JSON.parse(line.slice(6)) as Record<string, unknown>\n\t\t\t\t\t\t} catch { /* skip malformed */ }\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} finally {\n\t\t\treader.releaseLock()\n\t\t}\n\t}\n\n\t// ---------------------------------------------------------------------------\n\t// PTY — Interactive terminal (WebSocket)\n\t// ---------------------------------------------------------------------------\n\n\t/**\n\t * Open an interactive PTY session (WebSocket).\n\t *\n\t * Returns a WebSocket connected to a bash shell in the sandbox.\n\t * Token is passed as a query param (WebSocket doesn't support custom headers in browsers).\n\t *\n\t * @example\n\t * ```typescript\n\t * const ws = await sandbox.pty()\n\t * ws.on('message', (data) => process.stdout.write(JSON.parse(data).data))\n\t * ws.send(JSON.stringify({ type: 'input', data: 'ls -la\\n' }))\n\t * ws.send(JSON.stringify({ type: 'resize', cols: 120, rows: 40 }))\n\t * ```\n\t */\n\tpty(): WebSocket {\n\t\tthis.assertDirect()\n\n\t\tconst wsEndpoint = this.endpoint!.replace(/^https:\\/\\//, 'wss://').replace(\n\t\t\t/^http:\\/\\//,\n\t\t\t'ws://',\n\t\t)\n\n\t\treturn new WebSocket(`${wsEndpoint}/pty?token=${encodeURIComponent(this.token!)}`)\n\t}\n\n\t// ---------------------------------------------------------------------------\n\t// Private\n\t// ---------------------------------------------------------------------------\n\n\tprivate assertDirect(): void {\n\t\tif (!this.endpoint || !this.token) {\n\t\t\tthrow new Error(\n\t\t\t\t'Sandbox endpoint/token not available. ' +\n\t\t\t\t\t'This sandbox was created with an older SDK version or does not have a public endpoint.',\n\t\t\t)\n\t\t}\n\t}\n}\n","/**\n * Runs Client (ADR-040, formerly Workers)\n *\n * Fire-and-forget batch compute API (Modal-style run-to-completion jobs).\n *\n * Runs are ephemeral K8s Jobs that run to completion. Use them for:\n * - ML training folds (walk-forward cross-validation)\n * - Data processing pipelines\n * - Batch inference\n * - Any parallelisable CPU-heavy work\n *\n * ## Usage\n *\n * ### Single worker\n * ```typescript\n * import { createConfig, RunsClient } from '@sylphx/sdk'\n *\n * const config = createConfig({ secretKey: process.env.SYLPHX_SECRET_KEY!, ref: 'my-project' })\n *\n * const run = await RunsClient.create(config, {\n * image: 'registry.sylphx.com/sylphx/my-trainer:abc123',\n * command: ['python', 'train.py', '--fold', '0'],\n * resources: { requests: { cpu: '4', memory: '8Gi' } },\n * timeoutSeconds: 3600,\n * })\n *\n * const result = await worker.wait()\n * console.log(result.exitCode) // 0\n * console.log(result.stdout) // captured stdout\n * ```\n *\n * ### Parallel workers (walk-forward training)\n * ```typescript\n * const workers = await Promise.all(\n * folds.map((fold) =>\n * RunsClient.create(config, {\n * image: 'registry.sylphx.com/sylphx/trainer:abc123',\n * command: ['python', 'train.py', '--fold', String(fold.id)],\n * env: { FOLD_ID: String(fold.id), DATABASE_URL: process.env.DATABASE_URL! },\n * resources: { requests: { cpu: '4', memory: '8Gi' } },\n * volumeMounts: [{ volumeId: sharedCacheVolumeId, mountPath: '/cache' }],\n * timeoutSeconds: 7200,\n * }),\n * ),\n * )\n *\n * const results = await Promise.all(workers.map((w) => w.wait()))\n * const failures = results.filter((r) => r.exitCode !== 0)\n * ```\n *\n * ## Architecture\n *\n * - Workers are K8s Jobs (backoffLimit: 0, no restarts)\n * - Images must be from registry.sylphx.com (Harbor — scanned, private)\n * - Volumes: org-level volumeResources mounted as PVCs\n * - ReadWriteOnce → rook-ceph-block (single pod)\n * - ReadWriteMany → rook-cephfs (concurrent pods — use for shared feature caches)\n * - Auth: sk_* secret key (server-side only)\n * - Quota: 20 concurrent workers per org\n *\n * @module\n */\n\nimport { callApi, type SylphxConfig } from './config'\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport type RunStatus = 'pending' | 'running' | 'succeeded' | 'failed' | 'cancelled' | 'timeout'\n\nexport interface RunVolumeMount {\n\t/** UUID of the volumeResource to mount (must belong to this org) */\n\tvolumeId: string\n\t/** Absolute mount path inside the container (e.g. '/cache') */\n\tmountPath: string\n\t/** Optional sub-path within the volume (e.g. 'fold-3') */\n\tsubPath?: string\n\t/** Mount as read-only (default: false) */\n\treadOnly?: boolean\n}\n\nexport interface RunResourceSpec {\n\trequests?: {\n\t\t/** CPU request (e.g. '500m', '2', '4') */\n\t\tcpu?: string\n\t\t/** Memory request (e.g. '512Mi', '4Gi', '16Gi') */\n\t\tmemory?: string\n\t}\n\tlimits?: {\n\t\t/** CPU limit */\n\t\tcpu?: string\n\t\t/** Memory limit */\n\t\tmemory?: string\n\t}\n}\n\nexport interface CreateRunOptions {\n\t/**\n\t * Docker image to run (must be from registry.sylphx.com).\n\t *\n\t * @example 'registry.sylphx.com/sylphx/my-trainer:abc123def456'\n\t */\n\timage: string\n\n\t/**\n\t * Command + args to execute.\n\t *\n\t * @example ['python', 'train.py', '--fold', '3']\n\t * @example ['node', 'dist/process.js']\n\t */\n\tcommand: string[]\n\n\t/**\n\t * Environment variables to inject.\n\t * Use for fold IDs, feature flags, DB URLs, etc.\n\t */\n\tenv?: Record<string, string>\n\n\t/**\n\t * CPU/memory resource spec.\n\t * Defaults: { requests: { cpu: '500m', memory: '512Mi' }, limits: { cpu: '2', memory: '2Gi' } }\n\t */\n\tresources?: RunResourceSpec\n\n\t/**\n\t * Hard timeout in seconds (default: 3600 = 1 hour, max: 86400 = 24 hours).\n\t * K8s terminates the Job when the deadline is reached (status: 'timeout').\n\t */\n\ttimeoutSeconds?: number\n\n\t/**\n\t * Volume mounts from org-level volumeResources.\n\t * ReadWriteMany volumes (rook-cephfs) allow concurrent access by multiple parallel workers.\n\t */\n\tvolumeMounts?: RunVolumeMount[]\n}\n\nexport interface Run {\n\t/** Worker run ID (e.g. 'worker_Vh3kJ9mNpQ2wXsL1') */\n\tid: string\n\t/** Current lifecycle status */\n\tstatus: RunStatus\n\t/** Docker image */\n\timage: string\n\t/** Command being executed */\n\tcommand: string[]\n\t/** Environment variables */\n\tenv: Record<string, string> | null\n\t/** Resource spec */\n\tresources: RunResourceSpec | null\n\t/** Hard timeout in seconds */\n\ttimeoutSeconds: number\n\t/** Volume mounts */\n\tvolumeMounts: RunVolumeMount[] | null\n\t/** Exit code (only when succeeded or failed) */\n\texitCode: number | null\n\t/** Captured stdout (up to 1 MiB) */\n\tstdout: string | null\n\t/** Captured stderr (up to 1 MiB) */\n\tstderr: string | null\n\t/** Error message (e.g. OOMKilled, image pull failure) */\n\terrorMessage: string | null\n\t/** Duration in milliseconds (only when completed) */\n\tdurationMs: number | null\n\t/** When the worker pod started running */\n\tstartedAt: string | null\n\t/** When the worker completed */\n\tcompletedAt: string | null\n\t/** When this run was created */\n\tcreatedAt: string\n\t/** Last update timestamp */\n\tupdatedAt: string\n}\n\nexport interface RunResult {\n\t/** Exit code (0 = success) */\n\texitCode: number | null\n\t/** Status at completion */\n\tstatus: RunStatus\n\t/** Captured stdout */\n\tstdout: string | null\n\t/** Captured stderr */\n\tstderr: string | null\n\t/** Error message (OOMKilled, DeadlineExceeded, etc.) */\n\terrorMessage: string | null\n\t/** Wall-clock duration in milliseconds */\n\tdurationMs: number | null\n}\n\nexport interface RunLogsResult {\n\t/** Captured stdout (up to 1 MiB) */\n\tstdout: string\n\t/** Captured stderr (up to 1 MiB) */\n\tstderr: string\n\t/** Whether logs are still being captured (worker is running) */\n\tlive: boolean\n}\n\nexport interface ListRunsOptions {\n\t/** Filter by status */\n\tstatus?: RunStatus\n}\n\n/** OpenAI/Stripe-style list response */\nexport interface ListRunsResult {\n\tobject: 'list'\n\tdata: Run[]\n\t/** True if there are more results (limit was hit) */\n\thas_more: boolean\n}\n\n// ============================================================================\n// RunHandle — returned by RunsClient.run()\n// ============================================================================\n\nconst TERMINAL_STATUSES: ReadonlySet<RunStatus> = new Set([\n\t'succeeded',\n\t'failed',\n\t'cancelled',\n\t'timeout',\n])\nconst DEFAULT_POLL_INTERVAL_MS = 3_000\nconst DEFAULT_WAIT_TIMEOUT_MS = 7_200_000 // 2 hours\n\n/**\n * Handle to a running (or completed) worker.\n * Use `.wait()` to poll until completion, `.logs()` to stream logs, `.cancel()` to abort.\n */\nexport class RunHandle {\n\treadonly id: string\n\tprivate readonly config: SylphxConfig\n\n\tconstructor(id: string, config: SylphxConfig) {\n\t\tthis.id = id\n\t\tthis.config = config\n\t}\n\n\t// --------------------------------------------------------------------------\n\t// Status\n\t// --------------------------------------------------------------------------\n\n\t/**\n\t * Get the current status of this worker.\n\t */\n\tasync status(): Promise<Run> {\n\t\treturn callApi<Run>(this.config, `/workers/${this.id}`, { method: 'GET' })\n\t}\n\n\t// --------------------------------------------------------------------------\n\t// Wait (poll to completion)\n\t// --------------------------------------------------------------------------\n\n\t/**\n\t * Poll the worker until it reaches a terminal state (succeeded, failed, cancelled, timeout).\n\t *\n\t * @param options.pollIntervalMs - How often to poll in ms (default: 3000)\n\t * @param options.timeoutMs - Max time to wait before throwing (default: 7_200_000 = 2h)\n\t * @returns RunResult with exit code, status, stdout/stderr\n\t * @throws Error if waitTimeout is exceeded\n\t *\n\t * @example\n\t * ```typescript\n\t * const result = await worker.wait()\n\t * if (result.exitCode !== 0) {\n\t * throw new Error(`Worker failed: ${result.errorMessage ?? result.stderr}`)\n\t * }\n\t * ```\n\t */\n\tasync wait(options?: { pollIntervalMs?: number; timeoutMs?: number }): Promise<RunResult> {\n\t\tconst pollMs = options?.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS\n\t\tconst maxWaitMs = options?.timeoutMs ?? DEFAULT_WAIT_TIMEOUT_MS\n\t\tconst deadline = Date.now() + maxWaitMs\n\n\t\twhile (true) {\n\t\t\tconst run = await this.status()\n\n\t\t\tif (TERMINAL_STATUSES.has(run.status)) {\n\t\t\t\treturn {\n\t\t\t\t\texitCode: run.exitCode,\n\t\t\t\t\tstatus: run.status,\n\t\t\t\t\tstdout: run.stdout,\n\t\t\t\t\tstderr: run.stderr,\n\t\t\t\t\terrorMessage: run.errorMessage,\n\t\t\t\t\tdurationMs: run.durationMs,\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (Date.now() >= deadline) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Worker ${this.id} did not complete within ${maxWaitMs}ms (current status: ${run.status})`,\n\t\t\t\t)\n\t\t\t}\n\n\t\t\tawait sleep(pollMs)\n\t\t}\n\t}\n\n\t// --------------------------------------------------------------------------\n\t// Logs\n\t// --------------------------------------------------------------------------\n\n\t/**\n\t * Fetch captured logs for this worker.\n\t *\n\t * - For a running worker: returns live logs streamed from K8s (may be incomplete)\n\t * - For a completed worker: returns the full captured output stored in DB\n\t *\n\t * @example\n\t * ```typescript\n\t * const { stdout, stderr, live } = await worker.logs()\n\t * console.log(stdout)\n\t * if (live) console.log('(worker still running, logs may be incomplete)')\n\t * ```\n\t */\n\tasync logs(): Promise<RunLogsResult> {\n\t\treturn callApi<RunLogsResult>(this.config, `/workers/${this.id}/logs`, { method: 'GET' })\n\t}\n\n\t// --------------------------------------------------------------------------\n\t// Cancel\n\t// --------------------------------------------------------------------------\n\n\t/**\n\t * Cancel this worker.\n\t *\n\t * - If still pending: immediately cancelled (no K8s Job created)\n\t * - If running: K8s Job deleted (pod terminated)\n\t * - If already completed: no-op\n\t */\n\tasync cancel(): Promise<void> {\n\t\tawait callApi<{ success: boolean }>(this.config, `/workers/${this.id}`, { method: 'DELETE' })\n\t}\n}\n\n// ============================================================================\n// RunsClient\n// ============================================================================\n\n/**\n * Static client for the Workers BaaS service.\n *\n * @example\n * ```typescript\n * const config = createConfig({ secretKey: process.env.SYLPHX_SECRET_KEY!, ref: 'my-project' })\n *\n * // Run a worker and wait for completion\n * const result = await RunsClient.create(config, { ... }).then(w => w.wait())\n *\n * // Run N workers in parallel, wait for all\n * const handles = await Promise.all(folds.map(fold => RunsClient.create(config, { ... })))\n * const results = await Promise.all(handles.map(h => h.wait()))\n * ```\n */\nexport const RunsClient = {\n\t// --------------------------------------------------------------------------\n\t// Run\n\t// --------------------------------------------------------------------------\n\n\t/**\n\t * Spawn a new worker (K8s Job) and return a handle.\n\t *\n\t * The Job is created immediately and starts pulling the image.\n\t * Use the returned handle to `.wait()` for completion or `.cancel()`.\n\t *\n\t * @example\n\t * ```typescript\n\t * const run = await RunsClient.create(config, {\n\t * image: 'registry.sylphx.com/sylphx/trainer:abc123',\n\t * command: ['python', 'train.py', '--fold', '3'],\n\t * resources: { requests: { cpu: '4', memory: '16Gi' } },\n\t * volumeMounts: [{ volumeId: cacheVolumeId, mountPath: '/cache' }],\n\t * })\n\t * const result = await worker.wait()\n\t * ```\n\t */\n\tasync run(config: SylphxConfig, options: CreateRunOptions): Promise<RunHandle> {\n\t\tconst run = await callApi<{ id: string }>(config, '/runs', {\n\t\t\tmethod: 'POST',\n\t\t\tbody: {\n\t\t\t\timage: options.image,\n\t\t\t\tcommand: options.command,\n\t\t\t\tenv: options.env,\n\t\t\t\tresources: options.resources,\n\t\t\t\ttimeoutSeconds: options.timeoutSeconds ?? 3600,\n\t\t\t\tvolumeMounts: options.volumeMounts,\n\t\t\t},\n\t\t})\n\t\treturn new RunHandle(run.id, config)\n\t},\n\n\t// --------------------------------------------------------------------------\n\t// Get\n\t// --------------------------------------------------------------------------\n\n\t/**\n\t * Get a RunHandle for an existing run by ID.\n\t *\n\t * Useful for resuming monitoring across requests.\n\t *\n\t * @example\n\t * ```typescript\n\t * // Store the worker ID, retrieve later\n\t * const handle = RunsClient.fromId(config, storedWorkerId)\n\t * const result = await handle.wait()\n\t * ```\n\t */\n\tfromId(config: SylphxConfig, workerId: string): RunHandle {\n\t\treturn new RunHandle(workerId, config)\n\t},\n\n\t// --------------------------------------------------------------------------\n\t// List\n\t// --------------------------------------------------------------------------\n\n\t/**\n\t * List worker runs for this environment.\n\t *\n\t * @example\n\t * ```typescript\n\t * const { workers } = await RunsClient.list(config, { status: 'running' })\n\t * console.log(`${workers.length} workers currently running`)\n\t * ```\n\t */\n\tasync list(config: SylphxConfig, options?: ListRunsOptions): Promise<ListRunsResult> {\n\t\treturn callApi<ListRunsResult>(config, '/runs', {\n\t\t\tmethod: 'GET',\n\t\t\tquery: options?.status ? { status: options.status } : undefined,\n\t\t})\n\t},\n\n\t// --------------------------------------------------------------------------\n\t// Run-and-wait convenience\n\t// --------------------------------------------------------------------------\n\n\t/**\n\t * Spawn a worker and wait for it to complete in one call.\n\t *\n\t * Equivalent to `(await RunsClient.create(config, options)).wait(waitOptions)`.\n\t *\n\t * @example\n\t * ```typescript\n\t * const result = await RunsClient.runAndWait(config, {\n\t * image: 'registry.sylphx.com/sylphx/process:abc',\n\t * command: ['node', 'dist/process.js'],\n\t * })\n\t * if (result.exitCode !== 0) throw new Error(result.errorMessage ?? 'worker failed')\n\t * ```\n\t */\n\tasync runAndWait(\n\t\tconfig: SylphxConfig,\n\t\toptions: CreateRunOptions,\n\t\twaitOptions?: { pollIntervalMs?: number; timeoutMs?: number },\n\t): Promise<RunResult> {\n\t\tconst handle = await RunsClient.run(config, options)\n\t\treturn handle.wait(waitOptions)\n\t},\n}\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\nfunction sleep(ms: number): Promise<void> {\n\treturn new Promise((resolve) => setTimeout(resolve, ms))\n}\n\n// ── Backward-compat aliases (ADR-040) ────────────────────────────────────────\n/** @deprecated Use RunsClient */\nexport const WorkersClient = RunsClient\n/** @deprecated Use RunHandle */\nexport { RunHandle as WorkerHandle }\n/** @deprecated Use CreateRunOptions */\nexport type { CreateRunOptions as RunWorkerOptions }\n/** @deprecated Use Run */\nexport type { Run as WorkerRun }\n/** @deprecated Use RunLogsResult */\nexport type { RunLogsResult as WorkerLogsResult }\n/** @deprecated Use RunResult */\nexport type { RunResult as WorkerResult }\n/** @deprecated Use RunStatus */\nexport type { RunStatus as WorkerStatus }\n/** @deprecated Use RunResourceSpec */\nexport type { RunResourceSpec as WorkerResourceSpec }\n/** @deprecated Use RunVolumeMount */\nexport type { RunVolumeMount as WorkerVolumeMount }\n"],"mappings":"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","names":["createClient","createClient","isRetryableError","sleep"]}
1
+ {"version":3,"sources":["../src/constants.ts","../src/errors.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/iv.js","../../../node_modules/jose/dist/webapi/lib/check_iv_length.js","../../../node_modules/jose/dist/webapi/lib/check_cek_length.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/decrypt.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/aeskw.js","../../../node_modules/jose/dist/webapi/lib/digest.js","../../../node_modules/jose/dist/webapi/lib/ecdhes.js","../../../node_modules/jose/dist/webapi/lib/pbes2kw.js","../../../node_modules/jose/dist/webapi/lib/check_key_length.js","../../../node_modules/jose/dist/webapi/lib/rsaes.js","../../../node_modules/jose/dist/webapi/lib/cek.js","../../../node_modules/jose/dist/webapi/lib/asn1.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/encrypt.js","../../../node_modules/jose/dist/webapi/lib/aesgcmkw.js","../../../node_modules/jose/dist/webapi/lib/decrypt_key_management.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/jwe/flattened/decrypt.js","../../../node_modules/jose/dist/webapi/jwe/compact/decrypt.js","../../../node_modules/jose/dist/webapi/jwe/general/decrypt.js","../../../node_modules/jose/dist/webapi/lib/private_symbols.js","../../../node_modules/jose/dist/webapi/lib/key_to_jwk.js","../../../node_modules/jose/dist/webapi/key/export.js","../../../node_modules/jose/dist/webapi/lib/encrypt_key_management.js","../../../node_modules/jose/dist/webapi/jwe/flattened/encrypt.js","../../../node_modules/jose/dist/webapi/jwe/general/encrypt.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/jws/general/verify.js","../../../node_modules/jose/dist/webapi/lib/jwt_claims_set.js","../../../node_modules/jose/dist/webapi/jwt/verify.js","../../../node_modules/jose/dist/webapi/jwt/decrypt.js","../../../node_modules/jose/dist/webapi/jwe/compact/encrypt.js","../../../node_modules/jose/dist/webapi/lib/sign.js","../../../node_modules/jose/dist/webapi/jws/flattened/sign.js","../../../node_modules/jose/dist/webapi/jws/compact/sign.js","../../../node_modules/jose/dist/webapi/jws/general/sign.js","../../../node_modules/jose/dist/webapi/jwt/sign.js","../../../node_modules/jose/dist/webapi/jwt/encrypt.js","../../../node_modules/jose/dist/webapi/jwk/thumbprint.js","../../../node_modules/jose/dist/webapi/jwk/embedded.js","../../../node_modules/jose/dist/webapi/jwks/local.js","../../../node_modules/jose/dist/webapi/jwks/remote.js","../../../node_modules/jose/dist/webapi/jwt/unsecured.js","../../../node_modules/jose/dist/webapi/util/decode_protected_header.js","../../../node_modules/jose/dist/webapi/util/decode_jwt.js","../../../node_modules/jose/dist/webapi/key/generate_key_pair.js","../../../node_modules/jose/dist/webapi/key/generate_secret.js","../../../node_modules/jose/dist/webapi/index.js","../src/connection-url.ts","../src/config.ts","../src/debug.ts","../src/rest-client.ts","../src/key-validation.ts","../src/index.ts","../src/auth.ts","../src/audit.ts","../src/rate-limits.ts","../src/functions.ts","../src/realtime.ts","../src/realtime-admin.ts","../src/admin.ts","../src/analytics.ts","../src/ai.ts","../src/billing.ts","../src/storage.ts","../src/lib/notifications/service-worker.ts","../src/notifications.ts","../src/lib/triggers/index.ts","../src/lib/tasks/handler.ts","../src/lib/tasks/api-functions.ts","../src/flags.ts","../src/webhooks.ts","../src/email.ts","../src/consent.ts","../src/referrals.ts","../src/lib/engagement/types.ts","../src/engagement.ts","../src/orgs.ts","../src/permissions.ts","../src/roles.ts","../src/secrets.ts","../src/search.ts","../src/database.ts","../src/kv.ts","../src/deploy.ts","../src/monitoring.ts","../src/sandbox.ts","../src/workers.ts","../src/logs.ts","../src/misc.ts","../src/user.ts","../src/security.ts","../src/oauth.ts","../src/promo.ts"],"sourcesContent":["/**\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/**\n * Canonical environment variable name for the client connection URL.\n *\n * Format: sylphx://pk_prod_{hex}@slug.sylphx.com\n * Browser-safe (publishable key only).\n */\nexport const ENV_URL = 'SYLPHX_URL'\n\n/**\n * Canonical environment variable name for the Next.js public connection URL.\n *\n * Same format as ENV_URL, browser-safe.\n */\nexport const ENV_PUBLIC_URL = 'NEXT_PUBLIC_SYLPHX_URL'\n\n/**\n * Canonical environment variable name for the server secret connection URL.\n *\n * Format: sylphx://sk_prod_{hex}@slug.sylphx.com\n * Server-side only — never expose to client.\n */\nexport const ENV_SECRET_URL = 'SYLPHX_SECRET_URL'\n\n/**\n * @deprecated Use ENV_SECRET_URL. Kept for migration error messages only.\n */\nexport const ENV_SECRET_KEY = 'SYLPHX_SECRET_KEY'\n\n/**\n * Resolve the connection URL from environment variables.\n *\n * Checks SYLPHX_URL first, then NEXT_PUBLIC_SYLPHX_URL.\n */\nexport function resolveUrl(explicit?: string): string | undefined {\n\treturn explicit || process.env[ENV_URL] || process.env[ENV_PUBLIC_URL]\n}\n\n/**\n * Resolve the secret connection URL from environment variables.\n */\nexport function resolveSecretUrl(explicit?: string): string | undefined {\n\treturn explicit || process.env[ENV_SECRET_URL]\n}\n\n/**\n * SDK API path for the per-project subdomain-based SDK server.\n *\n * The full base URL is built as: https://{ref}.api.sylphx.com/v1\n */\nexport const SDK_API_PATH = `/v1`\nexport const SDK_API_VERSION = 'v1'\n\n/**\n * Default SDK API host.\n *\n * Management API: https://api.sylphx.com/v1/*\n * BaaS/SDK API: https://{ref}.api.sylphx.com/v1/*\n */\nexport const DEFAULT_SDK_API_HOST = 'api.sylphx.com'\nexport const DEFAULT_PLATFORM_URL = 'https://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.5.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 * Sylphx SDK Error Classes\n *\n * Typed error classes for better error handling and debugging.\n * Compatible with tRPC error codes and provides rich context.\n *\n * @example\n * ```typescript\n * import { SylphxError, isRetryableError, getErrorMessage } from '@sylphx/sdk'\n *\n * try {\n * await sylphx.auth.login.mutate({ email, password })\n * } catch (error) {\n * if (error instanceof SylphxError) {\n * console.log(error.code) // 'UNAUTHORIZED'\n * console.log(error.isRetryable) // false\n * }\n * if (isRetryableError(error)) {\n * // Safe to retry\n * }\n * }\n * ```\n */\n\nimport { BASE_RETRY_DELAY_MS, DEFAULT_TIMEOUT_MS, MAX_RETRY_DELAY_MS } from './constants'\n\n// ============================================================================\n// Error Codes (aligned with tRPC and HTTP semantics)\n// ============================================================================\n\nexport type SylphxErrorCode =\n\t// Client errors (4xx)\n\t| 'BAD_REQUEST' // 400 - Invalid input\n\t| 'UNAUTHORIZED' // 401 - Not authenticated\n\t| 'FORBIDDEN' // 403 - Not authorized\n\t| 'NOT_FOUND' // 404 - Resource not found\n\t| 'CONFLICT' // 409 - Resource conflict (e.g., duplicate)\n\t| 'PAYLOAD_TOO_LARGE' // 413 - Request too large\n\t| 'UNPROCESSABLE_ENTITY' // 422 - Validation failed\n\t| 'TOO_MANY_REQUESTS' // 429 - Rate limited\n\t| 'QUOTA_EXCEEDED' // 402/429 - Quota/plan limit exceeded\n\t// Server errors (5xx)\n\t| 'INTERNAL_SERVER_ERROR' // 500 - Server error\n\t| 'NOT_IMPLEMENTED' // 501 - Feature not available\n\t| 'BAD_GATEWAY' // 502 - Upstream error\n\t| 'SERVICE_UNAVAILABLE' // 503 - Temporarily unavailable\n\t| 'GATEWAY_TIMEOUT' // 504 - Upstream timeout\n\t// Network/Client errors\n\t| 'NETWORK_ERROR' // Network failure\n\t| 'TIMEOUT' // Request timeout\n\t| 'ABORTED' // Request aborted\n\t// SDK-specific\n\t| 'PARSE_ERROR' // JSON/response parse error\n\t| 'UNKNOWN' // Unknown error\n\n/**\n * Simplified semantic error codes (DX-friendly aliases).\n * Maps to the more granular SylphxErrorCode internally.\n *\n * @example\n * ```ts\n * if (SylphxError.isRateLimited(err)) {\n * console.log(`Retry after ${err.retryAfter}s`)\n * }\n * ```\n */\nexport type ErrorCode =\n\t| 'UNAUTHORIZED'\n\t| 'FORBIDDEN'\n\t| 'NOT_FOUND'\n\t| 'RATE_LIMITED'\n\t| 'QUOTA_EXCEEDED'\n\t| 'VALIDATION_ERROR'\n\t| 'NETWORK_ERROR'\n\t| 'UPSTREAM_ERROR'\n\t| 'INTERNAL_ERROR'\n\n/**\n * HTTP status code mapping for error codes\n */\nexport const ERROR_CODE_STATUS: Record<SylphxErrorCode, number> = {\n\tBAD_REQUEST: 400,\n\tUNAUTHORIZED: 401,\n\tFORBIDDEN: 403,\n\tNOT_FOUND: 404,\n\tCONFLICT: 409,\n\tPAYLOAD_TOO_LARGE: 413,\n\tUNPROCESSABLE_ENTITY: 422,\n\tTOO_MANY_REQUESTS: 429,\n\tQUOTA_EXCEEDED: 402,\n\tINTERNAL_SERVER_ERROR: 500,\n\tNOT_IMPLEMENTED: 501,\n\tBAD_GATEWAY: 502,\n\tSERVICE_UNAVAILABLE: 503,\n\tGATEWAY_TIMEOUT: 504,\n\tNETWORK_ERROR: 0,\n\tTIMEOUT: 0,\n\tABORTED: 0,\n\tPARSE_ERROR: 0,\n\tUNKNOWN: 0,\n}\n\n/**\n * Retryable error codes (safe to retry automatically)\n */\nexport const RETRYABLE_CODES: Set<SylphxErrorCode> = new Set([\n\t'NETWORK_ERROR',\n\t'TIMEOUT',\n\t'BAD_GATEWAY',\n\t'SERVICE_UNAVAILABLE',\n\t'GATEWAY_TIMEOUT',\n\t'TOO_MANY_REQUESTS', // With backoff\n\t'INTERNAL_SERVER_ERROR', // Sometimes transient\n])\n\n// ============================================================================\n// Error Classes\n// ============================================================================\n\nexport interface SylphxErrorOptions {\n\t/** Error code for programmatic handling */\n\tcode?: SylphxErrorCode\n\t/** HTTP status code (inferred from code if not provided) */\n\tstatus?: number\n\t/** Additional context data */\n\tdata?: Record<string, unknown>\n\t/** Original error that caused this */\n\tcause?: Error\n\t/** Retry-After header value (seconds) for rate limiting */\n\tretryAfter?: number\n}\n\n/**\n * Base error class for all Sylphx SDK errors\n *\n * @example\n * ```typescript\n * throw new SylphxError('Invalid email format', {\n * code: 'BAD_REQUEST',\n * data: { field: 'email' }\n * })\n * ```\n */\nexport class SylphxError extends Error {\n\t/** Error code for programmatic handling */\n\treadonly code: SylphxErrorCode\n\n\t/** HTTP status code */\n\treadonly status: number\n\n\t/** Additional context data */\n\treadonly data?: Record<string, unknown>\n\n\t/** Whether this error is safe to retry */\n\treadonly isRetryable: boolean\n\n\t/** Retry-After value in seconds (for rate limiting) */\n\treadonly retryAfter?: number\n\n\t/** Timestamp when error occurred */\n\treadonly timestamp: Date\n\n\tconstructor(message: string, options: SylphxErrorOptions = {}) {\n\t\tsuper(message, { cause: options.cause })\n\t\tthis.name = 'SylphxError'\n\t\tthis.code = options.code ?? 'UNKNOWN'\n\t\tthis.status = options.status ?? ERROR_CODE_STATUS[this.code]\n\t\tthis.data = options.data\n\t\tthis.isRetryable = RETRYABLE_CODES.has(this.code)\n\t\tthis.retryAfter = options.retryAfter\n\t\tthis.timestamp = new Date()\n\n\t\t// Maintain proper stack trace in V8\n\t\tif (Error.captureStackTrace) {\n\t\t\tError.captureStackTrace(this, SylphxError)\n\t\t}\n\t}\n\n\t// ============================================================================\n\t// Static Type Guards (DX helpers)\n\t// ============================================================================\n\n\t/**\n\t * Check if error is a rate-limit error (429 Too Many Requests)\n\t */\n\tstatic isRateLimited(err: unknown): err is SylphxError & { code: 'TOO_MANY_REQUESTS' } {\n\t\treturn err instanceof SylphxError && err.code === 'TOO_MANY_REQUESTS'\n\t}\n\n\t/**\n\t * Check if error is an account lockout error (too many failed login attempts).\n\t * When true, `error.data?.lockoutUntil` contains the ISO 8601 timestamp when the lockout expires.\n\t */\n\tstatic isAccountLocked(\n\t\terr: unknown,\n\t): err is SylphxError & { code: 'TOO_MANY_REQUESTS'; data: { lockoutUntil: string | null } } {\n\t\treturn (\n\t\t\terr instanceof SylphxError &&\n\t\t\terr.code === 'TOO_MANY_REQUESTS' &&\n\t\t\terr.data?.code === 'ACCOUNT_LOCKED'\n\t\t)\n\t}\n\n\t/**\n\t * Check if error is a quota exceeded error (plan limit reached)\n\t */\n\tstatic isQuotaExceeded(err: unknown): err is SylphxError & { code: 'QUOTA_EXCEEDED' } {\n\t\treturn err instanceof SylphxError && err.code === 'QUOTA_EXCEEDED'\n\t}\n\n\t/**\n\t * Check if error is an authentication error (401 Unauthorized)\n\t */\n\tstatic isUnauthorized(err: unknown): err is SylphxError & { code: 'UNAUTHORIZED' } {\n\t\treturn err instanceof SylphxError && err.code === 'UNAUTHORIZED'\n\t}\n\n\t/**\n\t * Check if error is a not-found error (404 Not Found)\n\t */\n\tstatic isNotFound(err: unknown): err is SylphxError & { code: 'NOT_FOUND' } {\n\t\treturn err instanceof SylphxError && err.code === 'NOT_FOUND'\n\t}\n\n\t/**\n\t * Check if error is an authorization error (403 Forbidden)\n\t */\n\tstatic isForbidden(err: unknown): err is SylphxError & { code: 'FORBIDDEN' } {\n\t\treturn err instanceof SylphxError && err.code === 'FORBIDDEN'\n\t}\n\n\t/**\n\t * Check if error is a validation error (422 Unprocessable Entity)\n\t */\n\tstatic isValidationError(err: unknown): err is SylphxError & { code: 'UNPROCESSABLE_ENTITY' } {\n\t\treturn err instanceof SylphxError && err.code === 'UNPROCESSABLE_ENTITY'\n\t}\n\n\t/**\n\t * Check if error is a network error (no response received)\n\t */\n\tstatic isNetworkError(err: unknown): err is SylphxError & { code: 'NETWORK_ERROR' } {\n\t\treturn err instanceof SylphxError && err.code === 'NETWORK_ERROR'\n\t}\n\n\t/**\n\t * Check if error is an upstream/gateway error (502/504)\n\t */\n\tstatic isUpstreamError(err: unknown): err is SylphxError {\n\t\treturn (\n\t\t\terr instanceof SylphxError &&\n\t\t\t(err.code === 'BAD_GATEWAY' ||\n\t\t\t\terr.code === 'GATEWAY_TIMEOUT' ||\n\t\t\t\terr.code === 'SERVICE_UNAVAILABLE')\n\t\t)\n\t}\n\n\t/**\n\t * Convert to JSON-serializable object\n\t */\n\ttoJSON(): Record<string, unknown> {\n\t\treturn {\n\t\t\tname: this.name,\n\t\t\tmessage: this.message,\n\t\t\tcode: this.code,\n\t\t\tstatus: this.status,\n\t\t\tdata: this.data,\n\t\t\tisRetryable: this.isRetryable,\n\t\t\tretryAfter: this.retryAfter,\n\t\t\ttimestamp: this.timestamp.toISOString(),\n\t\t}\n\t}\n}\n\n/**\n * Network-related errors (no response received)\n */\nexport class NetworkError extends SylphxError {\n\tconstructor(message = 'Network request failed', options?: Omit<SylphxErrorOptions, 'code'>) {\n\t\tsuper(message, { ...options, code: 'NETWORK_ERROR' })\n\t\tthis.name = 'NetworkError'\n\t}\n}\n\n/**\n * Request timeout errors\n */\nexport class TimeoutError extends SylphxError {\n\t/** Timeout duration in milliseconds */\n\treadonly timeout: number\n\n\tconstructor(timeout: number, options?: Omit<SylphxErrorOptions, 'code'>) {\n\t\tsuper(`Request timed out after ${timeout}ms`, {\n\t\t\t...options,\n\t\t\tcode: 'TIMEOUT',\n\t\t})\n\t\tthis.name = 'TimeoutError'\n\t\tthis.timeout = timeout\n\t}\n}\n\n/**\n * Authentication errors (401)\n */\nexport class AuthenticationError extends SylphxError {\n\tconstructor(message = 'Authentication required', options?: Omit<SylphxErrorOptions, 'code'>) {\n\t\tsuper(message, { ...options, code: 'UNAUTHORIZED' })\n\t\tthis.name = 'AuthenticationError'\n\t}\n}\n\n/**\n * Authorization errors (403)\n */\nexport class AuthorizationError extends SylphxError {\n\tconstructor(message = 'Permission denied', options?: Omit<SylphxErrorOptions, 'code'>) {\n\t\tsuper(message, { ...options, code: 'FORBIDDEN' })\n\t\tthis.name = 'AuthorizationError'\n\t}\n}\n\n/**\n * Validation errors (422)\n */\nexport class ValidationError extends SylphxError {\n\t/** Field-specific errors */\n\treadonly fieldErrors?: Record<string, string[]>\n\n\tconstructor(\n\t\tmessage: string,\n\t\toptions?: Omit<SylphxErrorOptions, 'code'> & {\n\t\t\tfieldErrors?: Record<string, string[]>\n\t\t},\n\t) {\n\t\tsuper(message, { ...options, code: 'UNPROCESSABLE_ENTITY' })\n\t\tthis.name = 'ValidationError'\n\t\tthis.fieldErrors = options?.fieldErrors\n\t}\n\n\t/**\n\t * Get error message for a specific field\n\t */\n\tgetFieldError(field: string): string | undefined {\n\t\treturn this.fieldErrors?.[field]?.[0]\n\t}\n}\n\n/**\n * Rate limit metadata (Stripe SDK pattern)\n */\nexport interface RateLimitInfo {\n\t/** Maximum requests allowed in window */\n\tlimit?: number\n\t/** Remaining requests in current window */\n\tremaining?: number\n\t/** Unix timestamp (seconds) when limit resets */\n\tresetAt?: number\n\t/** Seconds until limit resets (Retry-After header) */\n\tretryAfter?: number\n}\n\n/**\n * Rate limit errors (429)\n *\n * Provides full rate limit metadata for consumer apps to implement\n * proper backoff UI (countdown timers, retry buttons, etc.)\n *\n * @example\n * ```typescript\n * try {\n * await sendEmail(config, options)\n * } catch (error) {\n * if (error instanceof RateLimitError) {\n * const waitSeconds = error.retryAfter ?? 60\n * console.log(`Rate limited. Retry after ${waitSeconds}s`)\n * console.log(`Remaining: ${error.remaining}/${error.limit}`)\n * console.log(`Resets at: ${new Date(error.resetAt! * 1000)}`)\n * }\n * }\n * ```\n */\nexport class RateLimitError extends SylphxError {\n\t/** Maximum requests allowed in window */\n\treadonly limit?: number\n\n\t/** Remaining requests in current window */\n\treadonly remaining?: number\n\n\t/** Unix timestamp (seconds) when limit resets */\n\treadonly resetAt?: number\n\n\tconstructor(\n\t\tmessage = 'Too many requests',\n\t\toptions?: Omit<SylphxErrorOptions, 'code'> & RateLimitInfo,\n\t) {\n\t\tsuper(message, { ...options, code: 'TOO_MANY_REQUESTS' })\n\t\tthis.name = 'RateLimitError'\n\t\tthis.limit = options?.limit\n\t\tthis.remaining = options?.remaining\n\t\tthis.resetAt = options?.resetAt\n\t}\n\n\t/**\n\t * Get Date when rate limit resets\n\t */\n\tgetResetDate(): Date | undefined {\n\t\treturn this.resetAt ? new Date(this.resetAt * 1000) : undefined\n\t}\n\n\t/**\n\t * Get human-readable retry message\n\t */\n\tgetRetryMessage(): string {\n\t\tif (this.retryAfter) {\n\t\t\treturn `Please retry after ${this.retryAfter} seconds`\n\t\t}\n\t\tif (this.resetAt) {\n\t\t\tconst seconds = Math.max(0, this.resetAt - Math.floor(Date.now() / 1000))\n\t\t\treturn `Rate limit resets in ${seconds} seconds`\n\t\t}\n\t\treturn 'Please wait before retrying'\n\t}\n}\n\n/**\n * Resource not found errors (404)\n */\nexport class NotFoundError extends SylphxError {\n\t/** Type of resource that wasn't found */\n\treadonly resourceType?: string\n\n\t/** ID of the resource that wasn't found */\n\treadonly resourceId?: string\n\n\tconstructor(\n\t\tmessage = 'Resource not found',\n\t\toptions?: Omit<SylphxErrorOptions, 'code'> & {\n\t\t\tresourceType?: string\n\t\t\tresourceId?: string\n\t\t},\n\t) {\n\t\tsuper(message, { ...options, code: 'NOT_FOUND' })\n\t\tthis.name = 'NotFoundError'\n\t\tthis.resourceType = options?.resourceType\n\t\tthis.resourceId = options?.resourceId\n\t}\n}\n\n// ============================================================================\n// Utility Functions\n// ============================================================================\n\n/**\n * Check if an error is a Sylphx SDK error\n */\nexport function isSylphxError(error: unknown): error is SylphxError {\n\treturn error instanceof SylphxError\n}\n\n/**\n * Check if an error is safe to retry\n */\nexport function isRetryableError(error: unknown): boolean {\n\tif (error instanceof SylphxError) {\n\t\treturn error.isRetryable\n\t}\n\n\t// Check for network errors\n\tif (error instanceof Error) {\n\t\tconst message = error.message.toLowerCase()\n\t\tconst name = error.name.toLowerCase()\n\n\t\t// Network errors\n\t\tif (name === 'typeerror' && message.includes('fetch')) return true\n\t\tif (name === 'networkerror') return true\n\n\t\t// Timeout patterns\n\t\tif (message.includes('timeout')) return true\n\t\tif (message.includes('timed out')) return true\n\n\t\t// Connection errors\n\t\tif (message.includes('econnrefused')) return true\n\t\tif (message.includes('econnreset')) return true\n\t\tif (message.includes('socket')) return true\n\n\t\t// Server errors that might be transient\n\t\tif (message.includes('502')) return true\n\t\tif (message.includes('503')) return true\n\t\tif (message.includes('504')) return true\n\t}\n\n\treturn false\n}\n\n/**\n * Extract error message from any error type\n */\nexport function getErrorMessage(error: unknown): string {\n\tif (error instanceof Error) {\n\t\treturn error.message\n\t}\n\tif (typeof error === 'string') {\n\t\treturn error\n\t}\n\treturn 'An unknown error occurred'\n}\n\n/**\n * Get error code from any error type\n */\nexport function getErrorCode(error: unknown): SylphxErrorCode {\n\tif (error instanceof SylphxError) {\n\t\treturn error.code\n\t}\n\treturn 'UNKNOWN'\n}\n\n/**\n * Convert any error to SylphxError\n */\nexport function toSylphxError(error: unknown): SylphxError {\n\tif (error instanceof SylphxError) {\n\t\treturn error\n\t}\n\n\tif (error instanceof Error) {\n\t\t// Try to infer error type from message/name\n\t\tconst message = error.message.toLowerCase()\n\t\tconst name = error.name.toLowerCase()\n\n\t\t// Network errors\n\t\tif (name === 'typeerror' && message.includes('fetch')) {\n\t\t\treturn new NetworkError(error.message, { cause: error })\n\t\t}\n\t\tif (name === 'aborterror' || message.includes('aborted')) {\n\t\t\treturn new SylphxError(error.message, { code: 'ABORTED', cause: error })\n\t\t}\n\n\t\t// Timeout\n\t\tif (message.includes('timeout')) {\n\t\t\treturn new TimeoutError(DEFAULT_TIMEOUT_MS, { cause: error })\n\t\t}\n\n\t\t// HTTP status codes in message\n\t\tif (message.includes('401') || message.includes('unauthorized')) {\n\t\t\treturn new AuthenticationError(error.message, { cause: error })\n\t\t}\n\t\tif (message.includes('403') || message.includes('forbidden')) {\n\t\t\treturn new AuthorizationError(error.message, { cause: error })\n\t\t}\n\t\tif (message.includes('404') || message.includes('not found')) {\n\t\t\treturn new NotFoundError(error.message, { cause: error })\n\t\t}\n\t\tif (message.includes('429') || message.includes('rate limit')) {\n\t\t\treturn new RateLimitError(error.message, { cause: error })\n\t\t}\n\n\t\treturn new SylphxError(error.message, { cause: error })\n\t}\n\n\treturn new SylphxError(getErrorMessage(error))\n}\n\n/**\n * Calculate exponential backoff delay with jitter\n *\n * @param attempt - Retry attempt number (0-indexed)\n * @param baseDelay - Base delay in milliseconds (default: 1000)\n * @param maxDelay - Maximum delay in milliseconds (default: 30000)\n * @returns Delay in milliseconds with jitter\n */\nexport function exponentialBackoff(\n\tattempt: number,\n\tbaseDelay = BASE_RETRY_DELAY_MS,\n\tmaxDelay = MAX_RETRY_DELAY_MS,\n): number {\n\t// Calculate exponential delay: baseDelay * 2^attempt\n\tconst exponentialDelay = baseDelay * 2 ** attempt\n\n\t// Cap at maxDelay\n\tconst cappedDelay = Math.min(exponentialDelay, maxDelay)\n\n\t// Add jitter (±25% randomness)\n\tconst jitter = cappedDelay * 0.25 * (Math.random() * 2 - 1)\n\n\treturn Math.round(cappedDelay + jitter)\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","import { JOSENotSupported } from '../util/errors.js';\nexport function bitLength(alg) {\n switch (alg) {\n case 'A128GCM':\n case 'A128GCMKW':\n case 'A192GCM':\n case 'A192GCMKW':\n case 'A256GCM':\n case 'A256GCMKW':\n return 96;\n case 'A128CBC-HS256':\n case 'A192CBC-HS384':\n case 'A256CBC-HS512':\n return 128;\n default:\n throw new JOSENotSupported(`Unsupported JWE Algorithm: ${alg}`);\n }\n}\nexport const generateIv = (alg) => crypto.getRandomValues(new Uint8Array(bitLength(alg) >> 3));\n","import { JWEInvalid } from '../util/errors.js';\nimport { bitLength } from './iv.js';\nexport function checkIvLength(enc, iv) {\n if (iv.length << 3 !== bitLength(enc)) {\n throw new JWEInvalid('Invalid Initialization Vector length');\n }\n}\n","import { JWEInvalid } from '../util/errors.js';\nexport function checkCekLength(cek, expected) {\n const actual = cek.byteLength << 3;\n if (actual !== expected) {\n throw new JWEInvalid(`Invalid Content Encryption Key length. Expected ${expected} bits, got ${actual} bits`);\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","import { concat, uint64be } from './buffer_utils.js';\nimport { checkIvLength } from './check_iv_length.js';\nimport { checkCekLength } from './check_cek_length.js';\nimport { JOSENotSupported, JWEDecryptionFailed, JWEInvalid } from '../util/errors.js';\nimport { checkEncCryptoKey } from './crypto_key.js';\nimport { invalidKeyInput } from './invalid_key_input.js';\nimport { isCryptoKey } from './is_key_like.js';\nasync function timingSafeEqual(a, b) {\n if (!(a instanceof Uint8Array)) {\n throw new TypeError('First argument must be a buffer');\n }\n if (!(b instanceof Uint8Array)) {\n throw new TypeError('Second argument must be a buffer');\n }\n const algorithm = { name: 'HMAC', hash: 'SHA-256' };\n const key = (await crypto.subtle.generateKey(algorithm, false, ['sign']));\n const aHmac = new Uint8Array(await crypto.subtle.sign(algorithm, key, a));\n const bHmac = new Uint8Array(await crypto.subtle.sign(algorithm, key, b));\n let out = 0;\n let i = -1;\n while (++i < 32) {\n out |= aHmac[i] ^ bHmac[i];\n }\n return out === 0;\n}\nasync function cbcDecrypt(enc, cek, ciphertext, iv, tag, aad) {\n if (!(cek instanceof Uint8Array)) {\n throw new TypeError(invalidKeyInput(cek, 'Uint8Array'));\n }\n const keySize = parseInt(enc.slice(1, 4), 10);\n const encKey = await crypto.subtle.importKey('raw', cek.subarray(keySize >> 3), 'AES-CBC', false, ['decrypt']);\n const macKey = await crypto.subtle.importKey('raw', cek.subarray(0, keySize >> 3), {\n hash: `SHA-${keySize << 1}`,\n name: 'HMAC',\n }, false, ['sign']);\n const macData = concat(aad, iv, ciphertext, uint64be(aad.length << 3));\n const expectedTag = new Uint8Array((await crypto.subtle.sign('HMAC', macKey, macData)).slice(0, keySize >> 3));\n let macCheckPassed;\n try {\n macCheckPassed = await timingSafeEqual(tag, expectedTag);\n }\n catch {\n }\n if (!macCheckPassed) {\n throw new JWEDecryptionFailed();\n }\n let plaintext;\n try {\n plaintext = new Uint8Array(await crypto.subtle.decrypt({ iv: iv, name: 'AES-CBC' }, encKey, ciphertext));\n }\n catch {\n }\n if (!plaintext) {\n throw new JWEDecryptionFailed();\n }\n return plaintext;\n}\nasync function gcmDecrypt(enc, cek, ciphertext, iv, tag, aad) {\n let encKey;\n if (cek instanceof Uint8Array) {\n encKey = await crypto.subtle.importKey('raw', cek, 'AES-GCM', false, ['decrypt']);\n }\n else {\n checkEncCryptoKey(cek, enc, 'decrypt');\n encKey = cek;\n }\n try {\n return new Uint8Array(await crypto.subtle.decrypt({\n additionalData: aad,\n iv: iv,\n name: 'AES-GCM',\n tagLength: 128,\n }, encKey, concat(ciphertext, tag)));\n }\n catch {\n throw new JWEDecryptionFailed();\n }\n}\nexport async function decrypt(enc, cek, ciphertext, iv, tag, aad) {\n if (!isCryptoKey(cek) && !(cek instanceof Uint8Array)) {\n throw new TypeError(invalidKeyInput(cek, 'CryptoKey', 'KeyObject', 'Uint8Array', 'JSON Web Key'));\n }\n if (!iv) {\n throw new JWEInvalid('JWE Initialization Vector missing');\n }\n if (!tag) {\n throw new JWEInvalid('JWE Authentication Tag missing');\n }\n checkIvLength(enc, iv);\n switch (enc) {\n case 'A128CBC-HS256':\n case 'A192CBC-HS384':\n case 'A256CBC-HS512':\n if (cek instanceof Uint8Array)\n checkCekLength(cek, parseInt(enc.slice(-3), 10));\n return cbcDecrypt(enc, cek, ciphertext, iv, tag, aad);\n case 'A128GCM':\n case 'A192GCM':\n case 'A256GCM':\n if (cek instanceof Uint8Array)\n checkCekLength(cek, parseInt(enc.slice(1, 4), 10));\n return gcmDecrypt(enc, cek, ciphertext, iv, tag, aad);\n default:\n throw new JOSENotSupported('Unsupported JWE Content Encryption Algorithm');\n }\n}\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","import { checkEncCryptoKey } from './crypto_key.js';\nfunction checkKeySize(key, alg) {\n if (key.algorithm.length !== parseInt(alg.slice(1, 4), 10)) {\n throw new TypeError(`Invalid key size for alg: ${alg}`);\n }\n}\nfunction getCryptoKey(key, alg, usage) {\n if (key instanceof Uint8Array) {\n return crypto.subtle.importKey('raw', key, 'AES-KW', true, [usage]);\n }\n checkEncCryptoKey(key, alg, usage);\n return key;\n}\nexport async function wrap(alg, key, cek) {\n const cryptoKey = await getCryptoKey(key, alg, 'wrapKey');\n checkKeySize(cryptoKey, alg);\n const cryptoKeyCek = await crypto.subtle.importKey('raw', cek, { hash: 'SHA-256', name: 'HMAC' }, true, ['sign']);\n return new Uint8Array(await crypto.subtle.wrapKey('raw', cryptoKeyCek, cryptoKey, 'AES-KW'));\n}\nexport async function unwrap(alg, key, encryptedKey) {\n const cryptoKey = await getCryptoKey(key, alg, 'unwrapKey');\n checkKeySize(cryptoKey, alg);\n const cryptoKeyCek = await crypto.subtle.unwrapKey('raw', encryptedKey, cryptoKey, 'AES-KW', { hash: 'SHA-256', name: 'HMAC' }, true, ['sign']);\n return new Uint8Array(await crypto.subtle.exportKey('raw', cryptoKeyCek));\n}\n","export async function digest(algorithm, data) {\n const subtleDigest = `SHA-${algorithm.slice(-3)}`;\n return new Uint8Array(await crypto.subtle.digest(subtleDigest, data));\n}\n","import { encode, concat, uint32be } from './buffer_utils.js';\nimport { checkEncCryptoKey } from './crypto_key.js';\nimport { digest } from './digest.js';\nfunction lengthAndInput(input) {\n return concat(uint32be(input.length), input);\n}\nasync function concatKdf(Z, L, OtherInfo) {\n const dkLen = L >> 3;\n const hashLen = 32;\n const reps = Math.ceil(dkLen / hashLen);\n const dk = new Uint8Array(reps * hashLen);\n for (let i = 1; i <= reps; i++) {\n const hashInput = new Uint8Array(4 + Z.length + OtherInfo.length);\n hashInput.set(uint32be(i), 0);\n hashInput.set(Z, 4);\n hashInput.set(OtherInfo, 4 + Z.length);\n const hashResult = await digest('sha256', hashInput);\n dk.set(hashResult, (i - 1) * hashLen);\n }\n return dk.slice(0, dkLen);\n}\nexport async function deriveKey(publicKey, privateKey, algorithm, keyLength, apu = new Uint8Array(), apv = new Uint8Array()) {\n checkEncCryptoKey(publicKey, 'ECDH');\n checkEncCryptoKey(privateKey, 'ECDH', 'deriveBits');\n const algorithmID = lengthAndInput(encode(algorithm));\n const partyUInfo = lengthAndInput(apu);\n const partyVInfo = lengthAndInput(apv);\n const suppPubInfo = uint32be(keyLength);\n const suppPrivInfo = new Uint8Array();\n const otherInfo = concat(algorithmID, partyUInfo, partyVInfo, suppPubInfo, suppPrivInfo);\n const Z = new Uint8Array(await crypto.subtle.deriveBits({\n name: publicKey.algorithm.name,\n public: publicKey,\n }, privateKey, getEcdhBitLength(publicKey)));\n return concatKdf(Z, keyLength, otherInfo);\n}\nfunction getEcdhBitLength(publicKey) {\n if (publicKey.algorithm.name === 'X25519') {\n return 256;\n }\n return (Math.ceil(parseInt(publicKey.algorithm.namedCurve.slice(-3), 10) / 8) << 3);\n}\nexport function allowed(key) {\n switch (key.algorithm.namedCurve) {\n case 'P-256':\n case 'P-384':\n case 'P-521':\n return true;\n default:\n return key.algorithm.name === 'X25519';\n }\n}\n","import { encode as b64u } from '../util/base64url.js';\nimport * as aeskw from './aeskw.js';\nimport { checkEncCryptoKey } from './crypto_key.js';\nimport { concat, encode } from './buffer_utils.js';\nimport { JWEInvalid } from '../util/errors.js';\nfunction getCryptoKey(key, alg) {\n if (key instanceof Uint8Array) {\n return crypto.subtle.importKey('raw', key, 'PBKDF2', false, [\n 'deriveBits',\n ]);\n }\n checkEncCryptoKey(key, alg, 'deriveBits');\n return key;\n}\nconst concatSalt = (alg, p2sInput) => concat(encode(alg), Uint8Array.of(0x00), p2sInput);\nasync function deriveKey(p2s, alg, p2c, key) {\n if (!(p2s instanceof Uint8Array) || p2s.length < 8) {\n throw new JWEInvalid('PBES2 Salt Input must be 8 or more octets');\n }\n const salt = concatSalt(alg, p2s);\n const keylen = parseInt(alg.slice(13, 16), 10);\n const subtleAlg = {\n hash: `SHA-${alg.slice(8, 11)}`,\n iterations: p2c,\n name: 'PBKDF2',\n salt,\n };\n const cryptoKey = await getCryptoKey(key, alg);\n return new Uint8Array(await crypto.subtle.deriveBits(subtleAlg, cryptoKey, keylen));\n}\nexport async function wrap(alg, key, cek, p2c = 2048, p2s = crypto.getRandomValues(new Uint8Array(16))) {\n const derived = await deriveKey(p2s, alg, p2c, key);\n const encryptedKey = await aeskw.wrap(alg.slice(-6), derived, cek);\n return { encryptedKey, p2c, p2s: b64u(p2s) };\n}\nexport async function unwrap(alg, key, encryptedKey, p2c, p2s) {\n const derived = await deriveKey(p2s, alg, p2c, key);\n return aeskw.unwrap(alg.slice(-6), derived, encryptedKey);\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 { checkEncCryptoKey } from './crypto_key.js';\nimport { checkKeyLength } from './check_key_length.js';\nimport { JOSENotSupported } from '../util/errors.js';\nconst subtleAlgorithm = (alg) => {\n switch (alg) {\n case 'RSA-OAEP':\n case 'RSA-OAEP-256':\n case 'RSA-OAEP-384':\n case 'RSA-OAEP-512':\n return 'RSA-OAEP';\n default:\n throw new JOSENotSupported(`alg ${alg} is not supported either by JOSE or your javascript runtime`);\n }\n};\nexport async function encrypt(alg, key, cek) {\n checkEncCryptoKey(key, alg, 'encrypt');\n checkKeyLength(alg, key);\n return new Uint8Array(await crypto.subtle.encrypt(subtleAlgorithm(alg), key, cek));\n}\nexport async function decrypt(alg, key, encryptedKey) {\n checkEncCryptoKey(key, alg, 'decrypt');\n checkKeyLength(alg, key);\n return new Uint8Array(await crypto.subtle.decrypt(subtleAlgorithm(alg), key, encryptedKey));\n}\n","import { JOSENotSupported } from '../util/errors.js';\nexport function cekLength(alg) {\n switch (alg) {\n case 'A128GCM':\n return 128;\n case 'A192GCM':\n return 192;\n case 'A256GCM':\n case 'A128CBC-HS256':\n return 256;\n case 'A192CBC-HS384':\n return 384;\n case 'A256CBC-HS512':\n return 512;\n default:\n throw new JOSENotSupported(`Unsupported JWE Algorithm: ${alg}`);\n }\n}\nexport const generateCek = (alg) => crypto.getRandomValues(new Uint8Array(cekLength(alg) >> 3));\n","import { invalidKeyInput } from './invalid_key_input.js';\nimport { encodeBase64, decodeBase64 } from '../lib/base64.js';\nimport { JOSENotSupported } from '../util/errors.js';\nimport { isCryptoKey, isKeyObject } from './is_key_like.js';\nconst formatPEM = (b64, descriptor) => {\n const newlined = (b64.match(/.{1,64}/g) || []).join('\\n');\n return `-----BEGIN ${descriptor}-----\\n${newlined}\\n-----END ${descriptor}-----`;\n};\nconst genericExport = async (keyType, keyFormat, key) => {\n if (isKeyObject(key)) {\n if (key.type !== keyType) {\n throw new TypeError(`key is not a ${keyType} key`);\n }\n return key.export({ format: 'pem', type: keyFormat });\n }\n if (!isCryptoKey(key)) {\n throw new TypeError(invalidKeyInput(key, 'CryptoKey', 'KeyObject'));\n }\n if (!key.extractable) {\n throw new TypeError('CryptoKey is not extractable');\n }\n if (key.type !== keyType) {\n throw new TypeError(`key is not a ${keyType} key`);\n }\n return formatPEM(encodeBase64(new Uint8Array(await crypto.subtle.exportKey(keyFormat, key))), `${keyType.toUpperCase()} KEY`);\n};\nexport const toSPKI = (key) => genericExport('public', 'spki', key);\nexport const toPKCS8 = (key) => genericExport('private', 'pkcs8', key);\nconst bytesEqual = (a, b) => {\n if (a.byteLength !== b.length)\n return false;\n for (let i = 0; i < a.byteLength; i++) {\n if (a[i] !== b[i])\n return false;\n }\n return true;\n};\nconst createASN1State = (data) => ({ data, pos: 0 });\nconst parseLength = (state) => {\n const first = state.data[state.pos++];\n if (first & 0x80) {\n const lengthOfLen = first & 0x7f;\n let length = 0;\n for (let i = 0; i < lengthOfLen; i++) {\n length = (length << 8) | state.data[state.pos++];\n }\n return length;\n }\n return first;\n};\nconst skipElement = (state, count = 1) => {\n if (count <= 0)\n return;\n state.pos++;\n const length = parseLength(state);\n state.pos += length;\n if (count > 1) {\n skipElement(state, count - 1);\n }\n};\nconst expectTag = (state, expectedTag, errorMessage) => {\n if (state.data[state.pos++] !== expectedTag) {\n throw new Error(errorMessage);\n }\n};\nconst getSubarray = (state, length) => {\n const result = state.data.subarray(state.pos, state.pos + length);\n state.pos += length;\n return result;\n};\nconst parseAlgorithmOID = (state) => {\n expectTag(state, 0x06, 'Expected algorithm OID');\n const oidLen = parseLength(state);\n return getSubarray(state, oidLen);\n};\nfunction parsePKCS8Header(state) {\n expectTag(state, 0x30, 'Invalid PKCS#8 structure');\n parseLength(state);\n expectTag(state, 0x02, 'Expected version field');\n const verLen = parseLength(state);\n state.pos += verLen;\n expectTag(state, 0x30, 'Expected algorithm identifier');\n const algIdLen = parseLength(state);\n const algIdStart = state.pos;\n return { algIdStart, algIdLength: algIdLen };\n}\nfunction parseSPKIHeader(state) {\n expectTag(state, 0x30, 'Invalid SPKI structure');\n parseLength(state);\n expectTag(state, 0x30, 'Expected algorithm identifier');\n const algIdLen = parseLength(state);\n const algIdStart = state.pos;\n return { algIdStart, algIdLength: algIdLen };\n}\nconst parseECAlgorithmIdentifier = (state) => {\n const algOid = parseAlgorithmOID(state);\n if (bytesEqual(algOid, [0x2b, 0x65, 0x6e])) {\n return 'X25519';\n }\n if (!bytesEqual(algOid, [0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01])) {\n throw new Error('Unsupported key algorithm');\n }\n expectTag(state, 0x06, 'Expected curve OID');\n const curveOidLen = parseLength(state);\n const curveOid = getSubarray(state, curveOidLen);\n for (const { name, oid } of [\n { name: 'P-256', oid: [0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07] },\n { name: 'P-384', oid: [0x2b, 0x81, 0x04, 0x00, 0x22] },\n { name: 'P-521', oid: [0x2b, 0x81, 0x04, 0x00, 0x23] },\n ]) {\n if (bytesEqual(curveOid, oid)) {\n return name;\n }\n }\n throw new Error('Unsupported named curve');\n};\nconst genericImport = async (keyFormat, keyData, alg, options) => {\n let algorithm;\n let keyUsages;\n const isPublic = keyFormat === 'spki';\n const getSigUsages = () => (isPublic ? ['verify'] : ['sign']);\n const getEncUsages = () => isPublic ? ['encrypt', 'wrapKey'] : ['decrypt', 'unwrapKey'];\n switch (alg) {\n case 'PS256':\n case 'PS384':\n case 'PS512':\n algorithm = { name: 'RSA-PSS', hash: `SHA-${alg.slice(-3)}` };\n keyUsages = getSigUsages();\n break;\n case 'RS256':\n case 'RS384':\n case 'RS512':\n algorithm = { name: 'RSASSA-PKCS1-v1_5', hash: `SHA-${alg.slice(-3)}` };\n keyUsages = getSigUsages();\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(alg.slice(-3), 10) || 1}`,\n };\n keyUsages = getEncUsages();\n break;\n case 'ES256':\n case 'ES384':\n case 'ES512': {\n const curveMap = { ES256: 'P-256', ES384: 'P-384', ES512: 'P-521' };\n algorithm = { name: 'ECDSA', namedCurve: curveMap[alg] };\n keyUsages = getSigUsages();\n break;\n }\n case 'ECDH-ES':\n case 'ECDH-ES+A128KW':\n case 'ECDH-ES+A192KW':\n case 'ECDH-ES+A256KW': {\n try {\n const namedCurve = options.getNamedCurve(keyData);\n algorithm = namedCurve === 'X25519' ? { name: 'X25519' } : { name: 'ECDH', namedCurve };\n }\n catch (cause) {\n throw new JOSENotSupported('Invalid or unsupported key format');\n }\n keyUsages = isPublic ? [] : ['deriveBits'];\n break;\n }\n case 'Ed25519':\n case 'EdDSA':\n algorithm = { name: 'Ed25519' };\n keyUsages = getSigUsages();\n break;\n case 'ML-DSA-44':\n case 'ML-DSA-65':\n case 'ML-DSA-87':\n algorithm = { name: alg };\n keyUsages = getSigUsages();\n break;\n default:\n throw new JOSENotSupported('Invalid or unsupported \"alg\" (Algorithm) value');\n }\n return crypto.subtle.importKey(keyFormat, keyData, algorithm, options?.extractable ?? (isPublic ? true : false), keyUsages);\n};\nconst processPEMData = (pem, pattern) => {\n return decodeBase64(pem.replace(pattern, ''));\n};\nexport const fromPKCS8 = (pem, alg, options) => {\n const keyData = processPEMData(pem, /(?:-----(?:BEGIN|END) PRIVATE KEY-----|\\s)/g);\n let opts = options;\n if (alg?.startsWith?.('ECDH-ES')) {\n opts ||= {};\n opts.getNamedCurve = (keyData) => {\n const state = createASN1State(keyData);\n parsePKCS8Header(state);\n return parseECAlgorithmIdentifier(state);\n };\n }\n return genericImport('pkcs8', keyData, alg, opts);\n};\nexport const fromSPKI = (pem, alg, options) => {\n const keyData = processPEMData(pem, /(?:-----(?:BEGIN|END) PUBLIC KEY-----|\\s)/g);\n let opts = options;\n if (alg?.startsWith?.('ECDH-ES')) {\n opts ||= {};\n opts.getNamedCurve = (keyData) => {\n const state = createASN1State(keyData);\n parseSPKIHeader(state);\n return parseECAlgorithmIdentifier(state);\n };\n }\n return genericImport('spki', keyData, alg, opts);\n};\nfunction spkiFromX509(buf) {\n const state = createASN1State(buf);\n expectTag(state, 0x30, 'Invalid certificate structure');\n parseLength(state);\n expectTag(state, 0x30, 'Invalid tbsCertificate structure');\n parseLength(state);\n if (buf[state.pos] === 0xa0) {\n skipElement(state, 6);\n }\n else {\n skipElement(state, 5);\n }\n const spkiStart = state.pos;\n expectTag(state, 0x30, 'Invalid SPKI structure');\n const spkiContentLen = parseLength(state);\n return buf.subarray(spkiStart, spkiStart + spkiContentLen + (state.pos - spkiStart));\n}\nfunction extractX509SPKI(x509) {\n const derBytes = processPEMData(x509, /(?:-----(?:BEGIN|END) CERTIFICATE-----|\\s)/g);\n return spkiFromX509(derBytes);\n}\nexport const fromX509 = (pem, alg, options) => {\n let spki;\n try {\n spki = extractX509SPKI(pem);\n }\n catch (cause) {\n throw new TypeError('Failed to parse the X.509 certificate', { cause });\n }\n return fromSPKI(formatPEM(encodeBase64(spki), 'PUBLIC KEY'), alg, options);\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 { concat, uint64be } from './buffer_utils.js';\nimport { checkIvLength } from './check_iv_length.js';\nimport { checkCekLength } from './check_cek_length.js';\nimport { checkEncCryptoKey } from './crypto_key.js';\nimport { invalidKeyInput } from './invalid_key_input.js';\nimport { generateIv } from './iv.js';\nimport { JOSENotSupported } from '../util/errors.js';\nimport { isCryptoKey } from './is_key_like.js';\nasync function cbcEncrypt(enc, plaintext, cek, iv, aad) {\n if (!(cek instanceof Uint8Array)) {\n throw new TypeError(invalidKeyInput(cek, 'Uint8Array'));\n }\n const keySize = parseInt(enc.slice(1, 4), 10);\n const encKey = await crypto.subtle.importKey('raw', cek.subarray(keySize >> 3), 'AES-CBC', false, ['encrypt']);\n const macKey = await crypto.subtle.importKey('raw', cek.subarray(0, keySize >> 3), {\n hash: `SHA-${keySize << 1}`,\n name: 'HMAC',\n }, false, ['sign']);\n const ciphertext = new Uint8Array(await crypto.subtle.encrypt({\n iv: iv,\n name: 'AES-CBC',\n }, encKey, plaintext));\n const macData = concat(aad, iv, ciphertext, uint64be(aad.length << 3));\n const tag = new Uint8Array((await crypto.subtle.sign('HMAC', macKey, macData)).slice(0, keySize >> 3));\n return { ciphertext, tag, iv };\n}\nasync function gcmEncrypt(enc, plaintext, cek, iv, aad) {\n let encKey;\n if (cek instanceof Uint8Array) {\n encKey = await crypto.subtle.importKey('raw', cek, 'AES-GCM', false, ['encrypt']);\n }\n else {\n checkEncCryptoKey(cek, enc, 'encrypt');\n encKey = cek;\n }\n const encrypted = new Uint8Array(await crypto.subtle.encrypt({\n additionalData: aad,\n iv: iv,\n name: 'AES-GCM',\n tagLength: 128,\n }, encKey, plaintext));\n const tag = encrypted.slice(-16);\n const ciphertext = encrypted.slice(0, -16);\n return { ciphertext, tag, iv };\n}\nexport async function encrypt(enc, plaintext, cek, iv, aad) {\n if (!isCryptoKey(cek) && !(cek instanceof Uint8Array)) {\n throw new TypeError(invalidKeyInput(cek, 'CryptoKey', 'KeyObject', 'Uint8Array', 'JSON Web Key'));\n }\n if (iv) {\n checkIvLength(enc, iv);\n }\n else {\n iv = generateIv(enc);\n }\n switch (enc) {\n case 'A128CBC-HS256':\n case 'A192CBC-HS384':\n case 'A256CBC-HS512':\n if (cek instanceof Uint8Array) {\n checkCekLength(cek, parseInt(enc.slice(-3), 10));\n }\n return cbcEncrypt(enc, plaintext, cek, iv, aad);\n case 'A128GCM':\n case 'A192GCM':\n case 'A256GCM':\n if (cek instanceof Uint8Array) {\n checkCekLength(cek, parseInt(enc.slice(1, 4), 10));\n }\n return gcmEncrypt(enc, plaintext, cek, iv, aad);\n default:\n throw new JOSENotSupported('Unsupported JWE Content Encryption Algorithm');\n }\n}\n","import { encrypt } from './encrypt.js';\nimport { decrypt } from './decrypt.js';\nimport { encode as b64u } from '../util/base64url.js';\nexport async function wrap(alg, key, cek, iv) {\n const jweAlgorithm = alg.slice(0, 7);\n const wrapped = await encrypt(jweAlgorithm, cek, key, iv, new Uint8Array());\n return {\n encryptedKey: wrapped.ciphertext,\n iv: b64u(wrapped.iv),\n tag: b64u(wrapped.tag),\n };\n}\nexport async function unwrap(alg, key, encryptedKey, iv, tag) {\n const jweAlgorithm = alg.slice(0, 7);\n return decrypt(jweAlgorithm, key, encryptedKey, iv, tag, new Uint8Array());\n}\n","import * as aeskw from './aeskw.js';\nimport * as ecdhes from './ecdhes.js';\nimport * as pbes2kw from './pbes2kw.js';\nimport * as rsaes from './rsaes.js';\nimport { decode as b64u } from '../util/base64url.js';\nimport { JOSENotSupported, JWEInvalid } from '../util/errors.js';\nimport { cekLength } from '../lib/cek.js';\nimport { importJWK } from '../key/import.js';\nimport { isObject } from './is_object.js';\nimport { unwrap as aesGcmKw } from './aesgcmkw.js';\nimport { assertCryptoKey } from './is_key_like.js';\nexport async function decryptKeyManagement(alg, key, encryptedKey, joseHeader, options) {\n switch (alg) {\n case 'dir': {\n if (encryptedKey !== undefined)\n throw new JWEInvalid('Encountered unexpected JWE Encrypted Key');\n return key;\n }\n case 'ECDH-ES':\n if (encryptedKey !== undefined)\n throw new JWEInvalid('Encountered unexpected JWE Encrypted Key');\n case 'ECDH-ES+A128KW':\n case 'ECDH-ES+A192KW':\n case 'ECDH-ES+A256KW': {\n if (!isObject(joseHeader.epk))\n throw new JWEInvalid(`JOSE Header \"epk\" (Ephemeral Public Key) missing or invalid`);\n assertCryptoKey(key);\n if (!ecdhes.allowed(key))\n throw new JOSENotSupported('ECDH with the provided key is not allowed or not supported by your javascript runtime');\n const epk = await importJWK(joseHeader.epk, alg);\n assertCryptoKey(epk);\n let partyUInfo;\n let partyVInfo;\n if (joseHeader.apu !== undefined) {\n if (typeof joseHeader.apu !== 'string')\n throw new JWEInvalid(`JOSE Header \"apu\" (Agreement PartyUInfo) invalid`);\n try {\n partyUInfo = b64u(joseHeader.apu);\n }\n catch {\n throw new JWEInvalid('Failed to base64url decode the apu');\n }\n }\n if (joseHeader.apv !== undefined) {\n if (typeof joseHeader.apv !== 'string')\n throw new JWEInvalid(`JOSE Header \"apv\" (Agreement PartyVInfo) invalid`);\n try {\n partyVInfo = b64u(joseHeader.apv);\n }\n catch {\n throw new JWEInvalid('Failed to base64url decode the apv');\n }\n }\n const sharedSecret = await ecdhes.deriveKey(epk, key, alg === 'ECDH-ES' ? joseHeader.enc : alg, alg === 'ECDH-ES' ? cekLength(joseHeader.enc) : parseInt(alg.slice(-5, -2), 10), partyUInfo, partyVInfo);\n if (alg === 'ECDH-ES')\n return sharedSecret;\n if (encryptedKey === undefined)\n throw new JWEInvalid('JWE Encrypted Key missing');\n return aeskw.unwrap(alg.slice(-6), sharedSecret, encryptedKey);\n }\n case 'RSA-OAEP':\n case 'RSA-OAEP-256':\n case 'RSA-OAEP-384':\n case 'RSA-OAEP-512': {\n if (encryptedKey === undefined)\n throw new JWEInvalid('JWE Encrypted Key missing');\n assertCryptoKey(key);\n return rsaes.decrypt(alg, key, encryptedKey);\n }\n case 'PBES2-HS256+A128KW':\n case 'PBES2-HS384+A192KW':\n case 'PBES2-HS512+A256KW': {\n if (encryptedKey === undefined)\n throw new JWEInvalid('JWE Encrypted Key missing');\n if (typeof joseHeader.p2c !== 'number')\n throw new JWEInvalid(`JOSE Header \"p2c\" (PBES2 Count) missing or invalid`);\n const p2cLimit = options?.maxPBES2Count || 10_000;\n if (joseHeader.p2c > p2cLimit)\n throw new JWEInvalid(`JOSE Header \"p2c\" (PBES2 Count) out is of acceptable bounds`);\n if (typeof joseHeader.p2s !== 'string')\n throw new JWEInvalid(`JOSE Header \"p2s\" (PBES2 Salt) missing or invalid`);\n let p2s;\n try {\n p2s = b64u(joseHeader.p2s);\n }\n catch {\n throw new JWEInvalid('Failed to base64url decode the p2s');\n }\n return pbes2kw.unwrap(alg, key, encryptedKey, joseHeader.p2c, p2s);\n }\n case 'A128KW':\n case 'A192KW':\n case 'A256KW': {\n if (encryptedKey === undefined)\n throw new JWEInvalid('JWE Encrypted Key missing');\n return aeskw.unwrap(alg, key, encryptedKey);\n }\n case 'A128GCMKW':\n case 'A192GCMKW':\n case 'A256GCMKW': {\n if (encryptedKey === undefined)\n throw new JWEInvalid('JWE Encrypted Key missing');\n if (typeof joseHeader.iv !== 'string')\n throw new JWEInvalid(`JOSE Header \"iv\" (Initialization Vector) missing or invalid`);\n if (typeof joseHeader.tag !== 'string')\n throw new JWEInvalid(`JOSE Header \"tag\" (Authentication Tag) missing or invalid`);\n let iv;\n try {\n iv = b64u(joseHeader.iv);\n }\n catch {\n throw new JWEInvalid('Failed to base64url decode the iv');\n }\n let tag;\n try {\n tag = b64u(joseHeader.tag);\n }\n catch {\n throw new JWEInvalid('Failed to base64url decode the tag');\n }\n return aesGcmKw(alg, key, encryptedKey, iv, tag);\n }\n default: {\n throw new JOSENotSupported('Invalid or unsupported \"alg\" (JWE Algorithm) header value');\n }\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 { decode as b64u } from '../../util/base64url.js';\nimport { decrypt } from '../../lib/decrypt.js';\nimport { JOSEAlgNotAllowed, JOSENotSupported, JWEInvalid } from '../../util/errors.js';\nimport { isDisjoint } from '../../lib/is_disjoint.js';\nimport { isObject } from '../../lib/is_object.js';\nimport { decryptKeyManagement } from '../../lib/decrypt_key_management.js';\nimport { decoder, concat, encode } from '../../lib/buffer_utils.js';\nimport { generateCek } from '../../lib/cek.js';\nimport { validateCrit } from '../../lib/validate_crit.js';\nimport { validateAlgorithms } from '../../lib/validate_algorithms.js';\nimport { normalizeKey } from '../../lib/normalize_key.js';\nimport { checkKeyType } from '../../lib/check_key_type.js';\nexport async function flattenedDecrypt(jwe, key, options) {\n if (!isObject(jwe)) {\n throw new JWEInvalid('Flattened JWE must be an object');\n }\n if (jwe.protected === undefined && jwe.header === undefined && jwe.unprotected === undefined) {\n throw new JWEInvalid('JOSE Header missing');\n }\n if (jwe.iv !== undefined && typeof jwe.iv !== 'string') {\n throw new JWEInvalid('JWE Initialization Vector incorrect type');\n }\n if (typeof jwe.ciphertext !== 'string') {\n throw new JWEInvalid('JWE Ciphertext missing or incorrect type');\n }\n if (jwe.tag !== undefined && typeof jwe.tag !== 'string') {\n throw new JWEInvalid('JWE Authentication Tag incorrect type');\n }\n if (jwe.protected !== undefined && typeof jwe.protected !== 'string') {\n throw new JWEInvalid('JWE Protected Header incorrect type');\n }\n if (jwe.encrypted_key !== undefined && typeof jwe.encrypted_key !== 'string') {\n throw new JWEInvalid('JWE Encrypted Key incorrect type');\n }\n if (jwe.aad !== undefined && typeof jwe.aad !== 'string') {\n throw new JWEInvalid('JWE AAD incorrect type');\n }\n if (jwe.header !== undefined && !isObject(jwe.header)) {\n throw new JWEInvalid('JWE Shared Unprotected Header incorrect type');\n }\n if (jwe.unprotected !== undefined && !isObject(jwe.unprotected)) {\n throw new JWEInvalid('JWE Per-Recipient Unprotected Header incorrect type');\n }\n let parsedProt;\n if (jwe.protected) {\n try {\n const protectedHeader = b64u(jwe.protected);\n parsedProt = JSON.parse(decoder.decode(protectedHeader));\n }\n catch {\n throw new JWEInvalid('JWE Protected Header is invalid');\n }\n }\n if (!isDisjoint(parsedProt, jwe.header, jwe.unprotected)) {\n throw new JWEInvalid('JWE Protected, JWE Unprotected Header, and JWE Per-Recipient Unprotected Header Parameter names must be disjoint');\n }\n const joseHeader = {\n ...parsedProt,\n ...jwe.header,\n ...jwe.unprotected,\n };\n validateCrit(JWEInvalid, new Map(), options?.crit, parsedProt, joseHeader);\n if (joseHeader.zip !== undefined) {\n throw new JOSENotSupported('JWE \"zip\" (Compression Algorithm) Header Parameter is not supported.');\n }\n const { alg, enc } = joseHeader;\n if (typeof alg !== 'string' || !alg) {\n throw new JWEInvalid('missing JWE Algorithm (alg) in JWE Header');\n }\n if (typeof enc !== 'string' || !enc) {\n throw new JWEInvalid('missing JWE Encryption Algorithm (enc) in JWE Header');\n }\n const keyManagementAlgorithms = options && validateAlgorithms('keyManagementAlgorithms', options.keyManagementAlgorithms);\n const contentEncryptionAlgorithms = options &&\n validateAlgorithms('contentEncryptionAlgorithms', options.contentEncryptionAlgorithms);\n if ((keyManagementAlgorithms && !keyManagementAlgorithms.has(alg)) ||\n (!keyManagementAlgorithms && alg.startsWith('PBES2'))) {\n throw new JOSEAlgNotAllowed('\"alg\" (Algorithm) Header Parameter value not allowed');\n }\n if (contentEncryptionAlgorithms && !contentEncryptionAlgorithms.has(enc)) {\n throw new JOSEAlgNotAllowed('\"enc\" (Encryption Algorithm) Header Parameter value not allowed');\n }\n let encryptedKey;\n if (jwe.encrypted_key !== undefined) {\n try {\n encryptedKey = b64u(jwe.encrypted_key);\n }\n catch {\n throw new JWEInvalid('Failed to base64url decode the encrypted_key');\n }\n }\n let resolvedKey = false;\n if (typeof key === 'function') {\n key = await key(parsedProt, jwe);\n resolvedKey = true;\n }\n checkKeyType(alg === 'dir' ? enc : alg, key, 'decrypt');\n const k = await normalizeKey(key, alg);\n let cek;\n try {\n cek = await decryptKeyManagement(alg, k, encryptedKey, joseHeader, options);\n }\n catch (err) {\n if (err instanceof TypeError || err instanceof JWEInvalid || err instanceof JOSENotSupported) {\n throw err;\n }\n cek = generateCek(enc);\n }\n let iv;\n let tag;\n if (jwe.iv !== undefined) {\n try {\n iv = b64u(jwe.iv);\n }\n catch {\n throw new JWEInvalid('Failed to base64url decode the iv');\n }\n }\n if (jwe.tag !== undefined) {\n try {\n tag = b64u(jwe.tag);\n }\n catch {\n throw new JWEInvalid('Failed to base64url decode the tag');\n }\n }\n const protectedHeader = jwe.protected !== undefined ? encode(jwe.protected) : new Uint8Array();\n let additionalData;\n if (jwe.aad !== undefined) {\n additionalData = concat(protectedHeader, encode('.'), encode(jwe.aad));\n }\n else {\n additionalData = protectedHeader;\n }\n let ciphertext;\n try {\n ciphertext = b64u(jwe.ciphertext);\n }\n catch {\n throw new JWEInvalid('Failed to base64url decode the ciphertext');\n }\n const plaintext = await decrypt(enc, cek, ciphertext, iv, tag, additionalData);\n const result = { plaintext };\n if (jwe.protected !== undefined) {\n result.protectedHeader = parsedProt;\n }\n if (jwe.aad !== undefined) {\n try {\n result.additionalAuthenticatedData = b64u(jwe.aad);\n }\n catch {\n throw new JWEInvalid('Failed to base64url decode the aad');\n }\n }\n if (jwe.unprotected !== undefined) {\n result.sharedUnprotectedHeader = jwe.unprotected;\n }\n if (jwe.header !== undefined) {\n result.unprotectedHeader = jwe.header;\n }\n if (resolvedKey) {\n return { ...result, key: k };\n }\n return result;\n}\n","import { flattenedDecrypt } from '../flattened/decrypt.js';\nimport { JWEInvalid } from '../../util/errors.js';\nimport { decoder } from '../../lib/buffer_utils.js';\nexport async function compactDecrypt(jwe, key, options) {\n if (jwe instanceof Uint8Array) {\n jwe = decoder.decode(jwe);\n }\n if (typeof jwe !== 'string') {\n throw new JWEInvalid('Compact JWE must be a string or Uint8Array');\n }\n const { 0: protectedHeader, 1: encryptedKey, 2: iv, 3: ciphertext, 4: tag, length, } = jwe.split('.');\n if (length !== 5) {\n throw new JWEInvalid('Invalid Compact JWE');\n }\n const decrypted = await flattenedDecrypt({\n ciphertext,\n iv: iv || undefined,\n protected: protectedHeader,\n tag: tag || undefined,\n encrypted_key: encryptedKey || undefined,\n }, key, options);\n const result = { plaintext: decrypted.plaintext, protectedHeader: decrypted.protectedHeader };\n if (typeof key === 'function') {\n return { ...result, key: decrypted.key };\n }\n return result;\n}\n","import { flattenedDecrypt } from '../flattened/decrypt.js';\nimport { JWEDecryptionFailed, JWEInvalid } from '../../util/errors.js';\nimport { isObject } from '../../lib/is_object.js';\nexport async function generalDecrypt(jwe, key, options) {\n if (!isObject(jwe)) {\n throw new JWEInvalid('General JWE must be an object');\n }\n if (!Array.isArray(jwe.recipients) || !jwe.recipients.every(isObject)) {\n throw new JWEInvalid('JWE Recipients missing or incorrect type');\n }\n if (!jwe.recipients.length) {\n throw new JWEInvalid('JWE Recipients has no members');\n }\n for (const recipient of jwe.recipients) {\n try {\n return await flattenedDecrypt({\n aad: jwe.aad,\n ciphertext: jwe.ciphertext,\n encrypted_key: recipient.encrypted_key,\n header: recipient.header,\n iv: jwe.iv,\n protected: jwe.protected,\n tag: jwe.tag,\n unprotected: jwe.unprotected,\n }, key, options);\n }\n catch {\n }\n }\n throw new JWEDecryptionFailed();\n}\n","export const unprotected = Symbol();\n","import { invalidKeyInput } from './invalid_key_input.js';\nimport { encode as b64u } from '../util/base64url.js';\nimport { isCryptoKey, isKeyObject } from './is_key_like.js';\nexport async function keyToJWK(key) {\n if (isKeyObject(key)) {\n if (key.type === 'secret') {\n key = key.export();\n }\n else {\n return key.export({ format: 'jwk' });\n }\n }\n if (key instanceof Uint8Array) {\n return {\n kty: 'oct',\n k: b64u(key),\n };\n }\n if (!isCryptoKey(key)) {\n throw new TypeError(invalidKeyInput(key, 'CryptoKey', 'KeyObject', 'Uint8Array'));\n }\n if (!key.extractable) {\n throw new TypeError('non-extractable CryptoKey cannot be exported as a JWK');\n }\n const { ext, key_ops, alg, use, ...jwk } = await crypto.subtle.exportKey('jwk', key);\n if (jwk.kty === 'AKP') {\n ;\n jwk.alg = alg;\n }\n return jwk;\n}\n","import { toSPKI as exportPublic, toPKCS8 as exportPrivate } from '../lib/asn1.js';\nimport { keyToJWK } from '../lib/key_to_jwk.js';\nexport async function exportSPKI(key) {\n return exportPublic(key);\n}\nexport async function exportPKCS8(key) {\n return exportPrivate(key);\n}\nexport async function exportJWK(key) {\n return keyToJWK(key);\n}\n","import * as aeskw from './aeskw.js';\nimport * as ecdhes from './ecdhes.js';\nimport * as pbes2kw from './pbes2kw.js';\nimport * as rsaes from './rsaes.js';\nimport { encode as b64u } from '../util/base64url.js';\nimport { normalizeKey } from './normalize_key.js';\nimport { generateCek, cekLength } from '../lib/cek.js';\nimport { JOSENotSupported } from '../util/errors.js';\nimport { exportJWK } from '../key/export.js';\nimport { wrap as aesGcmKw } from './aesgcmkw.js';\nimport { assertCryptoKey } from './is_key_like.js';\nexport async function encryptKeyManagement(alg, enc, key, providedCek, providedParameters = {}) {\n let encryptedKey;\n let parameters;\n let cek;\n switch (alg) {\n case 'dir': {\n cek = key;\n break;\n }\n case 'ECDH-ES':\n case 'ECDH-ES+A128KW':\n case 'ECDH-ES+A192KW':\n case 'ECDH-ES+A256KW': {\n assertCryptoKey(key);\n if (!ecdhes.allowed(key)) {\n throw new JOSENotSupported('ECDH with the provided key is not allowed or not supported by your javascript runtime');\n }\n const { apu, apv } = providedParameters;\n let ephemeralKey;\n if (providedParameters.epk) {\n ephemeralKey = (await normalizeKey(providedParameters.epk, alg));\n }\n else {\n ephemeralKey = (await crypto.subtle.generateKey(key.algorithm, true, ['deriveBits'])).privateKey;\n }\n const { x, y, crv, kty } = await exportJWK(ephemeralKey);\n const sharedSecret = await ecdhes.deriveKey(key, ephemeralKey, alg === 'ECDH-ES' ? enc : alg, alg === 'ECDH-ES' ? cekLength(enc) : parseInt(alg.slice(-5, -2), 10), apu, apv);\n parameters = { epk: { x, crv, kty } };\n if (kty === 'EC')\n parameters.epk.y = y;\n if (apu)\n parameters.apu = b64u(apu);\n if (apv)\n parameters.apv = b64u(apv);\n if (alg === 'ECDH-ES') {\n cek = sharedSecret;\n break;\n }\n cek = providedCek || generateCek(enc);\n const kwAlg = alg.slice(-6);\n encryptedKey = await aeskw.wrap(kwAlg, sharedSecret, cek);\n break;\n }\n case 'RSA-OAEP':\n case 'RSA-OAEP-256':\n case 'RSA-OAEP-384':\n case 'RSA-OAEP-512': {\n cek = providedCek || generateCek(enc);\n assertCryptoKey(key);\n encryptedKey = await rsaes.encrypt(alg, key, cek);\n break;\n }\n case 'PBES2-HS256+A128KW':\n case 'PBES2-HS384+A192KW':\n case 'PBES2-HS512+A256KW': {\n cek = providedCek || generateCek(enc);\n const { p2c, p2s } = providedParameters;\n ({ encryptedKey, ...parameters } = await pbes2kw.wrap(alg, key, cek, p2c, p2s));\n break;\n }\n case 'A128KW':\n case 'A192KW':\n case 'A256KW': {\n cek = providedCek || generateCek(enc);\n encryptedKey = await aeskw.wrap(alg, key, cek);\n break;\n }\n case 'A128GCMKW':\n case 'A192GCMKW':\n case 'A256GCMKW': {\n cek = providedCek || generateCek(enc);\n const { iv } = providedParameters;\n ({ encryptedKey, ...parameters } = await aesGcmKw(alg, key, cek, iv));\n break;\n }\n default: {\n throw new JOSENotSupported('Invalid or unsupported \"alg\" (JWE Algorithm) header value');\n }\n }\n return { cek, encryptedKey, parameters };\n}\n","import { encode as b64u } from '../../util/base64url.js';\nimport { unprotected } from '../../lib/private_symbols.js';\nimport { encrypt } from '../../lib/encrypt.js';\nimport { encryptKeyManagement } from '../../lib/encrypt_key_management.js';\nimport { JOSENotSupported, JWEInvalid } from '../../util/errors.js';\nimport { isDisjoint } from '../../lib/is_disjoint.js';\nimport { concat, encode } from '../../lib/buffer_utils.js';\nimport { validateCrit } from '../../lib/validate_crit.js';\nimport { normalizeKey } from '../../lib/normalize_key.js';\nimport { checkKeyType } from '../../lib/check_key_type.js';\nexport class FlattenedEncrypt {\n #plaintext;\n #protectedHeader;\n #sharedUnprotectedHeader;\n #unprotectedHeader;\n #aad;\n #cek;\n #iv;\n #keyManagementParameters;\n constructor(plaintext) {\n if (!(plaintext instanceof Uint8Array)) {\n throw new TypeError('plaintext must be an instance of Uint8Array');\n }\n this.#plaintext = plaintext;\n }\n setKeyManagementParameters(parameters) {\n if (this.#keyManagementParameters) {\n throw new TypeError('setKeyManagementParameters can only be called once');\n }\n this.#keyManagementParameters = parameters;\n return this;\n }\n setProtectedHeader(protectedHeader) {\n if (this.#protectedHeader) {\n throw new TypeError('setProtectedHeader can only be called once');\n }\n this.#protectedHeader = protectedHeader;\n return this;\n }\n setSharedUnprotectedHeader(sharedUnprotectedHeader) {\n if (this.#sharedUnprotectedHeader) {\n throw new TypeError('setSharedUnprotectedHeader can only be called once');\n }\n this.#sharedUnprotectedHeader = sharedUnprotectedHeader;\n return this;\n }\n setUnprotectedHeader(unprotectedHeader) {\n if (this.#unprotectedHeader) {\n throw new TypeError('setUnprotectedHeader can only be called once');\n }\n this.#unprotectedHeader = unprotectedHeader;\n return this;\n }\n setAdditionalAuthenticatedData(aad) {\n this.#aad = aad;\n return this;\n }\n setContentEncryptionKey(cek) {\n if (this.#cek) {\n throw new TypeError('setContentEncryptionKey can only be called once');\n }\n this.#cek = cek;\n return this;\n }\n setInitializationVector(iv) {\n if (this.#iv) {\n throw new TypeError('setInitializationVector can only be called once');\n }\n this.#iv = iv;\n return this;\n }\n async encrypt(key, options) {\n if (!this.#protectedHeader && !this.#unprotectedHeader && !this.#sharedUnprotectedHeader) {\n throw new JWEInvalid('either setProtectedHeader, setUnprotectedHeader, or sharedUnprotectedHeader must be called before #encrypt()');\n }\n if (!isDisjoint(this.#protectedHeader, this.#unprotectedHeader, this.#sharedUnprotectedHeader)) {\n throw new JWEInvalid('JWE Protected, JWE Shared Unprotected and JWE Per-Recipient Header Parameter names must be disjoint');\n }\n const joseHeader = {\n ...this.#protectedHeader,\n ...this.#unprotectedHeader,\n ...this.#sharedUnprotectedHeader,\n };\n validateCrit(JWEInvalid, new Map(), options?.crit, this.#protectedHeader, joseHeader);\n if (joseHeader.zip !== undefined) {\n throw new JOSENotSupported('JWE \"zip\" (Compression Algorithm) Header Parameter is not supported.');\n }\n const { alg, enc } = joseHeader;\n if (typeof alg !== 'string' || !alg) {\n throw new JWEInvalid('JWE \"alg\" (Algorithm) Header Parameter missing or invalid');\n }\n if (typeof enc !== 'string' || !enc) {\n throw new JWEInvalid('JWE \"enc\" (Encryption Algorithm) Header Parameter missing or invalid');\n }\n let encryptedKey;\n if (this.#cek && (alg === 'dir' || alg === 'ECDH-ES')) {\n throw new TypeError(`setContentEncryptionKey cannot be called with JWE \"alg\" (Algorithm) Header ${alg}`);\n }\n checkKeyType(alg === 'dir' ? enc : alg, key, 'encrypt');\n let cek;\n {\n let parameters;\n const k = await normalizeKey(key, alg);\n ({ cek, encryptedKey, parameters } = await encryptKeyManagement(alg, enc, k, this.#cek, this.#keyManagementParameters));\n if (parameters) {\n if (options && unprotected in options) {\n if (!this.#unprotectedHeader) {\n this.setUnprotectedHeader(parameters);\n }\n else {\n this.#unprotectedHeader = { ...this.#unprotectedHeader, ...parameters };\n }\n }\n else if (!this.#protectedHeader) {\n this.setProtectedHeader(parameters);\n }\n else {\n this.#protectedHeader = { ...this.#protectedHeader, ...parameters };\n }\n }\n }\n let additionalData;\n let protectedHeaderS;\n let protectedHeaderB;\n let aadMember;\n if (this.#protectedHeader) {\n protectedHeaderS = b64u(JSON.stringify(this.#protectedHeader));\n protectedHeaderB = encode(protectedHeaderS);\n }\n else {\n protectedHeaderS = '';\n protectedHeaderB = new Uint8Array();\n }\n if (this.#aad) {\n aadMember = b64u(this.#aad);\n const aadMemberBytes = encode(aadMember);\n additionalData = concat(protectedHeaderB, encode('.'), aadMemberBytes);\n }\n else {\n additionalData = protectedHeaderB;\n }\n const { ciphertext, tag, iv } = await encrypt(enc, this.#plaintext, cek, this.#iv, additionalData);\n const jwe = {\n ciphertext: b64u(ciphertext),\n };\n if (iv) {\n jwe.iv = b64u(iv);\n }\n if (tag) {\n jwe.tag = b64u(tag);\n }\n if (encryptedKey) {\n jwe.encrypted_key = b64u(encryptedKey);\n }\n if (aadMember) {\n jwe.aad = aadMember;\n }\n if (this.#protectedHeader) {\n jwe.protected = protectedHeaderS;\n }\n if (this.#sharedUnprotectedHeader) {\n jwe.unprotected = this.#sharedUnprotectedHeader;\n }\n if (this.#unprotectedHeader) {\n jwe.header = this.#unprotectedHeader;\n }\n return jwe;\n }\n}\n","import { FlattenedEncrypt } from '../flattened/encrypt.js';\nimport { unprotected } from '../../lib/private_symbols.js';\nimport { JOSENotSupported, JWEInvalid } from '../../util/errors.js';\nimport { generateCek } from '../../lib/cek.js';\nimport { isDisjoint } from '../../lib/is_disjoint.js';\nimport { encryptKeyManagement } from '../../lib/encrypt_key_management.js';\nimport { encode as b64u } from '../../util/base64url.js';\nimport { validateCrit } from '../../lib/validate_crit.js';\nimport { normalizeKey } from '../../lib/normalize_key.js';\nimport { checkKeyType } from '../../lib/check_key_type.js';\nclass IndividualRecipient {\n #parent;\n unprotectedHeader;\n keyManagementParameters;\n key;\n options;\n constructor(enc, key, options) {\n this.#parent = enc;\n this.key = key;\n this.options = options;\n }\n setUnprotectedHeader(unprotectedHeader) {\n if (this.unprotectedHeader) {\n throw new TypeError('setUnprotectedHeader can only be called once');\n }\n this.unprotectedHeader = unprotectedHeader;\n return this;\n }\n setKeyManagementParameters(parameters) {\n if (this.keyManagementParameters) {\n throw new TypeError('setKeyManagementParameters can only be called once');\n }\n this.keyManagementParameters = parameters;\n return this;\n }\n addRecipient(...args) {\n return this.#parent.addRecipient(...args);\n }\n encrypt(...args) {\n return this.#parent.encrypt(...args);\n }\n done() {\n return this.#parent;\n }\n}\nexport class GeneralEncrypt {\n #plaintext;\n #recipients = [];\n #protectedHeader;\n #unprotectedHeader;\n #aad;\n constructor(plaintext) {\n this.#plaintext = plaintext;\n }\n addRecipient(key, options) {\n const recipient = new IndividualRecipient(this, key, { crit: options?.crit });\n this.#recipients.push(recipient);\n return recipient;\n }\n setProtectedHeader(protectedHeader) {\n if (this.#protectedHeader) {\n throw new TypeError('setProtectedHeader can only be called once');\n }\n this.#protectedHeader = protectedHeader;\n return this;\n }\n setSharedUnprotectedHeader(sharedUnprotectedHeader) {\n if (this.#unprotectedHeader) {\n throw new TypeError('setSharedUnprotectedHeader can only be called once');\n }\n this.#unprotectedHeader = sharedUnprotectedHeader;\n return this;\n }\n setAdditionalAuthenticatedData(aad) {\n this.#aad = aad;\n return this;\n }\n async encrypt() {\n if (!this.#recipients.length) {\n throw new JWEInvalid('at least one recipient must be added');\n }\n if (this.#recipients.length === 1) {\n const [recipient] = this.#recipients;\n const flattened = await new FlattenedEncrypt(this.#plaintext)\n .setAdditionalAuthenticatedData(this.#aad)\n .setProtectedHeader(this.#protectedHeader)\n .setSharedUnprotectedHeader(this.#unprotectedHeader)\n .setUnprotectedHeader(recipient.unprotectedHeader)\n .encrypt(recipient.key, { ...recipient.options });\n const jwe = {\n ciphertext: flattened.ciphertext,\n iv: flattened.iv,\n recipients: [{}],\n tag: flattened.tag,\n };\n if (flattened.aad)\n jwe.aad = flattened.aad;\n if (flattened.protected)\n jwe.protected = flattened.protected;\n if (flattened.unprotected)\n jwe.unprotected = flattened.unprotected;\n if (flattened.encrypted_key)\n jwe.recipients[0].encrypted_key = flattened.encrypted_key;\n if (flattened.header)\n jwe.recipients[0].header = flattened.header;\n return jwe;\n }\n let enc;\n for (let i = 0; i < this.#recipients.length; i++) {\n const recipient = this.#recipients[i];\n if (!isDisjoint(this.#protectedHeader, this.#unprotectedHeader, recipient.unprotectedHeader)) {\n throw new JWEInvalid('JWE Protected, JWE Shared Unprotected and JWE Per-Recipient Header Parameter names must be disjoint');\n }\n const joseHeader = {\n ...this.#protectedHeader,\n ...this.#unprotectedHeader,\n ...recipient.unprotectedHeader,\n };\n const { alg } = joseHeader;\n if (typeof alg !== 'string' || !alg) {\n throw new JWEInvalid('JWE \"alg\" (Algorithm) Header Parameter missing or invalid');\n }\n if (alg === 'dir' || alg === 'ECDH-ES') {\n throw new JWEInvalid('\"dir\" and \"ECDH-ES\" alg may only be used with a single recipient');\n }\n if (typeof joseHeader.enc !== 'string' || !joseHeader.enc) {\n throw new JWEInvalid('JWE \"enc\" (Encryption Algorithm) Header Parameter missing or invalid');\n }\n if (!enc) {\n enc = joseHeader.enc;\n }\n else if (enc !== joseHeader.enc) {\n throw new JWEInvalid('JWE \"enc\" (Encryption Algorithm) Header Parameter must be the same for all recipients');\n }\n validateCrit(JWEInvalid, new Map(), recipient.options.crit, this.#protectedHeader, joseHeader);\n if (joseHeader.zip !== undefined) {\n throw new JOSENotSupported('JWE \"zip\" (Compression Algorithm) Header Parameter is not supported.');\n }\n }\n const cek = generateCek(enc);\n const jwe = {\n ciphertext: '',\n recipients: [],\n };\n for (let i = 0; i < this.#recipients.length; i++) {\n const recipient = this.#recipients[i];\n const target = {};\n jwe.recipients.push(target);\n if (i === 0) {\n const flattened = await new FlattenedEncrypt(this.#plaintext)\n .setAdditionalAuthenticatedData(this.#aad)\n .setContentEncryptionKey(cek)\n .setProtectedHeader(this.#protectedHeader)\n .setSharedUnprotectedHeader(this.#unprotectedHeader)\n .setUnprotectedHeader(recipient.unprotectedHeader)\n .setKeyManagementParameters(recipient.keyManagementParameters)\n .encrypt(recipient.key, {\n ...recipient.options,\n [unprotected]: true,\n });\n jwe.ciphertext = flattened.ciphertext;\n jwe.iv = flattened.iv;\n jwe.tag = flattened.tag;\n if (flattened.aad)\n jwe.aad = flattened.aad;\n if (flattened.protected)\n jwe.protected = flattened.protected;\n if (flattened.unprotected)\n jwe.unprotected = flattened.unprotected;\n target.encrypted_key = flattened.encrypted_key;\n if (flattened.header)\n target.header = flattened.header;\n continue;\n }\n const alg = recipient.unprotectedHeader?.alg ||\n this.#protectedHeader?.alg ||\n this.#unprotectedHeader?.alg;\n checkKeyType(alg === 'dir' ? enc : alg, recipient.key, 'encrypt');\n const k = await normalizeKey(recipient.key, alg);\n const { encryptedKey, parameters } = await encryptKeyManagement(alg, enc, k, cek, recipient.keyManagementParameters);\n target.encrypted_key = b64u(encryptedKey);\n if (recipient.unprotectedHeader || parameters)\n target.header = { ...recipient.unprotectedHeader, ...parameters };\n }\n return jwe;\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 { flattenedVerify } from '../flattened/verify.js';\nimport { JWSInvalid, JWSSignatureVerificationFailed } from '../../util/errors.js';\nimport { isObject } from '../../lib/is_object.js';\nexport async function generalVerify(jws, key, options) {\n if (!isObject(jws)) {\n throw new JWSInvalid('General JWS must be an object');\n }\n if (!Array.isArray(jws.signatures) || !jws.signatures.every(isObject)) {\n throw new JWSInvalid('JWS Signatures missing or incorrect type');\n }\n for (const signature of jws.signatures) {\n try {\n return await flattenedVerify({\n header: signature.header,\n payload: jws.payload,\n protected: signature.protected,\n signature: signature.signature,\n }, key, options);\n }\n catch {\n }\n }\n throw new JWSSignatureVerificationFailed();\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","import { compactDecrypt } from '../jwe/compact/decrypt.js';\nimport { validateClaimsSet } from '../lib/jwt_claims_set.js';\nimport { JWTClaimValidationFailed } from '../util/errors.js';\nexport async function jwtDecrypt(jwt, key, options) {\n const decrypted = await compactDecrypt(jwt, key, options);\n const payload = validateClaimsSet(decrypted.protectedHeader, decrypted.plaintext, options);\n const { protectedHeader } = decrypted;\n if (protectedHeader.iss !== undefined && protectedHeader.iss !== payload.iss) {\n throw new JWTClaimValidationFailed('replicated \"iss\" claim header parameter mismatch', payload, 'iss', 'mismatch');\n }\n if (protectedHeader.sub !== undefined && protectedHeader.sub !== payload.sub) {\n throw new JWTClaimValidationFailed('replicated \"sub\" claim header parameter mismatch', payload, 'sub', 'mismatch');\n }\n if (protectedHeader.aud !== undefined &&\n JSON.stringify(protectedHeader.aud) !== JSON.stringify(payload.aud)) {\n throw new JWTClaimValidationFailed('replicated \"aud\" claim header parameter mismatch', payload, 'aud', 'mismatch');\n }\n const result = { payload, protectedHeader };\n if (typeof key === 'function') {\n return { ...result, key: decrypted.key };\n }\n return result;\n}\n","import { FlattenedEncrypt } from '../flattened/encrypt.js';\nexport class CompactEncrypt {\n #flattened;\n constructor(plaintext) {\n this.#flattened = new FlattenedEncrypt(plaintext);\n }\n setContentEncryptionKey(cek) {\n this.#flattened.setContentEncryptionKey(cek);\n return this;\n }\n setInitializationVector(iv) {\n this.#flattened.setInitializationVector(iv);\n return this;\n }\n setProtectedHeader(protectedHeader) {\n this.#flattened.setProtectedHeader(protectedHeader);\n return this;\n }\n setKeyManagementParameters(parameters) {\n this.#flattened.setKeyManagementParameters(parameters);\n return this;\n }\n async encrypt(key, options) {\n const jwe = await this.#flattened.encrypt(key, options);\n return [jwe.protected, jwe.encrypted_key, jwe.iv, jwe.ciphertext, jwe.tag].join('.');\n }\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 sign(alg, key, data) {\n const cryptoKey = await getSigKey(alg, key, 'sign');\n checkKeyLength(alg, cryptoKey);\n const signature = await crypto.subtle.sign(subtleAlgorithm(alg, cryptoKey.algorithm), cryptoKey, data);\n return new Uint8Array(signature);\n}\n","import { encode as b64u } from '../../util/base64url.js';\nimport { sign } from '../../lib/sign.js';\nimport { isDisjoint } from '../../lib/is_disjoint.js';\nimport { JWSInvalid } from '../../util/errors.js';\nimport { concat, encode } from '../../lib/buffer_utils.js';\nimport { checkKeyType } from '../../lib/check_key_type.js';\nimport { validateCrit } from '../../lib/validate_crit.js';\nimport { normalizeKey } from '../../lib/normalize_key.js';\nexport class FlattenedSign {\n #payload;\n #protectedHeader;\n #unprotectedHeader;\n constructor(payload) {\n if (!(payload instanceof Uint8Array)) {\n throw new TypeError('payload must be an instance of Uint8Array');\n }\n this.#payload = payload;\n }\n setProtectedHeader(protectedHeader) {\n if (this.#protectedHeader) {\n throw new TypeError('setProtectedHeader can only be called once');\n }\n this.#protectedHeader = protectedHeader;\n return this;\n }\n setUnprotectedHeader(unprotectedHeader) {\n if (this.#unprotectedHeader) {\n throw new TypeError('setUnprotectedHeader can only be called once');\n }\n this.#unprotectedHeader = unprotectedHeader;\n return this;\n }\n async sign(key, options) {\n if (!this.#protectedHeader && !this.#unprotectedHeader) {\n throw new JWSInvalid('either setProtectedHeader or setUnprotectedHeader must be called before #sign()');\n }\n if (!isDisjoint(this.#protectedHeader, this.#unprotectedHeader)) {\n throw new JWSInvalid('JWS Protected and JWS Unprotected Header Parameter names must be disjoint');\n }\n const joseHeader = {\n ...this.#protectedHeader,\n ...this.#unprotectedHeader,\n };\n const extensions = validateCrit(JWSInvalid, new Map([['b64', true]]), options?.crit, this.#protectedHeader, joseHeader);\n let b64 = true;\n if (extensions.has('b64')) {\n b64 = this.#protectedHeader.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 checkKeyType(alg, key, 'sign');\n let payloadS;\n let payloadB;\n if (b64) {\n payloadS = b64u(this.#payload);\n payloadB = encode(payloadS);\n }\n else {\n payloadB = this.#payload;\n payloadS = '';\n }\n let protectedHeaderString;\n let protectedHeaderBytes;\n if (this.#protectedHeader) {\n protectedHeaderString = b64u(JSON.stringify(this.#protectedHeader));\n protectedHeaderBytes = encode(protectedHeaderString);\n }\n else {\n protectedHeaderString = '';\n protectedHeaderBytes = new Uint8Array();\n }\n const data = concat(protectedHeaderBytes, encode('.'), payloadB);\n const k = await normalizeKey(key, alg);\n const signature = await sign(alg, k, data);\n const jws = {\n signature: b64u(signature),\n payload: payloadS,\n };\n if (this.#unprotectedHeader) {\n jws.header = this.#unprotectedHeader;\n }\n if (this.#protectedHeader) {\n jws.protected = protectedHeaderString;\n }\n return jws;\n }\n}\n","import { FlattenedSign } from '../flattened/sign.js';\nexport class CompactSign {\n #flattened;\n constructor(payload) {\n this.#flattened = new FlattenedSign(payload);\n }\n setProtectedHeader(protectedHeader) {\n this.#flattened.setProtectedHeader(protectedHeader);\n return this;\n }\n async sign(key, options) {\n const jws = await this.#flattened.sign(key, options);\n if (jws.payload === undefined) {\n throw new TypeError('use the flattened module for creating JWS with b64: false');\n }\n return `${jws.protected}.${jws.payload}.${jws.signature}`;\n }\n}\n","import { FlattenedSign } from '../flattened/sign.js';\nimport { JWSInvalid } from '../../util/errors.js';\nclass IndividualSignature {\n #parent;\n protectedHeader;\n unprotectedHeader;\n options;\n key;\n constructor(sig, key, options) {\n this.#parent = sig;\n this.key = key;\n this.options = options;\n }\n setProtectedHeader(protectedHeader) {\n if (this.protectedHeader) {\n throw new TypeError('setProtectedHeader can only be called once');\n }\n this.protectedHeader = protectedHeader;\n return this;\n }\n setUnprotectedHeader(unprotectedHeader) {\n if (this.unprotectedHeader) {\n throw new TypeError('setUnprotectedHeader can only be called once');\n }\n this.unprotectedHeader = unprotectedHeader;\n return this;\n }\n addSignature(...args) {\n return this.#parent.addSignature(...args);\n }\n sign(...args) {\n return this.#parent.sign(...args);\n }\n done() {\n return this.#parent;\n }\n}\nexport class GeneralSign {\n #payload;\n #signatures = [];\n constructor(payload) {\n this.#payload = payload;\n }\n addSignature(key, options) {\n const signature = new IndividualSignature(this, key, options);\n this.#signatures.push(signature);\n return signature;\n }\n async sign() {\n if (!this.#signatures.length) {\n throw new JWSInvalid('at least one signature must be added');\n }\n const jws = {\n signatures: [],\n payload: '',\n };\n for (let i = 0; i < this.#signatures.length; i++) {\n const signature = this.#signatures[i];\n const flattened = new FlattenedSign(this.#payload);\n flattened.setProtectedHeader(signature.protectedHeader);\n flattened.setUnprotectedHeader(signature.unprotectedHeader);\n const { payload, ...rest } = await flattened.sign(signature.key, signature.options);\n if (i === 0) {\n jws.payload = payload;\n }\n else if (jws.payload !== payload) {\n throw new JWSInvalid('inconsistent use of JWS Unencoded Payload (RFC7797)');\n }\n jws.signatures.push(rest);\n }\n return jws;\n }\n}\n","import { CompactSign } from '../jws/compact/sign.js';\nimport { JWTInvalid } from '../util/errors.js';\nimport { JWTClaimsBuilder } from '../lib/jwt_claims_set.js';\nexport class SignJWT {\n #protectedHeader;\n #jwt;\n constructor(payload = {}) {\n this.#jwt = new JWTClaimsBuilder(payload);\n }\n setIssuer(issuer) {\n this.#jwt.iss = issuer;\n return this;\n }\n setSubject(subject) {\n this.#jwt.sub = subject;\n return this;\n }\n setAudience(audience) {\n this.#jwt.aud = audience;\n return this;\n }\n setJti(jwtId) {\n this.#jwt.jti = jwtId;\n return this;\n }\n setNotBefore(input) {\n this.#jwt.nbf = input;\n return this;\n }\n setExpirationTime(input) {\n this.#jwt.exp = input;\n return this;\n }\n setIssuedAt(input) {\n this.#jwt.iat = input;\n return this;\n }\n setProtectedHeader(protectedHeader) {\n this.#protectedHeader = protectedHeader;\n return this;\n }\n async sign(key, options) {\n const sig = new CompactSign(this.#jwt.data());\n sig.setProtectedHeader(this.#protectedHeader);\n if (Array.isArray(this.#protectedHeader?.crit) &&\n this.#protectedHeader.crit.includes('b64') &&\n this.#protectedHeader.b64 === false) {\n throw new JWTInvalid('JWTs MUST NOT use unencoded payload');\n }\n return sig.sign(key, options);\n }\n}\n","import { CompactEncrypt } from '../jwe/compact/encrypt.js';\nimport { JWTClaimsBuilder } from '../lib/jwt_claims_set.js';\nexport class EncryptJWT {\n #cek;\n #iv;\n #keyManagementParameters;\n #protectedHeader;\n #replicateIssuerAsHeader;\n #replicateSubjectAsHeader;\n #replicateAudienceAsHeader;\n #jwt;\n constructor(payload = {}) {\n this.#jwt = new JWTClaimsBuilder(payload);\n }\n setIssuer(issuer) {\n this.#jwt.iss = issuer;\n return this;\n }\n setSubject(subject) {\n this.#jwt.sub = subject;\n return this;\n }\n setAudience(audience) {\n this.#jwt.aud = audience;\n return this;\n }\n setJti(jwtId) {\n this.#jwt.jti = jwtId;\n return this;\n }\n setNotBefore(input) {\n this.#jwt.nbf = input;\n return this;\n }\n setExpirationTime(input) {\n this.#jwt.exp = input;\n return this;\n }\n setIssuedAt(input) {\n this.#jwt.iat = input;\n return this;\n }\n setProtectedHeader(protectedHeader) {\n if (this.#protectedHeader) {\n throw new TypeError('setProtectedHeader can only be called once');\n }\n this.#protectedHeader = protectedHeader;\n return this;\n }\n setKeyManagementParameters(parameters) {\n if (this.#keyManagementParameters) {\n throw new TypeError('setKeyManagementParameters can only be called once');\n }\n this.#keyManagementParameters = parameters;\n return this;\n }\n setContentEncryptionKey(cek) {\n if (this.#cek) {\n throw new TypeError('setContentEncryptionKey can only be called once');\n }\n this.#cek = cek;\n return this;\n }\n setInitializationVector(iv) {\n if (this.#iv) {\n throw new TypeError('setInitializationVector can only be called once');\n }\n this.#iv = iv;\n return this;\n }\n replicateIssuerAsHeader() {\n this.#replicateIssuerAsHeader = true;\n return this;\n }\n replicateSubjectAsHeader() {\n this.#replicateSubjectAsHeader = true;\n return this;\n }\n replicateAudienceAsHeader() {\n this.#replicateAudienceAsHeader = true;\n return this;\n }\n async encrypt(key, options) {\n const enc = new CompactEncrypt(this.#jwt.data());\n if (this.#protectedHeader &&\n (this.#replicateIssuerAsHeader ||\n this.#replicateSubjectAsHeader ||\n this.#replicateAudienceAsHeader)) {\n this.#protectedHeader = {\n ...this.#protectedHeader,\n iss: this.#replicateIssuerAsHeader ? this.#jwt.iss : undefined,\n sub: this.#replicateSubjectAsHeader ? this.#jwt.sub : undefined,\n aud: this.#replicateAudienceAsHeader ? this.#jwt.aud : undefined,\n };\n }\n enc.setProtectedHeader(this.#protectedHeader);\n if (this.#iv) {\n enc.setInitializationVector(this.#iv);\n }\n if (this.#cek) {\n enc.setContentEncryptionKey(this.#cek);\n }\n if (this.#keyManagementParameters) {\n enc.setKeyManagementParameters(this.#keyManagementParameters);\n }\n return enc.encrypt(key, options);\n }\n}\n","import { digest } from '../lib/digest.js';\nimport { encode as b64u } from '../util/base64url.js';\nimport { JOSENotSupported, JWKInvalid } from '../util/errors.js';\nimport { encode } from '../lib/buffer_utils.js';\nimport { isKeyLike } from '../lib/is_key_like.js';\nimport { isJWK } from '../lib/is_jwk.js';\nimport { exportJWK } from '../key/export.js';\nimport { invalidKeyInput } from '../lib/invalid_key_input.js';\nconst check = (value, description) => {\n if (typeof value !== 'string' || !value) {\n throw new JWKInvalid(`${description} missing or invalid`);\n }\n};\nexport async function calculateJwkThumbprint(key, digestAlgorithm) {\n let jwk;\n if (isJWK(key)) {\n jwk = key;\n }\n else if (isKeyLike(key)) {\n jwk = await exportJWK(key);\n }\n else {\n throw new TypeError(invalidKeyInput(key, 'CryptoKey', 'KeyObject', 'JSON Web Key'));\n }\n digestAlgorithm ??= 'sha256';\n if (digestAlgorithm !== 'sha256' &&\n digestAlgorithm !== 'sha384' &&\n digestAlgorithm !== 'sha512') {\n throw new TypeError('digestAlgorithm must one of \"sha256\", \"sha384\", or \"sha512\"');\n }\n let components;\n switch (jwk.kty) {\n case 'AKP':\n check(jwk.alg, '\"alg\" (Algorithm) Parameter');\n check(jwk.pub, '\"pub\" (Public key) Parameter');\n components = { alg: jwk.alg, kty: jwk.kty, pub: jwk.pub };\n break;\n case 'EC':\n check(jwk.crv, '\"crv\" (Curve) Parameter');\n check(jwk.x, '\"x\" (X Coordinate) Parameter');\n check(jwk.y, '\"y\" (Y Coordinate) Parameter');\n components = { crv: jwk.crv, kty: jwk.kty, x: jwk.x, y: jwk.y };\n break;\n case 'OKP':\n check(jwk.crv, '\"crv\" (Subtype of Key Pair) Parameter');\n check(jwk.x, '\"x\" (Public Key) Parameter');\n components = { crv: jwk.crv, kty: jwk.kty, x: jwk.x };\n break;\n case 'RSA':\n check(jwk.e, '\"e\" (Exponent) Parameter');\n check(jwk.n, '\"n\" (Modulus) Parameter');\n components = { e: jwk.e, kty: jwk.kty, n: jwk.n };\n break;\n case 'oct':\n check(jwk.k, '\"k\" (Key Value) Parameter');\n components = { k: jwk.k, kty: jwk.kty };\n break;\n default:\n throw new JOSENotSupported('\"kty\" (Key Type) Parameter missing or unsupported');\n }\n const data = encode(JSON.stringify(components));\n return b64u(await digest(digestAlgorithm, data));\n}\nexport async function calculateJwkThumbprintUri(key, digestAlgorithm) {\n digestAlgorithm ??= 'sha256';\n const thumbprint = await calculateJwkThumbprint(key, digestAlgorithm);\n return `urn:ietf:params:oauth:jwk-thumbprint:sha-${digestAlgorithm.slice(-3)}:${thumbprint}`;\n}\n","import { importJWK } from '../key/import.js';\nimport { isObject } from '../lib/is_object.js';\nimport { JWSInvalid } from '../util/errors.js';\nexport async function EmbeddedJWK(protectedHeader, token) {\n const joseHeader = {\n ...protectedHeader,\n ...token?.header,\n };\n if (!isObject(joseHeader.jwk)) {\n throw new JWSInvalid('\"jwk\" (JSON Web Key) Header Parameter must be a JSON object');\n }\n const key = await importJWK({ ...joseHeader.jwk, ext: true }, joseHeader.alg);\n if (key instanceof Uint8Array || key.type !== 'public') {\n throw new JWSInvalid('\"jwk\" (JSON Web Key) Header Parameter must be a public key');\n }\n return key;\n}\n","import { importJWK } from '../key/import.js';\nimport { JWKSInvalid, JOSENotSupported, JWKSNoMatchingKey, JWKSMultipleMatchingKeys, } from '../util/errors.js';\nimport { isObject } from '../lib/is_object.js';\nfunction getKtyFromAlg(alg) {\n switch (typeof alg === 'string' && alg.slice(0, 2)) {\n case 'RS':\n case 'PS':\n return 'RSA';\n case 'ES':\n return 'EC';\n case 'Ed':\n return 'OKP';\n case 'ML':\n return 'AKP';\n default:\n throw new JOSENotSupported('Unsupported \"alg\" value for a JSON Web Key Set');\n }\n}\nfunction isJWKSLike(jwks) {\n return (jwks &&\n typeof jwks === 'object' &&\n Array.isArray(jwks.keys) &&\n jwks.keys.every(isJWKLike));\n}\nfunction isJWKLike(key) {\n return isObject(key);\n}\nclass LocalJWKSet {\n #jwks;\n #cached = new WeakMap();\n constructor(jwks) {\n if (!isJWKSLike(jwks)) {\n throw new JWKSInvalid('JSON Web Key Set malformed');\n }\n this.#jwks = structuredClone(jwks);\n }\n jwks() {\n return this.#jwks;\n }\n async getKey(protectedHeader, token) {\n const { alg, kid } = { ...protectedHeader, ...token?.header };\n const kty = getKtyFromAlg(alg);\n const candidates = this.#jwks.keys.filter((jwk) => {\n let candidate = kty === jwk.kty;\n if (candidate && typeof kid === 'string') {\n candidate = kid === jwk.kid;\n }\n if (candidate && (typeof jwk.alg === 'string' || kty === 'AKP')) {\n candidate = alg === jwk.alg;\n }\n if (candidate && typeof jwk.use === 'string') {\n candidate = jwk.use === 'sig';\n }\n if (candidate && Array.isArray(jwk.key_ops)) {\n candidate = jwk.key_ops.includes('verify');\n }\n if (candidate) {\n switch (alg) {\n case 'ES256':\n candidate = jwk.crv === 'P-256';\n break;\n case 'ES384':\n candidate = jwk.crv === 'P-384';\n break;\n case 'ES512':\n candidate = jwk.crv === 'P-521';\n break;\n case 'Ed25519':\n case 'EdDSA':\n candidate = jwk.crv === 'Ed25519';\n break;\n }\n }\n return candidate;\n });\n const { 0: jwk, length } = candidates;\n if (length === 0) {\n throw new JWKSNoMatchingKey();\n }\n if (length !== 1) {\n const error = new JWKSMultipleMatchingKeys();\n const _cached = this.#cached;\n error[Symbol.asyncIterator] = async function* () {\n for (const jwk of candidates) {\n try {\n yield await importWithAlgCache(_cached, jwk, alg);\n }\n catch { }\n }\n };\n throw error;\n }\n return importWithAlgCache(this.#cached, jwk, alg);\n }\n}\nasync function importWithAlgCache(cache, jwk, alg) {\n const cached = cache.get(jwk) || cache.set(jwk, {}).get(jwk);\n if (cached[alg] === undefined) {\n const key = await importJWK({ ...jwk, ext: true }, alg);\n if (key instanceof Uint8Array || key.type !== 'public') {\n throw new JWKSInvalid('JSON Web Key Set members must be public keys');\n }\n cached[alg] = key;\n }\n return cached[alg];\n}\nexport function createLocalJWKSet(jwks) {\n const set = new LocalJWKSet(jwks);\n const localJWKSet = async (protectedHeader, token) => set.getKey(protectedHeader, token);\n Object.defineProperties(localJWKSet, {\n jwks: {\n value: () => structuredClone(set.jwks()),\n enumerable: false,\n configurable: false,\n writable: false,\n },\n });\n return localJWKSet;\n}\n","import { JOSEError, JWKSNoMatchingKey, JWKSTimeout } from '../util/errors.js';\nimport { createLocalJWKSet } from './local.js';\nimport { isObject } from '../lib/is_object.js';\nfunction isCloudflareWorkers() {\n return (typeof WebSocketPair !== 'undefined' ||\n (typeof navigator !== 'undefined' && navigator.userAgent === 'Cloudflare-Workers') ||\n (typeof EdgeRuntime !== 'undefined' && EdgeRuntime === 'vercel'));\n}\nlet USER_AGENT;\nif (typeof navigator === 'undefined' || !navigator.userAgent?.startsWith?.('Mozilla/5.0 ')) {\n const NAME = 'jose';\n const VERSION = 'v6.1.3';\n USER_AGENT = `${NAME}/${VERSION}`;\n}\nexport const customFetch = Symbol();\nasync function fetchJwks(url, headers, signal, fetchImpl = fetch) {\n const response = await fetchImpl(url, {\n method: 'GET',\n signal,\n redirect: 'manual',\n headers,\n }).catch((err) => {\n if (err.name === 'TimeoutError') {\n throw new JWKSTimeout();\n }\n throw err;\n });\n if (response.status !== 200) {\n throw new JOSEError('Expected 200 OK from the JSON Web Key Set HTTP response');\n }\n try {\n return await response.json();\n }\n catch {\n throw new JOSEError('Failed to parse the JSON Web Key Set HTTP response as JSON');\n }\n}\nexport const jwksCache = Symbol();\nfunction isFreshJwksCache(input, cacheMaxAge) {\n if (typeof input !== 'object' || input === null) {\n return false;\n }\n if (!('uat' in input) || typeof input.uat !== 'number' || Date.now() - input.uat >= cacheMaxAge) {\n return false;\n }\n if (!('jwks' in input) ||\n !isObject(input.jwks) ||\n !Array.isArray(input.jwks.keys) ||\n !Array.prototype.every.call(input.jwks.keys, isObject)) {\n return false;\n }\n return true;\n}\nclass RemoteJWKSet {\n #url;\n #timeoutDuration;\n #cooldownDuration;\n #cacheMaxAge;\n #jwksTimestamp;\n #pendingFetch;\n #headers;\n #customFetch;\n #local;\n #cache;\n constructor(url, options) {\n if (!(url instanceof URL)) {\n throw new TypeError('url must be an instance of URL');\n }\n this.#url = new URL(url.href);\n this.#timeoutDuration =\n typeof options?.timeoutDuration === 'number' ? options?.timeoutDuration : 5000;\n this.#cooldownDuration =\n typeof options?.cooldownDuration === 'number' ? options?.cooldownDuration : 30000;\n this.#cacheMaxAge = typeof options?.cacheMaxAge === 'number' ? options?.cacheMaxAge : 600000;\n this.#headers = new Headers(options?.headers);\n if (USER_AGENT && !this.#headers.has('User-Agent')) {\n this.#headers.set('User-Agent', USER_AGENT);\n }\n if (!this.#headers.has('accept')) {\n this.#headers.set('accept', 'application/json');\n this.#headers.append('accept', 'application/jwk-set+json');\n }\n this.#customFetch = options?.[customFetch];\n if (options?.[jwksCache] !== undefined) {\n this.#cache = options?.[jwksCache];\n if (isFreshJwksCache(options?.[jwksCache], this.#cacheMaxAge)) {\n this.#jwksTimestamp = this.#cache.uat;\n this.#local = createLocalJWKSet(this.#cache.jwks);\n }\n }\n }\n pendingFetch() {\n return !!this.#pendingFetch;\n }\n coolingDown() {\n return typeof this.#jwksTimestamp === 'number'\n ? Date.now() < this.#jwksTimestamp + this.#cooldownDuration\n : false;\n }\n fresh() {\n return typeof this.#jwksTimestamp === 'number'\n ? Date.now() < this.#jwksTimestamp + this.#cacheMaxAge\n : false;\n }\n jwks() {\n return this.#local?.jwks();\n }\n async getKey(protectedHeader, token) {\n if (!this.#local || !this.fresh()) {\n await this.reload();\n }\n try {\n return await this.#local(protectedHeader, token);\n }\n catch (err) {\n if (err instanceof JWKSNoMatchingKey) {\n if (this.coolingDown() === false) {\n await this.reload();\n return this.#local(protectedHeader, token);\n }\n }\n throw err;\n }\n }\n async reload() {\n if (this.#pendingFetch && isCloudflareWorkers()) {\n this.#pendingFetch = undefined;\n }\n this.#pendingFetch ||= fetchJwks(this.#url.href, this.#headers, AbortSignal.timeout(this.#timeoutDuration), this.#customFetch)\n .then((json) => {\n this.#local = createLocalJWKSet(json);\n if (this.#cache) {\n this.#cache.uat = Date.now();\n this.#cache.jwks = json;\n }\n this.#jwksTimestamp = Date.now();\n this.#pendingFetch = undefined;\n })\n .catch((err) => {\n this.#pendingFetch = undefined;\n throw err;\n });\n await this.#pendingFetch;\n }\n}\nexport function createRemoteJWKSet(url, options) {\n const set = new RemoteJWKSet(url, options);\n const remoteJWKSet = async (protectedHeader, token) => set.getKey(protectedHeader, token);\n Object.defineProperties(remoteJWKSet, {\n coolingDown: {\n get: () => set.coolingDown(),\n enumerable: true,\n configurable: false,\n },\n fresh: {\n get: () => set.fresh(),\n enumerable: true,\n configurable: false,\n },\n reload: {\n value: () => set.reload(),\n enumerable: true,\n configurable: false,\n writable: false,\n },\n reloading: {\n get: () => set.pendingFetch(),\n enumerable: true,\n configurable: false,\n },\n jwks: {\n value: () => set.jwks(),\n enumerable: true,\n configurable: false,\n writable: false,\n },\n });\n return remoteJWKSet;\n}\n","import * as b64u from '../util/base64url.js';\nimport { decoder } from '../lib/buffer_utils.js';\nimport { JWTInvalid } from '../util/errors.js';\nimport { validateClaimsSet, JWTClaimsBuilder } from '../lib/jwt_claims_set.js';\nexport class UnsecuredJWT {\n #jwt;\n constructor(payload = {}) {\n this.#jwt = new JWTClaimsBuilder(payload);\n }\n encode() {\n const header = b64u.encode(JSON.stringify({ alg: 'none' }));\n const payload = b64u.encode(this.#jwt.data());\n return `${header}.${payload}.`;\n }\n setIssuer(issuer) {\n this.#jwt.iss = issuer;\n return this;\n }\n setSubject(subject) {\n this.#jwt.sub = subject;\n return this;\n }\n setAudience(audience) {\n this.#jwt.aud = audience;\n return this;\n }\n setJti(jwtId) {\n this.#jwt.jti = jwtId;\n return this;\n }\n setNotBefore(input) {\n this.#jwt.nbf = input;\n return this;\n }\n setExpirationTime(input) {\n this.#jwt.exp = input;\n return this;\n }\n setIssuedAt(input) {\n this.#jwt.iat = input;\n return this;\n }\n static decode(jwt, options) {\n if (typeof jwt !== 'string') {\n throw new JWTInvalid('Unsecured JWT must be a string');\n }\n const { 0: encodedHeader, 1: encodedPayload, 2: signature, length } = jwt.split('.');\n if (length !== 3 || signature !== '') {\n throw new JWTInvalid('Invalid Unsecured JWT');\n }\n let header;\n try {\n header = JSON.parse(decoder.decode(b64u.decode(encodedHeader)));\n if (header.alg !== 'none')\n throw new Error();\n }\n catch {\n throw new JWTInvalid('Invalid Unsecured JWT');\n }\n const payload = validateClaimsSet(header, b64u.decode(encodedPayload), options);\n return { payload, header };\n }\n}\n","import { decode as b64u } from './base64url.js';\nimport { decoder } from '../lib/buffer_utils.js';\nimport { isObject } from '../lib/is_object.js';\nexport function decodeProtectedHeader(token) {\n let protectedB64u;\n if (typeof token === 'string') {\n const parts = token.split('.');\n if (parts.length === 3 || parts.length === 5) {\n ;\n [protectedB64u] = parts;\n }\n }\n else if (typeof token === 'object' && token) {\n if ('protected' in token) {\n protectedB64u = token.protected;\n }\n else {\n throw new TypeError('Token does not contain a Protected Header');\n }\n }\n try {\n if (typeof protectedB64u !== 'string' || !protectedB64u) {\n throw new Error();\n }\n const result = JSON.parse(decoder.decode(b64u(protectedB64u)));\n if (!isObject(result)) {\n throw new Error();\n }\n return result;\n }\n catch {\n throw new TypeError('Invalid Token or Protected Header formatting');\n }\n}\n","import { decode as b64u } from './base64url.js';\nimport { decoder } from '../lib/buffer_utils.js';\nimport { isObject } from '../lib/is_object.js';\nimport { JWTInvalid } from './errors.js';\nexport function decodeJwt(jwt) {\n if (typeof jwt !== 'string')\n throw new JWTInvalid('JWTs must use Compact JWS serialization, JWT must be a string');\n const { 1: payload, length } = jwt.split('.');\n if (length === 5)\n throw new JWTInvalid('Only JWTs using Compact JWS serialization can be decoded');\n if (length !== 3)\n throw new JWTInvalid('Invalid JWT');\n if (!payload)\n throw new JWTInvalid('JWTs must contain a payload');\n let decoded;\n try {\n decoded = b64u(payload);\n }\n catch {\n throw new JWTInvalid('Failed to base64url decode the payload');\n }\n let result;\n try {\n result = JSON.parse(decoder.decode(decoded));\n }\n catch {\n throw new JWTInvalid('Failed to parse the decoded payload as JSON');\n }\n if (!isObject(result))\n throw new JWTInvalid('Invalid JWT Claims Set');\n return result;\n}\n","import { JOSENotSupported } from '../util/errors.js';\nfunction getModulusLengthOption(options) {\n const modulusLength = options?.modulusLength ?? 2048;\n if (typeof modulusLength !== 'number' || modulusLength < 2048) {\n throw new JOSENotSupported('Invalid or unsupported modulusLength option provided, 2048 bits or larger keys must be used');\n }\n return modulusLength;\n}\nexport async function generateKeyPair(alg, options) {\n let algorithm;\n let keyUsages;\n switch (alg) {\n case 'PS256':\n case 'PS384':\n case 'PS512':\n algorithm = {\n name: 'RSA-PSS',\n hash: `SHA-${alg.slice(-3)}`,\n publicExponent: Uint8Array.of(0x01, 0x00, 0x01),\n modulusLength: getModulusLengthOption(options),\n };\n keyUsages = ['sign', 'verify'];\n break;\n case 'RS256':\n case 'RS384':\n case 'RS512':\n algorithm = {\n name: 'RSASSA-PKCS1-v1_5',\n hash: `SHA-${alg.slice(-3)}`,\n publicExponent: Uint8Array.of(0x01, 0x00, 0x01),\n modulusLength: getModulusLengthOption(options),\n };\n keyUsages = ['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(alg.slice(-3), 10) || 1}`,\n publicExponent: Uint8Array.of(0x01, 0x00, 0x01),\n modulusLength: getModulusLengthOption(options),\n };\n keyUsages = ['decrypt', 'unwrapKey', 'encrypt', 'wrapKey'];\n break;\n case 'ES256':\n algorithm = { name: 'ECDSA', namedCurve: 'P-256' };\n keyUsages = ['sign', 'verify'];\n break;\n case 'ES384':\n algorithm = { name: 'ECDSA', namedCurve: 'P-384' };\n keyUsages = ['sign', 'verify'];\n break;\n case 'ES512':\n algorithm = { name: 'ECDSA', namedCurve: 'P-521' };\n keyUsages = ['sign', 'verify'];\n break;\n case 'Ed25519':\n case 'EdDSA': {\n keyUsages = ['sign', 'verify'];\n algorithm = { name: 'Ed25519' };\n break;\n }\n case 'ML-DSA-44':\n case 'ML-DSA-65':\n case 'ML-DSA-87': {\n keyUsages = ['sign', 'verify'];\n algorithm = { name: alg };\n break;\n }\n case 'ECDH-ES':\n case 'ECDH-ES+A128KW':\n case 'ECDH-ES+A192KW':\n case 'ECDH-ES+A256KW': {\n keyUsages = ['deriveBits'];\n const crv = options?.crv ?? 'P-256';\n switch (crv) {\n case 'P-256':\n case 'P-384':\n case 'P-521': {\n algorithm = { name: 'ECDH', namedCurve: crv };\n break;\n }\n case 'X25519':\n algorithm = { name: 'X25519' };\n break;\n default:\n throw new JOSENotSupported('Invalid or unsupported crv option provided, supported values are P-256, P-384, P-521, and X25519');\n }\n break;\n }\n default:\n throw new JOSENotSupported('Invalid or unsupported JWK \"alg\" (Algorithm) Parameter value');\n }\n return crypto.subtle.generateKey(algorithm, options?.extractable ?? false, keyUsages);\n}\n","import { JOSENotSupported } from '../util/errors.js';\nexport async function generateSecret(alg, options) {\n let length;\n let algorithm;\n let keyUsages;\n switch (alg) {\n case 'HS256':\n case 'HS384':\n case 'HS512':\n length = parseInt(alg.slice(-3), 10);\n algorithm = { name: 'HMAC', hash: `SHA-${length}`, length };\n keyUsages = ['sign', 'verify'];\n break;\n case 'A128CBC-HS256':\n case 'A192CBC-HS384':\n case 'A256CBC-HS512':\n length = parseInt(alg.slice(-3), 10);\n return crypto.getRandomValues(new Uint8Array(length >> 3));\n case 'A128KW':\n case 'A192KW':\n case 'A256KW':\n length = parseInt(alg.slice(1, 4), 10);\n algorithm = { name: 'AES-KW', length };\n keyUsages = ['wrapKey', 'unwrapKey'];\n break;\n case 'A128GCMKW':\n case 'A192GCMKW':\n case 'A256GCMKW':\n case 'A128GCM':\n case 'A192GCM':\n case 'A256GCM':\n length = parseInt(alg.slice(1, 4), 10);\n algorithm = { name: 'AES-GCM', length };\n keyUsages = ['encrypt', 'decrypt'];\n break;\n default:\n throw new JOSENotSupported('Invalid or unsupported JWK \"alg\" (Algorithm) Parameter value');\n }\n return crypto.subtle.generateKey(algorithm, options?.extractable ?? false, keyUsages);\n}\n","export { compactDecrypt } from './jwe/compact/decrypt.js';\nexport { flattenedDecrypt } from './jwe/flattened/decrypt.js';\nexport { generalDecrypt } from './jwe/general/decrypt.js';\nexport { GeneralEncrypt } from './jwe/general/encrypt.js';\nexport { compactVerify } from './jws/compact/verify.js';\nexport { flattenedVerify } from './jws/flattened/verify.js';\nexport { generalVerify } from './jws/general/verify.js';\nexport { jwtVerify } from './jwt/verify.js';\nexport { jwtDecrypt } from './jwt/decrypt.js';\nexport { CompactEncrypt } from './jwe/compact/encrypt.js';\nexport { FlattenedEncrypt } from './jwe/flattened/encrypt.js';\nexport { CompactSign } from './jws/compact/sign.js';\nexport { FlattenedSign } from './jws/flattened/sign.js';\nexport { GeneralSign } from './jws/general/sign.js';\nexport { SignJWT } from './jwt/sign.js';\nexport { EncryptJWT } from './jwt/encrypt.js';\nexport { calculateJwkThumbprint, calculateJwkThumbprintUri } from './jwk/thumbprint.js';\nexport { EmbeddedJWK } from './jwk/embedded.js';\nexport { createLocalJWKSet } from './jwks/local.js';\nexport { createRemoteJWKSet, jwksCache, customFetch } from './jwks/remote.js';\nexport { UnsecuredJWT } from './jwt/unsecured.js';\nexport { exportPKCS8, exportSPKI, exportJWK } from './key/export.js';\nexport { importSPKI, importPKCS8, importX509, importJWK } from './key/import.js';\nexport { decodeProtectedHeader } from './util/decode_protected_header.js';\nexport { decodeJwt } from './util/decode_jwt.js';\nimport * as errors from './util/errors.js';\nexport { errors };\nexport { generateKeyPair } from './key/generate_key_pair.js';\nexport { generateSecret } from './key/generate_secret.js';\nimport * as base64url from './util/base64url.js';\nexport { base64url };\nexport const cryptoRuntime = 'WebCryptoAPI';\n","/**\n * Sylphx Connection URL Parser — SDK Self-Contained Copy\n *\n * Implements the canonical connection string format defined in ADR-055 §5.\n * This is a self-contained copy for SDK package independence (no app imports).\n *\n * Format:\n * sylphx://{credential}@{slug}.{domain}[:port][/v{version}]\n *\n * Examples:\n * sylphx://pk_prod_f19e5cdc3cc54f7ff81bdc26ec5bfbad@bold-river-a1b2c3.sylphx.com\n * sylphx://sk_prod_5120bfeb5120bfeb5120bfeb5120bfeb@bold-river-a1b2c3.sylphx.com/v1\n * sylphx://pk_dev_abc12345abc12345abc12345abc12345@calm-peak-z9x4d5.sylphx.dev\n *\n * Invariants:\n * - Protocol is always `sylphx:` (no exceptions)\n * - Credential matches `(pk|sk)_(dev|stg|prod|prev)_[a-f0-9]{32,64}`\n * - Host's first DNS label is the resource slug (validated by slug regex)\n * - `apiBaseUrl` is always HTTPS, with `/v{version}` appended (default `v1`)\n *\n * Parsing uses the WHATWG `URL` constructor — custom regex parsing is banned\n * because it is notoriously brittle (ADR-055 §5.3).\n */\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport type ConnectionCredentialType = 'pk' | 'sk'\nexport type ConnectionEnv = 'dev' | 'stg' | 'prod' | 'prev'\n\nexport interface ParsedConnectionUrl {\n\t/** Full credential string, e.g. `pk_prod_f19e...` */\n\treadonly credential: string\n\t/** Credential kind — `pk` (publishable) or `sk` (secret) */\n\treadonly credentialType: ConnectionCredentialType\n\t/** Target environment encoded in the credential */\n\treadonly env: ConnectionEnv\n\t/** First DNS label of the host — the resource slug (e.g. `bold-river-a1b2c3`) */\n\treadonly slug: string\n\t/** Full host including port when present (e.g. `bold-river-a1b2c3.sylphx.com`) */\n\treadonly host: string\n\t/** Ready-to-use SDK base URL, always HTTPS (e.g. `https://bold-river-a1b2c3.sylphx.com/v1`) */\n\treadonly apiBaseUrl: string\n}\n\n// ============================================================================\n// Constants\n// ============================================================================\n\nconst SYLPHX_PROTOCOL = 'sylphx:'\nconst DEFAULT_VERSION = 'v1'\n\n/**\n * Credential format — opaque token with type, env, and hex payload.\n * Hex payload is 32–64 chars to accommodate both 128-bit and 256-bit secrets.\n */\nexport const CREDENTIAL_REGEX = /^(pk|sk)_(dev|stg|prod|prev)_[a-f0-9]{32,64}$/\n\n/** Version segment, e.g. `v1`, `v2`, `v10`. */\nconst VERSION_REGEX = /^v[0-9]+$/\n\n/**\n * Slug validation regex — RFC 1035 DNS label.\n * Lowercase letters, numbers, and hyphens; must start and end with alnum.\n * Length 1–63.\n */\nconst SLUG_REGEX = /^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/\n\n// ============================================================================\n// Errors\n// ============================================================================\n\nexport class InvalidConnectionUrlError extends Error {\n\treadonly code = 'INVALID_CONNECTION_URL' as const\n\n\tconstructor(message: string) {\n\t\tsuper(message)\n\t\tthis.name = 'InvalidConnectionUrlError'\n\t\tObject.setPrototypeOf(this, InvalidConnectionUrlError.prototype)\n\t}\n}\n\n// ============================================================================\n// Internal helpers\n// ============================================================================\n\nfunction fail(reason: string): never {\n\tthrow new InvalidConnectionUrlError(`Invalid Sylphx connection URL: ${reason}`)\n}\n\nfunction parseCredential(raw: string): {\n\tcredentialType: ConnectionCredentialType\n\tenv: ConnectionEnv\n} {\n\tconst match = CREDENTIAL_REGEX.exec(raw)\n\tif (!match) {\n\t\tfail(`credential must match (pk|sk)_(dev|stg|prod|prev)_[a-f0-9]{32,64}, got \"${raw}\"`)\n\t}\n\treturn {\n\t\tcredentialType: match[1] as ConnectionCredentialType,\n\t\tenv: match[2] as ConnectionEnv,\n\t}\n}\n\nfunction validateSlug(candidate: string): string {\n\tif (!candidate || candidate.length > 63 || !SLUG_REGEX.test(candidate)) {\n\t\tfail(`slug \"${candidate}\" is not a valid DNS label (lowercase alnum + hyphens, 1-63 chars)`)\n\t}\n\treturn candidate\n}\n\n// ============================================================================\n// Public API\n// ============================================================================\n\n/**\n * Parse a Sylphx connection URL into its structured components.\n *\n * Throws `InvalidConnectionUrlError` on any structural problem.\n */\nexport function parseConnectionUrl(url: string): ParsedConnectionUrl {\n\tif (typeof url !== 'string' || url.length === 0) {\n\t\tfail('url must be a non-empty string')\n\t}\n\n\tlet parsed: URL\n\ttry {\n\t\tparsed = new URL(url)\n\t} catch {\n\t\tfail(`not a valid URL: \"${url}\"`)\n\t}\n\n\tif (parsed.protocol !== SYLPHX_PROTOCOL) {\n\t\tfail(`protocol must be \"sylphx:\", got \"${parsed.protocol}\"`)\n\t}\n\n\t// URL parses `sylphx://cred@host/path` but places `cred` in `username` only\n\t// when the authority is parsed. For non-special schemes, browsers/Node parse\n\t// the authority uniformly — we defensively read both `username` and `host`.\n\tconst credential = decodeURIComponent(parsed.username)\n\tif (!credential) {\n\t\tfail('missing credential (expected `sylphx://<credential>@<host>`)')\n\t}\n\tif (parsed.password) {\n\t\tfail('connection URL must not contain a password component')\n\t}\n\n\tconst { credentialType, env } = parseCredential(credential)\n\n\tconst host = parsed.host\n\tif (!host) {\n\t\tfail('missing host')\n\t}\n\n\t// Extract slug from the first DNS label\n\tconst hostname = parsed.hostname\n\tconst firstDot = hostname.indexOf('.')\n\tif (firstDot <= 0) {\n\t\tfail(`host \"${hostname}\" must contain at least one dot (slug.domain)`)\n\t}\n\tconst slugCandidate = hostname.slice(0, firstDot)\n\tconst domainSuffix = hostname.slice(firstDot + 1)\n\tif (!domainSuffix) {\n\t\tfail(`host \"${hostname}\" has empty domain suffix`)\n\t}\n\tconst slug = validateSlug(slugCandidate)\n\n\t// Path is either empty, `/`, or `/v{N}`\n\tconst rawPath = parsed.pathname.replace(/^\\/+/, '').replace(/\\/+$/, '')\n\tlet version = DEFAULT_VERSION\n\tif (rawPath !== '') {\n\t\tif (!VERSION_REGEX.test(rawPath)) {\n\t\t\tfail(`path \"${parsed.pathname}\" must be empty or match /v{N}`)\n\t\t}\n\t\tversion = rawPath\n\t}\n\n\tif (parsed.search) {\n\t\tfail('connection URL must not contain a query string')\n\t}\n\tif (parsed.hash) {\n\t\tfail('connection URL must not contain a fragment')\n\t}\n\n\tconst apiBaseUrl = `https://${host}/${version}`\n\n\treturn {\n\t\tcredential,\n\t\tcredentialType,\n\t\tenv,\n\t\tslug,\n\t\thost,\n\t\tapiBaseUrl,\n\t}\n}\n","/**\n * SDK Configuration — ADR-055 Connection URL API\n *\n * v0.5.0: The primary entry point is `createClient(url)` which accepts\n * a `sylphx://` connection URL. The old `createConfig({ ref, publicKey })`\n * API is removed.\n *\n * @example\n * ```typescript\n * import { createClient } from '@sylphx/sdk'\n *\n * const sylphx = createClient(process.env.SYLPHX_URL!)\n * // Parses: sylphx://pk_prod_{hex}@bold-river-a1b2c3.sylphx.com\n * ```\n */\n\nimport {\n\tCREDENTIAL_REGEX,\n\tInvalidConnectionUrlError,\n\ttype ParsedConnectionUrl,\n\tparseConnectionUrl,\n} from './connection-url'\nimport { DEFAULT_TIMEOUT_MS } from './constants'\nimport {\n\tNetworkError,\n\tRateLimitError,\n\tSylphxError,\n\ttype SylphxErrorCode,\n\tTimeoutError,\n} from './errors'\n\nexport type { ParsedConnectionUrl } from './connection-url'\n// Re-export connection URL types for consumers\nexport { InvalidConnectionUrlError } from './connection-url'\n\n// =============================================================================\n// Legacy format detection — produces clear migration errors\n// =============================================================================\n\n/** Matches old ADR-021 format: pk_{env}_{ref12}_{hex} or sk_{env}_{ref12}_{hex} (4 underscore segments) */\nconst LEGACY_EMBEDDED_REF_PATTERN = /^(pk|sk)_(dev|stg|prod|prev)_[a-z0-9]{12}_[a-f0-9]+$/\n\n/** Matches old app_* format: app_{env}_{anything} */\nconst LEGACY_APP_KEY_PATTERN = /^app_(dev|stg|prod|prev)_/\n\nconst MIGRATION_MESSAGE =\n\t'API key format has changed. Use a sylphx:// connection URL instead.\\n\\n' +\n\t'New format: sylphx://pk_prod_{hex}@your-slug.sylphx.com\\n\\n' +\n\t'Generate new credentials from the Sylphx Console → Your App → Environments.\\n' +\n\t'See https://docs.sylphx.com/migration for details.'\n\n/**\n * Detect legacy key formats and throw a helpful migration error.\n */\nfunction rejectLegacyKeyFormat(input: string): void {\n\tconst trimmed = input.trim().toLowerCase()\n\n\tif (LEGACY_APP_KEY_PATTERN.test(trimmed)) {\n\t\tthrow new SylphxError(`[Sylphx] ${MIGRATION_MESSAGE}`, { code: 'BAD_REQUEST' })\n\t}\n\n\tif (LEGACY_EMBEDDED_REF_PATTERN.test(trimmed)) {\n\t\tthrow new SylphxError(`[Sylphx] ${MIGRATION_MESSAGE}`, { code: 'BAD_REQUEST' })\n\t}\n}\n\n// =============================================================================\n// Config types\n// =============================================================================\n\n/**\n * SDK Configuration object — immutable, frozen.\n *\n * Created by `createClient()` or `createServerClient()`.\n * Passed to all pure SDK functions (`track()`, `signIn()`, etc.).\n */\nexport interface SylphxConfig {\n\t/** The credential string (pk_* or sk_*) */\n\treadonly credential: string\n\t/** Credential type: 'pk' (publishable) or 'sk' (secret) */\n\treadonly credentialType: 'pk' | 'sk'\n\t/** Target environment: dev, stg, prod, or prev */\n\treadonly env: 'dev' | 'stg' | 'prod' | 'prev'\n\t/** Resource slug (first DNS label), e.g. 'bold-river-a1b2c3' */\n\treadonly slug: string\n\t/** Pre-computed API base URL, e.g. 'https://bold-river-a1b2c3.sylphx.com/v1' */\n\treadonly baseUrl: string\n\t/** Optional access token for authenticated requests */\n\treadonly accessToken?: string\n\t/**\n\t * Secret key — populated when credentialType is 'sk'.\n\t * Backward-compatible alias for `credential` when credential is sk_*.\n\t */\n\treadonly secretKey?: string\n\t/**\n\t * Publishable key — populated when credentialType is 'pk'.\n\t * Backward-compatible alias for `credential` when credential is pk_*.\n\t */\n\treadonly publicKey?: string\n\t/**\n\t * @deprecated Use `slug`. Backward-compatible alias.\n\t */\n\treadonly ref: string\n}\n\n/**\n * Explicit components input — alternative to connection URL string.\n *\n * For multi-tenant apps or cases where components are stored separately.\n */\nexport interface SylphxClientInput {\n\t/** Resource slug, e.g. 'bold-river-a1b2c3' */\n\tslug?: string\n\t/** Publishable key (pk_*) — client-safe */\n\tpublicKey?: string\n\t/** Secret key (sk_*) — server-side only */\n\tsecretKey?: string\n\t/** Optional access token */\n\taccessToken?: string\n\t/** API domain override (default: api.sylphx.com) */\n\tdomain?: string\n\t/**\n\t * @deprecated Use `slug`. Accepted for backward compatibility during migration.\n\t */\n\tref?: string\n\t/**\n\t * @deprecated Use `domain`. Accepted for backward compatibility during migration.\n\t */\n\tplatformUrl?: string\n}\n\n/**\n * Build a frozen SylphxConfig with backward-compat fields (secretKey, publicKey, ref).\n */\nfunction freezeConfig(opts: {\n\tcredential: string\n\tcredentialType: 'pk' | 'sk'\n\tenv: 'dev' | 'stg' | 'prod' | 'prev'\n\tslug: string\n\tbaseUrl: string\n\taccessToken?: string\n}): SylphxConfig {\n\treturn Object.freeze({\n\t\tcredential: opts.credential,\n\t\tcredentialType: opts.credentialType,\n\t\tenv: opts.env,\n\t\tslug: opts.slug,\n\t\tbaseUrl: opts.baseUrl,\n\t\taccessToken: opts.accessToken,\n\t\t// Backward-compat aliases\n\t\tsecretKey: opts.credentialType === 'sk' ? opts.credential : undefined,\n\t\tpublicKey: opts.credentialType === 'pk' ? opts.credential : undefined,\n\t\tref: opts.slug,\n\t})\n}\n\n// =============================================================================\n// createClient — primary entry point (ADR-055)\n// =============================================================================\n\n/**\n * Create a Sylphx client from a connection URL or explicit components.\n *\n * This is the primary SDK entry point for client-side (browser) usage.\n * Accepts a `sylphx://` connection URL or an explicit components object.\n *\n * @example Connection URL (recommended)\n * ```typescript\n * const sylphx = createClient(process.env.NEXT_PUBLIC_SYLPHX_URL!)\n * // Parses: sylphx://pk_prod_{hex}@bold-river-a1b2c3.sylphx.com\n * ```\n *\n * @example Explicit components\n * ```typescript\n * const sylphx = createClient({\n * slug: 'bold-river-a1b2c3',\n * publicKey: 'pk_prod_f19e...',\n * })\n * ```\n */\nexport function createClient(input: string | SylphxClientInput): SylphxConfig {\n\tif (typeof input === 'string') {\n\t\treturn createConfigFromUrl(input)\n\t}\n\treturn createConfigFromComponents(input)\n}\n\n/**\n * Create a Sylphx server client from a connection URL or explicit components.\n *\n * Equivalent to `createClient()` but validates that a secret key (sk_*) is provided.\n * Use this for server-side operations that require elevated permissions.\n *\n * @example Connection URL (recommended)\n * ```typescript\n * const sylphx = createServerClient(process.env.SYLPHX_SECRET_URL!)\n * // Parses: sylphx://sk_prod_{hex}@bold-river-a1b2c3.sylphx.com\n * ```\n *\n * @example Explicit components\n * ```typescript\n * const sylphx = createServerClient({\n * slug: 'bold-river-a1b2c3',\n * secretKey: 'sk_prod_5120...',\n * })\n * ```\n */\nexport function createServerClient(input: string | SylphxClientInput): SylphxConfig {\n\tconst config = createClient(input)\n\n\tif (config.credentialType !== 'sk') {\n\t\tthrow new SylphxError(\n\t\t\t'[Sylphx] createServerClient() requires a secret key (sk_*). ' +\n\t\t\t\t'Use a SYLPHX_SECRET_URL with an sk_ credential, or pass { secretKey } in the components object.',\n\t\t\t{ code: 'BAD_REQUEST' },\n\t\t)\n\t}\n\n\treturn config\n}\n\n// =============================================================================\n// Internal construction\n// =============================================================================\n\nfunction createConfigFromUrl(url: string): SylphxConfig {\n\tif (!url || typeof url !== 'string') {\n\t\tthrow new SylphxError(\n\t\t\t'[Sylphx] Connection URL is required. Set SYLPHX_URL or NEXT_PUBLIC_SYLPHX_URL environment variable.\\n\\n' +\n\t\t\t\t'Format: sylphx://pk_prod_{hex}@your-slug.sylphx.com',\n\t\t\t{ code: 'BAD_REQUEST' },\n\t\t)\n\t}\n\n\tconst trimmed = url.trim()\n\n\t// Detect legacy key formats passed as the URL string\n\trejectLegacyKeyFormat(trimmed)\n\n\t// If someone passes a bare key instead of a URL, give a helpful error\n\tif (!trimmed.startsWith('sylphx://')) {\n\t\t// Check if it looks like a new-format bare credential\n\t\tif (CREDENTIAL_REGEX.test(trimmed)) {\n\t\t\tthrow new SylphxError(\n\t\t\t\t'[Sylphx] Received a bare credential instead of a connection URL.\\n\\n' +\n\t\t\t\t\t'Wrap it in a connection URL: sylphx://<credential>@<slug>.sylphx.com\\n' +\n\t\t\t\t\t'Or use createClient({ slug, publicKey }) for explicit components.',\n\t\t\t\t{ code: 'BAD_REQUEST' },\n\t\t\t)\n\t\t}\n\t\tthrow new SylphxError(\n\t\t\t`[Sylphx] Invalid connection URL — must start with \"sylphx://\". Got: \"${trimmed.slice(0, 30)}...\"`,\n\t\t\t{ code: 'BAD_REQUEST' },\n\t\t)\n\t}\n\n\tlet parsed: ParsedConnectionUrl\n\ttry {\n\t\tparsed = parseConnectionUrl(trimmed)\n\t} catch (err) {\n\t\tif (err instanceof InvalidConnectionUrlError) {\n\t\t\tthrow new SylphxError(err.message, { code: 'BAD_REQUEST', cause: err })\n\t\t}\n\t\tthrow err\n\t}\n\n\treturn freezeConfig({\n\t\tcredential: parsed.credential,\n\t\tcredentialType: parsed.credentialType,\n\t\tenv: parsed.env,\n\t\tslug: parsed.slug,\n\t\tbaseUrl: parsed.apiBaseUrl,\n\t})\n}\n\nfunction createConfigFromComponents(input: SylphxClientInput): SylphxConfig {\n\tconst credential = input.secretKey || input.publicKey\n\tif (!credential) {\n\t\tthrow new SylphxError('[Sylphx] Either publicKey or secretKey must be provided.', {\n\t\t\tcode: 'BAD_REQUEST',\n\t\t})\n\t}\n\n\t// Accept deprecated `ref` as fallback for `slug` during migration\n\tconst resolvedSlug = input.slug || input.ref\n\n\tif (!resolvedSlug) {\n\t\tthrow new SylphxError('[Sylphx] slug is required when using explicit components.', {\n\t\t\tcode: 'BAD_REQUEST',\n\t\t})\n\t}\n\n\t// Try to validate as ADR-055 credential first; if invalid, check for legacy\n\tconst trimmedCred = credential.trim().toLowerCase()\n\n\tif (CREDENTIAL_REGEX.test(trimmedCred)) {\n\t\t// New-format credential (ADR-055): pk_{env}_{hex} or sk_{env}_{hex}\n\t\tconst match = CREDENTIAL_REGEX.exec(trimmedCred)!\n\t\tconst credentialType = match[1] as 'pk' | 'sk'\n\t\tconst env = match[2] as 'dev' | 'stg' | 'prod' | 'prev'\n\n\t\tconst slug = resolvedSlug.trim().toLowerCase()\n\t\t// Default to `api.sylphx.com` (DNS-only) — `sylphx.com` is Cloudflare-\n\t\t// proxied with no per-slug origin mapping and returns 404 for any\n\t\t// `<slug>.sylphx.com` request. The legacy components path below\n\t\t// (4-segment credentials) already defaults to `api.sylphx.com`; this\n\t\t// brings the new-format path in line so both behave consistently and\n\t\t// match the ADR-055 SYLPHX_URL injected by the platform.\n\t\tconst domain = input.domain?.trim() || 'api.sylphx.com'\n\t\tconst baseUrl = `https://${slug}.${domain}/v1`\n\n\t\treturn freezeConfig({\n\t\t\tcredential: trimmedCred,\n\t\t\tcredentialType,\n\t\t\tenv,\n\t\t\tslug,\n\t\t\tbaseUrl,\n\t\t\taccessToken: input.accessToken,\n\t\t})\n\t}\n\n\t// Backward compat: accept old-format keys (pk_{env}_{ref}_{hex} or sk_{env}_{ref}_{hex})\n\t// These have 4 underscore-delimited segments. Extract env from segment 1.\n\tconst parts = trimmedCred.split('_')\n\tconst prefix = parts[0] as 'pk' | 'sk'\n\tif ((prefix === 'pk' || prefix === 'sk') && parts.length >= 3) {\n\t\tconst envSegment = parts[1]\n\t\tconst validEnvs = ['dev', 'stg', 'prod', 'prev']\n\t\tconst env = validEnvs.includes(envSegment)\n\t\t\t? (envSegment as 'dev' | 'stg' | 'prod' | 'prev')\n\t\t\t: 'prod'\n\n\t\tconst slug = resolvedSlug.trim().toLowerCase()\n\t\t// Accept deprecated platformUrl for base URL construction\n\t\tlet baseUrl: string\n\t\tif (input.platformUrl) {\n\t\t\tconst platform = input.platformUrl.trim().replace(/\\/$/, '')\n\t\t\tbaseUrl = platform.includes('/v1') ? platform : `${platform}/v1`\n\t\t} else {\n\t\t\tconst domain = input.domain?.trim() || 'api.sylphx.com'\n\t\t\tbaseUrl = `https://${slug}.${domain}/v1`\n\t\t}\n\n\t\treturn freezeConfig({\n\t\t\tcredential: trimmedCred,\n\t\t\tcredentialType: prefix,\n\t\t\tenv,\n\t\t\tslug,\n\t\t\tbaseUrl,\n\t\t\taccessToken: input.accessToken,\n\t\t})\n\t}\n\n\tthrow new SylphxError(\n\t\t`[Sylphx] Invalid credential format. Expected (pk|sk)_(dev|stg|prod|prev)_[a-f0-9]{32,64}. Got: \"${trimmedCred.slice(0, 30)}...\"`,\n\t\t{ code: 'BAD_REQUEST' },\n\t)\n}\n\n// =============================================================================\n// Config utilities\n// =============================================================================\n\n/**\n * Create a new config with an updated access token.\n *\n * Returns a new frozen config — does not mutate the original.\n *\n * @example\n * ```typescript\n * const authenticatedConfig = withToken(config, 'access_token_here')\n * ```\n */\nexport function withToken(config: SylphxConfig, accessToken: string): SylphxConfig {\n\treturn Object.freeze({\n\t\t...config,\n\t\taccessToken,\n\t})\n}\n\n// =============================================================================\n// Backward compatibility — createConfig (deprecated, will be removed)\n// =============================================================================\n\n/**\n * @deprecated Use `createClient()` or `createServerClient()` instead.\n * This function is kept temporarily for migration but will be removed.\n */\nexport type SylphxConfigInput = string | SylphxClientInput\n\n/**\n * @deprecated Use `createClient()` instead. See ADR-055.\n */\nexport const createConfig = createClient\n\n// =============================================================================\n// Request helpers — internal SDK plumbing\n// =============================================================================\n\n/**\n * Map HTTP status code to SylphxErrorCode\n */\nfunction httpStatusToErrorCode(status: number): SylphxErrorCode {\n\tswitch (status) {\n\t\tcase 400:\n\t\t\treturn 'BAD_REQUEST'\n\t\tcase 401:\n\t\t\treturn 'UNAUTHORIZED'\n\t\tcase 403:\n\t\t\treturn 'FORBIDDEN'\n\t\tcase 404:\n\t\t\treturn 'NOT_FOUND'\n\t\tcase 409:\n\t\t\treturn 'CONFLICT'\n\t\tcase 413:\n\t\t\treturn 'PAYLOAD_TOO_LARGE'\n\t\tcase 422:\n\t\t\treturn 'UNPROCESSABLE_ENTITY'\n\t\tcase 429:\n\t\t\treturn 'TOO_MANY_REQUESTS'\n\t\tcase 500:\n\t\t\treturn 'INTERNAL_SERVER_ERROR'\n\t\tcase 501:\n\t\t\treturn 'NOT_IMPLEMENTED'\n\t\tcase 502:\n\t\t\treturn 'BAD_GATEWAY'\n\t\tcase 503:\n\t\t\treturn 'SERVICE_UNAVAILABLE'\n\t\tcase 504:\n\t\t\treturn 'GATEWAY_TIMEOUT'\n\t\tdefault:\n\t\t\treturn status >= 500 ? 'INTERNAL_SERVER_ERROR' : 'BAD_REQUEST'\n\t}\n}\n\n/**\n * Internal: Build headers for API requests.\n *\n * Sends the credential as `x-app-secret` header.\n */\nexport function buildHeaders(config: SylphxConfig): Record<string, string> {\n\tconst headers: Record<string, string> = {\n\t\t'Content-Type': 'application/json',\n\t}\n\n\tif (config.credential) {\n\t\theaders['x-app-secret'] = config.credential\n\t}\n\tif (config.accessToken) {\n\t\theaders.Authorization = `Bearer ${config.accessToken}`\n\t}\n\n\treturn headers\n}\n\n/**\n * Internal: Build REST API URL.\n *\n * Appends path to the pre-computed base URL.\n */\nexport function buildApiUrl(config: SylphxConfig, path: string): string {\n\tconst base = config.baseUrl.replace(/\\/$/, '')\n\tconst cleanPath = path.startsWith('/') ? path : `/${path}`\n\treturn `${base}${cleanPath}`\n}\n\n/**\n * Internal: Call REST API endpoint.\n *\n * Features:\n * - Request timeout (default 30s) prevents infinite hangs\n * - Proper HTTP status code mapping to error codes\n * - Safe JSON parsing with error handling\n * - Idempotency key support (Stripe pattern)\n */\nexport async function callApi<TOutput>(\n\tconfig: SylphxConfig,\n\tpath: string,\n\toptions: {\n\t\tmethod?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'\n\t\tbody?: unknown\n\t\tquery?: Record<string, string | number | boolean | undefined>\n\t\ttimeout?: number\n\t\tsignal?: AbortSignal\n\t\tidempotencyKey?: string\n\t\theaders?: Record<string, string>\n\t} = {},\n): Promise<TOutput> {\n\tconst {\n\t\tmethod = 'GET',\n\t\tbody,\n\t\tquery,\n\t\ttimeout = DEFAULT_TIMEOUT_MS,\n\t\tsignal,\n\t\tidempotencyKey,\n\t\theaders: extraHeaders,\n\t} = options\n\n\tlet url = buildApiUrl(config, path)\n\n\t// Add query parameters\n\tif (query) {\n\t\tconst params = new URLSearchParams()\n\t\tfor (const [key, value] of Object.entries(query)) {\n\t\t\tif (value !== undefined) {\n\t\t\t\tparams.set(key, String(value))\n\t\t\t}\n\t\t}\n\t\tconst queryString = params.toString()\n\t\tif (queryString) {\n\t\t\turl += `?${queryString}`\n\t\t}\n\t}\n\n\t// Create AbortController for timeout\n\tconst controller = new AbortController()\n\tconst timeoutId = setTimeout(() => controller.abort(), timeout)\n\n\t// Combine user signal with timeout signal\n\tconst combinedSignal = signal ? AbortSignal.any([signal, controller.signal]) : controller.signal\n\n\tconst headers = buildHeaders(config)\n\n\t// Add idempotency key header for safe retries (Stripe pattern)\n\tif (idempotencyKey) {\n\t\theaders['Idempotency-Key'] = idempotencyKey\n\t}\n\n\t// Merge user-supplied headers\n\tif (extraHeaders) {\n\t\tfor (const [k, v] of Object.entries(extraHeaders)) {\n\t\t\theaders[k] = v\n\t\t}\n\t}\n\n\tconst fetchOptions: RequestInit = {\n\t\tmethod,\n\t\theaders,\n\t\tsignal: combinedSignal,\n\t}\n\n\tif (body) {\n\t\tfetchOptions.body = JSON.stringify(body)\n\t}\n\n\tlet response: Response\n\ttry {\n\t\tresponse = await fetch(url, fetchOptions)\n\t} catch (error) {\n\t\tclearTimeout(timeoutId)\n\n\t\t// Handle abort/timeout\n\t\tif (error instanceof Error) {\n\t\t\tif (error.name === 'AbortError') {\n\t\t\t\t// Check if it was our timeout or user cancellation\n\t\t\t\tif (controller.signal.aborted && !signal?.aborted) {\n\t\t\t\t\tthrow new TimeoutError(timeout)\n\t\t\t\t}\n\t\t\t\tthrow new SylphxError('Request aborted', {\n\t\t\t\t\tcode: 'ABORTED',\n\t\t\t\t\tcause: error,\n\t\t\t\t})\n\t\t\t}\n\t\t\t// Network errors\n\t\t\tthrow new NetworkError(error.message, { cause: error })\n\t\t}\n\t\tthrow new NetworkError('Network request failed')\n\t} finally {\n\t\tclearTimeout(timeoutId)\n\t}\n\n\tif (!response.ok) {\n\t\tconst errorBody = await response.text().catch(() => '')\n\t\tlet errorMessage = 'Request failed'\n\t\tlet errorData: Record<string, unknown> | undefined\n\n\t\t// Safe JSON parsing\n\t\tif (errorBody) {\n\t\t\ttry {\n\t\t\t\tconst parsed = JSON.parse(errorBody) as {\n\t\t\t\t\terror?: { message?: string }\n\t\t\t\t\tmessage?: string\n\t\t\t\t}\n\t\t\t\terrorMessage = parsed.error?.message ?? parsed.message ?? errorMessage\n\t\t\t\terrorData = parsed.error as Record<string, unknown> | undefined\n\t\t\t} catch {\n\t\t\t\terrorMessage = response.statusText || errorMessage\n\t\t\t}\n\t\t}\n\n\t\tconst errorCode = httpStatusToErrorCode(response.status)\n\n\t\t// Extract rate limit headers (Stripe SDK pattern)\n\t\tconst retryAfterHeader = response.headers.get('Retry-After')\n\t\tconst rateLimitLimit = response.headers.get('X-RateLimit-Limit')\n\t\tconst rateLimitRemaining = response.headers.get('X-RateLimit-Remaining')\n\t\tconst rateLimitReset = response.headers.get('X-RateLimit-Reset')\n\n\t\tconst retryAfter = retryAfterHeader ? Number.parseInt(retryAfterHeader, 10) : undefined\n\n\t\t// Use specialized RateLimitError for 429 responses\n\t\tif (response.status === 429) {\n\t\t\tthrow new RateLimitError(errorMessage || 'Too many requests', {\n\t\t\t\tstatus: response.status,\n\t\t\t\tdata: errorData,\n\t\t\t\tretryAfter,\n\t\t\t\tlimit: rateLimitLimit ? Number.parseInt(rateLimitLimit, 10) : undefined,\n\t\t\t\tremaining: rateLimitRemaining ? Number.parseInt(rateLimitRemaining, 10) : undefined,\n\t\t\t\tresetAt: rateLimitReset ? Number.parseInt(rateLimitReset, 10) : undefined,\n\t\t\t})\n\t\t}\n\n\t\tthrow new SylphxError(errorMessage, {\n\t\t\tcode: errorCode,\n\t\t\tstatus: response.status,\n\t\t\tdata: errorData,\n\t\t\tretryAfter,\n\t\t})\n\t}\n\n\t// Handle empty responses (204 No Content)\n\tconst text = await response.text()\n\tif (!text) {\n\t\treturn {} as TOutput\n\t}\n\n\t// Safe JSON parsing for response body\n\ttry {\n\t\treturn JSON.parse(text) as TOutput\n\t} catch (error) {\n\t\tthrow new SylphxError('Failed to parse response', {\n\t\t\tcode: 'PARSE_ERROR',\n\t\t\tcause: error instanceof Error ? error : undefined,\n\t\t\tdata: { body: text.slice(0, 200) },\n\t\t})\n\t}\n}\n","/**\n * SDK Debug Mode\n *\n * Centralized debug logging for the SDK.\n *\n * Enable via:\n * - Browser: `localStorage.setItem('sylphx_debug', 'true')`\n * - Node.js: `SYLPHX_DEBUG=true`\n *\n * Debug messages are namespaced with [Sylphx] prefix for easy filtering.\n */\n\n// ============================================================================\n// Debug Configuration\n// ============================================================================\n\n/** Storage key for browser-side debug toggle */\nconst DEBUG_STORAGE_KEY = 'sylphx_debug'\n\n/**\n * Check if debug mode is enabled\n *\n * Checks multiple sources in order:\n * 1. localStorage (browser)\n * 2. SYLPHX_DEBUG environment variable\n * 3. NODE_ENV === 'development' with explicit opt-in\n */\nfunction isDebugEnabled(): boolean {\n\t// Browser environment\n\tif (typeof window !== 'undefined' && typeof localStorage !== 'undefined') {\n\t\ttry {\n\t\t\treturn localStorage.getItem(DEBUG_STORAGE_KEY) === 'true'\n\t\t} catch {\n\t\t\t// localStorage may be blocked in some contexts\n\t\t\treturn false\n\t\t}\n\t}\n\n\t// Node.js environment\n\tif (typeof process !== 'undefined' && process.env) {\n\t\treturn process.env.SYLPHX_DEBUG === 'true'\n\t}\n\n\treturn false\n}\n\n// Cache the debug state to avoid repeated localStorage/env checks\nlet debugModeCache: boolean | null = null\n\n/**\n * Whether debug mode is currently enabled\n *\n * Cached after first access for performance.\n */\nexport function getDebugMode(): boolean {\n\tif (debugModeCache === null) {\n\t\tdebugModeCache = isDebugEnabled()\n\t}\n\treturn debugModeCache\n}\n\n/**\n * Reset debug mode cache (for testing)\n */\nexport function resetDebugModeCache(): void {\n\tdebugModeCache = null\n}\n\n// ============================================================================\n// Debug Logging\n// ============================================================================\n\n/** Debug log categories */\nexport type DebugCategory =\n\t| 'auth'\n\t| 'api'\n\t| 'analytics'\n\t| 'flags'\n\t| 'storage'\n\t| 'cache'\n\t| 'token'\n\t| 'webhook'\n\t| 'error'\n\n/**\n * Log a debug message with category prefix\n *\n * @example\n * ```ts\n * debugLog('auth', 'Token refreshed', { expiresIn: 300 })\n * // [Sylphx auth] Token refreshed { expiresIn: 300 }\n * ```\n */\nexport function debugLog(category: DebugCategory, message: string, data?: unknown): void {\n\tif (!getDebugMode()) return\n\n\tconst _prefix = `[Sylphx ${category}]`\n\n\tif (data !== undefined) {\n\t} else {\n\t}\n}\n\n/**\n * Log a debug warning with category prefix\n */\nexport function debugWarn(category: DebugCategory, message: string, data?: unknown): void {\n\tif (!getDebugMode()) return\n\n\tconst prefix = `[Sylphx ${category}]`\n\n\tif (data !== undefined) {\n\t\tconsole.warn(prefix, message, data)\n\t} else {\n\t\tconsole.warn(prefix, message)\n\t}\n}\n\n/**\n * Log a debug error with category prefix\n *\n * Note: This always logs when debug mode is enabled, regardless of error severity.\n * Production error tracking should use the error tracking service, not this.\n */\nexport function debugError(category: DebugCategory, message: string, error?: unknown): void {\n\tif (!getDebugMode()) return\n\n\tconst prefix = `[Sylphx ${category}]`\n\n\tif (error !== undefined) {\n\t\tconsole.error(prefix, message, error)\n\t} else {\n\t\tconsole.error(prefix, message)\n\t}\n}\n\n// ============================================================================\n// Performance Timing\n// ============================================================================\n\n/**\n * Create a debug timer for measuring operation duration\n *\n * @example\n * ```ts\n * const timer = debugTimer('api', 'Fetching user profile')\n * // ... operation ...\n * timer.end() // Logs duration if debug mode enabled\n * ```\n */\nexport function debugTimer(category: DebugCategory, operation: string): { end: () => void } {\n\tif (!getDebugMode()) {\n\t\treturn { end: () => {} }\n\t}\n\n\tconst start = performance.now()\n\n\treturn {\n\t\tend() {\n\t\t\tconst duration = performance.now() - start\n\t\t\tdebugLog(category, `${operation} completed`, {\n\t\t\t\tdurationMs: Math.round(duration),\n\t\t\t})\n\t\t},\n\t}\n}\n\n// ============================================================================\n// Browser Console Helpers\n// ============================================================================\n\n/**\n * Enable debug mode from browser console\n *\n * Call this in the browser console to enable debug logging:\n * ```js\n * window.__sylphx?.enableDebug()\n * ```\n */\nexport function enableDebug(): void {\n\tif (typeof localStorage === 'undefined') {\n\t\tconsole.warn('[Sylphx] Debug mode can only be enabled in browser environments')\n\t\treturn\n\t}\n\n\ttry {\n\t\tlocalStorage.setItem(DEBUG_STORAGE_KEY, 'true')\n\t\tdebugModeCache = true\n\t} catch (e) {\n\t\tconsole.warn('[Sylphx] Failed to enable debug mode:', e)\n\t}\n}\n\n/**\n * Disable debug mode from browser console\n */\nexport function disableDebug(): void {\n\tif (typeof localStorage === 'undefined') {\n\t\tconsole.warn('[Sylphx] Debug mode can only be disabled in browser environments')\n\t\treturn\n\t}\n\n\ttry {\n\t\tlocalStorage.removeItem(DEBUG_STORAGE_KEY)\n\t\tdebugModeCache = false\n\t} catch (e) {\n\t\tconsole.warn('[Sylphx] Failed to disable debug mode:', e)\n\t}\n}\n\n// ============================================================================\n// Global Window Helper (Browser Only)\n// ============================================================================\n\n/**\n * Install debug helpers on window.__sylphx\n *\n * This is called automatically when the SDK is loaded in the browser,\n * providing developers easy console access to debug utilities.\n */\nexport function installGlobalDebugHelpers(): void {\n\tif (typeof window === 'undefined') return\n\n\t// Use type assertion to extend window\n\tconst w = window as typeof window & {\n\t\t__sylphx?: {\n\t\t\tenableDebug: typeof enableDebug\n\t\t\tdisableDebug: typeof disableDebug\n\t\t\tisDebugEnabled: typeof getDebugMode\n\t\t}\n\t}\n\n\tw.__sylphx = {\n\t\tenableDebug,\n\t\tdisableDebug,\n\t\tisDebugEnabled: getDebugMode,\n\t}\n}\n","/**\n * REST Client for Sylphx Platform\n *\n * Type-safe REST API client built on plain `fetch` (no runtime `openapi-fetch`\n * dependency — ADR-084 routes types through `@sylphx/contract` so the codegen\n * layer no longer needs a transport library of its own). Public surface is\n * preserved: consumers still call `client.GET('/path')`, `client.POST(...)`,\n * etc. The middleware chain (deduplication → circuit breaker → ETag →\n * retry) runs in the same order as the previous implementation.\n *\n * @example\n * ```typescript\n * import { createRestClient } from '@sylphx/sdk'\n *\n * const client = createRestClient({\n * secretKey: process.env.SYLPHX_SECRET_KEY!,\n * })\n *\n * const { data: user, error } = await client.GET('/auth/me')\n * const { data: result } = await client.POST('/auth/login', {\n * body: { email, password },\n * })\n * ```\n */\n\nimport {\n\tBASE_RETRY_DELAY_MS,\n\tCIRCUIT_BREAKER_FAILURE_THRESHOLD,\n\tCIRCUIT_BREAKER_OPEN_DURATION_MS,\n\tCIRCUIT_BREAKER_WINDOW_MS,\n\tDEFAULT_SDK_API_HOST,\n\tDEFAULT_TIMEOUT_MS,\n\tETAG_CACHE_MAX_ENTRIES,\n\tETAG_CACHE_TTL_MS,\n\tMAX_RETRY_DELAY_MS,\n\tSDK_API_PATH,\n\tSDK_PLATFORM,\n\tSDK_VERSION,\n} from './constants'\nimport { exponentialBackoff } from './errors'\nimport { validateAndSanitizeSecretKey } from './key-validation'\n\n/**\n * Retry configuration for automatic request retries\n */\nexport interface RetryConfig {\n\t/** Maximum number of retries (default: 3) */\n\tmaxRetries?: number\n\t/** Base delay in milliseconds (default: 1000) */\n\tbaseDelay?: number\n\t/** Maximum delay in milliseconds (default: 30000) */\n\tmaxDelay?: number\n\t/** Custom function to determine if error is retryable */\n\tshouldRetry?: (status: number, attempt: number) => boolean\n\t/** Request timeout in milliseconds (default: 30000) */\n\ttimeout?: number\n}\n\n/**\n * Request deduplication configuration\n */\nexport interface DeduplicationConfig {\n\t/** Enable request deduplication (default: true) */\n\tenabled?: boolean\n\t/** HTTP methods to deduplicate (default: ['GET']) */\n\tmethods?: ('GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH')[]\n}\n\n/**\n * Circuit breaker configuration (AWS/Resilience4j pattern)\n *\n * Prevents cascade failures by fast-failing when service is unhealthy.\n * States: CLOSED (normal) → OPEN (failing) → HALF_OPEN (testing)\n */\nexport interface CircuitBreakerConfig {\n\t/** Enable circuit breaker (default: true) */\n\tenabled?: boolean\n\t/** Number of failures before opening circuit (default: 5) */\n\tfailureThreshold?: number\n\t/** Time window for counting failures in ms (default: 10000) */\n\twindowMs?: number\n\t/** How long circuit stays open in ms (default: 30000) */\n\topenDurationMs?: number\n\t/** Custom function to determine if response is a failure */\n\tisFailure?: (status: number) => boolean\n}\n\n/**\n * ETag/Conditional request configuration (HTTP caching pattern)\n *\n * Enables HTTP conditional requests with If-None-Match header\n * to avoid re-downloading unchanged data (saves bandwidth).\n */\nexport interface ETagConfig {\n\t/** Enable ETag caching (default: true for GET requests) */\n\tenabled?: boolean\n\t/** Maximum cache entries (default: 100) */\n\tmaxEntries?: number\n\t/** Cache TTL in milliseconds (default: 5 minutes) */\n\tttlMs?: number\n}\n\n/**\n * Configuration for the REST client\n *\n * The app key identifies the app — no separate app ID needed.\n */\nexport interface RestClientConfig {\n\t/**\n\t * Your app key — identifies the app and environment.\n\t *\n\t * Accepts either:\n\t * - Secret key (sk_dev_, sk_stg_, sk_prod_) — full access, server-side only\n\t * - Publishable key (app_dev_, app_stg_, app_prod_) — limited access, safe for client\n\t */\n\tsecretKey: string\n\t/** Platform URL (default: https://sylphx.com) */\n\tplatformUrl?: string\n\t/** Retry configuration (default: 3 retries with exponential backoff) */\n\tretry?: RetryConfig | false\n\t/**\n\t * Request deduplication configuration (default: enabled for GET)\n\t *\n\t * Prevents duplicate concurrent requests for the same resource.\n\t * When multiple components request the same data simultaneously,\n\t * only one API call is made and the result is shared.\n\t */\n\tdeduplication?: DeduplicationConfig | false\n\t/**\n\t * Circuit breaker configuration (default: enabled)\n\t *\n\t * Prevents cascade failures by fast-failing when service is unhealthy.\n\t * Opens after 5 failures in 10s, stays open for 30s, then allows test request.\n\t */\n\tcircuitBreaker?: CircuitBreakerConfig | false\n\t/**\n\t * ETag caching configuration (default: enabled for GET)\n\t *\n\t * Uses HTTP conditional requests to avoid re-downloading unchanged data.\n\t * Saves bandwidth by returning 304 Not Modified when content hasn't changed.\n\t */\n\tetag?: ETagConfig | false\n}\n\n/**\n * Dynamic configuration that can change at runtime (e.g., access token)\n */\nexport interface RestDynamicConfig {\n\t/** Your secret key (sk_* or app_*) — identifies the app */\n\tsecretKey?: string\n\t/** Platform URL (default: https://sylphx.com) */\n\tplatformUrl?: string\n\t/** Get the current access token (called on each request) */\n\tgetAccessToken?: () => string | null | undefined\n\t/** Retry configuration (default: 3 retries with exponential backoff) */\n\tretry?: RetryConfig | false\n\t/** Request deduplication configuration (default: enabled for GET) */\n\tdeduplication?: DeduplicationConfig | false\n\t/** Circuit breaker configuration (default: enabled) */\n\tcircuitBreaker?: CircuitBreakerConfig | false\n\t/** ETag caching configuration (default: enabled for GET) */\n\tetag?: ETagConfig | false\n}\n\n// ============================================================================\n// Middleware Plumbing\n// ============================================================================\n\n/**\n * Middleware contract — kept structurally identical to the previous\n * `openapi-fetch` shape so existing implementations (dedup / circuit breaker\n * / ETag / retry) compose without change.\n */\nexport interface Middleware {\n\tonRequest?: (ctx: { request: Request }) => Promise<Request | undefined> | Request | undefined\n\tonResponse?: (ctx: {\n\t\trequest: Request\n\t\tresponse: Response\n\t}) => Promise<Response | undefined> | Response | undefined\n}\n\n/**\n * Run middleware pipeline over a request → response round-trip.\n *\n * `onRequest` handlers may mutate/replace the outgoing `Request`. One of them\n * may throw to short-circuit the call (circuit breaker uses this). All\n * `onResponse` handlers run in the order middleware was registered, so later\n * middleware observes earlier middleware's transforms.\n */\nasync function runPipeline(\n\tmiddlewares: readonly Middleware[],\n\tinitial: Request,\n): Promise<Response> {\n\tlet request = initial\n\tfor (const mw of middlewares) {\n\t\tif (mw.onRequest) {\n\t\t\tconst next = await mw.onRequest({ request })\n\t\t\tif (next) request = next\n\t\t}\n\t}\n\n\tlet response = await fetch(request)\n\n\tfor (const mw of middlewares) {\n\t\tif (mw.onResponse) {\n\t\t\tconst next = await mw.onResponse({ request, response })\n\t\t\tif (next) response = next\n\t\t}\n\t}\n\n\treturn response\n}\n\n/**\n * Serialize a URL + query object. Undefined values are dropped. Values are\n * coerced to string via URLSearchParams (matches the previous openapi-fetch\n * behaviour — `{ foo: undefined }` does not emit `?foo=undefined`).\n */\nfunction buildUrl(baseUrl: string, path: string, params?: Record<string, unknown>): string {\n\tconst url = `${baseUrl}${path}`\n\tif (!params) return url\n\tconst entries = Object.entries(params).filter(([, v]) => v !== undefined)\n\tif (entries.length === 0) return url\n\tconst search = new URLSearchParams(\n\t\tentries.map(([k, v]) => [k, String(v)] as [string, string]),\n\t).toString()\n\treturn `${url}?${search}`\n}\n\n/**\n * Options for an HTTP request — structural subset of `openapi-fetch`'s\n * `FetchOptions` so existing callsites (`client.GET('/path', { params: {...} })`)\n * continue to compile.\n */\nexport interface RequestOptions {\n\tbody?: unknown\n\tparams?: {\n\t\tpath?: Record<string, string>\n\t\tquery?: Record<string, unknown>\n\t}\n\theaders?: Record<string, string>\n}\n\n/**\n * Response envelope — `{ data, error, response }` mirroring `openapi-fetch`.\n * `data` is present on 2xx, `error` on non-2xx; both carry the parsed JSON\n * body when the server returns one. `response` is always the raw `Response`\n * so consumers can read headers (Content-Type, Retry-After, etc.).\n */\nexport interface FetchResponse<TOk, TError> {\n\tdata?: TOk\n\terror?: TError\n\tresponse: Response\n}\n\n/**\n * Replace `{path}` style tokens with URL-encoded values. Mirrors\n * openapi-fetch's `params.path` substitution.\n */\nfunction interpolatePath(path: string, pathParams?: Record<string, string>): string {\n\tif (!pathParams) return path\n\treturn path.replace(/\\{(\\w+)\\}/g, (_match, key: string) => {\n\t\tconst value = pathParams[key]\n\t\tif (value === undefined) return `{${key}}`\n\t\treturn encodeURIComponent(value)\n\t})\n}\n\nasync function executeRequest<TOk = unknown, TError = unknown>(\n\tmethod: string,\n\tbaseUrl: string,\n\tpath: string,\n\toptions: RequestOptions | undefined,\n\tbaseHeaders: Record<string, string>,\n\tmiddlewares: readonly Middleware[],\n): Promise<FetchResponse<TOk, TError>> {\n\tconst finalPath = interpolatePath(path, options?.params?.path)\n\tconst url = buildUrl(baseUrl, finalPath, options?.params?.query)\n\n\tconst headers: Record<string, string> = { ...baseHeaders, ...options?.headers }\n\tconst init: RequestInit = { method, headers }\n\tif (options?.body !== undefined) {\n\t\tinit.body = typeof options.body === 'string' ? options.body : JSON.stringify(options.body)\n\t\tif (!headers['Content-Type'] && !headers['content-type']) {\n\t\t\theaders['Content-Type'] = 'application/json'\n\t\t}\n\t}\n\n\tconst request = new Request(url, init)\n\tconst response = await runPipeline(middlewares, request)\n\n\t// openapi-fetch's envelope:\n\t// - 2xx → { data: parsedBody, response }\n\t// - non-2xx → { error: parsedBody, response }\n\t// - parse failure → parsed becomes undefined on either branch (consumers\n\t// fall back to `response.text()` themselves).\n\tconst contentType = response.headers.get('content-type') ?? ''\n\tlet parsed: unknown\n\tif (contentType.includes('json')) {\n\t\ttry {\n\t\t\tparsed = await response.clone().json()\n\t\t} catch {\n\t\t\tparsed = undefined\n\t\t}\n\t} else if (response.status !== 204 && response.status !== 205) {\n\t\ttry {\n\t\t\tconst text = await response.clone().text()\n\t\t\tparsed = text === '' ? undefined : text\n\t\t} catch {\n\t\t\tparsed = undefined\n\t\t}\n\t}\n\n\tif (response.ok) {\n\t\treturn { data: parsed as TOk, response }\n\t}\n\treturn { error: parsed as TError, response }\n}\n\n/**\n * The typed method surface. Callers pass a path + options; return envelope\n * follows openapi-fetch's shape so migration is drop-in for the small number\n * of internal callers that relied on `.GET` / `.POST` etc.\n */\nexport interface RestClient {\n\tGET<TOk = unknown, TError = unknown>(\n\t\tpath: string,\n\t\toptions?: RequestOptions,\n\t): Promise<FetchResponse<TOk, TError>>\n\tPOST<TOk = unknown, TError = unknown>(\n\t\tpath: string,\n\t\toptions?: RequestOptions,\n\t): Promise<FetchResponse<TOk, TError>>\n\tPUT<TOk = unknown, TError = unknown>(\n\t\tpath: string,\n\t\toptions?: RequestOptions,\n\t): Promise<FetchResponse<TOk, TError>>\n\tPATCH<TOk = unknown, TError = unknown>(\n\t\tpath: string,\n\t\toptions?: RequestOptions,\n\t): Promise<FetchResponse<TOk, TError>>\n\tDELETE<TOk = unknown, TError = unknown>(\n\t\tpath: string,\n\t\toptions?: RequestOptions,\n\t): Promise<FetchResponse<TOk, TError>>\n\tHEAD<TOk = unknown, TError = unknown>(\n\t\tpath: string,\n\t\toptions?: RequestOptions,\n\t): Promise<FetchResponse<TOk, TError>>\n\tOPTIONS<TOk = unknown, TError = unknown>(\n\t\tpath: string,\n\t\toptions?: RequestOptions,\n\t): Promise<FetchResponse<TOk, TError>>\n\tuse(...middleware: readonly Middleware[]): void\n}\n\nexport type DynamicRestClient = RestClient\n\n/**\n * Build a method-dispatch REST client. Each verb thin-wraps `executeRequest`\n * so middleware composition and request shape stay identical across verbs.\n */\nfunction buildClient(\n\tbaseUrl: string,\n\tbaseHeaders: Record<string, string>,\n): { client: RestClient; middlewares: Middleware[] } {\n\tconst middlewares: Middleware[] = []\n\tconst dispatch =\n\t\t<TOk, TError>(method: string) =>\n\t\t(path: string, options?: RequestOptions) =>\n\t\t\texecuteRequest<TOk, TError>(method, baseUrl, path, options, baseHeaders, middlewares)\n\n\tconst client: RestClient = {\n\t\tGET: dispatch('GET'),\n\t\tPOST: dispatch('POST'),\n\t\tPUT: dispatch('PUT'),\n\t\tPATCH: dispatch('PATCH'),\n\t\tDELETE: dispatch('DELETE'),\n\t\tHEAD: dispatch('HEAD'),\n\t\tOPTIONS: dispatch('OPTIONS'),\n\t\tuse(...mws: readonly Middleware[]) {\n\t\t\tmiddlewares.push(...mws)\n\t\t},\n\t}\n\n\treturn { client, middlewares }\n}\n\n/**\n * Create auth middleware that adds app credentials, access token, and SDK headers\n */\nfunction createAuthMiddleware(config: RestDynamicConfig): Middleware {\n\treturn {\n\t\tasync onRequest({ request }) {\n\t\t\t// Add SDK identification headers for debugging and analytics\n\t\t\trequest.headers.set('X-SDK-Version', SDK_VERSION)\n\t\t\trequest.headers.set('X-SDK-Platform', SDK_PLATFORM)\n\n\t\t\t// Add secret key if provided — identifies the app\n\t\t\tif (config.secretKey) {\n\t\t\t\trequest.headers.set('x-app-secret', config.secretKey)\n\t\t\t}\n\n\t\t\t// Add access token if available\n\t\t\tconst token = config.getAccessToken?.()\n\t\t\tif (token) {\n\t\t\t\trequest.headers.set('Authorization', `Bearer ${token}`)\n\t\t\t}\n\n\t\t\treturn request\n\t\t},\n\t}\n}\n\n/**\n * Check if a status code is retryable\n */\nfunction isRetryableStatus(status: number): boolean {\n\treturn status >= 500 || status === 429\n}\n\n// ============================================================================\n// Request Deduplication (React Query/SWR pattern)\n// ============================================================================\n\n/**\n * In-flight request tracking for deduplication\n *\n * When the same request is made multiple times concurrently,\n * we return the existing promise instead of making a new request.\n * This prevents duplicate API calls and improves efficiency.\n */\nconst inFlightRequests = new Map<string, Promise<Response>>()\n\n/**\n * Generate a unique key for a request (for deduplication)\n */\nasync function getRequestKey(request: Request): Promise<string> {\n\tconst body = request.body ? await request.clone().text() : ''\n\treturn `${request.method}:${request.url}:${body}`\n}\n\n/**\n * Create request deduplication middleware (React Query/SWR pattern)\n *\n * Features:\n * - Deduplicates concurrent identical requests\n * - Only applies to GET requests by default (safe to dedupe)\n * - POST/PUT/DELETE are always executed (mutations must run)\n * - Cleans up in-flight tracking after completion\n *\n * @param config - Whether to enable deduplication (default: GET only)\n */\nfunction createDeduplicationMiddleware(\n\tconfig: { enabled?: boolean; methods?: ('GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH')[] } = {},\n): Middleware {\n\tconst { enabled = true, methods = ['GET'] } = config\n\n\tif (!enabled) {\n\t\treturn {\n\t\t\tasync onRequest({ request }) {\n\t\t\t\treturn request\n\t\t\t},\n\t\t}\n\t}\n\n\treturn {\n\t\tasync onRequest({ request }) {\n\t\t\t// Only dedupe specified methods (default: GET only)\n\t\t\tif (!methods.includes(request.method as 'GET')) {\n\t\t\t\treturn request\n\t\t\t}\n\n\t\t\tconst key = await getRequestKey(request)\n\n\t\t\t// Check if there's an in-flight request\n\t\t\tconst existing = inFlightRequests.get(key)\n\t\t\tif (existing) {\n\t\t\t\t// Return a new Request that will be handled specially in onResponse\n\t\t\t\tconst deduped = request.clone()\n\t\t\t\t;(deduped as unknown as { _dedupKey: string })._dedupKey = key\n\t\t\t\treturn deduped\n\t\t\t}\n\t\t\t// Mark request key (so onResponse knows to track it)\n\t\t\t;(request as unknown as { _dedupKey: string })._dedupKey = key\n\t\t\treturn request\n\t\t},\n\t\tasync onResponse({ request, response }) {\n\t\t\tconst key = (request as unknown as { _dedupKey?: string })._dedupKey\n\t\t\tif (!key) return response\n\n\t\t\t// If there's already an in-flight request, wait for it\n\t\t\tconst existing = inFlightRequests.get(key)\n\t\t\tif (existing && inFlightRequests.get(key) !== undefined) {\n\t\t\t\t// Another request is in flight, clone its response\n\t\t\t\tconst cachedResponse = await existing\n\t\t\t\treturn cachedResponse.clone()\n\t\t\t}\n\n\t\t\t// This is the first request, track it\n\t\t\tconst responsePromise = Promise.resolve(response.clone())\n\t\t\tinFlightRequests.set(key, responsePromise)\n\n\t\t\t// Clean up after response is consumed\n\t\t\tresponsePromise.finally(() => {\n\t\t\t\t// Small delay to allow concurrent requests to find the cached response\n\t\t\t\tsetTimeout(() => inFlightRequests.delete(key), 100)\n\t\t\t})\n\n\t\t\treturn response\n\t\t},\n\t}\n}\n\n// ============================================================================\n// Circuit Breaker (AWS/Resilience4j pattern)\n// ============================================================================\n\n/**\n * Circuit breaker state machine\n *\n * CLOSED: Normal operation, requests pass through\n * OPEN: Service unhealthy, all requests fast-fail\n * HALF_OPEN: Testing recovery, allows one request\n */\nexport type CircuitState = 'CLOSED' | 'OPEN' | 'HALF_OPEN'\n\n/**\n * Error thrown when circuit is open\n */\nexport class CircuitBreakerOpenError extends Error {\n\treadonly remainingMs: number\n\n\tconstructor(remainingMs: number) {\n\t\tsuper(`Circuit breaker is open. Retry after ${Math.ceil(remainingMs / 1000)}s`)\n\t\tthis.name = 'CircuitBreakerOpenError'\n\t\tthis.remainingMs = remainingMs\n\t}\n}\n\n/**\n * Circuit breaker instance with state management\n */\ninterface CircuitBreaker {\n\tstate: CircuitState\n\tfailures: number[]\n\topenedAt: number | null\n\tconfig: Required<CircuitBreakerConfig>\n}\n\n/**\n * Create a fresh circuit breaker instance.\n *\n * Each REST client gets its own instance — no shared module-level singleton.\n * This prevents cross-client state bleed and makes testing reliable.\n */\nfunction createCircuitBreakerInstance(config: CircuitBreakerConfig = {}): CircuitBreaker {\n\treturn {\n\t\tstate: 'CLOSED',\n\t\tfailures: [],\n\t\topenedAt: null,\n\t\tconfig: {\n\t\t\tenabled: config.enabled ?? true,\n\t\t\tfailureThreshold: config.failureThreshold ?? CIRCUIT_BREAKER_FAILURE_THRESHOLD,\n\t\t\twindowMs: config.windowMs ?? CIRCUIT_BREAKER_WINDOW_MS,\n\t\t\topenDurationMs: config.openDurationMs ?? CIRCUIT_BREAKER_OPEN_DURATION_MS,\n\t\t\tisFailure: config.isFailure ?? ((status) => status >= 500 || status === 429),\n\t\t},\n\t}\n}\n\n/**\n * Record a failure and potentially open the circuit\n */\nfunction recordFailure(cb: CircuitBreaker): void {\n\tconst now = Date.now()\n\n\t// Remove old failures outside the window\n\tcb.failures = cb.failures.filter((t) => now - t < cb.config.windowMs)\n\n\t// Add new failure\n\tcb.failures.push(now)\n\n\t// Check if threshold exceeded\n\tif (cb.failures.length >= cb.config.failureThreshold) {\n\t\tcb.state = 'OPEN'\n\t\tcb.openedAt = now\n\t}\n}\n\n/**\n * Record a success and potentially close the circuit\n */\nfunction recordSuccess(cb: CircuitBreaker): void {\n\tif (cb.state === 'HALF_OPEN') {\n\t\t// Test request succeeded, close the circuit\n\t\tcb.state = 'CLOSED'\n\t\tcb.failures = []\n\t\tcb.openedAt = null\n\t}\n}\n\n/**\n * Check if circuit should allow request\n */\nfunction shouldAllowRequest(cb: CircuitBreaker): {\n\tallowed: boolean\n\tremainingMs?: number\n} {\n\tconst now = Date.now()\n\n\tswitch (cb.state) {\n\t\tcase 'CLOSED':\n\t\t\treturn { allowed: true }\n\n\t\tcase 'OPEN': {\n\t\t\tconst elapsed = now - (cb.openedAt ?? now)\n\t\t\tif (elapsed >= cb.config.openDurationMs) {\n\t\t\t\t// Timeout expired, transition to half-open\n\t\t\t\tcb.state = 'HALF_OPEN'\n\t\t\t\treturn { allowed: true }\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tallowed: false,\n\t\t\t\tremainingMs: cb.config.openDurationMs - elapsed,\n\t\t\t}\n\t\t}\n\n\t\tcase 'HALF_OPEN':\n\t\t\t// Only allow one test request at a time\n\t\t\t// In production, you'd use a flag to track if test is in progress\n\t\t\treturn { allowed: true }\n\n\t\tdefault:\n\t\t\treturn { allowed: true }\n\t}\n}\n\n/**\n * Create circuit breaker middleware (AWS/Resilience4j pattern)\n *\n * Features:\n * - Fast-fails when service is unhealthy (prevents cascade failures)\n * - Auto-recovery with half-open state for testing\n * - Configurable failure threshold and timeout\n * - Only counts server errors (5xx) and rate limits (429)\n * - Per-client instance: no shared module-level state\n */\nfunction createCircuitBreakerMiddleware(\n\tconfig: CircuitBreakerConfig | false | undefined,\n): Middleware {\n\tif (config === false) {\n\t\treturn {\n\t\t\tasync onRequest({ request }) {\n\t\t\t\treturn request\n\t\t\t},\n\t\t}\n\t}\n\n\t// Create a fresh circuit breaker per client (not a module-level singleton)\n\tconst cb = createCircuitBreakerInstance(config ?? {})\n\n\t// Track for deprecated getCircuitBreakerState() / resetCircuitBreaker() test helpers\n\t_lastCircuitBreaker = cb\n\n\treturn {\n\t\tasync onRequest({ request }) {\n\t\t\tif (!cb.config.enabled) {\n\t\t\t\treturn request\n\t\t\t}\n\n\t\t\tconst check = shouldAllowRequest(cb)\n\t\t\tif (!check.allowed) {\n\t\t\t\tthrow new CircuitBreakerOpenError(check.remainingMs!)\n\t\t\t}\n\n\t\t\treturn request\n\t\t},\n\t\tasync onResponse({ response }) {\n\t\t\tif (!cb.config.enabled) {\n\t\t\t\treturn response\n\t\t\t}\n\n\t\t\tif (cb.config.isFailure(response.status)) {\n\t\t\t\trecordFailure(cb)\n\t\t\t} else {\n\t\t\t\trecordSuccess(cb)\n\t\t\t}\n\n\t\t\treturn response\n\t\t},\n\t}\n}\n\n/**\n * Module-level reference to the most recently created circuit breaker.\n *\n * Used ONLY by the deprecated `getCircuitBreakerState()` / `resetCircuitBreaker()`\n * helpers (kept for backward compatibility with test suites).\n *\n * Production code should use `client.circuitBreaker.getState()` / `.reset()`\n * from the client object returned by `createRestClient()`.\n */\nlet _lastCircuitBreaker: CircuitBreaker | null = null\n\n/**\n * @deprecated Prefer creating a new `createRestClient()` for isolated state in tests.\n * Resets the most recently created circuit breaker and clears the reference,\n * so `getCircuitBreakerState()` returns null until the next client is created.\n */\nexport function resetCircuitBreaker(): void {\n\tif (_lastCircuitBreaker) {\n\t\t_lastCircuitBreaker.state = 'CLOSED'\n\t\t_lastCircuitBreaker.failures = []\n\t\t_lastCircuitBreaker.openedAt = null\n\t}\n\t_lastCircuitBreaker = null\n}\n\n/**\n * @deprecated Prefer `client.circuitBreaker.getState()` for per-instance state.\n * Returns state of the most recently created circuit breaker (test helper only).\n */\nexport function getCircuitBreakerState(): {\n\tstate: CircuitState\n\tfailures: number\n\topenedAt: number | null\n} | null {\n\tif (!_lastCircuitBreaker) return null\n\treturn {\n\t\tstate: _lastCircuitBreaker.state,\n\t\tfailures: _lastCircuitBreaker.failures.length,\n\t\topenedAt: _lastCircuitBreaker.openedAt,\n\t}\n}\n\n// ============================================================================\n// ETag Cache (HTTP conditional requests)\n// ============================================================================\n\n/**\n * Cached response entry with ETag\n */\ninterface ETagCacheEntry {\n\tetag: string\n\tbody: string\n\ttimestamp: number\n}\n\n/**\n * ETag cache with LRU eviction\n */\nconst etagCache = new Map<string, ETagCacheEntry>()\n\n/**\n * Generate cache key for request\n */\nfunction getETagCacheKey(request: Request): string {\n\treturn `${request.method}:${request.url}`\n}\n\n/**\n * Evict oldest entries when cache is full\n */\nfunction evictOldEntries(maxEntries: number, ttlMs: number): void {\n\tconst now = Date.now()\n\n\t// First, remove expired entries\n\tfor (const [key, entry] of etagCache) {\n\t\tif (now - entry.timestamp > ttlMs) {\n\t\t\tetagCache.delete(key)\n\t\t}\n\t}\n\n\t// If still over limit, remove oldest entries (LRU)\n\tif (etagCache.size > maxEntries) {\n\t\tconst entries = Array.from(etagCache.entries())\n\t\tentries.sort((a, b) => a[1].timestamp - b[1].timestamp)\n\n\t\tconst toRemove = entries.slice(0, entries.length - maxEntries)\n\t\tfor (const [key] of toRemove) {\n\t\t\tetagCache.delete(key)\n\t\t}\n\t}\n}\n\n/**\n * Create ETag middleware for HTTP conditional requests\n *\n * Features:\n * - Caches responses with ETag headers\n * - Sends If-None-Match on subsequent requests\n * - Returns cached response on 304 Not Modified\n * - LRU eviction when cache is full\n * - TTL-based expiration\n */\nfunction createETagMiddleware(config: ETagConfig | false | undefined): Middleware {\n\tif (config === false) {\n\t\treturn {\n\t\t\tasync onRequest({ request }) {\n\t\t\t\treturn request\n\t\t\t},\n\t\t}\n\t}\n\n\tconst {\n\t\tenabled = true,\n\t\tmaxEntries = ETAG_CACHE_MAX_ENTRIES,\n\t\tttlMs = ETAG_CACHE_TTL_MS,\n\t} = config ?? {}\n\n\tif (!enabled) {\n\t\treturn {\n\t\t\tasync onRequest({ request }) {\n\t\t\t\treturn request\n\t\t\t},\n\t\t}\n\t}\n\n\treturn {\n\t\tasync onRequest({ request }) {\n\t\t\t// Only cache GET requests\n\t\t\tif (request.method !== 'GET') {\n\t\t\t\treturn request\n\t\t\t}\n\n\t\t\tconst cacheKey = getETagCacheKey(request)\n\t\t\tconst cached = etagCache.get(cacheKey)\n\n\t\t\tif (cached) {\n\t\t\t\t// Check TTL\n\t\t\t\tif (Date.now() - cached.timestamp > ttlMs) {\n\t\t\t\t\tetagCache.delete(cacheKey)\n\t\t\t\t} else {\n\t\t\t\t\t// Add If-None-Match header\n\t\t\t\t\trequest.headers.set('If-None-Match', cached.etag)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn request\n\t\t},\n\t\tasync onResponse({ request, response }) {\n\t\t\t// Only cache GET requests\n\t\t\tif (request.method !== 'GET') {\n\t\t\t\treturn response\n\t\t\t}\n\n\t\t\tconst cacheKey = getETagCacheKey(request)\n\n\t\t\t// Handle 304 Not Modified\n\t\t\tif (response.status === 304) {\n\t\t\t\tconst cached = etagCache.get(cacheKey)\n\t\t\t\tif (cached) {\n\t\t\t\t\t// Update timestamp (LRU)\n\t\t\t\t\tcached.timestamp = Date.now()\n\n\t\t\t\t\t// Return cached response with original body\n\t\t\t\t\treturn new Response(cached.body, {\n\t\t\t\t\t\tstatus: 200,\n\t\t\t\t\t\theaders: response.headers,\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t\t// No cache, return original response\n\t\t\t\treturn response\n\t\t\t}\n\n\t\t\t// Cache successful responses with ETag\n\t\t\tif (response.ok) {\n\t\t\t\tconst etag = response.headers.get('ETag')\n\t\t\t\tif (etag) {\n\t\t\t\t\t// Clone response to read body (can only read once)\n\t\t\t\t\tconst cloned = response.clone()\n\t\t\t\t\tconst body = await cloned.text()\n\n\t\t\t\t\t// Evict old entries if needed\n\t\t\t\t\tevictOldEntries(maxEntries, ttlMs)\n\n\t\t\t\t\t// Cache the response\n\t\t\t\t\tetagCache.set(cacheKey, {\n\t\t\t\t\t\tetag,\n\t\t\t\t\t\tbody,\n\t\t\t\t\t\ttimestamp: Date.now(),\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn response\n\t\t},\n\t}\n}\n\n/**\n * Clear ETag cache (for testing)\n */\nexport function clearETagCache(): void {\n\tetagCache.clear()\n}\n\n/**\n * Get ETag cache stats (for monitoring)\n */\nexport function getETagCacheStats(): { size: number; entries: string[] } {\n\treturn {\n\t\tsize: etagCache.size,\n\t\tentries: Array.from(etagCache.keys()),\n\t}\n}\n\n// ============================================================================\n// Retry Middleware\n// ============================================================================\n\n/**\n * Per-request body storage for retry middleware.\n *\n * Using a WeakMap<Request, string | null> ensures each request has its own\n * stored body, preventing race conditions when multiple concurrent requests\n * use the same client instance.\n *\n * WeakMap keys are garbage-collected when the Request object is GC'd,\n * so no manual cleanup is needed.\n */\nconst retryBodyMap = new WeakMap<Request, string | null>()\n\n/**\n * Create retry middleware with exponential backoff and timeout\n *\n * Features:\n * - Request timeout (default 30s) prevents infinite hangs\n * - Exponential backoff with jitter for retries\n * - Respects Retry-After header for rate limiting\n * - Per-request body storage (WeakMap) — safe for concurrent requests\n */\nfunction createRetryMiddleware(retryConfig: RetryConfig | false | undefined): Middleware {\n\tif (retryConfig === false) {\n\t\t// No-op middleware - just passes through\n\t\treturn {\n\t\t\tasync onResponse({ response }) {\n\t\t\t\treturn response\n\t\t\t},\n\t\t}\n\t}\n\n\tconst {\n\t\tmaxRetries = 3,\n\t\tbaseDelay = BASE_RETRY_DELAY_MS,\n\t\tmaxDelay = MAX_RETRY_DELAY_MS,\n\t\tshouldRetry = isRetryableStatus,\n\t\ttimeout = DEFAULT_TIMEOUT_MS,\n\t} = retryConfig ?? {}\n\n\treturn {\n\t\tasync onRequest({ request }) {\n\t\t\t// Read body before it's consumed, store per-request in WeakMap\n\t\t\tconst body = request.body ? await request.clone().text() : null\n\n\t\t\t// Add timeout signal\n\t\t\tconst controller = new AbortController()\n\t\t\tsetTimeout(() => controller.abort(), timeout)\n\n\t\t\tconst newRequest = new Request(request.url, {\n\t\t\t\tmethod: request.method,\n\t\t\t\theaders: request.headers,\n\t\t\t\tbody,\n\t\t\t\tsignal: controller.signal,\n\t\t\t})\n\n\t\t\t// Associate body with this specific request object (concurrent-safe)\n\t\t\tretryBodyMap.set(newRequest, body)\n\n\t\t\treturn newRequest\n\t\t},\n\t\tasync onResponse({ response, request }) {\n\t\t\t// Retrieve body for this specific request (not shared across requests)\n\t\t\tconst originalBody = retryBodyMap.get(request) ?? null\n\n\t\t\tlet attempt = 0\n\t\t\tlet currentResponse = response\n\n\t\t\t// Check if we need to retry using the shouldRetry callback\n\t\t\twhile (attempt < maxRetries && shouldRetry(currentResponse.status, attempt)) {\n\t\t\t\tconst retryAfter = currentResponse.headers.get('Retry-After')\n\t\t\t\tconst delay = retryAfter\n\t\t\t\t\t? Number.parseInt(retryAfter, 10) * 1000\n\t\t\t\t\t: exponentialBackoff(attempt, baseDelay, maxDelay)\n\n\t\t\t\tawait new Promise((resolve) => setTimeout(resolve, delay))\n\t\t\t\tattempt++\n\n\t\t\t\t// Create timeout for retry\n\t\t\t\tconst controller = new AbortController()\n\t\t\t\tconst timeoutId = setTimeout(() => controller.abort(), timeout)\n\n\t\t\t\ttry {\n\t\t\t\t\t// Reconstruct request with per-request stored body and new signal\n\t\t\t\t\tconst retryRequest = new Request(request.url, {\n\t\t\t\t\t\tmethod: request.method,\n\t\t\t\t\t\theaders: request.headers,\n\t\t\t\t\t\tbody: originalBody,\n\t\t\t\t\t\tsignal: controller.signal,\n\t\t\t\t\t})\n\n\t\t\t\t\tconst newResponse = await fetch(retryRequest)\n\t\t\t\t\tclearTimeout(timeoutId)\n\n\t\t\t\t\t// If successful or non-retryable client error, return\n\t\t\t\t\tif (newResponse.ok || !shouldRetry(newResponse.status, attempt)) {\n\t\t\t\t\t\tretryBodyMap.delete(request) // cleanup\n\t\t\t\t\t\treturn newResponse\n\t\t\t\t\t}\n\n\t\t\t\t\tcurrentResponse = newResponse\n\t\t\t\t} catch (error) {\n\t\t\t\t\tclearTimeout(timeoutId)\n\t\t\t\t\t// On network/timeout error during retry, continue to next attempt\n\t\t\t\t\tif (attempt >= maxRetries) {\n\t\t\t\t\t\tretryBodyMap.delete(request) // cleanup\n\t\t\t\t\t\tthrow error\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tretryBodyMap.delete(request) // cleanup\n\t\t\treturn currentResponse\n\t\t},\n\t}\n}\n\n/**\n * Validate and sanitize REST client configuration (SSOT helper)\n */\nfunction validateClientConfig(config: { secretKey?: string; platformUrl?: string }) {\n\treturn {\n\t\tsecretKey: validateAndSanitizeSecretKey(config.secretKey),\n\t\tbaseUrl: (config.platformUrl || `https://${DEFAULT_SDK_API_HOST}`).trim(),\n\t}\n}\n\n/**\n * Create a type-safe REST API client.\n *\n * Uses plain `fetch` with a configurable middleware chain (deduplication →\n * circuit breaker → ETag → retry). All endpoints accept a string path; the\n * return type is openapi-fetch-compatible (`{ data, error, response }`).\n *\n * @example\n * ```typescript\n * const client = createRestClient({\n * secretKey: process.env.SYLPHX_SECRET_KEY!,\n * })\n *\n * const { data: user } = await client.GET('/auth/me')\n * const { data: plans } = await client.GET('/billing/plans')\n * const { data: result } = await client.POST('/auth/login', {\n * body: { email: 'test@example.com', password: 'secret' },\n * })\n * ```\n */\nexport function createRestClient(config: RestClientConfig): RestClient {\n\tconst { secretKey, baseUrl } = validateClientConfig(config)\n\n\tconst { client, middlewares } = buildClient(`${baseUrl}${SDK_API_PATH}`, {\n\t\t'Content-Type': 'application/json',\n\t\t'x-app-secret': secretKey,\n\t})\n\n\t// Add deduplication middleware first (before other middleware)\n\tif (config.deduplication !== false) {\n\t\tmiddlewares.push(createDeduplicationMiddleware(config.deduplication))\n\t}\n\n\t// Add circuit breaker middleware (before retry)\n\tif (config.circuitBreaker !== false) {\n\t\tmiddlewares.push(createCircuitBreakerMiddleware(config.circuitBreaker))\n\t}\n\n\t// Add ETag caching middleware (before retry, for HTTP conditional requests)\n\tif (config.etag !== false) {\n\t\tmiddlewares.push(createETagMiddleware(config.etag))\n\t}\n\n\t// Add retry middleware (last, so it can retry after circuit allows)\n\tmiddlewares.push(createRetryMiddleware(config.retry))\n\n\treturn client\n}\n\n/**\n * Create a dynamic REST client with runtime token injection.\n *\n * Use this when you need to inject an access token that may change. Tokens\n * should be read from HttpOnly cookies via a server endpoint, never from\n * localStorage (XSS vulnerability).\n *\n * @example\n * ```typescript\n * const client = createDynamicRestClient({\n * secretKey: process.env.SYLPHX_SECRET_KEY!,\n * getAccessToken: async () => (await cookies()).get('session')?.value,\n * })\n * ```\n */\nexport function createDynamicRestClient(config: RestDynamicConfig): DynamicRestClient {\n\tconst { secretKey, baseUrl } = validateClientConfig(config)\n\n\tconst validatedConfig: RestDynamicConfig = {\n\t\t...config,\n\t\tsecretKey,\n\t\tplatformUrl: baseUrl,\n\t}\n\n\tconst { client, middlewares } = buildClient(`${baseUrl}${SDK_API_PATH}`, {\n\t\t'Content-Type': 'application/json',\n\t})\n\n\t// Add deduplication middleware first (before other middleware)\n\tif (config.deduplication !== false) {\n\t\tmiddlewares.push(createDeduplicationMiddleware(config.deduplication))\n\t}\n\n\t// Add auth middleware (runs on each request)\n\tmiddlewares.push(createAuthMiddleware(validatedConfig))\n\n\t// Add circuit breaker middleware (before retry)\n\tif (config.circuitBreaker !== false) {\n\t\tmiddlewares.push(createCircuitBreakerMiddleware(config.circuitBreaker))\n\t}\n\n\t// Add ETag caching middleware (before retry, for HTTP conditional requests)\n\tif (config.etag !== false) {\n\t\tmiddlewares.push(createETagMiddleware(config.etag))\n\t}\n\n\t// Add retry middleware (last, so it can retry after circuit allows)\n\tmiddlewares.push(createRetryMiddleware(config.retry))\n\n\treturn client\n}\n\n/**\n * Check if a REST response has an error\n */\nexport function hasError<T, E>(response: {\n\tdata?: T\n\terror?: E\n}): response is {\n\tdata: undefined\n\terror: E\n} {\n\treturn response.error !== undefined\n}\n\n/**\n * Extract error message from REST error response\n */\nexport function getRestErrorMessage(error: unknown): string {\n\tif (error && typeof error === 'object' && 'error' in error) {\n\t\tconst err = error as { error?: { message?: string } }\n\t\treturn err.error?.message ?? 'An unknown error occurred'\n\t}\n\tif (error instanceof Error) {\n\t\treturn error.message\n\t}\n\treturn 'An unknown error occurred'\n}\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 (ADR-021):\n * - Publishable key: pk_(dev|stg|prod)_{ref}_{32hex} — client-safe (new)\n * - Secret Key: sk_(dev|stg|prod)_{ref}_{64hex} — server-side only\n *\n * Legacy Key Formats (backward-compat):\n * - App ID (old): app_(dev|stg|prod)_[identifier] — Public identifier\n *\n * Special Internal Formats (NOT rotated):\n * - Console bootstrap: app_prod_platform_{slug} / sk_prod_platform_{slug}\n */\n\n// =============================================================================\n// Types\n// =============================================================================\n\n/** Environment type derived from key prefix */\nexport type EnvironmentType = 'development' | 'staging' | 'production'\n\n/** Key type - publicKey (pk_*), appId (legacy app_*), or secret (sk_*) */\nexport type KeyType = 'publicKey' | '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 * Publishable key pattern (ADR-021): pk_(dev|stg|prod)_{ref}_{32hex}\n * - Prefix: pk_ (publishable key, safe for client)\n * - Environment: dev, stg, or prod\n * - Ref: 12-char base36 project ref\n * - Token: 32 hex chars (128-bit random)\n *\n * Example: pk_prod_2dubco39o9so_f19e5cdc3cc54f7ff81bdc26ec5bfbad\n */\nconst PUBLIC_KEY_PATTERN = /^pk_(dev|stg|prod)_[a-z0-9]{12}_[a-f0-9]{32}$/\n\n/**\n * Legacy App ID pattern: app_(dev|stg|prod)_[identifier]\n * - Prefix: app_ (application identifier, public) — legacy format, backward-compat\n * - Environment: dev, stg, or prod\n * - Suffix: alphanumeric with underscores/hyphens (hex for apps, or internal identifiers)\n *\n * Accepts both legacy app_* format and ADR-021 pk_* publishable keys.\n * pk_{env}_{ref}_{hex} is the standard customer key — Customer Zero uses it as appId.\n */\nconst APP_ID_PATTERN = /^(app|pk)_(dev|stg|prod|prev)_[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\n * - Suffix: alphanumeric with underscores/hyphens\n *\n * Accepts both old format (sk_prod_{64hex}) and new format (sk_prod_{ref}_{64hex}).\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(keyType: KeyType, issues: string[], envVarName: string): 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(keyType: KeyType, key: string, envVarName: string): string {\n\tconst maskedKey = key.length > 20 ? `${key.slice(0, 20)}...` : key\n\tconst formatHint =\n\t\tkeyType === 'appId'\n\t\t\t? 'pk_(dev|stg|prod)_{ref}_{hex} or app_(dev|stg|prod)_[id]'\n\t\t\t: 'sk_(dev|stg|prod)_{ref}_{hex}'\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: pk_ or 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 pk_, app_, or sk_ prefix followed by environment\n\tconst match = key.match(/^(?:app|pk|sk)_(dev|stg|prod|prev)_/)\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 — Publishable Key (ADR-021: pk_*) and legacy App ID (app_*)\n// =============================================================================\n\n/**\n * Validate an ADR-021 publishable key (pk_*).\n *\n * @example\n * ```typescript\n * const result = validatePublicKey(process.env.NEXT_PUBLIC_SYLPHX_KEY)\n * if (!result.valid) throw new Error(result.error)\n * ```\n */\nexport function validatePublicKey(key: string | undefined | null): KeyValidationResult {\n\treturn validateKeyForType(key, 'publicKey', PUBLIC_KEY_PATTERN, 'NEXT_PUBLIC_SYLPHX_KEY')\n}\n\n/**\n * Validate and sanitize a publishable key, throwing on invalid input.\n */\nexport function validateAndSanitizePublicKey(key: string | undefined | null): string {\n\tconst result = validatePublicKey(key)\n\tif (!result.valid) throw new Error(result.error)\n\tif (result.warning) console.warn(result.warning)\n\treturn result.sanitizedKey\n}\n\n/**\n * Validate a legacy App ID (app_*) and return detailed results.\n *\n * @deprecated Use validatePublicKey() for new pk_* keys (ADR-021).\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(key: string | undefined | null): KeyValidationResult {\n\treturn validateKeyForType(key, 'appId', APP_ID_PATTERN, 'NEXT_PUBLIC_SYLPHX_APP_ID')\n}\n\n/**\n * Validate and sanitize App ID, logging warnings.\n *\n * @deprecated Use validateAndSanitizePublicKey() for new pk_* keys (ADR-021).\n * @throws Error if the key is invalid and cannot be sanitized\n * @returns The sanitized App ID\n */\nexport function validateAndSanitizeAppId(key: string | undefined | null): 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(key: string | undefined | null): KeyValidationResult {\n\treturn validateKeyForType(key, 'secret', SECRET_KEY_PATTERN, 'SYLPHX_SECRET_KEY')\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(key: string | undefined | null): 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 all key types (ADR-021 and legacy)\n\tif (sanitized.startsWith('pk_')) {\n\t\tconst result = validatePublicKey(sanitized)\n\t\tif (!result.valid) throw new Error(result.error)\n\t\treturn result.environment!\n\t}\n\n\tif (sanitized.startsWith('sk_')) {\n\t\tconst result = validateSecretKey(sanitized)\n\t\tif (!result.valid) throw new Error(result.error)\n\t\treturn result.environment!\n\t}\n\n\tif (sanitized.startsWith('app_')) {\n\t\tconst result = validateAppId(sanitized)\n\t\tif (!result.valid) throw new Error(result.error)\n\t\treturn result.environment!\n\t}\n\n\tthrow new Error(\n\t\t`[Sylphx] Invalid key format. Key must start with 'pk_' (publishable), 'sk_' (secret), or 'app_' (legacy 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 = env === '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.\n *\n * @returns 'publicKey' (pk_*), 'appId' (legacy app_*), 'secret' (sk_*), or null if unknown\n */\nexport function detectKeyType(key: string): KeyType | null {\n\tconst sanitized = key.trim().toLowerCase()\n\tif (sanitized.startsWith('pk_')) return 'publicKey'\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 a publishable/public key (pk_* or legacy app_*)\n */\nexport function isPublishableKey(key: string): boolean {\n\tconst t = detectKeyType(key)\n\treturn t === 'publicKey' || t === 'appId'\n}\n\n/**\n * Check if a key is an App ID (legacy app_* format)\n *\n * @deprecated Use isPublishableKey() to also accept new pk_* keys\n */\nexport function isAppId(key: string): boolean {\n\treturn detectKeyType(key) === 'appId'\n}\n\n/**\n * Check if a key is a secret key (sk_*)\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(key: string | undefined | null): KeyValidationResult {\n\tconst keyType = key ? detectKeyType(key) : null\n\n\tif (keyType === 'publicKey') {\n\t\treturn validatePublicKey(key)\n\t}\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 'pk_' (publishable), 'app_' (legacy), or 'sk_' (secret), followed by environment (dev/stg/prod). 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 window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1'\n\t}\n\treturn false\n}\n","/**\n * @sylphx/sdk\n *\n * State-of-the-art platform SDK with pure functions.\n *\n * ## Architecture (see ADR.md for full details)\n *\n * This SDK follows Firebase's architecture pattern:\n * - **Pure functions** - No hidden state, config passed explicitly\n * - **Tree-shakeable** - Import only what you use, bundler removes the rest\n * - **4 entry points only** - Separate only when peer dependencies differ\n *\n * ## Entry Points\n *\n * | Entry | Purpose | Peer Dependencies |\n * |-------|---------|-------------------|\n * | `@sylphx/sdk` | All pure functions | None |\n * | `@sylphx/sdk/react` | React hooks & components | react, react-dom |\n * | `@sylphx/sdk/server` | Server utilities (JWT, webhooks) | jose |\n * | `@sylphx/sdk/nextjs` | Next.js integration | next |\n *\n * ## Service Quick Reference\n *\n * | Service | Key Functions | Description |\n * |---------|---------------|-------------|\n * | Config | `createConfig`, `withToken` | SDK configuration |\n * | Auth | `signIn`, `signUp`, `signOut` | Authentication |\n * | Analytics | `track`, `page`, `identify` | Event tracking |\n * | AI | `chat`, `embed`, `complete` | AI/LLM operations |\n * | Database | `getDatabaseConnectionString`, `getDatabaseStatus` | Provisioned PostgreSQL |\n * | KV | `kvSet`, `kvGet`, `kvRateLimit` | Redis key-value store |\n * | Realtime | `realtimeEmit`, `getRealtimeHistory` | Redis Streams pub/sub |\n * | Billing | `getPlans`, `createCheckout` | Subscriptions |\n * | Storage | `uploadFile`, `getFileUrl` | File storage |\n * | Tasks | `scheduleTask`, `createCron` | Background tasks |\n * | Flags | `checkFlag`, `getFlags`, `getAllFlags` | Feature flags |\n * | Consent | `hasConsent`, `setConsents` | GDPR/CCPA |\n * | Referrals | `getReferralStats`, `redeemReferralCode` | Referral system |\n * | Webhooks | `getWebhookConfig`, `replayWebhookDelivery` | Webhook management |\n * | Email | `sendEmail`, `sendTemplatedEmail` | Email sending |\n * | Notifications | `registerPush`, `sendPush` | Push notifications |\n * | Engagement | `getStreak`, `unlockAchievement` | Gamification |\n * | Monitoring | `captureException`, `captureMessage` | Error tracking |\n * | Deploy | `triggerDeploy`, `getDeployStatus` | CI/CD deployments |\n * | Orgs | `createOrganization`, `inviteOrganizationMember` | Multi-tenancy |\n * | Permissions | `listPermissions`, `hasPermission` | RBAC permissions |\n * | Roles | `listRoles`, `assignMemberRole` | RBAC roles |\n *\n * ## Usage\n *\n * @example\n * ```typescript\n * // Pure functions - tree-shakeable, works anywhere\n * import { createConfig, track, signIn, getPlans } from '@sylphx/sdk'\n *\n * const config = createConfig({\n * secretKey: process.env.SYLPHX_SECRET_KEY!,\n * })\n *\n * // Analytics\n * await track(config, { event: 'purchase', properties: { amount: 99 } })\n *\n * // Auth\n * const result = await signIn(config, { email, password })\n *\n * // Billing\n * const plans = await getPlans(config)\n * ```\n *\n * @example\n * ```typescript\n * // REST client for direct API access\n * import { createRestClient } from '@sylphx/sdk'\n *\n * const client = createRestClient({\n * secretKey: process.env.SYLPHX_SECRET_KEY!,\n * })\n *\n * // Type-safe REST calls\n * const { data: plans } = await client.GET('/billing/plans')\n * const { data: user } = await client.GET('/auth/me')\n * ```\n */\n\n// =============================================================================\n// Configuration (Foundation)\n// =============================================================================\n\nexport {\n\tcreateClient,\n\tcreateConfig,\n\tcreateServerClient,\n\tInvalidConnectionUrlError,\n\ttype ParsedConnectionUrl,\n\ttype SylphxClientInput,\n\ttype SylphxConfig,\n\ttype SylphxConfigInput,\n\twithToken,\n} from './config'\n\n// =============================================================================\n// Debug Utilities\n// =============================================================================\n\nexport {\n\ttype DebugCategory,\n\tdebugError,\n\tdebugLog,\n\tdebugTimer,\n\tdebugWarn,\n\tdisableDebug,\n\tenableDebug,\n\tgetDebugMode,\n\tinstallGlobalDebugHelpers,\n\tresetDebugModeCache,\n} from './debug'\n\n// =============================================================================\n// REST Client\n// =============================================================================\n\nexport {\n\ttype CircuitBreakerConfig,\n\tCircuitBreakerOpenError,\n\ttype CircuitState,\n\tcreateDynamicRestClient,\n\tcreateRestClient,\n\ttype DeduplicationConfig,\n\ttype DynamicRestClient,\n\tgetCircuitBreakerState,\n\tgetRestErrorMessage,\n\thasError,\n\ttype RestClient,\n\ttype RestClientConfig,\n\ttype RestDynamicConfig,\n\ttype RetryConfig,\n\tresetCircuitBreaker,\n} from './rest-client'\n\n// =============================================================================\n// Error Handling\n// =============================================================================\n\nexport {\n\tAuthenticationError,\n\tAuthorizationError,\n\tERROR_CODE_STATUS,\n\ttype ErrorCode,\n\texponentialBackoff,\n\tgetErrorCode,\n\tgetErrorMessage,\n\tisRetryableError,\n\tisSylphxError,\n\tNetworkError,\n\tNotFoundError,\n\tRateLimitError,\n\tRETRYABLE_CODES,\n\tSylphxError,\n\ttype SylphxErrorCode,\n\ttype SylphxErrorOptions,\n\tTimeoutError,\n\ttoSylphxError,\n\tValidationError,\n} from './errors'\n\n// =============================================================================\n// Auth Functions\n// =============================================================================\n\nexport {\n\tcookies,\n\ttype DeviceApproveInput,\n\ttype DeviceApproveResult,\n\ttype DeviceDenyInput,\n\ttype DeviceDenyResult,\n\ttype DeviceGrant,\n\ttype DeviceInitInput,\n\ttype DevicePollResult,\n\tdevice,\n\t// DPoP — sender-constrained access tokens (ADR-089 Phase 5.1e)\n\tdpop,\n\textendedSignUp,\n\tforgotPassword,\n\tgetSession,\n\ttype ImpersonationActive,\n\ttype ImpersonationEndResult,\n\ttype ImpersonationInfo,\n\ttype ImpersonationStartResult,\n\ttype InviteUserRequest,\n\ttype InviteUserResponse,\n\timpersonation,\n\tintrospectToken,\n\tinviteUser,\n\t// Generated API types (from OpenAPI spec)\n\ttype LoginRequest,\n\ttype LoginResponse,\n\ttype MeResponse,\n\ttype MintAccessTokenClaims,\n\ttype MintAccessTokenResult,\n\ttype OrgTokenPayload,\n\toauth,\n\ttype PlatformAccessTokenClaims,\n\t// Platform auth — refresh-token rotation + logout (ADR-089 SoC Tier-1)\n\ttype PlatformLogoutInput,\n\t// Platform password (ADR-089 Phase 2c)\n\ttype PlatformPasswordChangeInput,\n\ttype PlatformPasswordChangeResult,\n\ttype PlatformPasswordSetInput,\n\ttype PlatformPasswordSetResult,\n\ttype PlatformPasswordStatusResult,\n\ttype PlatformRefreshInput,\n\ttype PlatformRefreshResult,\n\t// Platform sessions (ADR-089 Phase 2b)\n\ttype PlatformSessionRenameInput,\n\ttype PlatformSessionRenameResult,\n\ttype PlatformSessionRevokeAllResult,\n\ttype PlatformSessionRevokeInput,\n\ttype PlatformSessionRevokeOtherResult,\n\ttype PlatformSessionRevokeResult,\n\ttype PlatformSessionsListResult,\n\ttype PlatformUserDeleteInput,\n\ttype PlatformUserDeleteResult,\n\ttype PlatformUserExportResult,\n\t// Platform user resolver (ADR-089 Phase 3b)\n\ttype PlatformUserRecord,\n\ttype PlatformUserResolution,\n\tpassword,\n\tplatformAuth,\n\ttype RegisterInput,\n\ttype RegisterRequest,\n\ttype RegisterResponse,\n\ttype RevokeTokenOptions,\n\trefreshToken,\n\tresetPassword,\n\tresetPlatformCookieCache,\n\tresetPlatformJwksCache,\n\trevokeAllTokens,\n\trevokeToken,\n\t// SDK-specific types\n\ttype SessionResult,\n\tsessions,\n\tsignIn,\n\tsignOut,\n\tsignUp,\n\tswitchOrg,\n\ttype TokenIntrospectionResult,\n\ttype TokenResponse,\n\ttype TwoFactorVerifyRequest,\n\tuser,\n\tverifyAccessToken,\n\tverifyEmail,\n\tverifyTwoFactor,\n} from './auth'\n\n// =============================================================================\n// Audit (Σ1 SoC rename — was `auth.audit`, now top-level `audit`)\n// =============================================================================\n\nexport { type AuditQueryFilter, type AuditQueryResult, audit } from './audit'\n\n// =============================================================================\n// Rate-Limits (Σ1 SoC rename — was `auth.rateLimits`)\n// =============================================================================\n\nexport {\n\ttype RateLimitStatusFilter,\n\ttype RateLimitStatusResult,\n\ttype RateLimitStrategiesFilter,\n\ttype RateLimitStrategiesResult,\n\ttype RateLimitStrategyDeleteInput,\n\ttype RateLimitStrategyDeleteResult,\n\ttype RateLimitStrategyUpsertInput,\n\ttype RateLimitStrategyUpsertResult,\n\trateLimits,\n} from './rate-limits'\n\n// =============================================================================\n// Realtime Admin + Functions Admin (Σ1 SoC rename — were nested inside `auth`\n// and re-exported as `realtimeAdmin` / `functionsInternal`; now nested under\n// `realtime.admin.*` and `functions.admin.*` at the package root)\n// =============================================================================\n\nimport { functionsAdmin } from './functions'\nimport * as realtimeCustomer from './realtime'\nimport { realtimeAdmin } from './realtime-admin'\n\nexport type { PlatformFunctionsDownloadBundleResult } from './functions'\nexport type {\n\tPlatformRealtimeChannel,\n\tPlatformRealtimeCreateChannelResult,\n\tPlatformRealtimeDeleteChannelResult,\n\tPlatformRealtimeListChannelsResult,\n\tPlatformRealtimeStatusResult,\n} from './realtime-admin'\n\n/**\n * `realtime` top-level namespace — customer-app data plane exposes\n * `realtime.emit` / `realtime.history`, Platform admin surface nests\n * at `realtime.admin.channels.*` (ADR-089 Phase 3a / Σ1 SoC rename).\n */\nexport const realtime = {\n\tadmin: realtimeAdmin.channels,\n\temit: realtimeCustomer.realtimeEmit,\n\thistory: realtimeCustomer.getRealtimeHistory,\n} as const\n\n/**\n * `functions` top-level namespace — Platform admin surface nests at\n * `functions.admin.downloadBundle` (ADR-089 Phase 3a / Σ1 SoC rename).\n * Customer-app function invocation surface is TBD.\n */\nexport const functions = {\n\tadmin: functionsAdmin,\n} as const\n\n// =============================================================================\n// Admin Functions (Server-side only — requires secretKey)\n// =============================================================================\n\nexport {\n\ttype AdminUser,\n\tdeleteUser,\n\tgetUser,\n\tgetUserByEmail,\n\ttype ListUsersOptions,\n\ttype ListUsersResult,\n\tlistUsers,\n\tsuspendUser,\n\tupdateUser,\n\tupdateUserMetadata,\n} from './admin'\n\n// =============================================================================\n// Analytics Functions\n// =============================================================================\n\nexport {\n\ttype BatchEvent,\n\tcreateTracker,\n\tgenerateAnonymousId,\n\ttype IdentifyInput,\n\tidentify,\n\ttype PageInput,\n\tpage,\n\ttype TrackInput,\n\ttrack,\n\ttrackBatch,\n} from './analytics'\n\n// =============================================================================\n// AI Functions\n// =============================================================================\n\nexport {\n\ttype AIModel,\n\ttype AIModelsResponse,\n\ttype AIRateLimitResponse,\n\t// Generated API types (from OpenAPI spec)\n\ttype AIUsageResponse,\n\ttype ChatInput,\n\t// SDK-specific types (OpenAI-compatible chat format)\n\ttype ChatMessage,\n\ttype ChatResult,\n\ttype ChatStreamChunk,\n\ttype ContentPart,\n\tchat,\n\tchatStream,\n\tcomplete,\n\ttype EmbedInput,\n\ttype EmbedResult,\n\tembed,\n\tstreamToString,\n\ttype Tool,\n\ttype ToolCall,\n} from './ai'\n\n// =============================================================================\n// Billing Functions\n// =============================================================================\n\nexport {\n\ttype BalanceResponse,\n\ttype CheckoutRequest,\n\ttype CheckoutResponse,\n\tcreateCheckout,\n\tcreatePortalSession,\n\tgetBillingBalance,\n\tgetBillingUsage,\n\tgetPlans,\n\tgetSubscription,\n\t// Generated API types\n\ttype Plan,\n\ttype PortalRequest,\n\ttype PortalResponse,\n\ttype Subscription,\n\ttype UsageResponse,\n} from './billing'\n\n// =============================================================================\n// Storage Functions\n// =============================================================================\n\nexport {\n\tdeleteFile,\n\tdownloadFileVersion,\n\ttype FileInfo,\n\ttype FileUploadOptions,\n\tgetFileInfo,\n\tgetFileUrl,\n\tgetSignedUrl,\n\tlistFileVersions,\n\trestoreFile,\n\trestoreFileVersion,\n\ttype SignedUrlOptions,\n\ttype SignedUrlResult,\n\ttype StorageFileVersion,\n\tsoftDeleteFile,\n\ttype UploadProgressEvent,\n\ttype UploadResult,\n\tuploadAvatar,\n\tuploadFile,\n} from './storage'\n\n// =============================================================================\n// Notifications Functions\n// =============================================================================\n\n// Service Worker utilities for push notifications (OneSignal/FCM pattern)\nexport {\n\tcreateServiceWorkerScript,\n\tinitPushServiceWorker,\n\ttype PushNotificationPayload,\n\ttype PushServiceWorkerConfig,\n\tregisterPushServiceWorker,\n} from './lib/notifications/service-worker'\nexport {\n\tcampaigns as pushCampaigns,\n\tgetPushPreferences,\n\ttype PushCampaign,\n\ttype PushCampaignStats,\n\ttype PushCampaignVariant,\n\ttype PushNotification,\n\ttype PushSegment,\n\ttype PushSegmentFilter,\n\ttype PushSubscription,\n\tregisterPush,\n\tsegments as pushSegments,\n\tsendPush,\n\tunregisterPush,\n\tupdatePushPreferences,\n} from './notifications'\n\n// =============================================================================\n// Tasks Functions\n// =============================================================================\n\nexport {\n\ttype CronInput,\n\ttype CronSchedule,\n\tcancelTask,\n\tcreateCron,\n\tdeleteCron,\n\tgetTask,\n\tlistTasks,\n\tpauseCron,\n\tresumeCron,\n\tscheduleTask,\n\ttype TaskInput,\n\ttype TaskResult,\n\ttype TaskStatus,\n} from './tasks'\n\n// TaskTriggerConfig exported via './tasks' → lib/tasks → task.ts\n\n// =============================================================================\n// Native Tasks Engine — Handler API\n// =============================================================================\n\nexport {\n\tcreateStepContext,\n\tcreateTasksHandler,\n\tStepCompleteSignal,\n\tStepSleepSignal,\n\tverifySignature as verifyTaskSignature,\n} from './lib/tasks/handler'\n\nexport type {\n\tNativeStepContext,\n\tNativeTaskDefinition,\n\tTaskRunStatus as NativeTaskRunStatus,\n} from './lib/tasks/types'\n\n// =============================================================================\n// Feature Flags Functions\n// =============================================================================\n\nexport {\n\tcheckFlag,\n\ttype FlagContext,\n\ttype FlagResult,\n\tgetAllFlags,\n\tgetFlagPayload,\n\tgetFlags,\n\tgetVariant,\n\tisEnabled,\n} from './flags'\n\n// =============================================================================\n// Webhooks Functions\n// =============================================================================\n\nexport {\n\tgetWebhookConfig,\n\tgetWebhookDeliveries,\n\tgetWebhookDelivery,\n\tgetWebhookStats,\n\treplayWebhookDelivery,\n\tupdateWebhookConfig,\n\ttype WebhookConfig,\n\ttype WebhookConfigUpdate,\n\ttype WebhookDeliveriesResult,\n\ttype WebhookDelivery,\n\ttype WebhookStats,\n} from './webhooks'\n\n// =============================================================================\n// Email Functions\n// =============================================================================\n\nexport {\n\tcancelScheduledEmail,\n\tgetScheduledEmail,\n\tgetScheduledEmailStats,\n\tisEmailConfigured,\n\ttype ListScheduledEmailsOptions,\n\tlistScheduledEmails,\n\trescheduleEmail,\n\ttype ScheduledEmail,\n\ttype ScheduledEmailStats,\n\ttype ScheduledEmailsResult,\n\ttype ScheduleEmailOptions,\n\ttype SendEmailOptions,\n\ttype SendResult,\n\ttype SendTemplatedEmailOptions,\n\ttype SendToUserOptions,\n\tscheduleEmail,\n\tsendEmail,\n\tsendEmailToUser,\n\tsendTemplatedEmail,\n} from './email'\n\n// =============================================================================\n// Consent Functions (GDPR/CCPA)\n// =============================================================================\n\nexport {\n\tacceptAllConsents,\n\ttype ConsentCategory,\n\ttype ConsentHistoryEntry,\n\ttype ConsentHistoryResult,\n\ttype ConsentPurposeDefaults,\n\t// Types\n\ttype ConsentType,\n\tdeclineOptionalConsents,\n\ttype GetConsentHistoryInput,\n\ttype GetConsentsInput,\n\tgetConsentHistory,\n\t// Runtime functions\n\tgetConsentTypes,\n\tgetUserConsents,\n\thasConsent,\n\ttype LinkAnonymousConsentsInput,\n\tlinkAnonymousConsents,\n\ttype SetConsentsInput,\n\tsetConsents,\n\ttype UserConsent,\n} from './consent'\n\n// =============================================================================\n// Referrals Functions\n// =============================================================================\n\nexport {\n\tgetMyReferralCode,\n\tgetReferralLeaderboard,\n\tgetReferralStats,\n\ttype LeaderboardEntry,\n\ttype LeaderboardOptions,\n\ttype LeaderboardResult,\n\ttype RedeemReferralInput,\n\ttype RedeemResult,\n\ttype ReferralCode,\n\ttype ReferralStats,\n\tredeemReferralCode,\n\tregenerateReferralCode,\n} from './referrals'\n\n// =============================================================================\n// Engagement Functions (Streaks, Leaderboards, Achievements)\n// =============================================================================\n\nexport {\n\t// Constants\n\tACHIEVEMENT_TIER_CONFIG,\n\ttype AchievementCategory,\n\ttype AchievementCriteria,\n\ttype AchievementCriterion,\n\ttype AchievementDefinition,\n\ttype AchievementTier,\n\ttype AchievementType,\n\ttype AchievementUnlockEvent,\n\ttype CriteriaOperator,\n\tgetAchievement,\n\tgetAchievementPoints,\n\t// Achievement functions\n\tgetAchievements,\n\tgetAllStreaks,\n\t// Leaderboard functions\n\tgetLeaderboard,\n\t// Streak functions\n\tgetStreak,\n\tgetUserLeaderboardRank,\n\tincrementAchievementProgress,\n\ttype LeaderboardAggregation,\n\ttype LeaderboardDefinition,\n\ttype LeaderboardEntry as EngagementLeaderboardEntry,\n\ttype LeaderboardQueryOptions,\n\ttype LeaderboardResetPeriod,\n\ttype LeaderboardResult as EngagementLeaderboardResult,\n\ttype LeaderboardSortDirection,\n\ttype RecordActivityInput,\n\ttype RecordActivityResult,\n\trecordStreakActivity,\n\trecoverStreak,\n\t// Types\n\ttype StreakDefinition,\n\ttype StreakFrequency,\n\ttype StreakState,\n\ttype SubmitScoreInput,\n\ttype SubmitScoreResult,\n\tsubmitScore,\n\ttype UserAchievement,\n\tunlockAchievement,\n} from './engagement'\n\n// =============================================================================\n// Organization Functions\n// =============================================================================\n\nexport {\n\tacceptOrganizationInvitation,\n\ttype CreateOrgInput,\n\tcanDeleteOrganization,\n\tcanManageMembers,\n\tcanManageSettings,\n\tcreateOrganization,\n\tdeleteOrganization,\n\tgetOrganization,\n\t// Invitations\n\tgetOrganizationInvitations,\n\t// Members\n\tgetOrganizationMembers,\n\t// CRUD\n\tgetOrganizations,\n\t// Permission helpers\n\thasRole,\n\ttype InviteMemberInput,\n\tinviteOrganizationMember,\n\tleaveOrganization,\n\t// Types\n\ttype Organization,\n\ttype OrganizationInvitation,\n\ttype OrganizationMember,\n\ttype OrganizationMembership,\n\ttype OrgRole,\n\tremoveOrganizationMember,\n\trevokeOrganizationInvitation,\n\ttype UpdateOrgInput,\n\tupdateOrganization,\n\tupdateOrganizationMemberRole,\n} from './orgs'\n\n// =============================================================================\n// Permission Functions (RBAC)\n// =============================================================================\n\nexport {\n\ttype CreatePermissionInput,\n\tcreatePermission,\n\tdeletePermission,\n\tgetMemberPermissions,\n\thasAllPermissions,\n\thasAnyPermission,\n\thasPermission,\n\tlistPermissions,\n\ttype MemberPermissionsResult,\n\ttype Permission,\n} from './permissions'\n\n// =============================================================================\n// Role Functions (RBAC)\n// =============================================================================\n\nexport {\n\tassignMemberRole,\n\ttype CreateRoleInput,\n\tcreateRole,\n\tdeleteRole,\n\tgetRole,\n\tlistRoles,\n\ttype Role,\n\ttype UpdateRoleInput,\n\tupdateRole,\n} from './roles'\n\n// =============================================================================\n// Secrets Functions\n// =============================================================================\n\nexport {\n\ttype GetSecretInput,\n\ttype GetSecretResult,\n\ttype GetSecretsInput,\n\ttype GetSecretsResult,\n\tgetAllSecrets,\n\tgetSecret,\n\tgetSecrets,\n\thasSecret,\n\ttype ListSecretKeysInput,\n\tlistSecretKeys,\n\ttype SecretKeyInfo,\n} from './secrets'\n\n// =============================================================================\n// Search Functions\n// =============================================================================\n\nexport {\n\ttype BatchIndexInput,\n\ttype BatchIndexResult,\n\tbatchIndex,\n\ttype DeleteDocumentInput,\n\tdeleteDocument,\n\ttype FacetsResponse,\n\ttype GetFacetsInput,\n\tgetFacets,\n\tgetSearchStats,\n\ttype IndexDocumentInput,\n\ttype IndexDocumentResult,\n\tindexDocument,\n\ttype SearchInput,\n\ttype SearchResponse,\n\ttype SearchResultItem,\n\ttype SearchStatsResult,\n\ttype SearchType,\n\tsearch,\n\ttype TrackClickInput,\n\ttrackClick,\n\ttype UpsertDocumentInput,\n\ttype UpsertDocumentResult,\n\tupsertDocument,\n} from './search'\n\n// =============================================================================\n// Database Functions (Platform-provisioned PostgreSQL)\n// =============================================================================\n\nexport {\n\ttype DatabaseConnectionInfo,\n\ttype DatabaseStatus,\n\ttype DatabaseStatusInfo,\n\tgetDatabaseConnectionString,\n\tgetDatabaseStatus,\n} from './database'\n\n// =============================================================================\n// KV Functions (Redis key-value store)\n// =============================================================================\n\nexport {\n\ttype KvExpireRequest,\n\ttype KvHgetallRequest,\n\ttype KvHgetRequest,\n\ttype KvHsetRequest,\n\ttype KvIncrRequest,\n\ttype KvLpushRequest,\n\ttype KvLrangeRequest,\n\ttype KvMgetRequest,\n\ttype KvMsetRequest,\n\ttype KvRateLimitRequest,\n\ttype KvRateLimitResult,\n\ttype KvScanOptions,\n\ttype KvScanResult,\n\ttype KvSetOptions,\n\ttype KvSetRequest,\n\ttype KvZaddRequest,\n\ttype KvZMember,\n\ttype KvZrangeRequest,\n\tkvDelete,\n\tkvExists,\n\tkvExpire,\n\tkvGet,\n\tkvGetJSON,\n\tkvHget,\n\tkvHgetall,\n\tkvHset,\n\tkvIncr,\n\tkvLpush,\n\tkvLrange,\n\tkvMget,\n\tkvMset,\n\tkvRateLimit,\n\tkvScan,\n\tkvSet,\n\tkvSetJSON,\n\tkvZadd,\n\tkvZrange,\n} from './kv'\n\n// =============================================================================\n// Realtime Functions (Redis Streams pub/sub)\n// =============================================================================\n\nexport {\n\tgetRealtimeHistory,\n\ttype RealtimeEmitRequest,\n\ttype RealtimeEmitResponse,\n\ttype RealtimeHistoryRequest,\n\ttype RealtimeHistoryResponse,\n\trealtimeEmit,\n\ttype StreamMessage,\n} from './realtime'\n\n// =============================================================================\n// Deploy Functions (CI/CD)\n// =============================================================================\n\nexport {\n\ttype BuildLog,\n\ttype BuildLogHistoryResponse,\n\ttype DeployHistoryResponse,\n\ttype DeployInfo,\n\ttype DeployStatus,\n\tdeleteEnvVar,\n\ttype EnvVar,\n\tgetBuildLogHistory,\n\tgetDeployHistory,\n\tgetDeployStatus,\n\tlistEnvVars,\n\ttype RollbackDeployRequest,\n\trollbackDeploy,\n\ttype SetEnvVarRequest,\n\tsetEnvVar,\n\ttype TriggerDeployRequest,\n\ttriggerDeploy,\n} from './deploy'\n\n// =============================================================================\n// Monitoring Functions (Error Tracking)\n// =============================================================================\n\nexport {\n\ttype Breadcrumb,\n\ttype CaptureExceptionRequest,\n\ttype CaptureMessageRequest,\n\tcaptureException,\n\tcaptureExceptionRaw,\n\tcaptureMessage,\n\ttype ExceptionFrame,\n\ttype ExceptionValue,\n\ttype MonitoringResponse,\n\ttype MonitoringSeverity,\n} from './monitoring'\n\n// =============================================================================\n// Sandbox Functions (Ephemeral Compute)\n// =============================================================================\n\nexport {\n\ttype CommandResult,\n\ttype ExecEvent,\n\ttype ExecOptions,\n\ttype ExecResult,\n\ttype FileEvent,\n\ttype ProcessEvent,\n\ttype ProcessInfo,\n\ttype ProcessStartOptions,\n\ttype ProcessSummary,\n\tSandboxClient,\n\ttype SandboxFile,\n\tSandboxFiles,\n\ttype SandboxOptions,\n\tSandboxProcesses,\n\ttype SandboxRecord,\n\tSandboxWatch,\n\ttype WatchEntry,\n\ttype WatchOptions,\n} from './sandbox'\n\n// =============================================================================\n// Workers (Batch Run-to-Completion Compute)\n// =============================================================================\n\nexport type { RunWorkerOptions } from './workers'\n\n// =============================================================================\n// Triggers (ADR-040 — Unified scheduling + event dispatch)\n// =============================================================================\n\nexport {\n\ttype CreateTriggerOptions,\n\ttype CronSource,\n\ttype EventSource,\n\ttype HttpTarget,\n\ttype ListTriggersResult,\n\ttype PublishEventResult,\n\ttype RunTarget,\n\ttype TaskTarget,\n\ttype Trigger,\n\ttype TriggerSource,\n\ttype TriggerSourceType,\n\ttype TriggerStatus,\n\tTriggersClient,\n\ttype TriggerTarget,\n\ttype TriggerTargetType,\n\ttype UpdateTriggerOptions,\n} from './lib/triggers'\n\n// =============================================================================\n// Runs (ADR-040 — formerly Workers)\n// =============================================================================\n\nexport {\n\ttype CreateRunOptions,\n\ttype ListRunsOptions,\n\ttype ListRunsResult,\n\ttype Run,\n\t// Primary exports (ADR-040)\n\tRunHandle,\n\ttype RunLogsResult,\n\ttype RunResourceSpec,\n\ttype RunResult,\n\ttype RunStatus,\n\tRunsClient,\n\ttype RunVolumeMount,\n\t// Backward-compat aliases\n\tWorkerHandle,\n\ttype WorkerLogsResult,\n\ttype WorkerResourceSpec,\n\ttype WorkerResult,\n\ttype WorkerRun,\n\ttype WorkerStatus,\n\tWorkersClient,\n\ttype WorkerVolumeMount,\n} from './workers'\n\n// =============================================================================\n// Common Types (SDK-specific helpers — SSOT: ./types)\n// =============================================================================\n\nexport type {\n\tAccessTokenPayload,\n\tErrorResponse,\n\tPaginatedResponse,\n\tPaginationInput,\n\tSuccessResponse,\n\tUser,\n} from './types'\n\n// =============================================================================\n// Application Logs (ADR-089 Phase 4a)\n// =============================================================================\n\nexport {\n\ttype IngestLogsResult,\n\tingestLogs,\n\ttype LogEntry,\n\ttype LogLevel,\n\ttype QueryLogsOptions,\n\ttype QueryLogsResult,\n\tqueryLogs,\n\ttype StoredLogEntry,\n} from './logs'\n\n// =============================================================================\n// Misc — project metadata + step-up challenge (ADR-089 Phase 4a)\n// =============================================================================\n\nexport {\n\ttype ChallengeMethod,\n\ttype ChallengeType,\n\ttype ChallengeVerifyInput,\n\ttype ChallengeVerifyResult,\n\tgetProjectMetadata,\n\ttype ProjectMetadata,\n\tverifyChallenge,\n} from './misc'\n\n// =============================================================================\n// User (customer-app profile + sessions, ADR-089 Phase 4a)\n// =============================================================================\n\nexport {\n\ttype DeleteAccountResult,\n\tdeleteUserAccount,\n\texportUserData,\n\tgetUserProfile,\n\tgetUserSecurity,\n\tlistUserSessions,\n\trenameUserSession,\n\trevokeUserSession,\n\ttype UserDataExport,\n\ttype UserFullProfile,\n\ttype UserSecuritySettings,\n\ttype UserSession,\n\ttype UserSessionsList,\n\ttype UserUpdateProfileInput,\n\tupdateUserProfile,\n} from './user'\n\n// =============================================================================\n// Security — passwords, 2FA, passkeys, alerts (ADR-089 Phase 4a)\n// =============================================================================\n\nexport {\n\ttype BackupCodesResult,\n\tconfirmEmailChange,\n\tdeletePasskey,\n\tdisableTwoFactor,\n\tdisconnectOAuthProvider,\n\ttype EmailChangeInput,\n\ttype EmailConfirmInput,\n\tgetBackupCodes,\n\tgetSecurityScore,\n\tlistPasskeys,\n\tlistSecurityAlerts,\n\tmarkAllSecurityAlertsRead,\n\tmarkSecurityAlertRead,\n\ttype PasskeyRegistrationInput,\n\ttype PasskeyRegistrationOptions,\n\ttype PasskeySummary,\n\ttype PasskeysList,\n\ttype PasswordSetInput,\n\tregenerateBackupCodes,\n\trenamePasskey,\n\trequestEmailChange,\n\ttype SecurityAlert,\n\ttype SecurityAlertsList,\n\ttype SecurityScoreResult,\n\tsetPassword,\n\tsetupTwoFactor,\n\tstartPasskeyRegistration,\n\ttype TwoFactorEnableResult,\n\ttype TwoFactorSetupResult,\n\tverifyPasskeyRegistration,\n\tverifyTwoFactorEnable,\n} from './security'\n\n// =============================================================================\n// Customer-app OAuth flow (social login, ADR-089 Phase 4a)\n// =============================================================================\n\nexport {\n\tauthorizeOAuth,\n\tgeneratePkce,\n\tgetOidcDiscoveryDocument,\n\ttype OAuthAuthorizeInput,\n\ttype OAuthAuthorizeResult,\n\ttype OAuthProvider,\n\ttype OidcDiscoveryDocument,\n\ttype OidcUserInfoResponse,\n\ttype PkceMethod,\n\tparseOAuthCallback,\n\tuserInfo,\n} from './oauth'\n\n// =============================================================================\n// Promo codes (validate / redeem + admin CRUD, ADR-089 Phase 4a)\n// =============================================================================\n\nexport {\n\ttype CreatePromoInput,\n\tcreatePromo,\n\tdeletePromo,\n\tgetPromo,\n\ttype ListPromosOptions,\n\ttype ListPromosResult,\n\ttype ListRedemptionsOptions,\n\ttype ListRedemptionsResult,\n\tlistPromoRedemptions,\n\tlistPromos,\n\ttype PromoCode,\n\ttype PromoRedemption,\n\ttype PromoStatus,\n\ttype PromoType,\n\ttype PromoValidationPreview,\n\ttype RedeemPromoInput,\n\ttype RedeemPromoResult,\n\tredeemPromo,\n\ttype UpdatePromoInput,\n\tupdatePromo,\n\ttype ValidatePromoInput,\n\ttype ValidatePromoResult,\n\tvalidatePromo,\n} from './promo'\n\n// =============================================================================\n// React-layer types (tRPC-like wrappers — SSOT: ./react/types)\n// =============================================================================\n// Re-exported from the non-React entry for backcompat; these ride along\n// at type-only cost (sideEffects: false) and don't tug in react runtime.\n\nexport type {\n\tAIListModelsOptions,\n\tAIListModelsResponse,\n\tAIMessage,\n\tAIMessageRole,\n\tAIModelInfo,\n\tAIProvider,\n\tAIRateLimitInfo,\n\tAIRequestType,\n\tAIStreamChunk,\n\tAITool,\n\tAIToolCall,\n\tAIUsageStats,\n\tChatCompletionInput,\n\tChatCompletionResponse,\n\tEmbeddingInput,\n\tEmbeddingResponse,\n\tLoginHistoryEntry,\n\tSecuritySettings,\n\tTextCompletionInput,\n\tTextCompletionResponse,\n\tUserProfile,\n\tVisionInput,\n} from './react/types'\n","/**\n * Auth Functions\n *\n * Pure functions for authentication - no hidden state.\n * Each function takes config as the first parameter.\n *\n * Uses REST API at /api/sdk/auth/* for all operations.\n *\n * Types are re-exported from `@sylphx/contract` (ADR-084). The contract is\n * the single source of truth for every wire shape — this module only adds\n * SDK-specific ergonomics (User brand swap, introspection result, invite\n * envelopes, org-token claims).\n */\n\n// Type-only imports from @sylphx/contract per ADR-084 Rule 3 — prevents\n// Effect runtime types from leaking into the published .d.ts surface.\nimport type {\n\tAuthTokensResponse,\n\tAuthUserDeleteRequest as ContractAuthUserDeleteRequest,\n\tAuthUserDeleteResponse as ContractAuthUserDeleteResponse,\n\tAuthUserExportResponse as ContractAuthUserExportResponse,\n\tDeviceApproveRequest as ContractDeviceApproveRequest,\n\tDeviceApproveResponse as ContractDeviceApproveResponse,\n\tDeviceDenyRequest as ContractDeviceDenyRequest,\n\tDeviceDenyResponse as ContractDeviceDenyResponse,\n\tDeviceInitRequest as ContractDeviceInitRequest,\n\tDeviceInitResponse as ContractDeviceInitResponse,\n\tDevicePollResponse as ContractDevicePollResponse,\n\tLoginRequest as ContractLoginRequest,\n\tLoginResponse as ContractLoginResponse,\n\tLogoutInput as ContractLogoutInput,\n\tOAuthIntrospectRequest as ContractOAuthIntrospectRequest,\n\tOAuthIntrospectResponse as ContractOAuthIntrospectResponse,\n\tOAuthRevokeRequest as ContractOAuthRevokeRequest,\n\tPlatformPasswordChangeRequest as ContractPlatformPasswordChangeRequest,\n\tPlatformPasswordChangeResponse as ContractPlatformPasswordChangeResponse,\n\tPlatformPasswordSetRequest as ContractPlatformPasswordSetRequest,\n\tPlatformPasswordSetResponse as ContractPlatformPasswordSetResponse,\n\tPlatformPasswordStatusResponse as ContractPlatformPasswordStatusResponse,\n\tPlatformSessionRenameRequest as ContractPlatformSessionRenameRequest,\n\tPlatformSessionRenameResponse as ContractPlatformSessionRenameResponse,\n\tPlatformSessionRevokeAllResponse as ContractPlatformSessionRevokeAllResponse,\n\tPlatformSessionRevokeOtherResponse as ContractPlatformSessionRevokeOtherResponse,\n\tPlatformSessionRevokeRequest as ContractPlatformSessionRevokeRequest,\n\tPlatformSessionRevokeResponse as ContractPlatformSessionRevokeResponse,\n\tPlatformSessionsListResponse as ContractPlatformSessionsListResponse,\n\tRefreshTokenInput as ContractRefreshTokenInput,\n\tRefreshTokenResult as ContractRefreshTokenResult,\n\tRegisterRequest as ContractRegisterRequest,\n\tRegisterResponse as ContractRegisterResponse,\n\tSignInInput as ContractSignInInput,\n\tTwoFactorVerifyRequest as ContractTwoFactorVerifyRequest,\n\tUserFullProfile,\n} from '@sylphx/contract'\nimport { authEndpoints } from '@sylphx/contract'\nimport { buildApiUrl, callApi, type SylphxConfig } from './config'\nimport type { User } from './types'\n\n// ============================================================================\n// Types (re-exported from @sylphx/contract)\n// ============================================================================\n\nexport type LoginRequest = ContractLoginRequest\nexport type LoginResponse = ContractLoginResponse\nexport type RegisterRequest = ContractRegisterRequest\nexport type RegisterResponse = ContractRegisterResponse\n/**\n * Token response — contract's `AuthTokensResponse.user` (optional `AuthUser`)\n * is re-mapped to the SDK's broader `User` type so legacy callers keep the\n * familiar brand. `AuthUser` and `User` are structurally identical, but\n * the SDK surface has wider reach (cookies, middleware, React hooks) and\n * renaming is out of scope for ADR-084 cleanup.\n */\nexport type TokenResponse = Omit<AuthTokensResponse, 'user'> & {\n\tuser: User\n}\nexport type TwoFactorVerifyRequest = ContractTwoFactorVerifyRequest\n/**\n * `GET /auth/me` — contract's `UserFullProfile` already includes the\n * optional `emailVerified` flag the backend returns, so the SDK can just\n * alias the contract type directly.\n */\nexport type MeResponse = UserFullProfile\n\n// SDK-specific types (not directly from API schema)\n/**\n * Token introspection result (RFC 7662)\n */\nexport interface TokenIntrospectionResult {\n\t/** Whether the token is active/valid */\n\tactive: boolean\n\t/** Token type (access_token or refresh_token) */\n\ttoken_type?: 'access_token' | 'refresh_token'\n\t/** User ID */\n\tsub?: string\n\t/** User email */\n\temail?: string\n\t/** User name */\n\tname?: string\n\t/** App ID */\n\tclient_id?: string\n\t/** Audience */\n\taud?: string\n\t/** Issuer */\n\tiss?: string\n\t/** Expiration time (Unix timestamp) */\n\texp?: number\n\t/** Issued at time (Unix timestamp) */\n\tiat?: number\n\t/** User role */\n\trole?: string\n\t/** Email verification status */\n\temail_verified?: boolean\n}\n\n/**\n * Token revocation options\n */\nexport interface RevokeTokenOptions {\n\t/** Revoke all tokens for a user in this app */\n\trevokeAll?: boolean\n\t/** User ID (required when revoking all) */\n\tuserId?: string\n}\n\n// SDK-specific types (not in generated API)\nexport interface SessionResult {\n\tuser: {\n\t\tid: string\n\t\temail: string\n\t\tname: string | null\n\t\timage: string | null\n\t\temailVerified: boolean\n\t} | null\n}\n\n/**\n * Extended registration input with metadata and invitation token support.\n * Use extendedSignUp() when you need to pass metadata or an invitation token.\n */\nexport interface RegisterInput {\n\temail: string\n\tpassword: string\n\tname?: string\n\tmetadata?: Record<string, unknown>\n\tinvitationToken?: string\n}\n\n/**\n * Org context claims present in org-scoped tokens (after switch-org).\n *\n * The JWT carries the role key only. Permissions are resolved server-side\n * via Redis-cached role→permissions lookup (WorkOS pattern). This keeps\n * tokens small and ensures permission changes take effect without token refresh.\n */\nexport interface OrgTokenPayload {\n\torg_id: string\n\torg_slug: string\n\t/** RBAC role key (e.g. \"hr_manager\", \"admin\"). Permissions resolved server-side. */\n\torg_role: string\n}\n\n/**\n * Invite a user request payload.\n */\nexport interface InviteUserRequest {\n\temail: string\n\tmetadata?: Record<string, unknown>\n\tredirectUrl?: string\n}\n\n/**\n * Response from inviteUser.\n */\nexport interface InviteUserResponse {\n\tinvitationToken: string\n\texpiresAt: string\n}\n\n// ============================================================================\n// Functions\n// ============================================================================\n\n/**\n * Sign in with email and password\n *\n * @example\n * ```typescript\n * const result = await signIn(config, { email: 'user@example.com', password: 'secret' })\n * if (result.requiresTwoFactor) {\n * // Handle 2FA flow\n * } else {\n * // Save tokens\n * const authenticatedConfig = withToken(config, result.accessToken!)\n * }\n * ```\n */\nexport async function signIn(config: SylphxConfig, input: LoginRequest): Promise<LoginResponse> {\n\t// Contract-derived path/method (SSOT per ADR-084). The contract's\n\t// `SignInInput` is structurally compatible with `LoginRequest`; the SDK\n\t// keeps the fatter `LoginResponse` (discriminated 2FA union + embedded\n\t// user profile) until the contract schema grows to match.\n\t// TODO ADR-084: extend contract's SignInResult with user profile + refreshToken shape.\n\tconst body = input satisfies ContractSignInInput\n\tconst endpoint = authEndpoints.signIn\n\treturn callApi<LoginResponse>(config, endpoint.path, {\n\t\tmethod: endpoint.method,\n\t\tbody,\n\t})\n}\n\n/**\n * Sign up with email and password\n *\n * @example\n * ```typescript\n * const result = await signUp(config, {\n * email: 'user@example.com',\n * password: 'secret',\n * name: 'John Doe',\n * })\n * // User needs to verify email\n * ```\n */\nexport async function signUp(\n\tconfig: SylphxConfig,\n\tinput: RegisterRequest,\n): Promise<RegisterResponse> {\n\t// Contract-derived path/method (SSOT per ADR-084). SDK's `RegisterRequest`\n\t// is a superset of the contract's `SignUpInput` — it adds optional\n\t// `metadata` and `invitationToken` the server accepts.\n\t// TODO ADR-084: extend contract's SignUpInput with metadata + invitationToken.\n\tconst endpoint = authEndpoints.signUp\n\treturn callApi<RegisterResponse>(config, endpoint.path, {\n\t\tmethod: endpoint.method,\n\t\tbody: input,\n\t})\n}\n\n/**\n * Sign out (revoke tokens)\n *\n * @example\n * ```typescript\n * await signOut(config)\n * ```\n */\nexport async function signOut(config: SylphxConfig): Promise<void> {\n\t// Contract-derived path/method (SSOT per ADR-084).\n\tconst endpoint = authEndpoints.signOut\n\tawait callApi<void>(config, endpoint.path, { method: endpoint.method })\n}\n\n/**\n * Refresh access token\n *\n * @example\n * ```typescript\n * const tokens = await refreshToken(config, refreshTokenString)\n * const newConfig = withToken(config, tokens.accessToken)\n * ```\n */\nexport async function refreshToken(config: SylphxConfig, token: string): Promise<TokenResponse> {\n\treturn callApi<TokenResponse>(config, '/auth/token', {\n\t\tmethod: 'POST',\n\t\tbody: {\n\t\t\tgrant_type: 'refresh_token',\n\t\t\trefresh_token: token,\n\t\t\tclient_secret: config.secretKey,\n\t\t},\n\t})\n}\n\n/**\n * Verify email with token\n *\n * @example\n * ```typescript\n * await verifyEmail(config, token)\n * ```\n */\nexport async function verifyEmail(config: SylphxConfig, token: string): Promise<void> {\n\tawait callApi<void>(config, '/auth/verify-email', {\n\t\tmethod: 'POST',\n\t\tbody: { token },\n\t})\n}\n\n/**\n * Request password reset email\n *\n * @example\n * ```typescript\n * await forgotPassword(config, 'user@example.com')\n * ```\n */\nexport async function forgotPassword(config: SylphxConfig, email: string): Promise<void> {\n\tawait callApi<{ success: boolean }>(config, '/auth/forgot-password', {\n\t\tmethod: 'POST',\n\t\tbody: { email },\n\t})\n}\n\n/**\n * Reset password with token\n *\n * @example\n * ```typescript\n * await resetPassword(config, { token, password: 'newpassword' })\n * ```\n */\nexport async function resetPassword(\n\tconfig: SylphxConfig,\n\tinput: { token: string; password: string },\n): Promise<void> {\n\tawait callApi<{ success: boolean }>(config, '/auth/reset-password', {\n\t\tmethod: 'POST',\n\t\tbody: { token: input.token, newPassword: input.password },\n\t})\n}\n\n/**\n * Get current session (requires authenticated config)\n *\n * @example\n * ```typescript\n * const session = await getSession(authenticatedConfig)\n * if (session.user) {\n * console.log(`Logged in as ${session.user.email}`)\n * }\n * ```\n */\nexport async function getSession(config: SylphxConfig): Promise<SessionResult> {\n\tif (!config.accessToken) {\n\t\treturn { user: null }\n\t}\n\n\t// Contract-derived path/method (SSOT per ADR-084). The contract's\n\t// `SessionResult` uses branded `UserId` — the SDK currently surfaces\n\t// the raw string on `SessionResult['user'].id` because consumers pass it\n\t// to URL builders, cookies, etc. that don't understand the brand. The\n\t// structural shape is otherwise identical.\n\t// TODO ADR-084: either rebrand SDK's User id everywhere, or unbrand\n\t// contract's SessionResult.user.id for cross-package compatibility.\n\tconst endpoint = authEndpoints.getSession\n\ttry {\n\t\tconst user = await callApi<SessionResult['user']>(config, endpoint.path, {\n\t\t\tmethod: endpoint.method,\n\t\t})\n\t\treturn { user }\n\t} catch {\n\t\treturn { user: null }\n\t}\n}\n\n/**\n * Verify 2FA code (when signIn returns requiresTwoFactor: true)\n *\n * @example\n * ```typescript\n * const result = await signIn(config, credentials)\n * if (result.requiresTwoFactor) {\n * const tokens = await verifyTwoFactor(config, result.userId!, code)\n * }\n * ```\n */\nexport async function verifyTwoFactor(\n\tconfig: SylphxConfig,\n\tuserId: string,\n\tcode: string,\n): Promise<TokenResponse> {\n\treturn callApi<TokenResponse>(config, '/auth/verify-2fa', {\n\t\tmethod: 'POST',\n\t\tbody: { userId, code },\n\t})\n}\n\n/**\n * Introspect a token to check its validity (RFC 7662)\n *\n * Use this to verify token status without decoding. Essential for:\n * - Checking if a token has been revoked\n * - Validating tokens at the edge\n * - Security-critical operations\n *\n * @example\n * ```typescript\n * const result = await introspectToken(config, accessToken)\n * if (!result.active) {\n * // Token is invalid, revoked, or expired\n * await refreshTokens()\n * }\n * ```\n */\nexport async function introspectToken(\n\tconfig: SylphxConfig,\n\ttoken: string,\n\ttokenTypeHint?: 'access_token' | 'refresh_token',\n): Promise<TokenIntrospectionResult> {\n\tconst response = await fetch(buildApiUrl(config, '/auth/introspect'), {\n\t\tmethod: 'POST',\n\t\theaders: {\n\t\t\t'Content-Type': 'application/json',\n\t\t\t// RFC 7662 §2: server-to-server call — authenticate with secret key\n\t\t\t'x-app-secret': config.secretKey ?? '',\n\t\t},\n\t\tbody: JSON.stringify({\n\t\t\ttoken,\n\t\t\ttoken_type_hint: tokenTypeHint,\n\t\t}),\n\t})\n\n\tif (!response.ok) {\n\t\t// Per RFC 7662, errors should return inactive\n\t\treturn { active: false }\n\t}\n\n\treturn response.json()\n}\n\n/**\n * Revoke a token (RFC 7009)\n *\n * Use cases:\n * - Sign out user from specific device\n * - Security response to compromised token\n * - User-initiated session termination\n *\n * @example\n * ```typescript\n * // Revoke single refresh token\n * await revokeToken(config, refreshToken)\n *\n * // Revoke all tokens for a user (logout everywhere)\n * await revokeToken(config, '', { revokeAll: true, userId: 'user-123' })\n * ```\n */\nexport async function revokeToken(\n\tconfig: SylphxConfig,\n\ttoken: string,\n\toptions?: RevokeTokenOptions,\n): Promise<void> {\n\tawait fetch(buildApiUrl(config, '/auth/revoke'), {\n\t\tmethod: 'POST',\n\t\theaders: { 'Content-Type': 'application/json' },\n\t\tbody: JSON.stringify({\n\t\t\ttoken: options?.revokeAll ? undefined : token,\n\t\t\tclient_secret: config.secretKey,\n\t\t\tuser_id: options?.userId,\n\t\t\trevoke_all: options?.revokeAll,\n\t\t}),\n\t})\n\t// Per RFC 7009, always succeeds (200 OK)\n}\n\n/**\n * Revoke all tokens for a user (logout from all devices)\n *\n * Convenience wrapper around revokeToken with revokeAll option.\n *\n * @example\n * ```typescript\n * // After password change, revoke all sessions\n * await revokeAllTokens(config, userId)\n * ```\n */\nexport async function revokeAllTokens(config: SylphxConfig, userId: string): Promise<void> {\n\tawait revokeToken(config, '', { revokeAll: true, userId })\n}\n\n/**\n * Sign up with extended input (metadata + invitation token support).\n *\n * Use this instead of signUp() when you need to:\n * - Pass metadata on registration (e.g., org context, role, referral info)\n * - Register with an invitation token\n *\n * @example\n * ```typescript\n * const result = await extendedSignUp(config, {\n * email: 'user@example.com',\n * password: 'secret',\n * name: 'John Doe',\n * metadata: { orgId: 'org-123', role: 'employee' },\n * invitationToken: 'inv_...',\n * })\n * ```\n */\nexport async function extendedSignUp(\n\tconfig: SylphxConfig,\n\tinput: RegisterInput,\n): Promise<RegisterResponse> {\n\treturn callApi<RegisterResponse>(config, '/auth/register', {\n\t\tmethod: 'POST',\n\t\tbody: input,\n\t})\n}\n\n/**\n * Invite a user to sign up for this project.\n * Server-side only (requires secretKey).\n * Sends an email invitation; user signs up via signUp() or extendedSignUp() with the invitation token.\n *\n * @example\n * ```typescript\n * const invite = await inviteUser(config, {\n * email: 'newemployee@company.com',\n * metadata: { role: 'employee', orgId: 'org-123' },\n * redirectUrl: 'https://app.example.com/signup',\n * })\n * console.log(invite.invitationToken, invite.expiresAt)\n * ```\n */\nexport async function inviteUser(\n\tconfig: SylphxConfig,\n\tinput: InviteUserRequest,\n): Promise<InviteUserResponse> {\n\treturn callApi<InviteUserResponse>(config, '/auth/invite', {\n\t\tmethod: 'POST',\n\t\tbody: input,\n\t})\n}\n\n/**\n * Exchange current user token for an org-scoped token.\n * The returned access_token JWT includes org_id, org_slug, org_role claims.\n *\n * @example\n * const tokens = await switchOrg(withToken(config, currentToken), 'org_xxx')\n */\nexport async function switchOrg(config: SylphxConfig, orgId: string): Promise<TokenResponse> {\n\treturn callApi<TokenResponse>(config, '/auth/switch-org', {\n\t\tmethod: 'POST',\n\t\tbody: JSON.stringify({ orgId }),\n\t})\n}\n\n// ============================================================================\n// OAuth 2.0 Device Authorization Grant (RFC 8628)\n// ============================================================================\n//\n// The device flow is the *bootstrap* leg for headless clients (CLI, TV apps,\n// IoT) that can't host a browser. It is deliberately separate from the\n// pk_/sk_-credentialled `SylphxConfig` above because the device flow runs\n// BEFORE the client has any credential — that's the whole point.\n//\n// Accordingly the device-flow methods accept a `baseUrl` argument directly\n// rather than a `SylphxConfig`. For the Sylphx platform itself this will be\n// `https://your-app.api.sylphx.com/v1` (configurable via SYLPHX_BAAS_URL for\n// dev/staging). Callers that already have a `SylphxConfig` for their own app\n// can pass `config.baseUrl` — both surfaces resolve to the same endpoints.\n//\n// See ADR-089 Phase 2a for the migration notes and the apps/runtime handler.\n\nexport type DeviceInitInput = ContractDeviceInitRequest\nexport type DeviceGrant = ContractDeviceInitResponse\nexport type DevicePollResult = ContractDevicePollResponse\nexport type DeviceApproveInput = ContractDeviceApproveRequest\nexport type DeviceApproveResult = ContractDeviceApproveResponse\nexport type DeviceDenyInput = ContractDeviceDenyRequest\nexport type DeviceDenyResult = ContractDeviceDenyResponse\n\n/**\n * `device` namespace — RFC 8628 device authorization grant.\n *\n * Used by headless clients (CLI, TV apps, IoT) to authorise via a\n * companion browser instead of reading credentials from env vars.\n */\nexport const device = {\n\t/**\n\t * Start a device authorization grant.\n\t *\n\t * Returns a `DeviceGrant` with `verification_uri_complete` (open this\n\t * in the user's browser) and `device_code` (use for polling).\n\t *\n\t * @example\n\t * ```typescript\n\t * const grant = await device.init({\n\t * baseUrl: 'https://your-app.api.sylphx.com/v1',\n\t * clientId: 'sylphx-cli',\n\t * scope: ['org:read', 'project:*'],\n\t * })\n\t * openBrowser(grant.verification_uri_complete)\n\t * ```\n\t */\n\tasync init(opts: {\n\t\treadonly baseUrl: string\n\t\treadonly clientId: string\n\t\treadonly scope?: readonly string[]\n\t\treadonly userAgent?: string\n\t}): Promise<DeviceGrant> {\n\t\tconst res = await fetch(`${opts.baseUrl.replace(/\\/$/, '')}/auth/device`, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: buildDeviceHeaders(opts.userAgent),\n\t\t\tbody: JSON.stringify({\n\t\t\t\tclient_id: opts.clientId,\n\t\t\t\tscope: opts.scope ?? [],\n\t\t\t}),\n\t\t})\n\t\tif (!res.ok) throw await deviceError(res, 'device.init')\n\t\treturn (await res.json()) as DeviceGrant\n\t},\n\n\t/**\n\t * Poll a pending grant. Returns `status: 'pending' | 'approved' |\n\t * 'denied' | 'expired'`. On `approved`, the result carries the OAuth\n\t * pair (access_token + refresh_token).\n\t *\n\t * Callers MUST respect the `interval` returned by `init()` — polling\n\t * faster than that may return 429 slow_down (RFC 8628 §5.5).\n\t */\n\tasync poll(opts: {\n\t\treadonly baseUrl: string\n\t\treadonly deviceCode: string\n\t\treadonly userAgent?: string\n\t}): Promise<DevicePollResult> {\n\t\tconst url = new URL(`${opts.baseUrl.replace(/\\/$/, '')}/auth/device/poll`)\n\t\turl.searchParams.set('device_code', opts.deviceCode)\n\t\tconst res = await fetch(url.toString(), {\n\t\t\tmethod: 'GET',\n\t\t\theaders: buildDeviceHeaders(opts.userAgent),\n\t\t})\n\t\tif (!res.ok) throw await deviceError(res, 'device.poll')\n\t\treturn (await res.json()) as DevicePollResult\n\t},\n\n\t/**\n\t * Browser leg — the approving user confirms the grant.\n\t *\n\t * Requires a valid platform-issued access token (`Authorization:\n\t * Bearer <accessToken>`) proving the user is logged in on the\n\t * Console. Typically called by the Console's `/device` verification\n\t * page server-side, forwarding the user's session JWT.\n\t */\n\tasync approve(opts: {\n\t\treadonly baseUrl: string\n\t\treadonly userCode: string\n\t\treadonly accessToken: string\n\t\treadonly userAgent?: string\n\t}): Promise<DeviceApproveResult> {\n\t\tconst res = await fetch(`${opts.baseUrl.replace(/\\/$/, '')}/auth/device/approve`, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: {\n\t\t\t\t...buildDeviceHeaders(opts.userAgent),\n\t\t\t\tAuthorization: `Bearer ${opts.accessToken}`,\n\t\t\t},\n\t\t\tbody: JSON.stringify({ user_code: opts.userCode }),\n\t\t})\n\t\tif (!res.ok) throw await deviceError(res, 'device.approve')\n\t\treturn (await res.json()) as DeviceApproveResult\n\t},\n\n\t/**\n\t * Browser leg — the user declines the grant.\n\t *\n\t * Requires a valid platform-issued access token just like `approve`.\n\t */\n\tasync deny(opts: {\n\t\treadonly baseUrl: string\n\t\treadonly userCode: string\n\t\treadonly accessToken: string\n\t\treadonly userAgent?: string\n\t}): Promise<DeviceDenyResult> {\n\t\tconst res = await fetch(`${opts.baseUrl.replace(/\\/$/, '')}/auth/device/deny`, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: {\n\t\t\t\t...buildDeviceHeaders(opts.userAgent),\n\t\t\t\tAuthorization: `Bearer ${opts.accessToken}`,\n\t\t\t},\n\t\t\tbody: JSON.stringify({ user_code: opts.userCode }),\n\t\t})\n\t\tif (!res.ok) throw await deviceError(res, 'device.deny')\n\t\treturn (await res.json()) as DeviceDenyResult\n\t},\n} as const\n\nfunction buildDeviceHeaders(userAgent: string | undefined): Record<string, string> {\n\tconst headers: Record<string, string> = {\n\t\t'Content-Type': 'application/json',\n\t}\n\tif (userAgent) headers['User-Agent'] = userAgent\n\treturn headers\n}\n\n// ============================================================================\n// OAuth AS — shared types (Phase 5.1d)\n// ============================================================================\n\nexport type OAuthRevokeInput = ContractOAuthRevokeRequest\nexport type OAuthIntrospectInput = ContractOAuthIntrospectRequest\nexport type OAuthIntrospectResult = ContractOAuthIntrospectResponse\n\ninterface OAuthClientCallOpts {\n\treadonly baseUrl: string\n\treadonly clientId: string\n\treadonly clientSecret?: string\n\treadonly token: string\n\treadonly tokenTypeHint?: 'access_token' | 'refresh_token'\n\treadonly userAgent?: string\n}\n\n// ============================================================================\n// Platform sessions (ADR-089 Phase 2b)\n// ============================================================================\n//\n// Session management for the Platform plane (Console / CLI operators).\n// Like the device flow, these endpoints accept a `baseUrl + accessToken`\n// rather than a `SylphxConfig` — the caller is authenticating with a\n// platform-audience JWT, not a customer-app `pk_`/`sk_` pair. The BaaS\n// runtime (`apps/runtime/src/server/runtime/routes/auth/platform-sessions.ts`)\n// verifies the token against audience `'platform'` and scopes every\n// operation by `sub` (user id).\n//\n// For the Sylphx platform itself, `baseUrl` is\n// `https://your-app.api.sylphx.com/v1` (configurable via SYLPHX_BAAS_URL\n// for dev/staging). Callers that already have a customer `SylphxConfig`\n// could pass `config.baseUrl` — but this namespace is designed for\n// platform-plane operations; customer apps use the BaaS `userAuth`\n// routes under `/auth/sessions/*` instead.\n//\n// See ADR-089 Phase 2b for the migration notes, the Platform route\n// rewrites in `apps/api/.../security/sessions.ts` + `.../user.ts`, and\n// the atomic grandfather removal in `.dogfood-grandfather.txt`.\n\nexport type PlatformSessionsListResult = ContractPlatformSessionsListResponse\nexport type PlatformSessionRevokeInput = ContractPlatformSessionRevokeRequest\nexport type PlatformSessionRevokeResult = ContractPlatformSessionRevokeResponse\nexport type PlatformSessionRevokeOtherResult = ContractPlatformSessionRevokeOtherResponse\nexport type PlatformSessionRevokeAllResult = ContractPlatformSessionRevokeAllResponse\nexport type PlatformSessionRenameInput = ContractPlatformSessionRenameRequest\nexport type PlatformSessionRenameResult = ContractPlatformSessionRenameResponse\n\n/**\n * `sessions` namespace — Platform-plane (Console / CLI) session\n * management. Backed by `/auth/platform-sessions/*` on the BaaS\n * runtime (ADR-089 Phase 2b). See module header for the full rationale.\n */\nexport const sessions = {\n\t/**\n\t * List every active platform session for the authenticated user.\n\t *\n\t * Ordering: most-recently-active first.\n\t *\n\t * @example\n\t * ```typescript\n\t * const { sessions } = await auth.sessions.list({\n\t * baseUrl: 'https://your-app.api.sylphx.com/v1',\n\t * accessToken: platformJwt,\n\t * })\n\t * ```\n\t */\n\tasync list(opts: {\n\t\treadonly baseUrl: string\n\t\treadonly accessToken: string\n\t\treadonly userAgent?: string\n\t}): Promise<PlatformSessionsListResult> {\n\t\tconst res = await fetch(`${opts.baseUrl.replace(/\\/$/, '')}/auth/platform-sessions`, {\n\t\t\tmethod: 'GET',\n\t\t\theaders: buildPlatformSessionsHeaders(opts.accessToken, opts.userAgent),\n\t\t})\n\t\tif (!res.ok) throw await platformSessionError(res, 'sessions.list')\n\t\treturn (await res.json()) as PlatformSessionsListResult\n\t},\n\n\t/**\n\t * Revoke a specific platform session by id.\n\t *\n\t * `sessionId` accepts either the prefixed TypeID (`sess_*`) or the\n\t * raw UUID — the BaaS side normalises via `parseIdOrError`.\n\t *\n\t * @example\n\t * ```typescript\n\t * await auth.sessions.revoke({\n\t * baseUrl,\n\t * accessToken,\n\t * sessionId: 'sess_01hxyz...',\n\t * })\n\t * ```\n\t */\n\tasync revoke(opts: {\n\t\treadonly baseUrl: string\n\t\treadonly accessToken: string\n\t\treadonly sessionId: string\n\t\treadonly userAgent?: string\n\t}): Promise<PlatformSessionRevokeResult> {\n\t\tconst res = await fetch(`${opts.baseUrl.replace(/\\/$/, '')}/auth/platform-sessions/revoke`, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: buildPlatformSessionsHeaders(opts.accessToken, opts.userAgent),\n\t\t\tbody: JSON.stringify({ sessionId: opts.sessionId } satisfies PlatformSessionRevokeInput),\n\t\t})\n\t\tif (!res.ok) throw await platformSessionError(res, 'sessions.revoke')\n\t\treturn (await res.json()) as PlatformSessionRevokeResult\n\t},\n\n\t/**\n\t * Revoke every platform session except the one presenting the\n\t * current access token. Used by \"sign me out of all other devices\".\n\t *\n\t * When the caller's JWT has no `sid` claim (pure-Bearer CLI/CI\n\t * flows), this degenerates to `revokeAll` — every session is\n\t * wiped — because there's no \"current\" row to keep.\n\t *\n\t * @example\n\t * ```typescript\n\t * const { revokedCount } = await auth.sessions.revokeOther({\n\t * baseUrl,\n\t * accessToken,\n\t * })\n\t * ```\n\t */\n\tasync revokeOther(opts: {\n\t\treadonly baseUrl: string\n\t\treadonly accessToken: string\n\t\treadonly userAgent?: string\n\t}): Promise<PlatformSessionRevokeOtherResult> {\n\t\tconst res = await fetch(\n\t\t\t`${opts.baseUrl.replace(/\\/$/, '')}/auth/platform-sessions/revoke-other`,\n\t\t\t{\n\t\t\t\tmethod: 'POST',\n\t\t\t\theaders: buildPlatformSessionsHeaders(opts.accessToken, opts.userAgent),\n\t\t\t},\n\t\t)\n\t\tif (!res.ok) throw await platformSessionError(res, 'sessions.revokeOther')\n\t\treturn (await res.json()) as PlatformSessionRevokeOtherResult\n\t},\n\n\t/**\n\t * Revoke every platform session for the user, including the\n\t * caller's own. Used by \"sign me out everywhere\" — after a\n\t * password change, a compromise scare, or GDPR-style erasure.\n\t *\n\t * The response includes the count of sessions that were\n\t * revoked so the caller can surface it in a toast or audit UI.\n\t *\n\t * @example\n\t * ```typescript\n\t * const { count } = await auth.sessions.revokeAll({\n\t * baseUrl,\n\t * accessToken,\n\t * })\n\t * ```\n\t */\n\tasync revokeAll(opts: {\n\t\treadonly baseUrl: string\n\t\treadonly accessToken: string\n\t\treadonly userAgent?: string\n\t}): Promise<PlatformSessionRevokeAllResult> {\n\t\tconst res = await fetch(\n\t\t\t`${opts.baseUrl.replace(/\\/$/, '')}/auth/platform-sessions/revoke-all`,\n\t\t\t{\n\t\t\t\tmethod: 'POST',\n\t\t\t\theaders: buildPlatformSessionsHeaders(opts.accessToken, opts.userAgent),\n\t\t\t},\n\t\t)\n\t\tif (!res.ok) throw await platformSessionError(res, 'sessions.revokeAll')\n\t\treturn (await res.json()) as PlatformSessionRevokeAllResult\n\t},\n\n\t/**\n\t * Rename a platform session (device label).\n\t *\n\t * `sessionId` accepts either the prefixed TypeID or the raw UUID;\n\t * `name` is a user-supplied string (≤100 chars) surfaced in the\n\t * \"Active sessions\" Console UI.\n\t *\n\t * @example\n\t * ```typescript\n\t * await auth.sessions.rename({\n\t * baseUrl,\n\t * accessToken,\n\t * sessionId,\n\t * name: 'MacBook (work)',\n\t * })\n\t * ```\n\t */\n\tasync rename(opts: {\n\t\treadonly baseUrl: string\n\t\treadonly accessToken: string\n\t\treadonly sessionId: string\n\t\treadonly name: string\n\t\treadonly userAgent?: string\n\t}): Promise<PlatformSessionRenameResult> {\n\t\tconst res = await fetch(`${opts.baseUrl.replace(/\\/$/, '')}/auth/platform-sessions/rename`, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: buildPlatformSessionsHeaders(opts.accessToken, opts.userAgent),\n\t\t\tbody: JSON.stringify({\n\t\t\t\tsessionId: opts.sessionId,\n\t\t\t\tname: opts.name,\n\t\t\t} satisfies PlatformSessionRenameInput),\n\t\t})\n\t\tif (!res.ok) throw await platformSessionError(res, 'sessions.rename')\n\t\treturn (await res.json()) as PlatformSessionRenameResult\n\t},\n} as const\n\nfunction buildPlatformSessionsHeaders(\n\taccessToken: string,\n\tuserAgent: string | undefined,\n): Record<string, string> {\n\tconst headers: Record<string, string> = {\n\t\t'Content-Type': 'application/json',\n\t\tAuthorization: `Bearer ${accessToken}`,\n\t}\n\tif (userAgent) headers['User-Agent'] = userAgent\n\treturn headers\n}\n\n// ============================================================================\n// Platform auth — refresh-token rotation + logout (ADR-089 SoC Tier-1)\n// ============================================================================\n//\n// Platform-plane (`apps/api`) refresh / logout endpoints. Mirrors the\n// `sessions.*` namespace shape: caller supplies `{ baseUrl, refreshToken }`\n// rather than a `SylphxConfig`, because these are CLI / Console\n// operator-context calls authenticating via the presented refresh token in\n// the JSON body — NOT via cookies, NOT via `pk_`/`sk_`.\n//\n// Backed by `apps/api/src/server/platform/routes/refresh.ts` (contract:\n// `refreshEndpoints.refresh` + `authEndpoints.signOut`). Eliminates the\n// last `fetch()` to `/auth/refresh` + `/auth/logout` from the CLI\n// (Q3-CF-1, Q3-CF-2 from the 2026-04-25 SoC review).\n//\n// Distinct from `oauth.refreshAccessToken` / `oauth.revokeToken` — those\n// drive the BaaS-plane RFC 6749/7009 OAuth AS at `/oauth/token` +\n// `/oauth/revoke`. This namespace targets the legacy Platform refresh\n// chain that still backs CLI device-flow tokens (consolidation deferred\n// to Phase 5.1+).\n\nexport type PlatformRefreshInput = ContractRefreshTokenInput\nexport type PlatformRefreshResult = ContractRefreshTokenResult\nexport type PlatformLogoutInput = ContractLogoutInput\n\n/**\n * `platformAuth` namespace — Platform-plane refresh-token + logout\n * operations for CLI / Console operators. Body-authenticated via the\n * presented refresh token (no cookie, no Bearer).\n */\nexport const platformAuth = {\n\t/**\n\t * Rotate a Platform refresh token. The presented token is consumed\n\t * single-use; the response carries a fresh access JWT plus the\n\t * rotated refresh token that supersedes it.\n\t *\n\t * On reuse-detection / expiry the server returns 401 — the SDK\n\t * preserves the upstream message so callers can pattern-match\n\t * `\"reuse\"` per RFC 6819 §5.2.2.3 and scrub local credentials.\n\t *\n\t * @example\n\t * ```typescript\n\t * const tokens = await auth.platformAuth.refresh({\n\t * baseUrl: 'https://sylphx.com',\n\t * refreshToken: stored.refreshToken,\n\t * })\n\t * ```\n\t */\n\tasync refresh(opts: {\n\t\treadonly baseUrl: string\n\t\treadonly refreshToken: string\n\t\treadonly userAgent?: string\n\t}): Promise<PlatformRefreshResult> {\n\t\tconst headers: Record<string, string> = { 'Content-Type': 'application/json' }\n\t\tif (opts.userAgent) headers['User-Agent'] = opts.userAgent\n\t\tconst res = await fetch(`${opts.baseUrl.replace(/\\/$/, '')}/api/v1/auth/refresh`, {\n\t\t\tmethod: 'POST',\n\t\t\theaders,\n\t\t\tbody: JSON.stringify({ refresh_token: opts.refreshToken } satisfies PlatformRefreshInput),\n\t\t})\n\t\tif (!res.ok) throw await platformAuthError(res, 'platformAuth.refresh')\n\t\treturn (await res.json()) as PlatformRefreshResult\n\t},\n\n\t/**\n\t * Revoke a Platform refresh token (logout). Server-side revocation\n\t * failure is the caller's call to surface — local-credential cleanup\n\t * is the CLI's responsibility (logout must succeed offline).\n\t *\n\t * @example\n\t * ```typescript\n\t * await auth.platformAuth.logout({\n\t * baseUrl: 'https://sylphx.com',\n\t * refreshToken: stored.refreshToken,\n\t * })\n\t * ```\n\t */\n\tasync logout(opts: {\n\t\treadonly baseUrl: string\n\t\treadonly refreshToken: string\n\t\treadonly userAgent?: string\n\t}): Promise<void> {\n\t\tconst headers: Record<string, string> = { 'Content-Type': 'application/json' }\n\t\tif (opts.userAgent) headers['User-Agent'] = opts.userAgent\n\t\tconst res = await fetch(`${opts.baseUrl.replace(/\\/$/, '')}/api/v1/auth/logout`, {\n\t\t\tmethod: 'POST',\n\t\t\theaders,\n\t\t\tbody: JSON.stringify({ refresh_token: opts.refreshToken } satisfies PlatformLogoutInput),\n\t\t})\n\t\tif (!res.ok) throw await platformAuthError(res, 'platformAuth.logout')\n\t},\n} as const\n\n/**\n * Normalise Platform refresh / logout HTTP errors into `SylphxError`s.\n * Preserves the upstream message verbatim so reuse-detection callers\n * can substring-match `\"reuse\"` per RFC 6819 §5.2.2.3.\n */\nasync function platformAuthError(res: Response, operation: string): Promise<Error> {\n\tconst { SylphxError } = await import('./errors')\n\tconst body = await res.text().catch(() => '')\n\tlet code = 'platform_auth_error'\n\tlet message = `${operation} failed: HTTP ${res.status}`\n\ttry {\n\t\tconst parsed = JSON.parse(body) as {\n\t\t\terror?: string | { code?: string; message?: string }\n\t\t\tmessage?: string\n\t\t}\n\t\tif (typeof parsed.error === 'string') code = parsed.error\n\t\telse if (parsed.error && typeof parsed.error === 'object') {\n\t\t\tif (parsed.error.code) code = parsed.error.code\n\t\t\tif (parsed.error.message) message = parsed.error.message\n\t\t} else if (parsed.message) {\n\t\t\tmessage = parsed.message\n\t\t}\n\t} catch {\n\t\t// Non-JSON body — fall back to raw text so reuse-detection still\n\t\t// matches if the upstream went bare-string.\n\t\tif (body) message = body\n\t}\n\tlet errorCode:\n\t\t| 'UNAUTHORIZED'\n\t\t| 'NOT_FOUND'\n\t\t| 'TOO_MANY_REQUESTS'\n\t\t| 'BAD_REQUEST'\n\t\t| 'INTERNAL_SERVER_ERROR'\n\tif (res.status === 401) errorCode = 'UNAUTHORIZED'\n\telse if (res.status === 404) errorCode = 'NOT_FOUND'\n\telse if (res.status === 429) errorCode = 'TOO_MANY_REQUESTS'\n\telse if (res.status >= 500) errorCode = 'INTERNAL_SERVER_ERROR'\n\telse errorCode = 'BAD_REQUEST'\n\treturn new SylphxError(message, {\n\t\tcode: errorCode,\n\t\tstatus: res.status,\n\t\tdata: { operation, code },\n\t})\n}\n\n/**\n * Normalise platform-sessions HTTP errors into `SylphxError`s with\n * meaningful codes. Mirrors `deviceError` above — the two share the\n * same 4xx/5xx treatment so Platform callers can rethrow cleanly.\n */\nasync function platformSessionError(res: Response, operation: string): Promise<Error> {\n\tconst { SylphxError } = await import('./errors')\n\tconst body = await res.text().catch(() => '')\n\tlet code = 'platform_sessions_error'\n\tlet message = `${operation} failed: HTTP ${res.status}`\n\ttry {\n\t\tconst parsed = JSON.parse(body) as {\n\t\t\terror?: string\n\t\t\tmessage?: string\n\t\t\terror_description?: string\n\t\t}\n\t\tif (parsed.error) code = parsed.error\n\t\tif (parsed.error_description) message = parsed.error_description\n\t\telse if (parsed.message) message = parsed.message\n\t} catch {\n\t\t// Non-JSON body — keep default message.\n\t}\n\tlet errorCode:\n\t\t| 'UNAUTHORIZED'\n\t\t| 'NOT_FOUND'\n\t\t| 'TOO_MANY_REQUESTS'\n\t\t| 'BAD_REQUEST'\n\t\t| 'INTERNAL_SERVER_ERROR'\n\tif (res.status === 401) errorCode = 'UNAUTHORIZED'\n\telse if (res.status === 404) errorCode = 'NOT_FOUND'\n\telse if (res.status === 429) errorCode = 'TOO_MANY_REQUESTS'\n\telse if (res.status >= 500) errorCode = 'INTERNAL_SERVER_ERROR'\n\telse errorCode = 'BAD_REQUEST'\n\treturn new SylphxError(message, {\n\t\tcode: errorCode,\n\t\tstatus: res.status,\n\t\tdata: { operation, code },\n\t})\n}\n\n/**\n * Normalise device-flow HTTP errors into `SylphxError`s with meaningful\n * codes so CLI-side retry logic can discriminate between `transient`\n * (5xx / network) and `invalid_grant` (404 / 409) outcomes.\n */\nasync function deviceError(res: Response, operation: string): Promise<Error> {\n\t// Dynamic import avoids a hard dependency on the error module for the\n\t// happy path. The tree-shaker drops this when unused.\n\tconst { SylphxError } = await import('./errors')\n\tconst body = await res.text().catch(() => '')\n\tlet code = 'device_flow_error'\n\tlet message = `${operation} failed: HTTP ${res.status}`\n\ttry {\n\t\tconst parsed = JSON.parse(body) as { error?: string; error_description?: string }\n\t\tif (parsed.error) code = parsed.error\n\t\tif (parsed.error_description) message = parsed.error_description\n\t} catch {\n\t\t// Non-JSON body — keep default message.\n\t}\n\treturn new SylphxError(message, {\n\t\tcode: res.status === 429 ? 'TOO_MANY_REQUESTS' : 'BAD_REQUEST',\n\t\tstatus: res.status,\n\t\tdata: { operation, code },\n\t})\n}\n\n// ============================================================================\n// Platform password (ADR-089 Phase 2c)\n// ============================================================================\n//\n// Password management for the Platform plane (Console / CLI operators).\n// Like the device flow and platform-sessions namespaces, these endpoints\n// accept a `baseUrl + accessToken` rather than a `SylphxConfig` — the\n// caller is authenticating with a platform-audience JWT, not a\n// customer-app `pk_`/`sk_` pair. The BaaS runtime\n// (`apps/runtime/src/server/runtime/routes/auth/platform-password.ts`)\n// verifies the token against audience `'platform'` and scopes every\n// operation by `sub` (user id).\n//\n// For the Sylphx platform itself, `baseUrl` is\n// `https://your-app.api.sylphx.com/v1` (configurable via SYLPHX_BAAS_URL\n// for dev/staging). Customer apps use the BaaS `/auth/change-password`\n// and `/auth/forgot-password` routes directly — those operate on the\n// per-project `projectUserTokens` surface and speak a different auth\n// model (projectAuth + userAuth with customer-app slug audience).\n//\n// The entire crypto primitive layer (bcrypt/argon2/scrypt, HIBP breach\n// check, session invalidation after change) lives inside the BaaS route\n// via `@sylphx/core/features/auth/lib/password` Effect helpers. Platform\n// callers NEVER see a raw hash primitive — ADR-089 §5 S1–S4.\n//\n// See ADR-089 Phase 2c for the migration notes, the Platform route\n// rewrites in `apps/api/.../security/password.ts` + `.../user.ts`, and\n// the atomic grandfather removal in `.dogfood-grandfather.txt`.\n\nexport type PlatformPasswordStatusResult = ContractPlatformPasswordStatusResponse\nexport type PlatformPasswordSetInput = ContractPlatformPasswordSetRequest\nexport type PlatformPasswordSetResult = ContractPlatformPasswordSetResponse\nexport type PlatformPasswordChangeInput = ContractPlatformPasswordChangeRequest\nexport type PlatformPasswordChangeResult = ContractPlatformPasswordChangeResponse\n\n/**\n * `password` namespace — Platform-plane (Console / CLI) password\n * management. Backed by `/auth/platform-password/*` on the BaaS\n * runtime (ADR-089 Phase 2c). See module header for the full rationale.\n */\nexport const password = {\n\t/**\n\t * Check whether the authenticated platform user has a password set.\n\t *\n\t * Returns `{ hasPassword: true }` for users that signed up with\n\t * email+password (or later called `set`), `{ hasPassword: false }`\n\t * for OAuth-only users (e.g. signed up via Google/GitHub).\n\t *\n\t * @example\n\t * ```typescript\n\t * const { hasPassword } = await auth.password.status({\n\t * baseUrl: 'https://your-app.api.sylphx.com/v1',\n\t * accessToken: platformJwt,\n\t * })\n\t * ```\n\t */\n\tasync status(opts: {\n\t\treadonly baseUrl: string\n\t\treadonly accessToken: string\n\t\treadonly userAgent?: string\n\t}): Promise<PlatformPasswordStatusResult> {\n\t\tconst res = await fetch(`${opts.baseUrl.replace(/\\/$/, '')}/auth/platform-password/status`, {\n\t\t\tmethod: 'GET',\n\t\t\theaders: buildPlatformPasswordHeaders(opts.accessToken, opts.userAgent),\n\t\t})\n\t\tif (!res.ok) throw await platformPasswordError(res, 'password.status')\n\t\treturn (await res.json()) as PlatformPasswordStatusResult\n\t},\n\n\t/**\n\t * Set an initial password for an OAuth-only user.\n\t *\n\t * Fails with 400 if the user already has a password (use `change`\n\t * instead), if the password is <8 characters, or if HIBP reports\n\t * the password as breached. BaaS invalidates every other session\n\t * for the user (keeping the caller's current one) after a\n\t * successful set.\n\t *\n\t * @example\n\t * ```typescript\n\t * await auth.password.set({\n\t * baseUrl,\n\t * accessToken,\n\t * password: 'correct-horse-battery-staple',\n\t * })\n\t * ```\n\t */\n\tasync set(opts: {\n\t\treadonly baseUrl: string\n\t\treadonly accessToken: string\n\t\treadonly password: string\n\t\treadonly userAgent?: string\n\t}): Promise<PlatformPasswordSetResult> {\n\t\tconst res = await fetch(`${opts.baseUrl.replace(/\\/$/, '')}/auth/platform-password/set`, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: buildPlatformPasswordHeaders(opts.accessToken, opts.userAgent),\n\t\t\tbody: JSON.stringify({\n\t\t\t\tpassword: opts.password,\n\t\t\t} satisfies PlatformPasswordSetInput),\n\t\t})\n\t\tif (!res.ok) throw await platformPasswordError(res, 'password.set')\n\t\treturn (await res.json()) as PlatformPasswordSetResult\n\t},\n\n\t/**\n\t * Change an existing password.\n\t *\n\t * Verifies `currentPassword` server-side; a mismatch returns 401.\n\t * OAuth-only users (no existing password) get 400 — use `set`\n\t * instead. New password must be ≥8 characters and must not be in\n\t * HIBP's breach database. BaaS invalidates every other session\n\t * for the user (keeping the caller's current one) after a\n\t * successful change.\n\t *\n\t * @example\n\t * ```typescript\n\t * await auth.password.change({\n\t * baseUrl,\n\t * accessToken,\n\t * currentPassword: 'old-plaintext',\n\t * newPassword: 'new-plaintext',\n\t * })\n\t * ```\n\t */\n\tasync change(opts: {\n\t\treadonly baseUrl: string\n\t\treadonly accessToken: string\n\t\treadonly currentPassword: string\n\t\treadonly newPassword: string\n\t\treadonly userAgent?: string\n\t}): Promise<PlatformPasswordChangeResult> {\n\t\tconst res = await fetch(`${opts.baseUrl.replace(/\\/$/, '')}/auth/platform-password/change`, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: buildPlatformPasswordHeaders(opts.accessToken, opts.userAgent),\n\t\t\tbody: JSON.stringify({\n\t\t\t\tcurrentPassword: opts.currentPassword,\n\t\t\t\tnewPassword: opts.newPassword,\n\t\t\t} satisfies PlatformPasswordChangeInput),\n\t\t})\n\t\tif (!res.ok) throw await platformPasswordError(res, 'password.change')\n\t\treturn (await res.json()) as PlatformPasswordChangeResult\n\t},\n} as const\n\nfunction buildPlatformPasswordHeaders(\n\taccessToken: string,\n\tuserAgent: string | undefined,\n): Record<string, string> {\n\tconst headers: Record<string, string> = {\n\t\t'Content-Type': 'application/json',\n\t\tAuthorization: `Bearer ${accessToken}`,\n\t}\n\tif (userAgent) headers['User-Agent'] = userAgent\n\treturn headers\n}\n\n/**\n * Normalise platform-password HTTP errors into `SylphxError`s with\n * meaningful codes. Mirrors `platformSessionError` above — same 4xx/5xx\n * treatment so Platform callers can rethrow cleanly and the Platform\n * route layer can discriminate NOT_FOUND / UNAUTHORIZED / BAD_REQUEST\n * by status code without parsing the body.\n */\nasync function platformPasswordError(res: Response, operation: string): Promise<Error> {\n\tconst { SylphxError } = await import('./errors')\n\tconst body = await res.text().catch(() => '')\n\tlet code = 'platform_password_error'\n\tlet message = `${operation} failed: HTTP ${res.status}`\n\ttry {\n\t\tconst parsed = JSON.parse(body) as {\n\t\t\terror?: string\n\t\t\tmessage?: string\n\t\t\terror_description?: string\n\t\t}\n\t\tif (parsed.error) code = parsed.error\n\t\tif (parsed.error_description) message = parsed.error_description\n\t\telse if (parsed.message) message = parsed.message\n\t} catch {\n\t\t// Non-JSON body — keep default message.\n\t}\n\tlet errorCode:\n\t\t| 'UNAUTHORIZED'\n\t\t| 'NOT_FOUND'\n\t\t| 'TOO_MANY_REQUESTS'\n\t\t| 'BAD_REQUEST'\n\t\t| 'INTERNAL_SERVER_ERROR'\n\tif (res.status === 401) errorCode = 'UNAUTHORIZED'\n\telse if (res.status === 404) errorCode = 'NOT_FOUND'\n\telse if (res.status === 429) errorCode = 'TOO_MANY_REQUESTS'\n\telse if (res.status >= 500) errorCode = 'INTERNAL_SERVER_ERROR'\n\telse errorCode = 'BAD_REQUEST'\n\treturn new SylphxError(message, {\n\t\tcode: errorCode,\n\t\tstatus: res.status,\n\t\tdata: { operation, code },\n\t})\n}\n\n// ============================================================================\n// Platform user data (ADR-089 Phase 2d)\n// ============================================================================\n//\n// GDPR export + erasure for the Platform plane (Console / CLI operators).\n// Like the sibling device / platform-sessions / platform-password\n// namespaces, these endpoints accept a `baseUrl + accessToken` rather\n// than a `SylphxConfig` — the caller authenticates with a platform-\n// audience JWT, not a customer-app `pk_`/`sk_` pair. The BaaS runtime\n// (`apps/runtime/src/server/runtime/routes/auth/platform-user.ts`)\n// verifies the token against audience `'platform'` and scopes every\n// operation by `sub` (user id).\n//\n// For the Sylphx platform itself, `baseUrl` is\n// `https://your-app.api.sylphx.com/v1` (configurable via SYLPHX_BAAS_URL\n// for dev/staging).\n//\n// The entire GDPR cascade (per-project BaaS DB erasure, Stripe customer\n// cleanup, S3 blob deletion, audit anonymisation) lives inside the BaaS\n// route via `@sylphx/core/lib/auth/user-deletion` Effect helpers.\n// Platform callers NEVER touch per-project DBs, Stripe, or S3 directly —\n// ADR-089 §5 S1–S4 / Principle 2.\n//\n// Method names:\n// - `exportData` (not `export`) — `export` is a JavaScript reserved\n// word and is illegal as a top-level binding inside an exported\n// namespace object.\n// - `deleteAccount` (not `delete`) — `delete` is a JavaScript operator\n// and is ambiguous as a property-access expression. `deleteAccount`\n// also reads more clearly at call sites.\n//\n// See ADR-089 Phase 2d for the migration notes, the Platform route\n// rewrites in `apps/api/.../user.ts`, and the atomic grandfather\n// removal in `.dogfood-grandfather.txt`.\n\nexport type PlatformUserExportResult = ContractAuthUserExportResponse\nexport type PlatformUserDeleteInput = ContractAuthUserDeleteRequest\nexport type PlatformUserDeleteResult = ContractAuthUserDeleteResponse\n\n/**\n * `user` namespace — Platform-plane (Console / CLI) GDPR operations.\n * Backed by `/auth/platform-user/*` on the BaaS runtime (ADR-089 Phase\n * 2d). See module header for the full rationale.\n */\nexport const user = {\n\t/**\n\t * Export every piece of personal data the platform holds about the\n\t * authenticated user (GDPR Article 20 — right to data portability).\n\t *\n\t * The returned record is deliberately loose — it contains the user\n\t * row, sessions, OAuth accounts, login history, security alerts,\n\t * organization memberships, subscriptions, per-project memberships,\n\t * and storage file metadata. Shape varies with customer provisioning.\n\t *\n\t * @example\n\t * ```typescript\n\t * const data = await auth.user.exportData({\n\t * baseUrl: 'https://your-app.api.sylphx.com/v1',\n\t * accessToken: platformJwt,\n\t * })\n\t * downloadAsJson(data, 'my-sylphx-data.json')\n\t * ```\n\t */\n\tasync exportData(opts: {\n\t\treadonly baseUrl: string\n\t\treadonly accessToken: string\n\t\treadonly userAgent?: string\n\t}): Promise<PlatformUserExportResult> {\n\t\tconst res = await fetch(`${opts.baseUrl.replace(/\\/$/, '')}/auth/platform-user/export`, {\n\t\t\tmethod: 'GET',\n\t\t\theaders: buildPlatformUserHeaders(opts.accessToken, opts.userAgent),\n\t\t})\n\t\tif (!res.ok) throw await platformUserError(res, 'user.exportData')\n\t\treturn (await res.json()) as PlatformUserExportResult\n\t},\n\n\t/**\n\t * Permanently delete the authenticated user's account (GDPR Article\n\t * 17 — right to erasure). Cascades through every provisioned project\n\t * DB, cancels Stripe subscriptions, deletes S3 blobs, and anonymises\n\t * billing transactions. Emits a `user.deleted` event so downstream\n\t * systems can clean up their own state.\n\t *\n\t * Returns `{ success: true, deletedData: [...] }` on success where\n\t * `deletedData` lists the resource kinds that were erased.\n\t *\n\t * @remarks\n\t * This operation is irreversible. Production callers SHOULD require\n\t * a challenge step (2FA / password confirm / WebAuthn) before\n\t * invoking this — the BaaS route does NOT perform challenge\n\t * verification in Phase 2d. ADR-089 Phase 5.11 lands passkey-primary\n\t * with WebAuthn-required step-up and will add the check at the\n\t * BaaS boundary.\n\t *\n\t * @example\n\t * ```typescript\n\t * const result = await auth.user.deleteAccount({\n\t * baseUrl,\n\t * accessToken,\n\t * reason: 'user_request',\n\t * })\n\t * if (result.success) signOutAndRedirect('/goodbye')\n\t * ```\n\t */\n\tasync deleteAccount(opts: {\n\t\treadonly baseUrl: string\n\t\treadonly accessToken: string\n\t\treadonly reason?: string\n\t\treadonly userAgent?: string\n\t}): Promise<PlatformUserDeleteResult> {\n\t\tconst res = await fetch(`${opts.baseUrl.replace(/\\/$/, '')}/auth/platform-user/account`, {\n\t\t\tmethod: 'DELETE',\n\t\t\theaders: buildPlatformUserHeaders(opts.accessToken, opts.userAgent),\n\t\t\tbody: JSON.stringify({\n\t\t\t\t...(opts.reason !== undefined && { reason: opts.reason }),\n\t\t\t} satisfies PlatformUserDeleteInput),\n\t\t})\n\t\tif (!res.ok) throw await platformUserError(res, 'user.deleteAccount')\n\t\treturn (await res.json()) as PlatformUserDeleteResult\n\t},\n\n\t/**\n\t * Async GDPR Article 20 export job API (ADR-089 Phase 5.5).\n\t *\n\t * `user.exportData` above is the Phase 2d synchronous shortcut —\n\t * kept for backward compat but production callers SHOULD prefer the\n\t * async flow: large users routinely exceed a single HTTP deadline\n\t * during enumeration.\n\t *\n\t * Typical flow:\n\t *\n\t * ```ts\n\t * const job = await auth.user.exports.initiate({ baseUrl, accessToken })\n\t * // Poll until terminal:\n\t * while (true) {\n\t * const cur = await auth.user.exports.status({ baseUrl, accessToken, id: job.id })\n\t * if (cur.status === 'complete') break\n\t * if (cur.status === 'failed') throw new Error(cur.errorMessage ?? 'export failed')\n\t * await new Promise(r => setTimeout(r, 2000))\n\t * }\n\t * const blob = await auth.user.exports.download({ baseUrl, accessToken, id: job.id })\n\t * saveAs(blob, 'sylphx-export.json')\n\t * ```\n\t *\n\t * Rate limit: 1 `initiate` per 24h per user. Polling + downloading\n\t * are NOT rate-limited through that bucket (they're cheap reads).\n\t */\n\texports: {\n\t\t/**\n\t\t * Kick off an export job. Returns the job row in `pending` status\n\t\t * with a 202-Accepted semantic — the HTTP layer has accepted the\n\t\t * request but the payload is not yet materialized. Poll\n\t\t * `status({ id })` until `status === 'complete'`.\n\t\t */\n\t\tasync initiate(opts: {\n\t\t\treadonly baseUrl: string\n\t\t\treadonly accessToken: string\n\t\t\treadonly format?: 'json' | 'json-ld'\n\t\t\treadonly userAgent?: string\n\t\t}): Promise<DataExportJob> {\n\t\t\tconst res = await fetch(`${opts.baseUrl.replace(/\\/$/, '')}/auth/platform-user/export`, {\n\t\t\t\tmethod: 'POST',\n\t\t\t\theaders: buildPlatformUserHeaders(opts.accessToken, opts.userAgent),\n\t\t\t\tbody: JSON.stringify(opts.format !== undefined ? { format: opts.format } : {}),\n\t\t\t})\n\t\t\tif (!res.ok) throw await platformUserError(res, 'user.exports.initiate')\n\t\t\treturn (await res.json()) as DataExportJob\n\t\t},\n\n\t\t/**\n\t\t * Read the current state of an in-flight or completed export job.\n\t\t * Returns 404 (via thrown `SylphxError`) if the job id is unknown\n\t\t * OR owned by a different user — cross-user probes can't\n\t\t * distinguish the two.\n\t\t */\n\t\tasync status(opts: {\n\t\t\treadonly baseUrl: string\n\t\t\treadonly accessToken: string\n\t\t\treadonly id: string\n\t\t\treadonly userAgent?: string\n\t\t}): Promise<DataExportJob> {\n\t\t\tconst res = await fetch(\n\t\t\t\t`${opts.baseUrl.replace(/\\/$/, '')}/auth/platform-user/export/${encodeURIComponent(\n\t\t\t\t\topts.id,\n\t\t\t\t)}`,\n\t\t\t\t{\n\t\t\t\t\tmethod: 'GET',\n\t\t\t\t\theaders: buildPlatformUserHeaders(opts.accessToken, opts.userAgent),\n\t\t\t\t},\n\t\t\t)\n\t\t\tif (!res.ok) throw await platformUserError(res, 'user.exports.status')\n\t\t\treturn (await res.json()) as DataExportJob\n\t\t},\n\n\t\t/**\n\t\t * Download the completed export payload. The BaaS route returns a\n\t\t * 302 to a freshly-signed object-storage URL; we follow the redirect\n\t\t * (standard `fetch` default) and resolve to the raw `Blob`.\n\t\t *\n\t\t * The integrity headers `X-Sylphx-Export-Sha256` + `X-Sylphx-Export-Size`\n\t\t * are available on the final response — CLI consumers SHOULD verify\n\t\t * the SHA-256 client-side before handing the archive to the user.\n\t\t */\n\t\tasync download(opts: {\n\t\t\treadonly baseUrl: string\n\t\t\treadonly accessToken: string\n\t\t\treadonly id: string\n\t\t\treadonly userAgent?: string\n\t\t}): Promise<{ blob: Blob; sha256: string | null; sizeBytes: number | null }> {\n\t\t\tconst res = await fetch(\n\t\t\t\t`${opts.baseUrl.replace(/\\/$/, '')}/auth/platform-user/export/${encodeURIComponent(\n\t\t\t\t\topts.id,\n\t\t\t\t)}/download`,\n\t\t\t\t{\n\t\t\t\t\tmethod: 'GET',\n\t\t\t\t\theaders: buildPlatformUserHeaders(opts.accessToken, opts.userAgent),\n\t\t\t\t},\n\t\t\t)\n\t\t\tif (!res.ok) throw await platformUserError(res, 'user.exports.download')\n\t\t\tconst sha256 = res.headers.get('X-Sylphx-Export-Sha256')\n\t\t\tconst sizeHeader = res.headers.get('X-Sylphx-Export-Size')\n\t\t\tconst sizeBytes = sizeHeader ? Number.parseInt(sizeHeader, 10) : null\n\t\t\tconst blob = await res.blob()\n\t\t\treturn { blob, sha256, sizeBytes: Number.isFinite(sizeBytes) ? sizeBytes : null }\n\t\t},\n\t},\n} as const\n\n/**\n * Wire shape of a data-export job. `status` progresses through\n * pending → running → (complete|failed); terminal rows carry `completedAt`,\n * complete rows additionally carry `sizeBytes` + `sha256`, failed rows\n * carry `errorMessage`. `downloadUrl` is always null in this projection\n * — use `user.exports.download()` to obtain a freshly-signed URL.\n */\nexport interface DataExportJob {\n\treadonly id: string\n\treadonly status: 'pending' | 'running' | 'complete' | 'failed'\n\treadonly format: 'json' | 'json-ld'\n\treadonly requestedAt: string\n\treadonly completedAt: string | null\n\treadonly downloadUrl: string | null\n\treadonly sizeBytes: number | null\n\treadonly sha256: string | null\n\treadonly errorMessage: string | null\n}\n\nfunction buildPlatformUserHeaders(\n\taccessToken: string,\n\tuserAgent: string | undefined,\n): Record<string, string> {\n\tconst headers: Record<string, string> = {\n\t\t'Content-Type': 'application/json',\n\t\tAuthorization: `Bearer ${accessToken}`,\n\t}\n\tif (userAgent) headers['User-Agent'] = userAgent\n\treturn headers\n}\n\n/**\n * Normalise platform-user HTTP errors into `SylphxError`s with\n * meaningful codes. Mirrors `platformPasswordError` / `platformSessionError`\n * above — same 4xx/5xx treatment so Platform callers can rethrow\n * cleanly and the Platform route layer can discriminate NOT_FOUND /\n * UNAUTHORIZED / BAD_REQUEST by status code without parsing the body.\n */\nasync function platformUserError(res: Response, operation: string): Promise<Error> {\n\tconst { SylphxError } = await import('./errors')\n\tconst body = await res.text().catch(() => '')\n\tlet code = 'platform_user_error'\n\tlet message = `${operation} failed: HTTP ${res.status}`\n\ttry {\n\t\tconst parsed = JSON.parse(body) as {\n\t\t\terror?: string\n\t\t\tmessage?: string\n\t\t\terror_description?: string\n\t\t}\n\t\tif (parsed.error) code = parsed.error\n\t\tif (parsed.error_description) message = parsed.error_description\n\t\telse if (parsed.message) message = parsed.message\n\t} catch {\n\t\t// Non-JSON body — keep default message.\n\t}\n\tlet errorCode:\n\t\t| 'UNAUTHORIZED'\n\t\t| 'NOT_FOUND'\n\t\t| 'TOO_MANY_REQUESTS'\n\t\t| 'BAD_REQUEST'\n\t\t| 'INTERNAL_SERVER_ERROR'\n\tif (res.status === 401) errorCode = 'UNAUTHORIZED'\n\telse if (res.status === 404) errorCode = 'NOT_FOUND'\n\telse if (res.status === 429) errorCode = 'TOO_MANY_REQUESTS'\n\telse if (res.status >= 500) errorCode = 'INTERNAL_SERVER_ERROR'\n\telse errorCode = 'BAD_REQUEST'\n\treturn new SylphxError(message, {\n\t\tcode: errorCode,\n\t\tstatus: res.status,\n\t\tdata: { operation, code },\n\t})\n}\n\n// ============================================================================\n// Platform JWT verify + cookies + oauth mint + impersonation (ADR-089 Phase 3b)\n// ============================================================================\n//\n// Phase 3b migrates the last three Platform-plane auth bypasses\n// (middleware `verifyAccessToken` + `resolvePlatformUser`, refresh\n// endpoint `generateAccessToken`, admin `/impersonation/*` effect\n// imports) out of direct core imports and onto the BaaS plane. The\n// SDK surface below mirrors Phase 2b/c/d — `baseUrl + accessToken`\n// first-arg discipline, lazy-imported helpers, and\n// `/auth/platform-{jwt,impersonation}/*` resource prefixes.\n//\n// ## verifyAccessToken — local-first, JWKS-cached\n//\n// Hot-path auth middleware cannot afford a per-request HTTPS hop. The\n// SDK fetches JWKS ONCE per process and caches for 1h (aligned with\n// `JWK_CACHE_TTL_MS`); signature / iss / aud / exp verification runs\n// locally via `jose` on every request. On kid miss (key rotation),\n// the cache is invalidated and re-fetched. See\n// `apps/runtime/.../sdk-app.ts` for the `/.well-known/jwks.json`\n// endpoint the SDK fetches.\n//\n// ## cookies.resolvePlatformUser\n//\n// Cookie-based Platform user resolution. The caller (hot-path\n// middleware in `apps/api/.../middleware/auth.ts`) forwards the raw\n// `Cookie:` header; the BaaS `/auth/platform-sessions/whoami`\n// endpoint parses the SDK session / user cookies, verifies the JWT\n// via `verifyPlatformJWT` (core), and returns the user row. Caching\n// (30s per cookie hash) lives in module scope here — avoids hammering\n// BaaS on every SSR request while still picking up fresh user state\n// after a reasonable delay.\n//\n// ## oauth.mintAccessToken\n//\n// Platform access-token minting. The refresh handler\n// (`apps/api/.../routes/refresh.ts`) rotates a refresh token and then\n// needs a freshly-signed access JWT. Phase 3b routes this through\n// BaaS `/auth/platform-jwt/mint` rather than importing\n// `generateAccessToken` directly. Refresh is rare (once / 15min /\n// user) so the HTTPS hop cost is negligible; purity wins.\n//\n// ## impersonation.{start,end,info,active}\n//\n// Admin user impersonation — 4 endpoints on the new\n// `/auth/platform-impersonation/*` surface. Phase 3b is the minimal\n// dogfood migration; WebAuthn step-up + target-user consent land in\n// Phase 5.9 (see `// TODO: Phase 5.9` comment on the `start` handler\n// in `apps/runtime/.../platform-impersonation.ts`).\n\n// ---------------------------------------------------------------------------\n// JWKS cache — module scope\n// ---------------------------------------------------------------------------\n\ninterface JwksCache {\n\tkeys: unknown[]\n\texpiresAt: number\n}\n\nlet jwtJwksCache: JwksCache | null = null\n\n/**\n * Reset the platform-JWKS cache. Tests should call this between cases\n * to avoid state bleed. Production code relies on the TTL-based\n * expiry.\n */\nexport function resetPlatformJwksCache(): void {\n\tjwtJwksCache = null\n}\n\nconst PLATFORM_JWKS_TTL_MS = 60 * 60 * 1000 // 1 hour\n\nasync function fetchPlatformJwks(baseUrl: string): Promise<unknown[]> {\n\tconst now = Date.now()\n\tif (jwtJwksCache && jwtJwksCache.expiresAt > now) return jwtJwksCache.keys\n\n\tconst root = baseUrl.replace(/\\/$/, '').replace(/\\/v1$/, '')\n\tconst res = await fetch(`${root}/.well-known/jwks.json`)\n\tif (!res.ok) throw new Error(`JWKS fetch failed: HTTP ${res.status}`)\n\tconst data = (await res.json()) as { keys?: unknown[] }\n\tif (!Array.isArray(data.keys)) throw new Error('JWKS response missing keys[]')\n\n\tjwtJwksCache = { keys: data.keys, expiresAt: now + PLATFORM_JWKS_TTL_MS }\n\treturn data.keys\n}\n\nexport interface PlatformAccessTokenClaims {\n\treadonly sub: string\n\treadonly pid?: string\n\treadonly email: string\n\treadonly name?: string\n\treadonly picture?: string\n\treadonly email_verified: boolean\n\treadonly app_id: string\n\treadonly role: string\n\treadonly org_id?: string\n\treadonly org_slug?: string\n\treadonly org_role?: string\n\treadonly iat?: number\n\treadonly exp?: number\n}\n\n/**\n * `verifyAccessToken` — local JWT verification against cached JWKS.\n *\n * Designed for the Platform API's hot-path auth middleware: JWKS is\n * fetched once per process (1h TTL), signature/iss/aud/exp\n * verification is local `jose` — no per-request HTTPS hop.\n *\n * @example\n * ```typescript\n * const claims = await auth.verifyAccessToken(bearer, {\n * baseUrl: 'https://your-app.api.sylphx.com/v1',\n * audience: 'platform',\n * })\n * ```\n */\nexport async function verifyAccessToken(\n\ttoken: string,\n\topts: {\n\t\treadonly baseUrl: string\n\t\treadonly audience: string\n\t},\n): Promise<PlatformAccessTokenClaims> {\n\tconst { importJWK, jwtVerify, decodeProtectedHeader } = await import('jose')\n\n\tlet keys = await fetchPlatformJwks(opts.baseUrl)\n\n\t// Kid-aware selection — if the token's kid isn't in cache, invalidate\n\t// and refetch once (handles key-rotation windows).\n\tlet kid: string | undefined\n\ttry {\n\t\tkid = decodeProtectedHeader(token).kid\n\t} catch {\n\t\t// Fall through — jwtVerify below will surface the malformed error.\n\t}\n\n\tconst hasKid = (keyList: unknown[]) =>\n\t\tkeyList.some((k) => (k as { kid?: string } | null)?.kid === kid)\n\n\tif (kid && !hasKid(keys)) {\n\t\tresetPlatformJwksCache()\n\t\tkeys = await fetchPlatformJwks(opts.baseUrl)\n\t}\n\n\tlet lastError: unknown = null\n\tfor (const key of keys) {\n\t\tconst candidate = key as { kid?: string }\n\t\tif (kid && candidate.kid && candidate.kid !== kid) continue\n\t\ttry {\n\t\t\tconst jwk = await importJWK(key as Parameters<typeof importJWK>[0], 'RS256')\n\t\t\tconst { payload } = await jwtVerify(token, jwk, {\n\t\t\t\taudience: opts.audience,\n\t\t\t})\n\t\t\treturn {\n\t\t\t\tsub: payload.sub as string,\n\t\t\t\tpid: payload.pid as string | undefined,\n\t\t\t\temail: payload.email as string,\n\t\t\t\tname: payload.name as string | undefined,\n\t\t\t\tpicture: payload.picture as string | undefined,\n\t\t\t\temail_verified: Boolean(payload.email_verified),\n\t\t\t\tapp_id: payload.app_id as string,\n\t\t\t\trole: (payload.role as string) ?? 'user',\n\t\t\t\torg_id: payload.org_id as string | undefined,\n\t\t\t\torg_slug: payload.org_slug as string | undefined,\n\t\t\t\torg_role: payload.org_role as string | undefined,\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\n\t\t}\n\t}\n\n\tthrow lastError instanceof Error ? lastError : new Error('Access token verification failed')\n}\n\n// ---------------------------------------------------------------------------\n// cookies.resolvePlatformUser\n// ---------------------------------------------------------------------------\n\nexport interface PlatformUserRecord {\n\treadonly id: string\n\treadonly email: string\n\treadonly name: string | null\n\treadonly image: string | null\n\treadonly emailVerified: boolean\n\treadonly role: string\n\treadonly twoFactorEnabled: boolean\n}\n\nexport interface PlatformUserResolution {\n\treadonly user: PlatformUserRecord\n\treadonly sessionId: string\n}\n\n// 30s per-cookie cache for `resolvePlatformUser`. Hot-path middleware\n// calls this on every request; the upstream BaaS hop shouldn't run\n// more than once per user-session per 30s window. Cache is keyed on\n// the full cookie header string — any cookie change (login,\n// rotation, logout) invalidates automatically.\nconst COOKIE_RESOLVER_TTL_MS = 30 * 1000\nconst cookieResolverCache = new Map<\n\tstring,\n\t{ expiresAt: number; result: PlatformUserResolution | null }\n>()\n\nexport function resetPlatformCookieCache(): void {\n\tcookieResolverCache.clear()\n}\n\n/**\n * `cookies` namespace — Platform cookie / session resolution for the\n * Platform API's hot-path auth middleware (ADR-089 Phase 3b).\n */\nexport const cookies = {\n\t/**\n\t * Resolve a platform user from a forwarded `Cookie:` header.\n\t *\n\t * Delegates to BaaS `/auth/platform-sessions/whoami`. Caches each\n\t * unique cookie string for 30s to avoid hammering BaaS on every\n\t * SSR request.\n\t *\n\t * @example\n\t * ```typescript\n\t * const result = await auth.cookies.resolvePlatformUser({\n\t * baseUrl: 'https://your-app.api.sylphx.com/v1',\n\t * cookieHeader: req.headers.get('cookie') ?? '',\n\t * })\n\t * if (!result) // unauthenticated\n\t * ```\n\t */\n\tasync resolvePlatformUser(opts: {\n\t\treadonly baseUrl: string\n\t\treadonly cookieHeader: string\n\t\treadonly userAgent?: string\n\t}): Promise<PlatformUserResolution | null> {\n\t\tif (!opts.cookieHeader) return null\n\n\t\tconst now = Date.now()\n\t\tconst cached = cookieResolverCache.get(opts.cookieHeader)\n\t\tif (cached && cached.expiresAt > now) return cached.result\n\n\t\tconst res = await fetch(`${opts.baseUrl.replace(/\\/$/, '')}/auth/platform-sessions/whoami`, {\n\t\t\tmethod: 'GET',\n\t\t\theaders: {\n\t\t\t\tCookie: opts.cookieHeader,\n\t\t\t\t...(opts.userAgent ? { 'User-Agent': opts.userAgent } : {}),\n\t\t\t},\n\t\t})\n\n\t\tif (!res.ok) {\n\t\t\t// Cache negative result briefly to avoid hammering on persistent\n\t\t\t// 5xx; 5s window balances responsiveness against amplification.\n\t\t\tcookieResolverCache.set(opts.cookieHeader, {\n\t\t\t\tresult: null,\n\t\t\t\texpiresAt: now + 5_000,\n\t\t\t})\n\t\t\treturn null\n\t\t}\n\n\t\tconst body = (await res.json()) as PlatformUserResolution | null\n\t\tcookieResolverCache.set(opts.cookieHeader, {\n\t\t\tresult: body,\n\t\t\texpiresAt: now + COOKIE_RESOLVER_TTL_MS,\n\t\t})\n\t\treturn body\n\t},\n} as const\n\n// ---------------------------------------------------------------------------\n// oauth.mintAccessToken\n// ---------------------------------------------------------------------------\n\nexport interface MintAccessTokenClaims {\n\treadonly sub: string\n\treadonly email: string\n\treadonly name?: string\n\treadonly email_verified: boolean\n\treadonly app_id: string\n\treadonly role: string\n\treadonly org_id?: string\n\treadonly org_slug?: string\n\treadonly org_role?: string\n\treadonly picture?: string\n\treadonly pid?: string\n}\n\nexport interface MintAccessTokenResult {\n\treadonly accessToken: string\n\treadonly expiresIn: number\n}\n\n/**\n * `oauth` namespace — Platform OAuth operations backed by BaaS.\n *\n * Phase 3b adds `mintAccessToken` for the refresh handler migration;\n * Phase 5.1 layered in full authorization-server verbs\n * (`/oauth/token`, `/oauth/revoke`, `/oauth/introspect`).\n *\n * TODO(ADR-084-wave-5): migrate `exchangeAuthorizationCode` +\n * `refreshAccessToken` off raw `fetch` onto the `@sylphx/contract` schema\n * pipeline. The OAuth endpoints are new (not migrations of existing\n * `@hono/zod-openapi` routes), so they can land contract-first without\n * rippling into the other 62 hand-written SDK modules the baseline\n * tracks. Blocked on Wave 5 scoping (contract-package OAuth schemas\n * need to model the RFC 6749 error envelope + PKCE/DPoP binding — see\n * packages/contract/src/endpoints/auth.ts for the existing auth-domain\n * precedent). Until then, these two methods stay on explicit fetch().\n */\nexport const oauth = {\n\t/**\n\t * Mint a platform-audience access token from supplied claims.\n\t *\n\t * Service-to-service call — authenticated via\n\t * `SYLPHX_INTERNAL_TOKEN` shared secret. Phase 6 will migrate this\n\t * to SPIFFE SVID mTLS (ADR-068).\n\t *\n\t * TODO: Phase 6 — prefer SPIFFE SVID over shared-secret auth.\n\t *\n\t * @example\n\t * ```typescript\n\t * const { accessToken, expiresIn } = await auth.oauth.mintAccessToken({\n\t * baseUrl: 'https://your-app.api.sylphx.com/v1',\n\t * internalToken: process.env.SYLPHX_INTERNAL_TOKEN!,\n\t * claims: { sub: user.id, email: user.email, app_id: 'platform', role: 'member', email_verified: true },\n\t * })\n\t * ```\n\t */\n\tasync mintAccessToken(opts: {\n\t\treadonly baseUrl: string\n\t\treadonly internalToken: string\n\t\treadonly claims: MintAccessTokenClaims\n\t\treadonly userAgent?: string\n\t}): Promise<MintAccessTokenResult> {\n\t\tconst res = await fetch(`${opts.baseUrl.replace(/\\/$/, '')}/auth/platform-jwt/mint`, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: {\n\t\t\t\t'Content-Type': 'application/json',\n\t\t\t\tAuthorization: `Bearer ${opts.internalToken}`,\n\t\t\t\t...(opts.userAgent ? { 'User-Agent': opts.userAgent } : {}),\n\t\t\t},\n\t\t\tbody: JSON.stringify(opts.claims),\n\t\t})\n\t\tif (!res.ok) throw await platformJwtError(res, 'oauth.mintAccessToken')\n\t\treturn (await res.json()) as MintAccessTokenResult\n\t},\n\n\t/**\n\t * Exchange an OAuth 2.0 authorization_code for an access + refresh token\n\t * pair (ADR-089 Phase 5.1b — RFC 6749 §4.1.3). PKCE S256 mandatory per\n\t * OAuth 2.1 baseline.\n\t *\n\t * @example\n\t * ```typescript\n\t * const { verifier, challenge } = await generatePkce()\n\t * // user redirected to /oauth/authorize?...&code_challenge=<challenge>\n\t * // ...user approves, browser hits your redirect_uri with ?code=<code>\n\t * const tokens = await auth.oauth.exchangeAuthorizationCode({\n\t * baseUrl: 'https://api.sylphx.com/v1',\n\t * clientId: 'sylphx-console',\n\t * clientSecret: process.env.CONSOLE_CLIENT_SECRET,\n\t * code,\n\t * redirectUri: 'https://console.sylphx.com/auth/callback',\n\t * codeVerifier: verifier,\n\t * })\n\t * ```\n\t */\n\tasync exchangeAuthorizationCode(opts: {\n\t\treadonly baseUrl: string\n\t\treadonly clientId: string\n\t\treadonly clientSecret?: string\n\t\treadonly code: string\n\t\treadonly redirectUri: string\n\t\treadonly codeVerifier: string\n\t}): Promise<OAuthTokenResult> {\n\t\tconst body: Record<string, string> = {\n\t\t\tgrant_type: 'authorization_code',\n\t\t\tcode: opts.code,\n\t\t\tredirect_uri: opts.redirectUri,\n\t\t\tclient_id: opts.clientId,\n\t\t\tcode_verifier: opts.codeVerifier,\n\t\t}\n\t\tif (opts.clientSecret) body.client_secret = opts.clientSecret\n\n\t\tconst res = await fetch(`${opts.baseUrl.replace(/\\/$/, '')}/oauth/token`, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: { 'Content-Type': 'application/x-www-form-urlencoded' },\n\t\t\tbody: new URLSearchParams(body).toString(),\n\t\t})\n\t\tif (!res.ok) throw await oauthTokenError(res, 'oauth.exchangeAuthorizationCode')\n\t\treturn (await res.json()) as OAuthTokenResult\n\t},\n\n\t/**\n\t * Refresh a platform access token using a refresh_token\n\t * (ADR-089 Phase 5.1b — RFC 6749 §6). Rotation is mandatory — the\n\t * presented refresh token is consumed and a new one returned.\n\t *\n\t * @example\n\t * ```typescript\n\t * const tokens = await auth.oauth.refreshAccessToken({\n\t * baseUrl: 'https://api.sylphx.com/v1',\n\t * clientId: 'sylphx-console',\n\t * clientSecret: process.env.CONSOLE_CLIENT_SECRET,\n\t * refreshToken: stored.refresh_token,\n\t * })\n\t * ```\n\t */\n\tasync refreshAccessToken(opts: {\n\t\treadonly baseUrl: string\n\t\treadonly clientId: string\n\t\treadonly clientSecret?: string\n\t\treadonly refreshToken: string\n\t\treadonly scope?: string\n\t}): Promise<OAuthTokenResult> {\n\t\tconst body: Record<string, string> = {\n\t\t\tgrant_type: 'refresh_token',\n\t\t\trefresh_token: opts.refreshToken,\n\t\t\tclient_id: opts.clientId,\n\t\t}\n\t\tif (opts.clientSecret) body.client_secret = opts.clientSecret\n\t\tif (opts.scope) body.scope = opts.scope\n\n\t\tconst res = await fetch(`${opts.baseUrl.replace(/\\/$/, '')}/oauth/token`, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: { 'Content-Type': 'application/x-www-form-urlencoded' },\n\t\t\tbody: new URLSearchParams(body).toString(),\n\t\t})\n\t\tif (!res.ok) throw await oauthTokenError(res, 'oauth.refreshAccessToken')\n\t\treturn (await res.json()) as OAuthTokenResult\n\t},\n\n\t/**\n\t * Poll the OAuth token endpoint for a device-code grant (ADR-089 Phase\n\t * 5.1c — RFC 8628 §3.4). The preferred way to exchange an approved\n\t * device grant for tokens — returns an RFC 6749 error envelope on the\n\t * `{pending, slow_down, denied, expired}` states so callers can\n\t * distinguish precisely without parsing Phase 2a's `/auth/device/poll`\n\t * status string.\n\t *\n\t * Returns `{ ok: true, tokens }` on success or `{ ok: false, error }`\n\t * for every RFC-defined polling outcome. Callers MUST honour the\n\t * polling `interval` returned by `/auth/device` — polling faster yields\n\t * `{ ok: false, error: 'slow_down' }`.\n\t *\n\t * @example\n\t * ```typescript\n\t * while (true) {\n\t * await sleep(interval * 1000)\n\t * const r = await auth.oauth.pollDeviceToken({\n\t * baseUrl: 'https://api.sylphx.com/v1',\n\t * clientId: 'sylphx-cli',\n\t * deviceCode,\n\t * })\n\t * if (r.ok) return r.tokens\n\t * if (r.error === 'authorization_pending' || r.error === 'slow_down') continue\n\t * throw new Error(r.error) // access_denied | expired_token\n\t * }\n\t * ```\n\t */\n\tasync pollDeviceToken(opts: {\n\t\treadonly baseUrl: string\n\t\treadonly clientId: string\n\t\treadonly deviceCode: string\n\t}): Promise<OAuthPollResult> {\n\t\tconst body = new URLSearchParams({\n\t\t\tgrant_type: 'urn:ietf:params:oauth:grant-type:device_code',\n\t\t\tdevice_code: opts.deviceCode,\n\t\t\tclient_id: opts.clientId,\n\t\t}).toString()\n\t\tconst res = await fetch(`${opts.baseUrl.replace(/\\/$/, '')}/oauth/token`, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: { 'Content-Type': 'application/x-www-form-urlencoded' },\n\t\t\tbody,\n\t\t})\n\t\tif (res.ok) {\n\t\t\treturn { ok: true as const, tokens: (await res.json()) as OAuthTokenResult }\n\t\t}\n\t\t// RFC 6749 §5.2 envelope — parse `error` to distinguish polling\n\t\t// outcomes. Non-JSON bodies fall back to `oauth_error`.\n\t\tconst text = await res.text().catch(() => '')\n\t\tlet code: OAuthPollError = 'oauth_error'\n\t\ttry {\n\t\t\tconst parsed = JSON.parse(text) as { error?: string }\n\t\t\tif (parsed.error) code = parsed.error as OAuthPollError\n\t\t} catch {\n\t\t\t// Non-JSON — keep default.\n\t\t}\n\t\treturn { ok: false as const, error: code, status: res.status }\n\t},\n\n\t/**\n\t * Mint a service-principal access token via the `client_credentials`\n\t * grant (ADR-089 Phase 5.1c — RFC 6749 §4.4). Requires a confidential\n\t * client (public clients cannot use this grant). No refresh token is\n\t * issued per §4.4.3 — callers re-run this exchange on expiry.\n\t *\n\t * Typical use: CI integrations, server-to-server automation that has\n\t * no human owner and cannot run a device flow.\n\t *\n\t * @example\n\t * ```typescript\n\t * const { access_token } = await auth.oauth.clientCredentialsToken({\n\t * baseUrl: 'https://api.sylphx.com/v1',\n\t * clientId: process.env.SYLPHX_CLIENT_ID!,\n\t * clientSecret: process.env.SYLPHX_CLIENT_SECRET!,\n\t * scope: 'tenants:provision',\n\t * })\n\t * ```\n\t */\n\tasync clientCredentialsToken(opts: {\n\t\treadonly baseUrl: string\n\t\treadonly clientId: string\n\t\treadonly clientSecret: string\n\t\treadonly scope?: string\n\t}): Promise<OAuthClientCredentialsResult> {\n\t\tconst body: Record<string, string> = {\n\t\t\tgrant_type: 'client_credentials',\n\t\t\tclient_id: opts.clientId,\n\t\t\tclient_secret: opts.clientSecret,\n\t\t}\n\t\tif (opts.scope) body.scope = opts.scope\n\n\t\tconst res = await fetch(`${opts.baseUrl.replace(/\\/$/, '')}/oauth/token`, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: { 'Content-Type': 'application/x-www-form-urlencoded' },\n\t\t\tbody: new URLSearchParams(body).toString(),\n\t\t})\n\t\tif (!res.ok) throw await oauthTokenError(res, 'oauth.clientCredentialsToken')\n\t\treturn (await res.json()) as OAuthClientCredentialsResult\n\t},\n\n\t/**\n\t * Revoke an OAuth access or refresh token (RFC 7009 — ADR-089 Phase 5.1d).\n\t *\n\t * Per §2.2 this always resolves successfully — the server returns 200\n\t * whether the token existed, was already revoked, or belonged to a\n\t * different client. Only true protocol-level failures (malformed\n\t * request, bad client credentials) throw.\n\t *\n\t * @example\n\t * ```typescript\n\t * await auth.oauth.revokeToken({\n\t * baseUrl: 'https://your-app.api.sylphx.com/v1',\n\t * clientId: 'sylphx-cli',\n\t * token: refreshToken,\n\t * tokenTypeHint: 'refresh_token',\n\t * })\n\t * ```\n\t */\n\tasync revokeToken(opts: OAuthClientCallOpts): Promise<void> {\n\t\tconst res = await fetch(`${opts.baseUrl.replace(/\\/$/, '')}/oauth/revoke`, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: buildDeviceHeaders(opts.userAgent),\n\t\t\tbody: JSON.stringify({\n\t\t\t\ttoken: opts.token,\n\t\t\t\ttoken_type_hint: opts.tokenTypeHint,\n\t\t\t\tclient_id: opts.clientId,\n\t\t\t\tclient_secret: opts.clientSecret,\n\t\t\t}),\n\t\t})\n\t\tif (!res.ok) {\n\t\t\tconst body = await res.text().catch(() => '')\n\t\t\tthrow new Error(`oauth.revokeToken failed (${res.status}): ${body}`)\n\t\t}\n\t},\n\n\t/**\n\t * Introspect an OAuth access or refresh token (RFC 7662 — ADR-089 Phase 5.1d).\n\t *\n\t * Returns `{ active: false }` for expired / revoked / unknown /\n\t * not-owned tokens (without revealing which); `{ active: true, ... }`\n\t * with full claims for live ones. Only protocol-level failures\n\t * (4xx on the revocation envelope itself) throw.\n\t *\n\t * @example\n\t * ```typescript\n\t * const result = await auth.oauth.introspectToken({\n\t * baseUrl: 'https://your-app.api.sylphx.com/v1',\n\t * clientId: 'gateway',\n\t * clientSecret: process.env.GATEWAY_SECRET,\n\t * token: accessToken,\n\t * })\n\t * if (!result.active) throw new Error('token not accepted')\n\t * ```\n\t */\n\tasync introspectToken(opts: OAuthClientCallOpts): Promise<OAuthIntrospectResult> {\n\t\tconst res = await fetch(`${opts.baseUrl.replace(/\\/$/, '')}/oauth/introspect`, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: buildDeviceHeaders(opts.userAgent),\n\t\t\tbody: JSON.stringify({\n\t\t\t\ttoken: opts.token,\n\t\t\t\ttoken_type_hint: opts.tokenTypeHint,\n\t\t\t\tclient_id: opts.clientId,\n\t\t\t\tclient_secret: opts.clientSecret,\n\t\t\t}),\n\t\t})\n\t\tif (!res.ok) {\n\t\t\tconst body = await res.text().catch(() => '')\n\t\t\tthrow new Error(`oauth.introspectToken failed (${res.status}): ${body}`)\n\t\t}\n\t\treturn (await res.json()) as OAuthIntrospectResult\n\t},\n} as const\n\n// ============================================================================\n// DPoP — Demonstration of Proof-of-Possession (RFC 9449 / ADR-089 Phase 5.1e)\n// ============================================================================\n//\n// Sender-constrained access tokens. The SDK surface here is the client\n// side of the binding: generate a key-pair at login, sign a short-lived\n// proof JWT on every request, and keep the private key in\n// platform-preferred storage (IndexedDB extractable=false in browsers,\n// keychain / DPAPI in native apps).\n//\n// The proof JWT format (RFC 9449 §4):\n//\n// Header = { typ: \"dpop+jwt\", alg: \"ES256\", jwk: <public-jwk> }\n// Payload = { jti, htm, htu, iat, ath?, nonce? }\n// Signature= ECDSA / EdDSA over the above.\n//\n// `htm` + `htu` bind the proof to the current HTTP method + URL.\n// `ath` is the SHA-256 hash of the access token (only when presenting\n// the proof at a resource server, not at the AS). `jti` is a 128-bit\n// random id used by the server to detect replay.\n\n/**\n * `dpop` namespace — client-side helpers for RFC 9449 sender-constrained\n * tokens. Built on `crypto.subtle` (no new npm deps).\n *\n * @example\n * ```typescript\n * // At login:\n * const kp = await dpop.generateKeyPair()\n * // Exchange device code at /oauth/token, attaching proof:\n * const tokenProof = await dpop.generateProof({\n * privateKey: kp.privateKey,\n * publicKey: kp.publicKey,\n * method: 'POST',\n * uri: 'https://api.sylphx.com/v1/oauth/token',\n * })\n * // later, calling a resource:\n * const resProof = await dpop.generateProof({\n * privateKey: kp.privateKey,\n * publicKey: kp.publicKey,\n * method: 'GET',\n * uri: 'https://api.sylphx.com/v1/me',\n * accessToken,\n * })\n * fetch('/v1/me', {\n * headers: { Authorization: `DPoP ${accessToken}`, DPoP: resProof },\n * })\n * ```\n */\nexport const dpop = {\n\t/**\n\t * Generate a fresh ES256 key pair. Private key is non-extractable\n\t * (`extractable: false`) so it can be stored but never serialised —\n\t * the only legal operation is `sign`. Clients that need to\n\t * hibernate the keypair across restarts must use a host-provided\n\t * secure store (Keychain, Credential Manager, IndexedDB + CryptoKey\n\t * wrapping).\n\t */\n\tasync generateKeyPair(): Promise<{\n\t\treadonly privateKey: CryptoKey\n\t\treadonly publicKey: CryptoKey\n\t\treadonly thumbprint: string\n\t}> {\n\t\tconst { privateKey, publicKey } = (await crypto.subtle.generateKey(\n\t\t\t{ name: 'ECDSA', namedCurve: 'P-256' },\n\t\t\tfalse,\n\t\t\t['sign', 'verify'],\n\t\t)) as CryptoKeyPair\n\t\tconst publicJwk = await crypto.subtle.exportKey('jwk', publicKey)\n\t\tconst thumbprint = await thumbprintFromJwk(sanitisePublicJwk(publicJwk))\n\t\treturn { privateKey, publicKey, thumbprint }\n\t},\n\n\t/**\n\t * Sign a DPoP proof JWT. When `accessToken` is provided, the proof\n\t * includes `ath = base64url(sha256(accessToken))` so the resource\n\t * server can bind the proof to the token being presented (RFC 9449\n\t * §4.3 step 11).\n\t */\n\tasync generateProof(opts: {\n\t\treadonly privateKey: CryptoKey\n\t\treadonly publicKey: CryptoKey\n\t\treadonly method: string\n\t\treadonly uri: string\n\t\treadonly accessToken?: string\n\t\treadonly nonce?: string\n\t}): Promise<string> {\n\t\tconst publicJwkRaw = await crypto.subtle.exportKey('jwk', opts.publicKey)\n\t\tconst publicJwk = sanitisePublicJwk(publicJwkRaw)\n\n\t\tconst header = { typ: 'dpop+jwt', alg: 'ES256', jwk: publicJwk }\n\t\tconst payload: Record<string, unknown> = {\n\t\t\tjti: randomJti(),\n\t\t\thtm: opts.method.toUpperCase(),\n\t\t\thtu: stripQueryAndFragment(opts.uri),\n\t\t\tiat: Math.floor(Date.now() / 1000),\n\t\t}\n\t\tif (opts.accessToken) {\n\t\t\tpayload.ath = await sha256Base64Url(new TextEncoder().encode(opts.accessToken))\n\t\t}\n\t\tif (opts.nonce) payload.nonce = opts.nonce\n\n\t\tconst headerB64 = base64UrlEncode(new TextEncoder().encode(JSON.stringify(header)))\n\t\tconst payloadB64 = base64UrlEncode(new TextEncoder().encode(JSON.stringify(payload)))\n\t\tconst signingInput = `${headerB64}.${payloadB64}`\n\n\t\tconst signingBytes = new TextEncoder().encode(signingInput)\n\t\tconst signingBuf = new Uint8Array(signingBytes.byteLength)\n\t\tsigningBuf.set(signingBytes)\n\t\tconst sigBuf = await crypto.subtle.sign(\n\t\t\t{ name: 'ECDSA', hash: 'SHA-256' },\n\t\t\topts.privateKey,\n\t\t\tsigningBuf.buffer,\n\t\t)\n\t\tconst sigB64 = base64UrlEncode(new Uint8Array(sigBuf))\n\t\treturn `${signingInput}.${sigB64}`\n\t},\n} as const\n\n// DPoP internal helpers — NOT exported. Kept private because they are\n// implementation details of the two public methods above; changing them\n// must not ripple into client code.\n\nfunction sanitisePublicJwk(jwk: JsonWebKey): { kty: string; crv: string; x: string; y: string } {\n\t// crypto.subtle may emit extra fields (ext, key_ops) that RFC 7638\n\t// excludes from the canonical form. Strip everything but kty/crv/x/y\n\t// so the thumbprint is deterministic across runtimes.\n\tif (jwk.kty !== 'EC' || jwk.crv !== 'P-256' || !jwk.x || !jwk.y) {\n\t\tthrow new Error('DPoP expects ES256 (EC P-256) JWK')\n\t}\n\treturn { kty: jwk.kty, crv: jwk.crv, x: jwk.x, y: jwk.y }\n}\n\nasync function thumbprintFromJwk(jwk: {\n\tkty: string\n\tcrv: string\n\tx: string\n\ty: string\n}): Promise<string> {\n\t// RFC 7638 canonical form — lexicographic key order, no whitespace.\n\tconst canonical = JSON.stringify({ crv: jwk.crv, kty: jwk.kty, x: jwk.x, y: jwk.y })\n\treturn sha256Base64Url(new TextEncoder().encode(canonical))\n}\n\nasync function sha256Base64Url(data: Uint8Array): Promise<string> {\n\t// Copy into a fresh ArrayBuffer-backed Uint8Array so `subtle.digest`\n\t// (typed `BufferSource` where `ArrayBuffer` is strict) is satisfied\n\t// regardless of whether the input view sits on a SharedArrayBuffer.\n\tconst copy = new Uint8Array(data.byteLength)\n\tcopy.set(data)\n\tconst digest = await crypto.subtle.digest('SHA-256', copy.buffer)\n\treturn base64UrlEncode(new Uint8Array(digest))\n}\n\nfunction base64UrlEncode(bytes: Uint8Array): string {\n\tlet s = ''\n\tfor (let i = 0; i < bytes.length; i++) s += String.fromCharCode(bytes[i]!)\n\treturn btoa(s).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '')\n}\n\nfunction stripQueryAndFragment(uri: string): string {\n\ttry {\n\t\tconst u = new URL(uri)\n\t\treturn `${u.protocol}//${u.host}${u.pathname}`\n\t} catch {\n\t\tconst q = uri.indexOf('?')\n\t\tconst h = uri.indexOf('#')\n\t\tconst cut = [q, h].filter((i) => i >= 0).sort((a, b) => a - b)[0]\n\t\treturn cut === undefined ? uri : uri.slice(0, cut)\n\t}\n}\n\nfunction randomJti(): string {\n\tconst bytes = new Uint8Array(16)\n\tcrypto.getRandomValues(bytes)\n\treturn base64UrlEncode(bytes)\n}\n\n// ============================================================================\n// OAuth token-endpoint shared types (Phase 5.1b)\n// ============================================================================\n\nexport interface OAuthTokenResult {\n\treadonly access_token: string\n\treadonly token_type: 'Bearer'\n\treadonly expires_in: number\n\treadonly refresh_token: string\n\treadonly scope: string\n}\n\n/**\n * client_credentials token response (RFC 6749 §4.4.3). Distinct from\n * {@link OAuthTokenResult} because §4.4.3 forbids issuing a refresh\n * token — callers re-run the grant on expiry rather than rotating.\n */\nexport interface OAuthClientCredentialsResult {\n\treadonly access_token: string\n\treadonly token_type: 'Bearer'\n\treadonly expires_in: number\n\treadonly scope: string\n}\n\n/**\n * RFC 8628 §3.5 polling outcomes surfaced by {@link oauth.pollDeviceToken}.\n * Callers pattern-match on `error` to choose the next action:\n * - `authorization_pending` + `slow_down` — keep polling (respect interval).\n * - `access_denied` — user declined; abort.\n * - `expired_token` — grant timed out; re-run `/auth/device`.\n * - others — unexpected; surface to the user.\n */\nexport type OAuthPollError =\n\t| 'authorization_pending'\n\t| 'slow_down'\n\t| 'access_denied'\n\t| 'expired_token'\n\t| 'invalid_grant'\n\t| 'invalid_client'\n\t| 'invalid_request'\n\t| 'unauthorized_client'\n\t| 'oauth_error'\n\nexport type OAuthPollResult =\n\t| { readonly ok: true; readonly tokens: OAuthTokenResult }\n\t| { readonly ok: false; readonly error: OAuthPollError; readonly status: number }\n\nasync function oauthTokenError(res: Response, operation: string): Promise<Error> {\n\tconst { SylphxError } = await import('./errors')\n\tconst body = await res.text().catch(() => '')\n\tlet code:\n\t\t| 'invalid_client'\n\t\t| 'invalid_grant'\n\t\t| 'invalid_request'\n\t\t| 'unsupported_grant_type'\n\t\t| 'invalid_scope'\n\t\t| 'unauthorized_client'\n\t\t| 'oauth_error' = 'oauth_error'\n\tlet message = `${operation} failed: HTTP ${res.status}`\n\ttry {\n\t\tconst parsed = JSON.parse(body) as { error?: string; error_description?: string }\n\t\tif (parsed.error) code = parsed.error as typeof code\n\t\tif (parsed.error_description) message = parsed.error_description\n\t} catch {\n\t\t// Non-JSON body — keep default message.\n\t}\n\tlet errorCode: 'UNAUTHORIZED' | 'BAD_REQUEST' | 'INTERNAL_SERVER_ERROR'\n\tif (res.status === 401) errorCode = 'UNAUTHORIZED'\n\telse if (res.status >= 500) errorCode = 'INTERNAL_SERVER_ERROR'\n\telse errorCode = 'BAD_REQUEST'\n\treturn new SylphxError(message, {\n\t\tcode: errorCode,\n\t\tstatus: res.status,\n\t\tdata: { oauthError: code },\n\t})\n}\n\nasync function platformJwtError(res: Response, operation: string): Promise<Error> {\n\tconst { SylphxError } = await import('./errors')\n\tconst body = await res.text().catch(() => '')\n\tlet code = 'platform_jwt_error'\n\tlet message = `${operation} failed: HTTP ${res.status}`\n\ttry {\n\t\tconst parsed = JSON.parse(body) as {\n\t\t\terror?: string\n\t\t\tmessage?: string\n\t\t\terror_description?: string\n\t\t}\n\t\tif (parsed.error) code = parsed.error\n\t\tif (parsed.error_description) message = parsed.error_description\n\t\telse if (parsed.message) message = parsed.message\n\t} catch {\n\t\t// Non-JSON body — keep default message.\n\t}\n\tlet errorCode: 'UNAUTHORIZED' | 'BAD_REQUEST' | 'INTERNAL_SERVER_ERROR' | 'TOO_MANY_REQUESTS'\n\tif (res.status === 401) errorCode = 'UNAUTHORIZED'\n\telse if (res.status === 429) errorCode = 'TOO_MANY_REQUESTS'\n\telse if (res.status >= 500) errorCode = 'INTERNAL_SERVER_ERROR'\n\telse errorCode = 'BAD_REQUEST'\n\treturn new SylphxError(message, {\n\t\tcode: errorCode,\n\t\tstatus: res.status,\n\t\tdata: { operation, code },\n\t})\n}\n\n// ---------------------------------------------------------------------------\n// impersonation.{start,end,info,active}\n// ---------------------------------------------------------------------------\n\nexport interface ImpersonationStartResult {\n\treadonly success: true\n\treadonly token: string\n\treadonly sessionId: string\n\treadonly expiresAt: string\n}\n\nexport interface ImpersonationEndResult {\n\treadonly success: boolean\n\treadonly sessionsEnded: number\n}\n\nexport interface ImpersonationInfo {\n\treadonly isImpersonation: true\n\treadonly adminUserId: string\n\treadonly adminEmail: string\n\treadonly adminName: string | null\n\treadonly impersonatedAt: string\n}\n\nexport interface ImpersonationActive {\n\treadonly sessionId: string\n\treadonly adminUserId: string\n\treadonly adminEmail: string\n\treadonly adminName: string | null\n\treadonly targetUserId: string\n\treadonly targetEmail: string\n\treadonly targetName: string | null\n\treadonly impersonatedAt: string\n\treadonly lastActiveAt: string\n}\n\n// ---------------------------------------------------------------------------\n// Phase 5.9 — WebAuthn step-up + consent workflow\n// ---------------------------------------------------------------------------\n\nexport interface ImpersonationStartChallengeInput {\n\treadonly baseUrl: string\n\treadonly accessToken: string\n\treadonly targetUserId: string\n\treadonly reason: string\n\treadonly userAgent?: string\n}\n\nexport interface ImpersonationChallenge {\n\treadonly requestId: string\n\treadonly challengeKey: string\n\treadonly webauthnOptions: {\n\t\treadonly challenge: string\n\t\treadonly rpId?: string\n\t\treadonly allowCredentials: ReadonlyArray<{\n\t\t\treadonly id: string\n\t\t\treadonly type: 'public-key'\n\t\t\treadonly transports?: readonly string[]\n\t\t}>\n\t\treadonly userVerification: 'required'\n\t\treadonly timeout: number\n\t}\n}\n\nexport interface ImpersonationStartStepupInput {\n\treadonly baseUrl: string\n\treadonly accessToken: string\n\treadonly requestId: string\n\treadonly challengeKey: string\n\treadonly assertion: unknown\n\treadonly emergencyBypass?: boolean\n\treadonly userAgent?: string\n}\n\nexport type ImpersonationStartStepupResult =\n\t| {\n\t\t\treadonly branch: 'emergency'\n\t\t\treadonly requestId: string\n\t\t\treadonly token: string\n\t\t\treadonly sessionId: string\n\t\t\treadonly expiresAt: string\n\t }\n\t| {\n\t\t\treadonly branch: 'awaiting-consent'\n\t\t\treadonly requestId: string\n\t\t\treadonly consentDeadline: string\n\t }\n\nexport type ImpersonationConsentDecision = 'approve' | 'deny'\n\nexport type ImpersonationConsentResponse =\n\t| {\n\t\t\treadonly branch: 'approved'\n\t\t\treadonly requestId: string\n\t\t\treadonly token: string\n\t\t\treadonly sessionId: string\n\t\t\treadonly expiresAt: string\n\t }\n\t| {\n\t\t\treadonly branch: 'denied'\n\t\t\treadonly requestId: string\n\t }\n\nexport interface ImpersonationRequestRow {\n\treadonly id: string\n\treadonly operatorId: string\n\treadonly targetUserId: string\n\treadonly reason: string\n\treadonly status:\n\t\t| 'awaiting-stepup'\n\t\t| 'awaiting-consent'\n\t\t| 'active'\n\t\t| 'denied'\n\t\t| 'expired'\n\t\t| 'ended'\n\t\t| 'revoked'\n\treadonly emergencyBypass: boolean\n\treadonly sessionId: string | null\n\treadonly consentDeadline: string | null\n\treadonly startedAt: string | null\n\treadonly endedAt: string | null\n\treadonly createdAt: string\n}\n\n/**\n * `impersonation` namespace — admin user impersonation for the\n * Platform plane. Phase 3b shipped the minimal one-shot surface\n * (`start/end/info/active`); Phase 5.9 layers on WebAuthn step-up\n * (ADR-089 P15 / S27), target-user consent, notification SLO, and\n * CAEP integration via the new `startChallenge` + `startStepup` +\n * `respondConsent` + `listRequests` + `endSession` methods.\n *\n * Migration from Phase 3b → 5.9:\n * - Old `start({targetUserId})` → new two-step flow:\n * 1. `startChallenge({targetUserId, reason})` returns WebAuthn\n * options + challengeKey.\n * 2. `startStepup({requestId, challengeKey, assertion})` verifies\n * the passkey and either mints the session (emergency bypass)\n * or transitions to awaiting-consent.\n * 3. Target calls `respondConsent(id, 'approve' | 'deny')`.\n * - Old `end({sessionId})` still works (legacy). New\n * `endSession(requestId)` preferred for sessions tracked via\n * `impersonation_requests`.\n */\nexport const impersonation = {\n\tasync start(opts: {\n\t\treadonly baseUrl: string\n\t\treadonly accessToken: string\n\t\treadonly targetUserId: string\n\t\treadonly ipAddress?: string\n\t\treadonly userAgent?: string\n\t}): Promise<ImpersonationStartResult> {\n\t\tconst res = await fetch(\n\t\t\t`${opts.baseUrl.replace(/\\/$/, '')}/auth/platform-impersonation/start`,\n\t\t\t{\n\t\t\t\tmethod: 'POST',\n\t\t\t\theaders: buildImpersonationHeaders(opts.accessToken, opts.userAgent),\n\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\ttargetUserId: opts.targetUserId,\n\t\t\t\t\t...(opts.ipAddress !== undefined && { ipAddress: opts.ipAddress }),\n\t\t\t\t\t...(opts.userAgent !== undefined && { userAgent: opts.userAgent }),\n\t\t\t\t}),\n\t\t\t},\n\t\t)\n\t\tif (!res.ok) throw await impersonationError(res, 'impersonation.start')\n\t\treturn (await res.json()) as ImpersonationStartResult\n\t},\n\n\tasync end(opts: {\n\t\treadonly baseUrl: string\n\t\treadonly accessToken: string\n\t\treadonly sessionId?: string\n\t\treadonly userAgent?: string\n\t}): Promise<ImpersonationEndResult> {\n\t\tconst res = await fetch(`${opts.baseUrl.replace(/\\/$/, '')}/auth/platform-impersonation/end`, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: buildImpersonationHeaders(opts.accessToken, opts.userAgent),\n\t\t\tbody: JSON.stringify(opts.sessionId !== undefined ? { sessionId: opts.sessionId } : {}),\n\t\t})\n\t\tif (!res.ok) throw await impersonationError(res, 'impersonation.end')\n\t\treturn (await res.json()) as ImpersonationEndResult\n\t},\n\n\tasync info(opts: {\n\t\treadonly baseUrl: string\n\t\treadonly accessToken: string\n\t\treadonly sessionId: string\n\t\treadonly userAgent?: string\n\t}): Promise<ImpersonationInfo | null> {\n\t\tconst res = await fetch(\n\t\t\t`${opts.baseUrl.replace(/\\/$/, '')}/auth/platform-impersonation/info/${encodeURIComponent(opts.sessionId)}`,\n\t\t\t{\n\t\t\t\tmethod: 'GET',\n\t\t\t\theaders: buildImpersonationHeaders(opts.accessToken, opts.userAgent),\n\t\t\t},\n\t\t)\n\t\tif (!res.ok) throw await impersonationError(res, 'impersonation.info')\n\t\treturn (await res.json()) as ImpersonationInfo | null\n\t},\n\n\tasync active(opts: {\n\t\treadonly baseUrl: string\n\t\treadonly accessToken: string\n\t\treadonly userAgent?: string\n\t}): Promise<readonly ImpersonationActive[]> {\n\t\tconst res = await fetch(\n\t\t\t`${opts.baseUrl.replace(/\\/$/, '')}/auth/platform-impersonation/active`,\n\t\t\t{\n\t\t\t\tmethod: 'GET',\n\t\t\t\theaders: buildImpersonationHeaders(opts.accessToken, opts.userAgent),\n\t\t\t},\n\t\t)\n\t\tif (!res.ok) throw await impersonationError(res, 'impersonation.active')\n\t\treturn (await res.json()) as readonly ImpersonationActive[]\n\t},\n\n\t// ── Phase 5.9 ──────────────────────────────────────────────────────\n\n\t/**\n\t * Phase 5.9 step 1 of 2 — request a WebAuthn assertion challenge.\n\t * Returns the pending-request id plus options ready for\n\t * `navigator.credentials.get(...)`. Caller is expected to post the\n\t * resulting assertion to {@link impersonation.startStepup}.\n\t */\n\tasync startChallenge(opts: ImpersonationStartChallengeInput): Promise<ImpersonationChallenge> {\n\t\tconst res = await fetch(\n\t\t\t`${opts.baseUrl.replace(/\\/$/, '')}/auth/platform-impersonation/start-challenge`,\n\t\t\t{\n\t\t\t\tmethod: 'POST',\n\t\t\t\theaders: buildImpersonationHeaders(opts.accessToken, opts.userAgent),\n\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\ttargetUserId: opts.targetUserId,\n\t\t\t\t\treason: opts.reason,\n\t\t\t\t}),\n\t\t\t},\n\t\t)\n\t\tif (!res.ok) throw await impersonationError(res, 'impersonation.startChallenge')\n\t\treturn (await res.json()) as ImpersonationChallenge\n\t},\n\n\t/**\n\t * Phase 5.9 step 2 of 2 — complete the WebAuthn step-up. Returns\n\t * either the active session (emergency bypass) or the\n\t * consent deadline (regular flow). Phase 3b `start` is superseded\n\t * by this method; old callers should migrate to\n\t * `startChallenge` → `startStepup`.\n\t */\n\tasync startStepup(opts: ImpersonationStartStepupInput): Promise<ImpersonationStartStepupResult> {\n\t\tconst res = await fetch(\n\t\t\t`${opts.baseUrl.replace(/\\/$/, '')}/auth/platform-impersonation/start`,\n\t\t\t{\n\t\t\t\tmethod: 'POST',\n\t\t\t\theaders: buildImpersonationHeaders(opts.accessToken, opts.userAgent),\n\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\trequestId: opts.requestId,\n\t\t\t\t\tchallengeKey: opts.challengeKey,\n\t\t\t\t\tassertion: opts.assertion,\n\t\t\t\t\t...(opts.emergencyBypass ? { emergencyBypass: true } : {}),\n\t\t\t\t}),\n\t\t\t},\n\t\t)\n\t\tif (!res.ok) throw await impersonationError(res, 'impersonation.startStepup')\n\t\treturn (await res.json()) as ImpersonationStartStepupResult\n\t},\n\n\t/**\n\t * Target user's consent decision. Approve mints the session token;\n\t * deny transitions the request to `denied`.\n\t */\n\tasync respondConsent(opts: {\n\t\treadonly baseUrl: string\n\t\treadonly accessToken: string\n\t\treadonly requestId: string\n\t\treadonly decision: ImpersonationConsentDecision\n\t\treadonly userAgent?: string\n\t}): Promise<ImpersonationConsentResponse> {\n\t\tconst res = await fetch(\n\t\t\t`${opts.baseUrl.replace(/\\/$/, '')}/auth/impersonation-consent/${encodeURIComponent(opts.requestId)}`,\n\t\t\t{\n\t\t\t\tmethod: 'POST',\n\t\t\t\theaders: buildImpersonationHeaders(opts.accessToken, opts.userAgent),\n\t\t\t\tbody: JSON.stringify({ decision: opts.decision }),\n\t\t\t},\n\t\t)\n\t\tif (!res.ok) throw await impersonationError(res, 'impersonation.respondConsent')\n\t\treturn (await res.json()) as ImpersonationConsentResponse\n\t},\n\n\t/** List impersonation requests. Non-super_admin sees only their own. */\n\tasync listRequests(opts: {\n\t\treadonly baseUrl: string\n\t\treadonly accessToken: string\n\t\treadonly filter?: {\n\t\t\treadonly operatorId?: string\n\t\t\treadonly targetUserId?: string\n\t\t\treadonly status?: ImpersonationRequestRow['status']\n\t\t\treadonly limit?: number\n\t\t}\n\t\treadonly userAgent?: string\n\t}): Promise<readonly ImpersonationRequestRow[]> {\n\t\tconst params = new URLSearchParams()\n\t\tif (opts.filter?.operatorId) params.set('operatorId', opts.filter.operatorId)\n\t\tif (opts.filter?.targetUserId) params.set('targetUserId', opts.filter.targetUserId)\n\t\tif (opts.filter?.status) params.set('status', opts.filter.status)\n\t\tif (opts.filter?.limit != null) params.set('limit', String(opts.filter.limit))\n\t\tconst qs = params.toString()\n\t\tconst res = await fetch(\n\t\t\t`${opts.baseUrl.replace(/\\/$/, '')}/auth/platform-impersonation/requests${qs ? `?${qs}` : ''}`,\n\t\t\t{\n\t\t\t\tmethod: 'GET',\n\t\t\t\theaders: buildImpersonationHeaders(opts.accessToken, opts.userAgent),\n\t\t\t},\n\t\t)\n\t\tif (!res.ok) throw await impersonationError(res, 'impersonation.listRequests')\n\t\treturn (await res.json()) as readonly ImpersonationRequestRow[]\n\t},\n\n\t/**\n\t * End an active impersonation session by request id. Emits a CAEP\n\t * `session-revoked` event via the Phase 5.Z outbox so every in-flight\n\t * verifier invalidates the token within ≤1s.\n\t */\n\tasync endSession(opts: {\n\t\treadonly baseUrl: string\n\t\treadonly accessToken: string\n\t\treadonly requestId: string\n\t\treadonly userAgent?: string\n\t}): Promise<{ success: true; requestId: string; sessionId: string | null }> {\n\t\tconst res = await fetch(\n\t\t\t`${opts.baseUrl.replace(/\\/$/, '')}/auth/platform-impersonation/end/${encodeURIComponent(opts.requestId)}`,\n\t\t\t{\n\t\t\t\tmethod: 'POST',\n\t\t\t\theaders: buildImpersonationHeaders(opts.accessToken, opts.userAgent),\n\t\t\t},\n\t\t)\n\t\tif (!res.ok) throw await impersonationError(res, 'impersonation.endSession')\n\t\treturn (await res.json()) as { success: true; requestId: string; sessionId: string | null }\n\t},\n} as const\n\nfunction buildImpersonationHeaders(\n\taccessToken: string,\n\tuserAgent: string | undefined,\n): Record<string, string> {\n\tconst headers: Record<string, string> = {\n\t\t'Content-Type': 'application/json',\n\t\tAuthorization: `Bearer ${accessToken}`,\n\t}\n\tif (userAgent) headers['User-Agent'] = userAgent\n\treturn headers\n}\n\nasync function impersonationError(res: Response, operation: string): Promise<Error> {\n\tconst { SylphxError } = await import('./errors')\n\tconst body = await res.text().catch(() => '')\n\tlet code = 'platform_impersonation_error'\n\tlet message = `${operation} failed: HTTP ${res.status}`\n\ttry {\n\t\tconst parsed = JSON.parse(body) as {\n\t\t\terror?: string\n\t\t\tmessage?: string\n\t\t\terror_description?: string\n\t\t}\n\t\tif (parsed.error) code = parsed.error\n\t\tif (parsed.error_description) message = parsed.error_description\n\t\telse if (parsed.message) message = parsed.message\n\t} catch {\n\t\t// Non-JSON body — keep default message.\n\t}\n\tlet errorCode:\n\t\t| 'UNAUTHORIZED'\n\t\t| 'NOT_FOUND'\n\t\t| 'TOO_MANY_REQUESTS'\n\t\t| 'BAD_REQUEST'\n\t\t| 'INTERNAL_SERVER_ERROR'\n\t\t| 'CONFLICT'\n\tif (res.status === 401) errorCode = 'UNAUTHORIZED'\n\telse if (res.status === 403) errorCode = 'UNAUTHORIZED'\n\telse if (res.status === 404) errorCode = 'NOT_FOUND'\n\telse if (res.status === 409) errorCode = 'CONFLICT'\n\telse if (res.status === 429) errorCode = 'TOO_MANY_REQUESTS'\n\telse if (res.status >= 500) errorCode = 'INTERNAL_SERVER_ERROR'\n\telse errorCode = 'BAD_REQUEST'\n\treturn new SylphxError(message, {\n\t\tcode: errorCode,\n\t\tstatus: res.status,\n\t\tdata: { operation, code },\n\t})\n}\n\n// ============================================================================\n// Passkey namespace — ADR-089 Phase 5.11 / P14 + S26\n// ============================================================================\n\nexport interface PasskeySignupChallengeInput {\n\treadonly baseUrl: string\n\treadonly projectKey: string // pk_{env}_{32hex}\n\treadonly email: string\n\treadonly displayName?: string\n\treadonly orgId?: string\n}\n\nexport interface PasskeySignupChallengeResult {\n\treadonly challenge: string\n\treadonly rp: { readonly name: string; readonly id?: string }\n\treadonly user: { readonly id: string; readonly name: string; readonly displayName: string }\n\treadonly pubKeyCredParams: ReadonlyArray<{ readonly type: 'public-key'; readonly alg: number }>\n\treadonly timeout?: number\n\treadonly attestation?: string\n\treadonly authenticatorSelection?: {\n\t\treadonly authenticatorAttachment?: 'platform' | 'cross-platform'\n\t\treadonly residentKey?: 'discouraged' | 'preferred' | 'required'\n\t\treadonly userVerification?: 'discouraged' | 'preferred' | 'required'\n\t}\n\treadonly userHandle: string\n}\n\nexport interface PasskeySignupVerifyInput {\n\treadonly baseUrl: string\n\treadonly projectKey: string\n\treadonly email: string\n\treadonly userHandle: string\n\treadonly credential: unknown // RegistrationResponseJSON\n\treadonly deviceName?: string\n}\n\nexport interface PasskeySignupResult {\n\treadonly accessToken: string\n\treadonly refreshToken: string\n\treadonly expiresIn: number\n\treadonly user: {\n\t\treadonly id: string\n\t\treadonly email: string\n\t\treadonly name: string | null\n\t\treadonly role: string\n\t}\n\treadonly passkey: {\n\t\treadonly id: string\n\t\treadonly authenticatorAttachment: 'platform' | 'cross-platform' | null\n\t\treadonly backupState: boolean | null\n\t\treadonly aaguid: string | null\n\t}\n}\n\n/**\n * Thrown by `passkey.signupVerify` when the org policy rejects a\n * credential. The `policyCode` tells you which rule fired so the UI can\n * render a specific remediation prompt (\"plug in a security key\" vs\n * \"use a device-bound authenticator\").\n *\n * Shaped as a plain `Error` rather than extending `SylphxError` so the SDK\n * stays lazy-import-friendly (SylphxError is dynamic-imported per existing\n * pattern in this file).\n */\nexport class PasskeyPolicyViolationError extends Error {\n\treadonly policyCode: 'device_bound_required' | 'aaguid_not_allowed'\n\treadonly status = 403\n\tconstructor(code: 'device_bound_required' | 'aaguid_not_allowed', message: string) {\n\t\tsuper(message)\n\t\tthis.name = 'PasskeyPolicyViolationError'\n\t\tthis.policyCode = code\n\t}\n}\n\n/**\n * `passkey` namespace — passkey-primary signup + WebAuthn L3 (ADR-089 Phase 5.11).\n *\n * Two-step signup flow:\n * 1. `signupChallenge` — server mints a WebAuthn PublicKeyCredentialCreationOptions +\n * a stable `userHandle`. Caller passes these to `navigator.credentials.create(...)`.\n * 2. `signupVerify` — caller posts the attestation back. Server verifies, enforces\n * org policy (device-bound / AAGUID allow-list), creates the user atomically,\n * and returns tokens.\n *\n * New accounts created via this flow have `primaryAuthMethod='passkey'` — no password\n * is set. Use `password` namespace later if the user wants to add a recovery password.\n *\n * On `signupVerify`, a `403 policy_violation` response is surfaced as a\n * `PasskeyPolicyViolationError` carrying the structured `policyCode`.\n */\nexport const passkey = {\n\t/**\n\t * Start a passkey-first signup. Returns WebAuthn options ready for\n\t * `navigator.credentials.create()`.\n\t */\n\tasync signupChallenge(opts: PasskeySignupChallengeInput): Promise<PasskeySignupChallengeResult> {\n\t\tconst res = await fetch(`${opts.baseUrl.replace(/\\/$/, '')}/auth/passkey/signup-challenge`, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: {\n\t\t\t\t'content-type': 'application/json',\n\t\t\t\t'x-sylphx-project-key': opts.projectKey,\n\t\t\t},\n\t\t\tbody: JSON.stringify({\n\t\t\t\temail: opts.email,\n\t\t\t\tdisplayName: opts.displayName,\n\t\t\t\torgId: opts.orgId,\n\t\t\t}),\n\t\t})\n\t\tif (!res.ok) throw await passkeyError(res, 'passkey.signupChallenge')\n\t\treturn (await res.json()) as PasskeySignupChallengeResult\n\t},\n\n\t/**\n\t * Verify the attestation + create the account atomically.\n\t *\n\t * @throws PasskeyPolicyViolationError when org policy rejects the credential\n\t * (synced credential against device-bound policy, or AAGUID not on\n\t * allow-list). The structured `policyCode` tells you which.\n\t */\n\tasync signupVerify(opts: PasskeySignupVerifyInput): Promise<PasskeySignupResult> {\n\t\tconst res = await fetch(`${opts.baseUrl.replace(/\\/$/, '')}/auth/passkey/signup-verify`, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: {\n\t\t\t\t'content-type': 'application/json',\n\t\t\t\t'x-sylphx-project-key': opts.projectKey,\n\t\t\t},\n\t\t\tbody: JSON.stringify({\n\t\t\t\temail: opts.email,\n\t\t\t\tuserHandle: opts.userHandle,\n\t\t\t\tcredential: opts.credential,\n\t\t\t\tdeviceName: opts.deviceName,\n\t\t\t}),\n\t\t})\n\t\tif (!res.ok) {\n\t\t\tif (res.status === 403) {\n\t\t\t\tconst body = (await res.json().catch(() => ({}))) as {\n\t\t\t\t\terror?: string\n\t\t\t\t\tcode?: 'device_bound_required' | 'aaguid_not_allowed'\n\t\t\t\t\tmessage?: string\n\t\t\t\t}\n\t\t\t\tif (body.error === 'policy_violation' && body.code) {\n\t\t\t\t\tthrow new PasskeyPolicyViolationError(body.code, body.message ?? 'Policy violation')\n\t\t\t\t}\n\t\t\t}\n\t\t\tthrow await passkeyError(res, 'passkey.signupVerify')\n\t\t}\n\t\treturn (await res.json()) as PasskeySignupResult\n\t},\n\n\t/**\n\t * Read the current user's primary auth method. `'passkey'` means the\n\t * account was created passkey-first OR an existing account has added a\n\t * passkey (password, if any, is recovery-only).\n\t */\n\tasync getPrimaryMethod(opts: {\n\t\treadonly baseUrl: string\n\t\treadonly projectKey: string\n\t\treadonly accessToken: string\n\t}): Promise<{ readonly userId: string; readonly primaryAuthMethod: 'passkey' | 'password' }> {\n\t\tconst res = await fetch(`${opts.baseUrl.replace(/\\/$/, '')}/auth/me/primary-method`, {\n\t\t\tmethod: 'GET',\n\t\t\theaders: {\n\t\t\t\t'x-sylphx-project-key': opts.projectKey,\n\t\t\t\tauthorization: `Bearer ${opts.accessToken}`,\n\t\t\t},\n\t\t})\n\t\tif (!res.ok) throw await passkeyError(res, 'passkey.getPrimaryMethod')\n\t\treturn (await res.json()) as {\n\t\t\tuserId: string\n\t\t\tprimaryAuthMethod: 'passkey' | 'password'\n\t\t}\n\t},\n} as const\n\nasync function passkeyError(res: Response, operation: string): Promise<Error> {\n\tconst { SylphxError } = await import('./errors')\n\tconst body = (await res.json().catch(() => ({}))) as { message?: string }\n\tconst message = body.message ?? `${operation} failed (HTTP ${res.status})`\n\tlet errorCode:\n\t\t| 'UNAUTHORIZED'\n\t\t| 'NOT_FOUND'\n\t\t| 'TOO_MANY_REQUESTS'\n\t\t| 'BAD_REQUEST'\n\t\t| 'INTERNAL_SERVER_ERROR'\n\t\t| 'CONFLICT'\n\tif (res.status === 401 || res.status === 403) errorCode = 'UNAUTHORIZED'\n\telse if (res.status === 404) errorCode = 'NOT_FOUND'\n\telse if (res.status === 409) errorCode = 'CONFLICT'\n\telse if (res.status === 429) errorCode = 'TOO_MANY_REQUESTS'\n\telse if (res.status >= 500) errorCode = 'INTERNAL_SERVER_ERROR'\n\telse errorCode = 'BAD_REQUEST'\n\treturn new SylphxError(message, { code: errorCode, status: res.status, data: { operation } })\n}\n\n// ============================================================================\n// orgPolicies namespace — per-org auth policy CRUD (ADR-089 Phase 5.11 / S26)\n// ============================================================================\n\nexport interface OrgAuthPolicy {\n\treadonly orgId: string\n\treadonly requirePasskeyForSignup: boolean\n\treadonly requireDeviceBoundPasskeys: boolean\n\treadonly allowedAaguids: readonly string[]\n\treadonly updatedAt: string\n\treadonly updatedBy: string | null\n}\n\nexport interface OrgAuthPolicyUpdate {\n\treadonly requirePasskeyForSignup?: boolean\n\treadonly requireDeviceBoundPasskeys?: boolean\n\treadonly allowedAaguids?: readonly string[]\n}\n\n/**\n * `orgPolicies` namespace — read / write per-org passkey enforcement policy.\n *\n * Auth: platform-audience Bearer JWT (from Console / CLI). NOT a project SDK\n * key — this surface is for platform-owner operators configuring their own\n * orgs, not for deployed-app runtime verbs.\n */\nexport const orgPolicies = {\n\tasync get(opts: {\n\t\treadonly baseUrl: string\n\t\treadonly accessToken: string\n\t\treadonly orgId: string\n\t}): Promise<OrgAuthPolicy> {\n\t\tconst res = await fetch(`${opts.baseUrl.replace(/\\/$/, '')}/auth/orgs/${opts.orgId}/policy`, {\n\t\t\tmethod: 'GET',\n\t\t\theaders: { authorization: `Bearer ${opts.accessToken}` },\n\t\t})\n\t\tif (!res.ok) throw await passkeyError(res, 'orgPolicies.get')\n\t\treturn (await res.json()) as OrgAuthPolicy\n\t},\n\n\tasync update(opts: {\n\t\treadonly baseUrl: string\n\t\treadonly accessToken: string\n\t\treadonly orgId: string\n\t\treadonly policy: OrgAuthPolicyUpdate\n\t}): Promise<OrgAuthPolicy> {\n\t\tconst res = await fetch(`${opts.baseUrl.replace(/\\/$/, '')}/auth/orgs/${opts.orgId}/policy`, {\n\t\t\tmethod: 'PUT',\n\t\t\theaders: {\n\t\t\t\t'content-type': 'application/json',\n\t\t\t\tauthorization: `Bearer ${opts.accessToken}`,\n\t\t\t},\n\t\t\tbody: JSON.stringify(opts.policy),\n\t\t})\n\t\tif (!res.ok) throw await passkeyError(res, 'orgPolicies.update')\n\t\treturn (await res.json()) as OrgAuthPolicy\n\t},\n} as const\n","/**\n * Audit namespace — BaaS audit-log reader (ADR-089 Phase 5.3b,\n * Σ1 SoC rename).\n *\n * Scope-filtered reader for the tamper-evident audit-log chain. The\n * runtime enforces role-scoped visibility server-side so the caller\n * only needs to present their platform JWT. All filter fields are\n * optional; `limit` caps at 500 (default 100).\n *\n * Phase Σ1 SoC rename: this was previously exported out of `./auth`\n * as `audit` and spoke to `/auth/platform-audit/*`. The server-side\n * surface moved to `/v1/audit/*` (audit is a cross-cutting BaaS\n * primitive — compliance / observability — not an auth verb); this\n * SDK module mirrors the move.\n *\n * @example\n * ```typescript\n * import { audit } from '@sylphx/sdk'\n * const { events, nextCursor } = await audit.query({\n * baseUrl: 'https://your-app.api.sylphx.com/v1',\n * accessToken: platformJwt,\n * filter: { scope: 'platform-ops', limit: 200 },\n * })\n * ```\n */\n\nimport type {\n\tPlatformAuditQueryRequest as ContractPlatformAuditQueryRequest,\n\tPlatformAuditQueryResponse as ContractPlatformAuditQueryResponse,\n} from '@sylphx/contract'\n\nexport type AuditQueryFilter = ContractPlatformAuditQueryRequest\nexport type AuditQueryResult = ContractPlatformAuditQueryResponse\n\nfunction buildHeaders(accessToken: string, userAgent: string | undefined): Record<string, string> {\n\tconst headers: Record<string, string> = {\n\t\tAccept: 'application/json',\n\t\tAuthorization: `Bearer ${accessToken}`,\n\t}\n\tif (userAgent) headers['User-Agent'] = userAgent\n\treturn headers\n}\n\nasync function auditError(res: Response, operation: string): Promise<Error> {\n\tconst { SylphxError } = await import('./errors')\n\tconst body = await res.text().catch(() => '')\n\tlet code = 'audit_error'\n\tlet message = `${operation} failed: HTTP ${res.status}`\n\ttry {\n\t\tconst parsed = JSON.parse(body) as {\n\t\t\terror?: string\n\t\t\tmessage?: string\n\t\t\terror_description?: string\n\t\t}\n\t\tif (parsed.error) code = parsed.error\n\t\tif (parsed.error_description) message = parsed.error_description\n\t\telse if (parsed.message) message = parsed.message\n\t} catch {\n\t\t// Non-JSON body — keep default message.\n\t}\n\tlet errorCode:\n\t\t| 'UNAUTHORIZED'\n\t\t| 'FORBIDDEN'\n\t\t| 'TOO_MANY_REQUESTS'\n\t\t| 'BAD_REQUEST'\n\t\t| 'INTERNAL_SERVER_ERROR'\n\tif (res.status === 401) errorCode = 'UNAUTHORIZED'\n\telse if (res.status === 403) errorCode = 'FORBIDDEN'\n\telse if (res.status === 429) errorCode = 'TOO_MANY_REQUESTS'\n\telse if (res.status >= 500) errorCode = 'INTERNAL_SERVER_ERROR'\n\telse errorCode = 'BAD_REQUEST'\n\treturn new SylphxError(message, {\n\t\tcode: errorCode,\n\t\tstatus: res.status,\n\t\tdata: { operation, code },\n\t})\n}\n\nexport const audit = {\n\tasync query(opts: {\n\t\treadonly baseUrl: string\n\t\treadonly accessToken: string\n\t\treadonly filter?: AuditQueryFilter\n\t\treadonly userAgent?: string\n\t}): Promise<AuditQueryResult> {\n\t\tconst url = new URL(`${opts.baseUrl.replace(/\\/$/, '')}/audit/query`)\n\t\tconst f = opts.filter ?? {}\n\t\tif (f.scope) url.searchParams.set('scope', f.scope)\n\t\tif (f.actor) url.searchParams.set('actor', f.actor)\n\t\tif (f.resourceType) url.searchParams.set('resource_type', f.resourceType)\n\t\tif (f.resourceId) url.searchParams.set('resource_id', f.resourceId)\n\t\tif (f.action) url.searchParams.set('action', f.action)\n\t\tif (f.from) url.searchParams.set('from', f.from)\n\t\tif (f.to) url.searchParams.set('to', f.to)\n\t\tif (f.cursor) url.searchParams.set('cursor', f.cursor)\n\t\tif (f.limit !== undefined) url.searchParams.set('limit', String(f.limit))\n\n\t\tconst res = await fetch(url.toString(), {\n\t\t\tmethod: 'GET',\n\t\t\theaders: buildHeaders(opts.accessToken, opts.userAgent),\n\t\t})\n\t\tif (!res.ok) throw await auditError(res, 'audit.query')\n\t\treturn (await res.json()) as AuditQueryResult\n\t},\n} as const\n","/**\n * Rate-Limits namespace — BaaS operator surface (ADR-089 Phase 5.2,\n * Σ1 SoC rename).\n *\n * Platform operators inspect + tune rate-limit enforcement without a\n * code deploy. All write paths are role-gated server-side\n * (`rate-limits.ts` on the runtime): super_admin/admin touch any\n * scope, project admins are narrowed to their project, regular users\n * to their own user row. Scope escalation returns 403.\n *\n * Phase Σ1 SoC rename: this was previously exported out of\n * `./auth` as `rateLimits` and spoke to `/auth/platform-rate-limits/*`.\n * The server-side surface moved to `/v1/rate-limits/*` (rate-limiting\n * is a cross-cutting BaaS primitive, not an auth verb); this SDK\n * module mirrors the move.\n *\n * @example\n * ```typescript\n * import { rateLimits } from '@sylphx/sdk'\n * await rateLimits.strategies.set({\n * baseUrl: 'https://your-app.api.sylphx.com/v1',\n * accessToken: platformJwt,\n * namespace: 'login',\n * body: {\n * scope: 'project',\n * scope_id: 'proj_abc',\n * strategy: 'fixed-window',\n * limit: 50,\n * windowSeconds: 300,\n * },\n * })\n * ```\n */\n\n// Type-only imports from @sylphx/contract per ADR-084 Rule 3 — prevents\n// Effect runtime types from leaking into the published .d.ts surface.\nimport type {\n\tPlatformRateLimitStatusRequest as ContractPlatformRateLimitStatusRequest,\n\tPlatformRateLimitStatusResponse as ContractPlatformRateLimitStatusResponse,\n\tPlatformRateLimitStrategiesListRequest as ContractPlatformRateLimitStrategiesListRequest,\n\tPlatformRateLimitStrategiesListResponse as ContractPlatformRateLimitStrategiesListResponse,\n\tPlatformRateLimitStrategyDeleteRequest as ContractPlatformRateLimitStrategyDeleteRequest,\n\tPlatformRateLimitStrategyDeleteResponse as ContractPlatformRateLimitStrategyDeleteResponse,\n\tPlatformRateLimitStrategyUpsertRequest as ContractPlatformRateLimitStrategyUpsertRequest,\n\tPlatformRateLimitStrategyUpsertResponse as ContractPlatformRateLimitStrategyUpsertResponse,\n} from '@sylphx/contract'\n\nexport type RateLimitStatusFilter = ContractPlatformRateLimitStatusRequest\nexport type RateLimitStatusResult = ContractPlatformRateLimitStatusResponse\nexport type RateLimitStrategiesFilter = ContractPlatformRateLimitStrategiesListRequest\nexport type RateLimitStrategiesResult = ContractPlatformRateLimitStrategiesListResponse\nexport type RateLimitStrategyUpsertInput = ContractPlatformRateLimitStrategyUpsertRequest\nexport type RateLimitStrategyUpsertResult = ContractPlatformRateLimitStrategyUpsertResponse\nexport type RateLimitStrategyDeleteInput = ContractPlatformRateLimitStrategyDeleteRequest\nexport type RateLimitStrategyDeleteResult = ContractPlatformRateLimitStrategyDeleteResponse\n\nfunction buildHeaders(accessToken: string, userAgent: string | undefined): Record<string, string> {\n\tconst headers: Record<string, string> = {\n\t\tAccept: 'application/json',\n\t\tAuthorization: `Bearer ${accessToken}`,\n\t}\n\tif (userAgent) headers['User-Agent'] = userAgent\n\treturn headers\n}\n\nasync function rateLimitError(res: Response, operation: string): Promise<Error> {\n\tconst { SylphxError } = await import('./errors')\n\tconst body = await res.text().catch(() => '')\n\tlet code = 'rate_limit_error'\n\tlet message = `${operation} failed: HTTP ${res.status}`\n\ttry {\n\t\tconst parsed = JSON.parse(body) as {\n\t\t\terror?: string\n\t\t\tmessage?: string\n\t\t\terror_description?: string\n\t\t}\n\t\tif (parsed.error) code = parsed.error\n\t\tif (parsed.error_description) message = parsed.error_description\n\t\telse if (parsed.message) message = parsed.message\n\t} catch {\n\t\t// Non-JSON body — keep default message.\n\t}\n\tlet errorCode:\n\t\t| 'UNAUTHORIZED'\n\t\t| 'FORBIDDEN'\n\t\t| 'NOT_FOUND'\n\t\t| 'TOO_MANY_REQUESTS'\n\t\t| 'BAD_REQUEST'\n\t\t| 'INTERNAL_SERVER_ERROR'\n\tif (res.status === 401) errorCode = 'UNAUTHORIZED'\n\telse if (res.status === 403) errorCode = 'FORBIDDEN'\n\telse if (res.status === 404) errorCode = 'NOT_FOUND'\n\telse if (res.status === 429) errorCode = 'TOO_MANY_REQUESTS'\n\telse if (res.status >= 500) errorCode = 'INTERNAL_SERVER_ERROR'\n\telse errorCode = 'BAD_REQUEST'\n\treturn new SylphxError(message, {\n\t\tcode: errorCode,\n\t\tstatus: res.status,\n\t\tdata: { operation, code },\n\t})\n}\n\nexport const rateLimits = {\n\tasync status(opts: {\n\t\treadonly baseUrl: string\n\t\treadonly accessToken: string\n\t\treadonly filter?: RateLimitStatusFilter\n\t\treadonly userAgent?: string\n\t}): Promise<RateLimitStatusResult> {\n\t\tconst url = new URL(`${opts.baseUrl.replace(/\\/$/, '')}/rate-limits/status`)\n\t\tconst f = opts.filter ?? {}\n\t\tif (f.scope) url.searchParams.set('scope', f.scope)\n\t\tif (f.scope_id) url.searchParams.set('scope_id', f.scope_id)\n\t\tif (f.namespace) url.searchParams.set('namespace', f.namespace)\n\t\tconst res = await fetch(url.toString(), {\n\t\t\tmethod: 'GET',\n\t\t\theaders: buildHeaders(opts.accessToken, opts.userAgent),\n\t\t})\n\t\tif (!res.ok) throw await rateLimitError(res, 'rateLimits.status')\n\t\treturn (await res.json()) as RateLimitStatusResult\n\t},\n\n\tstrategies: {\n\t\tasync list(opts: {\n\t\t\treadonly baseUrl: string\n\t\t\treadonly accessToken: string\n\t\t\treadonly filter?: RateLimitStrategiesFilter\n\t\t\treadonly userAgent?: string\n\t\t}): Promise<RateLimitStrategiesResult> {\n\t\t\tconst url = new URL(`${opts.baseUrl.replace(/\\/$/, '')}/rate-limits/strategies`)\n\t\t\tconst f = opts.filter ?? {}\n\t\t\tif (f.scope) url.searchParams.set('scope', f.scope)\n\t\t\tif (f.scope_id) url.searchParams.set('scope_id', f.scope_id)\n\t\t\tconst res = await fetch(url.toString(), {\n\t\t\t\tmethod: 'GET',\n\t\t\t\theaders: buildHeaders(opts.accessToken, opts.userAgent),\n\t\t\t})\n\t\t\tif (!res.ok) throw await rateLimitError(res, 'rateLimits.strategies.list')\n\t\t\treturn (await res.json()) as RateLimitStrategiesResult\n\t\t},\n\n\t\tasync set(opts: {\n\t\t\treadonly baseUrl: string\n\t\t\treadonly accessToken: string\n\t\t\treadonly namespace: string\n\t\t\treadonly body: RateLimitStrategyUpsertInput\n\t\t\treadonly userAgent?: string\n\t\t}): Promise<RateLimitStrategyUpsertResult> {\n\t\t\tconst url = `${opts.baseUrl.replace(/\\/$/, '')}/rate-limits/strategies/${encodeURIComponent(opts.namespace)}`\n\t\t\tconst res = await fetch(url, {\n\t\t\t\tmethod: 'PUT',\n\t\t\t\theaders: {\n\t\t\t\t\t...buildHeaders(opts.accessToken, opts.userAgent),\n\t\t\t\t\t'content-type': 'application/json',\n\t\t\t\t},\n\t\t\t\tbody: JSON.stringify(opts.body),\n\t\t\t})\n\t\t\tif (!res.ok) throw await rateLimitError(res, 'rateLimits.strategies.set')\n\t\t\treturn (await res.json()) as RateLimitStrategyUpsertResult\n\t\t},\n\n\t\tasync delete(opts: {\n\t\t\treadonly baseUrl: string\n\t\t\treadonly accessToken: string\n\t\t\treadonly namespace: string\n\t\t\treadonly body: RateLimitStrategyDeleteInput\n\t\t\treadonly userAgent?: string\n\t\t}): Promise<RateLimitStrategyDeleteResult> {\n\t\t\tconst url = `${opts.baseUrl.replace(/\\/$/, '')}/rate-limits/strategies/${encodeURIComponent(opts.namespace)}`\n\t\t\tconst res = await fetch(url, {\n\t\t\t\tmethod: 'DELETE',\n\t\t\t\theaders: {\n\t\t\t\t\t...buildHeaders(opts.accessToken, opts.userAgent),\n\t\t\t\t\t'content-type': 'application/json',\n\t\t\t\t},\n\t\t\t\tbody: JSON.stringify(opts.body),\n\t\t\t})\n\t\t\tif (!res.ok) throw await rateLimitError(res, 'rateLimits.strategies.delete')\n\t\t\treturn (await res.json()) as RateLimitStrategyDeleteResult\n\t\t},\n\t},\n} as const\n","/**\n * Functions Admin namespace — Platform-plane function-bundle admin\n * (ADR-089 Phase 3a, Σ1 SoC rename).\n *\n * Function-bundle download for the Sylphx-internal edge-runtime\n * orchestrator. Unlike the sibling Platform namespaces this one\n * authenticates with a shared `internalToken` (cluster-internal secret)\n * rather than a platform-audience JWT, because the caller is another\n * Sylphx service (the edge-runtime that spawns V8 isolates to invoke\n * user functions) not an end user. The BaaS runtime\n * (`apps/runtime/src/server/runtime/routes/functions/admin.ts`)\n * owns the raw `@aws-sdk/client-s3` client — Platform callers\n * dogfood through this SDK surface and never touch the S3 primitive.\n *\n * Phase Σ1 SoC rename: this was previously exported out of `./auth`\n * as `functions` (re-exported at the package root as `functionsInternal`)\n * and spoke to `/auth/platform-functions/*`. The server-side surface\n * moved to `/v1/functions/admin/*` (function bundle admin is a\n * cross-cutting BaaS primitive — infrastructure storage — not an auth\n * verb); this SDK module nests the admin verbs under\n * `functions.admin.*` at the package root.\n */\n\nexport interface PlatformFunctionsDownloadBundleResult {\n\treadonly code: string\n}\n\nasync function functionsAdminError(res: Response, operation: string): Promise<Error> {\n\tconst { SylphxError } = await import('./errors')\n\tconst body = await res.text().catch(() => '')\n\tlet code = 'functions_admin_error'\n\tlet message = `${operation} failed: HTTP ${res.status}`\n\ttry {\n\t\tconst parsed = JSON.parse(body) as {\n\t\t\terror?: string\n\t\t\tmessage?: string\n\t\t\terror_description?: string\n\t\t}\n\t\tif (parsed.error) code = parsed.error\n\t\tif (parsed.error_description) message = parsed.error_description\n\t\telse if (parsed.message) message = parsed.message\n\t} catch {\n\t\t// Non-JSON body — keep default message.\n\t}\n\tlet errorCode: 'UNAUTHORIZED' | 'NOT_FOUND' | 'BAD_REQUEST' | 'INTERNAL_SERVER_ERROR'\n\tif (res.status === 401) errorCode = 'UNAUTHORIZED'\n\telse if (res.status === 404) errorCode = 'NOT_FOUND'\n\telse if (res.status >= 500) errorCode = 'INTERNAL_SERVER_ERROR'\n\telse errorCode = 'BAD_REQUEST'\n\treturn new SylphxError(message, {\n\t\tcode: errorCode,\n\t\tstatus: res.status,\n\t\tdata: { operation, code },\n\t})\n}\n\n/**\n * `functionsAdmin` namespace — Platform-plane (edge-runtime\n * orchestrator) function-bundle fetch. Re-exported at the package\n * root as part of `functions.admin.*`.\n */\nexport const functionsAdmin = {\n\t/**\n\t * Download a function bundle (UTF-8 source) by its storage key.\n\t *\n\t * The storage key is an opaque string chosen by `sylphx deploy`\n\t * when the bundle was uploaded — callers read it from the\n\t * `functions.storagePath` column after resolving a function row\n\t * by `(projectId, name)`.\n\t *\n\t * @example\n\t * ```typescript\n\t * import { functions } from '@sylphx/sdk'\n\t * const { code } = await functions.admin.downloadBundle({\n\t * baseUrl: 'https://your-app.api.sylphx.com/v1',\n\t * internalToken: process.env.SYLPHX_INTERNAL_TOKEN!,\n\t * storagePath: 'bundles/proj_abc/my-fn/v3.js',\n\t * })\n\t * ```\n\t */\n\tasync downloadBundle(opts: {\n\t\treadonly baseUrl: string\n\t\treadonly internalToken: string\n\t\treadonly storagePath: string\n\t\treadonly userAgent?: string\n\t}): Promise<PlatformFunctionsDownloadBundleResult> {\n\t\tconst res = await fetch(`${opts.baseUrl.replace(/\\/$/, '')}/functions/admin/download-bundle`, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: {\n\t\t\t\t'Content-Type': 'application/json',\n\t\t\t\tAuthorization: `Bearer ${opts.internalToken}`,\n\t\t\t\t...(opts.userAgent ? { 'User-Agent': opts.userAgent } : {}),\n\t\t\t},\n\t\t\tbody: JSON.stringify({ storagePath: opts.storagePath }),\n\t\t})\n\t\tif (!res.ok) throw await functionsAdminError(res, 'functions.admin.downloadBundle')\n\t\treturn (await res.json()) as PlatformFunctionsDownloadBundleResult\n\t},\n} as const\n","/**\n * Realtime Functions\n *\n * Pure functions for real-time messaging via Redis Streams.\n * Supports channel-based pub/sub with SSE delivery to browsers.\n *\n * @example\n * ```ts\n * import { createConfig, realtimeEmit } from '@sylphx/sdk'\n *\n * // Server: emit events to connected clients\n * const config = createConfig({ secretKey: process.env.SYLPHX_SECRET_KEY! })\n * await realtimeEmit(config, {\n * channel: 'orders',\n * event: 'order.created',\n * data: { orderId: '123', amount: 99 },\n * })\n * ```\n */\n\n// Type-only imports from @sylphx/contract per ADR-084 Rule 3 — prevents\n// Effect runtime types from leaking into the published .d.ts surface.\nimport type {\n\tRealtimeEmitInput as ContractRealtimeEmitInput,\n\tRealtimeEmitResult as ContractRealtimeEmitResult,\n} from '@sylphx/contract'\nimport { realtimeEndpoints } from '@sylphx/contract'\nimport { callApi, type SylphxConfig } from './config'\nimport type { StreamMessage } from './realtime-types'\n\n// Re-export shared types\nexport type { StreamMessage } from './realtime-types'\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface RealtimeEmitRequest {\n\t/** Channel to emit the event to */\n\tchannel: string\n\t/** Event type/name */\n\tevent: string\n\t/** Event data (any JSON-serializable value) */\n\tdata: unknown\n}\n\nexport interface RealtimeEmitResponse {\n\t/** Stream entry ID */\n\tid: string\n\t/** Channel the event was emitted to */\n\tchannel: string\n}\n\nexport interface RealtimeHistoryRequest {\n\t/** Channel to get history for */\n\tchannel: string\n\t/** Maximum number of messages to return (default: 50) */\n\tlimit?: number\n\t/** Return messages after this stream entry ID */\n\tafter?: string\n}\n\nexport interface RealtimeHistoryResponse {\n\t/** List of historical messages */\n\tmessages: StreamMessage[]\n}\n\n// ============================================================================\n// Functions\n// ============================================================================\n\n/**\n * Emit an event to a realtime channel.\n *\n * All clients subscribed to the channel (via `useRealtime` hook or SSE)\n * will receive the event instantly.\n *\n * @example\n * ```ts\n * // Notify all clients watching a document\n * await realtimeEmit(config, {\n * channel: `doc:${documentId}`,\n * event: 'doc.updated',\n * data: { updatedBy: userId, timestamp: Date.now() },\n * })\n * ```\n */\nexport async function realtimeEmit(\n\tconfig: SylphxConfig,\n\trequest: RealtimeEmitRequest,\n): Promise<RealtimeEmitResponse> {\n\t// Contract-derived path/method (SSOT per ADR-084).\n\tconst body = request satisfies ContractRealtimeEmitInput\n\tconst endpoint = realtimeEndpoints.emit\n\treturn callApi<ContractRealtimeEmitResult>(config, endpoint.path, {\n\t\tmethod: endpoint.method,\n\t\tbody,\n\t})\n}\n\n/**\n * Get historical messages from a channel.\n *\n * Useful for initializing state when a client first connects,\n * or for resuming from a known stream position.\n *\n * @example\n * ```ts\n * // Get last 20 messages when a user joins a chat\n * const { messages } = await getRealtimeHistory(config, {\n * channel: 'chat:general',\n * limit: 20,\n * })\n * ```\n */\nexport async function getRealtimeHistory(\n\tconfig: SylphxConfig,\n\trequest: RealtimeHistoryRequest,\n): Promise<RealtimeHistoryResponse> {\n\t// Contract-derived path/method (SSOT per ADR-084).\n\t// TODO ADR-084 shape reconcile: contract's `RealtimeHistoryResult.messages`\n\t// is `readonly StreamMessage[]`; SDK exposes mutable. Cast at boundary.\n\tconst endpoint = realtimeEndpoints.history\n\treturn callApi<RealtimeHistoryResponse>(config, endpoint.path, {\n\t\tmethod: endpoint.method,\n\t\tquery: {\n\t\t\tchannel: request.channel,\n\t\t\t...(request.limit !== undefined && { limit: String(request.limit) }),\n\t\t\t...(request.after !== undefined && { after: request.after }),\n\t\t},\n\t})\n}\n","/**\n * Realtime Admin namespace — Platform-plane channel-registration\n * admin (ADR-089 Phase 3a, Σ1 SoC rename).\n *\n * Channel-registration admin for the Platform plane (Console / CLI\n * operators). Like the sibling device / platform-sessions / platform-\n * password / platform-user namespaces, these endpoints accept a\n * `baseUrl + accessToken` rather than a `SylphxConfig` — the caller\n * authenticates with a platform-audience JWT, not a customer-app\n * `pk_`/`sk_` pair. The BaaS runtime\n * (`apps/runtime/src/server/runtime/routes/realtime/admin.ts`)\n * verifies the token against audience `'platform'`, confirms\n * `verifyProjectAccess(userId, projectId)`, and owns the Redis set\n * operations.\n *\n * Phase Σ1 SoC rename: this was previously exported out of `./auth`\n * as `realtime` (re-exported at the package root as `realtimeAdmin`)\n * and spoke to `/auth/platform-realtime/*`. The server-side surface\n * moved to `/v1/realtime/admin/*` (realtime admin is a cross-cutting\n * BaaS primitive, not an auth verb); this SDK module nests the admin\n * verbs under `realtime.admin.channels.*` at the package root so it\n * no longer collides with the customer-app `realtimeEmit` /\n * `getRealtimeHistory` data-plane surface.\n *\n * For the Sylphx platform itself, `baseUrl` is\n * `https://your-app.api.sylphx.com/v1` (configurable via SYLPHX_BAAS_URL\n * for dev/staging).\n */\n\nexport interface PlatformRealtimeChannel {\n\treadonly name: string\n\treadonly activeConnections: number\n\treadonly messagesPerHour: number\n\treadonly status: 'active' | 'empty'\n}\n\nexport interface PlatformRealtimeStatusResult {\n\treadonly available: boolean\n\treadonly provider: string\n}\n\nexport interface PlatformRealtimeListChannelsResult {\n\treadonly channels: readonly PlatformRealtimeChannel[]\n\treadonly count: number\n}\n\nexport interface PlatformRealtimeCreateChannelResult {\n\treadonly name: string\n}\n\nexport interface PlatformRealtimeDeleteChannelResult {\n\treadonly success: boolean\n}\n\nfunction buildHeaders(accessToken: string, userAgent: string | undefined): Record<string, string> {\n\tconst headers: Record<string, string> = {\n\t\t'Content-Type': 'application/json',\n\t\tAuthorization: `Bearer ${accessToken}`,\n\t}\n\tif (userAgent) headers['User-Agent'] = userAgent\n\treturn headers\n}\n\nasync function realtimeAdminError(res: Response, operation: string): Promise<Error> {\n\tconst { SylphxError } = await import('./errors')\n\tconst body = await res.text().catch(() => '')\n\tlet code = 'realtime_admin_error'\n\tlet message = `${operation} failed: HTTP ${res.status}`\n\ttry {\n\t\tconst parsed = JSON.parse(body) as {\n\t\t\terror?: string\n\t\t\tmessage?: string\n\t\t\terror_description?: string\n\t\t}\n\t\tif (parsed.error) code = parsed.error\n\t\tif (parsed.error_description) message = parsed.error_description\n\t\telse if (parsed.message) message = parsed.message\n\t} catch {\n\t\t// Non-JSON body — keep default message.\n\t}\n\tlet errorCode:\n\t\t| 'UNAUTHORIZED'\n\t\t| 'NOT_FOUND'\n\t\t| 'TOO_MANY_REQUESTS'\n\t\t| 'BAD_REQUEST'\n\t\t| 'INTERNAL_SERVER_ERROR'\n\t\t| 'CONFLICT'\n\tif (res.status === 401) errorCode = 'UNAUTHORIZED'\n\telse if (res.status === 403) errorCode = 'UNAUTHORIZED'\n\telse if (res.status === 404) errorCode = 'NOT_FOUND'\n\telse if (res.status === 409) errorCode = 'CONFLICT'\n\telse if (res.status === 429) errorCode = 'TOO_MANY_REQUESTS'\n\telse if (res.status >= 500) errorCode = 'INTERNAL_SERVER_ERROR'\n\telse errorCode = 'BAD_REQUEST'\n\treturn new SylphxError(message, {\n\t\tcode: errorCode,\n\t\tstatus: res.status,\n\t\tdata: { operation, code },\n\t})\n}\n\n/**\n * `realtimeAdmin` namespace — Platform-plane realtime channel-\n * registration admin. Re-exported at the package root as part of\n * `realtime.admin.*` (nested under the existing `realtime` surface in\n * `./index.ts`).\n */\nexport const realtimeAdmin = {\n\tchannels: {\n\t\t/**\n\t\t * Get realtime service status for a project.\n\t\t */\n\t\tasync status(opts: {\n\t\t\treadonly baseUrl: string\n\t\t\treadonly accessToken: string\n\t\t\treadonly projectId: string\n\t\t\treadonly userAgent?: string\n\t\t}): Promise<PlatformRealtimeStatusResult> {\n\t\t\tconst url = new URL(`${opts.baseUrl.replace(/\\/$/, '')}/realtime/admin/status`)\n\t\t\turl.searchParams.set('projectId', opts.projectId)\n\t\t\tconst res = await fetch(url.toString(), {\n\t\t\t\tmethod: 'GET',\n\t\t\t\theaders: buildHeaders(opts.accessToken, opts.userAgent),\n\t\t\t})\n\t\t\tif (!res.ok) throw await realtimeAdminError(res, 'realtime.admin.channels.status')\n\t\t\treturn (await res.json()) as PlatformRealtimeStatusResult\n\t\t},\n\n\t\t/**\n\t\t * List registered channels for a project.\n\t\t *\n\t\t * Returns an empty list when the project's hidden Redis hasn't\n\t\t * been provisioned yet — BaaS side soft-fails because absent\n\t\t * registrations are semantically equivalent to \"none registered\".\n\t\t */\n\t\tasync list(opts: {\n\t\t\treadonly baseUrl: string\n\t\t\treadonly accessToken: string\n\t\t\treadonly projectId: string\n\t\t\treadonly userAgent?: string\n\t\t}): Promise<PlatformRealtimeListChannelsResult> {\n\t\t\tconst url = new URL(`${opts.baseUrl.replace(/\\/$/, '')}/realtime/admin/channels`)\n\t\t\turl.searchParams.set('projectId', opts.projectId)\n\t\t\tconst res = await fetch(url.toString(), {\n\t\t\t\tmethod: 'GET',\n\t\t\t\theaders: buildHeaders(opts.accessToken, opts.userAgent),\n\t\t\t})\n\t\t\tif (!res.ok) throw await realtimeAdminError(res, 'realtime.admin.channels.list')\n\t\t\treturn (await res.json()) as PlatformRealtimeListChannelsResult\n\t\t},\n\n\t\t/**\n\t\t * Register a named realtime channel for a project.\n\t\t *\n\t\t * Returns 409 if already registered — registration is\n\t\t * idempotent per name.\n\t\t */\n\t\tasync create(opts: {\n\t\t\treadonly baseUrl: string\n\t\t\treadonly accessToken: string\n\t\t\treadonly projectId: string\n\t\t\treadonly name: string\n\t\t\treadonly userAgent?: string\n\t\t}): Promise<PlatformRealtimeCreateChannelResult> {\n\t\t\tconst res = await fetch(`${opts.baseUrl.replace(/\\/$/, '')}/realtime/admin/channels`, {\n\t\t\t\tmethod: 'POST',\n\t\t\t\theaders: buildHeaders(opts.accessToken, opts.userAgent),\n\t\t\t\tbody: JSON.stringify({ projectId: opts.projectId, name: opts.name }),\n\t\t\t})\n\t\t\tif (!res.ok) throw await realtimeAdminError(res, 'realtime.admin.channels.create')\n\t\t\treturn (await res.json()) as PlatformRealtimeCreateChannelResult\n\t\t},\n\n\t\t/**\n\t\t * Unregister a named realtime channel for a project. Idempotent.\n\t\t */\n\t\tasync delete(opts: {\n\t\t\treadonly baseUrl: string\n\t\t\treadonly accessToken: string\n\t\t\treadonly projectId: string\n\t\t\treadonly channelName: string\n\t\t\treadonly userAgent?: string\n\t\t}): Promise<PlatformRealtimeDeleteChannelResult> {\n\t\t\tconst url = new URL(\n\t\t\t\t`${opts.baseUrl.replace(/\\/$/, '')}/realtime/admin/channels/${encodeURIComponent(\n\t\t\t\t\topts.channelName,\n\t\t\t\t)}`,\n\t\t\t)\n\t\t\turl.searchParams.set('projectId', opts.projectId)\n\t\t\tconst res = await fetch(url.toString(), {\n\t\t\t\tmethod: 'DELETE',\n\t\t\t\theaders: buildHeaders(opts.accessToken, opts.userAgent),\n\t\t\t})\n\t\t\tif (!res.ok) throw await realtimeAdminError(res, 'realtime.admin.channels.delete')\n\t\t\treturn (await res.json()) as PlatformRealtimeDeleteChannelResult\n\t\t},\n\t},\n} as const\n","/**\n * Admin Functions — Server-side user management\n * Requires secretKey (PLATFORM_TOKEN). Never use on client-side.\n */\nimport { callApi, type SylphxConfig } from './config'\n\nexport interface AdminUser {\n\tid: string\n\temail: string\n\tname: string | null\n\timage: string | null\n\temailVerified: boolean\n\trole: string\n\tstatus: 'active' | 'suspended' | 'deleted'\n\tmetadata: Record<string, unknown> | null\n\tfirstSeenAt: string\n\tlastActiveAt: string\n\tcreatedAt: string\n}\n\nexport interface ListUsersOptions {\n\temail?: string\n\tstatus?: 'active' | 'suspended'\n\tlimit?: number\n\toffset?: number\n}\n\nexport interface ListUsersResult {\n\tusers: AdminUser[]\n\ttotal: number\n\tlimit: number\n\toffset: number\n}\n\n/**\n * List users in this project (paginated).\n * Server-side only (requires secretKey).\n *\n * @example\n * ```typescript\n * const { users, total } = await listUsers(config, { status: 'active', limit: 20 })\n * ```\n */\nexport async function listUsers(\n\tconfig: SylphxConfig,\n\topts?: ListUsersOptions,\n): Promise<ListUsersResult> {\n\tconst params = new URLSearchParams()\n\tif (opts?.email) params.set('email', opts.email)\n\tif (opts?.status) params.set('status', opts.status)\n\tif (opts?.limit) params.set('limit', String(opts.limit))\n\tif (opts?.offset) params.set('offset', String(opts.offset))\n\tconst qs = params.toString()\n\treturn callApi<ListUsersResult>(config, `/admin/users${qs ? `?${qs}` : ''}`)\n}\n\n/**\n * Get a single user by ID.\n * Server-side only (requires secretKey).\n */\nexport async function getUser(config: SylphxConfig, userId: string): Promise<AdminUser> {\n\treturn callApi<AdminUser>(config, `/admin/users/${userId}`)\n}\n\n/**\n * Look up a user by email address. Returns null if not found.\n * Server-side only (requires secretKey).\n *\n * @example\n * ```typescript\n * const user = await getUserByEmail(config, 'user@example.com')\n * if (!user) console.log('User not found')\n * ```\n */\nexport async function getUserByEmail(\n\tconfig: SylphxConfig,\n\temail: string,\n): Promise<AdminUser | null> {\n\tconst result = await listUsers(config, { email, limit: 1 })\n\treturn result.users[0] ?? null\n}\n\n/**\n * Update a user's profile fields.\n * Server-side only (requires secretKey).\n *\n * @example\n * ```typescript\n * const updated = await updateUser(config, userId, { role: 'admin', name: 'Jane' })\n * ```\n */\nexport async function updateUser(\n\tconfig: SylphxConfig,\n\tuserId: string,\n\tinput: { name?: string; metadata?: Record<string, unknown>; role?: string },\n): Promise<AdminUser> {\n\treturn callApi<AdminUser>(config, `/admin/users/${userId}`, {\n\t\tmethod: 'PUT',\n\t\tbody: input,\n\t})\n}\n\n/**\n * Update only the metadata for a user (merge-style update).\n * Server-side only (requires secretKey).\n *\n * @example\n * ```typescript\n * await updateUserMetadata(config, userId, { employeeId: 'EMP-001', department: 'Engineering' })\n * ```\n */\nexport async function updateUserMetadata(\n\tconfig: SylphxConfig,\n\tuserId: string,\n\tmetadata: Record<string, unknown>,\n): Promise<AdminUser> {\n\treturn callApi<AdminUser>(config, `/admin/users/${userId}/metadata`, {\n\t\tmethod: 'PUT',\n\t\tbody: metadata,\n\t})\n}\n\n/**\n * Suspend a user account.\n * Server-side only (requires secretKey).\n *\n * @example\n * ```typescript\n * await suspendUser(config, userId, 'Violation of terms of service')\n * ```\n */\nexport async function suspendUser(\n\tconfig: SylphxConfig,\n\tuserId: string,\n\treason?: string,\n): Promise<void> {\n\tawait callApi<void>(config, `/admin/users/${userId}/suspend`, {\n\t\tmethod: 'POST',\n\t\tbody: { reason },\n\t})\n}\n\n/**\n * Delete a user account.\n * Server-side only (requires secretKey).\n *\n * @example\n * ```typescript\n * await deleteUser(config, userId)\n * ```\n */\nexport async function deleteUser(config: SylphxConfig, userId: string): Promise<void> {\n\tawait callApi<void>(config, `/admin/users/${userId}/delete`, {\n\t\tmethod: 'POST',\n\t})\n}\n","/**\n * Analytics Functions\n *\n * Pure functions for event tracking - no hidden state.\n * Events are sent directly to the platform.\n *\n * Wire-shape types are re-exported from `@sylphx/contract` (ADR-084). The\n * contract is the single source of truth for `/analytics/track`,\n * `/analytics/identify`, `/analytics/page`, and `/analytics/batch`. SDK-\n * specific convenience shapes (`BatchEvent`) stay local since they model\n * the multi-event tracker ergonomics, not the platform wire.\n */\n\n// Type-only imports from @sylphx/contract per ADR-084 Rule 3 — prevents\n// Effect runtime types from leaking into the published .d.ts surface.\nimport type {\n\tBatchTrackInput as ContractBatchTrackInput,\n\tBatchTrackResult as ContractBatchTrackResult,\n\tConversionData as ContractConversionData,\n\tIdentifyInput as ContractIdentifyInput,\n\tPageInput as ContractPageInput,\n\tTrackEvent as ContractTrackEvent,\n\tTrackInput as ContractTrackInput,\n} from '@sylphx/contract'\nimport { analyticsEndpoints } from '@sylphx/contract'\nimport { callApi, type SylphxConfig } from './config'\n\n// ============================================================================\n// Types (re-exported from @sylphx/contract)\n// ============================================================================\n\nexport type TrackEventItem = ContractTrackEvent\nexport type BatchTrackRequest = ContractBatchTrackInput\nexport type BatchTrackResponse = ContractBatchTrackResult\nexport type ConversionData = ContractConversionData\n\n// SDK-specific types for convenience\nexport interface TrackInput {\n\t/** Event name */\n\tevent: string\n\t/** Event properties */\n\tproperties?: Record<string, unknown>\n\t/** User ID (optional, for server-side tracking) */\n\tuserId?: string\n\t/** Anonymous ID (for tracking before user signs in) */\n\tanonymousId?: string\n\t/** Timestamp (defaults to now) */\n\ttimestamp?: string\n}\n\nexport interface PageInput {\n\t/** Page name or title */\n\tname: string\n\t/** Page properties */\n\tproperties?: Record<string, unknown>\n\t/** User ID (optional) */\n\tuserId?: string\n\t/** Anonymous ID */\n\tanonymousId?: string\n}\n\nexport interface IdentifyInput {\n\t/** User ID */\n\tuserId: string\n\t/** User traits */\n\ttraits?: Record<string, unknown>\n\t/** Anonymous ID to link */\n\tanonymousId?: string\n}\n\nexport interface BatchEvent {\n\ttype: 'track' | 'page' | 'identify'\n\tevent?: string\n\tname?: string\n\tuserId?: string\n\tanonymousId?: string\n\tproperties?: Record<string, unknown>\n\ttraits?: Record<string, unknown>\n\ttimestamp?: string\n}\n\n// ============================================================================\n// Functions\n// ============================================================================\n\n/**\n * Track a custom event\n *\n * @example\n * ```typescript\n * await track(config, {\n * event: 'purchase_completed',\n * properties: { amount: 99.99, currency: 'USD' },\n * userId: 'user-123',\n * })\n * ```\n */\nexport async function track(config: SylphxConfig, input: TrackInput): Promise<void> {\n\t// Contract-derived path/method (SSOT per ADR-084).\n\tconst endpoint = analyticsEndpoints.track\n\tconst body = {\n\t\tevent: input.event,\n\t\tproperties: input.properties ?? {},\n\t\tuserId: input.userId,\n\t\tanonymousId: input.anonymousId,\n\t\ttimestamp: input.timestamp ?? new Date().toISOString(),\n\t} satisfies ContractTrackInput\n\tawait callApi(config, endpoint.path, {\n\t\tmethod: endpoint.method,\n\t\tbody,\n\t})\n}\n\n/**\n * Track a page view\n *\n * @example\n * ```typescript\n * await page(config, {\n * name: 'Home',\n * properties: { path: '/', referrer: document.referrer },\n * })\n * ```\n */\nexport async function page(config: SylphxConfig, input: PageInput): Promise<void> {\n\t// Contract-derived path/method (SSOT per ADR-084). Contract `PageInput`\n\t// now carries the optional `timestamp` field (ADR-084 Wave 2d), so the\n\t// page + track envelopes are symmetric.\n\tconst endpoint = analyticsEndpoints.page\n\tconst body = {\n\t\tname: input.name,\n\t\tproperties: input.properties ?? {},\n\t\tuserId: input.userId,\n\t\tanonymousId: input.anonymousId,\n\t} satisfies ContractPageInput\n\tawait callApi(config, endpoint.path, {\n\t\tmethod: endpoint.method,\n\t\tbody: { ...body, timestamp: new Date().toISOString() },\n\t})\n}\n\n/**\n * Identify a user with traits\n *\n * @example\n * ```typescript\n * await identify(config, {\n * userId: 'user-123',\n * traits: { email: 'user@example.com', plan: 'pro' },\n * anonymousId: 'anon-456', // Links anonymous activity to user\n * })\n * ```\n */\nexport async function identify(config: SylphxConfig, input: IdentifyInput): Promise<void> {\n\t// Contract-derived path/method (SSOT per ADR-084).\n\tconst endpoint = analyticsEndpoints.identify\n\tconst body = {\n\t\tuserId: input.userId,\n\t\ttraits: input.traits ?? {},\n\t\tanonymousId: input.anonymousId,\n\t} satisfies ContractIdentifyInput\n\tawait callApi(config, endpoint.path, {\n\t\tmethod: endpoint.method,\n\t\tbody,\n\t})\n}\n\n/**\n * Send multiple events in a single request (batch)\n *\n * @example\n * ```typescript\n * await trackBatch(config, [\n * { type: 'track', event: 'item_viewed', properties: { id: '1' } },\n * { type: 'track', event: 'item_added', properties: { id: '1' } },\n * { type: 'track', event: 'checkout_started' },\n * ])\n * ```\n */\nexport async function trackBatch(config: SylphxConfig, events: BatchEvent[]): Promise<void> {\n\t// Contract-derived path/method (SSOT per ADR-084).\n\tconst endpoint = analyticsEndpoints.batch\n\tconst body = {\n\t\tevents: events.map((e) => ({\n\t\t\tevent: e.type === 'track' ? (e.event ?? '') : e.type === 'page' ? `$pageview` : '$identify',\n\t\t\tproperties: {\n\t\t\t\t...e.properties,\n\t\t\t\t...(e.type === 'page' && e.name ? { name: e.name } : {}),\n\t\t\t\t...(e.type === 'identify' && e.traits ? { traits: e.traits } : {}),\n\t\t\t},\n\t\t\tuserId: e.userId,\n\t\t\tanonymousId: e.anonymousId,\n\t\t\ttimestamp: e.timestamp ?? new Date().toISOString(),\n\t\t})),\n\t} satisfies ContractBatchTrackInput\n\tawait callApi(config, endpoint.path, {\n\t\tmethod: endpoint.method,\n\t\tbody,\n\t})\n}\n\n// ============================================================================\n// Convenience Functions\n// ============================================================================\n\n/**\n * Generate a random anonymous ID (Segment pattern: pure UUID)\n *\n * Uses UUID v4 format without timestamp component to prevent collision risk\n * in high-traffic applications where multiple users might generate IDs at\n * the same millisecond.\n *\n * @example\n * ```typescript\n * const anonId = generateAnonymousId()\n * await track(config, { event: 'page_view', anonymousId: anonId })\n * ```\n */\nexport function generateAnonymousId(): string {\n\t// Use crypto.randomUUID if available (standard UUID v4)\n\tif (typeof crypto !== 'undefined' && crypto.randomUUID) {\n\t\treturn crypto.randomUUID()\n\t}\n\t// Fallback for older browsers: generate UUID v4 manually\n\treturn 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {\n\t\tconst r = (Math.random() * 16) | 0\n\t\tconst v = c === 'x' ? r : (r & 0x3) | 0x8\n\t\treturn v.toString(16)\n\t})\n}\n\n/**\n * Create a tracker bound to a specific config\n *\n * For convenience when making many calls with the same config.\n * This is optional - you can always use the individual functions.\n *\n * @example\n * ```typescript\n * const analytics = createTracker(config)\n *\n * // No need to pass config each time\n * analytics.track('event', { prop: 'value' })\n * analytics.page('Home')\n * analytics.identify('user-123', { email: 'user@example.com' })\n * ```\n */\nexport function createTracker(config: SylphxConfig, defaultAnonymousId?: string) {\n\tconst anonymousId = defaultAnonymousId ?? generateAnonymousId()\n\n\treturn {\n\t\ttrack: (event: string, properties?: Record<string, unknown>, userId?: string) =>\n\t\t\ttrack(config, { event, properties, userId, anonymousId }),\n\n\t\tpage: (name: string, properties?: Record<string, unknown>, userId?: string) =>\n\t\t\tpage(config, { name, properties, userId, anonymousId }),\n\n\t\tidentify: (userId: string, traits?: Record<string, unknown>) =>\n\t\t\tidentify(config, { userId, traits, anonymousId }),\n\n\t\tbatch: (events: BatchEvent[]) =>\n\t\t\ttrackBatch(\n\t\t\t\tconfig,\n\t\t\t\tevents.map((e) => ({\n\t\t\t\t\t...e,\n\t\t\t\t\tanonymousId: e.anonymousId ?? anonymousId,\n\t\t\t\t})),\n\t\t\t),\n\n\t\t/** Get the anonymous ID for this tracker */\n\t\tgetAnonymousId: () => anonymousId,\n\t}\n}\n","/**\n * AI Functions\n *\n * Pure functions for AI completions - Vercel AI SDK style.\n * Direct API calls with natural tree-shaking.\n *\n * Wire-shape types are re-exported from `@sylphx/contract` (ADR-084). The\n * contract is the single source of truth for `GET /ai/models`,\n * `/ai/usage`, `/ai/rate-limit`. Chat-completion / embedding envelopes\n * remain local to this module — they pass through the Vercel AI SDK\n * bridge and evolve independently of the platform contract.\n */\n\n// Type-only imports from @sylphx/contract per ADR-084 Rule 3 — prevents\n// Effect runtime types from leaking into the published .d.ts surface.\nimport type {\n\tAIModel as ContractAIModel,\n\tGetModelsResponse,\n\tGetRateLimitResponse,\n\tGetUsageResponse,\n} from '@sylphx/contract'\nimport { buildApiUrl, buildHeaders, type SylphxConfig } from './config'\nimport { SylphxError } from './errors'\n\n// ============================================================================\n// Types (re-exported from @sylphx/contract)\n// ============================================================================\n\nexport type AIUsageResponse = GetUsageResponse\nexport type AIRateLimitResponse = GetRateLimitResponse\nexport type AIModelsResponse = GetModelsResponse\nexport type AIModel = ContractAIModel\n\n// ============================================================================\n// SDK-specific Types (OpenAI-compatible chat format)\n// ============================================================================\n\nexport interface ChatMessage {\n\trole: 'system' | 'user' | 'assistant' | 'tool'\n\tcontent: string | ContentPart[]\n\tname?: string\n\ttool_call_id?: string\n\ttool_calls?: ToolCall[]\n\t/** Timestamp for UI display */\n\ttimestamp?: Date\n}\n\nexport interface ContentPart {\n\ttype: 'text' | 'image_url'\n\ttext?: string\n\timage_url?: { url: string; detail?: 'auto' | 'low' | 'high' }\n}\n\nexport interface ToolCall {\n\tid: string\n\ttype: 'function'\n\tfunction: { name: string; arguments: string }\n}\n\nexport interface Tool {\n\ttype: 'function'\n\tfunction: {\n\t\tname: string\n\t\tdescription?: string\n\t\tparameters?: Record<string, unknown>\n\t}\n}\n\nexport interface ChatInput {\n\t/** Model ID (e.g., 'gpt-4o', 'claude-sonnet-4-20250514') */\n\tmodel: string\n\t/** Messages */\n\tmessages: ChatMessage[]\n\t/** Temperature (0-2) */\n\ttemperature?: number\n\t/** Max tokens to generate */\n\tmaxTokens?: number\n\t/** Top P sampling */\n\ttopP?: number\n\t/** Frequency penalty */\n\tfrequencyPenalty?: number\n\t/** Presence penalty */\n\tpresencePenalty?: number\n\t/** Stop sequences */\n\tstop?: string[]\n\t/** Tools for function calling */\n\ttools?: Tool[]\n\t/** Tool choice */\n\ttoolChoice?: 'auto' | 'none' | { type: 'function'; function: { name: string } }\n}\n\nexport interface ChatResult {\n\tid: string\n\tmodel: string\n\tchoices: Array<{\n\t\tindex: number\n\t\tmessage: {\n\t\t\trole: 'assistant'\n\t\t\tcontent: string | null\n\t\t\ttool_calls?: ToolCall[]\n\t\t}\n\t\tfinishReason: 'stop' | 'length' | 'tool_calls' | 'content_filter' | null\n\t}>\n\tusage: {\n\t\tpromptTokens: number\n\t\tcompletionTokens: number\n\t\ttotalTokens: number\n\t}\n}\n\nexport interface ChatStreamChunk {\n\tid: string\n\tmodel: string\n\tchoices: Array<{\n\t\tindex: number\n\t\tdelta: {\n\t\t\trole?: 'assistant'\n\t\t\tcontent?: string\n\t\t\ttool_calls?: ToolCall[]\n\t\t}\n\t\tfinishReason: 'stop' | 'length' | 'tool_calls' | 'content_filter' | null\n\t}>\n}\n\nexport interface EmbedInput {\n\t/** Model ID (e.g., 'text-embedding-3-small') */\n\tmodel: string\n\t/** Text(s) to embed */\n\tinput: string | string[]\n\t/** Dimensions (for models that support it) */\n\tdimensions?: number\n}\n\nexport interface EmbedResult {\n\tmodel: string\n\tdata: Array<{\n\t\tindex: number\n\t\tembedding: number[]\n\t}>\n\tusage: {\n\t\tpromptTokens: number\n\t\ttotalTokens: number\n\t}\n}\n\n// ============================================================================\n// Functions\n// ============================================================================\n\n/**\n * Create a chat completion\n *\n * @example\n * ```typescript\n * const response = await chat(config, {\n * model: 'gpt-4o',\n * messages: [\n * { role: 'system', content: 'You are a helpful assistant.' },\n * { role: 'user', content: 'Hello!' },\n * ],\n * })\n *\n * console.log(response.choices[0].message.content)\n * ```\n */\nexport async function chat(config: SylphxConfig, input: ChatInput): Promise<ChatResult> {\n\tconst response = await fetch(buildApiUrl(config, '/chat/completions'), {\n\t\tmethod: 'POST',\n\t\theaders: {\n\t\t\t...buildHeaders(config),\n\t\t\tAuthorization: `Bearer ${config.secretKey}`,\n\t\t},\n\t\tbody: JSON.stringify({\n\t\t\tmodel: input.model,\n\t\t\tmessages: input.messages,\n\t\t\ttemperature: input.temperature,\n\t\t\tmax_tokens: input.maxTokens,\n\t\t\ttop_p: input.topP,\n\t\t\tfrequency_penalty: input.frequencyPenalty,\n\t\t\tpresence_penalty: input.presencePenalty,\n\t\t\tstop: input.stop,\n\t\t\ttools: input.tools,\n\t\t\ttool_choice: input.toolChoice,\n\t\t}),\n\t})\n\n\tif (!response.ok) {\n\t\tconst error = await response.json().catch(() => ({ error: { message: 'Chat request failed' } }))\n\t\tthrow new SylphxError(error?.error?.message ?? 'Chat request failed', {\n\t\t\tcode: 'BAD_REQUEST',\n\t\t})\n\t}\n\n\tconst data = await response.json()\n\n\treturn {\n\t\tid: data.id,\n\t\tmodel: data.model,\n\t\tchoices: data.choices.map((c: Record<string, unknown>) => ({\n\t\t\tindex: c.index as number,\n\t\t\tmessage: {\n\t\t\t\trole: 'assistant' as const,\n\t\t\t\tcontent: (c.message as Record<string, unknown>)?.content as string | null,\n\t\t\t\ttool_calls: (c.message as Record<string, unknown>)?.tool_calls as ToolCall[] | undefined,\n\t\t\t},\n\t\t\tfinishReason: c.finish_reason as ChatResult['choices'][0]['finishReason'],\n\t\t})),\n\t\tusage: {\n\t\t\tpromptTokens: data.usage.prompt_tokens,\n\t\t\tcompletionTokens: data.usage.completion_tokens,\n\t\t\ttotalTokens: data.usage.total_tokens,\n\t\t},\n\t}\n}\n\n/**\n * Create a streaming chat completion\n *\n * @example\n * ```typescript\n * const stream = chatStream(config, {\n * model: 'gpt-4o',\n * messages: [{ role: 'user', content: 'Write a poem' }],\n * })\n *\n * for await (const chunk of stream) {\n * process.stdout.write(chunk.choices[0].delta.content ?? '')\n * }\n * ```\n */\nexport function chatStream(config: SylphxConfig, input: ChatInput): AsyncIterable<ChatStreamChunk> {\n\treturn {\n\t\t[Symbol.asyncIterator]: async function* () {\n\t\t\tconst response = await fetch(buildApiUrl(config, '/chat/completions'), {\n\t\t\t\tmethod: 'POST',\n\t\t\t\theaders: {\n\t\t\t\t\t...buildHeaders(config),\n\t\t\t\t\tAuthorization: `Bearer ${config.secretKey}`,\n\t\t\t\t},\n\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\tmodel: input.model,\n\t\t\t\t\tmessages: input.messages,\n\t\t\t\t\ttemperature: input.temperature,\n\t\t\t\t\tmax_tokens: input.maxTokens,\n\t\t\t\t\ttop_p: input.topP,\n\t\t\t\t\tfrequency_penalty: input.frequencyPenalty,\n\t\t\t\t\tpresence_penalty: input.presencePenalty,\n\t\t\t\t\tstop: input.stop,\n\t\t\t\t\ttools: input.tools,\n\t\t\t\t\ttool_choice: input.toolChoice,\n\t\t\t\t\tstream: true,\n\t\t\t\t}),\n\t\t\t})\n\n\t\t\tif (!response.ok) {\n\t\t\t\tconst error = await response\n\t\t\t\t\t.json()\n\t\t\t\t\t.catch(() => ({ error: { message: 'Stream request failed' } }))\n\t\t\t\tthrow new SylphxError(error?.error?.message ?? 'Stream request failed', {\n\t\t\t\t\tcode: 'BAD_REQUEST',\n\t\t\t\t})\n\t\t\t}\n\n\t\t\tconst reader = response.body?.getReader()\n\t\t\tif (!reader) {\n\t\t\t\tthrow new SylphxError('No response body', {\n\t\t\t\t\tcode: 'INTERNAL_SERVER_ERROR',\n\t\t\t\t})\n\t\t\t}\n\n\t\t\tconst decoder = new TextDecoder()\n\t\t\tlet buffer = ''\n\n\t\t\ttry {\n\t\t\t\twhile (true) {\n\t\t\t\t\tconst { done, value } = await reader.read()\n\t\t\t\t\tif (done) break\n\n\t\t\t\t\tbuffer += decoder.decode(value, { stream: true })\n\t\t\t\t\tconst lines = buffer.split('\\n')\n\t\t\t\t\tbuffer = lines.pop() ?? ''\n\n\t\t\t\t\tfor (const line of lines) {\n\t\t\t\t\t\tif (line.startsWith('data: ')) {\n\t\t\t\t\t\t\tconst data = line.slice(6).trim()\n\t\t\t\t\t\t\tif (data === '[DONE]') return\n\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tconst chunk = JSON.parse(data)\n\t\t\t\t\t\t\t\tyield {\n\t\t\t\t\t\t\t\t\tid: chunk.id ?? '',\n\t\t\t\t\t\t\t\t\tmodel: chunk.model ?? input.model,\n\t\t\t\t\t\t\t\t\tchoices: (chunk.choices ?? []).map((c: Record<string, unknown>) => ({\n\t\t\t\t\t\t\t\t\t\tindex: typeof c.index === 'number' ? c.index : 0,\n\t\t\t\t\t\t\t\t\t\tdelta: {\n\t\t\t\t\t\t\t\t\t\t\trole: (c.delta as Record<string, unknown>)?.role as 'assistant' | undefined,\n\t\t\t\t\t\t\t\t\t\t\tcontent: (c.delta as Record<string, unknown>)?.content as string | undefined,\n\t\t\t\t\t\t\t\t\t\t\ttool_calls: (c.delta as Record<string, unknown>)?.tool_calls as\n\t\t\t\t\t\t\t\t\t\t\t\t| ToolCall[]\n\t\t\t\t\t\t\t\t\t\t\t\t| undefined,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\tfinishReason:\n\t\t\t\t\t\t\t\t\t\t\t(c.finish_reason as ChatStreamChunk['choices'][0]['finishReason']) ?? null,\n\t\t\t\t\t\t\t\t\t})),\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\t// Skip malformed JSON\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} finally {\n\t\t\t\treader.releaseLock()\n\t\t\t}\n\t\t},\n\t}\n}\n\n/**\n * Create embeddings\n *\n * @example\n * ```typescript\n * const result = await embed(config, {\n * model: 'text-embedding-3-small',\n * input: ['Hello world', 'Goodbye world'],\n * })\n *\n * console.log(result.data[0].embedding) // [0.123, -0.456, ...]\n * ```\n */\nexport async function embed(config: SylphxConfig, input: EmbedInput): Promise<EmbedResult> {\n\tconst response = await fetch(buildApiUrl(config, '/embeddings'), {\n\t\tmethod: 'POST',\n\t\theaders: {\n\t\t\t...buildHeaders(config),\n\t\t\tAuthorization: `Bearer ${config.secretKey}`,\n\t\t},\n\t\tbody: JSON.stringify({\n\t\t\tmodel: input.model,\n\t\t\tinput: input.input,\n\t\t\tdimensions: input.dimensions,\n\t\t}),\n\t})\n\n\tif (!response.ok) {\n\t\tconst error = await response\n\t\t\t.json()\n\t\t\t.catch(() => ({ error: { message: 'Embedding request failed' } }))\n\t\tthrow new SylphxError(error?.error?.message ?? 'Embedding request failed', {\n\t\t\tcode: 'BAD_REQUEST',\n\t\t})\n\t}\n\n\tconst data = await response.json()\n\n\treturn {\n\t\tmodel: data.model,\n\t\tdata: data.data,\n\t\tusage: {\n\t\t\tpromptTokens: data.usage.prompt_tokens,\n\t\t\ttotalTokens: data.usage.total_tokens,\n\t\t},\n\t}\n}\n\n// ============================================================================\n// Convenience Functions\n// ============================================================================\n\n/**\n * Simple text completion (convenience wrapper)\n *\n * @example\n * ```typescript\n * const text = await complete(config, 'gpt-4o', 'Explain quantum computing in one sentence.')\n * ```\n */\nexport async function complete(\n\tconfig: SylphxConfig,\n\tmodel: string,\n\tprompt: string,\n\toptions?: Omit<ChatInput, 'model' | 'messages'>,\n): Promise<string> {\n\tconst response = await chat(config, {\n\t\tmodel,\n\t\tmessages: [{ role: 'user', content: prompt }],\n\t\t...options,\n\t})\n\treturn response.choices[0]?.message.content ?? ''\n}\n\n/**\n * Stream text to string (collects all chunks)\n *\n * @example\n * ```typescript\n * const text = await streamToString(config, {\n * model: 'gpt-4o',\n * messages: [{ role: 'user', content: 'Write a haiku' }],\n * })\n * ```\n */\nexport async function streamToString(config: SylphxConfig, input: ChatInput): Promise<string> {\n\tlet result = ''\n\tfor await (const chunk of chatStream(config, input)) {\n\t\tresult += chunk.choices[0]?.delta.content ?? ''\n\t}\n\treturn result\n}\n","/**\n * Billing Functions\n *\n * Pure functions for billing and subscriptions.\n * Uses REST API at /api/sdk/billing/* for all operations.\n *\n * Wire-shape types are re-exported from `@sylphx/contract` (ADR-084). The\n * contract is the single source of truth for `GET /billing/plans`,\n * `/billing/subscription`, `POST /billing/checkout`, `/billing/portal`,\n * `GET /billing/balance`, `/billing/usage`.\n */\n\n// Type-only imports from @sylphx/contract per ADR-084 Rule 3 — prevents\n// Effect runtime types from leaking into the published .d.ts surface.\nimport type {\n\tBillingBalanceResponse,\n\tBillingCheckoutRequest,\n\tBillingCheckoutResponse,\n\tBillingPortalRequest,\n\tBillingPortalResponse,\n\tBillingUsageResponse,\n\tSdkBillingPlan,\n\tSdkBillingSubscription,\n} from '@sylphx/contract'\nimport { callApi, type SylphxConfig } from './config'\n\n// ============================================================================\n// Types (re-exported from @sylphx/contract)\n// ============================================================================\n\nexport type Plan = SdkBillingPlan\nexport type Subscription = SdkBillingSubscription\nexport type { BillingCheckoutRequest as CheckoutRequest }\nexport type { BillingCheckoutResponse as CheckoutResponse }\nexport type { BillingPortalRequest as PortalRequest }\nexport type { BillingPortalResponse as PortalResponse }\nexport type { BillingBalanceResponse as BalanceResponse }\nexport type { BillingUsageResponse as UsageResponse }\n\n// ============================================================================\n// Functions\n// ============================================================================\n\n/**\n * Get available plans\n *\n * @example\n * ```typescript\n * const plans = await getPlans(config)\n * plans.forEach(plan => console.log(plan.name, plan.monthlyPrice))\n * ```\n */\nexport async function getPlans(config: SylphxConfig): Promise<Plan[]> {\n\treturn callApi<Plan[]>(config, '/billing/plans')\n}\n\n/**\n * Get user's subscription\n *\n * @example\n * ```typescript\n * const sub = await getSubscription(config, 'user-123')\n * if (sub?.status === 'active') {\n * console.log(`Active plan: ${sub.planSlug}`)\n * }\n * ```\n */\nexport async function getSubscription(\n\tconfig: SylphxConfig,\n\tuserId: string,\n): Promise<Subscription | null> {\n\treturn callApi<Subscription | null>(config, '/billing/subscription', {\n\t\tquery: { userId },\n\t})\n}\n\n/**\n * Create a checkout session\n *\n * @example\n * ```typescript\n * const { checkoutUrl } = await createCheckout(config, {\n * userId: 'user-123',\n * planSlug: 'pro',\n * interval: 'monthly',\n * successUrl: 'https://myapp.com/success',\n * cancelUrl: 'https://myapp.com/pricing',\n * })\n *\n * window.location.href = checkoutUrl\n * ```\n */\nexport async function createCheckout(\n\tconfig: SylphxConfig,\n\tinput: BillingCheckoutRequest,\n): Promise<BillingCheckoutResponse> {\n\treturn callApi<BillingCheckoutResponse>(config, '/billing/checkout', {\n\t\tmethod: 'POST',\n\t\tbody: input,\n\t})\n}\n\n/**\n * Create a billing portal session\n *\n * @example\n * ```typescript\n * const { portalUrl } = await createPortalSession(config, {\n * userId: 'user-123',\n * returnUrl: window.location.href,\n * })\n *\n * window.location.href = portalUrl\n * ```\n */\nexport async function createPortalSession(\n\tconfig: SylphxConfig,\n\tinput: BillingPortalRequest,\n): Promise<BillingPortalResponse> {\n\treturn callApi<BillingPortalResponse>(config, '/billing/portal', {\n\t\tmethod: 'POST',\n\t\tbody: input,\n\t})\n}\n\n/**\n * Get billing balance (credits, etc.)\n *\n * @example\n * ```typescript\n * const balance = await getBillingBalance(config)\n * console.log(`Balance: ${balance.balance.currentFormatted}`)\n * ```\n */\nexport async function getBillingBalance(config: SylphxConfig): Promise<BillingBalanceResponse> {\n\treturn callApi<BillingBalanceResponse>(config, '/billing/balance')\n}\n\n/**\n * Get billing usage\n *\n * @example\n * ```typescript\n * const usage = await getBillingUsage(config, { month: '2024-01' })\n * ```\n */\nexport async function getBillingUsage(\n\tconfig: SylphxConfig,\n\toptions?: { month?: string },\n): Promise<BillingUsageResponse> {\n\treturn callApi<BillingUsageResponse>(config, '/billing/usage', {\n\t\tquery: options?.month ? { month: options.month } : undefined,\n\t})\n}\n","/**\n * Storage Functions\n *\n * Pure functions for file storage operations.\n *\n * ## Industry Patterns Implemented\n * - AbortController cancellation (Vercel Blob pattern)\n * - Exponential backoff with jitter (AWS S3 pattern: 5 retries, 1s base)\n * - Concurrent chunk uploads (Vercel pattern: 3 concurrent)\n *\n * Wire-shape types are re-exported from `@sylphx/contract` (ADR-084). The\n * contract is the single source of truth — this module only adds ergonomic\n * aliases (`StorageFile`, `UploadUrlRequest`, `UploadUrlResponse`) and local\n * convenience shapes (`FileInfo`, `FileUploadOptions`, `SignedUrlOptions`,\n * `SignedUrlResult`) that pre-date the contract and are preserved for SDK\n * surface compatibility.\n */\n\n// Type-only imports from @sylphx/contract per ADR-084 Rule 3 — prevents\n// Effect runtime types from leaking into the published .d.ts surface.\nimport type {\n\tDeleteFileResult as ContractDeleteFileResult,\n\tFileInfo as ContractFileInfo,\n\tUploadTokenInput as ContractUploadTokenInput,\n\tUploadTokenResult as ContractUploadTokenResult,\n} from '@sylphx/contract'\nimport { storageEndpoints } from '@sylphx/contract'\nimport { buildApiUrl, buildHeaders, callApi, type SylphxConfig } from './config'\nimport { BASE_RETRY_DELAY_MS, MAX_RETRY_DELAY_MS } from './constants'\nimport { SylphxError } from './errors'\n\n// Re-export types from SSOT\nexport type {\n\tUploadOptions,\n\tUploadProgressEvent,\n\tUploadResult,\n} from './lib/storage/types'\n\nimport type { UploadProgressEvent, UploadResult } from './lib/storage/types'\n\n// ============================================================================\n// Types (re-exported from @sylphx/contract)\n// ============================================================================\n\n/**\n * Wire-shape file descriptor — superset of historical SDK / OpenAPI shapes\n * (see contract `FileInfo`). For the narrower SDK-native shape used by\n * `getFileInfo()`, see the `FileInfo` interface below.\n */\nexport type StorageFile = ContractFileInfo\n/** Input for the client-direct upload token flow (Vercel Blob pattern). */\nexport type UploadUrlRequest = ContractUploadTokenInput\n/** Upload token response (supports both simple and Vercel-Blob client-upload shapes). */\nexport type UploadUrlResponse = ContractUploadTokenResult\n\n// ============================================================================\n// Upload Retry Configuration (AWS S3 Pattern)\n// ============================================================================\n\nconst UPLOAD_RETRY_CONFIG = {\n\t/** Maximum number of retry attempts (AWS S3 pattern) */\n\tmaxRetries: 5,\n\t/** Base delay in milliseconds */\n\tbaseDelayMs: BASE_RETRY_DELAY_MS,\n\t/** Maximum delay cap in milliseconds */\n\tmaxDelayMs: MAX_RETRY_DELAY_MS,\n\t/** Jitter type: 'full' for full jitter (AWS recommended) */\n\tjitter: 'full' as const,\n}\n\n/**\n * Calculate exponential backoff delay with full jitter (AWS pattern)\n * Formula: random(0, min(cap, base * 2 ^ attempt))\n */\nfunction calculateBackoffDelay(attempt: number): number {\n\tconst { baseDelayMs, maxDelayMs } = UPLOAD_RETRY_CONFIG\n\tconst exponentialDelay = baseDelayMs * 2 ** attempt\n\tconst cappedDelay = Math.min(exponentialDelay, maxDelayMs)\n\t// Full jitter: random value between 0 and cappedDelay\n\treturn Math.random() * cappedDelay\n}\n\n/**\n * Sleep for a specified duration, respecting AbortSignal\n */\nasync function sleep(ms: number, signal?: AbortSignal): Promise<void> {\n\treturn new Promise((resolve, reject) => {\n\t\tif (signal?.aborted) {\n\t\t\treject(new DOMException('Upload aborted', 'AbortError'))\n\t\t\treturn\n\t\t}\n\n\t\tconst timeoutId = setTimeout(resolve, ms)\n\n\t\tsignal?.addEventListener(\n\t\t\t'abort',\n\t\t\t() => {\n\t\t\t\tclearTimeout(timeoutId)\n\t\t\t\treject(new DOMException('Upload aborted', 'AbortError'))\n\t\t\t},\n\t\t\t{ once: true },\n\t\t)\n\t})\n}\n\n/**\n * Check if an error is retryable (network errors, 5xx, 429)\n */\nfunction isRetryableError(error: unknown): boolean {\n\tif (error instanceof DOMException && error.name === 'AbortError') {\n\t\treturn false // Never retry aborted requests\n\t}\n\tif (error instanceof TypeError) {\n\t\treturn true // Network errors\n\t}\n\tif (error instanceof Error && 'status' in error) {\n\t\tconst status = (error as { status: number }).status\n\t\treturn status >= 500 || status === 429 // Server errors or rate limiting\n\t}\n\treturn false\n}\n\n// ============================================================================\n// Types (SDK-specific)\n// ============================================================================\n\nexport interface FileUploadOptions {\n\t/** Folder path */\n\tpath?: string\n\t/** File type (file, avatar, etc.) */\n\ttype?: 'file' | 'avatar'\n\t/** User ID (for avatar uploads) */\n\tuserId?: string\n\t/** Progress callback */\n\tonProgress?: (event: UploadProgressEvent) => void\n\t/**\n\t * Enable multipart upload for large files.\n\t * - `true`: Always use multipart upload\n\t * - `false`: Never use multipart upload\n\t * - `'auto'` (default): Auto-enable for files > 5MB\n\t *\n\t * Multipart uploads support files up to 5TB with better\n\t * reliability for large files.\n\t */\n\tmultipart?: boolean | 'auto'\n\t/**\n\t * AbortSignal to cancel the upload.\n\t * Vercel Blob pattern - enables cancellation of in-progress uploads.\n\t *\n\t * @example\n\t * ```typescript\n\t * const controller = new AbortController()\n\t * // Cancel after 30 seconds\n\t * setTimeout(() => controller.abort(), 30000)\n\t * await uploadFile(config, file, { signal: controller.signal })\n\t * ```\n\t */\n\tsignal?: AbortSignal\n\t/**\n\t * Idempotency key for safe retries (Stripe pattern)\n\t *\n\t * Prevents duplicate uploads if the same request is retried.\n\t * Use a unique key per logical upload operation.\n\t *\n\t * @example `upload-${userId}-${fileName}-${fileHash}`\n\t */\n\tidempotencyKey?: string\n}\n\nexport interface FileInfo {\n\tid: string\n\turl: string\n\tname: string\n\tsize: number\n\tcontentType: string\n\tisPrivate: boolean\n\tcreatedAt: string\n}\n\nexport interface SignedUrlOptions {\n\t/** Expiration in seconds (default: 3600, max: 604800 = 7 days) */\n\texpiresIn?: number\n\t/** Force download (attachment) vs inline display (default: attachment) */\n\tdisposition?: 'attachment' | 'inline'\n\t/** Restrict access to specific user */\n\tuserId?: string\n}\n\nexport interface SignedUrlResult {\n\t/** The signed download URL */\n\turl: string\n\t/** When the URL expires (ISO string) */\n\texpiresAt: string\n\t/** File metadata */\n\tfile: {\n\t\tid: string\n\t\tfilename: string\n\t\tmimeType: string\n\t\tsizeBytes: number\n\t\tisPrivate: boolean\n\t}\n}\n\n// ============================================================================\n// Functions\n// ============================================================================\n\n/**\n * Upload a file to storage\n *\n * Uses client-side upload for optimal performance (direct to CDN).\n *\n * ## Industry-Standard Features\n * - **Cancellation**: AbortController support (Vercel Blob pattern)\n * - **Retry**: Exponential backoff with jitter (AWS S3 pattern: 5 retries)\n * - **Progress**: Real-time upload progress tracking\n *\n * ## File Size Limits\n * - Standard uploads: up to 500MB\n * - For files > 500MB: use React hooks with `multipart: true` (supports up to 5TB)\n *\n * ## Multipart Uploads\n * For large files (> 5MB), multipart uploads provide:\n * - Better reliability with chunked uploads\n * - Resumable upload capability\n * - Progress tracking per chunk\n *\n * Use the `multipart` option or React hooks for large files:\n * ```typescript\n * // React hooks (recommended for large files)\n * const { upload } = useStorage()\n * await upload(file, { multipart: true })\n * ```\n *\n * @example\n * ```typescript\n * const file = new File(['Hello'], 'hello.txt', { type: 'text/plain' })\n * const result = await uploadFile(config, file, {\n * path: 'documents',\n * onProgress: (e) => console.log(`${e.progress}%`),\n * })\n *\n * console.log(result.url)\n * ```\n *\n * @example Cancellation\n * ```typescript\n * const controller = new AbortController()\n * setTimeout(() => controller.abort(), 30000) // Cancel after 30s\n *\n * try {\n * await uploadFile(config, file, { signal: controller.signal })\n * } catch (e) {\n * if (e.name === 'AbortError') {\n * console.log('Upload cancelled')\n * }\n * }\n * ```\n */\nexport async function uploadFile(\n\tconfig: SylphxConfig,\n\tfile: File,\n\toptions?: FileUploadOptions,\n): Promise<UploadResult> {\n\tconst { signal } = options ?? {}\n\n\t// Check if already aborted\n\tif (signal?.aborted) {\n\t\tthrow new DOMException('Upload aborted', 'AbortError')\n\t}\n\n\t// Get upload token from platform (with retry)\n\tlet tokenResponse: Response | null = null\n\tlet lastError: Error | null = null\n\n\tfor (let attempt = 0; attempt <= UPLOAD_RETRY_CONFIG.maxRetries; attempt++) {\n\t\ttry {\n\t\t\ttokenResponse = await fetch(buildApiUrl(config, '/storage/upload'), {\n\t\t\t\tmethod: 'POST',\n\t\t\t\theaders: buildHeaders(config),\n\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\tfilename: file.name,\n\t\t\t\t\tcontentType: file.type,\n\t\t\t\t\tsize: file.size,\n\t\t\t\t\tpath: options?.path,\n\t\t\t\t\ttype: options?.type ?? 'file',\n\t\t\t\t\tuserId: options?.userId,\n\t\t\t\t}),\n\t\t\t\tsignal,\n\t\t\t})\n\n\t\t\tif (tokenResponse.ok) {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\t// Check if error is retryable\n\t\t\tif (tokenResponse.status >= 500 || tokenResponse.status === 429) {\n\t\t\t\tif (attempt < UPLOAD_RETRY_CONFIG.maxRetries) {\n\t\t\t\t\tconst delay = calculateBackoffDelay(attempt)\n\t\t\t\t\tawait sleep(delay, signal)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Non-retryable error\n\t\t\tconst error = await tokenResponse\n\t\t\t\t.json()\n\t\t\t\t.catch(() => ({ message: 'Failed to get upload token' }))\n\t\t\tthrow new SylphxError(error.message ?? 'Failed to get upload token', {\n\t\t\t\tcode: 'BAD_REQUEST',\n\t\t\t})\n\t\t} catch (error) {\n\t\t\tif (error instanceof DOMException && error.name === 'AbortError') {\n\t\t\t\tthrow error // Don't retry aborted requests\n\t\t\t}\n\n\t\t\tlastError = error instanceof Error ? error : new Error(String(error))\n\n\t\t\tif (isRetryableError(error) && attempt < UPLOAD_RETRY_CONFIG.maxRetries) {\n\t\t\t\tconst delay = calculateBackoffDelay(attempt)\n\t\t\t\tawait sleep(delay, signal)\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tthrow lastError\n\t\t}\n\t}\n\n\tif (!tokenResponse?.ok) {\n\t\tthrow (\n\t\t\tlastError ??\n\t\t\tnew SylphxError('Failed to get upload token after retries', {\n\t\t\t\tcode: 'BAD_REQUEST',\n\t\t\t})\n\t\t)\n\t}\n\n\tconst { uploadUrl, publicUrl } = await tokenResponse.json()\n\n\t// Upload directly to storage with retry\n\treturn executeUploadWithRetry(file, uploadUrl, publicUrl, options)\n}\n\n/**\n * Execute the actual upload with retry logic\n */\nasync function executeUploadWithRetry(\n\tfile: File,\n\tuploadUrl: string,\n\tpublicUrl: string,\n\toptions?: FileUploadOptions,\n): Promise<UploadResult> {\n\tconst { signal } = options ?? {}\n\tlet lastError: Error | null = null\n\n\tfor (let attempt = 0; attempt <= UPLOAD_RETRY_CONFIG.maxRetries; attempt++) {\n\t\ttry {\n\t\t\treturn await executeUpload(file, uploadUrl, publicUrl, options)\n\t\t} catch (error) {\n\t\t\tif (error instanceof DOMException && error.name === 'AbortError') {\n\t\t\t\tthrow error // Don't retry aborted requests\n\t\t\t}\n\n\t\t\tlastError = error instanceof Error ? error : new Error(String(error))\n\n\t\t\tif (isRetryableError(error) && attempt < UPLOAD_RETRY_CONFIG.maxRetries) {\n\t\t\t\tconst delay = calculateBackoffDelay(attempt)\n\t\t\t\tawait sleep(delay, signal)\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tthrow lastError\n\t\t}\n\t}\n\n\tthrow lastError ?? new Error('Upload failed after retries')\n}\n\n/**\n * Execute a single upload attempt with XHR (for progress tracking)\n */\nfunction executeUpload(\n\tfile: File,\n\tuploadUrl: string,\n\tpublicUrl: string,\n\toptions?: FileUploadOptions,\n): Promise<UploadResult> {\n\tconst { signal, onProgress } = options ?? {}\n\n\treturn new Promise<UploadResult>((resolve, reject) => {\n\t\tconst xhr = new XMLHttpRequest()\n\n\t\t// Handle abort signal\n\t\tconst handleAbort = () => {\n\t\t\txhr.abort()\n\t\t\treject(new DOMException('Upload aborted', 'AbortError'))\n\t\t}\n\n\t\tif (signal?.aborted) {\n\t\t\treject(new DOMException('Upload aborted', 'AbortError'))\n\t\t\treturn\n\t\t}\n\n\t\tsignal?.addEventListener('abort', handleAbort, { once: true })\n\n\t\txhr.upload.addEventListener('progress', (event) => {\n\t\t\tif (event.lengthComputable && onProgress) {\n\t\t\t\tonProgress({\n\t\t\t\t\tloaded: event.loaded,\n\t\t\t\t\ttotal: event.total,\n\t\t\t\t\tprogress: Math.round((event.loaded / event.total) * 100),\n\t\t\t\t})\n\t\t\t}\n\t\t})\n\n\t\txhr.addEventListener('load', () => {\n\t\t\tsignal?.removeEventListener('abort', handleAbort)\n\n\t\t\tif (xhr.status >= 200 && xhr.status < 300) {\n\t\t\t\tresolve({\n\t\t\t\t\turl: publicUrl,\n\t\t\t\t\tpathname: options?.path ? `${options.path}/${file.name}` : file.name,\n\t\t\t\t\tcontentType: file.type,\n\t\t\t\t\tsize: file.size,\n\t\t\t\t})\n\t\t\t} else {\n\t\t\t\tconst error = new Error(`Upload failed with status ${xhr.status}`) as Error & {\n\t\t\t\t\tstatus: number\n\t\t\t\t}\n\t\t\t\terror.status = xhr.status\n\t\t\t\treject(error)\n\t\t\t}\n\t\t})\n\n\t\txhr.addEventListener('error', () => {\n\t\t\tsignal?.removeEventListener('abort', handleAbort)\n\t\t\treject(new TypeError('Network error during upload'))\n\t\t})\n\n\t\txhr.addEventListener('abort', () => {\n\t\t\tsignal?.removeEventListener('abort', handleAbort)\n\t\t\treject(new DOMException('Upload aborted', 'AbortError'))\n\t\t})\n\n\t\txhr.open('PUT', uploadUrl)\n\t\txhr.setRequestHeader('Content-Type', file.type)\n\t\txhr.send(file)\n\t})\n}\n\n/**\n * Upload a user avatar\n *\n * @example\n * ```typescript\n * const avatar = await uploadAvatar(config, file, 'user-123')\n * console.log(avatar.url)\n * ```\n */\nexport async function uploadAvatar(\n\tconfig: SylphxConfig,\n\tfile: File,\n\tuserId: string,\n\toptions?: Pick<FileUploadOptions, 'onProgress'>,\n): Promise<UploadResult> {\n\treturn uploadFile(config, file, {\n\t\t...options,\n\t\ttype: 'avatar',\n\t\tuserId,\n\t})\n}\n\n/**\n * Delete a file\n *\n * @example\n * ```typescript\n * await deleteFile(config, 'file-123')\n * ```\n */\nexport async function deleteFile(config: SylphxConfig, fileId: string): Promise<void> {\n\t// Contract-derived path/method (SSOT per ADR-084).\n\tconst endpoint = storageEndpoints.delete\n\tawait callApi<ContractDeleteFileResult>(\n\t\tconfig,\n\t\tendpoint.path.replace(':id', encodeURIComponent(fileId)),\n\t\t{ method: endpoint.method },\n\t)\n}\n\n/**\n * Get a file's URL by ID\n *\n * @example\n * ```typescript\n * const url = await getFileUrl(config, 'file-123')\n * ```\n */\nexport async function getFileUrl(config: SylphxConfig, fileId: string): Promise<string> {\n\tconst data = await callApi<{ url: string }>(config, `/storage/files/${fileId}`, { method: 'GET' })\n\treturn data.url\n}\n\n/**\n * Get file info by ID\n *\n * @example\n * ```typescript\n * const info = await getFileInfo(config, 'file-123')\n * console.log(info.name, info.size)\n * ```\n */\nexport async function getFileInfo(config: SylphxConfig, fileId: string): Promise<FileInfo> {\n\t// Contract-derived path/method (SSOT per ADR-084). Contract `FileInfo`\n\t// is the reconciled superset (ADR-084 Wave 2d) of SDK + OpenAPI shapes,\n\t// so the cast below preserves the narrower SDK-local surface for\n\t// downstream compat.\n\tconst endpoint = storageEndpoints.get\n\treturn callApi<FileInfo>(config, endpoint.path.replace(':id', encodeURIComponent(fileId)), {\n\t\tmethod: endpoint.method,\n\t})\n}\n\n// ============================================================================\n// ADR-089 Phase 5.8 — Versioning + soft-delete + restore\n// ============================================================================\n\n/**\n * A single version of a stored file. Mirrors the contract\n * `StorageFileVersion` shape.\n */\nexport interface StorageFileVersion {\n\tid: string\n\tfileId: string\n\tversionNumber: number\n\tsizeBytes: number\n\tcontentType: string | null\n\tchecksumSha256: string | null\n\tcreatedAt: string\n\tcreatedBy: string | null\n\tisCurrent: boolean\n}\n\n/**\n * List all versions of a file, newest first.\n *\n * Versions beyond the per-file retention cap (default 10) are pruned\n * automatically on each upload — this list reflects the retained window.\n *\n * @example\n * ```ts\n * const versions = await listFileVersions(config, 'file_abc')\n * const current = versions.find(v => v.isCurrent)\n * ```\n */\nexport async function listFileVersions(\n\tconfig: SylphxConfig,\n\tfileId: string,\n): Promise<StorageFileVersion[]> {\n\tconst data = await callApi<{ versions: StorageFileVersion[] }>(\n\t\tconfig,\n\t\t`/storage/files/${encodeURIComponent(fileId)}/versions`,\n\t\t{ method: 'GET' },\n\t)\n\treturn data.versions\n}\n\n/**\n * Restore an older version as the new current. The operation creates a\n * NEW version row pointing at the old object — the old row is NOT\n * mutated, preserving the audit trail.\n *\n * Rate-limited to 10/min/project.\n *\n * @example\n * ```ts\n * const restored = await restoreFileVersion(config, 'file_abc', 'fver_xyz')\n * console.log(restored.versionNumber) // e.g. 5 (the new current version #)\n * ```\n */\nexport async function restoreFileVersion(\n\tconfig: SylphxConfig,\n\tfileId: string,\n\tversionId: string,\n): Promise<StorageFileVersion> {\n\tconst data = await callApi<{ success: true; version: StorageFileVersion }>(\n\t\tconfig,\n\t\t`/storage/files/${encodeURIComponent(fileId)}/versions/${encodeURIComponent(versionId)}/restore`,\n\t\t{ method: 'POST' },\n\t)\n\treturn data.version\n}\n\n/**\n * Soft-delete a file. The version history is retained so\n * {@link restoreFile} can reverse the operation.\n *\n * This is an alias of {@link deleteFile} — the SDK `deleteFile` function\n * ALSO soft-deletes (ADR-089 Phase 5.8 changed DELETE semantics from\n * hard-delete to soft-delete). `softDeleteFile` is the explicit name for\n * code clarity.\n *\n * @example\n * ```ts\n * await softDeleteFile(config, 'file_abc')\n * // Later…\n * await restoreFile(config, 'file_abc')\n * ```\n */\nexport async function softDeleteFile(config: SylphxConfig, fileId: string): Promise<void> {\n\tawait callApi<{ success: true }>(config, `/storage/files/${encodeURIComponent(fileId)}`, {\n\t\tmethod: 'DELETE',\n\t})\n}\n\n/**\n * Reverse a soft-delete. Fails if the file is not currently soft-deleted\n * (explicit over silent to catch admin-UI bugs).\n *\n * @example\n * ```ts\n * const file = await restoreFile(config, 'file_abc')\n * ```\n */\nexport async function restoreFile(config: SylphxConfig, fileId: string): Promise<FileInfo> {\n\tconst data = await callApi<{ success: true; file: FileInfo }>(\n\t\tconfig,\n\t\t`/storage/files/${encodeURIComponent(fileId)}/restore`,\n\t\t{ method: 'POST' },\n\t)\n\treturn data.file\n}\n\n/**\n * Download the payload of a specific historical version via a short-lived\n * signed URL. Useful for diffing current vs a previous version or serving\n * an older variant to an admin audit UI.\n *\n * Internally calls {@link getSignedUrl} after flipping the version to be\n * \"temporarily current\" would NOT be safe, so instead the server minted\n * URL carries the explicit `versionId`. The resulting blob is streamed\n * directly from storage — no server round-trip for the bytes.\n *\n * @example\n * ```ts\n * const blob = await downloadFileVersion(config, 'file_abc', 'fver_xyz')\n * const bytes = new Uint8Array(await blob.arrayBuffer())\n * ```\n */\nexport async function downloadFileVersion(\n\tconfig: SylphxConfig,\n\tfileId: string,\n\tversionId: string,\n): Promise<Blob> {\n\t// Signed URL path reuses the existing `/storage/signed-url` endpoint\n\t// with an opaque `{ fileId, versionId }` body — the server resolves\n\t// the version's `object_key` and mints a URL bound to that object\n\t// rather than the current pointer. Forward-compat: if a future server\n\t// rejects the `versionId` field, the call surfaces a 400 that the\n\t// caller sees via `SylphxError`.\n\tconst signed = await callApi<SignedUrlResult & { versionId?: string }>(\n\t\tconfig,\n\t\t'/storage/signed-url',\n\t\t{\n\t\t\tmethod: 'POST',\n\t\t\tbody: { fileId, versionId },\n\t\t},\n\t)\n\tconst res = await fetch(signed.url)\n\tif (!res.ok) {\n\t\tthrow new SylphxError(`Failed to download version payload: ${res.status}`, {\n\t\t\tcode: 'BAD_REQUEST',\n\t\t})\n\t}\n\treturn res.blob()\n}\n\n/**\n * Generate a signed URL for accessing a private file\n *\n * Signed URLs provide time-limited access to private files without\n * exposing permanent URLs. Useful for:\n * - Secure document downloads\n * - Private media streaming\n * - Temporary file sharing\n *\n * @example\n * ```typescript\n * // Generate a download URL valid for 1 hour\n * const { url, expiresAt } = await getSignedUrl(config, 'file-123')\n *\n * // Generate an inline preview URL valid for 5 minutes\n * const preview = await getSignedUrl(config, 'file-123', {\n * expiresIn: 300,\n * disposition: 'inline',\n * })\n *\n * // Restrict access to a specific user\n * const userOnly = await getSignedUrl(config, 'file-123', {\n * userId: 'user-456',\n * })\n * ```\n */\nexport async function getSignedUrl(\n\tconfig: SylphxConfig,\n\tfileId: string,\n\toptions?: SignedUrlOptions,\n): Promise<SignedUrlResult> {\n\treturn callApi<SignedUrlResult>(config, '/storage/signed-url', {\n\t\tmethod: 'POST',\n\t\tbody: {\n\t\t\tfileId,\n\t\t\t...options,\n\t\t},\n\t})\n}\n","/**\n * Push Notification Service Worker Template\n *\n * This module provides a service worker implementation for handling\n * push notifications. Apps should copy or import this into their\n * service worker file.\n *\n * ## Industry Patterns Implemented (OneSignal/FCM)\n * - Push event handling with notification display\n * - Notification click with deep link navigation\n * - Notification close tracking\n * - Token refresh handling\n * - Background sync for offline actions\n *\n * ## Usage\n *\n * Create a service worker file in your app's public directory:\n *\n * ```typescript\n * // public/sw.ts or src/service-worker.ts\n * import { initPushServiceWorker } from '@sylphx/platform-sdk/notifications'\n *\n * initPushServiceWorker({\n * defaultIcon: '/icon-192.png',\n * defaultBadge: '/badge-72.png',\n * onNotificationClick: (data) => {\n * // Custom click handling\n * console.log('Notification clicked:', data)\n * },\n * })\n * ```\n */\n\n/**\n * Service Worker type definitions\n * These are minimal type definitions for Service Worker APIs.\n * Full types available with `lib: [\"WebWorker\"]` in tsconfig.\n */\ninterface PushEventData {\n\tjson(): unknown\n\ttext(): string\n}\n\ninterface PushEvent extends ExtendableEvent {\n\tdata: PushEventData | null\n}\n\ninterface NotificationEvent extends ExtendableEvent {\n\tnotification: Notification & {\n\t\tdata?: Record<string, unknown>\n\t\tclose(): void\n\t}\n\taction?: string\n}\n\ninterface WindowClient {\n\turl: string\n\tfocus(): Promise<WindowClient>\n}\n\ninterface Clients {\n\tmatchAll(options: { type: 'window'; includeUncontrolled: boolean }): Promise<WindowClient[]>\n\topenWindow(url: string): Promise<WindowClient | null>\n\tclaim(): Promise<void>\n}\n\ninterface ExtendableEvent extends Event {\n\twaitUntil(promise: Promise<unknown>): void\n}\n\ninterface ServiceWorkerRegistration {\n\tshowNotification(title: string, options?: NotificationOptions): Promise<void>\n}\n\ninterface ServiceWorkerGlobalScopeSubset {\n\treadonly registration: ServiceWorkerRegistration\n\treadonly clients: Clients\n\taddEventListener(type: 'push', listener: (event: PushEvent) => void): void\n\taddEventListener(\n\t\ttype: 'notificationclick' | 'notificationclose',\n\t\tlistener: (event: NotificationEvent) => void,\n\t): void\n\taddEventListener(type: 'activate', listener: (event: ExtendableEvent) => void): void\n}\n\ndeclare const self: ServiceWorkerGlobalScopeSubset\n\n/**\n * Notification payload from Sylphx platform\n */\nexport interface PushNotificationPayload {\n\t/** Notification title */\n\ttitle: string\n\t/** Notification body text */\n\tbody: string\n\t/** Icon URL (optional, falls back to default) */\n\ticon?: string\n\t/** Badge URL for Android (optional) */\n\tbadge?: string\n\t/** Image URL for expanded notification (optional) */\n\timage?: string\n\t/** Click action URL (optional) */\n\turl?: string\n\t/** Action buttons (optional) */\n\tactions?: Array<{\n\t\taction: string\n\t\ttitle: string\n\t\ticon?: string\n\t}>\n\t/** Custom data payload */\n\tdata?: Record<string, unknown>\n\t/** Notification tag for grouping (optional) */\n\ttag?: string\n\t/** Whether to require interaction (optional) */\n\trequireInteraction?: boolean\n\t/** Vibration pattern (optional) */\n\tvibrate?: number[]\n\t/** Silent notification (optional) */\n\tsilent?: boolean\n}\n\n/**\n * Service worker configuration options\n */\nexport interface PushServiceWorkerConfig {\n\t/** Default icon for notifications without an icon */\n\tdefaultIcon?: string\n\t/** Default badge for notifications without a badge */\n\tdefaultBadge?: string\n\t/** Called when notification is clicked */\n\tonNotificationClick?: (data: PushNotificationPayload) => void\n\t/** Called when notification is closed without clicking */\n\tonNotificationClose?: (data: PushNotificationPayload) => void\n\t/** Platform API URL for analytics/token refresh */\n\tplatformUrl?: string\n\t/** App ID for API calls */\n\tappId?: string\n}\n\n/**\n * Initialize push notification handling in service worker\n *\n * Call this in your service worker file to enable push notification handling.\n *\n * NOTE: This function should only be called from within a service worker context.\n * The types are loosely defined to work in both browser and service worker contexts.\n *\n * @example\n * ```typescript\n * // In your service worker (e.g., public/sw.ts)\n * initPushServiceWorker({\n * defaultIcon: '/icon-192.png',\n * defaultBadge: '/badge-72.png',\n * })\n * ```\n */\nexport function initPushServiceWorker(config: PushServiceWorkerConfig = {}): void {\n\tconst { defaultIcon, defaultBadge, onNotificationClick, onNotificationClose } = config\n\n\t// Handle push events (when notification arrives)\n\tself.addEventListener('push', (event) => {\n\t\tif (!event.data) {\n\t\t\tconsole.warn('[Sylphx SW] Push event received without data')\n\t\t\treturn\n\t\t}\n\n\t\tlet payload: PushNotificationPayload\n\t\ttry {\n\t\t\tpayload = event.data.json() as PushNotificationPayload\n\t\t} catch {\n\t\t\t// Fallback for plain text payloads\n\t\t\tpayload = {\n\t\t\t\ttitle: 'Notification',\n\t\t\t\tbody: event.data.text(),\n\t\t\t}\n\t\t}\n\n\t\t// Build notification options (compatible with both browser and SW contexts)\n\t\tconst notificationOptions = {\n\t\t\tbody: payload.body,\n\t\t\ticon: payload.icon || defaultIcon,\n\t\t\tbadge: payload.badge || defaultBadge,\n\t\t\timage: payload.image,\n\t\t\tdata: {\n\t\t\t\t...payload.data,\n\t\t\t\turl: payload.url,\n\t\t\t\t_sylphxPayload: payload,\n\t\t\t},\n\t\t\ttag: payload.tag,\n\t\t\trequireInteraction: payload.requireInteraction ?? false,\n\t\t\tvibrate: payload.vibrate,\n\t\t\tsilent: payload.silent ?? false,\n\t\t\tactions: payload.actions,\n\t\t}\n\n\t\tevent.waitUntil(self.registration.showNotification(payload.title, notificationOptions))\n\t})\n\n\t// Handle notification click events\n\tself.addEventListener('notificationclick', (event) => {\n\t\tevent.notification.close()\n\n\t\tconst data = event.notification.data\n\t\tconst payload = data?._sylphxPayload as PushNotificationPayload | undefined\n\t\tconst url = data?.url as string | undefined\n\n\t\t// Call custom handler if provided\n\t\tif (onNotificationClick && payload) {\n\t\t\tonNotificationClick(payload)\n\t\t}\n\n\t\t// Handle action button clicks\n\t\tif (event.action) {\n\t\t}\n\n\t\t// Navigate to URL if provided\n\t\tif (url) {\n\t\t\tevent.waitUntil(\n\t\t\t\tself.clients.matchAll({ type: 'window', includeUncontrolled: true }).then((clientList) => {\n\t\t\t\t\t// Try to focus an existing window with this URL\n\t\t\t\t\tfor (const client of clientList) {\n\t\t\t\t\t\tif (client.url === url && 'focus' in client) {\n\t\t\t\t\t\t\treturn client.focus()\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t// Open a new window if no existing window found\n\t\t\t\t\treturn self.clients.openWindow(url)\n\t\t\t\t}),\n\t\t\t)\n\t\t}\n\t})\n\n\t// Handle notification close events (for analytics)\n\tself.addEventListener('notificationclose', (event) => {\n\t\tconst data = event.notification.data\n\t\tconst payload = data?._sylphxPayload as PushNotificationPayload | undefined\n\n\t\tif (onNotificationClose && payload) {\n\t\t\tonNotificationClose(payload)\n\t\t}\n\t})\n\n\t// Handle service worker activation\n\tself.addEventListener('activate', (event) => {\n\t\tevent.waitUntil(\n\t\t\t// Claim all clients immediately\n\t\t\tself.clients.claim(),\n\t\t)\n\t})\n}\n\n/**\n * Helper to create a simple service worker script content\n *\n * For apps that want to dynamically generate their service worker,\n * this returns the JavaScript content as a string.\n *\n * @example\n * ```typescript\n * // In a route handler\n * export function GET() {\n * const content = createServiceWorkerScript({\n * defaultIcon: '/icon-192.png',\n * })\n * return new Response(content, {\n * headers: { 'Content-Type': 'application/javascript' },\n * })\n * }\n * ```\n */\nexport function createServiceWorkerScript(config: PushServiceWorkerConfig = {}): string {\n\tconst { defaultIcon = '/icon-192.png', defaultBadge = '/badge-72.png' } = config\n\n\treturn `\n// Sylphx Push Notification Service Worker\n// Auto-generated - do not edit directly\n\nconst DEFAULT_ICON = '${defaultIcon}';\nconst DEFAULT_BADGE = '${defaultBadge}';\n\nself.addEventListener('push', (event) => {\n if (!event.data) return;\n\n let payload;\n try {\n payload = event.data.json();\n } catch {\n payload = { title: 'Notification', body: event.data.text() };\n }\n\n const options = {\n body: payload.body,\n icon: payload.icon || DEFAULT_ICON,\n badge: payload.badge || DEFAULT_BADGE,\n image: payload.image,\n data: { ...payload.data, url: payload.url },\n tag: payload.tag,\n requireInteraction: payload.requireInteraction || false,\n vibrate: payload.vibrate,\n silent: payload.silent || false,\n actions: payload.actions,\n };\n\n event.waitUntil(\n self.registration.showNotification(payload.title, options)\n );\n});\n\nself.addEventListener('notificationclick', (event) => {\n event.notification.close();\n const url = event.notification.data?.url;\n\n if (url) {\n event.waitUntil(\n clients.matchAll({ type: 'window', includeUncontrolled: true }).then((clientList) => {\n for (const client of clientList) {\n if (client.url === url && 'focus' in client) {\n return client.focus();\n }\n }\n if (clients.openWindow) {\n return clients.openWindow(url);\n }\n })\n );\n }\n});\n\nself.addEventListener('activate', (event) => {\n event.waitUntil(clients.claim());\n});\n\nconsole.log('[Sylphx SW] Push notification service worker active');\n`.trim()\n}\n\n/**\n * Register the service worker from the client side\n *\n * Call this in your app's entry point to register the service worker.\n *\n * @example\n * ```typescript\n * // In your app's entry point (e.g., _app.tsx or layout.tsx)\n * import { registerPushServiceWorker } from '@sylphx/platform-sdk/notifications'\n *\n * useEffect(() => {\n * registerPushServiceWorker('/sw.js')\n * }, [])\n * ```\n */\nexport async function registerPushServiceWorker(\n\tswPath = '/sw.js',\n): Promise<ServiceWorkerRegistration | null> {\n\tif (typeof window === 'undefined') return null\n\tif (!('serviceWorker' in navigator)) {\n\t\tconsole.warn('[Sylphx] Service workers not supported')\n\t\treturn null\n\t}\n\n\ttry {\n\t\tconst registration = await navigator.serviceWorker.register(swPath)\n\t\treturn registration\n\t} catch (error) {\n\t\tconsole.error('[Sylphx] Service worker registration failed:', error)\n\t\treturn null\n\t}\n}\n","/**\n * Notifications Functions\n *\n * Pure functions for push notifications.\n *\n * Wire-shape types are re-exported from `@sylphx/contract` (ADR-084). The\n * contract is the single source of truth for `/notifications/register`,\n * `/unregister`, `/send`, `/preferences`, `/messages`, `/mobile/config`.\n */\n\n// Type-only imports from @sylphx/contract per ADR-084 Rule 3 — prevents\n// Effect runtime types from leaking into the published .d.ts surface.\nimport type {\n\tInAppMessagesResponse as ContractInAppMessagesResponse,\n\tMobileConfigResponse as ContractMobileConfigResponse,\n\tMobileDevice as ContractMobileDevice,\n\tPushPreferencesResponse as ContractPushPreferencesResponse,\n\tRegisterPushResponse as ContractRegisterPushResponse,\n\tSendPushInput as ContractSendPushInput,\n\tInAppMessageFull,\n\tRegisterPushInput,\n\tUnregisterPushInput,\n} from '@sylphx/contract'\nimport { callApi, type SylphxConfig } from './config'\n\n// ============================================================================\n// Types (re-exported from @sylphx/contract)\n// ============================================================================\n\nexport type RegisterPushRequest = RegisterPushInput\nexport type RegisterPushResponse = ContractRegisterPushResponse\nexport type UnregisterPushRequest = UnregisterPushInput\nexport type PushPreferencesResponse = ContractPushPreferencesResponse\n/**\n * Full in-app message envelope the REST API emits under\n * `GET /notifications/messages`. Aliased to the contract's rich shape\n * (`InAppMessageFull`) — the contract also exports a leaner `InAppMessage`\n * primitive keyed off `userId`, which endpoint modules use; the SDK needs\n * the full presentation envelope.\n */\nexport type InAppMessage = InAppMessageFull\nexport type InAppMessagesResponse = ContractInAppMessagesResponse\nexport type MobileConfigResponse = ContractMobileConfigResponse\nexport type MobileDevice = ContractMobileDevice\n\n// SDK-specific types for convenience\nexport interface PushSubscription {\n\tendpoint: string\n\tkeys: {\n\t\tp256dh: string\n\t\tauth: string\n\t}\n}\n\nexport interface PushNotification {\n\ttitle: string\n\tbody: string\n\ticon?: string\n\turl?: string\n}\n\n// ============================================================================\n// Functions\n// ============================================================================\n\n/**\n * Register a push subscription\n *\n * @example\n * ```typescript\n * // Get subscription from browser\n * const registration = await navigator.serviceWorker.ready\n * const sub = await registration.pushManager.subscribe({\n * userVisibleOnly: true,\n * applicationServerKey: vapidPublicKey,\n * })\n *\n * // Register with platform\n * await registerPush(config, {\n * endpoint: sub.endpoint,\n * keys: {\n * p256dh: sub.toJSON().keys!.p256dh,\n * auth: sub.toJSON().keys!.auth,\n * },\n * })\n * ```\n */\nexport async function registerPush(\n\tconfig: SylphxConfig,\n\tsubscription: PushSubscription,\n): Promise<void> {\n\t// Contract path (`/notifications/register`) is now the SSOT after\n\t// ADR-084 Wave 2d reconciliation — matches production SDK.\n\tawait callApi(config, '/notifications/register', {\n\t\tmethod: 'POST',\n\t\tbody: { subscription },\n\t})\n}\n\n/**\n * Unregister a push subscription\n *\n * @example\n * ```typescript\n * await unregisterPush(config, subscription.endpoint)\n * ```\n */\nexport async function unregisterPush(config: SylphxConfig, endpoint: string): Promise<void> {\n\tawait callApi(config, '/notifications/unregister', {\n\t\tmethod: 'POST',\n\t\tbody: { endpoint },\n\t})\n}\n\n/**\n * Send a push notification to a user (admin only)\n *\n * @example\n * ```typescript\n * await sendPush(config, 'user-123', {\n * title: 'New message',\n * body: 'You have a new message',\n * url: '/messages',\n * })\n * ```\n */\nexport async function sendPush(\n\tconfig: SylphxConfig,\n\tuserId: string,\n\tnotification: PushNotification,\n): Promise<{ sentTo: number; expired: number }> {\n\t// Contract path + `PushDeliveryResult` shape both widened to match the\n\t// SDK production surface (`/notifications/send` + counter fields) in\n\t// ADR-084 Wave 2d. The contract type is now a superset that accepts\n\t// either the counter shape (`sentTo`/`expired`) or the status union\n\t// (`status`/`messageId`/`reason`).\n\tconst body: ContractSendPushInput = {\n\t\tuserId,\n\t\ttitle: notification.title,\n\t\tbody: notification.body,\n\t\t...(notification.icon !== undefined && { icon: notification.icon }),\n\t\t...(notification.url !== undefined && { url: notification.url }),\n\t}\n\treturn callApi(config, '/notifications/send', {\n\t\tmethod: 'POST',\n\t\tbody,\n\t})\n}\n\n/**\n * Get push notification preferences\n *\n * @example\n * ```typescript\n * const prefs = await getPushPreferences(config)\n * ```\n */\nexport async function getPushPreferences(\n\tconfig: SylphxConfig,\n): Promise<{ enabled: boolean; categories: Record<string, boolean> }> {\n\treturn callApi(config, '/notifications/preferences', { method: 'GET' })\n}\n\n/**\n * Update push notification preferences\n *\n * @example\n * ```typescript\n * await updatePushPreferences(config, {\n * enabled: true,\n * categories: { marketing: false, updates: true },\n * })\n * ```\n */\nexport async function updatePushPreferences(\n\tconfig: SylphxConfig,\n\tpreferences: { enabled?: boolean; categories?: Record<string, boolean> },\n): Promise<void> {\n\tawait callApi(config, '/notifications/preferences', {\n\t\tmethod: 'PUT',\n\t\tbody: preferences,\n\t})\n}\n\n// ============================================================================\n// Phase 5.7 — Advanced push: segments, campaigns, scheduled + A/B sends\n//\n// Namespaced under `notifications.segments.*` + `notifications.campaigns.*`\n// to match the Firebase-style SDK pattern elsewhere in this file. Types\n// are intentionally structural (not re-exported from @sylphx/contract\n// yet — contract additions land separately as part of Wave 3 migration).\n// ============================================================================\n\n/**\n * Structured filter DSL for segments. Matches the server-side shape\n * defined in `@sylphx/core/lib/push/filter-dsl.ts`.\n */\nexport type PushSegmentFilter =\n\t| { field: string; op: 'eq' | 'ne' | 'gt' | 'gte' | 'lt' | 'lte'; value: unknown }\n\t| { field: string; op: 'in'; value: readonly unknown[] }\n\t| { field: string; op: 'contains'; value: unknown }\n\t| { all: readonly PushSegmentFilter[] }\n\t| { any: readonly PushSegmentFilter[] }\n\t| { not: PushSegmentFilter }\n\nexport type PushSegment = {\n\tid: string\n\tname: string\n\tdescription: string | null\n\tfilter: PushSegmentFilter\n\tmemberCount: number | null\n\tcomputedAt: string | null\n\tcreatedAt: string\n\tcreatedBy: string\n}\n\nexport type PushCampaignVariant = {\n\tname: string\n\tweight: number\n\ttitle: string\n\tbody: string\n\turl?: string\n\ticon?: string\n\tdata?: Record<string, unknown>\n}\n\nexport type PushCampaign = {\n\tid: string\n\tname: string\n\tsegmentId: string | null\n\tstatus: 'draft' | 'scheduled' | 'sending' | 'sent' | 'cancelled' | 'failed'\n\tvariants: readonly PushCampaignVariant[]\n\tscheduledAt: string | null\n\tsentAt: string | null\n\tcreatedAt: string\n}\n\nexport type PushCampaignStats = {\n\tcampaignId: string\n\ttotalDeliveries: number\n\tbyVariant: Record<\n\t\tstring,\n\t\t{ pending: number; sent: number; delivered: number; failed: number; clicked: number }\n\t>\n}\n\n/**\n * Segment-management namespace. Requires secret-key auth — call from\n * trusted server contexts only.\n */\nexport const segments = {\n\tasync create(\n\t\tconfig: SylphxConfig,\n\t\tinput: { name: string; description?: string; filter: PushSegmentFilter },\n\t): Promise<PushSegment> {\n\t\treturn callApi(config, '/notifications/segments', { method: 'POST', body: input })\n\t},\n\tasync list(config: SylphxConfig): Promise<{ segments: PushSegment[] }> {\n\t\treturn callApi(config, '/notifications/segments', { method: 'GET' })\n\t},\n\tasync get(config: SylphxConfig, id: string): Promise<PushSegment> {\n\t\treturn callApi(config, `/notifications/segments/${id}`, { method: 'GET' })\n\t},\n\tasync delete(config: SylphxConfig, id: string): Promise<void> {\n\t\tawait callApi(config, `/notifications/segments/${id}`, { method: 'DELETE' })\n\t},\n}\n\n/**\n * Campaign-management namespace. A/B variants assigned deterministically\n * per-user on the server; scheduled campaigns are picked up by the\n * scheduled-send worker.\n */\nexport const campaigns = {\n\tasync create(\n\t\tconfig: SylphxConfig,\n\t\tinput: {\n\t\t\tname: string\n\t\t\tsegmentId?: string\n\t\t\tvariants: readonly PushCampaignVariant[]\n\t\t\tscheduledAt?: string\n\t\t},\n\t): Promise<PushCampaign> {\n\t\treturn callApi(config, '/notifications/campaigns', { method: 'POST', body: input })\n\t},\n\tasync get(config: SylphxConfig, id: string): Promise<PushCampaign> {\n\t\treturn callApi(config, `/notifications/campaigns/${id}`, { method: 'GET' })\n\t},\n\tasync schedule(config: SylphxConfig, id: string, scheduledAt: string): Promise<PushCampaign> {\n\t\treturn callApi(config, `/notifications/campaigns/${id}/schedule`, {\n\t\t\tmethod: 'POST',\n\t\t\tbody: { scheduledAt },\n\t\t})\n\t},\n\tasync send(config: SylphxConfig, id: string): Promise<PushCampaign> {\n\t\treturn callApi(config, `/notifications/campaigns/${id}/send`, { method: 'POST' })\n\t},\n\tasync cancel(config: SylphxConfig, id: string): Promise<PushCampaign> {\n\t\treturn callApi(config, `/notifications/campaigns/${id}/cancel`, { method: 'POST' })\n\t},\n\tasync stats(config: SylphxConfig, id: string): Promise<PushCampaignStats> {\n\t\treturn callApi(config, `/notifications/campaigns/${id}/stats`, { method: 'GET' })\n\t},\n}\n","/**\n * Triggers Client (ADR-040)\n *\n * Unified scheduling + event dispatch API.\n * Create cron schedules and event triggers that dispatch to Tasks, Runs, or HTTP URLs.\n *\n * ## Usage\n *\n * ### Cron → Task\n * ```typescript\n * import { createConfig, TriggersClient } from '@sylphx/sdk'\n * const config = createConfig({ secretKey: process.env.SYLPHX_SECRET_KEY!, ref: 'my-project' })\n *\n * const trigger = await TriggersClient.create(config, {\n * name: 'daily-cleanup',\n * source: { type: 'cron', expression: '0 2 * * *' },\n * target: { type: 'task', taskName: 'daily-cleanup' },\n * })\n * ```\n *\n * ### Event → Task (fires when event is published via publishEvent)\n * ```typescript\n * const trigger = await TriggersClient.create(config, {\n * name: 'welcome-email-on-signup',\n * source: { type: 'event', eventName: 'user.signup' },\n * target: { type: 'task', taskName: 'send-welcome-email' },\n * })\n * // Publish from your app:\n * await TriggersClient.publishEvent(config, 'user.signup', { userId: '123' })\n * ```\n *\n * ### Cron → HTTP URL (any language, no code required)\n * ```typescript\n * const trigger = await TriggersClient.create(config, {\n * name: 'nightly-backup',\n * source: { type: 'cron', expression: '0 3 * * *' },\n * target: { type: 'http', url: 'https://myapp.com/api/backup', payload: { type: 'full' } },\n * })\n * ```\n */\n\nimport type { SylphxConfig } from '../../config'\nimport { callApi } from '../../config'\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport type TriggerTargetType = 'task' | 'run' | 'http'\nexport type TriggerSourceType = 'cron' | 'event'\nexport type TriggerStatus = 'active' | 'paused' | 'deleted'\n\nexport interface TaskTarget {\n\ttype: 'task'\n\ttaskName: string\n\thandlerPath?: string\n\tpayload?: Record<string, unknown>\n}\n\nexport interface HttpTarget {\n\ttype: 'http'\n\turl: string\n\tmethod?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'\n\theaders?: Record<string, string>\n\tpayload?: Record<string, unknown>\n}\n\nexport interface RunTarget {\n\ttype: 'run'\n\timage: string\n\tcommand: string[]\n\tresources?: { cpu?: string; memory?: string }\n}\n\nexport type TriggerTarget = TaskTarget | HttpTarget | RunTarget\n\nexport interface CronSource {\n\ttype: 'cron'\n\texpression: string\n}\n\nexport interface EventSource {\n\ttype: 'event'\n\t/** The event name to listen for. e.g. 'user.signup', 'order.paid' */\n\teventName: string\n}\n\nexport type TriggerSource = CronSource | EventSource\n\nexport interface CreateTriggerOptions {\n\tname?: string\n\tsource: TriggerSource\n\ttarget: TriggerTarget\n\tpaused?: boolean\n\t/** Idempotency key — prevents duplicate trigger creation per project+environment */\n\tidempotencyKey?: string\n}\n\nexport interface UpdateTriggerOptions {\n\tname?: string\n\tsource?: TriggerSource\n\tpaused?: boolean\n}\n\nexport interface Trigger {\n\tid: string\n\tname: string\n\ttargetType: TriggerTargetType\n\tsourceType: TriggerSourceType\n\tcronExpression: string | null\n\teventName: string | null\n\thandlerPath: string | null\n\tcallbackUrl: string | null\n\tpayload: unknown\n\tstatus: TriggerStatus\n\tnextRunAt: string | null\n\tlastRunAt: string | null\n\tcreatedAt: string\n\tupdatedAt: string\n}\n\nexport interface ListTriggersResult {\n\ttriggers: Trigger[]\n}\n\nexport interface PublishEventResult {\n\tdispatched: number\n\teventName: string\n}\n\n// ============================================================================\n// Client\n// ============================================================================\n\n/** Create a new trigger (cron or event source, task/run/http target) */\nasync function createTrigger(\n\tconfig: SylphxConfig,\n\toptions: CreateTriggerOptions,\n): Promise<Trigger> {\n\treturn callApi<Trigger>(config, '/triggers', {\n\t\tmethod: 'POST',\n\t\tbody: options,\n\t})\n}\n\n/** List all triggers for the project */\nasync function listTriggers(config: SylphxConfig): Promise<ListTriggersResult> {\n\treturn callApi<ListTriggersResult>(config, '/triggers')\n}\n\n/** Get a trigger by ID */\nasync function getTrigger(config: SylphxConfig, triggerId: string): Promise<Trigger> {\n\treturn callApi<Trigger>(config, `/triggers/${triggerId}`)\n}\n\n/** Update a trigger */\nasync function updateTrigger(\n\tconfig: SylphxConfig,\n\ttriggerId: string,\n\toptions: UpdateTriggerOptions,\n): Promise<Trigger> {\n\treturn callApi<Trigger>(config, `/triggers/${triggerId}`, {\n\t\tmethod: 'PATCH',\n\t\tbody: options,\n\t})\n}\n\n/** Delete a trigger */\nasync function deleteTrigger(\n\tconfig: SylphxConfig,\n\ttriggerId: string,\n): Promise<{ success: boolean }> {\n\treturn callApi<{ success: boolean }>(config, `/triggers/${triggerId}`, { method: 'DELETE' })\n}\n\n/** Pause a trigger */\nasync function pauseTrigger(config: SylphxConfig, triggerId: string): Promise<Trigger> {\n\treturn callApi<Trigger>(config, `/triggers/${triggerId}/pause`, { method: 'POST' })\n}\n\n/** Resume a paused trigger */\nasync function resumeTrigger(config: SylphxConfig, triggerId: string): Promise<Trigger> {\n\treturn callApi<Trigger>(config, `/triggers/${triggerId}/resume`, { method: 'POST' })\n}\n\n/** Fire a trigger immediately (one-shot, regardless of schedule) */\nasync function fireTrigger(\n\tconfig: SylphxConfig,\n\ttriggerId: string,\n): Promise<{ success: boolean; message: string }> {\n\treturn callApi<{ success: boolean; message: string }>(config, `/triggers/${triggerId}/fire`, {\n\t\tmethod: 'POST',\n\t})\n}\n\n/**\n * Publish an event — dispatches all active event triggers matching the event name.\n * Endpoint: POST /triggers/events\n *\n * @example\n * ```typescript\n * await TriggersClient.publishEvent(config, 'user.signup', { userId: '123', plan: 'pro' })\n * ```\n */\nasync function publishEvent(\n\tconfig: SylphxConfig,\n\teventName: string,\n\tpayload?: Record<string, unknown>,\n): Promise<PublishEventResult> {\n\treturn callApi<PublishEventResult>(config, '/triggers/events', {\n\t\tmethod: 'POST',\n\t\tbody: { eventName, payload: payload ?? {} },\n\t})\n}\n\n/**\n * Triggers client — namespace object exposing all trigger operations.\n * Use via `TriggersClient.create(...)`, `TriggersClient.publishEvent(...)`, etc.\n */\nexport const TriggersClient = {\n\tcreate: createTrigger,\n\tlist: listTriggers,\n\tget: getTrigger,\n\tupdate: updateTrigger,\n\tdelete: deleteTrigger,\n\tpause: pauseTrigger,\n\tresume: resumeTrigger,\n\tfire: fireTrigger,\n\tpublishEvent,\n} as const\n","/**\n * Tasks Handler\n *\n * Server-side endpoint factory for user task definitions.\n * Implements the Sylphx stateless-replay model:\n *\n * 1. Platform dispatches POST to the app's /api/tasks endpoint.\n * 2. The handler replays from the beginning.\n * 3. Completed steps hit a cache and return immediately.\n * 4. The first uncached step executes, then throws StepCompleteSignal.\n * 5. The platform saves the result and re-dispatches.\n * 6. After all steps complete the handler returns normally.\n *\n * @example\n * ```typescript\n * // app/api/tasks/route.ts\n * import { sylphx } from '@/lib/sylphx'\n *\n * const sendEmail = sylphx.tasks.define('send-email', async (payload, { step }) => {\n * const validated = await step.run('validate', () => validateEmail(payload.to))\n * await step.sleep('cool-down', '5 minutes')\n * return step.run('send', () => sendEmail(validated))\n * })\n *\n * export const { GET, POST } = sylphx.tasks.handler([sendEmail])\n * ```\n */\n\nimport { createHmac, timingSafeEqual } from 'node:crypto'\nimport type { NativeStepContext, NativeTaskDefinition } from './types'\n\n// ============================================================================\n// Signals (control flow via throw)\n// ============================================================================\n\n/**\n * Thrown by step.run() when a step's result is not yet cached.\n * The handler aborts; the platform saves the result and re-dispatches.\n */\nexport class StepCompleteSignal {\n\treadonly _isStepCompleteSignal = true\n\n\tconstructor(\n\t\tpublic readonly stepName: string,\n\t\tpublic readonly result: unknown,\n\t) {}\n}\n\n/**\n * Thrown by step.sleep() when the sleep is not yet resolved.\n * The handler aborts; the platform waits and re-dispatches.\n */\nexport class StepSleepSignal {\n\treadonly _isStepSleepSignal = true\n\n\tconstructor(\n\t\tpublic readonly stepName: string,\n\t\tpublic readonly duration: string,\n\t) {}\n}\n\n/**\n * Thrown by step.waitForEvent() when the event has not yet been received.\n * The handler aborts; the platform persists the wait record.\n * When the event arrives (via TriggersClient.publishEvent()), the platform\n * resolves the wait and re-dispatches with the event payload in context.waits.\n */\nexport class StepWaitEventSignal {\n\treadonly _isStepWaitEventSignal = true\n\n\tconstructor(\n\t\tpublic readonly stepName: string,\n\t\tpublic readonly eventName: string,\n\t\tpublic readonly options: {\n\t\t\t/** Timeout duration, e.g. '24h', '7d'. Task fails if event not received in time. */\n\t\t\ttimeout?: string\n\t\t\t/** Optional JSON filter — only resolve if event payload matches */\n\t\t\tfilter?: Record<string, unknown>\n\t\t} = {},\n\t) {}\n}\n\n// ============================================================================\n// Step context factory\n// ============================================================================\n\n/**\n * Build the step proxy for a single handler invocation.\n *\n * @param completedSteps Map of stepName → cached result\n * @param resolvedWaits Map of stepName → wait result (sleep = undefined, event = event payload)\n */\nexport function createStepContext(\n\tcompletedSteps: Map<string, unknown>,\n\tresolvedWaits: Map<string, unknown>,\n): NativeStepContext {\n\treturn {\n\t\t/**\n\t\t * Execute a named step.\n\t\t *\n\t\t * - If cached: return the cached value immediately (replay).\n\t\t * - If not cached: execute fn, then throw StepCompleteSignal with the result.\n\t\t */\n\t\tasync run<T>(name: string, fn: () => T | Promise<T>): Promise<T> {\n\t\t\tif (completedSteps.has(name)) {\n\t\t\t\treturn completedSteps.get(name) as T\n\t\t\t}\n\n\t\t\tconst result = await fn()\n\t\t\tthrow new StepCompleteSignal(name, result)\n\t\t},\n\n\t\t/**\n\t\t * Sleep for the given duration.\n\t\t *\n\t\t * - If resolved (platform woke us up): return immediately.\n\t\t * - If not resolved: throw StepSleepSignal to pause execution.\n\t\t */\n\t\tasync sleep(name: string, duration: string): Promise<void> {\n\t\t\tif (resolvedWaits.has(name)) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tthrow new StepSleepSignal(name, duration)\n\t\t},\n\n\t\t/**\n\t\t * Pause execution until a named event is published via TriggersClient.publishEvent().\n\t\t *\n\t\t * - If event already arrived (platform re-dispatched with result): return event payload.\n\t\t * - If not yet arrived: throw StepWaitEventSignal to pause execution.\n\t\t *\n\t\t * @param name Step identifier (unique within handler).\n\t\t * @param eventName The event name to listen for (e.g. 'user.approved').\n\t\t * @param options Optional timeout ('24h', '7d') and payload filter.\n\t\t *\n\t\t * @example Human-in-the-loop approval\n\t\t * ```typescript\n\t\t * const approval = await step.waitForEvent('wait-approval', 'order.approved', {\n\t\t * timeout: '48h',\n\t\t * filter: { orderId: payload.orderId },\n\t\t * })\n\t\t * if (!approval) throw new Error('Approval timed out')\n\t\t * await sendConfirmation(approval.approvedBy)\n\t\t * ```\n\t\t */\n\t\tasync waitForEvent<T = unknown>(\n\t\t\tname: string,\n\t\t\teventName: string,\n\t\t\toptions: { timeout?: string; filter?: Record<string, unknown> } = {},\n\t\t): Promise<T | null> {\n\t\t\tif (resolvedWaits.has(name)) {\n\t\t\t\t// Platform resolved the wait — return the event payload (null if timed out)\n\t\t\t\treturn (resolvedWaits.get(name) as T | null) ?? null\n\t\t\t}\n\n\t\t\tthrow new StepWaitEventSignal(name, eventName, options)\n\t\t},\n\t}\n}\n\n// ============================================================================\n// Signature verification\n// ============================================================================\n\n/**\n * Constant-time HMAC-SHA256 signature verification.\n * Accepts both raw hex and 'sha256={hex}' formats.\n */\nexport function verifySignature(body: string, signature: string, secret: string): boolean {\n\ttry {\n\t\tconst hmac = createHmac('sha256', secret).update(body, 'utf8').digest('hex')\n\t\tconst normalised = signature.replace(/^sha256=/, '')\n\n\t\tconst expected = Buffer.from(hmac, 'hex')\n\t\tconst provided = Buffer.from(normalised, 'hex')\n\n\t\tif (expected.length !== provided.length) return false\n\t\treturn timingSafeEqual(expected, provided)\n\t} catch {\n\t\treturn false\n\t}\n}\n\n// ============================================================================\n// Request / response types\n// ============================================================================\n\ninterface DispatchStepEntry {\n\tname: string\n\tresult: unknown\n\tcompletedAt: string\n}\n\ninterface DispatchWaitEntry {\n\tname: string\n\tresolvedAt: string\n\tresult?: unknown\n}\n\ninterface DispatchContext {\n\tattempt: number\n\tsteps: DispatchStepEntry[]\n\twaits: DispatchWaitEntry[]\n}\n\ninterface DispatchBody {\n\ttaskRunId: string\n\ttaskName: string\n\tpayload: unknown\n\tcontext: DispatchContext\n}\n\n// ============================================================================\n// Handler factory\n// ============================================================================\n\nexport interface TasksHandlerOptions {\n\t/** Platform signing secret. If not set, signature verification is skipped. */\n\tsigningSecret?: string\n}\n\nexport interface TasksHandlerResult {\n\tGET: (req: Request) => Promise<Response>\n\tPOST: (req: Request) => Promise<Response>\n}\n\n/**\n * Create a Next.js-compatible route handler for a list of task definitions.\n *\n * @example\n * ```typescript\n * export const { GET, POST } = createTasksHandler([sendEmail, processOrder])\n * ```\n */\nexport function createTasksHandler(\n\ttaskDefs: NativeTaskDefinition[],\n\toptions: TasksHandlerOptions = {},\n): TasksHandlerResult {\n\tconst taskMap = new Map<string, NativeTaskDefinition>()\n\tfor (const def of taskDefs) {\n\t\ttaskMap.set(def.name, def)\n\t}\n\n\t// GET: health/discovery — returns registered task names\n\tconst GET = async (_req: Request): Promise<Response> => {\n\t\treturn Response.json({\n\t\t\tok: true,\n\t\t\ttasks: Array.from(taskMap.keys()),\n\t\t})\n\t}\n\n\t// POST: dispatch handler\n\tconst POST = async (req: Request): Promise<Response> => {\n\t\t// ------------------------------------------------------------------\n\t\t// 1. Read raw body as text\n\t\t// ------------------------------------------------------------------\n\t\tlet rawBody: string\n\t\ttry {\n\t\t\trawBody = await req.text()\n\t\t} catch {\n\t\t\treturn Response.json(\n\t\t\t\t{ status: 'error', message: 'Failed to read request body' },\n\t\t\t\t{ status: 400 },\n\t\t\t)\n\t\t}\n\n\t\t// ------------------------------------------------------------------\n\t\t// 2. Verify signature if configured\n\t\t// ------------------------------------------------------------------\n\t\tconst signingSecret =\n\t\t\toptions.signingSecret ??\n\t\t\tprocess.env.SYLPHX_SIGNING_SECRET ??\n\t\t\tprocess.env.SYLPHX_SECRET_KEY ??\n\t\t\t''\n\n\t\tif (signingSecret) {\n\t\t\tconst signature = req.headers.get('x-sylphx-signature') ?? ''\n\t\t\tif (!signature) {\n\t\t\t\treturn Response.json(\n\t\t\t\t\t{ status: 'error', message: 'Missing X-Sylphx-Signature header' },\n\t\t\t\t\t{ status: 401 },\n\t\t\t\t)\n\t\t\t}\n\n\t\t\tif (!verifySignature(rawBody, signature, signingSecret)) {\n\t\t\t\treturn Response.json({ status: 'error', message: 'Invalid signature' }, { status: 401 })\n\t\t\t}\n\t\t}\n\n\t\t// ------------------------------------------------------------------\n\t\t// 3. Parse body\n\t\t// ------------------------------------------------------------------\n\t\tlet dispatch: DispatchBody\n\t\ttry {\n\t\t\tdispatch = JSON.parse(rawBody) as DispatchBody\n\t\t} catch {\n\t\t\treturn Response.json(\n\t\t\t\t{ status: 'error', message: 'Request body is not valid JSON' },\n\t\t\t\t{ status: 400 },\n\t\t\t)\n\t\t}\n\n\t\tconst { taskName, payload, context } = dispatch\n\n\t\tif (!taskName || typeof taskName !== 'string') {\n\t\t\treturn Response.json(\n\t\t\t\t{ status: 'error', message: 'Missing or invalid \"taskName\" field' },\n\t\t\t\t{ status: 400 },\n\t\t\t)\n\t\t}\n\n\t\t// ------------------------------------------------------------------\n\t\t// 4. Find task definition\n\t\t// ------------------------------------------------------------------\n\t\tconst taskDef = taskMap.get(taskName)\n\t\tif (!taskDef) {\n\t\t\treturn Response.json(\n\t\t\t\t{\n\t\t\t\t\tstatus: 'error',\n\t\t\t\t\tmessage: `Task \"${taskName}\" not found. Registered tasks: ${Array.from(taskMap.keys()).join(', ')}`,\n\t\t\t\t},\n\t\t\t\t{ status: 404 },\n\t\t\t)\n\t\t}\n\n\t\t// ------------------------------------------------------------------\n\t\t// 5. Build step context from dispatch context\n\t\t// ------------------------------------------------------------------\n\t\tconst completedSteps = new Map<string, unknown>()\n\t\tfor (const step of context?.steps ?? []) {\n\t\t\tcompletedSteps.set(step.name, step.result)\n\t\t}\n\n\t\t// resolvedWaits: stepName → result (sleep=undefined, event=payload, timeout=null)\n\t\tconst resolvedWaits = new Map<string, unknown>()\n\t\tfor (const wait of context?.waits ?? []) {\n\t\t\tresolvedWaits.set(wait.name, wait.result ?? undefined)\n\t\t}\n\n\t\tconst stepCtx = createStepContext(completedSteps, resolvedWaits)\n\n\t\t// ------------------------------------------------------------------\n\t\t// 6. Invoke the handler\n\t\t// ------------------------------------------------------------------\n\t\ttry {\n\t\t\tconst result = await taskDef.handler(payload, { step: stepCtx })\n\n\t\t\t// Handler returned normally → task is complete\n\t\t\treturn Response.json({ status: 'complete', result })\n\t\t} catch (err: unknown) {\n\t\t\t// ------------------------------------------------------------------\n\t\t\t// 7a. Step completed — save result and re-dispatch\n\t\t\t// ------------------------------------------------------------------\n\t\t\tif (err instanceof StepCompleteSignal || (err as StepCompleteSignal)?._isStepCompleteSignal) {\n\t\t\t\tconst signal = err as StepCompleteSignal\n\t\t\t\treturn Response.json({\n\t\t\t\t\tstatus: 'step_complete',\n\t\t\t\t\tstepName: signal.stepName,\n\t\t\t\t\tresult: signal.result,\n\t\t\t\t})\n\t\t\t}\n\n\t\t\t// ------------------------------------------------------------------\n\t\t\t// 7b. Step sleep — create wait record\n\t\t\t// ------------------------------------------------------------------\n\t\t\tif (err instanceof StepSleepSignal || (err as StepSleepSignal)?._isStepSleepSignal) {\n\t\t\t\tconst signal = err as StepSleepSignal\n\t\t\t\treturn Response.json({\n\t\t\t\t\tstatus: 'step_sleep',\n\t\t\t\t\tstepName: signal.stepName,\n\t\t\t\t\tduration: signal.duration,\n\t\t\t\t})\n\t\t\t}\n\n\t\t\t// ------------------------------------------------------------------\n\t\t\t// 7c. Step waitForEvent — suspend until named event arrives\n\t\t\t// ------------------------------------------------------------------\n\t\t\tif (\n\t\t\t\terr instanceof StepWaitEventSignal ||\n\t\t\t\t(err as StepWaitEventSignal)?._isStepWaitEventSignal\n\t\t\t) {\n\t\t\t\tconst signal = err as StepWaitEventSignal\n\t\t\t\treturn Response.json({\n\t\t\t\t\tstatus: 'step_wait_event',\n\t\t\t\t\tstepName: signal.stepName,\n\t\t\t\t\teventName: signal.eventName,\n\t\t\t\t\ttimeout: signal.options.timeout ?? null,\n\t\t\t\t\tfilter: signal.options.filter ?? null,\n\t\t\t\t})\n\t\t\t}\n\n\t\t\t// ------------------------------------------------------------------\n\t\t\t// 7d. Unexpected error\n\t\t\t// ------------------------------------------------------------------\n\t\t\tconst message = err instanceof Error ? err.message : String(err)\n\t\t\tconsole.error(`[sylphx/tasks] Task \"${taskName}\" threw an error:`, err)\n\t\t\treturn Response.json(\n\t\t\t\t{\n\t\t\t\t\tstatus: 'error',\n\t\t\t\t\tmessage,\n\t\t\t\t\tretriable: true,\n\t\t\t\t},\n\t\t\t\t{ status: 500 },\n\t\t\t)\n\t\t}\n\t}\n\n\treturn { GET, POST }\n}\n","/**\n * Task API Functions\n *\n * Standalone functions for scheduling tasks and managing crons via the Sylphx API.\n * These are backward-compat exports preserved from the pre-refactor tasks.ts.\n */\n\nimport { callApi, type SylphxConfig } from '../../config'\nimport type { CronSchedule } from './types'\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface TaskInput {\n\t/** Callback URL to call when task executes */\n\tcallbackUrl: string\n\t/** Task name/type */\n\tname?: string\n\t/** Task type for categorization */\n\ttype?: string\n\t/** Task payload sent to callback */\n\tpayload?: Record<string, unknown>\n\t/** HTTP method for callback (default: POST) */\n\tmethod?: 'GET' | 'POST' | 'PUT' | 'DELETE'\n\t/** Additional headers for callback */\n\theaders?: Record<string, string>\n\t/** Delay before executing (in seconds, max 604800 = 7 days) */\n\tdelay?: number\n\t/** Schedule for later (ISO timestamp) */\n\tscheduledFor?: string\n\t/** Number of retries on failure (0-5, default: 3) */\n\tretries?: number\n\t/** Request timeout in seconds (1-300, default: 30) */\n\ttimeout?: number\n\t/**\n\t * Idempotency key for safe retries (Stripe/Inngest pattern).\n\t *\n\t * When provided, prevents duplicate task execution if the same\n\t * key is used within a 24-hour window.\n\t */\n\tidempotencyKey?: string\n}\n\nexport interface TaskResult {\n\t/** Task ID */\n\ttaskId: string\n\t/** QStash message ID */\n\tmessageId?: string\n\t/** Scheduled execution time */\n\tscheduledFor?: string\n}\n\nexport interface TaskStatus {\n\tid: string\n\tname?: string\n\tstatus: 'pending' | 'queued' | 'running' | 'completed' | 'failed' | 'cancelled'\n\tpayload?: Record<string, unknown>\n\tresult?: unknown\n\terror?: string\n\tcreatedAt: string\n\tqueuedAt?: string\n\tstartedAt?: string\n\tcompletedAt?: string\n}\n\nexport interface CronInput {\n\t/** Callback URL to call on each cron trigger */\n\tcallbackUrl: string\n\t/** Cron expression (e.g., '0 0 * * *' for daily at midnight) */\n\tcron: string\n\t/** Task name (required, max 200 chars) */\n\tname: string\n\t/** Task type for categorization */\n\ttype?: string\n\t/** Task payload sent to callback */\n\tpayload?: Record<string, unknown>\n\t/** HTTP method for callback (default: POST) */\n\tmethod?: 'GET' | 'POST' | 'PUT' | 'DELETE'\n\t/** Additional headers for callback */\n\theaders?: Record<string, string>\n\t/** Number of retries on failure (0-5, default: 3) */\n\tretries?: number\n\t/** Start in paused state */\n\tpaused?: boolean\n\t/**\n\t * Idempotency key for safe cron creation.\n\t *\n\t * When provided, prevents duplicate cron schedule creation if\n\t * the same key is used.\n\t */\n\tidempotencyKey?: string\n}\n\n// ============================================================================\n// Functions\n// ============================================================================\n\n/**\n * Schedule a one-time task for execution\n */\nexport async function scheduleTask(config: SylphxConfig, input: TaskInput): Promise<TaskResult> {\n\treturn callApi<TaskResult>(config, '/tasks/schedule', {\n\t\tmethod: 'POST',\n\t\tbody: input,\n\t})\n}\n\n/**\n * Get a task's status by ID\n */\nexport async function getTask(config: SylphxConfig, taskId: string): Promise<TaskStatus> {\n\treturn callApi<TaskStatus>(config, `/tasks/${taskId}`, { method: 'GET' })\n}\n\n/**\n * Cancel a pending task\n */\nexport async function cancelTask(config: SylphxConfig, taskId: string): Promise<boolean> {\n\tconst result = await callApi<{ success: boolean }>(config, `/tasks/${taskId}/cancel`, {\n\t\tmethod: 'POST',\n\t})\n\treturn result.success\n}\n\n/**\n * List tasks with optional filters\n */\nexport async function listTasks(\n\tconfig: SylphxConfig,\n\toptions?: { status?: TaskStatus['status']; limit?: number; offset?: number },\n): Promise<{ tasks: TaskStatus[]; total: number }> {\n\treturn callApi(config, '/tasks', {\n\t\tmethod: 'GET',\n\t\tquery: options as Record<string, string | number | undefined>,\n\t})\n}\n\n/**\n * Create a recurring cron task\n */\nexport async function createCron(config: SylphxConfig, input: CronInput): Promise<CronSchedule> {\n\treturn callApi<CronSchedule>(config, '/tasks/cron', {\n\t\tmethod: 'POST',\n\t\tbody: input,\n\t})\n}\n\n/**\n * Pause a cron schedule\n */\nexport async function pauseCron(config: SylphxConfig, scheduleId: string): Promise<boolean> {\n\tconst result = await callApi<{ success: boolean }>(config, `/tasks/cron/${scheduleId}/pause`, {\n\t\tmethod: 'POST',\n\t})\n\treturn result.success\n}\n\n/**\n * Resume a cron schedule\n */\nexport async function resumeCron(config: SylphxConfig, scheduleId: string): Promise<boolean> {\n\tconst result = await callApi<{ success: boolean }>(config, `/tasks/cron/${scheduleId}/resume`, {\n\t\tmethod: 'POST',\n\t})\n\treturn result.success\n}\n\n/**\n * Delete a cron schedule\n */\nexport async function deleteCron(config: SylphxConfig, scheduleId: string): Promise<boolean> {\n\tconst result = await callApi<{ success: boolean }>(config, `/tasks/cron/${scheduleId}`, {\n\t\tmethod: 'DELETE',\n\t})\n\treturn result.success\n}\n","/**\n * Feature Flags Functions\n *\n * Pure functions for feature flag evaluation.\n *\n * Pattern: LaunchDarkly/Statsig server-side evaluation\n * - Server-side: POST /flags/evaluate with context\n * - Returns evaluated results (enabled/disabled for this context)\n *\n * Types are derived from the OpenAPI spec (generated/api.d.ts).\n * Run `bun run generate:types:local` to regenerate after API changes.\n */\n\n// Type-only imports from @sylphx/contract per ADR-084 Rule 3 — prevents\n// Effect runtime types from leaking into the published .d.ts surface.\nimport type { EvaluateFlagsInput as ContractEvaluateFlagsInput } from '@sylphx/contract'\nimport { flagsEndpoints } from '@sylphx/contract'\nimport { callApi, type SylphxConfig } from './config'\n\n// ============================================================================\n// Types (SDK-specific - no direct API schema for flag results)\n// ============================================================================\n\nexport interface FlagResult {\n\t/** Flag key */\n\tkey: string\n\t/** Whether the flag is enabled for this context */\n\tenabled: boolean\n\t/** Variant value (for multivariate flags) */\n\tvariant?: string\n\t/** Reason for the evaluation result */\n\treason?: string\n\t/** Additional payload data */\n\tpayload?: Record<string, unknown>\n}\n\nexport interface FlagContext {\n\t/** User ID for consistent targeting */\n\tuserId?: string\n\t/** Anonymous ID for pre-auth targeting */\n\tanonymousId?: string\n\t/** User properties for targeting rules (plan, isAdmin, etc.) */\n\tproperties?: Record<string, unknown>\n}\n\n/** Response from the evaluate endpoint */\ninterface EvaluateFlagsResponse {\n\tdata: Record<string, FlagResult>\n}\n\n// ============================================================================\n// Functions\n// ============================================================================\n\n/**\n * Check a single feature flag (server-side evaluation)\n *\n * Uses POST /flags/evaluate for consistent, server-side targeting.\n * The server evaluates rollout percentage, premium targeting, etc.\n *\n * @example\n * ```typescript\n * const flag = await checkFlag(config, 'new-checkout', {\n * userId: 'user-123',\n * properties: { plan: 'pro' },\n * })\n *\n * if (flag.enabled) {\n * // Show new checkout\n * }\n * ```\n */\nexport async function checkFlag(\n\tconfig: SylphxConfig,\n\tflagKey: string,\n\tcontext?: FlagContext,\n): Promise<FlagResult> {\n\t// Contract-derived path/method (SSOT per ADR-084).\n\tconst endpoint = flagsEndpoints.evaluate\n\tconst body = {\n\t\tcontext: {\n\t\t\tuserId: context?.userId,\n\t\t\tanonymousId: context?.anonymousId,\n\t\t\tproperties: context?.properties,\n\t\t},\n\t\tkeys: [flagKey],\n\t} satisfies ContractEvaluateFlagsInput\n\tconst response = await callApi<EvaluateFlagsResponse>(config, endpoint.path, {\n\t\tmethod: endpoint.method,\n\t\tbody,\n\t})\n\n\t// Return the evaluated flag, or a disabled default if not found\n\treturn (\n\t\tresponse.data[flagKey] ?? {\n\t\t\tkey: flagKey,\n\t\t\tenabled: false,\n\t\t\treason: 'flag_not_found',\n\t\t}\n\t)\n}\n\n/**\n * Get multiple feature flags at once (batch evaluation)\n *\n * Evaluates all requested flags in a single API call.\n * More efficient than calling checkFlag() multiple times.\n *\n * @example\n * ```typescript\n * const flags = await getFlags(config, ['new-checkout', 'dark-mode', 'ai-features'], {\n * userId: 'user-123',\n * })\n *\n * if (flags['new-checkout'].enabled) {\n * // Show new checkout\n * }\n * ```\n */\nexport async function getFlags(\n\tconfig: SylphxConfig,\n\tflagKeys: string[],\n\tcontext?: FlagContext,\n): Promise<Record<string, FlagResult>> {\n\t// Contract-derived path/method (SSOT per ADR-084).\n\tconst endpoint = flagsEndpoints.evaluate\n\tconst body = {\n\t\tcontext: {\n\t\t\tuserId: context?.userId,\n\t\t\tanonymousId: context?.anonymousId,\n\t\t\tproperties: context?.properties,\n\t\t},\n\t\tkeys: flagKeys,\n\t} satisfies ContractEvaluateFlagsInput\n\tconst response = await callApi<EvaluateFlagsResponse>(config, endpoint.path, {\n\t\tmethod: endpoint.method,\n\t\tbody,\n\t})\n\n\treturn response.data\n}\n\n/**\n * Get all feature flags for a context (bootstrap)\n *\n * Evaluates ALL flags for the app in a single API call.\n * Useful for bootstrapping the flag state on app load.\n *\n * @example\n * ```typescript\n * // Bootstrap all flags on app load\n * const allFlags = await getAllFlags(config, { userId: 'user-123' })\n *\n * // Use throughout the app\n * if (allFlags['new-checkout']?.enabled) {\n * // Show new checkout\n * }\n * ```\n */\nexport async function getAllFlags(\n\tconfig: SylphxConfig,\n\tcontext?: FlagContext,\n): Promise<Record<string, FlagResult>> {\n\t// Contract-derived path/method (SSOT per ADR-084).\n\tconst endpoint = flagsEndpoints.evaluate\n\tconst body = {\n\t\tcontext: {\n\t\t\tuserId: context?.userId,\n\t\t\tanonymousId: context?.anonymousId,\n\t\t\tproperties: context?.properties,\n\t\t},\n\t\t// Omit keys to get all flags\n\t} satisfies ContractEvaluateFlagsInput\n\tconst response = await callApi<EvaluateFlagsResponse>(config, endpoint.path, {\n\t\tmethod: endpoint.method,\n\t\tbody,\n\t})\n\n\treturn response.data\n}\n\n/**\n * Check if a flag is enabled (boolean helper)\n *\n * @example\n * ```typescript\n * if (await isEnabled(config, 'new-checkout', { userId: 'user-123' })) {\n * // Show new checkout\n * }\n * ```\n */\nexport async function isEnabled(\n\tconfig: SylphxConfig,\n\tflagKey: string,\n\tcontext?: FlagContext,\n): Promise<boolean> {\n\tconst flag = await checkFlag(config, flagKey, context)\n\treturn flag.enabled\n}\n\n/**\n * Get flag variant (for A/B tests)\n *\n * @example\n * ```typescript\n * const variant = await getVariant(config, 'checkout-experiment', {\n * userId: 'user-123',\n * })\n *\n * switch (variant) {\n * case 'control':\n * // Show original checkout\n * break\n * case 'variant-a':\n * // Show variant A\n * break\n * case 'variant-b':\n * // Show variant B\n * break\n * }\n * ```\n */\nexport async function getVariant(\n\tconfig: SylphxConfig,\n\tflagKey: string,\n\tcontext?: FlagContext,\n): Promise<string | undefined> {\n\tconst flag = await checkFlag(config, flagKey, context)\n\treturn flag.variant\n}\n\n/**\n * Get flag payload (for remote config)\n *\n * @example\n * ```typescript\n * const payload = await getFlagPayload<{ maxItems: number }>(config, 'cart-config', {\n * userId: 'user-123',\n * })\n *\n * console.log(payload?.maxItems) // 10\n * ```\n */\nexport async function getFlagPayload<T extends Record<string, unknown>>(\n\tconfig: SylphxConfig,\n\tflagKey: string,\n\tcontext?: FlagContext,\n): Promise<T | undefined> {\n\tconst flag = await checkFlag(config, flagKey, context)\n\treturn flag.payload as T | undefined\n}\n","/**\n * Webhooks Functions\n *\n * Pure functions for webhook configuration and delivery management.\n *\n * Wire-shape types are re-exported from `@sylphx/contract` (ADR-084). The\n * contract is the single source of truth for every `/webhooks/*` endpoint\n * under the Console / Management plane. This module keeps a handful of\n * SDK-specific ergonomic envelopes (`WebhookConfig`, `WebhookEnvironment`,\n * `WebhookStats`, `WebhookConfigUpdate`, `ListDeliveriesOptions`,\n * `WebhookDeliveriesResult`) that are looser or richer than the strict\n * contract shapes — they predate the contract and stay put to avoid\n * breaking downstream consumers (SDK tests, apps/web hooks layer).\n */\n\n// Type-only imports from @sylphx/contract per ADR-084 Rule 3 — prevents\n// Effect runtime types from leaking into the published .d.ts surface.\nimport type {\n\tGetWebhookConfigResult,\n\tListWebhookDeliveriesResult,\n\tReplayDeliveryResult,\n\tUpdateWebhookConfigInput,\n\tUpdateWebhookConfigResult,\n\tWebhookDelivery as ContractWebhookDelivery,\n\tWebhookEnvironment as ContractWebhookEnvironment,\n\tWebhookStatsResult,\n} from '@sylphx/contract'\nimport { callApi, type SylphxConfig } from './config'\n\n// ============================================================================\n// Types (re-exported from @sylphx/contract)\n// ============================================================================\n\nexport type WebhookConfigResponse = GetWebhookConfigResult\nexport type WebhookEnvironmentConfig = ContractWebhookEnvironment\nexport type UpdateWebhookConfigRequest = UpdateWebhookConfigInput\nexport type UpdateWebhookConfigResponse = UpdateWebhookConfigResult\nexport type ListWebhookDeliveriesResponse = ListWebhookDeliveriesResult\nexport type WebhookDelivery = ContractWebhookDelivery\nexport type ReplayDeliveryResponse = ReplayDeliveryResult\nexport type WebhookStatsResponse = WebhookStatsResult\n\n// SDK-specific types for convenience\nexport interface WebhookEnvironment {\n\tid: string\n\tname: string\n\twebhookUrl: string | null\n\twebhookSecret?: string | null\n\thasSecret?: boolean\n\tevents?: string[]\n\tcreatedAt: string\n\tupdatedAt: string | null\n}\n\nexport interface WebhookConfig {\n\tenvironments: WebhookEnvironment[]\n\tsupportedEvents?: string[]\n\tenabled?: boolean\n\turl?: string | null\n\tsecret?: string | null\n\tevents?: string[]\n}\n\nexport interface WebhookConfigUpdate {\n\tenvironmentId: string\n\twebhookUrl: string | null\n}\n\nexport interface WebhookDeliveriesResult {\n\tdeliveries: WebhookDelivery[]\n\ttotal: number\n\thasMore: boolean\n}\n\nexport interface WebhookStats {\n\t// Summary totals\n\ttotal: number\n\tdelivered: number\n\tfailed: number\n\tpending: number\n\tdeliveryRate: number\n\tavgLatencyMs: number | null\n\t// Extended stats (for UI)\n\tperiod?: string\n\ttotals?: {\n\t\ttotal: number\n\t\tdelivered: number\n\t\tfailed: number\n\t\tpending: number\n\t\tdeliveryRate: number | string\n\t}\n\tbyEvent?: Array<{ event: string; count: number }>\n\tbyStatus?: Array<{ status: string; count: number }>\n}\n\nexport interface ListDeliveriesOptions {\n\tenvironmentId?: string\n\tstatus?: 'pending' | 'queued' | 'delivered' | 'failed'\n\tlimit?: number\n\toffset?: number\n}\n\n// ============================================================================\n// Functions\n// ============================================================================\n\n/**\n * Get webhook configuration for the app\n *\n * @example\n * ```typescript\n * const config = await getWebhookConfig(sylphxConfig)\n * console.log(config.environments)\n * ```\n */\nexport async function getWebhookConfig(config: SylphxConfig): Promise<WebhookConfig> {\n\treturn callApi(config, '/webhooks/config', { method: 'GET' })\n}\n\n/**\n * Update webhook URL for an environment\n *\n * @example\n * ```typescript\n * await updateWebhookConfig(config, {\n * environmentId: 'env-123',\n * webhookUrl: 'https://myapp.com/webhooks',\n * })\n * ```\n */\nexport async function updateWebhookConfig(\n\tconfig: SylphxConfig,\n\tdata: WebhookConfigUpdate,\n): Promise<void> {\n\treturn callApi(config, '/webhooks/config', { method: 'PUT', body: data })\n}\n\n/**\n * Get webhook delivery history\n *\n * @example\n * ```typescript\n * const { deliveries, total } = await getWebhookDeliveries(config, {\n * status: 'failed',\n * limit: 20,\n * })\n * ```\n */\nexport async function getWebhookDeliveries(\n\tconfig: SylphxConfig,\n\toptions?: ListDeliveriesOptions,\n): Promise<WebhookDeliveriesResult> {\n\treturn callApi(config, '/webhooks/deliveries', {\n\t\tmethod: 'GET',\n\t\tquery: options as Record<string, string | number | undefined>,\n\t})\n}\n\n/**\n * Get a single webhook delivery by ID\n *\n * @example\n * ```typescript\n * const delivery = await getWebhookDelivery(config, 'del-123')\n * console.log(delivery.payload)\n * ```\n */\nexport async function getWebhookDelivery(\n\tconfig: SylphxConfig,\n\tdeliveryId: string,\n): Promise<WebhookDelivery> {\n\treturn callApi(config, `/webhooks/deliveries/${deliveryId}`, {\n\t\tmethod: 'GET',\n\t})\n}\n\n/**\n * Replay a failed webhook delivery\n *\n * @example\n * ```typescript\n * await replayWebhookDelivery(config, 'del-123')\n * ```\n */\nexport async function replayWebhookDelivery(\n\tconfig: SylphxConfig,\n\tdeliveryId: string,\n): Promise<void> {\n\treturn callApi(config, `/webhooks/deliveries/${deliveryId}/replay`, {\n\t\tmethod: 'POST',\n\t})\n}\n\n/**\n * Get webhook statistics\n *\n * @example\n * ```typescript\n * const stats = await getWebhookStats(config)\n * console.log(`Delivery rate: ${stats.deliveryRate}%`)\n * ```\n */\nexport async function getWebhookStats(\n\tconfig: SylphxConfig,\n\tenvironmentId?: string,\n): Promise<WebhookStats> {\n\treturn callApi(config, '/webhooks/stats', {\n\t\tmethod: 'GET',\n\t\tquery: environmentId ? { environmentId } : undefined,\n\t})\n}\n","/**\n * Email Functions\n *\n * Pure functions for transactional email operations.\n *\n * Wire-shape types are re-exported from `@sylphx/contract` (ADR-084). The\n * contract is the single source of truth for `/email/configured`,\n * `/email/send`, `/email/send-templated`, and `/email/send-to-user`. SDK-\n * specific convenience shapes (scheduling options, domain management) stay\n * local — their routes are served by the Console plane and live alongside\n * the BaaS `emailEndpoints` in the contract's `emailAdmin` namespace.\n */\n\n// Type-only imports from @sylphx/contract per ADR-084 Rule 3 — prevents\n// Effect runtime types from leaking into the published .d.ts surface.\nimport type {\n\tSendEmailInput as ContractSendEmailInput,\n\tSendEmailResult as ContractSendEmailResult,\n\tSendEmailToUserInput as ContractSendEmailToUserInput,\n\tSendTemplatedEmailInput as ContractSendTemplatedEmailInput,\n} from '@sylphx/contract'\nimport { emailEndpoints } from '@sylphx/contract'\nimport { callApi, type SylphxConfig } from './config'\n\n// ============================================================================\n// Types (re-exported from @sylphx/contract)\n// ============================================================================\n\nexport type { ContractSendEmailInput as SendEmailRequest }\nexport type { ContractSendEmailResult as SendEmailResponse }\nexport type { ContractSendTemplatedEmailInput as SendTemplatedEmailRequest }\nexport type { ContractSendEmailResult as SendTemplatedEmailResponse }\nexport type { ContractSendEmailToUserInput as SendToUserRequest }\nexport type { ContractSendEmailResult as SendToUserResponse }\n\n// SDK-specific types for convenience\nexport interface SendEmailOptions {\n\t/** Recipient email address */\n\tto: string\n\t/** Email subject line */\n\tsubject: string\n\t/** HTML content */\n\thtml: string\n\t/** Plain text content (optional fallback) */\n\ttext?: string\n\t/** Reply-to address */\n\treplyTo?: string\n\t/**\n\t * Sender email address (must be from a verified domain).\n\t * Falls back to the app environment default, then the platform FROM_EMAIL.\n\t *\n\t * @example `support@yourdomain.com`\n\t */\n\tfromEmail?: string\n\t/**\n\t * Sender display name (used together with fromEmail).\n\t *\n\t * @example `Acme Support`\n\t */\n\tfromName?: string\n\t/**\n\t * Idempotency key for safe retries (Stripe pattern)\n\t *\n\t * When provided, prevents duplicate email sends if the same request\n\t * is retried within 24 hours. Use a unique key per logical operation.\n\t *\n\t * @example `welcome-email-${userId}`\n\t */\n\tidempotencyKey?: string\n\t/**\n\t * Custom email headers passed directly to the provider.\n\t * Use for email threading (In-Reply-To, References) or other RFC 5322 headers.\n\t * Do not override From, To, or Subject here.\n\t *\n\t * @example `{ 'In-Reply-To': '<abc@cubeage.com>', References: '<abc@cubeage.com>' }`\n\t */\n\theaders?: Record<string, string>\n}\n\nexport interface SendTemplatedEmailOptions {\n\t/** Template name: 'welcome', 'verification', 'password_reset', 'security_alert' */\n\ttemplate: 'welcome' | 'verification' | 'password_reset' | 'security_alert'\n\t/** Recipient email address */\n\tto: string\n\t/** Template variables */\n\tdata?: Record<string, unknown>\n\t/**\n\t * Idempotency key for safe retries (Stripe pattern)\n\t *\n\t * @example `verification-email-${userId}`\n\t */\n\tidempotencyKey?: string\n}\n\nexport interface SendToUserOptions {\n\t/** User ID to send to */\n\tuserId: string\n\t/** Email subject line */\n\tsubject: string\n\t/** HTML content */\n\thtml: string\n\t/** Plain text content (optional fallback) */\n\ttext?: string\n\t/**\n\t * Idempotency key for safe retries (Stripe pattern)\n\t *\n\t * @example `notification-${userId}-${Date.now()}`\n\t */\n\tidempotencyKey?: string\n}\n\nexport interface ScheduleEmailOptions {\n\t/** Recipient email address */\n\tto: string\n\t/** Recipient name (optional) */\n\ttoName?: string\n\t/** Email subject line */\n\tsubject: string\n\t/** HTML content */\n\thtml?: string\n\t/** Plain text content */\n\ttext?: string\n\t/** Reply-to address */\n\treplyTo?: string\n\t/** From email (defaults to app's configured sender) */\n\tfromEmail?: string\n\t/** From name */\n\tfromName?: string\n\t/** ISO timestamp for when to send */\n\tscheduledFor: string\n\t/** Template key for templated emails */\n\ttemplateKey?: string\n\t/** Template variables */\n\ttemplateData?: Record<string, unknown>\n\t/** Idempotency key to prevent duplicates */\n\tidempotencyKey?: string\n\t/** Custom metadata */\n\tmetadata?: Record<string, unknown>\n}\n\nexport interface ScheduledEmail {\n\tid: string\n\tto: string\n\ttoName: string | null\n\tsubject: string\n\tstatus: 'pending' | 'queued' | 'sent' | 'cancelled' | 'failed'\n\tscheduledFor: string\n\tsentAt: string | null\n\tcreatedAt: string\n}\n\nexport interface ScheduledEmailsResult {\n\temails: ScheduledEmail[]\n\ttotal: number\n\thasMore: boolean\n}\n\nexport interface ScheduledEmailStats {\n\ttotal: number\n\tpending: number\n\tqueued: number\n\tsent: number\n\tcancelled: number\n\tfailed: number\n}\n\nexport interface ListScheduledEmailsOptions {\n\tstatus?: 'pending' | 'queued' | 'sent' | 'cancelled' | 'failed' | 'all'\n\tlimit?: number\n\toffset?: number\n}\n\nexport interface SendResult {\n\tid: string\n\tsuccess: boolean\n}\n\n// ============================================================================\n// Functions\n// ============================================================================\n\n/**\n * Check if email service is configured for the app\n *\n * @example\n * ```typescript\n * const configured = await isEmailConfigured(config)\n * if (!configured) console.log('Please configure email settings')\n * ```\n */\nexport async function isEmailConfigured(config: SylphxConfig): Promise<boolean> {\n\t// Contract-derived path/method (SSOT per ADR-084).\n\tconst endpoint = emailEndpoints.isConfigured\n\treturn callApi(config, endpoint.path, { method: endpoint.method })\n}\n\n/**\n * Send a custom email\n *\n * @example\n * ```typescript\n * const result = await sendEmail(config, {\n * to: 'user@example.com',\n * subject: 'Hello!',\n * html: '<p>Welcome to our app!</p>',\n * idempotencyKey: `welcome-${userId}`, // Safe retry\n * })\n * ```\n */\nexport async function sendEmail(\n\tconfig: SylphxConfig,\n\toptions: SendEmailOptions,\n): Promise<SendResult> {\n\t// Contract-derived path/method (SSOT per ADR-084).\n\t// TODO ADR-084 shape reconcile: SDK's `SendEmailOptions` is a superset\n\t// of contract's `SendEmailInput` — SDK exposes `html` as required while\n\t// server accepts broader templating. Contract is tightened subset.\n\tconst { idempotencyKey, ...body } = options\n\tconst endpoint = emailEndpoints.send\n\treturn callApi<ContractSendEmailResult>(config, endpoint.path, {\n\t\tmethod: endpoint.method,\n\t\tbody: body as ContractSendEmailInput,\n\t\tidempotencyKey,\n\t})\n}\n\n/**\n * Send a templated email\n *\n * @example\n * ```typescript\n * await sendTemplatedEmail(config, {\n * template: 'welcome',\n * to: 'user@example.com',\n * data: { name: 'John' },\n * idempotencyKey: `welcome-${userId}`, // Safe retry\n * })\n * ```\n */\nexport async function sendTemplatedEmail(\n\tconfig: SylphxConfig,\n\toptions: SendTemplatedEmailOptions,\n): Promise<SendResult> {\n\t// Contract-derived path/method (SSOT per ADR-084).\n\tconst { idempotencyKey, ...body } = options\n\tconst endpoint = emailEndpoints.sendTemplated\n\treturn callApi<ContractSendEmailResult>(config, endpoint.path, {\n\t\tmethod: endpoint.method,\n\t\tbody: body satisfies ContractSendTemplatedEmailInput,\n\t\tidempotencyKey,\n\t})\n}\n\n/**\n * Send email to a user by their ID\n *\n * @example\n * ```typescript\n * await sendEmailToUser(config, {\n * userId: 'user-123',\n * subject: 'Account Update',\n * html: '<p>Your account has been updated.</p>',\n * idempotencyKey: `update-${userId}-${timestamp}`, // Safe retry\n * })\n * ```\n */\nexport async function sendEmailToUser(\n\tconfig: SylphxConfig,\n\toptions: SendToUserOptions,\n): Promise<SendResult> {\n\t// Contract-derived path/method (SSOT per ADR-084).\n\tconst { idempotencyKey, ...body } = options\n\tconst endpoint = emailEndpoints.sendToUser\n\treturn callApi<ContractSendEmailResult>(config, endpoint.path, {\n\t\tmethod: endpoint.method,\n\t\tbody: body satisfies ContractSendEmailToUserInput,\n\t\tidempotencyKey,\n\t})\n}\n\n/**\n * Schedule an email for future delivery\n *\n * @example\n * ```typescript\n * const scheduled = await scheduleEmail(config, {\n * to: 'user@example.com',\n * subject: 'Reminder',\n * html: '<p>Don\\'t forget!</p>',\n * scheduledFor: new Date(Date.now() + 86400000).toISOString(), // 24 hours\n * })\n * ```\n */\nexport async function scheduleEmail(\n\tconfig: SylphxConfig,\n\toptions: ScheduleEmailOptions,\n): Promise<ScheduledEmail> {\n\treturn callApi(config, '/email/schedule', { method: 'POST', body: options })\n}\n\n/**\n * List scheduled emails\n *\n * @example\n * ```typescript\n * const { emails, total } = await listScheduledEmails(config, {\n * status: 'pending',\n * limit: 20,\n * })\n * ```\n */\nexport async function listScheduledEmails(\n\tconfig: SylphxConfig,\n\toptions?: ListScheduledEmailsOptions,\n): Promise<ScheduledEmailsResult> {\n\treturn callApi(config, '/email/scheduled', {\n\t\tmethod: 'GET',\n\t\tquery: options as Record<string, string | number | undefined>,\n\t})\n}\n\n/**\n * Get a scheduled email by ID\n *\n * @example\n * ```typescript\n * const email = await getScheduledEmail(config, 'email-123')\n * console.log(email.status)\n * ```\n */\nexport async function getScheduledEmail(\n\tconfig: SylphxConfig,\n\temailId: string,\n): Promise<ScheduledEmail> {\n\treturn callApi(config, `/email/scheduled/${emailId}`, { method: 'GET' })\n}\n\n/**\n * Cancel a scheduled email\n *\n * @example\n * ```typescript\n * await cancelScheduledEmail(config, 'email-123')\n * ```\n */\nexport async function cancelScheduledEmail(config: SylphxConfig, emailId: string): Promise<void> {\n\treturn callApi(config, `/email/scheduled/${emailId}/cancel`, {\n\t\tmethod: 'POST',\n\t})\n}\n\n/**\n * Reschedule an email\n *\n * @example\n * ```typescript\n * await rescheduleEmail(config, 'email-123', new Date(Date.now() + 3600000).toISOString())\n * ```\n */\nexport async function rescheduleEmail(\n\tconfig: SylphxConfig,\n\temailId: string,\n\tscheduledFor: string,\n): Promise<ScheduledEmail> {\n\treturn callApi(config, `/email/scheduled/${emailId}/reschedule`, {\n\t\tmethod: 'POST',\n\t\tbody: { scheduledFor },\n\t})\n}\n\n/**\n * Get scheduled email statistics\n *\n * @example\n * ```typescript\n * const stats = await getScheduledEmailStats(config)\n * console.log(`${stats.pending} emails pending`)\n * ```\n */\nexport async function getScheduledEmailStats(config: SylphxConfig): Promise<ScheduledEmailStats> {\n\treturn callApi(config, '/email/scheduled/stats', { method: 'GET' })\n}\n\n// ============================================================================\n// Email Domain Management\n// ============================================================================\n\n/**\n * DNS record required for domain verification\n */\nexport interface DnsRecord {\n\t/** DNS record type */\n\ttype: 'MX' | 'TXT' | 'CNAME'\n\t/** DNS record name (hostname) */\n\tname: string\n\t/** DNS record value */\n\tvalue: string\n\t/** MX priority (only for MX records) */\n\tpriority?: number\n\t/** TTL in seconds */\n\tttl: number\n}\n\n/**\n * A registered custom sending domain\n */\nexport interface EmailDomain {\n\tid: string\n\tdomain: string\n\tstatus: 'pending' | 'verifying' | 'verified' | 'failed'\n\tdefaultFromEmail: string | null\n\tdefaultFromName: string | null\n\tdnsRecords: DnsRecord[]\n\tcreatedAt: string\n\tverifiedAt: string | null\n}\n\nexport interface RegisterEmailDomainOptions {\n\t/** Default from address for this domain (e.g. support@cubeage.com) */\n\tdefaultFromEmail?: string\n\t/** Default sender display name (e.g. Cubeage Support) */\n\tdefaultFromName?: string\n}\n\nexport interface SetDefaultEmailDomainOptions {\n\t/** Override the default from address */\n\tdefaultFromEmail?: string\n\t/** Override the default sender name */\n\tdefaultFromName?: string\n}\n\n/**\n * Register a custom sending domain\n *\n * Enables email sending for this domain. Returns DNS records to add to your DNS provider.\n * After adding DNS records, call verifyEmailDomain to confirm ownership.\n *\n * @example\n * ```typescript\n * const domain = await registerEmailDomain(config, 'cubeage.com', {\n * defaultFromEmail: 'support@cubeage.com',\n * defaultFromName: 'Cubeage Support',\n * })\n * console.log('Add these DNS records:', domain.dnsRecords)\n * ```\n */\nexport async function registerEmailDomain(\n\tconfig: SylphxConfig,\n\tdomain: string,\n\topts?: RegisterEmailDomainOptions,\n): Promise<EmailDomain> {\n\treturn callApi(config, '/email/domains', {\n\t\tmethod: 'POST',\n\t\tbody: { domain, ...opts },\n\t})\n}\n\n/**\n * List all custom sending domains for this app\n *\n * @example\n * ```typescript\n * const { domains } = await listEmailDomains(config)\n * for (const d of domains) {\n * console.log(d.domain, d.status)\n * }\n * ```\n */\nexport async function listEmailDomains(config: SylphxConfig): Promise<{ domains: EmailDomain[] }> {\n\treturn callApi(config, '/email/domains', { method: 'GET' })\n}\n\n/**\n * Get a specific domain by ID\n *\n * @example\n * ```typescript\n * const domain = await getEmailDomain(config, 'domain-uuid')\n * console.log(domain.dnsRecords)\n * ```\n */\nexport async function getEmailDomain(config: SylphxConfig, domainId: string): Promise<EmailDomain> {\n\treturn callApi(config, `/email/domains/${domainId}`, { method: 'GET' })\n}\n\n/**\n * Delete a custom sending domain\n *\n * Disables email sending for this domain and removes DKIM signing configuration.\n *\n * @example\n * ```typescript\n * await deleteEmailDomain(config, 'domain-uuid')\n * ```\n */\nexport async function deleteEmailDomain(config: SylphxConfig, domainId: string): Promise<void> {\n\treturn callApi(config, `/email/domains/${domainId}`, { method: 'DELETE' })\n}\n\n/**\n * Trigger DNS verification for a domain\n *\n * Checks if your DNS records have propagated. Status changes to 'verified' when DKIM is confirmed.\n * Status changes to 'verified' on success or 'failed' on error.\n *\n * @example\n * ```typescript\n * const domain = await verifyEmailDomain(config, 'domain-uuid')\n * if (domain.status === 'verified') {\n * console.log('Domain verified!')\n * }\n * ```\n */\nexport async function verifyEmailDomain(\n\tconfig: SylphxConfig,\n\tdomainId: string,\n): Promise<EmailDomain> {\n\treturn callApi(config, `/email/domains/${domainId}/verify`, {\n\t\tmethod: 'POST',\n\t})\n}\n\n/**\n * Set a domain as the default sender for this app\n *\n * @example\n * ```typescript\n * const domain = await setDefaultEmailDomain(config, 'domain-uuid', {\n * defaultFromEmail: 'support@cubeage.com',\n * defaultFromName: 'Cubeage Support',\n * })\n * ```\n */\nexport async function setDefaultEmailDomain(\n\tconfig: SylphxConfig,\n\tdomainId: string,\n\topts?: SetDefaultEmailDomainOptions,\n): Promise<EmailDomain> {\n\treturn callApi(config, `/email/domains/${domainId}/set-default`, {\n\t\tmethod: 'POST',\n\t\tbody: opts ?? {},\n\t})\n}\n","/**\n * Consent Functions\n *\n * Pure functions for GDPR/CCPA consent management.\n *\n * ## Architecture (ADR-004)\n *\n * Consent uses **Inline Defaults + Auto-Discovery + Console Override**:\n * - Code provides optional inline defaults when checking consent\n * - Platform auto-discovers/creates consent types when first referenced\n * - Console can override names, descriptions, requirements without deployment\n *\n * Wire-shape types are re-exported from `@sylphx/contract` (ADR-084). The\n * contract is the single source of truth for `GET /consent/types`,\n * `GET /consent`, `POST /consent`, and friends. SDK-specific input types\n * (history pagination, anonymous linking) remain local — they describe\n * ergonomic helpers on top of the wire shapes rather than the wire\n * shapes themselves.\n *\n * @example\n * ```typescript\n * import { hasConsent, getUserConsents, setConsents } from '@sylphx/sdk'\n *\n * // Check consent with inline defaults (auto-discovered if doesn't exist)\n * if (await hasConsent(config, 'analytics', { userId: 'user-123' }, {\n * name: 'Analytics Cookies',\n * description: 'Help us understand how visitors use our site',\n * category: 'analytics',\n * required: false,\n * })) {\n * track('pageview')\n * }\n *\n * // Get user's current consents\n * const consents = await getUserConsents(config, { userId: 'user-123' })\n *\n * // Set specific consents\n * await setConsents(config, {\n * userId: 'user-123',\n * consents: { analytics: true, marketing: false }\n * })\n * ```\n */\n\n// Type-only imports from @sylphx/contract per ADR-084 Rule 3 — prevents\n// Effect runtime types from leaking into the published .d.ts surface.\nimport type {\n\tSdkConsentType as ContractConsentType,\n\tSetConsentsRequest as ContractSetConsentsRequest,\n\tSetConsentsResponse as ContractSetConsentsResponse,\n\tUserConsent as ContractUserConsent,\n} from '@sylphx/contract'\nimport { callApi, type SylphxConfig } from './config'\n\n// ============================================================================\n// Types (re-exported from @sylphx/contract)\n// ============================================================================\n\nexport type ConsentType = ContractConsentType\nexport type UserConsent = ContractUserConsent\nexport type SetConsentRequest = ContractSetConsentsRequest\nexport type SetConsentResponse = ContractSetConsentsResponse\n\n// SDK-specific types (not directly from API schema)\n/** Consent category for grouping */\nexport type ConsentCategory = 'necessary' | 'analytics' | 'marketing' | 'functional' | 'preferences'\n\nexport interface SetConsentsInput {\n\t/** User ID (optional for anonymous users) */\n\tuserId?: string\n\t/** Anonymous ID (for guest users) */\n\tanonymousId?: string\n\t/** Consent settings by type slug */\n\tconsents: Record<string, boolean>\n}\n\nexport interface LinkAnonymousConsentsInput {\n\t/** The authenticated user ID to link to */\n\tuserId: string\n\t/** The anonymous ID whose consents should be linked */\n\tanonymousId: string\n}\n\nexport interface GetConsentHistoryInput {\n\t/** User ID (for authenticated users) */\n\tuserId?: string\n\t/** Anonymous ID (for anonymous users) */\n\tanonymousId?: string\n\t/** Maximum records to return (default: 50) */\n\tlimit?: number\n\t/**\n\t * Opaque pagination cursor returned by a previous response.\n\t * Omit (or pass undefined) to fetch the first page.\n\t */\n\tcursor?: string\n}\n\n/** A single consent change history entry */\nexport interface ConsentHistoryEntry {\n\t/** Unique entry ID */\n\tid: string\n\t/** Consent type slug (e.g., 'analytics') */\n\tconsentType: string\n\t/** Display name of the consent type */\n\tconsentTypeName: string\n\t/** Previous consent state (null = initial consent) */\n\tpreviousGranted: boolean | null\n\t/** New consent state */\n\tnewGranted: boolean\n\t/** Source of the change (banner, settings, api) */\n\tsource: string\n\t/** Reason for change (user_action, policy_update, etc.) */\n\treason: string | null\n\t/** ISO timestamp when change occurred */\n\tcreatedAt: string\n}\n\nexport interface ConsentHistoryResult {\n\t/** List of consent change entries */\n\tentries: ConsentHistoryEntry[]\n\t/**\n\t * Opaque cursor for the next page. Pass as `cursor` to the next call.\n\t * Null when this is the last page.\n\t */\n\tnextCursor: string | null\n\t/** Whether there are more entries */\n\thasMore: boolean\n}\n\nexport interface GetConsentsInput {\n\t/** User ID (optional for anonymous users) */\n\tuserId?: string\n\t/** Anonymous ID (for guest users) */\n\tanonymousId?: string\n}\n\n/**\n * Inline defaults for consent purpose auto-discovery\n *\n * @example\n * ```typescript\n * await hasConsent(config, 'analytics', { userId: 'user-123' }, {\n * name: 'Analytics Cookies',\n * description: 'Help us understand how visitors use our site',\n * category: 'analytics',\n * required: false,\n * })\n * ```\n */\nexport interface ConsentPurposeDefaults {\n\t/** Display name */\n\tname?: string\n\t/** Description */\n\tdescription?: string\n\t/** Category */\n\tcategory?: ConsentCategory\n\t/** Whether consent is required (always granted) */\n\trequired?: boolean\n\t/** Whether enabled by default */\n\tdefaultEnabled?: boolean\n\t/** Sort order in UI */\n\tsortOrder?: number\n}\n\n// ============================================================================\n// Functions\n// ============================================================================\n\n/**\n * Get all consent types configured for the app\n *\n * Returns GDPR-standard defaults if none configured.\n *\n * @example\n * ```typescript\n * const types = await getConsentTypes(config)\n * types.forEach(t => console.log(`${t.name}: ${t.required ? 'Required' : 'Optional'}`))\n * ```\n */\nexport async function getConsentTypes(config: SylphxConfig): Promise<ConsentType[]> {\n\treturn callApi(config, '/consent/types', { method: 'GET' })\n}\n\n/**\n * Check if user has granted consent for a specific purpose\n *\n * If the consent type doesn't exist, it will be auto-discovered with the provided defaults.\n * Console can override any values without deployment.\n *\n * @param config - SDK configuration\n * @param purposeSlug - Consent purpose slug (e.g., 'analytics', 'marketing')\n * @param input - User identification (userId or anonymousId)\n * @param defaults - Optional inline defaults for auto-discovery\n * @returns Whether consent is granted\n *\n * @example\n * ```typescript\n * // Check analytics consent with inline defaults\n * if (await hasConsent(config, 'analytics', { userId: 'user-123' }, {\n * name: 'Analytics Cookies',\n * description: 'Help us understand how visitors use our site',\n * category: 'analytics',\n * required: false,\n * })) {\n * track('pageview')\n * }\n *\n * // Required consent always returns true\n * const hasNecessary = await hasConsent(config, 'necessary', { userId }, {\n * name: 'Essential Cookies',\n * description: 'Required for the website to function',\n * category: 'necessary',\n * required: true,\n * })\n * ```\n */\nexport async function hasConsent(\n\tconfig: SylphxConfig,\n\tpurposeSlug: string,\n\tinput: GetConsentsInput,\n\tdefaults?: ConsentPurposeDefaults,\n): Promise<boolean> {\n\treturn callApi(config, '/consent/check', {\n\t\tmethod: 'POST',\n\t\tbody: { purposeSlug, ...input, defaults },\n\t})\n}\n\n/**\n * Get user's current consent settings\n *\n * @example\n * ```typescript\n * // For authenticated user\n * const consents = await getUserConsents(config, { userId: 'user-123' })\n *\n * // For anonymous user\n * const consents = await getUserConsents(config, { anonymousId: 'anon-456' })\n * ```\n */\nexport async function getUserConsents(\n\tconfig: SylphxConfig,\n\tinput: GetConsentsInput,\n): Promise<UserConsent[]> {\n\treturn callApi(config, '/consent/user', {\n\t\tmethod: 'GET',\n\t\tquery: input as Record<string, string | undefined>,\n\t})\n}\n\n/**\n * Set user's consent preferences\n *\n * @example\n * ```typescript\n * await setConsents(config, {\n * userId: 'user-123',\n * consents: {\n * analytics: true,\n * marketing: false,\n * },\n * })\n * ```\n */\nexport async function setConsents(config: SylphxConfig, input: SetConsentsInput): Promise<void> {\n\treturn callApi(config, '/consent/set', { method: 'POST', body: input })\n}\n\n/**\n * Accept all consent types\n *\n * @example\n * ```typescript\n * await acceptAllConsents(config, { userId: 'user-123' })\n * ```\n */\nexport async function acceptAllConsents(\n\tconfig: SylphxConfig,\n\tinput: GetConsentsInput,\n): Promise<void> {\n\treturn callApi(config, '/consent/accept-all', {\n\t\tmethod: 'POST',\n\t\tbody: input,\n\t})\n}\n\n/**\n * Decline all optional consent types (keeps required ones)\n *\n * @example\n * ```typescript\n * await declineOptionalConsents(config, { anonymousId: 'anon-456' })\n * ```\n */\nexport async function declineOptionalConsents(\n\tconfig: SylphxConfig,\n\tinput: GetConsentsInput,\n): Promise<void> {\n\treturn callApi(config, '/consent/decline-optional', {\n\t\tmethod: 'POST',\n\t\tbody: input,\n\t})\n}\n\n/**\n * Link anonymous user's consents to authenticated user\n *\n * Call this after user signs up/logs in to merge their anonymous consent history.\n *\n * @example\n * ```typescript\n * await linkAnonymousConsents(config, {\n * userId: 'user-123',\n * anonymousId: 'anon-456',\n * })\n * ```\n */\nexport async function linkAnonymousConsents(\n\tconfig: SylphxConfig,\n\tinput: LinkAnonymousConsentsInput,\n): Promise<void> {\n\treturn callApi(config, '/consent/link-anonymous', {\n\t\tmethod: 'POST',\n\t\tbody: input,\n\t})\n}\n\n/**\n * Get consent change history for GDPR audit trail\n *\n * Returns a paginated list of all consent state changes for a user.\n * Required for GDPR compliance - provides complete audit trail of consent decisions.\n *\n * @example\n * ```typescript\n * // Get consent history for authenticated user (first page)\n * const history = await getConsentHistory(config, { userId: 'user-123', limit: 20 })\n * history.entries.forEach(entry => {\n * console.log(`${entry.consentType}: ${entry.previousGranted} → ${entry.newGranted}`)\n * })\n *\n * // Fetch next page using the cursor\n * if (history.nextCursor) {\n * const page2 = await getConsentHistory(config, {\n * userId: 'user-123',\n * limit: 20,\n * cursor: history.nextCursor,\n * })\n * }\n * ```\n */\nexport async function getConsentHistory(\n\tconfig: SylphxConfig,\n\tinput: GetConsentHistoryInput,\n): Promise<ConsentHistoryResult> {\n\treturn callApi(config, '/consent/history', {\n\t\tmethod: 'GET',\n\t\tquery: {\n\t\t\tuserId: input.userId,\n\t\t\tanonymousId: input.anonymousId,\n\t\t\tlimit: input.limit?.toString(),\n\t\t\tcursor: input.cursor,\n\t\t},\n\t})\n}\n","/**\n * Referrals Functions\n *\n * Pure functions for referral code management and tracking.\n *\n * ## Architecture (ADR-004)\n *\n * Referrals uses **Inline Defaults + Auto-Discovery + Console Override**:\n * - Code provides optional inline defaults when redeeming referral codes\n * - Platform uses defaults if no Console override exists\n * - Console can override reward values without deployment\n *\n * Wire-shape types are re-exported from `@sylphx/contract` (ADR-084). The\n * contract is the single source of truth for `GET /referrals/code`,\n * `/referrals/code/regenerate`, `/referrals/stats`, `/referrals/redeem`,\n * `/referrals/leaderboard`.\n *\n * @example\n * ```typescript\n * import { redeemReferralCode } from '@sylphx/sdk'\n *\n * // Redeem with inline defaults (overridable in Console)\n * const result = await redeemReferralCode(config, {\n * code: 'ABC123',\n * userId: 'new-user-456',\n * }, {\n * referrerReward: { type: 'premium_trial', days: 7 },\n * refereeReward: { type: 'premium_trial', days: 7 },\n * })\n * ```\n */\n\n// Type-only imports from @sylphx/contract per ADR-084 Rule 3 — prevents\n// Effect runtime types from leaking into the published .d.ts surface.\nimport type {\n\tReferralRewardConfig as ContractReferralRewardConfig,\n\tReferralRewardDefaults as ContractReferralRewardDefaults,\n\tRegenerateCodeResponse as ContractRegenerateCodeResponse,\n\tGetCodeResponse,\n\tGetStatsResponse,\n\tRedeemRequest,\n\tRedeemResponse,\n\tReferralLeaderboardEntry,\n\tReferralLeaderboardResponse,\n} from '@sylphx/contract'\nimport { callApi, type SylphxConfig } from './config'\n\n// ============================================================================\n// Types (re-exported from @sylphx/contract)\n// ============================================================================\n\nexport type ReferralCodeResponse = GetCodeResponse\nexport type RegenerateCodeResponse = ContractRegenerateCodeResponse\nexport type ReferralStatsResponse = GetStatsResponse\nexport type RedeemReferralRequest = RedeemRequest\nexport type RedeemReferralResponse = RedeemResponse\nexport type ReferralRewardDefaults = ContractReferralRewardDefaults\nexport type ReferralRewardConfig = ContractReferralRewardConfig\nexport type LeaderboardResponse = ReferralLeaderboardResponse\nexport type LeaderboardEntry = ReferralLeaderboardEntry\n\n// SDK-specific types for convenience\nexport interface ReferralCode {\n\tcode: string\n\tcreatedAt: string\n}\n\nexport interface ReferralStats {\n\t/** User's referral code */\n\tcode: string\n\t/** Total referrals made */\n\ttotalReferrals: number\n\t/** Successful (redeemed) referrals */\n\tsuccessfulReferrals: number\n\t/** Pending referrals */\n\tpendingReferrals: number\n\t/** Total rewards earned */\n\ttotalRewards: number\n}\n\ntype LeaderboardPeriod = 'all' | 'month' | 'week'\n\nexport interface LeaderboardResult {\n\t/** Time period for the leaderboard */\n\tperiod?: LeaderboardPeriod\n\tentries: LeaderboardEntry[]\n\t/** Current user's position (may not be in top entries) */\n\tcurrentUserRank: number | null\n\t/** Total participants */\n\ttotalParticipants: number\n}\n\nexport interface RedeemReferralInput {\n\t/** Referral code to redeem */\n\tcode: string\n\t/** User ID of the person redeeming (optional for anonymous) */\n\tuserId?: string\n}\n\nexport interface RedeemResult {\n\tsuccess: boolean\n\t/** Reward type - platform types or app-specific types */\n\trewardType: 'points' | 'premium_trial' | 'discount' | 'credit' | (string & {})\n\treferredReward?: Record<string, unknown>\n\treferrerReward?: Record<string, unknown>\n}\n\nexport interface LeaderboardOptions {\n\t/** Number of entries to return (default: 10) */\n\tlimit?: number\n}\n\n// ============================================================================\n// Functions\n// ============================================================================\n\n/**\n * Get current user's referral code\n *\n * Creates one if it doesn't exist.\n *\n * @example\n * ```typescript\n * const { code } = await getMyReferralCode(config, 'user-123')\n * console.log(`Share your code: ${code}`)\n * ```\n */\nexport async function getMyReferralCode(\n\tconfig: SylphxConfig,\n\tuserId: string,\n): Promise<ReferralCode> {\n\treturn callApi(config, '/referrals/code', {\n\t\tmethod: 'GET',\n\t\tquery: { userId },\n\t})\n}\n\n/**\n * Get referral statistics for a user\n *\n * @example\n * ```typescript\n * const stats = await getReferralStats(config, 'user-123')\n * console.log(`${stats.successfulReferrals} successful referrals`)\n * ```\n */\nexport async function getReferralStats(\n\tconfig: SylphxConfig,\n\tuserId: string,\n): Promise<ReferralStats> {\n\treturn callApi(config, '/referrals/stats', {\n\t\tmethod: 'GET',\n\t\tquery: { userId },\n\t})\n}\n\n/**\n * Redeem a referral code\n *\n * If the referral program rewards aren't configured in Console, the provided\n * defaults will be used. Console can override any values without deployment.\n *\n * @param config - SDK configuration\n * @param input - Referral redemption input (code, userId)\n * @param defaults - Optional inline defaults for reward configuration\n *\n * @example\n * ```typescript\n * // Basic redemption (uses Console-configured rewards)\n * const result = await redeemReferralCode(config, {\n * code: 'ABC123',\n * userId: 'new-user-456',\n * })\n *\n * // With inline defaults (auto-discovered if not in Console)\n * const result = await redeemReferralCode(config, {\n * code: 'ABC123',\n * userId: 'new-user-456',\n * }, {\n * referrerReward: { type: 'premium_trial', days: 7 },\n * refereeReward: { type: 'premium_trial', days: 7 },\n * })\n *\n * if (result.success) {\n * console.log(`Reward: ${result.reward?.type}`)\n * }\n * ```\n */\nexport async function redeemReferralCode(\n\tconfig: SylphxConfig,\n\tinput: RedeemReferralInput,\n\tdefaults?: ReferralRewardDefaults,\n): Promise<RedeemResult> {\n\treturn callApi(config, '/referrals/redeem', {\n\t\tmethod: 'POST',\n\t\tbody: { ...input, defaults },\n\t})\n}\n\n/**\n * Get referral leaderboard\n *\n * @example\n * ```typescript\n * const { entries, currentUserRank } = await getReferralLeaderboard(config, 'user-123')\n *\n * entries.forEach(e => {\n * console.log(`#${e.rank} ${e.displayName}: ${e.completedReferrals} referrals`)\n * })\n * ```\n */\nexport async function getReferralLeaderboard(\n\tconfig: SylphxConfig,\n\tuserId: string,\n\toptions?: LeaderboardOptions,\n): Promise<LeaderboardResult> {\n\treturn callApi(config, '/referrals/leaderboard', {\n\t\tmethod: 'GET',\n\t\tquery: { userId, ...options } as Record<string, string | number | undefined>,\n\t})\n}\n\n/**\n * Regenerate user's referral code\n *\n * Use this if the current code has been compromised or user wants a fresh start.\n *\n * @example\n * ```typescript\n * const { code } = await regenerateReferralCode(config, 'user-123')\n * console.log(`New code: ${code}`)\n * ```\n */\nexport async function regenerateReferralCode(\n\tconfig: SylphxConfig,\n\tuserId: string,\n): Promise<ReferralCode> {\n\treturn callApi(config, '/referrals/code/regenerate', {\n\t\tmethod: 'POST',\n\t\tbody: { userId },\n\t})\n}\n","/**\n * Engagement Service Types\n *\n * Core types for streaks, leaderboards, and achievements.\n *\n * ## Architecture (ADR-004)\n *\n * Engagement uses **Inline Defaults + Auto-Discovery + Console Override**:\n * - Code provides optional inline defaults when calling APIs\n * - Platform auto-discovers/creates entities when first referenced\n * - Console can override names, descriptions, values without deployment\n */\n\n// ============================================================================\n// Streaks\n// ============================================================================\n\n/** Streak activity frequency */\nexport type StreakFrequency = 'daily' | 'weekly' | 'custom'\n\n/** Streak definition (auto-discovered or from Console) */\nexport interface StreakDefinition {\n\t/** Unique identifier */\n\tid: string\n\t/** Display name */\n\tname: string\n\t/** Description */\n\tdescription?: string\n\t/** Activity frequency */\n\tfrequency: StreakFrequency\n\t/** Grace period in hours (default: 0) */\n\tgracePeriodHours?: number\n\t/** Whether streak resets on miss (default: true) */\n\tresetOnMiss?: boolean\n\t/** Maximum streak value (optional cap) */\n\tmaxValue?: number\n\t/** Custom interval in hours (only for 'custom' frequency) */\n\tcustomIntervalHours?: number\n}\n\n/** User's streak state (from platform) */\nexport interface StreakState {\n\t/** Streak definition ID */\n\tstreakId: string\n\t/** Current streak count */\n\tcurrent: number\n\t/** Longest streak ever */\n\tlongest: number\n\t/** Last activity timestamp */\n\tlastActivityAt: string | null\n\t/** When current streak will expire */\n\texpiresAt: string | null\n\t/** Whether streak can be recovered (within grace period) */\n\tcanRecover: boolean\n\t/** Time remaining until expiry in ms */\n\ttimeRemainingMs: number | null\n\t/** User's timezone preference for streak expiry (IANA timezone, e.g., 'America/New_York') */\n\tuserTimezone: string | null\n}\n\n/** Activity recording input */\nexport interface RecordActivityInput {\n\t/** Streak ID */\n\tstreakId: string\n\t/** User's IANA timezone (e.g., 'America/New_York') for calculating streak expiry at user's local midnight */\n\tuserTimezone?: string\n\t/** Optional metadata */\n\tmetadata?: Record<string, unknown>\n\t/**\n\t * Idempotency key for safe retries (Stripe pattern)\n\t *\n\t * Prevents duplicate streak recordings if the same request is retried.\n\t * Use a unique key per logical activity (e.g., `streak-${userId}-${date}`).\n\t */\n\tidempotencyKey?: string\n}\n\n/** Activity recording result */\nexport interface RecordActivityResult {\n\t/** Updated streak state */\n\tstreak: StreakState\n\t/** Whether this activity extended the streak */\n\textended: boolean\n\t/** Whether a new personal best was achieved */\n\tnewPersonalBest: boolean\n\t/** Previous streak value (for animation) */\n\tpreviousValue: number\n}\n\n// ============================================================================\n// Leaderboards\n// ============================================================================\n\n/** Leaderboard sort direction */\nexport type LeaderboardSortDirection = 'asc' | 'desc'\n\n/** Leaderboard reset period */\nexport type LeaderboardResetPeriod = 'hourly' | 'daily' | 'weekly' | 'monthly' | 'never'\n\n/** Score aggregation method */\nexport type LeaderboardAggregation = 'max' | 'sum' | 'latest' | 'count' | 'min' | 'avg'\n\n/** Leaderboard definition (auto-discovered or from Console) */\nexport interface LeaderboardDefinition {\n\t/** Unique identifier */\n\tid: string\n\t/** Display name */\n\tname: string\n\t/** Description */\n\tdescription?: string\n\t/** Sort direction (desc = higher is better) */\n\tsortDirection: LeaderboardSortDirection\n\t/** Reset period */\n\tresetPeriod: LeaderboardResetPeriod\n\t/** How to aggregate multiple scores from same user */\n\taggregation: LeaderboardAggregation\n\t/** Default privacy for entries */\n\tdefaultPrivacy?: 'public' | 'friends' | 'anonymous'\n\t/** Maximum entries to keep per period */\n\tmaxEntries?: number\n}\n\n/** Leaderboard entry */\nexport interface LeaderboardEntry {\n\t/** Rank (1-indexed) */\n\trank: number\n\t/** User ID (may be null for anonymous) */\n\tuserId: string | null\n\t/** Display name */\n\tdisplayName: string\n\t/** Avatar URL */\n\tavatarUrl: string | null\n\t/** Score/value */\n\tvalue: number\n\t/** Whether this is the current user */\n\tisCurrentUser: boolean\n\t/** Entry metadata */\n\tmetadata?: Record<string, unknown>\n\t/** When the score was submitted */\n\tsubmittedAt: string\n}\n\n/** Leaderboard query options */\nexport interface LeaderboardQueryOptions {\n\t/** Number of entries to return (default: 10) */\n\tlimit?: number\n\t/** Offset for pagination */\n\toffset?: number\n\t/** Include surrounding entries for current user */\n\tincludeSurrounding?: boolean\n\t/** Number of surrounding entries (default: 2) */\n\tsurroundingCount?: number\n}\n\n/** Leaderboard query result */\nexport interface LeaderboardResult {\n\t/** Leaderboard definition ID */\n\tleaderboardId: string\n\t/** Period (for periodic leaderboards) */\n\tperiod?: string\n\t/** Entries (top N or paginated) */\n\tentries: LeaderboardEntry[]\n\t/** Current user's entry (may not be in top entries) */\n\tcurrentUserEntry: LeaderboardEntry | null\n\t/** Entries surrounding the current user (when includeSurrounding=true and user is outside main entries) */\n\tsurroundingEntries?: LeaderboardEntry[]\n\t/** Total participants */\n\ttotalParticipants: number\n\t/** Next reset time (for periodic leaderboards) */\n\tnextResetAt: string | null\n}\n\n/** Score submission input */\nexport interface SubmitScoreInput {\n\t/** Leaderboard ID */\n\tleaderboardId: string\n\t/** Score value */\n\tvalue: number\n\t/** Optional metadata */\n\tmetadata?: Record<string, unknown>\n}\n\n/** Score submission result */\nexport interface SubmitScoreResult {\n\t/** Whether submission was accepted */\n\taccepted: boolean\n\t/** New rank (if in leaderboard) */\n\trank: number | null\n\t/** Previous best (if any) */\n\tpreviousBest: number | null\n\t/** Whether this is a new personal best */\n\tnewPersonalBest: boolean\n\t/** Rank change (positive = improved) */\n\trankChange: number | null\n}\n\n// ============================================================================\n// Achievements\n// ============================================================================\n\n/** Achievement type */\nexport type AchievementType = 'standard' | 'hidden' | 'incremental'\n\n/** Achievement tier */\nexport type AchievementTier = 'bronze' | 'silver' | 'gold' | 'platinum' | 'diamond'\n\n/** Achievement category */\nexport type AchievementCategory = string // App-defined\n\n/** Achievement criteria operator */\nexport type CriteriaOperator = 'eq' | 'ne' | 'gt' | 'gte' | 'lt' | 'lte' | 'in' | 'contains'\n\n/** Single criterion */\nexport interface AchievementCriterion {\n\t/** Property to check (e.g., 'event', 'count', 'streak.daily') */\n\tproperty: string\n\t/** Comparison operator */\n\toperator: CriteriaOperator\n\t/** Value to compare against */\n\tvalue: string | number | boolean | string[] | number[]\n}\n\n/** Achievement criteria (AND logic within, OR between arrays) */\nexport interface AchievementCriteria {\n\t/** Event name to track (for event-based achievements) */\n\tevent?: string\n\t/** Required count of events */\n\tcount?: number\n\t/** Additional conditions */\n\tconditions?: AchievementCriterion[]\n}\n\n/** Achievement definition (auto-discovered or from Console) */\nexport interface AchievementDefinition {\n\t/** Unique identifier */\n\tid: string\n\t/** Display name */\n\tname: string\n\t/** Description (shown before unlock) */\n\tdescription: string\n\t/** Description shown after unlock (optional) */\n\tunlockedDescription?: string\n\t/** Achievement type */\n\ttype: AchievementType\n\t/** Tier/rarity */\n\ttier: AchievementTier\n\t/** Category (app-defined) */\n\tcategory: AchievementCategory\n\t/** Icon (Iconify name or URL) */\n\ticon: string\n\t/** Points awarded */\n\tpoints?: number\n\t/** Unlock criteria */\n\tcriteria: AchievementCriteria\n\t/** Target value for incremental achievements */\n\ttarget?: number\n\t/** Whether to show in list before unlock */\n\tsecret?: boolean\n\t/** Order in list */\n\torder?: number\n}\n\n/** User's achievement state */\nexport interface UserAchievement {\n\t/** Achievement definition ID */\n\tachievementId: string\n\t/** Whether unlocked */\n\tunlocked: boolean\n\t/** Unlock timestamp */\n\tunlockedAt: string | null\n\t/** Progress (for incremental) */\n\tprogress: number\n\t/** Target (for incremental) */\n\ttarget: number | null\n\t/** Progress percentage (0-100) */\n\tprogressPercent: number\n}\n\n/** Achievement unlock event */\nexport interface AchievementUnlockEvent {\n\t/** Achievement definition */\n\tachievement: AchievementDefinition\n\t/** User achievement state */\n\tuserAchievement: UserAchievement\n\t/** Whether this is a new unlock (vs already unlocked) */\n\tisNew: boolean\n}\n\n// ============================================================================\n// Engagement Config (from Platform)\n// ============================================================================\n\n/** Complete engagement configuration (fetched from platform) */\nexport interface EngagementConfig {\n\t/** Streak definitions */\n\tstreaks?: StreakDefinition[]\n\t/** Leaderboard definitions */\n\tleaderboards?: LeaderboardDefinition[]\n\t/** Achievement definitions */\n\tachievements?: AchievementDefinition[]\n\t/** Achievement categories (for UI grouping) */\n\tachievementCategories?: {\n\t\tid: string\n\t\tname: string\n\t\ticon?: string\n\t\torder?: number\n\t}[]\n}\n\n// ============================================================================\n// Tier Metadata (for UI)\n// ============================================================================\n\nexport const ACHIEVEMENT_TIER_CONFIG = {\n\tbronze: { color: '#CD7F32', points: 10 },\n\tsilver: { color: '#C0C0C0', points: 25 },\n\tgold: { color: '#FFD700', points: 50 },\n\tplatinum: { color: '#00CED1', points: 100 },\n\tdiamond: { color: '#B9F2FF', points: 200 },\n} as const\n\n// ============================================================================\n// Inline Defaults (Auto-Discovery)\n// ============================================================================\n// These types define the optional inline defaults that can be passed when\n// calling engagement functions. If the entity doesn't exist, the platform\n// will auto-create it with these defaults. Console can override any values.\n\n/**\n * Inline defaults for streak auto-discovery\n *\n * @example\n * ```typescript\n * await recordStreakActivity(config, { streakId: 'daily-login' }, userId, {\n * name: 'Daily Login',\n * frequency: 'daily',\n * gracePeriodHours: 12,\n * })\n * ```\n */\nexport interface StreakDefaults {\n\t/** Display name */\n\tname?: string\n\t/** Description */\n\tdescription?: string\n\t/** Activity frequency */\n\tfrequency?: StreakFrequency\n\t/** Grace period in hours (default: 0) */\n\tgracePeriodHours?: number\n\t/** Whether streak resets on miss (default: true) */\n\tresetOnMiss?: boolean\n\t/** Maximum streak value (optional cap) */\n\tmaxValue?: number\n\t/** Custom interval in hours (only for 'custom' frequency) */\n\tcustomIntervalHours?: number\n}\n\n/**\n * Inline defaults for leaderboard auto-discovery\n *\n * @example\n * ```typescript\n * await submitScore(config, { leaderboardId: 'high-scores', value: 1500 }, userId, {\n * name: 'High Scores',\n * sortDirection: 'desc',\n * resetPeriod: 'weekly',\n * })\n * ```\n */\nexport interface LeaderboardDefaults {\n\t/** Display name */\n\tname?: string\n\t/** Description */\n\tdescription?: string\n\t/** Sort direction (desc = higher is better) */\n\tsortDirection?: LeaderboardSortDirection\n\t/** Reset period */\n\tresetPeriod?: LeaderboardResetPeriod\n\t/** How to aggregate multiple scores from same user */\n\taggregation?: LeaderboardAggregation\n\t/** Maximum entries to keep per period */\n\tmaxEntries?: number\n}\n\n/**\n * Inline defaults for achievement auto-discovery\n *\n * @example\n * ```typescript\n * await unlockAchievement(config, 'first-purchase', userId, {\n * name: 'First Purchase',\n * description: 'Made your first purchase',\n * points: 100,\n * tier: 'bronze',\n * })\n * ```\n */\nexport interface AchievementDefaults {\n\t/** Display name */\n\tname?: string\n\t/** Description (shown before unlock) */\n\tdescription?: string\n\t/** Description shown after unlock */\n\tunlockedDescription?: string\n\t/** Achievement type */\n\ttype?: AchievementType\n\t/** Tier/rarity */\n\ttier?: AchievementTier\n\t/** Category (app-defined) */\n\tcategory?: AchievementCategory\n\t/** Icon (Iconify name or URL) */\n\ticon?: string\n\t/** Points awarded */\n\tpoints?: number\n\t/** Target value for incremental achievements */\n\ttarget?: number\n\t/** Whether to show in list before unlock */\n\tsecret?: boolean\n}\n","/**\n * Engagement Functions\n *\n * Pure functions for streaks, leaderboards, and achievements.\n *\n * ## Architecture (ADR-004)\n *\n * Engagement uses **Inline Defaults + Auto-Discovery + Console Override**:\n * - Code provides optional inline defaults when calling functions\n * - Platform auto-discovers/creates entities when first referenced\n * - Console can override names, descriptions, values without deployment\n *\n * @example\n * ```typescript\n * import { unlockAchievement, recordStreakActivity, submitScore } from '@sylphx/sdk'\n *\n * // Unlock achievement with inline defaults (auto-discovered if doesn't exist)\n * await unlockAchievement(config, 'first-win', userId, {\n * name: 'First Win',\n * description: 'Won your first game',\n * points: 100,\n * tier: 'bronze',\n * })\n *\n * // Record streak activity with inline defaults\n * await recordStreakActivity(config, { streakId: 'daily-login' }, userId, {\n * name: 'Daily Login',\n * frequency: 'daily',\n * gracePeriodHours: 12,\n * })\n *\n * // Submit leaderboard score with inline defaults\n * await submitScore(config, { leaderboardId: 'high-scores', value: 1500 }, userId, {\n * name: 'High Scores',\n * sortDirection: 'desc',\n * resetPeriod: 'weekly',\n * })\n * ```\n */\n\nimport { callApi, type SylphxConfig } from './config'\n\n// Re-export types from types file\nexport type {\n\tAchievementCategory,\n\tAchievementCriteria,\n\tAchievementCriterion,\n\t// Achievements\n\tAchievementDefinition,\n\tAchievementTier,\n\tAchievementType,\n\tAchievementUnlockEvent,\n\tCriteriaOperator,\n\tLeaderboardAggregation,\n\t// Leaderboards\n\tLeaderboardDefinition,\n\tLeaderboardEntry,\n\tLeaderboardQueryOptions,\n\tLeaderboardResetPeriod,\n\tLeaderboardResult,\n\tLeaderboardSortDirection,\n\tRecordActivityInput,\n\tRecordActivityResult,\n\t// Streaks\n\tStreakDefinition,\n\tStreakFrequency,\n\tStreakState,\n\tSubmitScoreInput,\n\tSubmitScoreResult,\n\tUserAchievement,\n} from './lib/engagement/types'\n\nexport { ACHIEVEMENT_TIER_CONFIG } from './lib/engagement/types'\n\n// ============================================================================\n// Streak Functions\n// ============================================================================\n\nimport type {\n\tRecordActivityInput,\n\tRecordActivityResult,\n\tStreakDefaults,\n\tStreakState,\n} from './lib/engagement/types'\n\n/**\n * Get current streak state for a user\n *\n * @example\n * ```typescript\n * const streak = await getStreak(config, 'daily-challenge', userId)\n * console.log(`Current streak: ${streak.current}`)\n * console.log(`Expires in: ${streak.timeRemainingMs}ms`)\n * ```\n */\nexport async function getStreak(\n\tconfig: SylphxConfig,\n\tstreakId: string,\n\tuserId: string,\n): Promise<StreakState> {\n\treturn callApi(config, '/engagement/streaks/get', {\n\t\tmethod: 'GET',\n\t\tquery: { streakId, userId },\n\t})\n}\n\n/**\n * Get all streak states for a user\n *\n * @example\n * ```typescript\n * const streaks = await getAllStreaks(config, userId)\n * for (const streak of streaks) {\n * console.log(`${streak.streakId}: ${streak.current}`)\n * }\n * ```\n */\nexport async function getAllStreaks(config: SylphxConfig, userId: string): Promise<StreakState[]> {\n\treturn callApi(config, '/engagement/streaks', {\n\t\tmethod: 'GET',\n\t\tquery: { userId },\n\t})\n}\n\n/**\n * Record an activity to extend/maintain a streak\n *\n * If the streak doesn't exist, it will be auto-discovered with the provided defaults.\n * Console can override any values without deployment.\n *\n * @param config - SDK configuration\n * @param input - Activity input (streakId required)\n * @param userId - User ID\n * @param defaults - Optional inline defaults for auto-discovery\n *\n * @example\n * ```typescript\n * const result = await recordStreakActivity(config, {\n * streakId: 'daily-challenge',\n * }, userId, {\n * name: 'Daily Challenge',\n * frequency: 'daily',\n * gracePeriodHours: 12,\n * })\n *\n * if (result.extended) {\n * console.log(`Streak extended to ${result.streak.current}!`)\n * }\n * if (result.newPersonalBest) {\n * console.log('New personal best!')\n * }\n * ```\n */\nexport async function recordStreakActivity(\n\tconfig: SylphxConfig,\n\tinput: RecordActivityInput,\n\tuserId: string,\n\tdefaults?: StreakDefaults,\n): Promise<RecordActivityResult> {\n\tconst { idempotencyKey, ...inputBody } = input\n\treturn callApi(config, '/engagement/streaks/record', {\n\t\tmethod: 'POST',\n\t\tbody: { ...inputBody, userId, defaults },\n\t\tidempotencyKey,\n\t})\n}\n\n/**\n * Recover a streak within grace period (may require payment/reward)\n *\n * @example\n * ```typescript\n * const result = await recoverStreak(config, 'daily-challenge', userId)\n * if (result.success) {\n * console.log(`Streak recovered at ${result.streak.current}`)\n * }\n * ```\n */\nexport async function recoverStreak(\n\tconfig: SylphxConfig,\n\tstreakId: string,\n\tuserId: string,\n): Promise<{ success: boolean; streak: StreakState }> {\n\treturn callApi(config, '/engagement/streaks/recover', {\n\t\tmethod: 'POST',\n\t\tbody: { streakId, userId },\n\t})\n}\n\n// ============================================================================\n// Leaderboard Functions\n// ============================================================================\n\nimport type {\n\tLeaderboardDefaults,\n\tLeaderboardQueryOptions,\n\tLeaderboardResult,\n\tSubmitScoreInput,\n\tSubmitScoreResult,\n} from './lib/engagement/types'\n\n/**\n * Get leaderboard entries\n *\n * @example\n * ```typescript\n * const result = await getLeaderboard(config, 'high-scores', userId, {\n * limit: 10,\n * includeSurrounding: true,\n * })\n *\n * for (const entry of result.entries) {\n * console.log(`#${entry.rank} ${entry.displayName}: ${entry.value}`)\n * }\n *\n * if (result.currentUserEntry) {\n * console.log(`Your rank: #${result.currentUserEntry.rank}`)\n * }\n * ```\n */\nexport async function getLeaderboard(\n\tconfig: SylphxConfig,\n\tleaderboardId: string,\n\tuserId: string | null,\n\toptions?: LeaderboardQueryOptions,\n): Promise<LeaderboardResult> {\n\treturn callApi(config, '/engagement/leaderboards/get', {\n\t\tmethod: 'GET',\n\t\tquery: { leaderboardId, userId: userId ?? undefined, ...options } as Record<\n\t\t\tstring,\n\t\t\tstring | number | boolean | undefined\n\t\t>,\n\t})\n}\n\n/**\n * Submit a score to a leaderboard\n *\n * If the leaderboard doesn't exist, it will be auto-discovered with the provided defaults.\n * Console can override any values without deployment.\n *\n * @param config - SDK configuration\n * @param input - Score submission input (leaderboardId, value required)\n * @param userId - User ID\n * @param defaults - Optional inline defaults for auto-discovery\n *\n * @example\n * ```typescript\n * const result = await submitScore(config, {\n * leaderboardId: 'high-scores',\n * value: 1500,\n * metadata: { level: 'hard' },\n * }, userId, {\n * name: 'High Scores',\n * sortDirection: 'desc',\n * resetPeriod: 'weekly',\n * aggregation: 'max',\n * })\n *\n * if (result.newPersonalBest) {\n * console.log('New personal best!')\n * }\n * if (result.rank !== null) {\n * console.log(`Ranked #${result.rank}`)\n * }\n * ```\n */\nexport async function submitScore(\n\tconfig: SylphxConfig,\n\tinput: SubmitScoreInput,\n\tuserId: string,\n\tdefaults?: LeaderboardDefaults,\n): Promise<SubmitScoreResult> {\n\treturn callApi(config, '/engagement/leaderboards/submit', {\n\t\tmethod: 'POST',\n\t\tbody: { ...input, userId, defaults },\n\t})\n}\n\n/**\n * Get user's rank on a leaderboard (even if not in top entries)\n *\n * @example\n * ```typescript\n * const rank = await getUserRank(config, 'high-scores', userId)\n * if (rank) {\n * console.log(`You are ranked #${rank.rank} with score ${rank.value}`)\n * }\n * ```\n */\nexport async function getUserLeaderboardRank(\n\tconfig: SylphxConfig,\n\tleaderboardId: string,\n\tuserId: string,\n): Promise<{ rank: number; value: number } | null> {\n\treturn callApi(config, '/engagement/leaderboards/rank', {\n\t\tmethod: 'GET',\n\t\tquery: { leaderboardId, userId },\n\t})\n}\n\n// ============================================================================\n// Achievement Functions\n// ============================================================================\n\nimport type {\n\tAchievementDefaults,\n\tAchievementUnlockEvent,\n\tUserAchievement,\n} from './lib/engagement/types'\n\n/**\n * Get all achievements with user progress\n *\n * @example\n * ```typescript\n * const achievements = await getAchievements(config, userId)\n *\n * const unlocked = achievements.filter(a => a.unlocked)\n * console.log(`${unlocked.length} achievements unlocked`)\n *\n * const inProgress = achievements.filter(a => !a.unlocked && a.progress > 0)\n * for (const a of inProgress) {\n * console.log(`${a.achievementId}: ${a.progress}/${a.target}`)\n * }\n * ```\n */\nexport async function getAchievements(\n\tconfig: SylphxConfig,\n\tuserId: string,\n): Promise<UserAchievement[]> {\n\treturn callApi(config, '/engagement/achievements', {\n\t\tmethod: 'GET',\n\t\tquery: { userId },\n\t})\n}\n\n/**\n * Get a single achievement with user progress\n *\n * @example\n * ```typescript\n * const achievement = await getAchievement(config, 'first-win', userId)\n * if (achievement?.unlocked) {\n * console.log(`Unlocked at ${achievement.unlockedAt}`)\n * }\n * ```\n */\nexport async function getAchievement(\n\tconfig: SylphxConfig,\n\tachievementId: string,\n\tuserId: string,\n): Promise<UserAchievement | null> {\n\treturn callApi(config, '/engagement/achievements/get', {\n\t\tmethod: 'GET',\n\t\tquery: { achievementId, userId },\n\t})\n}\n\n/**\n * Manually unlock an achievement\n *\n * If the achievement doesn't exist, it will be auto-discovered with the provided defaults.\n * Console can override any values without deployment.\n *\n * @param config - SDK configuration\n * @param achievementId - Achievement ID\n * @param userId - User ID\n * @param defaults - Optional inline defaults for auto-discovery\n *\n * @example\n * ```typescript\n * const result = await unlockAchievement(config, 'first-purchase', userId, {\n * name: 'First Purchase',\n * description: 'Made your first purchase',\n * points: 100,\n * tier: 'bronze',\n * })\n * if (result.isNew) {\n * showAchievementToast(result.achievement)\n * }\n * ```\n */\nexport async function unlockAchievement(\n\tconfig: SylphxConfig,\n\tachievementId: string,\n\tuserId: string,\n\tdefaults?: AchievementDefaults,\n): Promise<AchievementUnlockEvent> {\n\treturn callApi(config, '/engagement/achievements/unlock', {\n\t\tmethod: 'POST',\n\t\tbody: { achievementId, userId, defaults },\n\t})\n}\n\n/**\n * Increment progress on an incremental achievement\n *\n * If the achievement doesn't exist, it will be auto-discovered with the provided defaults.\n * Console can override any values without deployment.\n *\n * @param config - SDK configuration\n * @param achievementId - Achievement ID\n * @param amount - Amount to increment\n * @param userId - User ID\n * @param defaults - Optional inline defaults for auto-discovery\n *\n * @example\n * ```typescript\n * // User collected an item\n * const result = await incrementAchievementProgress(config, 'collector-100', 1, userId, {\n * name: 'Collector',\n * description: 'Collect 100 items',\n * type: 'incremental',\n * target: 100,\n * tier: 'silver',\n * })\n *\n * if (result.unlocked) {\n * console.log('Achievement unlocked!')\n * } else {\n * console.log(`Progress: ${result.progress}/${result.target}`)\n * }\n * ```\n */\nexport async function incrementAchievementProgress(\n\tconfig: SylphxConfig,\n\tachievementId: string,\n\tamount: number,\n\tuserId: string,\n\tdefaults?: AchievementDefaults,\n): Promise<UserAchievement> {\n\treturn callApi(config, '/engagement/achievements/progress', {\n\t\tmethod: 'POST',\n\t\tbody: { achievementId, amount, userId, defaults },\n\t})\n}\n\n/**\n * Get total achievement points for a user\n *\n * @example\n * ```typescript\n * const points = await getAchievementPoints(config, userId)\n * console.log(`Total points: ${points.total}`)\n * console.log(`This month: ${points.thisMonth}`)\n * ```\n */\nexport async function getAchievementPoints(\n\tconfig: SylphxConfig,\n\tuserId: string,\n): Promise<{ total: number; thisMonth: number; rank: number | null }> {\n\treturn callApi(config, '/engagement/achievements/points', {\n\t\tmethod: 'GET',\n\t\tquery: { userId },\n\t})\n}\n","/**\n * Organization Functions\n *\n * Pure functions for organization management - no hidden state.\n * Each function takes config as the first parameter.\n *\n * Uses REST API at /api/sdk/orgs/* for all operations.\n *\n * Types are re-exported from `@sylphx/contract` (ADR-084). The contract is\n * the single source of truth for every wire shape — this module only adds\n * ergonomic aliases (`Organization*` wrappers) and inline envelopes for\n * request bodies + member role updates.\n */\n\n// Type-only imports from @sylphx/contract per ADR-084 Rule 3 — prevents\n// Effect runtime types from leaking into the published .d.ts surface.\nimport type {\n\tCreateOrgInput as ContractCreateOrgInput,\n\tInviteMemberInput as ContractInviteMemberInput,\n\tUpdateOrgInput as ContractUpdateOrgInput,\n\tMembershipInfo,\n\tOrganization,\n\tOrgInvitation,\n\tOrgMember,\n\tOrgSdkRole,\n} from '@sylphx/contract'\nimport { callApi, type SylphxConfig } from './config'\n\n// ============================================================================\n// Types (re-exported from @sylphx/contract)\n// ============================================================================\n\nexport type { Organization }\n/**\n * The contract types `OrgMember.role` as a permissive `string` so it can\n * absorb any role stored in the DB (including legacy `'member'`). The SDK\n * surface is narrower — components key off the six-value role union — so\n * re-narrow here to keep `member.role` valid in existing call sites.\n */\nexport type OrganizationMember = Omit<OrgMember, 'role'> & {\n\trole: OrgSdkRole\n}\nexport type OrganizationInvitation = OrgInvitation\n/**\n * Membership info returned inline with `GET /orgs/:idOrSlug`. The endpoint\n * may return `null` when the caller has no role on the org (platform-admin\n * path) — SDK callers get the union on the response envelope, not here.\n */\nexport type OrganizationMembership = MembershipInfo\nexport type OrgRole = OrgSdkRole\n/**\n * The contract's `CreateOrgInput` requires `{ name, slug }`; the SDK's\n * previous OpenAPI-derived shape allowed omitting `slug` (server\n * auto-generates from name) and accepted optional `email` / `metadata`.\n * Preserve the looser SDK surface with a local `Omit` + widening.\n */\nexport type CreateOrgInput = Omit<ContractCreateOrgInput, 'slug'> & {\n\tslug?: string\n\temail?: string\n\tmetadata?: Record<string, unknown>\n}\nexport type UpdateOrgInput = ContractUpdateOrgInput & {\n\tmetadata?: Record<string, unknown> | null\n}\nexport type InviteMemberInput = ContractInviteMemberInput\n\n// ============================================================================\n// Organization CRUD\n// ============================================================================\n\n/**\n * Get all organizations the current user belongs to\n *\n * @example\n * ```typescript\n * const { organizations } = await getOrganizations(config)\n * ```\n */\nexport async function getOrganizations(\n\tconfig: SylphxConfig,\n): Promise<{ organizations: Organization[] }> {\n\treturn callApi<{ organizations: Organization[] }>(config, '/orgs')\n}\n\n/**\n * Get organization by ID or slug\n *\n * @example\n * ```typescript\n * const { organization, membership } = await getOrganization(config, 'my-org')\n * ```\n */\nexport async function getOrganization(\n\tconfig: SylphxConfig,\n\torgIdOrSlug: string,\n): Promise<{\n\torganization: Organization\n\tmembership: OrganizationMembership | null\n}> {\n\treturn callApi<{\n\t\torganization: Organization\n\t\tmembership: OrganizationMembership | null\n\t}>(config, `/orgs/${orgIdOrSlug}`)\n}\n\n/**\n * Create a new organization\n *\n * @example\n * ```typescript\n * const { organization } = await createOrganization(config, {\n * name: 'My Company',\n * slug: 'my-company',\n * })\n * ```\n */\nexport async function createOrganization(\n\tconfig: SylphxConfig,\n\tinput: CreateOrgInput,\n): Promise<{ organization: Organization }> {\n\treturn callApi<{ organization: Organization }>(config, '/orgs', {\n\t\tmethod: 'POST',\n\t\tbody: input,\n\t})\n}\n\n/**\n * Update an organization\n *\n * @example\n * ```typescript\n * const { organization } = await updateOrganization(config, 'my-org', {\n * name: 'New Name',\n * })\n * ```\n */\nexport async function updateOrganization(\n\tconfig: SylphxConfig,\n\torgIdOrSlug: string,\n\tinput: UpdateOrgInput,\n): Promise<{ organization: Organization }> {\n\treturn callApi<{ organization: Organization }>(config, `/orgs/${orgIdOrSlug}`, {\n\t\tmethod: 'PUT',\n\t\tbody: input,\n\t})\n}\n\n/**\n * Delete an organization\n *\n * Requires super_admin role.\n *\n * @example\n * ```typescript\n * await deleteOrganization(config, 'my-org')\n * ```\n */\nexport async function deleteOrganization(\n\tconfig: SylphxConfig,\n\torgIdOrSlug: string,\n): Promise<{ success: boolean }> {\n\treturn callApi<{ success: boolean }>(config, `/orgs/${orgIdOrSlug}`, {\n\t\tmethod: 'DELETE',\n\t})\n}\n\n// ============================================================================\n// Members\n// ============================================================================\n\n/**\n * Get organization members\n *\n * @example\n * ```typescript\n * const { members } = await getOrganizationMembers(config, 'my-org')\n * ```\n */\nexport async function getOrganizationMembers(\n\tconfig: SylphxConfig,\n\torgIdOrSlug: string,\n): Promise<{ members: OrganizationMember[] }> {\n\treturn callApi<{ members: OrganizationMember[] }>(config, `/orgs/${orgIdOrSlug}/members`)\n}\n\n/**\n * Invite a member to an organization\n *\n * Requires admin or super_admin role.\n *\n * @example\n * ```typescript\n * const { invitation } = await inviteOrganizationMember(config, 'my-org', {\n * email: 'user@example.com',\n * role: 'developer',\n * })\n * ```\n */\nexport async function inviteOrganizationMember(\n\tconfig: SylphxConfig,\n\torgIdOrSlug: string,\n\tinput: InviteMemberInput,\n): Promise<{ invitation: OrganizationInvitation }> {\n\treturn callApi<{ invitation: OrganizationInvitation }>(\n\t\tconfig,\n\t\t`/orgs/${orgIdOrSlug}/members/invite`,\n\t\t{\n\t\t\tmethod: 'POST',\n\t\t\tbody: input,\n\t\t},\n\t)\n}\n\n/**\n * Update a member's role\n *\n * Requires admin or super_admin role.\n *\n * @example\n * ```typescript\n * const { member } = await updateOrganizationMemberRole(config, 'my-org', userId, 'admin')\n * ```\n */\nexport async function updateOrganizationMemberRole(\n\tconfig: SylphxConfig,\n\torgIdOrSlug: string,\n\tmemberId: string,\n\trole: OrgRole,\n): Promise<{ member: OrganizationMember }> {\n\treturn callApi<{ member: OrganizationMember }>(\n\t\tconfig,\n\t\t`/orgs/${orgIdOrSlug}/members/${memberId}/role`,\n\t\t{\n\t\t\tmethod: 'PUT',\n\t\t\tbody: { role },\n\t\t},\n\t)\n}\n\n/**\n * Remove a member from an organization\n *\n * Requires admin or super_admin role.\n *\n * @example\n * ```typescript\n * await removeOrganizationMember(config, 'my-org', userId)\n * ```\n */\nexport async function removeOrganizationMember(\n\tconfig: SylphxConfig,\n\torgIdOrSlug: string,\n\tmemberId: string,\n): Promise<{ success: boolean }> {\n\treturn callApi<{ success: boolean }>(config, `/orgs/${orgIdOrSlug}/members/${memberId}`, {\n\t\tmethod: 'DELETE',\n\t})\n}\n\n/**\n * Leave an organization\n *\n * @example\n * ```typescript\n * await leaveOrganization(config, 'my-org')\n * ```\n */\nexport async function leaveOrganization(\n\tconfig: SylphxConfig,\n\torgIdOrSlug: string,\n): Promise<{ success: boolean }> {\n\treturn callApi<{ success: boolean }>(config, `/orgs/${orgIdOrSlug}/leave`, {\n\t\tmethod: 'POST',\n\t})\n}\n\n// ============================================================================\n// Invitations\n// ============================================================================\n\n/**\n * Get pending invitations for an organization\n *\n * Requires admin or super_admin role.\n *\n * @example\n * ```typescript\n * const { invitations } = await getOrganizationInvitations(config, 'my-org')\n * ```\n */\nexport async function getOrganizationInvitations(\n\tconfig: SylphxConfig,\n\torgIdOrSlug: string,\n): Promise<{ invitations: OrganizationInvitation[] }> {\n\treturn callApi<{ invitations: OrganizationInvitation[] }>(\n\t\tconfig,\n\t\t`/orgs/${orgIdOrSlug}/invitations`,\n\t)\n}\n\n/**\n * Accept an organization invitation\n *\n * @example\n * ```typescript\n * const { organization } = await acceptOrganizationInvitation(config, invitationToken)\n * ```\n */\nexport async function acceptOrganizationInvitation(\n\tconfig: SylphxConfig,\n\ttoken: string,\n): Promise<{ organization: Organization }> {\n\treturn callApi<{ organization: Organization }>(config, '/orgs/invitations/accept', {\n\t\tmethod: 'POST',\n\t\tbody: { token },\n\t})\n}\n\n/**\n * Revoke a pending invitation\n *\n * Requires admin or super_admin role.\n *\n * @example\n * ```typescript\n * await revokeOrganizationInvitation(config, 'my-org', invitationId)\n * ```\n */\nexport async function revokeOrganizationInvitation(\n\tconfig: SylphxConfig,\n\torgIdOrSlug: string,\n\tinvitationId: string,\n): Promise<{ success: boolean }> {\n\treturn callApi<{ success: boolean }>(config, `/orgs/${orgIdOrSlug}/invitations/${invitationId}`, {\n\t\tmethod: 'DELETE',\n\t})\n}\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\n/**\n * Check if user has a specific role or higher in the organization\n */\nexport function hasRole(membership: OrganizationMembership | null, minimumRole: OrgRole): boolean {\n\tif (!membership) return false\n\n\tconst roleHierarchy: OrgRole[] = [\n\t\t'viewer',\n\t\t'analytics',\n\t\t'developer',\n\t\t'billing',\n\t\t'admin',\n\t\t'super_admin',\n\t]\n\n\tconst userRoleIndex = roleHierarchy.indexOf(membership.role)\n\tconst requiredRoleIndex = roleHierarchy.indexOf(minimumRole)\n\n\treturn userRoleIndex >= requiredRoleIndex\n}\n\n/**\n * Check if user can manage members (invite, remove, change roles)\n */\nexport function canManageMembers(membership: OrganizationMembership | null): boolean {\n\treturn hasRole(membership, 'admin')\n}\n\n/**\n * Check if user can manage organization settings\n */\nexport function canManageSettings(membership: OrganizationMembership | null): boolean {\n\treturn hasRole(membership, 'admin')\n}\n\n/**\n * Check if user can delete the organization\n */\nexport function canDeleteOrganization(membership: OrganizationMembership | null): boolean {\n\treturn hasRole(membership, 'super_admin')\n}\n","/**\n * Permission Functions\n *\n * Pure functions for permission management — no hidden state.\n * Each function takes config as the first parameter.\n *\n * Uses REST API at /permissions/* for project-scoped operations.\n * Uses REST API at /orgs/{orgId}/members/{memberId}/permissions for member checks.\n *\n * Types are self-contained (not dependent on generated OpenAPI spec) because\n * the RBAC routes were added after the last spec generation.\n */\n\nimport { callApi, type SylphxConfig } from './config'\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * A permission definition within a project.\n *\n * Permissions are the atomic building blocks of RBAC roles.\n * They use colon-separated keys (e.g. \"org:members:read\", \"payroll:approve\").\n */\nexport interface Permission {\n\t/** Prefixed permission ID (e.g. \"perm_xxx\") */\n\tid: string\n\t/** Unique key within the project (e.g. \"org:members:read\") */\n\tkey: string\n\t/** Human-readable name */\n\tname: string\n\t/** Optional description */\n\tdescription: string | null\n\t/** Whether this is a system-defined permission (immutable) */\n\tisSystem: boolean\n\t/** ISO 8601 creation timestamp */\n\tcreatedAt: string\n}\n\n/**\n * Input for creating a custom permission.\n */\nexport interface CreatePermissionInput {\n\t/** Unique key — colon-separated lowercase segments (e.g. \"org:leave:approve\") */\n\tkey: string\n\t/** Human-readable name */\n\tname: string\n\t/** Optional description */\n\tdescription?: string\n}\n\n/**\n * Resolved permissions for a member, including their assigned role.\n */\nexport interface MemberPermissionsResult {\n\t/** Prefixed user ID of the member */\n\tmemberId: string\n\t/** Assigned role (null if no role assigned) */\n\trole: { key: string; name: string } | null\n\t/** Flattened, deduplicated permission keys from all assigned roles */\n\tpermissions: string[]\n}\n\n// ============================================================================\n// Permission CRUD (project-scoped, requires secretKey)\n// ============================================================================\n\n/**\n * List all permissions for the current project.\n *\n * Returns both system-defined and custom permissions.\n * Requires a secret key (server-side only).\n *\n * @example\n * ```typescript\n * const { permissions } = await listPermissions(config)\n * console.log(permissions.map(p => p.key))\n * // ['org:members:read', 'org:members:manage', 'payroll:view', ...]\n * ```\n */\nexport async function listPermissions(\n\tconfig: SylphxConfig,\n): Promise<{ permissions: Permission[] }> {\n\treturn callApi<{ permissions: Permission[] }>(config, '/permissions')\n}\n\n/**\n * Create a custom permission for the project.\n *\n * Permission keys must be colon-separated lowercase segments\n * (e.g. \"org:leave:approve\", \"payroll:run\").\n * Requires a secret key (server-side only).\n *\n * @example\n * ```typescript\n * const { permission } = await createPermission(config, {\n * key: 'payroll:approve',\n * name: 'Approve Payroll',\n * description: 'Can approve payroll runs for the organization',\n * })\n * ```\n */\nexport async function createPermission(\n\tconfig: SylphxConfig,\n\tinput: CreatePermissionInput,\n): Promise<{ permission: Permission }> {\n\treturn callApi<{ permission: Permission }>(config, '/permissions', {\n\t\tmethod: 'POST',\n\t\tbody: input,\n\t})\n}\n\n/**\n * Delete a custom permission by key.\n *\n * System permissions cannot be deleted.\n * Role-permission assignments are removed automatically via cascading delete.\n * Requires a secret key (server-side only).\n *\n * @example\n * ```typescript\n * const { success } = await deletePermission(config, 'payroll:approve')\n * ```\n */\nexport async function deletePermission(\n\tconfig: SylphxConfig,\n\tpermissionKey: string,\n): Promise<{ success: boolean }> {\n\treturn callApi<{ success: boolean }>(config, `/permissions/${permissionKey}`, {\n\t\tmethod: 'DELETE',\n\t})\n}\n\n// ============================================================================\n// Member Permissions (org-scoped, requires accessToken)\n// ============================================================================\n\n/**\n * Get a member's resolved permissions within an organization.\n *\n * Returns the flattened, deduplicated set of permission keys from all\n * roles assigned to the member. Also returns their current role info.\n * Requires the caller to be a member of the same organization.\n *\n * @example\n * ```typescript\n * const result = await getMemberPermissions(config, 'my-org', 'usr_abc123')\n * console.log(result.permissions)\n * // ['org:members:read', 'payroll:view', 'payroll:approve']\n * console.log(result.role)\n * // { key: 'hr_manager', name: 'HR Manager' }\n * ```\n */\nexport async function getMemberPermissions(\n\tconfig: SylphxConfig,\n\torgIdOrSlug: string,\n\tmemberId: string,\n): Promise<MemberPermissionsResult> {\n\treturn callApi<MemberPermissionsResult>(\n\t\tconfig,\n\t\t`/orgs/${orgIdOrSlug}/members/${memberId}/permissions`,\n\t)\n}\n\n// ============================================================================\n// Pure Helpers (no API calls — client-side permission checks)\n// ============================================================================\n\n/**\n * Check if a permission set includes a specific permission.\n *\n * Pure function — no API call. Use with permissions from JWT claims\n * (org_permissions) or from getMemberPermissions().\n *\n * @example\n * ```typescript\n * const permissions = ['org:members:read', 'payroll:view']\n * hasPermission(permissions, 'payroll:view') // true\n * hasPermission(permissions, 'payroll:approve') // false\n * ```\n */\nexport function hasPermission(permissions: string[], required: string): boolean {\n\treturn permissions.includes(required)\n}\n\n/**\n * Check if a permission set includes ANY of the required permissions.\n *\n * Pure function — no API call. Returns true if at least one of the\n * required permissions is present.\n *\n * @example\n * ```typescript\n * const permissions = ['org:members:read', 'payroll:view']\n * hasAnyPermission(permissions, ['payroll:view', 'payroll:approve']) // true\n * hasAnyPermission(permissions, ['admin:full', 'super:admin']) // false\n * ```\n */\nexport function hasAnyPermission(permissions: string[], required: string[]): boolean {\n\treturn required.some((perm) => permissions.includes(perm))\n}\n\n/**\n * Check if a permission set includes ALL of the required permissions.\n *\n * Pure function — no API call. Returns true only if every required\n * permission is present.\n *\n * @example\n * ```typescript\n * const permissions = ['org:members:read', 'payroll:view', 'payroll:approve']\n * hasAllPermissions(permissions, ['payroll:view', 'payroll:approve']) // true\n * hasAllPermissions(permissions, ['payroll:view', 'admin:full']) // false\n * ```\n */\nexport function hasAllPermissions(permissions: string[], required: string[]): boolean {\n\treturn required.every((perm) => permissions.includes(perm))\n}\n","/**\n * Role Functions\n *\n * Pure functions for role management — no hidden state.\n * Each function takes config as the first parameter.\n *\n * Uses REST API at /roles/* for project-scoped operations.\n * Uses REST API at /orgs/{orgId}/members/{memberId}/assign-role for assignment.\n *\n * Types are self-contained (not dependent on generated OpenAPI spec) because\n * the RBAC routes were added after the last spec generation.\n */\n\nimport { callApi, type SylphxConfig } from './config'\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * A role definition within a project.\n *\n * Roles bundle permissions into named groups that can be assigned to\n * organization members (e.g. \"HR Manager\", \"Payroll Admin\").\n */\nexport interface Role {\n\t/** Prefixed role ID (e.g. \"role_xxx\") */\n\tid: string\n\t/** Unique key within the project (e.g. \"hr_manager\") */\n\tkey: string\n\t/** Human-readable name */\n\tname: string\n\t/** Optional description */\n\tdescription: string | null\n\t/** Whether this is a system-defined role (metadata immutable) */\n\tisSystem: boolean\n\t/** Whether this role is automatically assigned to new org members */\n\tisDefault: boolean\n\t/** Display order (lower = higher priority) */\n\tsortOrder: number\n\t/** Permission keys assigned to this role */\n\tpermissions: string[]\n\t/** ISO 8601 creation timestamp */\n\tcreatedAt: string\n\t/** ISO 8601 update timestamp (present on roles route response) */\n\tupdatedAt?: string\n}\n\n/**\n * Input for creating a custom role.\n */\nexport interface CreateRoleInput {\n\t/** Unique key — lowercase alphanumeric with underscores (e.g. \"hr_manager\") */\n\tkey: string\n\t/** Human-readable name */\n\tname: string\n\t/** Optional description */\n\tdescription?: string\n\t/** Permission keys to assign to this role */\n\tpermissions?: string[]\n\t/** Whether to auto-assign to new org members */\n\tisDefault?: boolean\n\t/** Display order (lower = higher priority) */\n\tsortOrder?: number\n}\n\n/**\n * Input for updating an existing role.\n *\n * System role metadata (name, description) is immutable, but their\n * permissions can be changed.\n */\nexport interface UpdateRoleInput {\n\t/** Human-readable name (ignored for system roles) */\n\tname?: string\n\t/** Description (ignored for system roles) */\n\tdescription?: string | null\n\t/** Permission keys to assign (replaces existing) */\n\tpermissions?: string[]\n\t/** Whether to auto-assign to new org members */\n\tisDefault?: boolean\n\t/** Display order */\n\tsortOrder?: number\n}\n\n// ============================================================================\n// Role CRUD (project-scoped, requires secretKey)\n// ============================================================================\n\n/**\n * List all roles for the current project.\n *\n * Returns both system-defined and custom roles, each with their\n * assigned permission keys. Requires a secret key (server-side only).\n *\n * @example\n * ```typescript\n * const { roles } = await listRoles(config)\n * for (const role of roles) {\n * console.log(`${role.name}: ${role.permissions.join(', ')}`)\n * }\n * ```\n */\nexport async function listRoles(config: SylphxConfig): Promise<{ roles: Role[] }> {\n\treturn callApi<{ roles: Role[] }>(config, '/roles')\n}\n\n/**\n * Get a single role by key, including its assigned permission keys.\n *\n * Requires a secret key (server-side only).\n *\n * @example\n * ```typescript\n * const { role } = await getRole(config, 'hr_manager')\n * console.log(role.permissions)\n * // ['org:members:read', 'payroll:view', 'payroll:approve']\n * ```\n */\nexport async function getRole(config: SylphxConfig, roleKey: string): Promise<{ role: Role }> {\n\treturn callApi<{ role: Role }>(config, `/roles/${roleKey}`)\n}\n\n/**\n * Create a custom role with optional permission assignments.\n *\n * Role keys must be lowercase alphanumeric with underscores\n * (e.g. \"hr_manager\", \"payroll_admin\").\n * Requires a secret key (server-side only).\n *\n * @example\n * ```typescript\n * const { role } = await createRole(config, {\n * key: 'hr_manager',\n * name: 'HR Manager',\n * description: 'Can manage employees and approve leave',\n * permissions: ['org:members:read', 'leave:approve', 'payroll:view'],\n * })\n * ```\n */\nexport async function createRole(\n\tconfig: SylphxConfig,\n\tinput: CreateRoleInput,\n): Promise<{ role: Role }> {\n\t// Map SDK field names to API field names\n\tconst body: Record<string, unknown> = {\n\t\tkey: input.key,\n\t\tname: input.name,\n\t}\n\tif (input.description !== undefined) body.description = input.description\n\tif (input.permissions !== undefined) body.permissionKeys = input.permissions\n\tif (input.isDefault !== undefined) body.isDefault = input.isDefault\n\tif (input.sortOrder !== undefined) body.sortOrder = input.sortOrder\n\n\treturn callApi<{ role: Role }>(config, '/roles', {\n\t\tmethod: 'POST',\n\t\tbody,\n\t})\n}\n\n/**\n * Update a role's metadata and/or permission assignments.\n *\n * System role metadata (name, description) is immutable, but their\n * permissions can be changed. Passing `permissions` replaces the\n * entire permission set for the role.\n * Requires a secret key (server-side only).\n *\n * @example\n * ```typescript\n * const { role } = await updateRole(config, 'hr_manager', {\n * permissions: ['org:members:read', 'org:members:manage', 'leave:approve'],\n * })\n * ```\n */\nexport async function updateRole(\n\tconfig: SylphxConfig,\n\troleKey: string,\n\tinput: UpdateRoleInput,\n): Promise<{ role: Role }> {\n\t// Map SDK field names to API field names\n\tconst body: Record<string, unknown> = {}\n\tif (input.name !== undefined) body.name = input.name\n\tif (input.description !== undefined) body.description = input.description\n\tif (input.permissions !== undefined) body.permissionKeys = input.permissions\n\tif (input.isDefault !== undefined) body.isDefault = input.isDefault\n\tif (input.sortOrder !== undefined) body.sortOrder = input.sortOrder\n\n\treturn callApi<{ role: Role }>(config, `/roles/${roleKey}`, {\n\t\tmethod: 'PUT',\n\t\tbody,\n\t})\n}\n\n/**\n * Delete a custom role by key.\n *\n * System roles cannot be deleted. Roles with active member assignments\n * cannot be deleted — reassign members first.\n * Requires a secret key (server-side only).\n *\n * @example\n * ```typescript\n * const { success } = await deleteRole(config, 'hr_manager')\n * ```\n */\nexport async function deleteRole(\n\tconfig: SylphxConfig,\n\troleKey: string,\n): Promise<{ success: boolean }> {\n\treturn callApi<{ success: boolean }>(config, `/roles/${roleKey}`, {\n\t\tmethod: 'DELETE',\n\t})\n}\n\n// ============================================================================\n// Member Role Assignment (org-scoped, requires accessToken)\n// ============================================================================\n\n/**\n * Assign an RBAC role to an organization member.\n *\n * Replaces any existing role assignment (single-role mode).\n * Requires admin access to the organization.\n *\n * @example\n * ```typescript\n * const { success } = await assignMemberRole(config, 'my-org', 'usr_abc123', 'hr_manager')\n * ```\n */\nexport async function assignMemberRole(\n\tconfig: SylphxConfig,\n\torgIdOrSlug: string,\n\tmemberId: string,\n\troleKey: string,\n): Promise<{ success: boolean }> {\n\treturn callApi<{ success: boolean }>(\n\t\tconfig,\n\t\t`/orgs/${orgIdOrSlug}/members/${memberId}/assign-role`,\n\t\t{\n\t\t\tmethod: 'PUT',\n\t\t\tbody: { roleKey },\n\t\t},\n\t)\n}\n","/**\n * Secrets SDK\n *\n * Secure secrets management for applications.\n * Secrets are encrypted at rest with AES-256-GCM.\n *\n * @example\n * ```typescript\n * import { createConfig, getSecret, getSecrets, listSecretKeys } from '@sylphx/sdk'\n *\n * const config = createConfig({\n * secretKey: process.env.SYLPHX_SECRET_KEY!,\n * })\n *\n * // Get a single secret\n * const dbUrl = await getSecret(config, { key: 'DATABASE_URL' })\n * console.log(dbUrl.value) // postgres://...\n *\n * // Get multiple secrets at once\n * const secrets = await getSecrets(config, {\n * keys: ['DATABASE_URL', 'API_KEY', 'JWT_SECRET']\n * })\n * console.log(secrets.DATABASE_URL) // postgres://...\n *\n * // List all secret keys (without values)\n * const keys = await listSecretKeys(config)\n * keys.forEach(k => console.log(k.key, k.description))\n * ```\n */\n\nimport { callApi, type SylphxConfig } from './config'\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface GetSecretInput {\n\t/** Secret key (uppercase, underscores allowed) */\n\tkey: string\n\t/** Optional environment ID override */\n\tenvironmentId?: string\n}\n\nexport interface GetSecretResult {\n\t/** Secret key */\n\tkey: string\n\t/** Decrypted secret value */\n\tvalue: string\n\t/** Version number */\n\tversion: string\n}\n\nexport interface GetSecretsInput {\n\t/** Array of secret keys to retrieve */\n\tkeys: string[]\n\t/** Optional environment ID override */\n\tenvironmentId?: string\n}\n\n/** Map of key -> decrypted value */\nexport type GetSecretsResult = Record<string, string>\n\nexport interface ListSecretKeysInput {\n\t/** Optional environment ID filter */\n\tenvironmentId?: string\n}\n\nexport interface SecretKeyInfo {\n\t/** Secret key name */\n\tkey: string\n\t/** Human-readable description */\n\tdescription: string | null\n\t/** Current version */\n\tversion: string\n\t/** Whether this is environment-specific */\n\tisEnvironmentSpecific: boolean\n}\n\n// ============================================================================\n// Functions\n// ============================================================================\n\n/**\n * Get a single secret value by key.\n *\n * @param config - SDK configuration\n * @param input - Secret key and optional environment ID\n * @returns Decrypted secret value\n * @throws Error if secret not found or access denied\n *\n * @example\n * ```typescript\n * const secret = await getSecret(config, { key: 'DATABASE_URL' })\n * const dbConnection = createPool(secret.value)\n * ```\n */\nexport async function getSecret(\n\tconfig: SylphxConfig,\n\tinput: GetSecretInput,\n): Promise<GetSecretResult> {\n\treturn callApi<GetSecretResult>(config, '/secrets/get', {\n\t\tmethod: 'POST',\n\t\tbody: {\n\t\t\tkey: input.key,\n\t\t\tenvironmentId: input.environmentId,\n\t\t},\n\t})\n}\n\n/**\n * Get multiple secrets at once.\n *\n * More efficient than multiple getSecret calls.\n *\n * @param config - SDK configuration\n * @param input - Array of secret keys\n * @returns Map of key -> decrypted value\n *\n * @example\n * ```typescript\n * const secrets = await getSecrets(config, {\n * keys: ['DATABASE_URL', 'REDIS_URL', 'JWT_SECRET']\n * })\n *\n * const db = createPool(secrets.DATABASE_URL)\n * const redis = createClient(secrets.REDIS_URL)\n * ```\n */\nexport async function getSecrets(\n\tconfig: SylphxConfig,\n\tinput: GetSecretsInput,\n): Promise<GetSecretsResult> {\n\treturn callApi<GetSecretsResult>(config, '/secrets/getMany', {\n\t\tmethod: 'POST',\n\t\tbody: {\n\t\t\tkeys: input.keys,\n\t\t\tenvironmentId: input.environmentId,\n\t\t},\n\t})\n}\n\n/**\n * List all secret keys (without values).\n *\n * Useful for showing available secrets in UI or debugging.\n *\n * @param config - SDK configuration\n * @param input - Optional environment filter\n * @returns Array of secret key info\n *\n * @example\n * ```typescript\n * const keys = await listSecretKeys(config)\n * console.log('Available secrets:')\n * keys.forEach(k => console.log(` ${k.key}: ${k.description}`))\n * ```\n */\nexport async function listSecretKeys(\n\tconfig: SylphxConfig,\n\tinput: ListSecretKeysInput = {},\n): Promise<SecretKeyInfo[]> {\n\treturn callApi<SecretKeyInfo[]>(config, '/secrets/listKeys', {\n\t\tmethod: 'GET',\n\t\tquery: input.environmentId ? { environmentId: input.environmentId } : undefined,\n\t})\n}\n\n/**\n * Check if a secret exists without retrieving its value.\n *\n * @param config - SDK configuration\n * @param key - Secret key to check\n * @returns true if the secret exists\n *\n * @example\n * ```typescript\n * if (await hasSecret(config, 'STRIPE_SECRET_KEY')) {\n * // Stripe is configured, enable payment features\n * }\n * ```\n */\nexport async function hasSecret(config: SylphxConfig, key: string): Promise<boolean> {\n\ttry {\n\t\tconst keys = await listSecretKeys(config)\n\t\treturn keys.some((k) => k.key === key)\n\t} catch {\n\t\treturn false\n\t}\n}\n\n/**\n * Get all secrets for an environment as an object.\n *\n * Useful for loading all secrets into process.env at startup.\n *\n * @param config - SDK configuration\n * @param environmentId - Optional environment ID\n * @returns Object with all secrets\n *\n * @example\n * ```typescript\n * // Load all secrets into process.env at app startup\n * const secrets = await getAllSecrets(config)\n * Object.assign(process.env, secrets)\n * ```\n */\nexport async function getAllSecrets(\n\tconfig: SylphxConfig,\n\tenvironmentId?: string,\n): Promise<GetSecretsResult> {\n\tconst keys = await listSecretKeys(config, { environmentId })\n\tif (keys.length === 0) {\n\t\treturn {}\n\t}\n\treturn getSecrets(config, { keys: keys.map((k) => k.key), environmentId })\n}\n","/**\n * Search SDK\n *\n * State-of-the-art search with full-text, semantic, and hybrid modes.\n * Powered by PostgreSQL tsvector + pgvector.\n *\n * @example\n * ```typescript\n * import { createConfig, indexDocument, search, batchIndex } from '@sylphx/sdk'\n *\n * const config = createConfig({\n * secretKey: process.env.SYLPHX_SECRET_KEY!,\n * })\n *\n * // Index a document\n * await indexDocument(config, {\n * content: 'How to reset your password...',\n * title: 'Password Reset Guide',\n * namespace: 'help-articles',\n * category: 'account',\n * tags: ['password', 'security'],\n * })\n *\n * // Search (hybrid mode by default)\n * const results = await search(config, {\n * query: 'forgot my login credentials',\n * namespace: 'help-articles',\n * searchType: 'hybrid',\n * highlight: true,\n * })\n *\n * results.results.forEach(r => console.log(r.title, r.score, r.highlight))\n * ```\n */\n\nimport { callApi, type SylphxConfig } from './config'\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface IndexDocumentInput {\n\t/** Document title (weighted higher in search) */\n\ttitle?: string\n\t/** Document content to index */\n\tcontent: string\n\t/** Namespace for data isolation (e.g., 'products', 'articles') */\n\tnamespace?: string\n\t/** External document ID (your system's ID) */\n\texternalId?: string\n\t/** URL or path */\n\turl?: string\n\t/** Searchable metadata */\n\tmetadata?: Record<string, unknown>\n\t/** Category facet for filtering */\n\tcategory?: string\n\t/** Type facet for filtering */\n\ttype?: string\n\t/** Tags facet for filtering */\n\ttags?: string[]\n\t/** Language for full-text search (default: english) */\n\tlanguage?: string\n\t/** Skip embedding generation (for keyword-only search) */\n\tskipEmbedding?: boolean\n\t/** Embedding model to use */\n\tembeddingModel?: string\n}\n\nexport interface IndexDocumentResult {\n\t/** Generated document ID */\n\tid: string\n\t/** External ID if provided */\n\texternalId: string | null\n\t/** Namespace */\n\tnamespace: string\n}\n\nexport interface BatchIndexInput {\n\t/** Documents to index (max 100) */\n\tdocuments: Array<{\n\t\ttitle?: string\n\t\tcontent: string\n\t\texternalId?: string\n\t\turl?: string\n\t\tmetadata?: Record<string, unknown>\n\t\tcategory?: string\n\t\ttype?: string\n\t\ttags?: string[]\n\t}>\n\t/** Namespace for all documents */\n\tnamespace?: string\n\t/** Language for full-text search */\n\tlanguage?: string\n\t/** Skip embedding generation */\n\tskipEmbedding?: boolean\n\t/** Embedding model to use */\n\tembeddingModel?: string\n}\n\nexport interface BatchIndexResult {\n\t/** Number of documents indexed */\n\tindexed: number\n\t/** Generated document IDs */\n\tids: string[]\n}\n\nexport type SearchType = 'keyword' | 'semantic' | 'hybrid'\n\nexport interface SearchInput {\n\t/** Search query text */\n\tquery: string\n\t/** Namespace to search within */\n\tnamespace?: string\n\t/** Search type: keyword, semantic, or hybrid (default) */\n\tsearchType?: SearchType\n\t/** Maximum results to return (default: 10, max: 100) */\n\tlimit?: number\n\t/** Offset for pagination */\n\toffset?: number\n\t/** Minimum similarity threshold (0-1) for semantic search */\n\tminSimilarity?: number\n\t/** Enable typo tolerance (default: true) */\n\ttypoTolerance?: boolean\n\t/** Language for full-text search */\n\tlanguage?: string\n\t/** Facet filters */\n\tfilters?: {\n\t\tcategory?: string\n\t\ttype?: string\n\t\ttags?: string[]\n\t\tmetadata?: Record<string, unknown>\n\t}\n\t/** Include highlighted snippets (default: true) */\n\thighlight?: boolean\n\t/** Embedding model for semantic search */\n\tembeddingModel?: string\n\t/** Track this query for analytics (default: true) */\n\ttrackQuery?: boolean\n\t/** Session ID for analytics */\n\tsessionId?: string\n\t/** User ID for analytics */\n\tuserId?: string\n}\n\nexport interface SearchResultItem {\n\t/** Document ID */\n\tid: string\n\t/** External ID if set */\n\texternalId: string | null\n\t/** Document title */\n\ttitle: string | null\n\t/** Document content */\n\tcontent: string\n\t/** Document URL */\n\turl: string | null\n\t/** Document metadata */\n\tmetadata: Record<string, unknown> | null\n\t/** Category facet */\n\tcategory: string | null\n\t/** Type facet */\n\ttype: string | null\n\t/** Tags facet */\n\ttags: string[] | null\n\t/** Combined score */\n\tscore: number\n\t/** Keyword search score (if hybrid) */\n\tkeywordScore?: number\n\t/** Semantic search score (if hybrid) */\n\tsemanticScore?: number\n\t/** Highlighted snippet (if enabled) */\n\thighlight?: string\n}\n\nexport interface SearchResponse {\n\t/** Search results */\n\tresults: SearchResultItem[]\n\t/** Total results found */\n\ttotal: number\n\t/** Original query */\n\tquery: string\n\t/** Search type used */\n\tsearchType: SearchType\n\t/** Query processing time in ms */\n\tlatencyMs: number\n}\n\nexport interface GetFacetsInput {\n\t/** Namespace to get facets from */\n\tnamespace?: string\n\t/** Facets to retrieve */\n\tfacets?: Array<'category' | 'type' | 'tags'>\n\t/** Filter facets by category or type */\n\tfilters?: {\n\t\tcategory?: string\n\t\ttype?: string\n\t}\n}\n\nexport interface FacetsResponse {\n\tfacets: {\n\t\tcategory?: Array<{ value: string; count: number }>\n\t\ttype?: Array<{ value: string; count: number }>\n\t\ttags?: Array<{ value: string; count: number }>\n\t}\n}\n\nexport interface DeleteDocumentInput {\n\t/** Document ID to delete */\n\tid?: string\n\t/** Or delete by external ID */\n\texternalId?: string\n\t/** Namespace (required if using externalId) */\n\tnamespace?: string\n}\n\nexport interface UpsertDocumentInput extends IndexDocumentInput {\n\t/** External ID is required for upsert */\n\texternalId: string\n}\n\nexport interface UpsertDocumentResult extends IndexDocumentResult {\n\t/** Whether the document was created (true) or updated (false) */\n\tcreated: boolean\n}\n\nexport interface SearchStatsResult {\n\t/** Total documents indexed */\n\ttotalDocuments: number\n\t/** Documents with embeddings */\n\tdocumentsWithEmbedding: number\n\t/** Documents by namespace */\n\tbyNamespace: Array<{ namespace: string; count: number }>\n}\n\nexport interface TrackClickInput {\n\t/** Search query ID */\n\tqueryId: string\n\t/** Clicked document ID */\n\tdocumentId: string\n\t/** Position in results (1-indexed) */\n\tposition: number\n}\n\n// ============================================================================\n// Functions\n// ============================================================================\n\n/**\n * Index a document for search.\n *\n * Automatically generates tsvector for full-text search and\n * optional embedding for semantic search.\n *\n * @param config - SDK configuration\n * @param input - Document to index\n * @returns Indexed document info\n *\n * @example\n * ```typescript\n * const result = await indexDocument(config, {\n * title: 'Getting Started Guide',\n * content: 'Welcome to our platform...',\n * namespace: 'docs',\n * category: 'tutorials',\n * tags: ['beginner', 'setup'],\n * })\n * ```\n */\nexport async function indexDocument(\n\tconfig: SylphxConfig,\n\tinput: IndexDocumentInput,\n): Promise<IndexDocumentResult> {\n\treturn callApi<IndexDocumentResult>(config, '/search/index', {\n\t\tmethod: 'POST',\n\t\tbody: {\n\t\t\ttitle: input.title,\n\t\t\tcontent: input.content,\n\t\t\tnamespace: input.namespace ?? 'default',\n\t\t\texternalId: input.externalId,\n\t\t\turl: input.url,\n\t\t\tmetadata: input.metadata,\n\t\t\tcategory: input.category,\n\t\t\ttype: input.type,\n\t\t\ttags: input.tags,\n\t\t\tlanguage: input.language ?? 'english',\n\t\t\tskipEmbedding: input.skipEmbedding ?? false,\n\t\t\tembeddingModel: input.embeddingModel ?? 'openai/text-embedding-3-small',\n\t\t},\n\t})\n}\n\n/**\n * Index multiple documents in a single batch.\n *\n * More efficient than multiple indexDocument calls.\n * Max 100 documents per batch.\n *\n * @param config - SDK configuration\n * @param input - Documents to index\n * @returns Batch index result\n *\n * @example\n * ```typescript\n * const result = await batchIndex(config, {\n * namespace: 'products',\n * documents: products.map(p => ({\n * title: p.name,\n * content: p.description,\n * externalId: p.id,\n * category: p.category,\n * }))\n * })\n * console.log(`Indexed ${result.indexed} products`)\n * ```\n */\nexport async function batchIndex(\n\tconfig: SylphxConfig,\n\tinput: BatchIndexInput,\n): Promise<BatchIndexResult> {\n\treturn callApi<BatchIndexResult>(config, '/search/batchIndex', {\n\t\tmethod: 'POST',\n\t\tbody: {\n\t\t\tdocuments: input.documents,\n\t\t\tnamespace: input.namespace ?? 'default',\n\t\t\tlanguage: input.language ?? 'english',\n\t\t\tskipEmbedding: input.skipEmbedding ?? false,\n\t\t\tembeddingModel: input.embeddingModel ?? 'openai/text-embedding-3-small',\n\t\t},\n\t})\n}\n\n/**\n * Search documents.\n *\n * Supports three search modes:\n * - `keyword`: Full-text search with typo tolerance\n * - `semantic`: AI-powered vector search\n * - `hybrid`: Combined ranking (default, best results)\n *\n * @param config - SDK configuration\n * @param input - Search query and options\n * @returns Search results with scores\n *\n * @example\n * ```typescript\n * // Hybrid search (recommended)\n * const results = await search(config, {\n * query: 'how to change email address',\n * namespace: 'help',\n * searchType: 'hybrid',\n * highlight: true,\n * })\n *\n * results.results.forEach(r => {\n * console.log(`[${r.score.toFixed(3)}] ${r.title}`)\n * console.log(r.highlight)\n * })\n * ```\n */\nexport async function search(config: SylphxConfig, input: SearchInput): Promise<SearchResponse> {\n\treturn callApi<SearchResponse>(config, '/search/search', {\n\t\tmethod: 'POST',\n\t\tbody: {\n\t\t\tquery: input.query,\n\t\t\tnamespace: input.namespace ?? 'default',\n\t\t\tsearchType: input.searchType ?? 'hybrid',\n\t\t\tlimit: input.limit ?? 10,\n\t\t\toffset: input.offset ?? 0,\n\t\t\tminSimilarity: input.minSimilarity,\n\t\t\ttypoTolerance: input.typoTolerance ?? true,\n\t\t\tlanguage: input.language ?? 'english',\n\t\t\tfilters: input.filters,\n\t\t\thighlight: input.highlight ?? true,\n\t\t\tembeddingModel: input.embeddingModel ?? 'openai/text-embedding-3-small',\n\t\t\ttrackQuery: input.trackQuery ?? true,\n\t\t\tsessionId: input.sessionId,\n\t\t\tuserId: input.userId,\n\t\t},\n\t})\n}\n\n/**\n * Get facet counts for filtering.\n *\n * Returns counts of documents by category, type, and tags.\n *\n * @param config - SDK configuration\n * @param input - Facet options\n * @returns Facet counts\n *\n * @example\n * ```typescript\n * const facets = await getFacets(config, {\n * namespace: 'products',\n * facets: ['category', 'type'],\n * })\n *\n * facets.facets.category?.forEach(f => {\n * console.log(`${f.value}: ${f.count} products`)\n * })\n * ```\n */\nexport async function getFacets(\n\tconfig: SylphxConfig,\n\tinput: GetFacetsInput = {},\n): Promise<FacetsResponse> {\n\treturn callApi<FacetsResponse>(config, '/search/getFacets', {\n\t\tmethod: 'POST',\n\t\tbody: {\n\t\t\tnamespace: input.namespace ?? 'default',\n\t\t\tfacets: input.facets ?? ['category', 'type'],\n\t\t\tfilters: input.filters,\n\t\t},\n\t})\n}\n\n/**\n * Delete a document from the search index.\n *\n * @param config - SDK configuration\n * @param input - Document ID or external ID\n * @returns Deletion result\n *\n * @example\n * ```typescript\n * // Delete by internal ID\n * await deleteDocument(config, { id: 'doc-uuid-123' })\n *\n * // Delete by external ID\n * await deleteDocument(config, {\n * externalId: 'product-456',\n * namespace: 'products'\n * })\n * ```\n */\nexport async function deleteDocument(\n\tconfig: SylphxConfig,\n\tinput: DeleteDocumentInput,\n): Promise<{ deleted: number }> {\n\treturn callApi<{ deleted: number }>(config, '/search/delete', {\n\t\tmethod: 'POST',\n\t\tbody: {\n\t\t\tid: input.id,\n\t\t\texternalId: input.externalId,\n\t\t\tnamespace: input.namespace ?? 'default',\n\t\t},\n\t})\n}\n\n/**\n * Upsert a document (insert or update by externalId).\n *\n * If a document with the same externalId exists, it will be replaced.\n * Otherwise, a new document is created.\n *\n * @param config - SDK configuration\n * @param input - Document to upsert (externalId required)\n * @returns Upsert result\n *\n * @example\n * ```typescript\n * const result = await upsertDocument(config, {\n * externalId: 'product-123',\n * title: 'Updated Product Name',\n * content: 'New description...',\n * namespace: 'products',\n * })\n * console.log(result.created ? 'Created' : 'Updated')\n * ```\n */\nexport async function upsertDocument(\n\tconfig: SylphxConfig,\n\tinput: UpsertDocumentInput,\n): Promise<UpsertDocumentResult> {\n\treturn callApi<UpsertDocumentResult>(config, '/search/upsert', {\n\t\tmethod: 'POST',\n\t\tbody: {\n\t\t\ttitle: input.title,\n\t\t\tcontent: input.content,\n\t\t\tnamespace: input.namespace ?? 'default',\n\t\t\texternalId: input.externalId,\n\t\t\turl: input.url,\n\t\t\tmetadata: input.metadata,\n\t\t\tcategory: input.category,\n\t\t\ttype: input.type,\n\t\t\ttags: input.tags,\n\t\t\tlanguage: input.language ?? 'english',\n\t\t\tskipEmbedding: input.skipEmbedding ?? false,\n\t\t\tembeddingModel: input.embeddingModel ?? 'openai/text-embedding-3-small',\n\t\t},\n\t})\n}\n\n/**\n * Get search index statistics.\n *\n * @param config - SDK configuration\n * @param namespace - Optional namespace filter\n * @returns Index statistics\n *\n * @example\n * ```typescript\n * const stats = await getSearchStats(config)\n * console.log(`Total docs: ${stats.totalDocuments}`)\n * console.log(`With embeddings: ${stats.documentsWithEmbedding}`)\n * ```\n */\nexport async function getSearchStats(\n\tconfig: SylphxConfig,\n\tnamespace?: string,\n): Promise<SearchStatsResult> {\n\treturn callApi<SearchStatsResult>(config, '/search/getStats', {\n\t\tmethod: 'POST',\n\t\tbody: { namespace },\n\t})\n}\n\n/**\n * Track a click on a search result.\n *\n * Use this to improve search quality over time.\n *\n * @param config - SDK configuration\n * @param input - Click information\n * @returns Success status\n *\n * @example\n * ```typescript\n * await trackClick(config, {\n * queryId: searchResponse.queryId,\n * documentId: clickedResult.id,\n * position: 3,\n * })\n * ```\n */\nexport async function trackClick(\n\tconfig: SylphxConfig,\n\tinput: TrackClickInput,\n): Promise<{ success: boolean }> {\n\treturn callApi<{ success: boolean }>(config, '/search/trackClick', {\n\t\tmethod: 'POST',\n\t\tbody: input,\n\t})\n}\n","/**\n * Database Functions\n *\n * Pure functions for retrieving Platform-provisioned database connection strings.\n * Server-side only (requires secret key `sk_*`).\n *\n * The Platform provisions a PostgreSQL database for each app and encrypts\n * the connection string. These functions retrieve and decrypt the connection\n * string at startup, so your app never needs to store it.\n *\n * @example\n * ```ts\n * import { createConfig, getDatabaseConnectionString } from '@sylphx/sdk'\n *\n * const config = createConfig({ secretKey: process.env.SYLPHX_SECRET_KEY! })\n * const { connectionString } = await getDatabaseConnectionString(config)\n *\n * const pool = new Pool({ connectionString })\n * ```\n */\n\nimport { callApi, type SylphxConfig } from './config'\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport type DatabaseStatus =\n\t| 'provisioning'\n\t| 'ready'\n\t| 'suspended'\n\t| 'failed'\n\t| 'deleted'\n\t| 'not_provisioned'\n\nexport interface DatabaseConnectionInfo {\n\t/** Decrypted PostgreSQL connection string */\n\tconnectionString: string\n\t/** Database name */\n\tdatabaseName: string\n\t/** Database role/user name */\n\troleName: string | null\n\t/** Database provisioning status */\n\tstatus: Exclude<DatabaseStatus, 'not_provisioned'>\n}\n\nexport interface DatabaseStatusInfo {\n\t/** Current database status */\n\tstatus: DatabaseStatus\n\t/** Provisioned region */\n\tregion: string | null\n\t/** PostgreSQL major version */\n\tpgVersion: number | null\n\t/** Database name */\n\tdatabaseName: string | null\n}\n\n// ============================================================================\n// Functions\n// ============================================================================\n\n/**\n * Get the provisioned PostgreSQL connection string for this app.\n *\n * Requires secret key authentication (server-side only).\n * The connection string is decrypted on the Platform and returned in plaintext.\n *\n * @throws `NOT_FOUND` if no database has been provisioned for this app\n * @throws `UNPROCESSABLE_ENTITY` if database is not yet ready\n *\n * @example\n * ```ts\n * const { connectionString } = await getDatabaseConnectionString(config)\n * const pool = new Pool({ connectionString })\n * ```\n */\nexport async function getDatabaseConnectionString(\n\tconfig: SylphxConfig,\n): Promise<DatabaseConnectionInfo> {\n\treturn callApi<DatabaseConnectionInfo>(config, '/sdk/database/connection-string', {\n\t\tmethod: 'GET',\n\t})\n}\n\n/**\n * Get the current status of the provisioned database.\n *\n * Use this to check if the database is ready before attempting to connect.\n * Requires secret key authentication (server-side only).\n *\n * @example\n * ```ts\n * const { status } = await getDatabaseStatus(config)\n * if (status === 'ready') {\n * // Connect to database\n * }\n * ```\n */\nexport async function getDatabaseStatus(config: SylphxConfig): Promise<DatabaseStatusInfo> {\n\treturn callApi<DatabaseStatusInfo>(config, '/sdk/database/status', {\n\t\tmethod: 'GET',\n\t})\n}\n","/**\n * KV (Key-Value Store) Functions\n *\n * Pure functions for distributed key-value storage backed by Redis.\n * Supports strings, hashes, lists, sorted sets, and built-in rate limiting.\n *\n * Keys are automatically namespaced per app, so no key collisions occur\n * between different apps on the same Platform.\n *\n * @example\n * ```ts\n * import { createConfig, kvSet, kvGet, kvDelete } from '@sylphx/sdk'\n *\n * const config = createConfig({ secretKey: process.env.SYLPHX_SECRET_KEY! })\n *\n * // Basic key-value operations\n * await kvSet(config, { key: 'user:123', value: { name: 'Alice' }, ex: 3600 })\n * const user = await kvGet(config, 'user:123')\n * await kvDelete(config, 'user:123')\n * ```\n */\n\n// Type-only imports from @sylphx/contract per ADR-084 Rule 3 — prevents\n// Effect runtime types from leaking into the published .d.ts surface.\nimport type {\n\tKvDeleteResult as ContractKvDeleteResult,\n\tKvExistsResult as ContractKvExistsResult,\n\tKvExpireInput as ContractKvExpireInput,\n\tKvIncrInput as ContractKvIncrInput,\n\tKvIncrResult as ContractKvIncrResult,\n\tKvRateLimitInput as ContractKvRateLimitInput,\n\tKvScanResult as ContractKvScanResult,\n\tKvSetInput as ContractKvSetInput,\n\tKvSetResult as ContractKvSetResult,\n} from '@sylphx/contract'\nimport { kvEndpoints } from '@sylphx/contract'\nimport { callApi, type SylphxConfig } from './config'\nimport type { KvRateLimitResult, KvSetOptions, KvZMember } from './kv-types'\n\n// Re-export shared types\nexport type { KvRateLimitResult, KvSetOptions, KvZMember } from './kv-types'\n\n/**\n * Interpolate `:param` placeholders in a path template with URL-encoded values.\n *\n * Example: `interpolatePath('/sdk/kv/get/:key', { key: 'a/b' })` → `/sdk/kv/get/a%2Fb`.\n */\nfunction interpolatePath(template: string, params: Record<string, string>): string {\n\tlet path = template\n\tfor (const [key, value] of Object.entries(params)) {\n\t\tpath = path.replace(`:${key}`, encodeURIComponent(value))\n\t}\n\treturn path\n}\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface KvSetRequest extends KvSetOptions {\n\t/** Key to store */\n\tkey: string\n\t/** Value to store (any JSON-serializable value) */\n\tvalue: unknown\n}\n\nexport interface KvMsetRequest {\n\t/** Key-value pairs to set in a single atomic operation */\n\tentries: Array<{ key: string; value: unknown }>\n}\n\nexport interface KvMgetRequest {\n\t/** Keys to retrieve */\n\tkeys: string[]\n}\n\nexport interface KvHsetRequest {\n\t/** Hash key */\n\tkey: string\n\t/** Field-value pairs to set on the hash */\n\tfields: Record<string, unknown>\n}\n\nexport interface KvHgetRequest {\n\t/** Hash key */\n\tkey: string\n\t/** Field to get */\n\tfield: string\n}\n\nexport interface KvHgetallRequest {\n\t/** Hash key */\n\tkey: string\n}\n\nexport interface KvLpushRequest {\n\t/** List key */\n\tkey: string\n\t/** Values to prepend (left push) */\n\tvalues: unknown[]\n}\n\nexport interface KvLrangeRequest {\n\t/** List key */\n\tkey: string\n\t/** Start index (0-based, negative counts from end) */\n\tstart: number\n\t/** Stop index (inclusive, negative counts from end) */\n\tstop: number\n}\n\nexport interface KvZaddRequest {\n\t/** Sorted set key */\n\tkey: string\n\t/** Members with scores to add */\n\tmembers: KvZMember[]\n}\n\nexport interface KvZrangeRequest {\n\t/** Sorted set key */\n\tkey: string\n\t/** Start index or score */\n\tstart: number | string\n\t/** Stop index or score */\n\tstop: number | string\n\t/** Return scores alongside members */\n\twithScores?: boolean\n\t/** Reverse order */\n\trev?: boolean\n\t/** Treat start/stop as scores (BYSCORE) */\n\tbyScore?: boolean\n}\n\nexport interface KvIncrRequest {\n\t/** Key to increment */\n\tkey: string\n\t/** Amount to increment by (default: 1) */\n\tby?: number\n}\n\nexport interface KvExpireRequest {\n\t/** Key to set expiry on */\n\tkey: string\n\t/** TTL in seconds */\n\tseconds: number\n}\n\nexport interface KvRateLimitRequest {\n\t/** Rate limit identifier (e.g., userId, IP) */\n\tidentifier: string\n\t/** Maximum requests allowed in the window */\n\tlimit: number\n\t/** Window duration in seconds */\n\twindow: number\n}\n\n// ============================================================================\n// Functions — Basic Operations\n// ============================================================================\n\n/**\n * Set a key-value pair, with optional TTL and conditional flags.\n *\n * @example\n * ```ts\n * // Simple set\n * await kvSet(config, { key: 'session:abc', value: { userId: '123' }, ex: 86400 })\n *\n * // Set only if not exists (NX)\n * await kvSet(config, { key: 'lock:task', value: '1', ex: 30, nx: true })\n * ```\n */\nexport async function kvSet(config: SylphxConfig, request: KvSetRequest): Promise<{ ok: boolean }> {\n\t// Contract-derived path/method (SSOT per ADR-084).\n\t// `KvSetRequest` is structurally compatible with `ContractKvSetInput` (key/value/ex/nx/xx).\n\tconst body = request satisfies ContractKvSetInput\n\tconst endpoint = kvEndpoints.set\n\treturn callApi<ContractKvSetResult>(config, endpoint.path, {\n\t\tmethod: endpoint.method,\n\t\tbody,\n\t})\n}\n\n/**\n * Get a value by key.\n *\n * Returns `null` if the key does not exist or has expired.\n *\n * @example\n * ```ts\n * const session = await kvGet<{ userId: string }>(config, 'session:abc')\n * if (session) {\n * console.log(session.userId)\n * }\n * ```\n */\nexport async function kvGet<T = unknown>(config: SylphxConfig, key: string): Promise<T | null> {\n\t// Contract-derived path/method (SSOT per ADR-084).\n\tconst endpoint = kvEndpoints.get\n\tconst result = await callApi<{ value: T | null }>(\n\t\tconfig,\n\t\tinterpolatePath(endpoint.path, { key }),\n\t\t{ method: endpoint.method },\n\t)\n\treturn result.value\n}\n\n/**\n * Delete one or more keys.\n *\n * @example\n * ```ts\n * const { deleted } = await kvDelete(config, 'session:abc')\n * console.log(`Deleted ${deleted} keys`)\n * ```\n */\nexport async function kvDelete(config: SylphxConfig, key: string): Promise<{ deleted: number }> {\n\t// Contract-derived path/method (SSOT per ADR-084).\n\tconst endpoint = kvEndpoints.delete\n\treturn callApi<ContractKvDeleteResult>(config, interpolatePath(endpoint.path, { key }), {\n\t\tmethod: endpoint.method,\n\t})\n}\n\n/**\n * Check if a key exists.\n *\n * @example\n * ```ts\n * const { exists } = await kvExists(config, 'session:abc')\n * ```\n */\nexport async function kvExists(config: SylphxConfig, key: string): Promise<{ exists: boolean }> {\n\t// Contract-derived path/method (SSOT per ADR-084).\n\tconst endpoint = kvEndpoints.exists\n\treturn callApi<ContractKvExistsResult>(config, interpolatePath(endpoint.path, { key }), {\n\t\tmethod: endpoint.method,\n\t})\n}\n\n/**\n * Set expiry on an existing key.\n *\n * @example\n * ```ts\n * await kvExpire(config, { key: 'session:abc', seconds: 3600 })\n * ```\n */\nexport async function kvExpire(\n\tconfig: SylphxConfig,\n\trequest: KvExpireRequest,\n): Promise<{ ok: boolean }> {\n\t// Contract-derived path/method (SSOT per ADR-084).\n\tconst body = request satisfies ContractKvExpireInput\n\tconst endpoint = kvEndpoints.expire\n\treturn callApi<ContractKvSetResult>(config, endpoint.path, {\n\t\tmethod: endpoint.method,\n\t\tbody,\n\t})\n}\n\n/**\n * Increment a numeric value.\n *\n * @example\n * ```ts\n * const { value } = await kvIncr(config, { key: 'page:views', by: 1 })\n * ```\n */\nexport async function kvIncr(\n\tconfig: SylphxConfig,\n\trequest: KvIncrRequest,\n): Promise<{ value: number }> {\n\t// Contract-derived path/method (SSOT per ADR-084).\n\tconst body = request satisfies ContractKvIncrInput\n\tconst endpoint = kvEndpoints.incr\n\treturn callApi<ContractKvIncrResult>(config, endpoint.path, {\n\t\tmethod: endpoint.method,\n\t\tbody,\n\t})\n}\n\n// ============================================================================\n// Functions — Bulk Operations\n// ============================================================================\n\n/**\n * Set multiple key-value pairs atomically.\n */\nexport async function kvMset(\n\tconfig: SylphxConfig,\n\trequest: KvMsetRequest,\n): Promise<{ ok: boolean }> {\n\treturn callApi<{ ok: boolean }>(config, '/sdk/kv/mset', {\n\t\tmethod: 'POST',\n\t\tbody: request,\n\t})\n}\n\n/**\n * Get multiple values by keys in a single request.\n *\n * Returns `null` for keys that don't exist.\n */\nexport async function kvMget<T = unknown>(\n\tconfig: SylphxConfig,\n\trequest: KvMgetRequest,\n): Promise<Array<T | null>> {\n\tconst result = await callApi<{ values: Array<T | null> }>(config, '/sdk/kv/mget', {\n\t\tmethod: 'POST',\n\t\tbody: request,\n\t})\n\treturn result.values\n}\n\n// ============================================================================\n// Functions — Hash Operations\n// ============================================================================\n\n/**\n * Set fields on a hash key.\n *\n * @example\n * ```ts\n * await kvHset(config, { key: 'user:123', fields: { name: 'Alice', age: 30 } })\n * ```\n */\nexport async function kvHset(\n\tconfig: SylphxConfig,\n\trequest: KvHsetRequest,\n): Promise<{ count: number }> {\n\treturn callApi<{ count: number }>(config, '/sdk/kv/hset', {\n\t\tmethod: 'POST',\n\t\tbody: request,\n\t})\n}\n\n/**\n * Get a single field from a hash key.\n */\nexport async function kvHget<T = unknown>(\n\tconfig: SylphxConfig,\n\trequest: KvHgetRequest,\n): Promise<T | null> {\n\tconst result = await callApi<{ value: T | null }>(config, '/sdk/kv/hget', {\n\t\tmethod: 'POST',\n\t\tbody: request,\n\t})\n\treturn result.value\n}\n\n/**\n * Get all fields from a hash key.\n */\nexport async function kvHgetall<T extends Record<string, unknown> = Record<string, unknown>>(\n\tconfig: SylphxConfig,\n\trequest: KvHgetallRequest,\n): Promise<T | null> {\n\tconst result = await callApi<{ value: T | null }>(config, '/sdk/kv/hgetall', {\n\t\tmethod: 'POST',\n\t\tbody: request,\n\t})\n\treturn result.value\n}\n\n// ============================================================================\n// Functions — List Operations\n// ============================================================================\n\n/**\n * Left-push values onto a list.\n *\n * @example\n * ```ts\n * const { length } = await kvLpush(config, { key: 'events', values: [event] })\n * ```\n */\nexport async function kvLpush(\n\tconfig: SylphxConfig,\n\trequest: KvLpushRequest,\n): Promise<{ length: number }> {\n\treturn callApi<{ length: number }>(config, '/sdk/kv/lpush', {\n\t\tmethod: 'POST',\n\t\tbody: request,\n\t})\n}\n\n/**\n * Get a range of elements from a list.\n *\n * @example\n * ```ts\n * // Get last 10 events\n * const items = await kvLrange(config, { key: 'events', start: 0, stop: 9 })\n * ```\n */\nexport async function kvLrange<T = unknown>(\n\tconfig: SylphxConfig,\n\trequest: KvLrangeRequest,\n): Promise<T[]> {\n\tconst result = await callApi<{ items: T[] }>(config, '/sdk/kv/lrange', {\n\t\tmethod: 'POST',\n\t\tbody: request,\n\t})\n\treturn result.items\n}\n\n// ============================================================================\n// Functions — Sorted Set Operations\n// ============================================================================\n\n/**\n * Add members to a sorted set.\n *\n * @example\n * ```ts\n * // Add to leaderboard\n * await kvZadd(config, {\n * key: 'leaderboard',\n * members: [{ member: 'user:123', score: 1500 }],\n * })\n * ```\n */\nexport async function kvZadd(\n\tconfig: SylphxConfig,\n\trequest: KvZaddRequest,\n): Promise<{ added: number }> {\n\treturn callApi<{ added: number }>(config, '/sdk/kv/zadd', {\n\t\tmethod: 'POST',\n\t\tbody: request,\n\t})\n}\n\n/**\n * Get a range of members from a sorted set.\n *\n * @example\n * ```ts\n * // Get top 10 leaderboard entries\n * const entries = await kvZrange(config, {\n * key: 'leaderboard',\n * start: 0,\n * stop: 9,\n * rev: true,\n * withScores: true,\n * })\n * ```\n */\nexport async function kvZrange(\n\tconfig: SylphxConfig,\n\trequest: KvZrangeRequest,\n): Promise<Array<{ member: string; score?: number }>> {\n\tconst result = await callApi<{\n\t\tmembers: Array<{ member: string; score?: number }>\n\t}>(config, '/sdk/kv/zrange', {\n\t\tmethod: 'POST',\n\t\tbody: request,\n\t})\n\treturn result.members\n}\n\n// ============================================================================\n// Functions — Rate Limiting\n// ============================================================================\n\n/**\n * Check and consume a rate limit token using Redis sliding window.\n *\n * This is a built-in rate limiter — no external service needed.\n *\n * @example\n * ```ts\n * // 10 requests per 60 seconds per user\n * const result = await kvRateLimit(config, {\n * identifier: `user:${userId}`,\n * limit: 10,\n * window: 60,\n * })\n *\n * if (!result.success) {\n * return Response.json({ error: 'Rate limit exceeded' }, { status: 429 })\n * }\n * ```\n */\nexport async function kvRateLimit(\n\tconfig: SylphxConfig,\n\trequest: KvRateLimitRequest,\n): Promise<KvRateLimitResult> {\n\t// Contract-derived path/method (SSOT per ADR-084).\n\tconst body = request satisfies ContractKvRateLimitInput\n\tconst endpoint = kvEndpoints.rateLimit\n\treturn callApi<KvRateLimitResult>(config, endpoint.path, {\n\t\tmethod: endpoint.method,\n\t\tbody,\n\t})\n}\n\n// ============================================================================\n// Functions — Scan / Iteration\n// ============================================================================\n\nexport interface KvScanOptions {\n\t/** Key pattern to match (e.g. 'user:*'). Defaults to '*' (all keys). */\n\tpattern?: string\n\t/** Cursor for pagination. Use '0' to start a new scan (default). */\n\tcursor?: string\n\t/** Hint to Redis for how many keys to return per iteration (1–1000). Default: 100. */\n\tcount?: number\n}\n\nexport interface KvScanResult {\n\t/** Keys matching the pattern (namespace prefix stripped). */\n\tkeys: string[]\n\t/** Cursor for the next page. Pass this as `cursor` in the next call. */\n\tnextCursor: string\n\t/** True when the full keyspace has been scanned (nextCursor is '0'). */\n\tdone: boolean\n}\n\n/**\n * Scan keys matching a pattern using Redis SCAN (cursor-based pagination).\n *\n * Unlike `KEYS`, SCAN is safe to use in production — it iterates incrementally.\n * Call repeatedly with the returned `nextCursor` until `done` is true.\n *\n * @example\n * ```ts\n * // Iterate all user keys\n * let cursor = '0'\n * do {\n * const result = await kvScan(config, { pattern: 'user:*', cursor })\n * for (const key of result.keys) console.log(key)\n * cursor = result.nextCursor\n * } while (!result.done)\n * ```\n */\nexport async function kvScan(config: SylphxConfig, options?: KvScanOptions): Promise<KvScanResult> {\n\t// Contract-derived path/method (SSOT per ADR-084).\n\t// TODO ADR-084 shape reconcile: contract's `KvScanResult.keys` is\n\t// `readonly string[]` but the SDK promises a mutable `string[]` to\n\t// consumers. Cast is safe at runtime (same array).\n\tconst endpoint = kvEndpoints.scan\n\treturn callApi<ContractKvScanResult>(config, endpoint.path, {\n\t\tmethod: endpoint.method,\n\t\tquery: {\n\t\t\t...(options?.pattern !== undefined && { pattern: options.pattern }),\n\t\t\t...(options?.cursor !== undefined && { cursor: options.cursor }),\n\t\t\t...(options?.count !== undefined && { count: String(options.count) }),\n\t\t},\n\t}) as Promise<KvScanResult>\n}\n\n// ============================================================================\n// Convenience — JSON helpers\n// ============================================================================\n\n/**\n * Get a JSON value by key. Automatically parses the stored JSON string.\n *\n * Returns `null` if the key does not exist or has expired.\n *\n * @example\n * ```ts\n * const profile = await kvGetJSON<UserProfile>(config, 'user:123:profile')\n * if (profile) console.log(profile.name)\n * ```\n */\nexport async function kvGetJSON<T = unknown>(config: SylphxConfig, key: string): Promise<T | null> {\n\tconst raw = await kvGet<string>(config, key)\n\tif (raw === null) return null\n\ttry {\n\t\treturn JSON.parse(raw) as T\n\t} catch {\n\t\treturn null\n\t}\n}\n\n/**\n * Set a JSON value by key. Automatically serializes the value to JSON.\n *\n * @example\n * ```ts\n * await kvSetJSON(config, 'user:123:profile', { name: 'Alice', plan: 'pro' }, { ex: 3600 })\n * ```\n */\nexport async function kvSetJSON<T>(\n\tconfig: SylphxConfig,\n\tkey: string,\n\tvalue: T,\n\toptions?: KvSetOptions,\n): Promise<{ ok: boolean }> {\n\treturn kvSet(config, { key, value: JSON.stringify(value), ...options })\n}\n","/**\n * Deploy Functions\n *\n * Pure functions for managing app deployments, environment variables,\n * and custom domains via the Platform Deploy API.\n *\n * Requires secret key authentication (`sk_*`).\n *\n * @example\n * ```ts\n * import { createConfig, triggerDeploy, getDeployStatus } from '@sylphx/sdk'\n *\n * const config = createConfig({ secretKey: process.env.SYLPHX_SECRET_KEY! })\n *\n * // Trigger a deployment\n * const deploy = await triggerDeploy(config, { envId: 'env_prod_xxx' })\n *\n * // Poll for completion\n * const status = await getDeployStatus(config, deploy.envId)\n * console.log(status.status) // 'building' | 'deploying' | 'success' | 'failed'\n * ```\n */\n\nimport { callApi, type SylphxConfig } from './config'\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport type DeployStatus = 'queued' | 'building' | 'deploying' | 'success' | 'failed' | 'cancelled'\n\nexport interface DeployInfo {\n\t/** Deployment ID */\n\tdeploymentId: string\n\t/** Environment ID */\n\tenvId: string\n\t/** Current deployment status */\n\tstatus: DeployStatus\n\t/** Deployment URL */\n\turl?: string\n\t/** Git commit SHA */\n\tcommitSha?: string\n\t/** Git branch */\n\tbranch?: string\n\t/** Deployment started at (ISO timestamp) */\n\tstartedAt?: string\n\t/** Deployment completed at (ISO timestamp) */\n\tcompletedAt?: string\n\t/** Error message if failed */\n\terror?: string\n}\n\nexport interface TriggerDeployRequest {\n\t/** Environment ID to deploy */\n\tenvId: string\n\t/** Force rebuild without cache */\n\tforceRebuild?: boolean\n}\n\nexport interface RollbackDeployRequest {\n\t/** Environment ID to rollback */\n\tenvId: string\n\t/** Deployment ID to rollback to */\n\tdeploymentId: string\n}\n\nexport interface EnvVar {\n\t/** Environment variable key */\n\tkey: string\n\t/** Environment variable value */\n\tvalue: string\n\t/** Whether value is sensitive (masked in logs) */\n\tsensitive?: boolean\n}\n\nexport interface SetEnvVarRequest {\n\t/** Environment variable key */\n\tkey: string\n\t/** Environment variable value */\n\tvalue: string\n\t/** Whether value is sensitive/secret */\n\tsensitive?: boolean\n}\n\nexport interface DeployHistoryResponse {\n\t/** List of past deployments */\n\tdeployments: DeployInfo[]\n}\n\nexport interface BuildLog {\n\t/** Log line text */\n\ttext: string\n\t/** Log timestamp (ISO) */\n\ttimestamp?: string\n\t/** Log level */\n\tlevel?: 'info' | 'warn' | 'error'\n}\n\nexport interface BuildLogHistoryResponse {\n\t/** Log lines */\n\tlogs: BuildLog[]\n}\n\n// ============================================================================\n// Functions — Deployments\n// ============================================================================\n\n/**\n * Trigger a new deployment for an environment.\n *\n * @example\n * ```ts\n * const deploy = await triggerDeploy(config, { envId: 'env_prod_xxx' })\n * console.log(`Deployment ${deploy.deploymentId} started`)\n * ```\n */\nexport async function triggerDeploy(\n\tconfig: SylphxConfig,\n\trequest: TriggerDeployRequest,\n): Promise<DeployInfo> {\n\treturn callApi<DeployInfo>(config, `/sdk/deploy/trigger/${encodeURIComponent(request.envId)}`, {\n\t\tmethod: 'POST',\n\t\tbody: request.forceRebuild !== undefined ? { forceRebuild: request.forceRebuild } : undefined,\n\t})\n}\n\n/**\n * Get the current deployment status for an environment.\n *\n * @example\n * ```ts\n * const { status } = await getDeployStatus(config, 'env_prod_xxx')\n * if (status === 'success') {\n * console.log('Deployment succeeded!')\n * }\n * ```\n */\nexport async function getDeployStatus(config: SylphxConfig, envId: string): Promise<DeployInfo> {\n\treturn callApi<DeployInfo>(config, `/sdk/deploy/status/${encodeURIComponent(envId)}`, {\n\t\tmethod: 'GET',\n\t})\n}\n\n/**\n * Get deployment history for an environment.\n *\n * @example\n * ```ts\n * const { deployments } = await getDeployHistory(config, 'env_prod_xxx')\n * const lastDeploy = deployments[0]\n * ```\n */\nexport async function getDeployHistory(\n\tconfig: SylphxConfig,\n\tenvId: string,\n): Promise<DeployHistoryResponse> {\n\treturn callApi<DeployHistoryResponse>(\n\t\tconfig,\n\t\t`/sdk/deploy/history/${encodeURIComponent(envId)}`,\n\t\t{ method: 'GET' },\n\t)\n}\n\n/**\n * Rollback an environment to a previous deployment.\n *\n * @example\n * ```ts\n * await rollbackDeploy(config, {\n * envId: 'env_prod_xxx',\n * deploymentId: 'dep_abc123',\n * })\n * ```\n */\nexport async function rollbackDeploy(\n\tconfig: SylphxConfig,\n\trequest: RollbackDeployRequest,\n): Promise<DeployInfo> {\n\treturn callApi<DeployInfo>(config, `/sdk/deploy/rollback/${encodeURIComponent(request.envId)}`, {\n\t\tmethod: 'POST',\n\t\tbody: { deploymentId: request.deploymentId },\n\t})\n}\n\n/**\n * Get stored build log history for an environment.\n *\n * For live log streaming during an active build, use the SSE endpoint\n * directly or the `useDeployLogs` React hook.\n *\n * @example\n * ```ts\n * const { logs } = await getBuildLogHistory(config, 'env_prod_xxx')\n * for (const log of logs) {\n * console.log(log.text)\n * }\n * ```\n */\nexport async function getBuildLogHistory(\n\tconfig: SylphxConfig,\n\tenvId: string,\n): Promise<BuildLogHistoryResponse> {\n\treturn callApi<BuildLogHistoryResponse>(\n\t\tconfig,\n\t\t`/sdk/deploy/logs/${encodeURIComponent(envId)}/history`,\n\t\t{ method: 'GET' },\n\t)\n}\n\n// ============================================================================\n// Functions — Environment Variables\n// ============================================================================\n\n/**\n * List environment variables for a deployment environment.\n *\n * Sensitive values are masked in the response.\n *\n * @example\n * ```ts\n * const envVars = await listEnvVars(config, 'env_prod_xxx')\n * ```\n */\nexport async function listEnvVars(config: SylphxConfig, envId: string): Promise<EnvVar[]> {\n\tconst result = await callApi<{ envVars: EnvVar[] }>(\n\t\tconfig,\n\t\t`/sdk/deploy/envvars/${encodeURIComponent(envId)}`,\n\t\t{ method: 'GET' },\n\t)\n\treturn result.envVars\n}\n\n/**\n * Set (create or update) an environment variable.\n *\n * @example\n * ```ts\n * await setEnvVar(config, 'env_prod_xxx', {\n * key: 'DATABASE_URL',\n * value: 'postgresql://...',\n * sensitive: true,\n * })\n * ```\n */\nexport async function setEnvVar(\n\tconfig: SylphxConfig,\n\tenvId: string,\n\trequest: SetEnvVarRequest,\n): Promise<EnvVar> {\n\treturn callApi<EnvVar>(config, `/sdk/deploy/envvars/${encodeURIComponent(envId)}`, {\n\t\tmethod: 'POST',\n\t\tbody: request,\n\t})\n}\n\n/**\n * Delete an environment variable.\n *\n * @example\n * ```ts\n * await deleteEnvVar(config, 'env_prod_xxx', 'DATABASE_URL')\n * ```\n */\nexport async function deleteEnvVar(\n\tconfig: SylphxConfig,\n\tenvId: string,\n\tkey: string,\n): Promise<{ deleted: boolean }> {\n\treturn callApi<{ deleted: boolean }>(\n\t\tconfig,\n\t\t`/sdk/deploy/envvars/${encodeURIComponent(envId)}/${encodeURIComponent(key)}`,\n\t\t{ method: 'DELETE' },\n\t)\n}\n","/**\n * Monitoring Functions\n *\n * Pure functions for error tracking and log capture.\n * Works client-side and server-side.\n *\n * ## Industry Patterns\n * - **Error grouping via fingerprinting** — Same error only billed once (Sentry pattern)\n * - **Adaptive sampling** — Automatic sample rate adjustment based on quota usage\n * - **Breadcrumb trails** — Contextual trail leading to errors\n *\n * @example\n * ```ts\n * import { createConfig, captureException, captureMessage } from '@sylphx/sdk'\n *\n * const config = createConfig({ appId: process.env.NEXT_PUBLIC_SYLPHX_APP_ID! })\n *\n * // Capture errors\n * try {\n * await riskyOperation()\n * } catch (err) {\n * await captureException(config, err as Error)\n * }\n *\n * // Capture log messages\n * await captureMessage(config, 'User completed onboarding', { level: 'info' })\n * ```\n */\n\n// ADR-084 Wave 2d: contract now carries the Sentry-style envelope\n// (`exception: { values: ExceptionValue[] }`) plus the richer response\n// fields (`eventId`/`isNewError`/`quotaUsage`/`recommendedSampleRate`),\n// matching this SDK's production wire shape. Path is `/sdk/monitoring/*`\n// on both sides. Full contract rewire (runtime import + path derivation)\n// is Agent J's follow-up; this file keeps its SDK-native types until\n// then.\nimport { callApi, type SylphxConfig } from './config'\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport type MonitoringSeverity = 'fatal' | 'error' | 'warning' | 'info'\n\nexport interface ExceptionFrame {\n\t/** Source filename */\n\tfilename?: string\n\t/** Function name */\n\tfunction?: string\n\t/** Line number */\n\tlineno?: number\n\t/** Column number */\n\tcolno?: number\n}\n\nexport interface ExceptionValue {\n\t/** Exception class/type (e.g., \"TypeError\") */\n\ttype: string\n\t/** Exception message */\n\tvalue: string\n\t/** Stack trace frames (innermost first) */\n\tstacktrace?: { frames?: ExceptionFrame[] }\n}\n\nexport interface Breadcrumb {\n\t/** Breadcrumb type (e.g., \"navigation\", \"http\", \"ui.click\") */\n\ttype?: string\n\t/** Log level */\n\tlevel?: MonitoringSeverity\n\t/** Breadcrumb message */\n\tmessage?: string\n\t/** Breadcrumb data */\n\tdata?: Record<string, unknown>\n\t/** Unix timestamp (seconds) */\n\ttimestamp?: number\n}\n\nexport interface CaptureExceptionRequest {\n\t/** Exception value(s) — first is primary, rest are chained causes */\n\texception: { values: ExceptionValue[] }\n\t/** Severity level (default: \"error\") */\n\tlevel?: MonitoringSeverity\n\t/** Current page route */\n\troute?: string\n\t/** User agent string */\n\tuserAgent?: string\n\t/** App release version */\n\trelease?: string\n\t/** Environment name (e.g., \"production\", \"staging\") */\n\tenvironment?: string\n\t/** Custom tags for filtering */\n\ttags?: Record<string, string>\n\t/** Extra context data */\n\textra?: Record<string, unknown>\n\t/** Breadcrumb trail leading to the error */\n\tbreadcrumbs?: Breadcrumb[]\n\t/** Custom fingerprint for grouping (overrides automatic grouping) */\n\tfingerprint?: string[]\n}\n\nexport interface CaptureMessageRequest {\n\t/** Log message */\n\tmessage: string\n\t/** Severity level (default: \"info\") */\n\tlevel?: MonitoringSeverity\n\t/** Current page route */\n\troute?: string\n\t/** App release version */\n\trelease?: string\n\t/** Custom tags for filtering */\n\ttags?: Record<string, string>\n\t/** Extra context data */\n\textra?: Record<string, unknown>\n}\n\nexport interface MonitoringResponse {\n\t/** Internal event ID */\n\teventId: string\n\t/** Whether this is a new unique error (true = billed, false = duplicate = free) */\n\tisNewError: boolean\n\t/** Current quota usage percentage (0-100+). Present when >= 50%. */\n\tquotaUsage?: number\n\t/**\n\t * Recommended client-side sample rate (0.0-1.0).\n\t * Reduce your error capture rate to this value when quota is high.\n\t * Present when quotaUsage >= 50%.\n\t */\n\trecommendedSampleRate?: number\n}\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\n/**\n * Convert a native Error object to ExceptionValue format.\n */\nfunction errorToExceptionValue(error: Error): ExceptionValue {\n\tconst frames: ExceptionFrame[] = []\n\n\tif (error.stack) {\n\t\t// Parse V8/SpiderMonkey style stack traces\n\t\tconst lines = error.stack.split('\\n').slice(1)\n\t\tfor (const line of lines) {\n\t\t\t// V8: \" at functionName (file:line:col)\"\n\t\t\tconst v8Match = line.match(/^\\s+at\\s+(.+?)\\s+\\((.+):(\\d+):(\\d+)\\)$/)\n\t\t\tif (v8Match) {\n\t\t\t\tframes.push({\n\t\t\t\t\tfunction: v8Match[1],\n\t\t\t\t\tfilename: v8Match[2],\n\t\t\t\t\tlineno: Number(v8Match[3]),\n\t\t\t\t\tcolno: Number(v8Match[4]),\n\t\t\t\t})\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\t// V8 (no function): \" at file:line:col\"\n\t\t\tconst v8AnonMatch = line.match(/^\\s+at\\s+(.+):(\\d+):(\\d+)$/)\n\t\t\tif (v8AnonMatch) {\n\t\t\t\tframes.push({\n\t\t\t\t\tfilename: v8AnonMatch[1],\n\t\t\t\t\tlineno: Number(v8AnonMatch[2]),\n\t\t\t\t\tcolno: Number(v8AnonMatch[3]),\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t}\n\n\treturn {\n\t\ttype: error.name || 'Error',\n\t\tvalue: error.message,\n\t\tstacktrace: frames.length > 0 ? { frames } : undefined,\n\t}\n}\n\n// ============================================================================\n// Functions\n// ============================================================================\n\n/**\n * Capture an exception for error tracking.\n *\n * Errors with the same fingerprint are grouped automatically.\n * Duplicate occurrences of the same error are FREE (only new unique\n * errors count against your quota).\n *\n * @example\n * ```ts\n * try {\n * await processPayment(amount)\n * } catch (err) {\n * const result = await captureException(config, err as Error, {\n * tags: { paymentProvider: 'stripe' },\n * extra: { amount, userId },\n * })\n * }\n * ```\n */\nexport async function captureException(\n\tconfig: SylphxConfig,\n\terror: Error,\n\toptions: Omit<CaptureExceptionRequest, 'exception'> = {},\n): Promise<MonitoringResponse> {\n\t// Contract shape (Sentry envelope + rich response) reconciled with this\n\t// SDK in ADR-084 Wave 2d. Paths are already aligned (`/sdk/monitoring/*`).\n\tconst exceptionValue = errorToExceptionValue(error)\n\tconst request: CaptureExceptionRequest = {\n\t\t...options,\n\t\texception: { values: [exceptionValue] },\n\t}\n\treturn callApi<MonitoringResponse>(config, '/sdk/monitoring/exception', {\n\t\tmethod: 'POST',\n\t\tbody: request,\n\t})\n}\n\n/**\n * Capture an exception with full control over the exception payload.\n *\n * Use this for structured exception capture with custom types, chained\n * causes, or when not working with native Error objects.\n */\nexport async function captureExceptionRaw(\n\tconfig: SylphxConfig,\n\trequest: CaptureExceptionRequest,\n): Promise<MonitoringResponse> {\n\treturn callApi<MonitoringResponse>(config, '/sdk/monitoring/exception', {\n\t\tmethod: 'POST',\n\t\tbody: request,\n\t})\n}\n\n/**\n * Capture a log message for monitoring.\n *\n * Like `captureException` but for non-error events (warnings, info, etc.).\n * Messages with the same content are grouped automatically.\n *\n * @example\n * ```ts\n * // Info log\n * await captureMessage(config, 'Payment webhook received', {\n * level: 'info',\n * tags: { provider: 'stripe', event: 'payment.succeeded' },\n * })\n *\n * // Warning\n * await captureMessage(config, 'Slow query detected', {\n * level: 'warning',\n * extra: { queryMs: 2400, query: sql },\n * })\n * ```\n */\nexport async function captureMessage(\n\tconfig: SylphxConfig,\n\tmessage: string,\n\toptions: Omit<CaptureMessageRequest, 'message'> = {},\n): Promise<MonitoringResponse> {\n\tconst request: CaptureMessageRequest = { ...options, message }\n\treturn callApi<MonitoringResponse>(config, '/sdk/monitoring/message', {\n\t\tmethod: 'POST',\n\t\tbody: request,\n\t})\n}\n","/**\n * Sandbox Client\n *\n * Ephemeral compute sandbox API — SOTA direct-connection design.\n *\n * ## Architecture\n *\n * POST /sandboxes → Platform provisions sandbox, waits for pod readiness,\n * returns { endpoint, token }. All subsequent exec/files/pty operations\n * go DIRECTLY to the sandbox exec-server — Platform is not in the data path.\n *\n * ```\n * SDK.create() ──→ Platform API (lifecycle only)\n * ↓ returns endpoint + token\n * SDK.exec() ──→ sandbox exec-server (direct, SSE stream)\n * SDK.files ──→ sandbox exec-server (direct, REST)\n * SDK.pty() ──→ sandbox exec-server (direct, WebSocket)\n * ```\n *\n * ## Usage\n *\n * ```typescript\n * import { createConfig, SandboxClient } from '@sylphx/sdk'\n *\n * const config = createConfig({ secretKey: process.env.SYLPHX_SECRET_KEY!, ref: 'your-ref' })\n *\n * // Create sandbox (Platform waits for pod ready before returning)\n * const sandbox = await SandboxClient.create(config)\n *\n * // Stream exec output in real-time\n * for await (const event of sandbox.exec(['npm', 'install'])) {\n * if (event.type === 'stdout') process.stdout.write(event.data)\n * if (event.type === 'exit') console.log('exit', event.exitCode)\n * }\n *\n * // File operations\n * await sandbox.files.write('/workspace/app.py', 'print(\"hello\")')\n * const content = await sandbox.files.read('/workspace/output.txt')\n *\n * // Terminate when done\n * await sandbox.terminate()\n * ```\n *\n * ## Auth\n * Requires sk_* secret key (server-side only).\n */\n\nimport { callApi, type SylphxConfig } from './config'\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport interface SandboxOptions {\n\t/** Docker image (must be in registry.sylphx.com). Omit to use env default. */\n\timage?: string\n\t/** Idle timeout in ms before auto-termination (default: 300_000 = 5 min) */\n\tidleTimeoutMs?: number\n\t/** Storage size in GiB (enables persistent PVC; default: disabled) */\n\tstorageGi?: number\n\t/** CPU/memory resource spec */\n\tresources?: {\n\t\trequests?: { cpu?: string; memory?: string }\n\t\tlimits?: { cpu?: string; memory?: string }\n\t}\n\t/** Environment variables injected into the sandbox container */\n\tenv?: Record<string, string>\n\t/**\n\t * Shared volume mounts from org-level managed volumes.\n\t * Requires ReadWriteMany volumes (CephFS). Multiple sandboxes can mount\n\t * the same volume for shared filesystem access.\n\t */\n\tvolumeMounts?: Array<{\n\t\t/** Volume resource ID (from `sylphx volumes list`) */\n\t\tvolumeId: string\n\t\t/** Absolute path inside the container (e.g. \"/shared\") */\n\t\tmountPath: string\n\t\t/** Optional sub-path within the volume */\n\t\tsubPath?: string\n\t\t/** Read-only mount (default: false) */\n\t\treadOnly?: boolean\n\t}>\n}\n\n/** SSE event emitted by sandbox.exec() */\nexport type ExecEvent =\n\t| { type: 'stdout'; data: string }\n\t| { type: 'stderr'; data: string }\n\t| { type: 'exit'; exitCode: number; durationMs: number; timedOut?: boolean }\n\t| { type: 'error'; message: string }\n\n/** Non-streaming exec result (all output collected, returned at once) */\nexport interface ExecResult {\n\tstdout: string\n\tstderr: string\n\texitCode: number\n\tdurationMs: number\n}\n\n/** @deprecated Use ExecResult */\nexport type CommandResult = ExecResult\n\n/** @deprecated File operations are now handled by SandboxFiles class */\nexport interface SandboxFile {\n\tpath: string\n\tcontent: string\n\tencoding?: 'utf8' | 'base64'\n}\n\nexport interface ExecOptions {\n\tcwd?: string\n\tenv?: Record<string, string>\n\ttimeout?: number\n\tstdin?: string\n}\n\n// =============================================================================\n// Process API Types\n// =============================================================================\n\nexport interface ProcessStartOptions {\n\t/** Command + args (e.g. ['npm', 'install']) */\n\tcommand: string[]\n\t/** Working directory */\n\tcwd?: string\n\t/** Environment variables */\n\tenv?: Record<string, string>\n\t/** Hard timeout in seconds (0 = no timeout) */\n\ttimeoutSeconds?: number\n\t/** Open stdin pipe for writing */\n\tstdin?: boolean\n}\n\nexport interface ProcessInfo {\n\tid: string\n\tpid: number\n\tcommand: string[]\n\tcwd: string\n\tstatus: 'running' | 'exited' | 'killed' | 'timeout'\n\texitCode: number | null\n\tsignal: string | null\n\tstartedAt: string\n\texitedAt: string | null\n\tdurationMs: number | null\n\tstdout: string\n\tstderr: string\n}\n\nexport interface ProcessSummary {\n\tid: string\n\tpid: number\n\tcommand: string[]\n\tstatus: 'running' | 'exited' | 'killed' | 'timeout'\n\texitCode: number | null\n\tstartedAt: string\n\texitedAt: string | null\n\tdurationMs: number | null\n}\n\n/** SSE event from a process stream */\nexport type ProcessEvent =\n\t| { type: 'stdout'; pid: number; data: string }\n\t| { type: 'stderr'; pid: number; data: string }\n\t| { type: 'exit'; pid: number; exitCode: number }\n\n// =============================================================================\n// Watch API Types\n// =============================================================================\n\nexport interface WatchOptions {\n\t/** Path to watch (relative to /workspace or absolute) */\n\tpath: string\n\t/** Watch subdirectories recursively (default: true) */\n\trecursive?: boolean\n\t/** Additional patterns to ignore */\n\tignore?: string[]\n}\n\nexport interface WatchEntry {\n\tpath: string\n\trecursive: boolean\n\tcreatedAt: string\n}\n\n/** File change event delivered via SSE /events stream */\nexport interface FileEvent {\n\ttype: 'file'\n\tpath: string\n\tevent: 'created' | 'modified' | 'deleted'\n}\n\nexport interface SandboxRecord {\n\tid: string\n\tstatus: 'starting' | 'running' | 'idle' | 'terminated' | 'error'\n\timage: string\n\t/** Public HTTPS endpoint: https://sbx-xxx.sandboxes.sylphx.app */\n\tendpoint: string | null\n\t/** Per-sandbox RS256 JWT for direct exec-server authentication */\n\ttoken: string | null\n\tprojectId: string\n\tidleTimeoutMs: number\n\tcreatedAt: string\n\tstartedAt: string | null\n\texpiresAt: string | null\n\tterminatedAt: string | null\n}\n\n// =============================================================================\n// Files namespace\n// =============================================================================\n\nexport class SandboxFiles {\n\tconstructor(\n\t\tprivate readonly endpoint: string,\n\t\tprivate readonly token: string,\n\t) {}\n\n\tprivate authHeader(): Record<string, string> {\n\t\treturn { Authorization: `Bearer ${this.token}` }\n\t}\n\n\t/** Write a file to the sandbox filesystem. */\n\tasync write(\n\t\tpath: string,\n\t\tcontent: string | Buffer,\n\t\tencoding: 'utf8' | 'base64' = 'utf8',\n\t): Promise<void> {\n\t\tconst contentStr = Buffer.isBuffer(content) ? content.toString('base64') : content\n\t\tconst effectiveEncoding = Buffer.isBuffer(content) ? 'base64' : encoding\n\n\t\tconst res = await fetch(`${this.endpoint}/files`, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: { ...this.authHeader(), 'Content-Type': 'application/json' },\n\t\t\tbody: JSON.stringify({ path, content: contentStr, encoding: effectiveEncoding }),\n\t\t})\n\t\tif (!res.ok) throw new Error(`files.write failed: ${await res.text()}`)\n\t}\n\n\t/** Read a file from the sandbox filesystem. Returns content as string. */\n\tasync read(path: string): Promise<string> {\n\t\tconst res = await fetch(`${this.endpoint}/files?path=${encodeURIComponent(path)}`, {\n\t\t\theaders: this.authHeader(),\n\t\t})\n\t\tif (!res.ok) throw new Error(`files.read failed: ${await res.text()}`)\n\t\tconst data = (await res.json()) as { content: string }\n\t\treturn data.content\n\t}\n\n\t/** Delete a file from the sandbox filesystem. */\n\tasync delete(path: string): Promise<void> {\n\t\tconst res = await fetch(`${this.endpoint}/files?path=${encodeURIComponent(path)}`, {\n\t\t\tmethod: 'DELETE',\n\t\t\theaders: this.authHeader(),\n\t\t})\n\t\tif (!res.ok) throw new Error(`files.delete failed: ${await res.text()}`)\n\t}\n\n\t/** List files in a directory. */\n\tasync list(path = '/'): Promise<string[]> {\n\t\tconst res = await fetch(`${this.endpoint}/list?path=${encodeURIComponent(path)}`, {\n\t\t\theaders: this.authHeader(),\n\t\t})\n\t\tif (!res.ok) throw new Error(`files.list failed: ${await res.text()}`)\n\t\tconst data = (await res.json()) as { files: string[] }\n\t\treturn data.files\n\t}\n}\n\n// =============================================================================\n// Process namespace\n// =============================================================================\n\nexport class SandboxProcesses {\n\tconstructor(\n\t\tprivate readonly endpoint: string,\n\t\tprivate readonly token: string,\n\t) {}\n\n\tprivate authHeader(): Record<string, string> {\n\t\treturn { Authorization: `Bearer ${this.token}` }\n\t}\n\n\t/** Spawn a new tracked process. Returns processId + pid immediately. */\n\tasync start(opts: ProcessStartOptions): Promise<{ id: string; pid: number }> {\n\t\tconst res = await fetch(`${this.endpoint}/process/start`, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: { ...this.authHeader(), 'Content-Type': 'application/json' },\n\t\t\tbody: JSON.stringify(opts),\n\t\t})\n\t\tif (!res.ok) throw new Error(`process.start failed: ${await res.text()}`)\n\t\treturn (await res.json()) as { id: string; pid: number }\n\t}\n\n\t/** List all tracked processes. */\n\tasync list(): Promise<ProcessSummary[]> {\n\t\tconst res = await fetch(`${this.endpoint}/process/list`, {\n\t\t\theaders: this.authHeader(),\n\t\t})\n\t\tif (!res.ok) throw new Error(`process.list failed: ${await res.text()}`)\n\t\treturn (await res.json()) as ProcessSummary[]\n\t}\n\n\t/** Get full process info including buffered output. */\n\tasync get(processId: string): Promise<ProcessInfo> {\n\t\tconst res = await fetch(`${this.endpoint}/process/${processId}`, {\n\t\t\theaders: this.authHeader(),\n\t\t})\n\t\tif (!res.ok) throw new Error(`process.get failed: ${await res.text()}`)\n\t\treturn (await res.json()) as ProcessInfo\n\t}\n\n\t/** Send a signal to a process. */\n\tasync kill(processId: string, signal: string = 'SIGTERM'): Promise<void> {\n\t\tconst res = await fetch(`${this.endpoint}/process/${processId}/kill`, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: { ...this.authHeader(), 'Content-Type': 'application/json' },\n\t\t\tbody: JSON.stringify({ signal }),\n\t\t})\n\t\tif (!res.ok) throw new Error(`process.kill failed: ${await res.text()}`)\n\t}\n\n\t/** Write to process stdin. */\n\tasync writeStdin(processId: string, data: string): Promise<void> {\n\t\tconst res = await fetch(`${this.endpoint}/process/${processId}/input`, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: { ...this.authHeader(), 'Content-Type': 'application/json' },\n\t\t\tbody: JSON.stringify({ data }),\n\t\t})\n\t\tif (!res.ok) throw new Error(`process.writeStdin failed: ${await res.text()}`)\n\t}\n\n\t/**\n\t * Wait for a process to complete and return its final info.\n\t * Polls every 500ms until status is no longer 'running'.\n\t *\n\t * For real-time output, use stream() instead.\n\t */\n\tasync wait(processId: string, timeoutMs = 300_000): Promise<ProcessInfo> {\n\t\tconst deadline = Date.now() + timeoutMs\n\t\twhile (Date.now() < deadline) {\n\t\t\tconst info = await this.get(processId)\n\t\t\tif (info.status !== 'running') return info\n\t\t\tawait new Promise((r) => setTimeout(r, 500))\n\t\t}\n\t\tthrow new Error(`Timed out waiting for process ${processId} to complete (${timeoutMs}ms)`)\n\t}\n\n\t/** Stream process output as async iterable SSE events. */\n\tasync *stream(processId: string): AsyncGenerator<ProcessEvent> {\n\t\tconst res = await fetch(`${this.endpoint}/process/${processId}/stream`, {\n\t\t\theaders: this.authHeader(),\n\t\t})\n\t\tif (!res.ok) throw new Error(`process.stream failed: ${await res.text()}`)\n\t\tif (!res.body) throw new Error('process.stream: no response body')\n\n\t\tconst decoder = new TextDecoder()\n\t\tconst reader = res.body.getReader()\n\t\tlet buffer = ''\n\n\t\ttry {\n\t\t\twhile (true) {\n\t\t\t\tconst { done, value } = await reader.read()\n\t\t\t\tif (done) break\n\t\t\t\tbuffer += decoder.decode(value, { stream: true })\n\t\t\t\tconst lines = buffer.split('\\n')\n\t\t\t\tbuffer = lines.pop() ?? ''\n\t\t\t\tfor (const line of lines) {\n\t\t\t\t\tif (line.startsWith('data: ')) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst event = JSON.parse(line.slice(6)) as ProcessEvent\n\t\t\t\t\t\t\tyield event\n\t\t\t\t\t\t\tif (event.type === 'exit') return\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t/* skip malformed */\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} finally {\n\t\t\treader.releaseLock()\n\t\t}\n\t}\n}\n\n// =============================================================================\n// Watch namespace\n// =============================================================================\n\nexport class SandboxWatch {\n\tconstructor(\n\t\tprivate readonly endpoint: string,\n\t\tprivate readonly token: string,\n\t) {}\n\n\tprivate authHeader(): Record<string, string> {\n\t\treturn { Authorization: `Bearer ${this.token}` }\n\t}\n\n\t/** Start watching a path. Events delivered via sandbox.events() SSE stream. */\n\tasync add(opts: WatchOptions): Promise<WatchEntry> {\n\t\tconst res = await fetch(`${this.endpoint}/watch`, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: { ...this.authHeader(), 'Content-Type': 'application/json' },\n\t\t\tbody: JSON.stringify(opts),\n\t\t})\n\t\tif (!res.ok) throw new Error(`watch.add failed: ${await res.text()}`)\n\t\treturn (await res.json()) as WatchEntry\n\t}\n\n\t/** List active watches. */\n\tasync list(): Promise<WatchEntry[]> {\n\t\tconst res = await fetch(`${this.endpoint}/watch`, {\n\t\t\theaders: this.authHeader(),\n\t\t})\n\t\tif (!res.ok) throw new Error(`watch.list failed: ${await res.text()}`)\n\t\tconst data = (await res.json()) as { watches: WatchEntry[] }\n\t\treturn data.watches\n\t}\n\n\t/** Stop watching a path. */\n\tasync remove(path: string): Promise<void> {\n\t\tconst res = await fetch(`${this.endpoint}/watch?path=${encodeURIComponent(path)}`, {\n\t\t\tmethod: 'DELETE',\n\t\t\theaders: this.authHeader(),\n\t\t})\n\t\tif (!res.ok) throw new Error(`watch.remove failed: ${await res.text()}`)\n\t}\n}\n\n// =============================================================================\n// SandboxClient\n// =============================================================================\n\nexport class SandboxClient {\n\treadonly id: string\n\tprivate readonly config: SylphxConfig\n\n\t/** Public endpoint from Platform (may be null for sandboxes from pool pre-v2) */\n\treadonly endpoint: string | null\n\t/** Per-sandbox JWT for direct exec-server auth */\n\treadonly token: string | null\n\n\t/** File operations (direct to exec-server) */\n\treadonly files: SandboxFiles | null\n\n\t/** Concurrent process management (direct to exec-server) */\n\treadonly processes: SandboxProcesses | null\n\n\t/** Filesystem watch management (direct to exec-server) */\n\treadonly watch: SandboxWatch | null\n\n\tprivate constructor(\n\t\tid: string,\n\t\tconfig: SylphxConfig,\n\t\tendpoint: string | null,\n\t\ttoken: string | null,\n\t) {\n\t\tthis.id = id\n\t\tthis.config = config\n\t\tthis.endpoint = endpoint\n\t\tthis.token = token\n\t\tthis.files = endpoint && token ? new SandboxFiles(endpoint, token) : null\n\t\tthis.processes = endpoint && token ? new SandboxProcesses(endpoint, token) : null\n\t\tthis.watch = endpoint && token ? new SandboxWatch(endpoint, token) : null\n\t}\n\n\t// ---------------------------------------------------------------------------\n\t// Factory\n\t// ---------------------------------------------------------------------------\n\n\t/**\n\t * Create a new sandbox.\n\t *\n\t * Platform provisions the K8s pod, waits for readiness, and returns\n\t * { endpoint, token } once the sandbox is fully ready to accept traffic.\n\t * No client-side polling required.\n\t */\n\tstatic async create(config: SylphxConfig, options?: SandboxOptions): Promise<SandboxClient> {\n\t\tconst record = await callApi<SandboxRecord>(config, '/sandboxes', {\n\t\t\tmethod: 'POST',\n\t\t\tbody: {\n\t\t\t\timage: options?.image,\n\t\t\t\tidleTimeoutMs: options?.idleTimeoutMs ?? 300_000,\n\t\t\t\tresources: options?.resources,\n\t\t\t\tenv: options?.env,\n\t\t\t\tstorage:\n\t\t\t\t\toptions?.storageGi !== undefined\n\t\t\t\t\t\t? { enabled: true, sizeGi: options.storageGi }\n\t\t\t\t\t\t: undefined,\n\t\t\t\tvolumeMounts: options?.volumeMounts,\n\t\t\t},\n\t\t})\n\n\t\treturn new SandboxClient(record.id, config, record.endpoint, record.token)\n\t}\n\n\t/**\n\t * Reconnect to an existing sandbox by ID.\n\t * Fetches the current status to get the endpoint + token.\n\t */\n\tstatic async fromId(config: SylphxConfig, sandboxId: string): Promise<SandboxClient> {\n\t\tconst record = await callApi<SandboxRecord>(config, `/sandboxes/${sandboxId}`, {\n\t\t\tmethod: 'GET',\n\t\t})\n\t\treturn new SandboxClient(record.id, config, record.endpoint, record.token)\n\t}\n\n\t// ---------------------------------------------------------------------------\n\t// Lifecycle\n\t// ---------------------------------------------------------------------------\n\n\tasync getStatus(): Promise<SandboxRecord> {\n\t\treturn callApi<SandboxRecord>(this.config, `/sandboxes/${this.id}`, { method: 'GET' })\n\t}\n\n\tasync terminate(): Promise<void> {\n\t\tawait callApi<{ success: boolean }>(this.config, `/sandboxes/${this.id}`, { method: 'DELETE' })\n\t}\n\n\t// ---------------------------------------------------------------------------\n\t// Exec — SSE streaming (primary)\n\t// ---------------------------------------------------------------------------\n\n\t/**\n\t * Execute a command and stream output as async iterable SSE events.\n\t *\n\t * **Stateless mode**: each exec() call runs in an isolated bash invocation.\n\t * Shell state (CWD changes, exported env vars, functions) is NOT preserved\n\t * between calls.\n\t *\n\t * For state-preserving execution (CWD, env), use `run()` which runs in the\n\t * persistent active shell and returns the result once complete.\n\t *\n\t * For streaming + state-preserving (advanced), combine `sandbox.events()` with `run()`:\n\t * ```typescript\n\t * const eventStream = sandbox.events({ type: 'stdout' })\n\t * sandbox.run(['npm', 'install']) // don't await yet\n\t * for await (const ev of eventStream) { ... }\n\t * ```\n\t *\n\t * @example\n\t * ```typescript\n\t * for await (const event of sandbox.exec(['npm', 'install'])) {\n\t * if (event.type === 'stdout') process.stdout.write(event.data)\n\t * if (event.type === 'exit') console.log('Done:', event.exitCode)\n\t * }\n\t * ```\n\t */\n\tasync *exec(command: string[], options?: ExecOptions): AsyncGenerator<ExecEvent> {\n\t\tthis.assertDirect()\n\n\t\t// POST /exec with stateless:true, stream:true → exec-server returns SSE response.\n\t\t// 'stateless' runs in an isolated bash process (not the active shell).\n\t\t// Without stateless:true, /exec runs in the active shell and returns JSON — not SSE.\n\t\tconst res = await fetch(`${this.endpoint!}/exec`, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: {\n\t\t\t\tAuthorization: `Bearer ${this.token!}`,\n\t\t\t\t'Content-Type': 'application/json',\n\t\t\t},\n\t\t\tbody: JSON.stringify({ command, ...options, stateless: true, stream: true }),\n\t\t})\n\n\t\tif (!res.ok) {\n\t\t\tthrow new Error(`exec failed (${res.status}): ${await res.text()}`)\n\t\t}\n\t\tif (!res.body) throw new Error('exec: no response body')\n\n\t\t// Parse SSE stream\n\t\tconst decoder = new TextDecoder()\n\t\tconst reader = res.body.getReader()\n\t\tlet buffer = ''\n\n\t\ttry {\n\t\t\twhile (true) {\n\t\t\t\tconst { done, value } = await reader.read()\n\t\t\t\tif (done) break\n\n\t\t\t\tbuffer += decoder.decode(value, { stream: true })\n\t\t\t\tconst lines = buffer.split('\\n')\n\t\t\t\tbuffer = lines.pop() ?? '' // Keep incomplete last line\n\n\t\t\t\tfor (const line of lines) {\n\t\t\t\t\tif (line.startsWith('data: ')) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst event = JSON.parse(line.slice(6)) as ExecEvent\n\t\t\t\t\t\t\tyield event\n\t\t\t\t\t\t\tif (event.type === 'exit' || event.type === 'error') return\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t// Malformed SSE data — skip\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} finally {\n\t\t\treader.releaseLock()\n\t\t}\n\t}\n\n\t/**\n\t * Execute a command and collect all output (non-streaming).\n\t * Convenience wrapper over exec() for simple use cases.\n\t *\n\t * For long-running commands, prefer exec() to stream output incrementally.\n\t */\n\tasync run(command: string[], options?: ExecOptions): Promise<ExecResult> {\n\t\tlet stdout = ''\n\t\tlet stderr = ''\n\t\tlet exitCode = 1\n\t\tlet durationMs = 0\n\n\t\tfor await (const event of this.exec(command, options)) {\n\t\t\tif (event.type === 'stdout') stdout += event.data\n\t\t\telse if (event.type === 'stderr') stderr += event.data\n\t\t\telse if (event.type === 'exit') {\n\t\t\t\texitCode = event.exitCode\n\t\t\t\tdurationMs = event.durationMs\n\t\t\t}\n\t\t}\n\n\t\treturn { stdout, stderr, exitCode, durationMs }\n\t}\n\n\t// ---------------------------------------------------------------------------\n\t// Events — Unified SSE stream\n\t// ---------------------------------------------------------------------------\n\n\t/**\n\t * Subscribe to the unified event stream (SSE).\n\t *\n\t * Receives all sandbox events: stdout, stderr, exit, port, file, shell, resource.\n\t * Filter by type/pid/shellId using query params.\n\t *\n\t * @example\n\t * ```typescript\n\t * for await (const event of sandbox.events({ type: 'file' })) {\n\t * console.log('File changed:', event.path, event.event)\n\t * }\n\t * ```\n\t */\n\tasync *events(filter?: {\n\t\ttype?: 'stdout' | 'stderr' | 'exit' | 'port' | 'file' | 'shell' | 'resource'\n\t\tpid?: number\n\t\tshellId?: string\n\t}): AsyncGenerator<Record<string, unknown>> {\n\t\tthis.assertDirect()\n\n\t\tconst params = new URLSearchParams()\n\t\tif (filter?.type) params.set('type', filter.type)\n\t\tif (filter?.pid !== undefined) params.set('pid', String(filter.pid))\n\t\tif (filter?.shellId) params.set('shellId', filter.shellId)\n\n\t\tconst qs = params.toString()\n\t\tconst url = `${this.endpoint!}/events${qs ? `?${qs}` : ''}`\n\n\t\tconst res = await fetch(url, {\n\t\t\theaders: { Authorization: `Bearer ${this.token!}` },\n\t\t})\n\n\t\tif (!res.ok) throw new Error(`events failed (${res.status}): ${await res.text()}`)\n\t\tif (!res.body) throw new Error('events: no response body')\n\n\t\tconst decoder = new TextDecoder()\n\t\tconst reader = res.body.getReader()\n\t\tlet buffer = ''\n\n\t\ttry {\n\t\t\twhile (true) {\n\t\t\t\tconst { done, value } = await reader.read()\n\t\t\t\tif (done) break\n\t\t\t\tbuffer += decoder.decode(value, { stream: true })\n\t\t\t\tconst lines = buffer.split('\\n')\n\t\t\t\tbuffer = lines.pop() ?? ''\n\t\t\t\tfor (const line of lines) {\n\t\t\t\t\tif (line.startsWith('data: ')) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tyield JSON.parse(line.slice(6)) as Record<string, unknown>\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t/* skip malformed */\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} finally {\n\t\t\treader.releaseLock()\n\t\t}\n\t}\n\n\t// ---------------------------------------------------------------------------\n\t// PTY — Interactive terminal (WebSocket)\n\t// ---------------------------------------------------------------------------\n\n\t/**\n\t * Open an interactive PTY session (WebSocket).\n\t *\n\t * Returns a WebSocket connected to a bash shell in the sandbox.\n\t * Token is passed as a query param (WebSocket doesn't support custom headers in browsers).\n\t *\n\t * @example\n\t * ```typescript\n\t * const ws = await sandbox.pty()\n\t * ws.on('message', (data) => process.stdout.write(JSON.parse(data).data))\n\t * ws.send(JSON.stringify({ type: 'input', data: 'ls -la\\n' }))\n\t * ws.send(JSON.stringify({ type: 'resize', cols: 120, rows: 40 }))\n\t * ```\n\t */\n\tpty(): WebSocket {\n\t\tthis.assertDirect()\n\n\t\tconst wsEndpoint = this.endpoint!.replace(/^https:\\/\\//, 'wss://').replace(\n\t\t\t/^http:\\/\\//,\n\t\t\t'ws://',\n\t\t)\n\n\t\treturn new WebSocket(`${wsEndpoint}/pty?token=${encodeURIComponent(this.token!)}`)\n\t}\n\n\t// ---------------------------------------------------------------------------\n\t// Private\n\t// ---------------------------------------------------------------------------\n\n\tprivate assertDirect(): void {\n\t\tif (!this.endpoint || !this.token) {\n\t\t\tthrow new Error(\n\t\t\t\t'Sandbox endpoint/token not available. ' +\n\t\t\t\t\t'This sandbox was created with an older SDK version or does not have a public endpoint.',\n\t\t\t)\n\t\t}\n\t}\n}\n","/**\n * Runs Client (ADR-040, formerly Workers)\n *\n * Fire-and-forget batch compute API (Modal-style run-to-completion jobs).\n *\n * Runs are ephemeral K8s Jobs that run to completion. Use them for:\n * - ML training folds (walk-forward cross-validation)\n * - Data processing pipelines\n * - Batch inference\n * - Any parallelisable CPU-heavy work\n *\n * ## Usage\n *\n * ### Single worker\n * ```typescript\n * import { createConfig, RunsClient } from '@sylphx/sdk'\n *\n * const config = createConfig({ secretKey: process.env.SYLPHX_SECRET_KEY!, ref: 'my-project' })\n *\n * const run = await RunsClient.create(config, {\n * image: 'registry.sylphx.com/sylphx/my-trainer:abc123',\n * command: ['python', 'train.py', '--fold', '0'],\n * resources: { requests: { cpu: '4', memory: '8Gi' } },\n * timeoutSeconds: 3600,\n * })\n *\n * const result = await worker.wait()\n * console.log(result.exitCode) // 0\n * console.log(result.stdout) // captured stdout\n * ```\n *\n * ### Parallel workers (walk-forward training)\n * ```typescript\n * const workers = await Promise.all(\n * folds.map((fold) =>\n * RunsClient.create(config, {\n * image: 'registry.sylphx.com/sylphx/trainer:abc123',\n * command: ['python', 'train.py', '--fold', String(fold.id)],\n * env: { FOLD_ID: String(fold.id), DATABASE_URL: process.env.DATABASE_URL! },\n * resources: { requests: { cpu: '4', memory: '8Gi' } },\n * volumeMounts: [{ volumeId: sharedCacheVolumeId, mountPath: '/cache' }],\n * timeoutSeconds: 7200,\n * }),\n * ),\n * )\n *\n * const results = await Promise.all(workers.map((w) => w.wait()))\n * const failures = results.filter((r) => r.exitCode !== 0)\n * ```\n *\n * ## Architecture\n *\n * - Workers are K8s Jobs (backoffLimit: 0, no restarts)\n * - Images must be from registry.sylphx.com (scanned, private)\n * - Volumes: org-level volumeResources mounted as PVCs\n * - ReadWriteOnce → rook-ceph-block (single pod)\n * - ReadWriteMany → rook-cephfs (concurrent pods — use for shared feature caches)\n * - Auth: sk_* secret key (server-side only)\n * - Quota: 20 concurrent workers per org\n *\n * @module\n */\n\nimport { callApi, type SylphxConfig } from './config'\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport type RunStatus = 'pending' | 'running' | 'succeeded' | 'failed' | 'cancelled' | 'timeout'\n\nexport interface RunVolumeMount {\n\t/** UUID of the volumeResource to mount (must belong to this org) */\n\tvolumeId: string\n\t/** Absolute mount path inside the container (e.g. '/cache') */\n\tmountPath: string\n\t/** Optional sub-path within the volume (e.g. 'fold-3') */\n\tsubPath?: string\n\t/** Mount as read-only (default: false) */\n\treadOnly?: boolean\n}\n\nexport interface RunResourceSpec {\n\trequests?: {\n\t\t/** CPU request (e.g. '500m', '2', '4') */\n\t\tcpu?: string\n\t\t/** Memory request (e.g. '512Mi', '4Gi', '16Gi') */\n\t\tmemory?: string\n\t}\n\tlimits?: {\n\t\t/** CPU limit */\n\t\tcpu?: string\n\t\t/** Memory limit */\n\t\tmemory?: string\n\t}\n}\n\nexport interface CreateRunOptions {\n\t/**\n\t * Docker image to run (must be from registry.sylphx.com).\n\t *\n\t * @example 'registry.sylphx.com/sylphx/my-trainer:abc123def456'\n\t */\n\timage: string\n\n\t/**\n\t * Command + args to execute.\n\t *\n\t * @example ['python', 'train.py', '--fold', '3']\n\t * @example ['node', 'dist/process.js']\n\t */\n\tcommand: string[]\n\n\t/**\n\t * Environment variables to inject.\n\t * Use for fold IDs, feature flags, DB URLs, etc.\n\t */\n\tenv?: Record<string, string>\n\n\t/**\n\t * CPU/memory resource spec.\n\t * Defaults: { requests: { cpu: '500m', memory: '512Mi' }, limits: { cpu: '2', memory: '2Gi' } }\n\t */\n\tresources?: RunResourceSpec\n\n\t/**\n\t * Hard timeout in seconds (default: 3600 = 1 hour, max: 86400 = 24 hours).\n\t * K8s terminates the Job when the deadline is reached (status: 'timeout').\n\t */\n\ttimeoutSeconds?: number\n\n\t/**\n\t * Volume mounts from org-level volumeResources.\n\t * ReadWriteMany volumes (rook-cephfs) allow concurrent access by multiple parallel workers.\n\t */\n\tvolumeMounts?: RunVolumeMount[]\n}\n\nexport interface Run {\n\t/** Worker run ID (e.g. 'worker_Vh3kJ9mNpQ2wXsL1') */\n\tid: string\n\t/** Current lifecycle status */\n\tstatus: RunStatus\n\t/** Docker image */\n\timage: string\n\t/** Command being executed */\n\tcommand: string[]\n\t/** Environment variables */\n\tenv: Record<string, string> | null\n\t/** Resource spec */\n\tresources: RunResourceSpec | null\n\t/** Hard timeout in seconds */\n\ttimeoutSeconds: number\n\t/** Volume mounts */\n\tvolumeMounts: RunVolumeMount[] | null\n\t/** Exit code (only when succeeded or failed) */\n\texitCode: number | null\n\t/** Captured stdout (up to 1 MiB) */\n\tstdout: string | null\n\t/** Captured stderr (up to 1 MiB) */\n\tstderr: string | null\n\t/** Error message (e.g. OOMKilled, image pull failure) */\n\terrorMessage: string | null\n\t/** Duration in milliseconds (only when completed) */\n\tdurationMs: number | null\n\t/** When the worker pod started running */\n\tstartedAt: string | null\n\t/** When the worker completed */\n\tcompletedAt: string | null\n\t/** When this run was created */\n\tcreatedAt: string\n\t/** Last update timestamp */\n\tupdatedAt: string\n}\n\nexport interface RunResult {\n\t/** Exit code (0 = success) */\n\texitCode: number | null\n\t/** Status at completion */\n\tstatus: RunStatus\n\t/** Captured stdout */\n\tstdout: string | null\n\t/** Captured stderr */\n\tstderr: string | null\n\t/** Error message (OOMKilled, DeadlineExceeded, etc.) */\n\terrorMessage: string | null\n\t/** Wall-clock duration in milliseconds */\n\tdurationMs: number | null\n}\n\nexport interface RunLogsResult {\n\t/** Captured stdout (up to 1 MiB) */\n\tstdout: string\n\t/** Captured stderr (up to 1 MiB) */\n\tstderr: string\n\t/** Whether logs are still being captured (worker is running) */\n\tlive: boolean\n}\n\nexport interface ListRunsOptions {\n\t/** Filter by status */\n\tstatus?: RunStatus\n}\n\n/** OpenAI/Stripe-style list response */\nexport interface ListRunsResult {\n\tobject: 'list'\n\tdata: Run[]\n\t/** True if there are more results (limit was hit) */\n\thas_more: boolean\n}\n\n// ============================================================================\n// RunHandle — returned by RunsClient.run()\n// ============================================================================\n\nconst TERMINAL_STATUSES: ReadonlySet<RunStatus> = new Set([\n\t'succeeded',\n\t'failed',\n\t'cancelled',\n\t'timeout',\n])\nconst DEFAULT_POLL_INTERVAL_MS = 3_000\nconst DEFAULT_WAIT_TIMEOUT_MS = 7_200_000 // 2 hours\n\n/**\n * Handle to a running (or completed) worker.\n * Use `.wait()` to poll until completion, `.logs()` to stream logs, `.cancel()` to abort.\n */\nexport class RunHandle {\n\treadonly id: string\n\tprivate readonly config: SylphxConfig\n\n\tconstructor(id: string, config: SylphxConfig) {\n\t\tthis.id = id\n\t\tthis.config = config\n\t}\n\n\t// --------------------------------------------------------------------------\n\t// Status\n\t// --------------------------------------------------------------------------\n\n\t/**\n\t * Get the current status of this worker.\n\t */\n\tasync status(): Promise<Run> {\n\t\treturn callApi<Run>(this.config, `/workers/${this.id}`, { method: 'GET' })\n\t}\n\n\t// --------------------------------------------------------------------------\n\t// Wait (poll to completion)\n\t// --------------------------------------------------------------------------\n\n\t/**\n\t * Poll the worker until it reaches a terminal state (succeeded, failed, cancelled, timeout).\n\t *\n\t * @param options.pollIntervalMs - How often to poll in ms (default: 3000)\n\t * @param options.timeoutMs - Max time to wait before throwing (default: 7_200_000 = 2h)\n\t * @returns RunResult with exit code, status, stdout/stderr\n\t * @throws Error if waitTimeout is exceeded\n\t *\n\t * @example\n\t * ```typescript\n\t * const result = await worker.wait()\n\t * if (result.exitCode !== 0) {\n\t * throw new Error(`Worker failed: ${result.errorMessage ?? result.stderr}`)\n\t * }\n\t * ```\n\t */\n\tasync wait(options?: { pollIntervalMs?: number; timeoutMs?: number }): Promise<RunResult> {\n\t\tconst pollMs = options?.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS\n\t\tconst maxWaitMs = options?.timeoutMs ?? DEFAULT_WAIT_TIMEOUT_MS\n\t\tconst deadline = Date.now() + maxWaitMs\n\n\t\twhile (true) {\n\t\t\tconst run = await this.status()\n\n\t\t\tif (TERMINAL_STATUSES.has(run.status)) {\n\t\t\t\treturn {\n\t\t\t\t\texitCode: run.exitCode,\n\t\t\t\t\tstatus: run.status,\n\t\t\t\t\tstdout: run.stdout,\n\t\t\t\t\tstderr: run.stderr,\n\t\t\t\t\terrorMessage: run.errorMessage,\n\t\t\t\t\tdurationMs: run.durationMs,\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (Date.now() >= deadline) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Worker ${this.id} did not complete within ${maxWaitMs}ms (current status: ${run.status})`,\n\t\t\t\t)\n\t\t\t}\n\n\t\t\tawait sleep(pollMs)\n\t\t}\n\t}\n\n\t// --------------------------------------------------------------------------\n\t// Logs\n\t// --------------------------------------------------------------------------\n\n\t/**\n\t * Fetch captured logs for this worker.\n\t *\n\t * - For a running worker: returns live logs streamed from K8s (may be incomplete)\n\t * - For a completed worker: returns the full captured output stored in DB\n\t *\n\t * @example\n\t * ```typescript\n\t * const { stdout, stderr, live } = await worker.logs()\n\t * console.log(stdout)\n\t * if (live) console.log('(worker still running, logs may be incomplete)')\n\t * ```\n\t */\n\tasync logs(): Promise<RunLogsResult> {\n\t\treturn callApi<RunLogsResult>(this.config, `/workers/${this.id}/logs`, { method: 'GET' })\n\t}\n\n\t// --------------------------------------------------------------------------\n\t// Cancel\n\t// --------------------------------------------------------------------------\n\n\t/**\n\t * Cancel this worker.\n\t *\n\t * - If still pending: immediately cancelled (no K8s Job created)\n\t * - If running: K8s Job deleted (pod terminated)\n\t * - If already completed: no-op\n\t */\n\tasync cancel(): Promise<void> {\n\t\tawait callApi<{ success: boolean }>(this.config, `/workers/${this.id}`, { method: 'DELETE' })\n\t}\n}\n\n// ============================================================================\n// RunsClient\n// ============================================================================\n\n/**\n * Static client for the Workers BaaS service.\n *\n * @example\n * ```typescript\n * const config = createConfig({ secretKey: process.env.SYLPHX_SECRET_KEY!, ref: 'my-project' })\n *\n * // Run a worker and wait for completion\n * const result = await RunsClient.create(config, { ... }).then(w => w.wait())\n *\n * // Run N workers in parallel, wait for all\n * const handles = await Promise.all(folds.map(fold => RunsClient.create(config, { ... })))\n * const results = await Promise.all(handles.map(h => h.wait()))\n * ```\n */\nexport const RunsClient = {\n\t// --------------------------------------------------------------------------\n\t// Run\n\t// --------------------------------------------------------------------------\n\n\t/**\n\t * Spawn a new worker (K8s Job) and return a handle.\n\t *\n\t * The Job is created immediately and starts pulling the image.\n\t * Use the returned handle to `.wait()` for completion or `.cancel()`.\n\t *\n\t * @example\n\t * ```typescript\n\t * const run = await RunsClient.create(config, {\n\t * image: 'registry.sylphx.com/sylphx/trainer:abc123',\n\t * command: ['python', 'train.py', '--fold', '3'],\n\t * resources: { requests: { cpu: '4', memory: '16Gi' } },\n\t * volumeMounts: [{ volumeId: cacheVolumeId, mountPath: '/cache' }],\n\t * })\n\t * const result = await worker.wait()\n\t * ```\n\t */\n\tasync run(config: SylphxConfig, options: CreateRunOptions): Promise<RunHandle> {\n\t\tconst run = await callApi<{ id: string }>(config, '/runs', {\n\t\t\tmethod: 'POST',\n\t\t\tbody: {\n\t\t\t\timage: options.image,\n\t\t\t\tcommand: options.command,\n\t\t\t\tenv: options.env,\n\t\t\t\tresources: options.resources,\n\t\t\t\ttimeoutSeconds: options.timeoutSeconds ?? 3600,\n\t\t\t\tvolumeMounts: options.volumeMounts,\n\t\t\t},\n\t\t})\n\t\treturn new RunHandle(run.id, config)\n\t},\n\n\t// --------------------------------------------------------------------------\n\t// Get\n\t// --------------------------------------------------------------------------\n\n\t/**\n\t * Get a RunHandle for an existing run by ID.\n\t *\n\t * Useful for resuming monitoring across requests.\n\t *\n\t * @example\n\t * ```typescript\n\t * // Store the worker ID, retrieve later\n\t * const handle = RunsClient.fromId(config, storedWorkerId)\n\t * const result = await handle.wait()\n\t * ```\n\t */\n\tfromId(config: SylphxConfig, workerId: string): RunHandle {\n\t\treturn new RunHandle(workerId, config)\n\t},\n\n\t// --------------------------------------------------------------------------\n\t// List\n\t// --------------------------------------------------------------------------\n\n\t/**\n\t * List worker runs for this environment.\n\t *\n\t * @example\n\t * ```typescript\n\t * const { workers } = await RunsClient.list(config, { status: 'running' })\n\t * console.log(`${workers.length} workers currently running`)\n\t * ```\n\t */\n\tasync list(config: SylphxConfig, options?: ListRunsOptions): Promise<ListRunsResult> {\n\t\treturn callApi<ListRunsResult>(config, '/runs', {\n\t\t\tmethod: 'GET',\n\t\t\tquery: options?.status ? { status: options.status } : undefined,\n\t\t})\n\t},\n\n\t// --------------------------------------------------------------------------\n\t// Run-and-wait convenience\n\t// --------------------------------------------------------------------------\n\n\t/**\n\t * Spawn a worker and wait for it to complete in one call.\n\t *\n\t * Equivalent to `(await RunsClient.create(config, options)).wait(waitOptions)`.\n\t *\n\t * @example\n\t * ```typescript\n\t * const result = await RunsClient.runAndWait(config, {\n\t * image: 'registry.sylphx.com/sylphx/process:abc',\n\t * command: ['node', 'dist/process.js'],\n\t * })\n\t * if (result.exitCode !== 0) throw new Error(result.errorMessage ?? 'worker failed')\n\t * ```\n\t */\n\tasync runAndWait(\n\t\tconfig: SylphxConfig,\n\t\toptions: CreateRunOptions,\n\t\twaitOptions?: { pollIntervalMs?: number; timeoutMs?: number },\n\t): Promise<RunResult> {\n\t\tconst handle = await RunsClient.run(config, options)\n\t\treturn handle.wait(waitOptions)\n\t},\n}\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\nfunction sleep(ms: number): Promise<void> {\n\treturn new Promise((resolve) => setTimeout(resolve, ms))\n}\n\n// ── Backward-compat aliases (ADR-040) ────────────────────────────────────────\n/** @deprecated Use RunsClient */\nexport const WorkersClient = RunsClient\n/** @deprecated Use RunHandle */\nexport { RunHandle as WorkerHandle }\n/** @deprecated Use CreateRunOptions */\nexport type { CreateRunOptions as RunWorkerOptions }\n/** @deprecated Use Run */\nexport type { Run as WorkerRun }\n/** @deprecated Use RunLogsResult */\nexport type { RunLogsResult as WorkerLogsResult }\n/** @deprecated Use RunResult */\nexport type { RunResult as WorkerResult }\n/** @deprecated Use RunStatus */\nexport type { RunStatus as WorkerStatus }\n/** @deprecated Use RunResourceSpec */\nexport type { RunResourceSpec as WorkerResourceSpec }\n/** @deprecated Use RunVolumeMount */\nexport type { RunVolumeMount as WorkerVolumeMount }\n","/**\n * Application Logs SDK (ADR-089 Phase 4a)\n *\n * Pure functions for runtime application log ingestion and querying,\n * backed by `apps/runtime/src/server/runtime/routes/logs.ts`:\n *\n * POST /logs — ingest log entries (requires secret key / serverAuth)\n * GET /logs — query logs (requires any key / configAuth)\n *\n * Logs are persisted in the project's `appLogs` table. Ingestion is\n * batched via `{ logs: [...] }` — do not call once per line in a loop.\n */\n\nimport { callApi, type SylphxConfig } from './config'\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'fatal'\n\nexport interface LogEntry {\n\treadonly level: LogLevel\n\treadonly message: string\n\treadonly timestamp?: string\n\treadonly metadata?: Record<string, unknown>\n\treadonly source?: string\n\treadonly traceId?: string\n}\n\nexport interface StoredLogEntry {\n\treadonly id: string\n\treadonly level: LogLevel\n\treadonly message: string\n\treadonly timestamp: string\n\treadonly metadata: Record<string, unknown> | null\n\treadonly traceId: string | null\n\treadonly source: string | null\n\treadonly userId: string | null\n}\n\nexport interface IngestLogsResult {\n\treadonly ingested: number\n}\n\nexport interface QueryLogsOptions {\n\t/** Minimum level to return (levels at or above this are included). */\n\treadonly level?: LogLevel\n\t/** ISO 8601 lower bound (inclusive). */\n\treadonly since?: string\n\t/** ISO 8601 upper bound (inclusive). */\n\treadonly until?: string\n\t/** Max entries (default 100, server-enforced cap 1000). */\n\treadonly limit?: number\n\t/** Full-text search against `message` (case-insensitive). */\n\treadonly search?: string\n\t/** Filter by a specific trace correlation ID. */\n\treadonly traceId?: string\n}\n\nexport interface QueryLogsResult {\n\treadonly logs: readonly StoredLogEntry[]\n\treadonly total: number\n}\n\n// ============================================================================\n// Functions\n// ============================================================================\n\n/**\n * Ingest one or more log entries for the current project.\n *\n * @example\n * ```typescript\n * await ingestLogs(config, [\n * { level: 'info', message: 'user signed in', metadata: { userId } },\n * { level: 'warn', message: 'stripe webhook retry' },\n * ])\n * ```\n */\nexport async function ingestLogs(\n\tconfig: SylphxConfig,\n\tentries: readonly LogEntry[],\n): Promise<IngestLogsResult> {\n\treturn callApi<IngestLogsResult>(config, '/logs', {\n\t\tmethod: 'POST',\n\t\tbody: { logs: entries },\n\t})\n}\n\n/**\n * Query stored application logs with optional filtering.\n * Returns newest-first, capped at the server's limit (1000).\n *\n * @example\n * ```typescript\n * const { logs } = await queryLogs(config, { level: 'error', limit: 50 })\n * ```\n */\nexport async function queryLogs(\n\tconfig: SylphxConfig,\n\toptions: QueryLogsOptions = {},\n): Promise<QueryLogsResult> {\n\treturn callApi<QueryLogsResult>(config, '/logs', {\n\t\tmethod: 'GET',\n\t\tquery: {\n\t\t\tlevel: options.level,\n\t\t\tsince: options.since,\n\t\t\tuntil: options.until,\n\t\t\tlimit: options.limit,\n\t\t\tsearch: options.search,\n\t\t\ttraceId: options.traceId,\n\t\t},\n\t})\n}\n","/**\n * Miscellaneous SDK endpoints (ADR-089 Phase 4a)\n *\n * Backed by `apps/runtime/src/server/runtime/routes/misc.ts`:\n *\n * GET /app — project metadata (configAuth)\n * POST /challenge/verify — step-up identity verification (userAuth)\n */\n\nimport { callApi, type SylphxConfig } from './config'\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface ProjectMetadata {\n\treadonly id: string\n\treadonly name: string\n\treadonly slug: string\n\treadonly [key: string]: unknown\n}\n\nexport type ChallengeMethod = 'password' | 'email' | 'totp' | 'backup_code'\nexport type ChallengeType = 'identity' | 'mfa'\n\nexport interface ChallengeVerifyInput {\n\t/** Verification method to use. */\n\treadonly method: ChallengeMethod\n\t/** Credential matching `method` (password, OTP, TOTP code, backup code). */\n\treadonly credential: string\n\t/** Whether this challenge is for identity step-up or MFA gate (default: identity). */\n\treadonly type?: ChallengeType\n}\n\nexport interface ChallengeVerifyResult {\n\treadonly verified: boolean\n\treadonly method: ChallengeMethod\n\treadonly type: ChallengeType\n}\n\n// ============================================================================\n// Functions\n// ============================================================================\n\n/**\n * Get app metadata for the current project (id, name, slug).\n * Cacheable — the BaaS emits `Cache-Control` headers for CDN reuse.\n */\nexport async function getProjectMetadata(config: SylphxConfig): Promise<ProjectMetadata> {\n\treturn callApi<ProjectMetadata>(config, '/app')\n}\n\n/**\n * Verify the authenticated user's identity for step-up authentication.\n *\n * Lockout is enforced server-side after repeated failures — respect the\n * `429` response. Methods accepted: password, email OTP, TOTP, backup code.\n *\n * @example\n * ```typescript\n * await verifyChallenge(config, { method: 'password', credential: pw })\n * ```\n */\nexport async function verifyChallenge(\n\tconfig: SylphxConfig,\n\tinput: ChallengeVerifyInput,\n): Promise<ChallengeVerifyResult> {\n\treturn callApi<ChallengeVerifyResult>(config, '/challenge/verify', {\n\t\tmethod: 'POST',\n\t\tbody: input,\n\t})\n}\n","/**\n * User SDK — customer-app-facing user management (ADR-089 Phase 4a)\n *\n * Backed by `apps/runtime/src/server/runtime/routes/user.ts`:\n *\n * GET /user/profile — full profile\n * PUT /user/profile — update profile\n * GET /user/security — 2FA / password status\n * GET /user/sessions — list active sessions\n * PUT /user/sessions/{id} — rename session device\n * DELETE /user/sessions/{id} — revoke session\n * GET /user/export — GDPR export\n * DELETE /user/account — GDPR erasure\n *\n * These routes are authenticated with a **user access token** (bearer) —\n * distinct from the platform-user namespace in `auth.ts` which targets\n * `/auth/platform-user/*` for Console / CLI operators. Customer apps\n * should use these; platform tooling should use `auth.user.*`.\n */\n\nimport { callApi, type SylphxConfig } from './config'\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface UserFullProfile {\n\treadonly id: string\n\treadonly email: string\n\treadonly name: string | null\n\treadonly image: string | null\n\treadonly emailVerified: boolean\n\treadonly createdAt: string\n\treadonly updatedAt: string\n\treadonly [key: string]: unknown\n}\n\nexport interface UserUpdateProfileInput {\n\treadonly name?: string\n\treadonly image?: string\n\treadonly metadata?: Record<string, unknown>\n}\n\nexport interface UserSecuritySettings {\n\treadonly hasPassword: boolean\n\treadonly twoFactorEnabled: boolean\n\treadonly passkeyCount: number\n\treadonly oauthProviders: readonly string[]\n\treadonly [key: string]: unknown\n}\n\nexport interface UserSession {\n\treadonly id: string\n\treadonly deviceName: string | null\n\treadonly ipAddress: string | null\n\treadonly userAgent: string | null\n\treadonly createdAt: string\n\treadonly lastActiveAt: string | null\n\treadonly expiresAt: string\n\treadonly current: boolean\n}\n\nexport interface UserSessionsList {\n\treadonly sessions: readonly UserSession[]\n}\n\nexport interface UserDataExport {\n\treadonly exportedAt: string\n\treadonly user: Record<string, unknown>\n\treadonly [key: string]: unknown\n}\n\nexport interface DeleteAccountResult {\n\treadonly success: boolean\n\treadonly deletedData: readonly string[]\n}\n\n// ============================================================================\n// Functions\n// ============================================================================\n\nexport async function getUserProfile(config: SylphxConfig): Promise<UserFullProfile> {\n\treturn callApi<UserFullProfile>(config, '/user/profile')\n}\n\nexport async function updateUserProfile(\n\tconfig: SylphxConfig,\n\tinput: UserUpdateProfileInput,\n): Promise<UserFullProfile> {\n\treturn callApi<UserFullProfile>(config, '/user/profile', {\n\t\tmethod: 'PUT',\n\t\tbody: input,\n\t})\n}\n\nexport async function getUserSecurity(config: SylphxConfig): Promise<UserSecuritySettings> {\n\treturn callApi<UserSecuritySettings>(config, '/user/security')\n}\n\nexport async function listUserSessions(config: SylphxConfig): Promise<UserSessionsList> {\n\treturn callApi<UserSessionsList>(config, '/user/sessions')\n}\n\nexport async function revokeUserSession(\n\tconfig: SylphxConfig,\n\tsessionId: string,\n): Promise<{ success: boolean }> {\n\treturn callApi<{ success: boolean }>(config, `/user/sessions/${encodeURIComponent(sessionId)}`, {\n\t\tmethod: 'DELETE',\n\t})\n}\n\nexport async function renameUserSession(\n\tconfig: SylphxConfig,\n\tsessionId: string,\n\tdeviceName: string,\n): Promise<{ success: boolean }> {\n\treturn callApi<{ success: boolean }>(config, `/user/sessions/${encodeURIComponent(sessionId)}`, {\n\t\tmethod: 'PUT',\n\t\tbody: { deviceName },\n\t})\n}\n\n/**\n * Export every piece of personal data the platform holds about the\n * authenticated user (GDPR Article 20 — data portability).\n */\nexport async function exportUserData(config: SylphxConfig): Promise<UserDataExport> {\n\treturn callApi<UserDataExport>(config, '/user/export')\n}\n\n/**\n * Permanently delete the authenticated user's account and all\n * associated data (GDPR Article 17 — right to erasure). Callers\n * SHOULD gate this behind a `verifyChallenge()` step-up.\n */\nexport async function deleteUserAccount(config: SylphxConfig): Promise<DeleteAccountResult> {\n\treturn callApi<DeleteAccountResult>(config, '/user/account', {\n\t\tmethod: 'DELETE',\n\t})\n}\n","/**\n * Security SDK — customer-app-facing account security management (ADR-089 Phase 4a)\n *\n * Backed by `apps/runtime/src/server/runtime/routes/security/*`:\n *\n * /security/password/set — set or replace password\n * /security/oauth/disconnect — remove linked OAuth provider\n * /security/score — security posture score\n * /security/email/change + confirm — verified email change flow\n * /security/passkeys (+ register) — WebAuthn passkey CRUD\n * /security/2fa/setup|verify|disable — TOTP 2FA lifecycle\n * /security/backup-codes — view / regenerate recovery codes\n * /security/alerts — security alert inbox\n *\n * All routes require a user access token (bearer). Destructive verbs\n * (disable 2FA, delete passkey, disconnect OAuth) SHOULD be gated\n * behind a `verifyChallenge()` step-up from `@sylphx/sdk/misc`.\n */\n\nimport { callApi, type SylphxConfig } from './config'\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface SecurityScoreResult {\n\treadonly score: number\n\treadonly maxScore: number\n\treadonly factors: readonly {\n\t\treadonly key: string\n\t\treadonly label: string\n\t\treadonly satisfied: boolean\n\t\treadonly weight: number\n\t}[]\n}\n\nexport interface PasswordSetInput {\n\treadonly password: string\n\t/** Current password — required if one is already set. */\n\treadonly currentPassword?: string\n}\n\nexport interface EmailChangeInput {\n\treadonly newEmail: string\n}\n\nexport interface EmailConfirmInput {\n\treadonly code: string\n}\n\nexport interface PasskeySummary {\n\treadonly id: string\n\treadonly name: string | null\n\treadonly createdAt: string\n\treadonly lastUsedAt: string | null\n}\n\nexport interface PasskeysList {\n\treadonly passkeys: readonly PasskeySummary[]\n}\n\nexport interface PasskeyRegistrationOptions {\n\t/** WebAuthn `PublicKeyCredentialCreationOptions` — pass to `navigator.credentials.create()`. */\n\treadonly [key: string]: unknown\n}\n\nexport interface PasskeyRegistrationInput {\n\t/** WebAuthn credential response from `navigator.credentials.create()`. */\n\treadonly credential: Record<string, unknown>\n\treadonly deviceName?: string\n}\n\nexport interface TwoFactorSetupResult {\n\treadonly secret: string\n\treadonly qrCodeUri: string\n\treadonly recoveryHint?: string\n}\n\nexport interface TwoFactorEnableResult {\n\treadonly success: boolean\n\treadonly backupCodes: readonly string[]\n}\n\nexport interface BackupCodesResult {\n\treadonly codes: readonly string[]\n\treadonly remaining: number\n}\n\nexport interface SecurityAlert {\n\treadonly id: string\n\treadonly type: string\n\treadonly severity: 'info' | 'warning' | 'critical'\n\treadonly message: string\n\treadonly createdAt: string\n\treadonly readAt: string | null\n\treadonly metadata: Record<string, unknown> | null\n}\n\nexport interface SecurityAlertsList {\n\treadonly alerts: readonly SecurityAlert[]\n\treadonly unread: number\n}\n\n// ============================================================================\n// Password & OAuth linkage\n// ============================================================================\n\nexport async function setPassword(\n\tconfig: SylphxConfig,\n\tinput: PasswordSetInput,\n): Promise<{ success: boolean }> {\n\treturn callApi<{ success: boolean }>(config, '/security/password/set', {\n\t\tmethod: 'POST',\n\t\tbody: input,\n\t})\n}\n\nexport async function disconnectOAuthProvider(\n\tconfig: SylphxConfig,\n\tprovider: string,\n): Promise<{ success: boolean }> {\n\treturn callApi<{ success: boolean }>(config, '/security/oauth/disconnect', {\n\t\tmethod: 'POST',\n\t\tbody: { provider },\n\t})\n}\n\nexport async function getSecurityScore(config: SylphxConfig): Promise<SecurityScoreResult> {\n\treturn callApi<SecurityScoreResult>(config, '/security/score')\n}\n\n// ============================================================================\n// Email change\n// ============================================================================\n\nexport async function requestEmailChange(\n\tconfig: SylphxConfig,\n\tinput: EmailChangeInput,\n): Promise<{ success: boolean }> {\n\treturn callApi<{ success: boolean }>(config, '/security/email/change', {\n\t\tmethod: 'POST',\n\t\tbody: input,\n\t})\n}\n\nexport async function confirmEmailChange(\n\tconfig: SylphxConfig,\n\tinput: EmailConfirmInput,\n): Promise<{ success: boolean }> {\n\treturn callApi<{ success: boolean }>(config, '/security/email/confirm', {\n\t\tmethod: 'POST',\n\t\tbody: input,\n\t})\n}\n\n// ============================================================================\n// Passkeys (WebAuthn)\n// ============================================================================\n\nexport async function listPasskeys(config: SylphxConfig): Promise<PasskeysList> {\n\treturn callApi<PasskeysList>(config, '/security/passkeys')\n}\n\nexport async function startPasskeyRegistration(\n\tconfig: SylphxConfig,\n): Promise<PasskeyRegistrationOptions> {\n\treturn callApi<PasskeyRegistrationOptions>(config, '/security/passkeys/register/start', {\n\t\tmethod: 'POST',\n\t})\n}\n\nexport async function verifyPasskeyRegistration(\n\tconfig: SylphxConfig,\n\tinput: PasskeyRegistrationInput,\n): Promise<{ success: boolean; passkey: PasskeySummary }> {\n\treturn callApi(config, '/security/passkeys/register/verify', {\n\t\tmethod: 'POST',\n\t\tbody: input,\n\t})\n}\n\nexport async function renamePasskey(\n\tconfig: SylphxConfig,\n\tpasskeyId: string,\n\tname: string,\n): Promise<{ success: boolean }> {\n\treturn callApi<{ success: boolean }>(\n\t\tconfig,\n\t\t`/security/passkeys/${encodeURIComponent(passkeyId)}`,\n\t\t{\n\t\t\tmethod: 'PUT',\n\t\t\tbody: { name },\n\t\t},\n\t)\n}\n\nexport async function deletePasskey(\n\tconfig: SylphxConfig,\n\tpasskeyId: string,\n): Promise<{ success: boolean }> {\n\treturn callApi<{ success: boolean }>(\n\t\tconfig,\n\t\t`/security/passkeys/${encodeURIComponent(passkeyId)}`,\n\t\t{ method: 'DELETE' },\n\t)\n}\n\n// ============================================================================\n// Two-factor authentication\n// ============================================================================\n\nexport async function setupTwoFactor(config: SylphxConfig): Promise<TwoFactorSetupResult> {\n\treturn callApi<TwoFactorSetupResult>(config, '/security/2fa/setup', { method: 'POST' })\n}\n\nexport async function verifyTwoFactorEnable(\n\tconfig: SylphxConfig,\n\tcode: string,\n): Promise<TwoFactorEnableResult> {\n\treturn callApi<TwoFactorEnableResult>(config, '/security/2fa/verify', {\n\t\tmethod: 'POST',\n\t\tbody: { code },\n\t})\n}\n\nexport async function disableTwoFactor(config: SylphxConfig): Promise<{ success: boolean }> {\n\treturn callApi<{ success: boolean }>(config, '/security/2fa/disable', { method: 'POST' })\n}\n\nexport async function getBackupCodes(config: SylphxConfig): Promise<BackupCodesResult> {\n\treturn callApi<BackupCodesResult>(config, '/security/backup-codes')\n}\n\nexport async function regenerateBackupCodes(config: SylphxConfig): Promise<BackupCodesResult> {\n\treturn callApi<BackupCodesResult>(config, '/security/backup-codes/regenerate', {\n\t\tmethod: 'POST',\n\t})\n}\n\n// ============================================================================\n// Security alerts\n// ============================================================================\n\nexport async function listSecurityAlerts(config: SylphxConfig): Promise<SecurityAlertsList> {\n\treturn callApi<SecurityAlertsList>(config, '/security/alerts')\n}\n\nexport async function markSecurityAlertRead(\n\tconfig: SylphxConfig,\n\talertId: string,\n): Promise<{ success: boolean }> {\n\treturn callApi<{ success: boolean }>(\n\t\tconfig,\n\t\t`/security/alerts/${encodeURIComponent(alertId)}/read`,\n\t\t{ method: 'POST' },\n\t)\n}\n\nexport async function markAllSecurityAlertsRead(\n\tconfig: SylphxConfig,\n): Promise<{ success: boolean; updated: number }> {\n\treturn callApi(config, '/security/alerts/read-all', { method: 'POST' })\n}\n","/**\n * OAuth SDK — customer-app-facing social login (ADR-089 Phase 4a)\n *\n * Backed by `apps/runtime/src/server/runtime/routes/oauth.ts`:\n *\n * POST /oauth/authorize — initiate OAuth flow, returns provider URL\n *\n * The per-provider callback handler is a browser-side redirect endpoint\n * on the runtime (`GET /oauth/callback/{provider}`); SDK consumers\n * redirect the user to `authorizationUrl`, then receive a `code` on\n * their own `redirect_uri` which they exchange via `signIn()` or\n * `auth/login` with grant_type=authorization_code.\n *\n * PKCE is required per OAuth 2.1. Callers MUST generate `code_verifier`\n * + `code_challenge` and persist the verifier in session / cookie for\n * the subsequent token exchange — this SDK does not retain state.\n *\n * ## Distinction from `auth.oauth`\n *\n * `auth.oauth.*` (from `./auth`) targets platform-plane admin mint\n * (`/auth/platform-jwt/mint`) used by Console / CLI. The functions\n * here target the customer-app social-login flow.\n */\n\nimport { callApi, type SylphxConfig } from './config'\n\n// ============================================================================\n// OIDC Discovery + UserInfo — ADR-089 Phase 5.6\n// ============================================================================\n\n/**\n * OIDC Discovery document shape (OIDC-Core §4). Every published field is\n * optional from the SDK's perspective because different providers\n * advertise different subsets; Sylphx's own doc is shipped fully\n * populated by {@link buildOidcDiscoveryDocument}.\n */\nexport interface OidcDiscoveryDocument {\n\treadonly issuer: string\n\treadonly authorization_endpoint?: string\n\treadonly token_endpoint?: string\n\treadonly userinfo_endpoint?: string\n\treadonly jwks_uri?: string\n\treadonly introspection_endpoint?: string\n\treadonly revocation_endpoint?: string\n\treadonly device_authorization_endpoint?: string\n\treadonly response_types_supported?: readonly string[]\n\treadonly subject_types_supported?: readonly string[]\n\treadonly id_token_signing_alg_values_supported?: readonly string[]\n\treadonly grant_types_supported?: readonly string[]\n\treadonly scopes_supported?: readonly string[]\n\treadonly claims_supported?: readonly string[]\n\treadonly token_endpoint_auth_methods_supported?: readonly string[]\n\treadonly code_challenge_methods_supported?: readonly string[]\n\treadonly dpop_signing_alg_values_supported?: readonly string[]\n\treadonly frontchannel_logout_supported?: boolean\n\treadonly backchannel_logout_supported?: boolean\n\treadonly [k: string]: unknown\n}\n\nexport interface OidcUserInfoResponse {\n\treadonly sub: string\n\treadonly email?: string\n\treadonly email_verified?: boolean\n\treadonly name?: string\n\treadonly picture?: string\n\treadonly updated_at?: number\n\treadonly [k: string]: unknown\n}\n\n/**\n * Fetch the provider's OIDC discovery document. Works against any\n * spec-compliant provider (Sylphx, Okta, Azure AD, etc.) — pass the\n * issuer URL (scheme + host, no path) as `baseUrl`.\n *\n * @example\n * ```ts\n * const doc = await getOidcDiscoveryDocument({ baseUrl: 'https://api.sylphx.com' })\n * console.log(doc.token_endpoint)\n * ```\n */\nexport async function getOidcDiscoveryDocument(opts: {\n\tbaseUrl: string\n}): Promise<OidcDiscoveryDocument> {\n\tconst url = `${opts.baseUrl.replace(/\\/$/, '')}/.well-known/openid-configuration`\n\tconst res = await fetch(url, { headers: { accept: 'application/json' } })\n\tif (!res.ok) {\n\t\tthrow new Error(`OIDC discovery failed: ${res.status} ${res.statusText}`)\n\t}\n\treturn (await res.json()) as OidcDiscoveryDocument\n}\n\n/**\n * Call the OIDC UserInfo endpoint (OIDC-Core §5.3). Returns identity\n * claims for the subject identified by `accessToken`. The token MUST\n * have been granted `openid` scope; otherwise the endpoint returns 403\n * `insufficient_scope`.\n *\n * @example\n * ```ts\n * const info = await userInfo({\n * baseUrl: 'https://api.sylphx.com',\n * accessToken: token.access_token,\n * })\n * console.log(info.sub, info.email)\n * ```\n */\nexport async function userInfo(opts: {\n\tbaseUrl: string\n\taccessToken: string\n\t/** Override the discovered endpoint (e.g. when testing against a staging AS). */\n\tendpoint?: string\n}): Promise<OidcUserInfoResponse> {\n\tconst url = opts.endpoint ?? `${opts.baseUrl.replace(/\\/$/, '')}/v1/auth/oauth/userinfo`\n\tconst res = await fetch(url, {\n\t\tmethod: 'GET',\n\t\theaders: {\n\t\t\tauthorization: `Bearer ${opts.accessToken}`,\n\t\t\taccept: 'application/json',\n\t\t},\n\t})\n\tif (!res.ok) {\n\t\tconst body = await res.text()\n\t\tthrow new Error(`userinfo failed: ${res.status} ${res.statusText} ${body}`)\n\t}\n\treturn (await res.json()) as OidcUserInfoResponse\n}\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport type OAuthProvider = 'google' | 'github' | 'microsoft' | 'apple' | 'facebook' | (string & {})\n\nexport type PkceMethod = 'S256' | 'plain'\n\nexport interface OAuthAuthorizeInput {\n\treadonly provider: OAuthProvider\n\t/** Where the OAuth provider sends the user after consent. */\n\treadonly redirectUri: string\n\t/** PKCE code challenge derived from `code_verifier` (S256 recommended). */\n\treadonly codeChallenge: string\n\treadonly codeChallengeMethod?: PkceMethod\n\t/** Override the default scopes for the provider. */\n\treadonly scopes?: readonly string[]\n\t/** Opaque state for CSRF protection. */\n\treadonly state?: string\n}\n\nexport interface OAuthAuthorizeResult {\n\t/** Fully-qualified URL to redirect the user to. */\n\treadonly authorizationUrl: string\n\t/** Opaque server-side state — echo on callback handler if present. */\n\treadonly state: string\n}\n\n// ============================================================================\n// Functions\n// ============================================================================\n\n/**\n * Initiate an OAuth flow with the given provider. Returns the provider's\n * authorization URL — redirect the user to it.\n *\n * @example\n * ```typescript\n * import { generatePkce } from '@sylphx/sdk'\n * const { verifier, challenge } = await generatePkce()\n * sessionStorage.setItem('pkce_verifier', verifier)\n * const { authorizationUrl } = await authorizeOAuth(config, {\n * provider: 'google',\n * redirectUri: 'https://app.example.com/auth/callback',\n * codeChallenge: challenge,\n * codeChallengeMethod: 'S256',\n * })\n * window.location.href = authorizationUrl\n * ```\n */\nexport async function authorizeOAuth(\n\tconfig: SylphxConfig,\n\tinput: OAuthAuthorizeInput,\n): Promise<OAuthAuthorizeResult> {\n\treturn callApi<OAuthAuthorizeResult>(config, '/oauth/authorize', {\n\t\tmethod: 'POST',\n\t\tbody: {\n\t\t\tprovider: input.provider,\n\t\t\tredirect_uri: input.redirectUri,\n\t\t\tcode_challenge: input.codeChallenge,\n\t\t\tcode_challenge_method: input.codeChallengeMethod ?? 'S256',\n\t\t\t...(input.scopes && { scopes: input.scopes }),\n\t\t\t...(input.state && { state: input.state }),\n\t\t},\n\t})\n}\n\n/**\n * Parse an OAuth callback URL (e.g. `window.location.href`) into the\n * fields a customer app needs to complete sign-in.\n *\n * Pure function — no network. Does NOT validate `state` against your\n * session store; callers MUST compare `parsed.state` to the opaque\n * value they persisted before redirect (CSRF mitigation).\n */\nexport function parseOAuthCallback(url: string): {\n\treadonly code: string | null\n\treadonly state: string | null\n\treadonly error: string | null\n\treadonly errorDescription: string | null\n} {\n\tconst parsed = new URL(url)\n\treturn {\n\t\tcode: parsed.searchParams.get('code'),\n\t\tstate: parsed.searchParams.get('state'),\n\t\terror: parsed.searchParams.get('error'),\n\t\terrorDescription: parsed.searchParams.get('error_description'),\n\t}\n}\n\n/**\n * Generate a cryptographically random PKCE verifier + S256 challenge\n * pair (RFC 7636 §4.1-4.2). Works in browsers (Web Crypto) and Bun /\n * Node 18+ (`globalThis.crypto`).\n */\nexport async function generatePkce(): Promise<{ verifier: string; challenge: string }> {\n\tconst bytes = new Uint8Array(32)\n\tglobalThis.crypto.getRandomValues(bytes)\n\tconst verifier = base64UrlEncode(bytes)\n\tconst digest = await globalThis.crypto.subtle.digest(\n\t\t'SHA-256',\n\t\tnew TextEncoder().encode(verifier),\n\t)\n\tconst challenge = base64UrlEncode(new Uint8Array(digest))\n\treturn { verifier, challenge }\n}\n\nfunction base64UrlEncode(bytes: Uint8Array): string {\n\tlet binary = ''\n\tfor (let i = 0; i < bytes.length; i++) binary += String.fromCharCode(bytes[i] as number)\n\treturn btoa(binary).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '')\n}\n","/**\n * Promo Code SDK (ADR-089 Phase 4a)\n *\n * Backed by `apps/runtime/src/server/runtime/routes/promo.ts`:\n *\n * POST /promo/validate — check code validity (projectAuth)\n * POST /promo/redeem — redeem for current user (userAuth)\n * GET /admin/promo — list codes (serverAuth)\n * POST /admin/promo — create code (serverAuth)\n * GET /admin/promo/{id} — get single code (serverAuth)\n * PATCH /admin/promo/{id} — update code (serverAuth)\n * DELETE /admin/promo/{id} — archive code (serverAuth)\n * GET /admin/promo/redemptions — redemption history (serverAuth)\n */\n\nimport { callApi, type SylphxConfig } from './config'\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport type PromoType = 'percent_off' | 'fixed_off' | 'free_trial' | 'feature_unlock'\nexport type PromoStatus = 'active' | 'paused' | 'expired' | 'archived'\n\nexport interface PromoCode {\n\treadonly id: string\n\treadonly code: string\n\treadonly name: string\n\treadonly description: string | null\n\treadonly type: PromoType\n\treadonly value: number\n\treadonly maxUses: number | null\n\treadonly maxUsesPerUser: number | null\n\treadonly usedCount: number\n\treadonly status: PromoStatus\n\treadonly expiresAt: string | null\n\treadonly startsAt: string | null\n\treadonly minPurchaseAmount: number | null\n\treadonly applicablePlanIds: readonly string[] | null\n\treadonly metadata: Record<string, unknown> | null\n\treadonly createdAt: string\n\treadonly updatedAt: string\n}\n\nexport interface PromoValidationPreview {\n\treadonly code: string\n\treadonly name: string\n\treadonly description: string | null\n\treadonly type: PromoType\n\treadonly value: number\n\treadonly expiresAt: string | null\n}\n\nexport interface ValidatePromoInput {\n\treadonly code: string\n\treadonly planId?: string\n\treadonly purchaseAmount?: number\n}\n\nexport interface ValidatePromoResult {\n\treadonly valid: boolean\n\treadonly promo: PromoValidationPreview | null\n\treadonly error?: string\n}\n\nexport interface RedeemPromoInput {\n\treadonly code: string\n\treadonly planId?: string\n\treadonly purchaseAmount?: number\n}\n\nexport interface RedeemPromoResult {\n\treadonly success: boolean\n\treadonly redemption: {\n\t\treadonly id: string\n\t\treadonly code: string\n\t\treadonly type: PromoType\n\t\treadonly appliedValue: number\n\t\treadonly discountAmount: number | null\n\t\treadonly trialDays: number | null\n\t\treadonly featureId: string | null\n\t}\n}\n\nexport interface CreatePromoInput {\n\treadonly code: string\n\treadonly name: string\n\treadonly description?: string\n\treadonly type: PromoType\n\treadonly value: number\n\treadonly maxUses?: number\n\treadonly maxUsesPerUser?: number\n\treadonly expiresAt?: string\n\treadonly startsAt?: string\n\treadonly minPurchaseAmount?: number\n\treadonly applicablePlanIds?: readonly string[]\n\treadonly metadata?: Record<string, unknown>\n}\n\nexport interface UpdatePromoInput {\n\treadonly name?: string\n\treadonly description?: string | null\n\treadonly status?: PromoStatus\n\treadonly maxUses?: number | null\n\treadonly maxUsesPerUser?: number | null\n\treadonly expiresAt?: string | null\n\treadonly startsAt?: string | null\n\treadonly minPurchaseAmount?: number | null\n\treadonly applicablePlanIds?: readonly string[] | null\n\treadonly metadata?: Record<string, unknown>\n}\n\nexport interface ListPromosOptions {\n\treadonly status?: PromoStatus\n\treadonly limit?: number\n\treadonly offset?: number\n}\n\nexport interface ListPromosResult {\n\treadonly promos: readonly PromoCode[]\n\treadonly total: number\n}\n\nexport interface PromoRedemption {\n\treadonly id: string\n\treadonly promoId: string\n\treadonly code: string\n\treadonly userId: string\n\treadonly appliedValue: number\n\treadonly createdAt: string\n}\n\nexport interface ListRedemptionsOptions {\n\treadonly promoId?: string\n\treadonly userId?: string\n\treadonly limit?: number\n\treadonly offset?: number\n}\n\nexport interface ListRedemptionsResult {\n\treadonly redemptions: readonly PromoRedemption[]\n\treadonly total: number\n}\n\n// ============================================================================\n// Client functions (projectAuth + userAuth)\n// ============================================================================\n\n/** Validate a promo code — safe to call with a publishable key. */\nexport async function validatePromo(\n\tconfig: SylphxConfig,\n\tinput: ValidatePromoInput,\n): Promise<ValidatePromoResult> {\n\treturn callApi<ValidatePromoResult>(config, '/promo/validate', {\n\t\tmethod: 'POST',\n\t\tbody: input,\n\t})\n}\n\n/** Redeem a promo for the authenticated user. Requires a user access token. */\nexport async function redeemPromo(\n\tconfig: SylphxConfig,\n\tinput: RedeemPromoInput,\n): Promise<RedeemPromoResult> {\n\treturn callApi<RedeemPromoResult>(config, '/promo/redeem', {\n\t\tmethod: 'POST',\n\t\tbody: input,\n\t})\n}\n\n// ============================================================================\n// Admin functions (serverAuth — secret key only)\n// ============================================================================\n\nexport async function listPromos(\n\tconfig: SylphxConfig,\n\toptions: ListPromosOptions = {},\n): Promise<ListPromosResult> {\n\treturn callApi<ListPromosResult>(config, '/admin/promo', {\n\t\tquery: {\n\t\t\tstatus: options.status,\n\t\t\tlimit: options.limit,\n\t\t\toffset: options.offset,\n\t\t},\n\t})\n}\n\nexport async function getPromo(\n\tconfig: SylphxConfig,\n\tpromoId: string,\n): Promise<{ promo: PromoCode }> {\n\treturn callApi(config, `/admin/promo/${encodeURIComponent(promoId)}`)\n}\n\nexport async function createPromo(\n\tconfig: SylphxConfig,\n\tinput: CreatePromoInput,\n): Promise<{ promo: PromoCode }> {\n\treturn callApi(config, '/admin/promo', {\n\t\tmethod: 'POST',\n\t\tbody: input,\n\t})\n}\n\nexport async function updatePromo(\n\tconfig: SylphxConfig,\n\tpromoId: string,\n\tinput: UpdatePromoInput,\n): Promise<{ promo: PromoCode }> {\n\treturn callApi(config, `/admin/promo/${encodeURIComponent(promoId)}`, {\n\t\tmethod: 'PATCH',\n\t\tbody: input,\n\t})\n}\n\nexport async function deletePromo(\n\tconfig: SylphxConfig,\n\tpromoId: string,\n): Promise<{ success: boolean }> {\n\treturn callApi(config, `/admin/promo/${encodeURIComponent(promoId)}`, {\n\t\tmethod: 'DELETE',\n\t})\n}\n\nexport async function listPromoRedemptions(\n\tconfig: SylphxConfig,\n\toptions: ListRedemptionsOptions = {},\n): Promise<ListRedemptionsResult> {\n\treturn callApi<ListRedemptionsResult>(config, '/admin/promo/redemptions', {\n\t\tquery: {\n\t\t\tpromoId: options.promoId,\n\t\t\tuserId: options.userId,\n\t\t\tlimit: options.limit,\n\t\t\toffset: options.offset,\n\t\t},\n\t})\n}\n"],"mappings":"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","names":["message","encode","errors_exports","init_errors","message","init_errors","init_errors","init_errors","tag","init_errors","getCryptoKey","deriveKey","wrap","encode","unwrap","init_errors","decrypt","init_errors","init_errors","init_errors","keyData","init_errors","init_errors","tag","encrypt","init_errors","wrap","encrypt","encode","unwrap","tag","decrypt","unwrap","tag","init_errors","init_errors","protectedHeader","tag","init_decrypt","init_errors","tag","init_decrypt","init_errors","init_decrypt","init_errors","encode","encode","wrap","init_errors","init_encrypt","init_errors","encode","tag","encrypt","init_encrypt","init_errors","jwe","encode","subtleAlgorithm","init_errors","subtleAlgorithm","init_verify","init_errors","init_verify","init_errors","init_verify","init_errors","init_errors","init_verify","init_errors","init_decrypt","init_errors","init_encrypt","subtleAlgorithm","init_sign","init_errors","encode","init_sign","init_sign","init_errors","init_sign","init_errors","init_encrypt","encode","init_errors","init_errors","cache","init_errors","jwk","init_errors","init_errors","encode","init_errors","init_errors","init_errors","errors_exports","init_decrypt","init_encrypt","init_verify","init_sign","init_errors","message","message","search","check","user","SylphxError","message","importJWK","jwtVerify","decodeProtectedHeader","digest","buildHeaders","SylphxError","message","buildHeaders","SylphxError","message","SylphxError","message","buildHeaders","SylphxError","message","decoder","isRetryableError","timingSafeEqual","message","interpolatePath","message","decoder","sleep","base64UrlEncode","digest"]}