scorezilla 0.3.0-next.2 → 0.3.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/config.ts","../src/hmac.ts","../src/paths.ts","../src/errors.ts","../src/retry.ts","../src/transport.ts","../src/user-agent.ts","../src/verifiers.ts","../src/server.ts"],"names":[],"mappings":"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","file":"server.js","sourcesContent":["/**\n * SDK configuration.\n *\n * The `ScorezillaConfig` is a TypeScript-level discriminated union of\n * `PublicKeyConfig` and `SecretKeyConfig`. The mutual-exclusivity (you may\n * pass `publicKey` OR `secretKey`, never both) is enforced at compile time:\n * passing both fields fails type-checking before the runtime check fires.\n *\n * The runtime check in {@link validateConfig} is the second line of defense\n * for consumers using plain JS or `as any` casts.\n */\n\nimport type { FetchImpl } from './transport';\n\n/** Production API URL. Override via `baseUrl` in {@link ScorezillaConfig} to\n * point at a development worker, staging environment, or a private\n * deployment. */\nexport const DEFAULT_BASE_URL = 'https://api.scorezilla.dev';\n\n/** Public key format: `pk_<slug>_<base62>`. Issued by the operator\n * dashboard. Slug is the game slug; base62 is the random suffix. */\nexport const PUBLIC_KEY_PATTERN = /^pk_[a-z0-9-]+_[A-Za-z0-9]+$/;\n\n/** Secret key prefix — secrets are `sk_live_<id>_<base62>`. Live-only for\n * v0.1.0; the SDK doesn't yet support a `sk_test_*` tier. */\nexport const SECRET_KEY_PREFIX = 'sk_live_';\n\n/** Shared options across both auth modes. */\nexport interface BaseConfig {\n /** API base URL (no trailing slash required). Defaults to {@link DEFAULT_BASE_URL}. */\n baseUrl?: string;\n /** Custom fetch implementation — defaults to `globalThis.fetch`. Pass\n * `node-fetch`, `undici`, or a mock here. The explicit signature\n * (`(RequestInfo | URL, init?) => Promise<Response>`) is broader than\n * `typeof fetch` so common polyfills typecheck cleanly. */\n fetch?: FetchImpl;\n /** Per-request timeout in milliseconds. Defaults to 30 s. */\n timeoutMs?: number;\n /** Maximum retry attempts on transient failures. Defaults to 2 (so the\n * worst-case total request count is 3). */\n maxRetries?: number;\n /** Override the default `User-Agent` header (Node/Workers/Bun/Deno —\n * browsers silently ignore the value). */\n userAgent?: string;\n /** Injectable sleep implementation for the retry loop's inter-attempt\n * pause. Exists for tests that need deterministic, zero-delay retries\n * rather than real wall-clock backoff. Production code should leave\n * this unset to use the default exponential backoff with jitter.\n * @internal */\n sleepImpl?: (ms: number, signal?: AbortSignal) => Promise<void>;\n /** Inject a sink for SDK deprecation warnings. Defaults to\n * `console.warn`. Pass your logger's `warn` to route SDK signals into\n * the rest of your observability stack, or pass `() => {}` to\n * suppress them. The SDK uses this ONLY for developer-visible\n * deprecation notices triggered by `Deprecation` / `Sunset` response\n * headers — never for runtime errors. */\n warn?: (...args: unknown[]) => void;\n}\n\n/** Public-key auth: browser-safe path. The key is fingerprinted to a game\n * on the server side via `pk_<gameSlug>_<base62>`. */\nexport type PublicKeyConfig = BaseConfig & {\n publicKey: string;\n secretKey?: never;\n};\n\n/** Secret-key auth: server-side HMAC. A single self-contained token of the\n * shape `sk_live_<keyId>_<random>`. The SDK parses the keyId out and uses\n * the whole string as the HMAC key. One value to copy, one to manage —\n * matches Stripe's design and the public-key client's single-string shape.\n *\n * Past versions of the SDK took `{ id, secret }` separately. That was an\n * unnecessary cognitive tax — the id was always derivable from a properly-\n * formatted secret. v0.1.0-next.2+ takes the single-string form. */\nexport type SecretKeyConfig = BaseConfig & {\n secretKey: string;\n publicKey?: never;\n};\n\n/** The top-level config type. The union is open for additional auth modes\n * in future major releases. */\nexport type ScorezillaConfig = PublicKeyConfig | SecretKeyConfig;\n\n/**\n * Internal post-validation shape. The client layer reads from this — every\n * field is non-optional with defaults applied, and `auth` is a clean\n * discriminated union (no leftover `publicKey?: never` cruft).\n */\nexport interface ResolvedConfig {\n readonly baseUrl: string;\n readonly fetch: FetchImpl | undefined;\n readonly timeoutMs: number | undefined;\n readonly maxRetries: number | undefined;\n readonly sleepImpl: ((ms: number, signal?: AbortSignal) => Promise<void>) | undefined;\n readonly warn: ((...args: unknown[]) => void) | undefined;\n readonly userAgent: string | undefined;\n readonly auth:\n | { kind: 'public'; key: string }\n | { kind: 'secret'; keyId: string; secret: string };\n}\n\n/**\n * Validate a `ScorezillaConfig` and return a normalized {@link ResolvedConfig}.\n *\n * Throws a plain `Error` (not `ScorezillaError`) on misuse — these are\n * caller bugs, not API failures, and shouldn't be confused with the\n * runtime error class.\n */\nexport function validateConfig(cfg: ScorezillaConfig): ResolvedConfig {\n if (!cfg || typeof cfg !== 'object') {\n throw new Error('scorezilla: config must be an object with publicKey or secretKey');\n }\n\n const hasPublic = 'publicKey' in cfg && cfg.publicKey !== undefined;\n const hasSecret = 'secretKey' in cfg && cfg.secretKey !== undefined;\n\n // Defensive runtime checks for consumers using `as any` or plain JS.\n if (hasPublic && hasSecret) {\n throw new Error('scorezilla: config must not contain both publicKey and secretKey');\n }\n if (!hasPublic && !hasSecret) {\n throw new Error('scorezilla: config must contain either publicKey or secretKey');\n }\n\n let auth: ResolvedConfig['auth'];\n if (hasPublic) {\n auth = { kind: 'public', key: validatePublicKeyValue((cfg as PublicKeyConfig).publicKey) };\n } else {\n const resolved = validateSecretKey(cfg as SecretKeyConfig);\n auth = { kind: 'secret', keyId: resolved.keyId, secret: resolved.secret };\n }\n\n const baseUrlRaw = cfg.baseUrl ?? DEFAULT_BASE_URL;\n if (typeof baseUrlRaw !== 'string' || baseUrlRaw.length === 0) {\n throw new Error('scorezilla: baseUrl must be a non-empty string when provided');\n }\n\n return {\n baseUrl: baseUrlRaw.replace(/\\/+$/, ''),\n fetch: cfg.fetch,\n timeoutMs: cfg.timeoutMs,\n maxRetries: cfg.maxRetries,\n sleepImpl: cfg.sleepImpl,\n warn: cfg.warn,\n userAgent: cfg.userAgent,\n auth,\n };\n}\n\n/**\n * Validate a `publicKey` string and return it. Throws a plain `Error` on\n * misuse — caller bug, not an API failure.\n *\n * Never echo any characters of the supplied key in the error message —\n * if a developer paste-mistakes a `sk_live_*` secret here, the previous\n * `pk.slice(0, 12)` would have leaked 12 chars of the secret to whatever\n * log aggregator catches the Error. Report only the shape.\n */\nfunction validatePublicKeyValue(pk: unknown): string {\n if (typeof pk !== 'string' || !PUBLIC_KEY_PATTERN.test(pk)) {\n const shape = typeof pk === 'string' ? `string of length ${pk.length}` : typeof pk;\n throw new Error(\n `scorezilla: publicKey must match ${PUBLIC_KEY_PATTERN.toString()} (got: ${shape})`,\n );\n }\n return pk;\n}\n\n/** Exact shape of the new secret-key format:\n *\n * `sk_live_<keyId>_<random>`\n *\n * - `<keyId>` is a UUID v4 (hyphenated, 36 chars). Used by the API for\n * row lookup and as the `keyId=` parameter in HMAC Authorization\n * headers. Non-sensitive; appears in logs and audit trails.\n * - `<random>` is a base62-encoded suffix from the operator dashboard's\n * issuance flow (~32 chars). The HMAC key is the WHOLE plaintext\n * string, so changing only the prefix doesn't weaken anything.\n *\n * Two-field `{ id, secret }` configs from pre-next.2 are NOT accepted —\n * `validateSecretKey` requires a single string.\n */\nexport const SECRET_KEY_PATTERN =\n /^sk_live_([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})_[A-Za-z0-9]+$/;\n\n/**\n * Validate a {@link SecretKeyConfig} and return a normalized `{ keyId,\n * secret }`. The input is a single self-contained string; we parse the\n * keyId out of it via {@link SECRET_KEY_PATTERN}.\n *\n * Throws a plain `Error` on misuse. The error never echoes any characters\n * of the secret — only the shape and prefix sanity, just like the\n * public-key validator.\n *\n * @stability internal — exposed for `scorezilla/server`'s constructor\n * and unit tests. Not part of the public API.\n */\nexport function validateSecretKey(cfg: SecretKeyConfig): { keyId: string; secret: string } {\n if (!cfg || typeof cfg !== 'object') {\n throw new Error('scorezilla/server: config must be an object with a secretKey field');\n }\n const sk = cfg.secretKey;\n if (typeof sk !== 'string') {\n throw new Error(\n `scorezilla/server: secretKey must be a single string of the shape ${SECRET_KEY_PREFIX}<keyId>_<random> (got: ${typeof sk})`,\n );\n }\n const match = SECRET_KEY_PATTERN.exec(sk);\n if (!match) {\n // Never echo the value. A typo'd publicKey paste or a pre-next.2\n // `{ id, secret }` object lands here.\n const shape = `string of length ${sk.length}`;\n throw new Error(\n `scorezilla/server: secretKey must match ${SECRET_KEY_PATTERN.toString()} ` +\n `(got: ${shape}). v0.1.0-next.2 switched to a single-token format — if you have a pre-next.2 ` +\n `pair, issue a fresh key in the dashboard to upgrade.`,\n );\n }\n return { keyId: match[1]!, secret: sk };\n}\n","/**\n * HMAC-SHA256 request signing for the secret-key path (`scorezilla/server`).\n *\n * The SDK side here MUST stay in lockstep with the API's verifier\n * (`apps/api/src/auth/hmac.ts` in the monorepo). The contract:\n *\n * Wire format\n * -----------\n * Authorization: Scorezilla-HMAC-SHA256 keyId=<id>, ts=<unix-seconds>,\n * nonce=<random>, signature=<base64url>\n *\n * Canonical signing string (newline-separated, 5 lines)\n * -----------------------------------------------------\n * {ts}\\n{nonce}\\n{METHOD}\\n{pathAndQuery}\\n{sha256_hex(body)}\n *\n * Algorithm: HMAC-SHA256 of the signing string with the raw secret\n * bytes as the key. Output: base64url (no padding).\n *\n * Everything is built on WebCrypto (`crypto.subtle`) — works in browsers,\n * Node ≥ 20, Workers, Bun, and Deno without a Node-only dependency.\n *\n * Stability: this module is internal — exported only for tests and the\n * server adapter. Consumers should always use `Scorezilla` from\n * `scorezilla/server` (which calls into here).\n */\n\nconst enc = new TextEncoder();\n\n/** Auth-scheme prefix. Mirrors the API's `AUTH_SCHEME` constant exactly. */\nexport const HMAC_AUTH_SCHEME = 'Scorezilla-HMAC-SHA256';\n\n/** Minimum acceptable length for a caller-supplied nonce. The default\n * path uses `crypto.randomUUID()` which is 36 characters; injectable\n * nonces (test paths, advanced custom-flow consumers) must clear a\n * conservative floor so a misconfigured caller can't accidentally\n * emit a signed header with a weak or empty nonce. 16 characters is\n * the documented minimum and matches the server's lower bound for\n * acceptable replay-protection entropy. */\nconst MIN_NONCE_LENGTH = 16;\n\n/** Latest signing-string format version this SDK emits. The API verifier\n * also accepts v=1 (legacy, no host binding) during the rollout window —\n * see `apps/api/src/auth/hmac.ts` in the monorepo. */\nexport const HMAC_SIGNING_VERSION_LATEST = 2 as const;\n\n/**\n * Construct the canonical signing string. Pure — no I/O. Both sender\n * (this module) and verifier (the API) call this with the same inputs\n * and must produce identical output.\n *\n * `pathAndQuery` is signed verbatim. If the SDK ever URL-encodes path\n * segments differently than the server does, signatures will mismatch.\n *\n * `host` MUST be the host portion of the URL the request is being sent\n * to. It's lowercased here per RFC 9110 §4.2.4 (case-insensitive host\n * comparison). With v=2 (current default), `host` is the 4th line of\n * the canonical string and binds the signature to the target origin so\n * a signature minted against staging cannot replay against prod.\n *\n * `version` defaults to {@link HMAC_SIGNING_VERSION_LATEST}. v=1 (legacy,\n * pre-A-H4) omits `host` from the canonical string — kept for compat\n * tests; production callers should not pass v=1.\n */\nexport async function buildSigningString(\n method: string,\n pathAndQuery: string,\n ts: number,\n nonce: string,\n body: string,\n host: string,\n version: number = HMAC_SIGNING_VERSION_LATEST,\n): Promise<string> {\n const bodyHash = await sha256Hex(body);\n const upperMethod = method.toUpperCase();\n if (version === 1) {\n return `${ts}\\n${nonce}\\n${upperMethod}\\n${pathAndQuery}\\n${bodyHash}`;\n }\n return `${ts}\\n${nonce}\\n${upperMethod}\\n${host.toLowerCase()}\\n${pathAndQuery}\\n${bodyHash}`;\n}\n\n/** HMAC-SHA-256 of `message` with `secret` (UTF-8 encoded), base64url. */\nexport async function hmacSha256B64u(secret: string, message: string): Promise<string> {\n const key = await crypto.subtle.importKey(\n 'raw',\n enc.encode(secret),\n { name: 'HMAC', hash: 'SHA-256' },\n false,\n ['sign'],\n );\n const sig = await crypto.subtle.sign('HMAC', key, enc.encode(message));\n return base64UrlEncode(new Uint8Array(sig));\n}\n\n/** SHA-256 of `message` (UTF-8), lowercase hex. Used inside the signing\n * string to hash the request body. */\nexport async function sha256Hex(message: string): Promise<string> {\n const digest = await crypto.subtle.digest('SHA-256', enc.encode(message));\n return Array.from(new Uint8Array(digest))\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('');\n}\n\n/**\n * Build the `Authorization` header value for a single request.\n *\n * Each call generates a fresh `ts` and `nonce`. Retries MUST call this\n * again — reusing a (ts, nonce) is what the server's replay protection\n * rejects.\n *\n * Emits v=2 by default (host-bound). The API verifier still accepts v=1\n * (no host binding) for pre-A-H4 SDK builds during the rollout window;\n * see `apps/api/src/auth/hmac.ts:parseAuthHeader`. New code paths should\n * use v=2 — the v=1 escape hatch exists only for legacy interop.\n *\n * @returns the full header value (including the scheme prefix)\n */\nexport async function buildHmacAuthHeader(args: {\n keyId: string;\n secret: string;\n method: string;\n pathAndQuery: string;\n /** Host portion of the request URL (e.g. `new URL(baseUrl).host`). v=2\n * signatures bind to this; v=1 ignores it. */\n host: string;\n body: string;\n /** Injectable for tests; defaults to `Math.floor(Date.now() / 1000)`. */\n nowSeconds?: number;\n /** Injectable for tests; defaults to `crypto.randomUUID()`. */\n nonce?: string;\n /** Signing-string version. Defaults to {@link HMAC_SIGNING_VERSION_LATEST}.\n * v=1 omits both the host from the canonical string AND the `v=` param\n * from the header (for byte-for-byte parity with pre-A-H4 SDKs). */\n version?: 1 | 2;\n}): Promise<string> {\n const ts = args.nowSeconds ?? Math.floor(Date.now() / 1000);\n // If a nonce was injected, validate it. The default path generates a\n // 36-char UUIDv4 which trivially clears the floor — only test or\n // advanced-custom-flow callers ever supply their own. Guarding here\n // means a misconfigured caller can't accidentally sign with an empty\n // or weak nonce that the server's replay protection might still\n // accept (`hmac.ts` on the API side has no minimum-length check).\n if (args.nonce !== undefined) {\n if (typeof args.nonce !== 'string' || args.nonce.length < MIN_NONCE_LENGTH) {\n throw new Error(\n `scorezilla: nonce must be a string of at least ${MIN_NONCE_LENGTH} characters; ` +\n 'use the default (UUIDv4 via crypto.randomUUID) unless you have a specific reason.',\n );\n }\n }\n const nonce = args.nonce ?? generateNonce();\n const version = args.version ?? HMAC_SIGNING_VERSION_LATEST;\n const signingString = await buildSigningString(\n args.method,\n args.pathAndQuery,\n ts,\n nonce,\n args.body,\n args.host,\n version,\n );\n const signature = await hmacSha256B64u(args.secret, signingString);\n // v=1: omit the `v=` param (back-compat byte parity).\n // v=2 (default): append `v=2` so the verifier knows to include host in\n // the canonical string. Future versions follow the same pattern.\n const vParam = version === 1 ? '' : `, v=${version}`;\n return `${HMAC_AUTH_SCHEME} keyId=${args.keyId}, ts=${ts}, nonce=${nonce}, signature=${signature}${vParam}`;\n}\n\n/**\n * Cryptographically-random nonce. The server enforces no-reuse within a\n * 10-minute window (per keyId), so a fresh random value per request is\n * required for retry correctness — if the same (keyId, nonce) pair lands\n * twice the second is rejected as a replay.\n */\nexport function generateNonce(): string {\n const c = (globalThis as { crypto?: { randomUUID?: () => string } }).crypto;\n if (!c || typeof c.randomUUID !== 'function') {\n // Same posture as `generateIdempotencyKey` in retry.ts — runtime\n // misconfiguration, surface a typed error consumers can branch on.\n throw new Error(\n 'scorezilla: globalThis.crypto.randomUUID is unavailable. ' +\n 'The HMAC server adapter requires Node ≥ 20 or a modern runtime.',\n );\n }\n return c.randomUUID();\n}\n\n/** URL-safe base64 without padding. Matches the API's `base64UrlEncode`. */\nexport function base64UrlEncode(bytes: Uint8Array): string {\n let bin = '';\n for (const b of bytes) bin += String.fromCharCode(b);\n return btoa(bin).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '');\n}\n","/**\n * URL path builders for the Scorezilla API at `/v1`.\n *\n * Every helper:\n * • URL-encodes segments via `encodeURIComponent` (boardIds and\n * playerIds may contain `/`, `#`, `?`, etc.).\n * • Rejects empty or non-string segments with a thrown `Error` (caller\n * bug, not an API failure — `ScorezillaError` is reserved for\n * network-layer outcomes).\n *\n * Each returned path:\n * • Starts with `/v1/`\n * • Has no trailing slash\n * • Includes the query string (if any) joined with `?`\n *\n * The transport's `buildUrl` strips any trailing slash from `baseUrl`\n * before joining, so the two never collide into `//`.\n */\n\nfunction encodeSegment(value: unknown, label: 'boardId' | 'playerId' | 'gameId'): string {\n if (typeof value !== 'string' || value.length === 0) {\n throw new Error(`scorezilla: ${label} must be a non-empty string`);\n }\n return encodeURIComponent(value);\n}\n\nfunction buildQueryString(params: Record<string, number | undefined>): string {\n const usp = new URLSearchParams();\n for (const [k, v] of Object.entries(params)) {\n if (v !== undefined) usp.set(k, String(v));\n }\n const qs = usp.toString();\n return qs.length > 0 ? `?${qs}` : '';\n}\n\n/** `POST /v1/boards/:boardId/scores` */\nexport function submitScorePath(boardId: string): string {\n return `/v1/boards/${encodeSegment(boardId, 'boardId')}/scores`;\n}\n\n/** `POST /v1/secure/scores` — the HMAC-signed submission endpoint used by\n * the `scorezilla/server` adapter. The boardId moves into the request\n * body rather than the path: every submission here signs over the body\n * hash, so the API resolves the board from the body and authorizes via\n * the verified keyId in the Authorization header. */\nexport function submitScoreSecurePath(): string {\n return '/v1/secure/scores';\n}\n\n/** Options for {@link getLeaderboardPath}. */\nexport interface LeaderboardQuery {\n /** Number of entries to return (the API caps at 1000). Defaults server-side to 100. */\n top?: number;\n /** Offset into the sorted board (the API caps at 1_000_000). Defaults server-side to 0. */\n offset?: number;\n}\n\n/** `GET /v1/boards/:boardId/leaderboard?top=&offset=` */\nexport function getLeaderboardPath(boardId: string, q?: LeaderboardQuery): string {\n return (\n `/v1/boards/${encodeSegment(boardId, 'boardId')}/leaderboard` +\n buildQueryString({ top: q?.top, offset: q?.offset })\n );\n}\n\n/** `GET /v1/boards/:boardId/players/:playerId/rank` */\nexport function getPlayerRankPath(boardId: string, playerId: string): string {\n return `/v1/boards/${encodeSegment(boardId, 'boardId')}/players/${encodeSegment(playerId, 'playerId')}/rank`;\n}\n\n/** Options for {@link getWindowAroundPath}. */\nexport interface WindowAroundQuery {\n /** Entries strictly above the player (the API caps at 100). Defaults server-side to 5. */\n before?: number;\n /** Entries strictly below the player (the API caps at 100). Defaults server-side to 5. */\n after?: number;\n}\n\n/** `GET /v1/boards/:boardId/players/:playerId/window?before=&after=` */\nexport function getWindowAroundPath(\n boardId: string,\n playerId: string,\n q?: WindowAroundQuery,\n): string {\n return (\n `/v1/boards/${encodeSegment(boardId, 'boardId')}/players/${encodeSegment(playerId, 'playerId')}/window` +\n buildQueryString({ before: q?.before, after: q?.after })\n );\n}\n","/**\n * SDK error type.\n *\n * Every non-2xx API response is normalized into a `ScorezillaError` instance\n * by the transport layer. Network failures and timeouts surface as the same\n * class (with `status: 0`) so callers have a single error type to catch.\n *\n * **Invariant — consumers MUST branch on `code` (and optionally `reason`),\n * never on `message`.** The English-language `message` is for operator\n * logging only and is explicitly **not** part of the SemVer contract; a\n * minor release MAY reword any message. Machine logic that depends on\n * message text will break silently across upgrades.\n */\nimport type {\n ApiError,\n BillingTier,\n OutOfBoundsReason,\n ScorezillaErrorCode,\n UsageCapReason,\n} from './types';\n\n/** Maximum length, in characters, that an error `message` may hold.\n *\n * Defense against a future server-side change that includes caller-controlled\n * strings in error messages — e.g., echoing back a malformed `playerId` of\n * arbitrary length. Capping at 500 keeps the thrown error printable in\n * devtools and bounded in memory usage. */\nexport const MESSAGE_MAX_CHARS = 500;\n\n/** Suffix appended when a server-supplied message exceeds {@link MESSAGE_MAX_CHARS}. */\nexport const TRUNCATION_SUFFIX = '… [truncated]';\n\n/** Sentinel `status` for network errors / timeouts (no HTTP response was received). */\nexport const STATUS_NETWORK_ERROR = 0;\n\nfunction truncateMessage(raw: unknown): string {\n if (typeof raw !== 'string') return '';\n if (raw.length <= MESSAGE_MAX_CHARS) return raw;\n // Safety against a future tweak that makes TRUNCATION_SUFFIX longer than\n // the cap — `slice(0, -n)` would silently chop from the end instead of\n // from the beginning, masking the bug. `Math.max(0, …)` keeps the\n // truncation honest.\n const sliceEnd = Math.max(0, MESSAGE_MAX_CHARS - TRUNCATION_SUFFIX.length);\n return raw.slice(0, sliceEnd) + TRUNCATION_SUFFIX;\n}\n\n/**\n * Truncate a server-supplied string field that lives on `ScorezillaError`\n * but isn't `message`. Returns `undefined` for non-strings so the field\n * type stays `string | undefined` rather than being coerced to `''`.\n *\n * Defense-in-depth: even though current API contracts treat these as small\n * identifiers/classifiers, the SDK shouldn't trust the server to keep them\n * bounded — a regression that echoes back caller-controlled input would\n * otherwise land unbounded strings in the thrown error object.\n */\nfunction truncateField(raw: unknown): string | undefined {\n if (typeof raw !== 'string') return undefined;\n if (raw.length <= MESSAGE_MAX_CHARS) return raw;\n const sliceEnd = Math.max(0, MESSAGE_MAX_CHARS - TRUNCATION_SUFFIX.length);\n return raw.slice(0, sliceEnd) + TRUNCATION_SUFFIX;\n}\n\n/**\n * Options for {@link ScorezillaError.from}.\n *\n * The fields mirror what's available after a fetch round-trip: the HTTP\n * status, the parsed JSON body (if any), the request ID from\n * `X-Request-Id`, and an optional `cause` for the underlying\n * network/abort error.\n */\nexport interface ScorezillaErrorFromInit {\n status: number;\n body?: ApiError | undefined;\n requestId?: string | undefined;\n cause?: unknown;\n}\n\n/**\n * Thrown by the SDK for every failure path — non-2xx responses, network\n * errors, aborts, and timeouts.\n *\n * Cross-realm `instanceof` is guaranteed: the class sets `Error.prototype`\n * explicitly so checks survive iframe / worker boundaries.\n *\n * @example\n * ```ts\n * try {\n * await sz.submitScore({ boardId, playerId, score });\n * } catch (e) {\n * if (!(e instanceof ScorezillaError)) throw e;\n *\n * if (e.isRateLimited()) {\n * await sleep((e.retryAfter ?? 30) * 1000);\n * return retry();\n * }\n * if (e.code === 'out_of_bounds') {\n * console.warn(`Score crosses ${e.reason} bound (limit ${e.bound})`);\n * return;\n * }\n * if (e.isAuth()) throw new Error('SDK misconfigured — bad publicKey');\n *\n * // Anything else: surface to your reporter with requestId for support.\n * console.error(`Scorezilla ${e.code} (${e.status}) — request ${e.requestId}`);\n * throw e;\n * }\n * ```\n *\n * @since 0.1.0\n * @stability stable\n */\nexport class ScorezillaError extends Error {\n /** HTTP status of the response, or {@link STATUS_NETWORK_ERROR} (0) for\n * network / abort / timeout. */\n readonly status: number;\n\n /** Machine-stable error code from the API. Open union — see\n * {@link ScorezillaErrorCode}. For network errors, this is `'network_error'`;\n * for aborts, `'aborted'`; for timeouts, `'timeout'`. */\n readonly code: ScorezillaErrorCode;\n\n /** Sub-classifier — present on:\n * - `out_of_bounds`: `'below_min' | 'above_max'`\n * - `usage_cap_exceeded`: `'over_cap' | 'suspended'`\n * and possibly other codes in future minor releases. */\n readonly reason: OutOfBoundsReason | UsageCapReason | string | undefined;\n\n /** Seconds — present on `rate_limited`. Honored by the transport's retry\n * policy (Step 2.4). */\n readonly retryAfter: number | undefined;\n\n /** Server-issued request ID, lifted from the `X-Request-Id` response\n * header. Pass this to support when filing bugs. */\n readonly requestId: string | undefined;\n\n /** The bound value crossed on `out_of_bounds`. */\n readonly bound: number | undefined;\n\n /** Which rate-limit layer fired on `rate_limited`. */\n readonly layer: string | undefined;\n\n /** Tenant's billing tier — present on `usage_cap_exceeded`. */\n readonly tier: BillingTier | undefined;\n\n /** The cap value crossed on `usage_cap_exceeded`. `0` indicates a\n * suspended tenant. `undefined` on all other error codes. */\n readonly cap: number | undefined;\n\n /** The post-increment submit count on `usage_cap_exceeded`. Always\n * `> cap` when `reason === 'over_cap'`. */\n readonly count: number | undefined;\n\n /** The period the count belongs to on `usage_cap_exceeded`, in `YYYY-MM`\n * UTC form. */\n readonly period: string | undefined;\n\n /** ISO-8601 timestamp of midnight UTC on the 1st of the next month —\n * the counter's natural reset point on `usage_cap_exceeded`. */\n readonly resetsAt: string | undefined;\n\n /** The underlying cause (e.g., a `TypeError: fetch failed`) for\n * network/abort/timeout paths. `undefined` when the error came from a\n * successfully-parsed API error body. */\n override readonly cause: unknown;\n\n constructor(\n message: string,\n init: {\n status: number;\n code: ScorezillaErrorCode;\n reason?: string | undefined;\n retryAfter?: number | undefined;\n requestId?: string | undefined;\n bound?: number | undefined;\n layer?: string | undefined;\n tier?: BillingTier | undefined;\n cap?: number | undefined;\n count?: number | undefined;\n period?: string | undefined;\n resetsAt?: string | undefined;\n cause?: unknown;\n },\n ) {\n super(truncateMessage(message));\n this.name = 'ScorezillaError';\n this.status = init.status;\n this.code = init.code;\n // String fields from the server side are length-capped. The cap is\n // generous — `MESSAGE_MAX_CHARS` is well above any legitimate\n // identifier or classifier — but defends against a future server\n // regression that echoes back caller-controlled input into these\n // fields. `requestId` typically a UUID; `reason`/`layer` typically a\n // short enum-like string; all three should sit far under the cap.\n this.reason = truncateField(init.reason);\n this.retryAfter = init.retryAfter;\n this.requestId = truncateField(init.requestId);\n this.bound = init.bound;\n this.layer = truncateField(init.layer);\n // Usage-cap fields. `tier` is a short enum-like string; field-trunc\n // is defense-in-depth in case the server ever leaks a longer value\n // through. The numeric fields don't need truncation.\n this.tier = truncateField(init.tier) as BillingTier | undefined;\n this.cap = init.cap;\n this.count = init.count;\n this.period = truncateField(init.period);\n this.resetsAt = truncateField(init.resetsAt);\n this.cause = init.cause;\n\n // Cross-realm instanceof: explicitly set the prototype. Without this,\n // an instance of ScorezillaError thrown in one realm (e.g., a worker)\n // and caught in another (the main thread) wouldn't satisfy\n // `e instanceof ScorezillaError` because the constructor lookup\n // crosses the realm boundary.\n Object.setPrototypeOf(this, ScorezillaError.prototype);\n\n // V8 stack capture — omits the constructor frame for cleaner traces.\n // No-op on engines without `captureStackTrace` (Safari, older Firefox).\n if (\n typeof (Error as unknown as { captureStackTrace?: unknown }).captureStackTrace === 'function'\n ) {\n (\n Error as unknown as {\n captureStackTrace: (target: object, ctor: unknown) => void;\n }\n ).captureStackTrace(this, ScorezillaError);\n }\n }\n\n // ─── Sub-message helpers ─────────────────────────────────────────────\n // Stable wrappers over the `code` discriminator so consumers can write\n // `if (err.isRateLimited())` instead of memorizing the code spelling.\n\n /** `true` when this error is a 429 / `rate_limited`. */\n isRateLimited(): boolean {\n return this.code === 'rate_limited';\n }\n\n /**\n * `true` when this error is a 402 / `usage_cap_exceeded`. The tenant\n * has either hit their tier's monthly submit cap (`reason ===\n * 'over_cap'`) or is suspended (`reason === 'suspended'`).\n *\n * Consumers SHOULD NOT auto-retry on this error — the cap doesn't lift\n * until `resetsAt`. Surface to the developer with an upgrade prompt\n * (over_cap) or contact-support message (suspended).\n */\n isUsageCapExceeded(): boolean {\n return this.code === 'usage_cap_exceeded';\n }\n\n /** `true` when this error is a 402 + reason 'suspended' (vs over-cap). */\n isSuspended(): boolean {\n return this.code === 'usage_cap_exceeded' && this.reason === 'suspended';\n }\n\n /** `true` when this error is a 401 / `unauthorized` (or 403 / `forbidden`). */\n isAuth(): boolean {\n return this.code === 'unauthorized' || this.code === 'forbidden';\n }\n\n /** `true` when this error is a 404 / `not_found`. */\n isNotFound(): boolean {\n return this.code === 'not_found';\n }\n\n /** `true` when this error is a 422 / `out_of_bounds` (score below/above board limit). */\n isOutOfBounds(): boolean {\n return this.code === 'out_of_bounds';\n }\n\n /** `true` for the SDK's retryable conditions: pure network errors, 5xx, and\n * 429. Deliberately excludes `timeout` and `aborted` — those are caller-\n * observable terminal states, not transient. Aligned with `shouldRetryError`\n * in `retry.ts` so a consumer mirroring the SDK's retry policy gets the\n * same answer the transport does. */\n isTransient(): boolean {\n if (this.code === 'network_error') return true;\n if (this.status >= 500 && this.status < 600) return true;\n return this.isRateLimited();\n }\n\n /** `true` when this error is a 409 / `conflict` (idempotency-key conflict\n * on retry). */\n isConflict(): boolean {\n return this.code === 'conflict';\n }\n\n // ─── Factory ─────────────────────────────────────────────────────────\n\n /**\n * Build a `ScorezillaError` from a fetch round-trip outcome.\n *\n * Prefer this over `new ScorezillaError(...)` from the transport layer —\n * it does the mapping from API response shape to error fields in one\n * place, so future fields like `correlationId` get added once here.\n *\n * @param init - status, optional parsed body, optional requestId, optional cause\n */\n static from(init: ScorezillaErrorFromInit): ScorezillaError {\n const { status, body, requestId, cause } = init;\n\n // If the body parsed as an API error, use its fields. Otherwise, fall\n // back to status-derived defaults so the SDK always returns a\n // typed error even when the server returns garbage.\n if (body && body.ok === false && typeof body.error === 'string') {\n return new ScorezillaError(body.message ?? `Request failed: ${body.error}`, {\n status,\n code: body.error,\n reason: body.reason,\n retryAfter: body.retryAfter,\n bound: body.bound,\n layer: body.layer,\n // Usage-cap fields from `ApiError` (populated by the server on\n // 402 responses; undefined on other errors).\n tier: body.tier,\n cap: body.cap,\n count: body.count,\n period: body.period,\n resetsAt: body.resetsAt,\n requestId,\n cause,\n });\n }\n\n // No usable body — synthesize from status code.\n const code = codeForStatus(status);\n return new ScorezillaError(`Request failed with status ${status}`, {\n status,\n code,\n requestId,\n cause,\n });\n }\n\n /**\n * Build a `ScorezillaError` for a transport-level failure (no HTTP\n * response received): network error, abort, or timeout.\n */\n static network(message: string, cause: unknown): ScorezillaError {\n return new ScorezillaError(message, {\n status: STATUS_NETWORK_ERROR,\n code: 'network_error',\n cause,\n });\n }\n\n /** Build a `ScorezillaError` for an `AbortSignal`-triggered cancellation. */\n static aborted(cause: unknown): ScorezillaError {\n return new ScorezillaError('Request aborted', {\n status: STATUS_NETWORK_ERROR,\n code: 'aborted',\n cause,\n });\n }\n\n /** Build a `ScorezillaError` for a request that exceeded its timeout budget. */\n static timeout(timeoutMs: number): ScorezillaError {\n return new ScorezillaError(`Request timed out after ${timeoutMs}ms`, {\n status: STATUS_NETWORK_ERROR,\n code: 'timeout',\n });\n }\n}\n\n/** Default `code` for a given HTTP status when the body didn't parse as ApiError. */\nfunction codeForStatus(status: number): ScorezillaErrorCode {\n if (status === 401) return 'unauthorized';\n if (status === 402) return 'usage_cap_exceeded';\n if (status === 403) return 'forbidden';\n if (status === 404) return 'not_found';\n if (status === 409) return 'conflict';\n if (status === 422) return 'out_of_bounds';\n if (status === 429) return 'rate_limited';\n if (status >= 500) return 'internal_error';\n if (status >= 400) return 'invalid_input';\n return 'internal_error';\n}\n","/**\n * Retry + backoff helpers used by the HTTP transport (src/transport.ts).\n *\n * Pure where possible — `nextDelay` and the predicate functions take no\n * side effects, so they're unit-testable without time mocks. The only\n * impure helpers are {@link sleep} and {@link generateIdempotencyKey},\n * both isolated so callers can swap them in tests.\n */\n\nimport { ScorezillaError } from './errors';\n\n/** Default cap on retry attempts (does not include the initial attempt). */\nexport const DEFAULT_MAX_RETRIES = 2;\n\n/** Base delay for exponential backoff, in milliseconds. */\nexport const BASE_DELAY_MS = 200;\n\n/** Hard ceiling on per-attempt backoff, in milliseconds. */\nexport const MAX_DELAY_MS = 4_000;\n\n/**\n * Maximum `Retry-After` value (in seconds) the SDK will honor. A misbehaving\n * server returning `Retry-After: 86400` won't park the caller for a day —\n * we treat anything over this as transient and fall back to exponential\n * backoff. The transport surfaces a `ScorezillaError` on the next attempt\n * if the server still rejects.\n */\nexport const MAX_RETRY_AFTER_SEC = 30;\n\n/**\n * Pure: compute the delay (in milliseconds) before the next retry.\n *\n * The algorithm is \"decorrelated exponential\" backoff: `BASE_DELAY_MS *\n * 2^attempt` capped at `MAX_DELAY_MS`, multiplied by a jitter factor in\n * `[0.5, 1.0]` to avoid thundering-herd retries from clients that all\n * receive the same 5xx at the same moment.\n *\n * If `retryAfterSec` is provided and `<= MAX_RETRY_AFTER_SEC`, that wins\n * over the exponential schedule (the server has told us a specific wait).\n * Values over the cap are ignored — we fall back to exponential.\n *\n * @param attempt Zero-based retry index (0 = first retry, 1 = second, …).\n * @param retryAfterSec `Retry-After` header value in seconds, if any.\n * @param random Injectable RNG for jitter — defaults to `Math.random`.\n * Pass a deterministic stub in tests.\n */\nexport function nextDelay(\n attempt: number,\n retryAfterSec: number | undefined,\n random: () => number = Math.random,\n): number {\n if (\n typeof retryAfterSec === 'number' &&\n Number.isFinite(retryAfterSec) &&\n retryAfterSec >= 0 &&\n retryAfterSec <= MAX_RETRY_AFTER_SEC\n ) {\n return Math.round(retryAfterSec * 1000);\n }\n\n const exponential = Math.min(BASE_DELAY_MS * 2 ** attempt, MAX_DELAY_MS);\n const jitterFactor = 0.5 + random() * 0.5; // [0.5, 1.0]\n return Math.round(exponential * jitterFactor);\n}\n\n/**\n * Pure: should an HTTP status code trigger a retry?\n *\n * 429 (rate limited) and 5xx (server error) are retryable. 4xx other than\n * 429 are caller errors and never retried — they won't succeed on\n * re-attempt and would waste budget.\n */\nexport function shouldRetryStatus(status: number): boolean {\n if (status === 429) return true;\n if (status >= 500 && status < 600) return true;\n return false;\n}\n\n/**\n * Pure: should a thrown error trigger a retry?\n *\n * A network-level failure (no HTTP response) is retryable. Timeouts are\n * NOT retried by default — the caller set the budget intentionally; retrying\n * would extend it past their intent. Aborts are never retried (signal was\n * explicit).\n */\nexport function shouldRetryError(err: unknown): boolean {\n if (err instanceof ScorezillaError) {\n return err.code === 'network_error';\n }\n return false;\n}\n\n/**\n * Generate an idempotency key for a POST request.\n *\n * Note: the workplan refers to \"UUID v7\" but `crypto.randomUUID()` returns\n * v4 universally (Node 19+, all modern browsers, Workers, Bun, Deno). v4 is\n * the correct choice for an idempotency key — we need uniqueness, not\n * time-ordering. v7's time prefix offers no benefit for keys that live for\n * one request lifetime.\n *\n * Throws if `crypto.randomUUID` isn't available on the platform — that's\n * always a misconfiguration (the SDK declares Node ≥ 20 / modern browsers\n * in `engines`).\n */\nexport function generateIdempotencyKey(): string {\n const c = (globalThis as { crypto?: { randomUUID?: () => string } }).crypto;\n if (!c || typeof c.randomUUID !== 'function') {\n // Throw a `ScorezillaError`, not a plain `Error`. The documented catch\n // pattern in README.md is `if (!(e instanceof ScorezillaError)) throw e;` —\n // a plain `Error` here would escape that guard and bubble up as\n // unhandled. `code: 'internal_error'` is the right category: this is\n // a runtime misconfiguration, not an API failure.\n throw new ScorezillaError(\n 'scorezilla: globalThis.crypto.randomUUID is unavailable. ' +\n 'The SDK requires Node ≥ 20 or a modern browser. Check your runtime.',\n { status: 0, code: 'internal_error' },\n );\n }\n return c.randomUUID();\n}\n\n/**\n * Sleep for `ms` milliseconds. Aborts immediately if the provided\n * `AbortSignal` fires — the returned promise rejects with the signal's\n * `reason` so the transport can map it to {@link ScorezillaError.aborted}.\n *\n * The handler unhooks itself when the timer settles, so a long-lived\n * signal can be reused across many sleeps without leaking listeners.\n */\nexport function sleep(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise((resolve, reject) => {\n if (signal?.aborted) {\n reject(signal.reason ?? new DOMException('Aborted', 'AbortError'));\n return;\n }\n const timer = setTimeout(() => {\n signal?.removeEventListener('abort', onAbort);\n resolve();\n }, ms);\n const onAbort = (): void => {\n clearTimeout(timer);\n signal?.removeEventListener('abort', onAbort);\n reject(signal?.reason ?? new DOMException('Aborted', 'AbortError'));\n };\n signal?.addEventListener('abort', onAbort, { once: true });\n });\n}\n","/**\n * HTTP transport for the Scorezilla SDK.\n *\n * Single entry point — {@link request} — wraps `fetch` with the SDK's\n * cross-cutting concerns:\n * • JSON serialization / parsing\n * • Idempotency-Key on retried POSTs (same key reused across attempts)\n * • Retry loop with exponential backoff + jitter on 5xx / 429 / network\n * • `Retry-After` honored when ≤ {@link MAX_RETRY_AFTER_SEC}\n * • Combined AbortSignal: caller-supplied + per-call timeout budget\n * • Uniform {@link ScorezillaError} for every failure path\n *\n * The function is fully fetch-impl-injectable so it tests cleanly with a\n * stub. No Node-only APIs; runs in browsers, Node, Workers, Bun, Deno.\n */\n\nimport { ScorezillaError } from './errors';\nimport {\n DEFAULT_MAX_RETRIES,\n generateIdempotencyKey,\n nextDelay,\n shouldRetryError,\n shouldRetryStatus,\n sleep,\n} from './retry';\nimport type { ApiError, ApiResponse } from './types';\n\n/** Default per-request timeout budget in milliseconds. */\nexport const DEFAULT_TIMEOUT_MS = 30_000;\n\n/** HTTP methods the SDK issues. */\nexport type HttpMethod = 'GET' | 'POST' | 'DELETE';\n\n/** Minimal fetch shape — broader than `typeof fetch` so polyfills and\n * test stubs (`vi.fn()`, `node-fetch`, etc.) typecheck cleanly. */\nexport type FetchImpl = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;\n\n/** Options for {@link request}. */\nexport interface RequestOptions {\n /** Base URL — typically the API origin, no trailing slash. */\n baseUrl: string;\n /** Path with leading `/` — typically built via the helpers in `src/paths.ts`. */\n path: string;\n /** HTTP method. */\n method: HttpMethod;\n /** Request body to JSON-stringify. `undefined` → no body, no Content-Type. */\n body?: Record<string, unknown> | undefined;\n /** Extra headers to merge on top of the SDK's defaults. The public-key\n * client passes a static `Authorization: Bearer pk_*` here. Leave\n * `Authorization` unset when using `signRequest` — the per-attempt\n * hook owns that header. */\n headers?: Record<string, string> | undefined;\n /** Per-attempt request-signing hook. Called fresh on every fetch attempt\n * (including each retry) with the canonicalized method, path-and-query,\n * and body, returning the `Authorization` header value.\n *\n * This is what the HMAC server adapter uses: each attempt needs a fresh\n * timestamp + nonce, so a static header would burn replay-protection\n * budget. The public-key client doesn't pass this — it uses `headers`\n * with a static Bearer token instead. Mutually exclusive in practice. */\n signRequest?:\n | ((args: { method: HttpMethod; pathAndQuery: string; body: string }) => Promise<string>)\n | undefined;\n /** Injectable fetch — defaults to `globalThis.fetch`. */\n fetchImpl?: FetchImpl | undefined;\n /** Injectable warn sink for deprecation notices. Defaults to\n * `console.warn`. Pass a function to route SDK warnings into your\n * logger of choice, or pass `() => {}` to suppress them entirely.\n * At million-integration scale, embedders shouldn't have to\n * console-filter our deprecation messages.\n *\n * Same signature as `console.warn`. The SDK never calls\n * `warnImpl` for anything other than developer-visible deprecations. */\n warnImpl?: ((...args: unknown[]) => void) | undefined;\n /** Caller-supplied AbortSignal — composed with the SDK's internal timeout signal. */\n signal?: AbortSignal | undefined;\n /** Per-request timeout in milliseconds. Defaults to {@link DEFAULT_TIMEOUT_MS}. */\n timeoutMs?: number | undefined;\n /** Retry policy overrides. */\n retry?:\n | {\n maxRetries?: number | undefined;\n /** Injectable RNG for jitter — used by tests for deterministic delays. */\n random?: (() => number) | undefined;\n /** Injectable sleep — used by tests to advance time without real waits. */\n sleepImpl?: ((ms: number, signal?: AbortSignal) => Promise<void>) | undefined;\n }\n | undefined;\n}\n\n/**\n * Make an HTTP request and return the parsed JSON body on success.\n *\n * Throws {@link ScorezillaError} on:\n * • non-2xx response (with status, code, reason, retryAfter, requestId)\n * • network failure (`code: 'network_error'`)\n * • timeout (`code: 'timeout'`)\n * • abort via caller's signal (`code: 'aborted'`)\n * • response JSON parsing failure (`code: 'invalid_json'`)\n *\n * @typeParam T - the per-route success payload shape — always an\n * `ApiSuccess<X> = { ok: true } & X`. The constraint enforces\n * that `parseJson`'s discriminator check applies to every\n * call site at compile time, with no escape hatch.\n */\nexport async function request<T extends { ok: true }>(opts: RequestOptions): Promise<T> {\n const fetchImpl: FetchImpl = opts.fetchImpl ?? (globalThis.fetch as FetchImpl);\n if (typeof fetchImpl !== 'function') {\n throw new Error(\n 'scorezilla: globalThis.fetch is unavailable. ' +\n 'Either upgrade your runtime (Node ≥ 20 has fetch built in) or pass `fetch: yourFetch` in the SDK config.',\n );\n }\n\n const url = buildUrl(opts.baseUrl, opts.path);\n const maxRetries = opts.retry?.maxRetries ?? DEFAULT_MAX_RETRIES;\n const random = opts.retry?.random ?? Math.random;\n const sleepImpl = opts.retry?.sleepImpl ?? sleep;\n const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {\n throw new Error(\n `scorezilla: timeoutMs must be a positive finite number (got ${String(timeoutMs)})`,\n );\n }\n\n // Wrapped retry sleep — if the caller's signal aborts during the inter-attempt\n // pause, the raw rejection (typically a DOMException) would otherwise leak\n // out of request() unwrapped. Normalize every abort path to a ScorezillaError.\n const retrySleep = async (delay: number): Promise<void> => {\n try {\n await sleepImpl(delay, opts.signal);\n } catch (cause) {\n throw ScorezillaError.aborted(cause);\n }\n };\n\n // Idempotency-Key is generated ONCE per logical request and reused across\n // all retry attempts. This makes server-side dedup (if/when added) safe:\n // the same logical write maps to one key, multiple network attempts.\n // GET / DELETE are already idempotent; no key needed.\n const idempotencyKey = opts.method === 'POST' ? generateIdempotencyKey() : null;\n\n let lastError: unknown;\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n const combined = combineSignalsWithTimeout(opts.signal, timeoutMs);\n\n // Cleanup is structural, not positional: a `try { … } finally { cleanup }`\n // wrapper guarantees the per-attempt signal+timer is detached on EVERY\n // exit path — return, throw, or `continue`. The earlier implementation\n // called `cleanup()` at two positional points (after fetch, in catch);\n // any future early-exit added between them would silently leak listeners\n // and timers on a long-lived caller signal. The current shape is\n // resilient to that class of edit.\n try {\n // Serialize the body ONCE per attempt — both the fetch and the\n // signRequest hook need identical bytes. Re-stringifying inside\n // the signer would be a subtle correctness hazard if Date.now /\n // any non-deterministic field ever crept into body construction.\n const bodyString = opts.body !== undefined ? JSON.stringify(opts.body) : '';\n\n // Headers + Authorization. The HMAC signer (if present) wins —\n // per-attempt fresh signing is the contract for that auth mode.\n // Path-and-query fed to the signer must match what the server\n // will see (`/v1/...?...`), without the baseUrl origin prefix.\n const perAttemptHeaders = { ...(opts.headers ?? {}) };\n if (opts.signRequest) {\n perAttemptHeaders.Authorization = await opts.signRequest({\n method: opts.method,\n pathAndQuery: opts.path,\n body: bodyString,\n });\n }\n const init: RequestInit = {\n method: opts.method,\n headers: buildHeaders({ ...opts, headers: perAttemptHeaders }, idempotencyKey),\n signal: combined.signal,\n };\n if (opts.body !== undefined) {\n init.body = bodyString;\n }\n const response = await fetchImpl(url, init);\n\n if (response.ok) {\n // PR R: surface API-level deprecation signals (RFC 8594 Sunset +\n // IETF draft Deprecation headers). The server emits these when\n // a deprecated request shape is in use. We log a warning\n // exactly once per SDK process per (code-path) to avoid spam.\n warnOnDeprecationOnce(response, opts.warnImpl);\n return await parseJson<T>(response);\n }\n\n // Non-2xx — try to parse the error body for structured fields.\n const body = await safelyParseErrorBody(response);\n const err = ScorezillaError.from({\n status: response.status,\n body,\n requestId: response.headers.get('X-Request-Id') ?? undefined,\n });\n\n if (shouldRetryStatus(response.status) && attempt < maxRetries) {\n const retryAfter = readRetryAfter(response);\n const delay = nextDelay(attempt, retryAfter, random);\n await retrySleep(delay);\n lastError = err;\n continue;\n }\n\n throw err;\n } catch (caught: unknown) {\n // ScorezillaError thrown by our own logic above (already typed) —\n // either retry or rethrow per the retry policy.\n if (caught instanceof ScorezillaError) {\n if (shouldRetryError(caught) && attempt < maxRetries) {\n const delay = nextDelay(attempt, undefined, random);\n await retrySleep(delay);\n lastError = caught;\n continue;\n }\n throw caught;\n }\n\n // Map raw fetch failures to ScorezillaError. `combined.timedOut()`\n // remains queryable after cleanup — the boolean is captured in the\n // closure regardless of timer state — so this works correctly even\n // though the `finally` below has already run by the time we get here.\n const mapped = mapTransportError(caught, opts.signal, timeoutMs, combined);\n if (shouldRetryError(mapped) && attempt < maxRetries) {\n const delay = nextDelay(attempt, undefined, random);\n await retrySleep(delay);\n lastError = mapped;\n continue;\n }\n throw mapped;\n } finally {\n combined.cleanup();\n }\n }\n\n // Unreachable in practice — every loop iteration either returns, throws,\n // or `continue`s. Keep as a typed fallback for the compiler.\n throw (\n lastError ??\n new ScorezillaError('Request failed after retries', {\n status: 0,\n code: 'internal_error',\n })\n );\n}\n\n// ───────────────────────────────────────────────────────────────────────────\n// Helpers\n// ───────────────────────────────────────────────────────────────────────────\n\nfunction buildUrl(baseUrl: string, path: string): string {\n // Trim a single trailing slash from baseUrl so `baseUrl + path` doesn't\n // produce double slashes. Path is expected to start with `/` (enforced by\n // the path-helper functions).\n const base = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl;\n return base + path;\n}\n\nfunction buildHeaders(opts: RequestOptions, idempotencyKey: string | null): Record<string, string> {\n const headers: Record<string, string> = { Accept: 'application/json' };\n if (opts.body !== undefined) {\n headers['Content-Type'] = 'application/json';\n }\n if (idempotencyKey !== null) {\n headers['Idempotency-Key'] = idempotencyKey;\n }\n // Caller-supplied headers (e.g., Authorization) override defaults. The\n // client layer is trusted; this is a public-API style merge, not security.\n if (opts.headers) {\n for (const [k, v] of Object.entries(opts.headers)) headers[k] = v;\n }\n return headers;\n}\n\n/**\n * Parse a successful response body and assert it matches the success envelope.\n *\n * The `T extends { ok: true }` constraint reflects that every API success\n * payload is shaped `ApiSuccess<X> = { ok: true } & X`. Asserting the\n * discriminator at runtime catches a class of silent contract violations:\n * a server-side regression that omits `ok` or returns a non-object on a\n * 2xx would otherwise produce `undefined` on typed-as-required fields far\n * from this fetch site, with no error message that pointed back here.\n *\n * Three distinct failure modes all map to `code: 'invalid_json'`:\n * 1. JSON parse error (malformed body)\n * 2. Non-object body (`null`, array, primitive)\n * 3. Object missing `ok: true` discriminator\n *\n * `'invalid_json'` is documented as a transport-layer code in errors.ts\n * and ScorezillaErrorCode; consumers can `if (e.code === 'invalid_json')`\n * to detect API/SDK contract drift.\n */\nasync function parseJson<T extends { ok: true }>(response: Response): Promise<T> {\n const requestId = response.headers.get('X-Request-Id') ?? undefined;\n\n let parsed: unknown;\n try {\n parsed = await response.json();\n } catch (cause) {\n throw new ScorezillaError('Response body was not valid JSON', {\n status: response.status,\n code: 'invalid_json',\n requestId,\n cause,\n });\n }\n\n if (parsed === null || typeof parsed !== 'object') {\n const observed = parsed === null ? 'null' : typeof parsed;\n throw new ScorezillaError(`Response body was not a JSON object (got ${observed})`, {\n status: response.status,\n code: 'invalid_json',\n requestId,\n });\n }\n\n // The `ok: true` discriminator must be present on a successful response.\n // If it isn't, the server has drifted from the API contract — surface\n // that as a typed error rather than letting the consumer's code crash on\n // `result.rank` being undefined three call frames away.\n const okField = (parsed as { ok?: unknown }).ok;\n if (okField !== true) {\n throw new ScorezillaError(\n `Response body on a 2xx is missing the \\`ok: true\\` discriminator (got ok=${String(okField)})`,\n {\n status: response.status,\n code: 'invalid_json',\n requestId,\n },\n );\n }\n\n return parsed as T;\n}\n\nasync function safelyParseErrorBody(response: Response): Promise<ApiError | undefined> {\n // Error responses may legitimately have empty body (e.g., some 5xx).\n // We try to parse, but a parse failure is non-fatal here — the caller\n // gets a status-derived code via ScorezillaError.from.\n try {\n const json = (await response.json()) as ApiResponse<unknown>;\n if (json && typeof json === 'object' && 'ok' in json && json.ok === false) {\n return json;\n }\n return undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction readRetryAfter(response: Response): number | undefined {\n const raw = response.headers.get('Retry-After');\n if (!raw) return undefined;\n const n = Number(raw);\n return Number.isFinite(n) && n >= 0 ? n : undefined;\n}\n\n/**\n * PR R: emit a once-per-process warning when an API response carries\n * the `Deprecation` header (per IETF draft) or a `Sunset` header\n * (RFC 8594). The dedupe key is the (Deprecation + Sunset + Link)\n * triplet, so different deprecation signals across the SDK lifetime\n * each surface once but the SAME signal across many requests fires\n * once.\n *\n * Quiet by design: this is a developer warning, not a runtime error.\n * Production loops shouldn't see this unless the SDK is genuinely\n * out-of-date.\n */\nconst seenDeprecations = new Set<string>();\nfunction warnOnDeprecationOnce(response: Response, warnImpl?: (...args: unknown[]) => void): void {\n const deprecation = response.headers.get('Deprecation');\n const sunset = response.headers.get('Sunset');\n if (!deprecation && !sunset) return;\n const link = response.headers.get('Link') ?? '';\n const key = `${deprecation ?? ''}|${sunset ?? ''}|${link}`;\n if (seenDeprecations.has(key)) return;\n seenDeprecations.add(key);\n\n const detail: string[] = [];\n if (deprecation === 'true' || deprecation) detail.push(`Deprecation: ${deprecation}`);\n if (sunset) detail.push(`Sunset: ${sunset}`);\n if (link) {\n // Pull the URL out of `<url>; rel=\"deprecation\"` per RFC 8288.\n const m = link.match(/<([^>]+)>/);\n if (m) detail.push(`Docs: ${m[1]}`);\n }\n const message =\n `[scorezilla-sdk] API responded with deprecation signal: ${detail.join(' · ')}. ` +\n `Upgrade your SDK before the sunset date.`;\n // Inject point — embedders can route via warnImpl or suppress with `() => {}`.\n if (warnImpl) {\n warnImpl(message);\n } else {\n // eslint-disable-next-line no-console -- developer-facing warning, intentional\n console.warn(message);\n }\n}\n\n/**\n * Test-only: clear the seen-deprecations dedupe set so unit tests can\n * exercise the warn-once behavior across cases. Not exported from the\n * public entry point; reachable only via the internal transport module\n * from inside the package.\n */\nexport function __resetDeprecationDedupe(): void {\n seenDeprecations.clear();\n}\n\n/**\n * Compose the caller's signal with a fresh timeout signal, returning a\n * single signal to pass to fetch plus a `cleanup` to detach the listeners.\n *\n * Implemented manually (not `AbortSignal.any`) because Safari 17.0–17.3\n * lacks that primitive. The cleanup is essential — without it, a long-lived\n * caller signal accumulates listeners every retry.\n */\nfunction combineSignalsWithTimeout(\n caller: AbortSignal | undefined,\n timeoutMs: number,\n): { signal: AbortSignal; cleanup: () => void; timedOut: () => boolean } {\n const ctrl = new AbortController();\n let didTimeOut = false;\n\n if (caller?.aborted) {\n ctrl.abort(caller.reason);\n return { signal: ctrl.signal, cleanup: () => {}, timedOut: () => false };\n }\n\n const onCallerAbort = (): void => {\n ctrl.abort(caller?.reason);\n };\n caller?.addEventListener('abort', onCallerAbort, { once: true });\n\n const timer = setTimeout(() => {\n didTimeOut = true;\n ctrl.abort(new DOMException(`Request timed out after ${timeoutMs}ms`, 'TimeoutError'));\n }, timeoutMs);\n\n return {\n signal: ctrl.signal,\n cleanup: () => {\n clearTimeout(timer);\n caller?.removeEventListener('abort', onCallerAbort);\n },\n timedOut: () => didTimeOut,\n };\n}\n\nfunction mapTransportError(\n caught: unknown,\n callerSignal: AbortSignal | undefined,\n timeoutMs: number,\n combined: { timedOut: () => boolean },\n): ScorezillaError {\n // If the caller's signal aborted, that wins (most specific).\n if (callerSignal?.aborted) {\n return ScorezillaError.aborted(callerSignal.reason ?? caught);\n }\n // If our internal timeout fired, surface that.\n if (combined.timedOut()) {\n return ScorezillaError.timeout(timeoutMs);\n }\n // Generic fetch-throws-everything path: TypeErrors, DOMExceptions, etc.\n const message = caught instanceof Error ? caught.message : 'Network request failed';\n return ScorezillaError.network(message, caught);\n}\n","/**\n * Runtime detection + `User-Agent` builder.\n *\n * **Privacy invariant:** detection happens via cheap probes on\n * `globalThis` only. The SDK never reads `navigator.userAgent` for\n * fingerprinting — only for the narrow case of distinguishing Cloudflare\n * Workers from a generic worker scope. No other DOM, hardware, or\n * timezone signals are touched. This is documented in COMPATIBILITY.md.\n *\n * Note on browsers: per the Fetch spec, browsers silently ignore the\n * `User-Agent` request header. Setting it has no effect there — but it\n * remains meaningful in Node, Bun, Deno, and Workers, where we want\n * server-side observability of which SDK version + runtime issued each\n * request. The client layer also sends a separate `X-Scorezilla-Client`\n * header that browsers do honor, so we get browser-side telemetry too.\n */\n\n/** Runtimes the SDK explicitly identifies. `unknown` is the fallback when\n * no signature matches (e.g., a new runtime, or one with all the right\n * globals stripped). */\nexport type Runtime = 'browser' | 'node' | 'bun' | 'deno' | 'workers' | 'unknown';\n\ninterface GlobalProbe {\n readonly Bun?: unknown;\n readonly Deno?: unknown;\n readonly process?: { readonly versions?: { readonly node?: string } };\n readonly document?: unknown;\n readonly WorkerGlobalScope?: unknown;\n readonly navigator?: { readonly userAgent?: string };\n}\n\n/**\n * Detect the current runtime by probing well-known globals. Pure function\n * — accepts an optional `g` override so tests can simulate any runtime.\n *\n * Order matters: Bun and Deno expose `process.versions.node`-like shims\n * for compat, so we check their own identifiers first.\n *\n * @example\n * ```ts\n * import { detectRuntime } from 'scorezilla';\n * const runtime = detectRuntime(); // → 'browser' | 'node' | 'bun' | 'deno' | 'workers' | 'unknown'\n * myTelemetry.track('app.start', { sdk_runtime: runtime });\n * ```\n *\n * @since 0.1.0\n * @stability stable\n */\nexport function detectRuntime(g: GlobalProbe = globalThis as GlobalProbe): Runtime {\n if (typeof g.Bun !== 'undefined') return 'bun';\n if (typeof g.Deno !== 'undefined') return 'deno';\n\n // Cloudflare Workers set `navigator.userAgent === 'Cloudflare-Workers'`.\n // Check this BEFORE the generic node check — Workers expose neither\n // `process` nor `document`, so the navigator probe is the unique signal.\n if (\n typeof g.navigator?.userAgent === 'string' &&\n g.navigator.userAgent.includes('Cloudflare-Workers')\n ) {\n return 'workers';\n }\n\n if (typeof g.process?.versions?.node === 'string') return 'node';\n if (typeof g.document !== 'undefined') return 'browser';\n\n return 'unknown';\n}\n\n/**\n * Build the SDK's default `User-Agent` header value.\n *\n * Shape: `scorezilla-js/<version> (<runtime>)`, e.g.\n * `scorezilla-js/0.1.0 (node)`. Version is the build-time-injected\n * `SDK_VERSION` so we don't read package.json at runtime.\n */\nexport function defaultUserAgent(version: string, runtime: Runtime = detectRuntime()): string {\n return `scorezilla-js/${version} (${runtime})`;\n}\n","/**\n * Built-in request verifiers for {@link createScoreSubmitHandler} (#211).\n *\n * These turn the common \"verify a JWT, derive the player id from a claim\"\n * shape into a one-liner. They produce a function with the same signature as\n * the handler's `verify` callback, so they drop straight in:\n *\n * ```ts\n * import { createScoreSubmitHandler, verifySupabaseJwt } from 'scorezilla/server';\n *\n * createScoreSubmitHandler({\n * secretKey, boardId,\n * verify: verifySupabaseJwt({ supabaseUrl: process.env.SUPABASE_URL! }),\n * });\n * ```\n *\n * **`jose` is an optional peer dependency.** Only these verifiers use it, and\n * only via a lazy `import('jose')` — so consumers who use the public-key\n * client, the factory with their own `verify`, or a provider backend SDK never\n * install or load it. If you call a built-in verifier without `jose` present,\n * it throws a clear \"install jose\" error.\n */\nimport type { VerifiedIdentity } from './server';\n\n/** Same shape as the handler's `verify` callback. */\nexport type RequestVerifier = (req: Request) => Promise<VerifiedIdentity | null>;\n\n/** Options for the generic JWKS verifier {@link verifyJwt}. */\nexport interface VerifyJwtOptions {\n /** JWKS endpoint, e.g. `https://issuer/.well-known/jwks.json`. */\n readonly jwksUrl: string | URL;\n /** Expected `iss` claim — strongly recommended. */\n readonly issuer?: string | string[];\n /** Expected `aud` claim — strongly recommended. */\n readonly audience?: string | string[];\n /** Which claim becomes the `playerId`. Default `'sub'`. */\n readonly claim?: string;\n /** Custom `fetch` for retrieving the JWKS (proxy / self-host / testing). */\n readonly fetch?: typeof fetch;\n}\n\n/** Options for the Supabase preset {@link verifySupabaseJwt}. */\nexport interface VerifySupabaseJwtOptions {\n /** Your Supabase project URL, e.g. `https://abcd.supabase.co`. */\n readonly supabaseUrl: string;\n /** Which claim becomes the `playerId`. Default `'sub'`. */\n readonly claim?: string;\n /** Custom `fetch` for retrieving the JWKS (proxy / self-host / testing). */\n readonly fetch?: typeof fetch;\n}\n\ntype JoseModule = typeof import('jose');\n\nasync function loadJose(): Promise<JoseModule> {\n try {\n return await import('jose');\n } catch (cause) {\n throw new Error(\n \"scorezilla/server: the optional peer dependency 'jose' is required for \" +\n 'verifyJwt() / verifySupabaseJwt(). Install it with `npm i jose` ' +\n '(or your package manager).',\n { cause },\n );\n }\n}\n\nfunction extractBearerToken(req: Request): string | null {\n const header = req.headers.get('authorization');\n if (!header) return null;\n const trimmed = header.trim();\n if (!/^bearer\\s+/i.test(trimmed)) return null;\n return trimmed.replace(/^bearer\\s+/i, '').trim() || null;\n}\n\n/**\n * Generic JWKS-backed JWT verifier. Verifies a `Bearer` token against the\n * given JWKS and returns `{ playerId }` from the configured claim (default\n * `sub`), or `null` if there's no token or verification fails.\n *\n * Covers the modern provider majority (Supabase, Clerk, Auth0, Firebase,\n * WorkOS, …) — they differ only by `jwksUrl` / `issuer` / `audience`.\n *\n * @since 0.3.0\n */\nexport function verifyJwt(options: VerifyJwtOptions): RequestVerifier {\n const claim = options.claim ?? 'sub';\n // Lazily built + memoized: the remote key set caches fetched keys and\n // refetches on unknown `kid`, so we create it once per verifier.\n let keySet: ReturnType<JoseModule['createRemoteJWKSet']> | null = null;\n\n return async (req: Request): Promise<VerifiedIdentity | null> => {\n const token = extractBearerToken(req);\n if (token === null) return null;\n\n // A missing `jose` surfaces here (not swallowed as a null/401) so the\n // misconfiguration is debuggable.\n const jose = await loadJose();\n if (keySet === null) {\n keySet = jose.createRemoteJWKSet(\n new URL(options.jwksUrl),\n options.fetch ? { [jose.customFetch]: options.fetch } : undefined,\n );\n }\n\n try {\n const { payload } = await jose.jwtVerify(token, keySet, {\n ...(options.issuer !== undefined ? { issuer: options.issuer } : {}),\n ...(options.audience !== undefined ? { audience: options.audience } : {}),\n });\n const id = payload[claim];\n return typeof id === 'string' && id.length > 0 ? { playerId: id } : null;\n } catch {\n // Bad signature / expired / wrong issuer-audience / unknown kid.\n return null;\n }\n };\n}\n\n/**\n * Supabase preset over {@link verifyJwt}. Verifies a Supabase user JWT via the\n * project's JWKS and derives the `playerId` from `sub`.\n *\n * ```ts\n * verify: verifySupabaseJwt({ supabaseUrl: process.env.SUPABASE_URL! })\n * ```\n *\n * @since 0.3.0\n */\nexport function verifySupabaseJwt(options: VerifySupabaseJwtOptions): RequestVerifier {\n const base = options.supabaseUrl.replace(/\\/+$/, '');\n return verifyJwt({\n jwksUrl: `${base}/auth/v1/.well-known/jwks.json`,\n issuer: `${base}/auth/v1`,\n audience: 'authenticated',\n ...(options.claim !== undefined ? { claim: options.claim } : {}),\n ...(options.fetch !== undefined ? { fetch: options.fetch } : {}),\n });\n}\n\n/** Options for the Clerk preset {@link verifyClerkJwt}. */\nexport interface VerifyClerkJwtOptions {\n /**\n * Your Clerk instance issuer (the token's `iss`), e.g.\n * `https://clerk.your-app.com` or `https://<slug>.clerk.accounts.dev`. The\n * JWKS URL is derived from it.\n */\n readonly issuer: string;\n /**\n * Expected `aud`. Clerk session tokens have **no** `aud` by default, so leave\n * this unset unless you added one via a custom JWT template.\n */\n readonly audience?: string | string[];\n /** Which claim becomes the `playerId`. Default `'sub'` (the Clerk user id). */\n readonly claim?: string;\n /** Custom `fetch` for retrieving the JWKS (proxy / self-host / testing). */\n readonly fetch?: typeof fetch;\n}\n\n/**\n * Clerk preset over {@link verifyJwt}. Verifies a Clerk session JWT against the\n * instance JWKS and derives the `playerId` from `sub` (the Clerk user id).\n *\n * @since 0.3.0\n */\nexport function verifyClerkJwt(options: VerifyClerkJwtOptions): RequestVerifier {\n const issuer = options.issuer.replace(/\\/+$/, '');\n return verifyJwt({\n jwksUrl: `${issuer}/.well-known/jwks.json`,\n issuer,\n ...(options.audience !== undefined ? { audience: options.audience } : {}),\n ...(options.claim !== undefined ? { claim: options.claim } : {}),\n ...(options.fetch !== undefined ? { fetch: options.fetch } : {}),\n });\n}\n\n/** Options for the Auth0 preset {@link verifyAuth0Jwt}. */\nexport interface VerifyAuth0JwtOptions {\n /** Your Auth0 domain, e.g. `your-tenant.us.auth0.com` (scheme optional). */\n readonly domain: string;\n /** Your API identifier — the access token's `aud`. */\n readonly audience: string | string[];\n /** Which claim becomes the `playerId`. Default `'sub'`. */\n readonly claim?: string;\n /** Custom `fetch` for retrieving the JWKS (proxy / self-host / testing). */\n readonly fetch?: typeof fetch;\n}\n\n/**\n * Auth0 preset over {@link verifyJwt}. Note Auth0's issuer carries a trailing\n * slash (`https://<domain>/`) — the preset adds it for you.\n *\n * @since 0.3.0\n */\nexport function verifyAuth0Jwt(options: VerifyAuth0JwtOptions): RequestVerifier {\n const host = options.domain.replace(/^https?:\\/\\//, '').replace(/\\/+$/, '');\n return verifyJwt({\n jwksUrl: `https://${host}/.well-known/jwks.json`,\n issuer: `https://${host}/`,\n audience: options.audience,\n ...(options.claim !== undefined ? { claim: options.claim } : {}),\n ...(options.fetch !== undefined ? { fetch: options.fetch } : {}),\n });\n}\n\n/**\n * JWK-set endpoint for Firebase ID tokens (the `securetoken` system service\n * account). Google publishes a standard JWK set here — no x509 import needed.\n */\nconst FIREBASE_JWKS_URL =\n 'https://www.googleapis.com/service_accounts/v1/jwk/securetoken@system.gserviceaccount.com';\n\n/** Options for the Firebase preset {@link verifyFirebaseIdToken}. */\nexport interface VerifyFirebaseIdTokenOptions {\n /** Your Firebase project id — both the token's `aud` and the issuer suffix. */\n readonly projectId: string;\n /** Which claim becomes the `playerId`. Default `'sub'` (the Firebase uid). */\n readonly claim?: string;\n /** Custom `fetch` for retrieving the JWKS (proxy / self-host / testing). */\n readonly fetch?: typeof fetch;\n}\n\n/**\n * Firebase Authentication preset over {@link verifyJwt}. Verifies a Firebase ID\n * token (`iss = https://securetoken.google.com/<projectId>`, `aud = projectId`)\n * and derives the `playerId` from `sub` (the Firebase uid).\n *\n * @since 0.3.0\n */\nexport function verifyFirebaseIdToken(options: VerifyFirebaseIdTokenOptions): RequestVerifier {\n return verifyJwt({\n jwksUrl: FIREBASE_JWKS_URL,\n issuer: `https://securetoken.google.com/${options.projectId}`,\n audience: options.projectId,\n ...(options.claim !== undefined ? { claim: options.claim } : {}),\n ...(options.fetch !== undefined ? { fetch: options.fetch } : {}),\n });\n}\n","/**\n * `scorezilla/server` — HMAC-signed adapter for game backends (#17, v0.2.0).\n *\n * Why this exists\n * ---------------\n * The default `Scorezilla` from `'scorezilla'` uses a public key\n * (`pk_*`) and is browser-safe. That model is client-authoritative —\n * any player can submit any score from devtools. Fine for casual\n * leaderboards; not fine for anything where the ranking matters.\n *\n * This adapter is the opposite: the game backend signs each request\n * with a secret key (`sk_live_*`). The Scorezilla API verifies the\n * signature server-side. Players can't forge submissions even with\n * full client-side access.\n *\n * Surface parity with the public-key client\n * -----------------------------------------\n * The method shape is intentionally identical — `submitScore`,\n * `getLeaderboard`, `getPlayerRank`, `getWindowAround`. The only\n * difference at the call site is the constructor argument: a single\n * `sk_live_<keyId>_<random>` token replaces the public key (Stripe-\n * style single-token format; the keyId is embedded in the plaintext\n * so consumers manage one value, not two):\n *\n * import { Scorezilla } from 'scorezilla/server';\n * const sz = new Scorezilla({\n * secretKey: process.env.SCOREZILLA_SECRET_KEY!, // sk_live_<keyId>_<random>\n * });\n *\n * Behind the scenes:\n * - `submitScore` posts to `/v1/secure/scores` (different from the\n * public-key submit endpoint, which carries the boardId in the\n * path). The HMAC signing string covers method + path + ts +\n * nonce + sha256(body), so the API verifies before any DO read.\n * - Read methods hit the same `/v1/boards/…/leaderboard` etc.\n * endpoints as the public-key client.\n *\n * Browser hard-stop\n * -----------------\n * The package's exports map routes `\"./server\"` through\n * `src/server-browser-stub.ts` when the bundler honors the `browser`\n * condition, so a browser-side import throws at module evaluation. The\n * secret key MUST NEVER leave the server.\n */\n\nimport { validateSecretKey, DEFAULT_BASE_URL, type SecretKeyConfig } from './config';\nimport { buildHmacAuthHeader } from './hmac';\nimport {\n getLeaderboardPath,\n getPlayerRankPath,\n getWindowAroundPath,\n submitScoreSecurePath,\n} from './paths';\nimport { request, type FetchImpl, type RequestOptions } from './transport';\nimport type {\n ApiSuccess,\n LeaderboardResponse,\n PlayerRankResponse,\n SubmitScoreResponse,\n WindowAroundResponse,\n} from './types';\nimport { defaultUserAgent } from './user-agent';\nimport { ScorezillaError } from './errors';\n\n// ---------------------------------------------------------------------------\n// Public input types\n// ---------------------------------------------------------------------------\n// Intentionally mirror the public-key client's input shapes (see\n// src/client.ts). Kept as a separate set of declarations rather than\n// re-exported to keep the `scorezilla/server` surface self-contained —\n// consumers of this entry point shouldn't need to import from\n// `scorezilla` core to get types.\n\n/** Caller-cancellable common shape — server-side too. */\nexport interface CancellableInput {\n /** Optional `AbortSignal` to cancel mid-flight. The transport composes\n * it with the per-attempt timeout, so aborting always wins. */\n signal?: AbortSignal | undefined;\n}\n\n/** Input for {@link Scorezilla.submitScore}. */\nexport interface SubmitScoreInput extends CancellableInput {\n /** UUID-typed board identifier — issued by the operator dashboard. */\n boardId: string;\n /** Stable per-player identifier (UUID, your account ID, etc.). Avoid PII. */\n playerId: string;\n /** Finite number. Rejected with `out_of_bounds` if outside the board's\n * configured `[minScore, maxScore]` range. */\n score: number;\n /** Optional structured context attached to the submission. ≤ 4 KB JSON. */\n metadata?: Record<string, unknown> | undefined;\n}\n\n/** Input for {@link Scorezilla.getLeaderboard}. */\nexport interface GetLeaderboardInput extends CancellableInput {\n boardId: string;\n /** Number of entries (API caps at 1000; default 100). */\n top?: number | undefined;\n /** Offset into the sorted board (API caps at 1_000_000; default 0). */\n offset?: number | undefined;\n}\n\n/** Input for {@link Scorezilla.getPlayerRank}. */\nexport interface GetPlayerRankInput extends CancellableInput {\n boardId: string;\n playerId: string;\n}\n\n/** Input for {@link Scorezilla.getWindowAround}. */\nexport interface GetWindowAroundInput extends CancellableInput {\n boardId: string;\n playerId: string;\n /** Entries strictly above the player (API caps at 100; default 5). */\n before?: number | undefined;\n /** Entries strictly below the player (API caps at 100; default 5). */\n after?: number | undefined;\n}\n\n// ---------------------------------------------------------------------------\n// The Scorezilla server client\n// ---------------------------------------------------------------------------\n\n/**\n * Server-side, HMAC-signing Scorezilla client.\n *\n * Construct once at process boot with your `sk_live_*` secret and reuse\n * the instance across requests — there's no per-request state in here\n * other than the freshly-generated timestamp + nonce computed inside\n * each HTTP attempt.\n *\n * @example\n * ```ts\n * import { Scorezilla, ScorezillaError } from 'scorezilla/server';\n *\n * const sz = new Scorezilla({\n * secretKey: process.env.SCOREZILLA_SECRET_KEY!, // sk_live_<keyId>_<random>\n * });\n *\n * try {\n * const r = await sz.submitScore({ boardId, playerId, score, metadata });\n * if (r.isPersonalBest) notifyPlayer(r.rank);\n * } catch (e) {\n * if (e instanceof ScorezillaError && e.isRateLimited()) {\n * await delay((e.retryAfter ?? 30) * 1000);\n * } else throw e;\n * }\n * ```\n *\n * @since 0.2.0\n * @stability stable\n */\nexport class Scorezilla {\n /** The package version, injected at build time from `package.json`.\n * Mirrors the static on the public-key client so consumers can log\n * the running SDK build the same way regardless of which surface\n * they imported. */\n static readonly version: string = __SCOREZILLA_SDK_VERSION__;\n\n readonly #keyId: string;\n readonly #secret: string;\n readonly #baseUrl: string;\n /** Host portion of `#baseUrl` (e.g. \"api.scorezilla.dev\"). Captured at\n * construction so every signed request binds to this exact origin —\n * see `buildSigningString` v=2 in `hmac.ts`. */\n readonly #host: string;\n readonly #fetchImpl: FetchImpl | undefined;\n readonly #timeoutMs: number | undefined;\n readonly #maxRetries: number | undefined;\n readonly #sleepImpl: ((ms: number, signal?: AbortSignal) => Promise<void>) | undefined;\n readonly #warnImpl: ((...args: unknown[]) => void) | undefined;\n readonly #userAgent: string;\n\n constructor(config: SecretKeyConfig) {\n // Belt-and-suspenders browser guard. The package's exports map routes\n // `scorezilla/server` to `server-browser-stub.ts` when the bundler\n // honors the `browser` condition — which closes the issue cleanly for\n // modern bundlers (Vite, esbuild, Rollup, Webpack 5 with the right\n // resolve config). But misconfigured older bundlers (Webpack 4 without\n // `resolve.conditionNames`, certain custom Rollup setups) may bundle\n // this file directly into a browser bundle. The secret would leak.\n // Throwing at construction time is a non-negotiable runtime fence\n // against that misconfiguration.\n //\n // Detection has to distinguish a *real browser* from *Node-with-jsdom*\n // (the latter is what vitest's `environment: 'jsdom'` produces — it\n // sets `window` + `document` but is fundamentally a Node process).\n // Strategy: if we have a Node-like host (Node, Bun, Deno, or a\n // Workers runtime with `nodejs_compat`), the secret is safe; otherwise\n // if we see browser globals, refuse to instantiate.\n if (isRealBrowserEnvironment()) {\n throw new Error(\n 'scorezilla/server: this adapter is server-only and must not run in browsers. ' +\n 'Your bundler is shipping `scorezilla/server` into a browser bundle — check that it ' +\n 'honors the `browser` export condition in package.json. Use the public-key client ' +\n \"(`import { Scorezilla } from 'scorezilla'`) from browser code.\",\n );\n }\n\n const resolved = validateSecretKey(config);\n this.#keyId = resolved.keyId;\n this.#secret = resolved.secret;\n this.#baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, '');\n // Derive host once. URL parsing is also a soft validation of baseUrl —\n // a malformed baseUrl (no scheme, etc.) would throw here at boot rather\n // than surface as a confusing \"signature mismatch\" 401 on every request.\n try {\n this.#host = new URL(this.#baseUrl).host;\n } catch {\n throw new Error(\n `scorezilla/server: baseUrl must be a valid absolute URL (got: ${this.#baseUrl})`,\n );\n }\n this.#fetchImpl = config.fetch;\n this.#timeoutMs = config.timeoutMs;\n this.#maxRetries = config.maxRetries;\n this.#sleepImpl = config.sleepImpl;\n this.#warnImpl = config.warn;\n this.#userAgent = config.userAgent ?? defaultUserAgent(Scorezilla.version);\n }\n\n /**\n * Submit a score to a board. Signed end-to-end — the API verifies\n * before any state change.\n *\n * **Behavioral note vs. the public-key client**: the server adapter\n * does NOT perform local `metadata` validation. The public-key\n * client (`scorezilla`) validates size + structure client-side and\n * fails fast; the server adapter relies on the API to reject\n * malformed metadata with `invalid_input`. Trade-off: smaller bundle\n * + simpler server-side logic vs. one extra network round-trip on\n * caller mistakes. If you want fast-fail behavior, validate metadata\n * yourself before calling this method.\n */\n async submitScore(input: SubmitScoreInput): Promise<ApiSuccess<SubmitScoreResponse>> {\n return this.#request<ApiSuccess<SubmitScoreResponse>>({\n path: submitScoreSecurePath(),\n method: 'POST',\n body: {\n boardId: input.boardId,\n playerId: input.playerId,\n score: input.score,\n ...(input.metadata !== undefined ? { metadata: input.metadata } : {}),\n },\n signal: input.signal,\n });\n }\n\n /** Fetch the top-N entries on a board. */\n async getLeaderboard(input: GetLeaderboardInput): Promise<ApiSuccess<LeaderboardResponse>> {\n return this.#request<ApiSuccess<LeaderboardResponse>>({\n path: getLeaderboardPath(input.boardId, {\n ...(input.top !== undefined ? { top: input.top } : {}),\n ...(input.offset !== undefined ? { offset: input.offset } : {}),\n }),\n method: 'GET',\n signal: input.signal,\n });\n }\n\n /** Look up a single player's rank on a board. */\n async getPlayerRank(input: GetPlayerRankInput): Promise<ApiSuccess<PlayerRankResponse>> {\n return this.#request<ApiSuccess<PlayerRankResponse>>({\n path: getPlayerRankPath(input.boardId, input.playerId),\n method: 'GET',\n signal: input.signal,\n });\n }\n\n /** Fetch the slice of entries surrounding a player. */\n async getWindowAround(input: GetWindowAroundInput): Promise<ApiSuccess<WindowAroundResponse>> {\n return this.#request<ApiSuccess<WindowAroundResponse>>({\n path: getWindowAroundPath(input.boardId, input.playerId, {\n ...(input.before !== undefined ? { before: input.before } : {}),\n ...(input.after !== undefined ? { after: input.after } : {}),\n }),\n method: 'GET',\n signal: input.signal,\n });\n }\n\n /**\n * Thin wrapper around `transport.request` that wires the HMAC signer\n * for every attempt. Each retry calls `signRequest` again, producing\n * a fresh `(ts, nonce)` pair — the server's replay protection (10-min\n * KV) requires this.\n */\n async #request<T extends { ok: true }>(\n opts: Pick<RequestOptions, 'path' | 'method' | 'body' | 'signal'>,\n ): Promise<T> {\n const baseHeaders: Record<string, string> = {\n // User-Agent: useful in Node/Bun/Deno/Workers for server observability.\n // (The browser stub blocks this code path from running browser-side.)\n 'User-Agent': this.#userAgent,\n 'X-Scorezilla-Client': this.#userAgent,\n };\n\n const requestOpts: RequestOptions = {\n baseUrl: this.#baseUrl,\n path: opts.path,\n method: opts.method,\n headers: baseHeaders,\n signRequest: async ({ method, pathAndQuery, body }) =>\n buildHmacAuthHeader({\n keyId: this.#keyId,\n secret: this.#secret,\n method,\n pathAndQuery,\n host: this.#host,\n body,\n }),\n };\n if (opts.body !== undefined) requestOpts.body = opts.body;\n if (opts.signal !== undefined) requestOpts.signal = opts.signal;\n if (this.#fetchImpl !== undefined) requestOpts.fetchImpl = this.#fetchImpl;\n if (this.#warnImpl !== undefined) requestOpts.warnImpl = this.#warnImpl;\n if (this.#timeoutMs !== undefined) requestOpts.timeoutMs = this.#timeoutMs;\n if (this.#maxRetries !== undefined || this.#sleepImpl !== undefined) {\n requestOpts.retry = {\n ...(this.#maxRetries !== undefined ? { maxRetries: this.#maxRetries } : {}),\n ...(this.#sleepImpl !== undefined ? { sleepImpl: this.#sleepImpl } : {}),\n };\n }\n\n return request<T>(requestOpts);\n }\n}\n\n/**\n * Distinguish a real browser from a Node-with-jsdom test environment.\n *\n * Browser globals (`window`, `document`) appear in both contexts. The\n * differentiator is the presence of a recognizable server runtime:\n * - Node + Bun: `process.versions.node`\n * - Cloudflare Workers\n * w/ nodejs_compat: `process.versions.node` too\n * - Deno: `globalThis.Deno`\n *\n * `globalThis.EdgeRuntime` is intentionally NOT on the trust list. It's\n * a Vercel-Edge convention that can be polyfilled by browser extensions\n * or bundler misconfiguration; trusting it would let an adversarial\n * page bypass the runtime guard by setting `globalThis.EdgeRuntime =\n * 'edge'`. The package's `exports.browser` condition remains the\n * primary gate against browser loading; this runtime check is\n * defense-in-depth and should err on the side of REFUSING.\n *\n * Real Vercel Edge code typically lacks `window` and `document` so it\n * never reaches the disqualifier branch — no false positive.\n *\n * If ANY trusted server runtime is detected we trust the caller.\n * Otherwise, if browser globals exist, refuse.\n */\nfunction isRealBrowserEnvironment(): boolean {\n const g = globalThis as {\n window?: unknown;\n document?: unknown;\n Deno?: unknown;\n Bun?: unknown;\n process?: { versions?: { node?: string } };\n };\n const hasBrowserGlobals = typeof g.window !== 'undefined' && typeof g.document !== 'undefined';\n if (!hasBrowserGlobals) return false;\n const hasNodeLikeHost =\n Boolean(g.process?.versions?.node) ||\n typeof g.Deno !== 'undefined' ||\n typeof g.Bun !== 'undefined';\n return !hasNodeLikeHost;\n}\n\n// ---------------------------------------------------------------------------\n// createScoreSubmitHandler — turnkey secure-submit endpoint (#211)\n// ---------------------------------------------------------------------------\n\n/** A value or a promise of it. */\ntype Awaitable<T> = T | Promise<T>;\n\n/**\n * The trusted identity produced by your `verify` callback. `playerId` is what\n * gets submitted — derived from the *verified* request, never the request body.\n */\nexport interface VerifiedIdentity {\n /** Stable, trusted per-player id (e.g. your auth user id). Avoid PII. */\n readonly playerId: string;\n /** Optional trusted metadata merged into the submission (wins over the body). */\n readonly metadata?: Record<string, unknown> | undefined;\n}\n\n/** The score payload extracted from the request body. */\nexport interface ParsedScoreSubmission {\n readonly score: number;\n readonly metadata?: Record<string, unknown> | undefined;\n}\n\n/** Decision returned by an optional pre-verify rate-limit gate. */\nexport interface RateLimitDecision {\n readonly ok: boolean;\n readonly retryAfterSeconds?: number | undefined;\n}\n\n/** CORS config for the handler. Omit entirely for same-origin endpoints. */\nexport interface ScoreSubmitCorsOptions {\n /**\n * Allowed origin(s): an exact string, an array of strings, a predicate, or\n * `true` to reflect any `Origin`. `false` disables reflection.\n */\n readonly origin: string | readonly string[] | boolean | ((origin: string | null) => boolean);\n /** Methods for the preflight. Default `['POST', 'OPTIONS']`. */\n readonly methods?: readonly string[];\n /** Request headers for the preflight. Default `['content-type', 'authorization']`. */\n readonly headers?: readonly string[];\n /** `Access-Control-Max-Age` seconds. Default `600`. */\n readonly maxAgeSeconds?: number;\n}\n\n/** Configuration for {@link createScoreSubmitHandler}. */\nexport interface CreateScoreSubmitHandlerConfig {\n /** Your `sk_live_*` secret. Server-only — never ship to a browser. */\n readonly secretKey: string;\n /** The board UUID this handler submits to. */\n readonly boardId: string;\n /**\n * Authenticate the request and return the **trusted** `playerId` (and any\n * trusted metadata). Return `null` to reject (→ 401); throwing also rejects.\n * Read identity from headers/cookies — the request **body** is reserved for\n * the score payload (see `parseSubmission`). This callback is the universal\n * seam: wire any auth (provider SDK, JWT verify, DB session lookup) here.\n */\n readonly verify: (req: Request) => Awaitable<VerifiedIdentity | null>;\n /**\n * Extract the score (+ optional client metadata) from the request. Defaults\n * to JSON `{ score: number, metadata?: object }`. Return `null` (or throw)\n * to reject as a bad request (→ 400). Note: a `playerId` in the body is\n * always ignored — identity comes only from `verify`.\n */\n readonly parseSubmission?: (req: Request) => Awaitable<ParsedScoreSubmission | null>;\n /**\n * Optional gate that runs **before** `verify` (cheap defense — e.g. a per-IP\n * rate limit, so unauthenticated spam can't drive auth/crypto work). Return\n * `{ ok: false }` to reject with 429. Per-user limits belong inside `verify`.\n */\n readonly rateLimit?: (req: Request) => Awaitable<RateLimitDecision>;\n /** Optional CORS handling (OPTIONS preflight + reflected `Access-Control-Allow-Origin`). */\n readonly cors?: ScoreSubmitCorsOptions;\n /** Override the API base URL (self-host / testing). */\n readonly baseUrl?: string;\n /** Inject a `fetch` (testing / custom transport). */\n readonly fetch?: FetchImpl;\n /** Max transport retries (default SDK policy). Set `0` to disable. */\n readonly maxRetries?: number;\n /** Per-attempt timeout in ms. */\n readonly timeoutMs?: number;\n}\n\n/** The web-standard request handler returned by {@link createScoreSubmitHandler}. */\nexport type ScoreSubmitHandler = (req: Request) => Promise<Response>;\n\n/**\n * Build a turnkey, framework-agnostic secure score-submit endpoint.\n *\n * Returns a standard `(Request) => Promise<Response>` handler — drop it into a\n * Cloudflare Worker, a Next.js route handler, Hono, Deno, Bun, or any runtime\n * that speaks web `Request`/`Response`. You supply only what's app-specific:\n * the `secretKey`, the `boardId`, and a `verify` callback that proves identity\n * and returns the trusted `playerId`. The handler owns parsing/validation, the\n * \"playerId comes from `verify`, never the body\" guarantee, signing via the\n * HMAC server client, and error → HTTP mapping.\n *\n * **Construction patterns.** In Node/Next, secrets are in `process.env`, so\n * build the handler once at module scope. In Cloudflare Workers, secrets live\n * on the per-request `env` binding, so build it inside `fetch` (closing over\n * `env`) — the construction is cheap (no I/O).\n *\n * @example Cloudflare Worker\n * ```ts\n * import { createScoreSubmitHandler } from 'scorezilla/server';\n *\n * export default {\n * fetch(req, env) {\n * const handler = createScoreSubmitHandler({\n * secretKey: env.SCOREZILLA_SECRET_KEY,\n * boardId: env.SCOREZILLA_BOARD_ID,\n * verify: async (r) => {\n * const user = await verifyMyAuth(r, env); // your auth: SDK / JWT / DB\n * return user ? { playerId: user.id } : null;\n * },\n * cors: { origin: 'https://mygame.example' },\n * });\n * return handler(req);\n * },\n * };\n * ```\n *\n * @since 0.3.0\n * @stability stable\n */\nexport function createScoreSubmitHandler(\n config: CreateScoreSubmitHandlerConfig,\n): ScoreSubmitHandler {\n // Construct the signing client once; reuse across requests.\n const sz = new Scorezilla({\n secretKey: config.secretKey,\n ...(config.baseUrl !== undefined ? { baseUrl: config.baseUrl } : {}),\n ...(config.fetch !== undefined ? { fetch: config.fetch } : {}),\n ...(config.maxRetries !== undefined ? { maxRetries: config.maxRetries } : {}),\n ...(config.timeoutMs !== undefined ? { timeoutMs: config.timeoutMs } : {}),\n });\n const parse = config.parseSubmission ?? defaultParseSubmission;\n\n return async (req: Request): Promise<Response> => {\n const cors = config.cors ? buildCorsHeaders(config.cors, req.headers.get('Origin')) : {};\n\n if (req.method === 'OPTIONS' && config.cors) {\n return new Response(null, { status: 204, headers: cors });\n }\n if (req.method !== 'POST') {\n return jsonResponse({ ok: false, error: 'method_not_allowed' }, 405, cors);\n }\n\n if (config.rateLimit) {\n const decision = await config.rateLimit(req);\n if (!decision.ok) {\n const headers = { ...cors };\n if (decision.retryAfterSeconds !== undefined) {\n headers['Retry-After'] = String(decision.retryAfterSeconds);\n }\n return jsonResponse({ ok: false, error: 'rate_limited' }, 429, headers);\n }\n }\n\n let identity: VerifiedIdentity | null;\n try {\n identity = await config.verify(req);\n } catch {\n // A throwing verify is treated as a rejection — it should catch its own\n // errors. We never surface its message (it may carry token internals).\n identity = null;\n }\n if (!identity || typeof identity.playerId !== 'string' || identity.playerId.length === 0) {\n return jsonResponse({ ok: false, error: 'unauthorized' }, 401, cors);\n }\n\n let submission: ParsedScoreSubmission | null;\n try {\n submission = await parse(req);\n } catch {\n submission = null;\n }\n if (!submission || typeof submission.score !== 'number' || !Number.isFinite(submission.score)) {\n return jsonResponse(\n { ok: false, error: 'bad_request', message: 'invalid score submission' },\n 400,\n cors,\n );\n }\n\n const metadata = mergeMetadata(submission.metadata, identity.metadata);\n\n try {\n const result = await sz.submitScore({\n boardId: config.boardId,\n playerId: identity.playerId,\n score: submission.score,\n ...(metadata !== undefined ? { metadata } : {}),\n });\n return jsonResponse(\n {\n ok: true,\n rank: result.rank,\n totalEntries: result.totalEntries,\n isPersonalBest: result.isPersonalBest,\n },\n 200,\n cors,\n );\n } catch (err: unknown) {\n return mapSubmitError(err, cors);\n }\n };\n}\n\nasync function defaultParseSubmission(req: Request): Promise<ParsedScoreSubmission | null> {\n const raw: unknown = await req.json().catch(() => null);\n if (!isPlainObject(raw)) return null;\n const score = raw.score;\n if (typeof score !== 'number' || !Number.isFinite(score)) return null;\n return { score, metadata: isPlainObject(raw.metadata) ? raw.metadata : undefined };\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction mergeMetadata(\n client: Record<string, unknown> | undefined,\n verified: Record<string, unknown> | undefined,\n): Record<string, unknown> | undefined {\n if (!client && !verified) return undefined;\n // Verified (trusted) values win over client-supplied ones on conflict.\n return { ...(client ?? {}), ...(verified ?? {}) };\n}\n\nfunction jsonResponse(body: unknown, status: number, extra: Record<string, string>): Response {\n return new Response(JSON.stringify(body), {\n status,\n headers: { 'Content-Type': 'application/json; charset=utf-8', ...extra },\n });\n}\n\nfunction mapSubmitError(err: unknown, cors: Record<string, string>): Response {\n if (err instanceof ScorezillaError) {\n if (err.isRateLimited()) {\n const headers = { ...cors };\n if (err.retryAfter !== undefined) headers['Retry-After'] = String(err.retryAfter);\n return jsonResponse({ ok: false, error: 'rate_limited' }, 429, headers);\n }\n // Echo genuine client errors (e.g. out_of_bounds, invalid_input); treat\n // everything else (5xx, network) as an upstream failure.\n if (err.status >= 400 && err.status < 500) {\n return jsonResponse({ ok: false, error: err.code, message: err.message }, err.status, cors);\n }\n return jsonResponse({ ok: false, error: 'upstream_error' }, 502, cors);\n }\n return jsonResponse({ ok: false, error: 'server_error' }, 500, cors);\n}\n\nfunction buildCorsHeaders(\n cors: ScoreSubmitCorsOptions,\n origin: string | null,\n): Record<string, string> {\n const headers: Record<string, string> = {\n 'Access-Control-Allow-Methods': (cors.methods ?? ['POST', 'OPTIONS']).join(', '),\n 'Access-Control-Allow-Headers': (cors.headers ?? ['content-type', 'authorization']).join(', '),\n 'Access-Control-Max-Age': String(cors.maxAgeSeconds ?? 600),\n Vary: 'Origin',\n };\n if (origin !== null && isCorsOriginAllowed(cors.origin, origin)) {\n headers['Access-Control-Allow-Origin'] = origin;\n }\n return headers;\n}\n\nfunction isCorsOriginAllowed(rule: ScoreSubmitCorsOptions['origin'], origin: string): boolean {\n if (typeof rule === 'boolean') return rule;\n if (typeof rule === 'string') return rule === origin;\n if (typeof rule === 'function') return rule(origin);\n return rule.includes(origin);\n}\n\n// Mirror the public-key client's pattern: re-export error + response\n// types so consumers of `'scorezilla/server'` get everything they need\n// for typed catch blocks without a second import from the core package.\nexport { ScorezillaError } from './errors';\nexport type {\n ApiSuccess,\n LeaderboardResponse,\n PlayerRankResponse,\n RankedEntry,\n ScorezillaErrorCode,\n SubmitScoreResponse,\n WindowAroundResponse,\n} from './types';\n\n// Built-in `verify` helpers for createScoreSubmitHandler (#211). `jose` is an\n// optional peer dependency, loaded lazily — only consumers of these pay for it.\nexport {\n verifyJwt,\n verifySupabaseJwt,\n verifyClerkJwt,\n verifyAuth0Jwt,\n verifyFirebaseIdToken,\n} from './verifiers';\nexport type {\n RequestVerifier,\n VerifyJwtOptions,\n VerifySupabaseJwtOptions,\n VerifyClerkJwtOptions,\n VerifyAuth0JwtOptions,\n VerifyFirebaseIdTokenOptions,\n} from './verifiers';\n"]}
1
+ {"version":3,"sources":["../src/config.ts","../src/hmac.ts","../src/paths.ts","../src/errors.ts","../src/retry.ts","../src/transport.ts","../src/user-agent.ts","../src/verifiers.ts","../src/github-oauth.ts","../src/server.ts"],"names":[],"mappings":";AAiBO,IAAM,gBAAA,GAAmB,4BAAA;AAQzB,IAAM,iBAAA,GAAoB,UAAA;AA6J1B,IAAM,kBAAA,GACX,uFAAA;AAcK,SAAS,kBAAkB,GAAA,EAAyD;AACzF,EAAA,IAAI,CAAC,GAAA,IAAO,OAAO,GAAA,KAAQ,QAAA,EAAU;AACnC,IAAA,MAAM,IAAI,MAAM,oEAAoE,CAAA;AAAA,EACtF;AACA,EAAA,MAAM,KAAK,GAAA,CAAI,SAAA;AACf,EAAA,IAAI,OAAO,OAAO,QAAA,EAAU;AAC1B,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,CAAA,kEAAA,EAAqE,iBAAiB,CAAA,uBAAA,EAA0B,OAAO,EAAE,CAAA,CAAA;AAAA,KAC3H;AAAA,EACF;AACA,EAAA,MAAM,KAAA,GAAQ,kBAAA,CAAmB,IAAA,CAAK,EAAE,CAAA;AACxC,EAAA,IAAI,CAAC,KAAA,EAAO;AAGV,IAAA,MAAM,KAAA,GAAQ,CAAA,iBAAA,EAAoB,EAAA,CAAG,MAAM,CAAA,CAAA;AAC3C,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,CAAA,wCAAA,EAA2C,kBAAA,CAAmB,QAAA,EAAU,UAC7D,KAAK,CAAA,uIAAA;AAAA,KAElB;AAAA,EACF;AACA,EAAA,OAAO,EAAE,KAAA,EAAO,KAAA,CAAM,CAAC,CAAA,EAAI,QAAQ,EAAA,EAAG;AACxC;;;ACjMA,IAAM,GAAA,GAAM,IAAI,WAAA,EAAY;AAGrB,IAAM,gBAAA,GAAmB,wBAAA;AAShC,IAAM,gBAAA,GAAmB,EAAA;AAKlB,IAAM,2BAAA,GAA8B,CAAA;AAoB3C,eAAsB,kBAAA,CACpB,QACA,YAAA,EACA,EAAA,EACA,OACA,IAAA,EACA,IAAA,EACA,UAAkB,2BAAA,EACD;AACjB,EAAA,MAAM,QAAA,GAAW,MAAM,SAAA,CAAU,IAAI,CAAA;AACrC,EAAA,MAAM,WAAA,GAAc,OAAO,WAAA,EAAY;AACvC,EAAA,IAAI,YAAY,CAAA,EAAG;AACjB,IAAA,OAAO,GAAG,EAAE;AAAA,EAAK,KAAK;AAAA,EAAK,WAAW;AAAA,EAAK,YAAY;AAAA,EAAK,QAAQ,CAAA,CAAA;AAAA,EACtE;AACA,EAAA,OAAO,GAAG,EAAE;AAAA,EAAK,KAAK;AAAA,EAAK,WAAW;AAAA,EAAK,IAAA,CAAK,aAAa;AAAA,EAAK,YAAY;AAAA,EAAK,QAAQ,CAAA,CAAA;AAC7F;AAGA,eAAsB,cAAA,CAAe,QAAgB,OAAA,EAAkC;AACrF,EAAA,MAAM,GAAA,GAAM,MAAM,MAAA,CAAO,MAAA,CAAO,SAAA;AAAA,IAC9B,KAAA;AAAA,IACA,GAAA,CAAI,OAAO,MAAM,CAAA;AAAA,IACjB,EAAE,IAAA,EAAM,MAAA,EAAQ,IAAA,EAAM,SAAA,EAAU;AAAA,IAChC,KAAA;AAAA,IACA,CAAC,MAAM;AAAA,GACT;AACA,EAAA,MAAM,GAAA,GAAM,MAAM,MAAA,CAAO,MAAA,CAAO,IAAA,CAAK,QAAQ,GAAA,EAAK,GAAA,CAAI,MAAA,CAAO,OAAO,CAAC,CAAA;AACrE,EAAA,OAAO,eAAA,CAAgB,IAAI,UAAA,CAAW,GAAG,CAAC,CAAA;AAC5C;AAIA,eAAsB,UAAU,OAAA,EAAkC;AAChE,EAAA,MAAM,MAAA,GAAS,MAAM,MAAA,CAAO,MAAA,CAAO,OAAO,SAAA,EAAW,GAAA,CAAI,MAAA,CAAO,OAAO,CAAC,CAAA;AACxE,EAAA,OAAO,KAAA,CAAM,KAAK,IAAI,UAAA,CAAW,MAAM,CAAC,CAAA,CACrC,IAAI,CAAC,CAAA,KAAM,EAAE,QAAA,CAAS,EAAE,EAAE,QAAA,CAAS,CAAA,EAAG,GAAG,CAAC,CAAA,CAC1C,KAAK,EAAE,CAAA;AACZ;AAgBA,eAAsB,oBAAoB,IAAA,EAiBtB;AAClB,EAAA,MAAM,EAAA,GAAK,KAAK,UAAA,IAAc,IAAA,CAAK,MAAM,IAAA,CAAK,GAAA,KAAQ,GAAI,CAAA;AAO1D,EAAA,IAAI,IAAA,CAAK,UAAU,MAAA,EAAW;AAC5B,IAAA,IAAI,OAAO,IAAA,CAAK,KAAA,KAAU,YAAY,IAAA,CAAK,KAAA,CAAM,SAAS,gBAAA,EAAkB;AAC1E,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,kDAAkD,gBAAgB,CAAA,8FAAA;AAAA,OAEpE;AAAA,IACF;AAAA,EACF;AACA,EAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,KAAA,IAAS,aAAA,EAAc;AAC1C,EAAA,MAAM,OAAA,GAAU,KAAK,OAAA,IAAW,2BAAA;AAChC,EAAA,MAAM,gBAAgB,MAAM,kBAAA;AAAA,IAC1B,IAAA,CAAK,MAAA;AAAA,IACL,IAAA,CAAK,YAAA;AAAA,IACL,EAAA;AAAA,IACA,KAAA;AAAA,IACA,IAAA,CAAK,IAAA;AAAA,IACL,IAAA,CAAK,IAAA;AAAA,IACL;AAAA,GACF;AACA,EAAA,MAAM,SAAA,GAAY,MAAM,cAAA,CAAe,IAAA,CAAK,QAAQ,aAAa,CAAA;AAIjE,EAAA,MAAM,MAAA,GAAS,OAAA,KAAY,CAAA,GAAI,EAAA,GAAK,OAAO,OAAO,CAAA,CAAA;AAClD,EAAA,OAAO,CAAA,EAAG,gBAAgB,CAAA,OAAA,EAAU,IAAA,CAAK,KAAK,CAAA,KAAA,EAAQ,EAAE,CAAA,QAAA,EAAW,KAAK,CAAA,YAAA,EAAe,SAAS,CAAA,EAAG,MAAM,CAAA,CAAA;AAC3G;AAQO,SAAS,aAAA,GAAwB;AACtC,EAAA,MAAM,IAAK,UAAA,CAA0D,MAAA;AACrE,EAAA,IAAI,CAAC,CAAA,IAAK,OAAO,CAAA,CAAE,eAAe,UAAA,EAAY;AAG5C,IAAA,MAAM,IAAI,KAAA;AAAA,MACR;AAAA,KAEF;AAAA,EACF;AACA,EAAA,OAAO,EAAE,UAAA,EAAW;AACtB;AAGO,SAAS,gBAAgB,KAAA,EAA2B;AACzD,EAAA,IAAI,GAAA,GAAM,EAAA;AACV,EAAA,KAAA,MAAW,CAAA,IAAK,KAAA,EAAO,GAAA,IAAO,MAAA,CAAO,aAAa,CAAC,CAAA;AACnD,EAAA,OAAO,IAAA,CAAK,GAAG,CAAA,CAAE,OAAA,CAAQ,KAAA,EAAO,GAAG,CAAA,CAAE,OAAA,CAAQ,KAAA,EAAO,GAAG,CAAA,CAAE,OAAA,CAAQ,OAAO,EAAE,CAAA;AAC5E;;;AC7KA,SAAS,aAAA,CAAc,OAAgB,KAAA,EAAkD;AACvF,EAAA,IAAI,OAAO,KAAA,KAAU,QAAA,IAAY,KAAA,CAAM,WAAW,CAAA,EAAG;AACnD,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,YAAA,EAAe,KAAK,CAAA,2BAAA,CAA6B,CAAA;AAAA,EACnE;AACA,EAAA,OAAO,mBAAmB,KAAK,CAAA;AACjC;AAEA,SAAS,iBAAiB,MAAA,EAAoD;AAC5E,EAAA,MAAM,GAAA,GAAM,IAAI,eAAA,EAAgB;AAChC,EAAA,KAAA,MAAW,CAAC,CAAA,EAAG,CAAC,KAAK,MAAA,CAAO,OAAA,CAAQ,MAAM,CAAA,EAAG;AAC3C,IAAA,IAAI,MAAM,MAAA,EAAW,GAAA,CAAI,IAAI,CAAA,EAAG,MAAA,CAAO,CAAC,CAAC,CAAA;AAAA,EAC3C;AACA,EAAA,MAAM,EAAA,GAAK,IAAI,QAAA,EAAS;AACxB,EAAA,OAAO,EAAA,CAAG,MAAA,GAAS,CAAA,GAAI,CAAA,CAAA,EAAI,EAAE,CAAA,CAAA,GAAK,EAAA;AACpC;AAYO,SAAS,qBAAA,GAAgC;AAC9C,EAAA,OAAO,mBAAA;AACT;AAWO,SAAS,kBAAA,CAAmB,SAAiB,CAAA,EAA8B;AAChF,EAAA,OACE,CAAA,WAAA,EAAc,aAAA,CAAc,OAAA,EAAS,SAAS,CAAC,CAAA,YAAA,CAAA,GAC/C,gBAAA,CAAiB,EAAE,GAAA,EAAK,CAAA,EAAG,GAAA,EAAK,MAAA,EAAQ,CAAA,EAAG,QAAQ,CAAA;AAEvD;AAGO,SAAS,iBAAA,CAAkB,SAAiB,QAAA,EAA0B;AAC3E,EAAA,OAAO,CAAA,WAAA,EAAc,cAAc,OAAA,EAAS,SAAS,CAAC,CAAA,SAAA,EAAY,aAAA,CAAc,QAAA,EAAU,UAAU,CAAC,CAAA,KAAA,CAAA;AACvG;AAWO,SAAS,mBAAA,CACd,OAAA,EACA,QAAA,EACA,CAAA,EACQ;AACR,EAAA,OACE,cAAc,aAAA,CAAc,OAAA,EAAS,SAAS,CAAC,CAAA,SAAA,EAAY,cAAc,QAAA,EAAU,UAAU,CAAC,CAAA,OAAA,CAAA,GAC9F,gBAAA,CAAiB,EAAE,MAAA,EAAQ,CAAA,EAAG,QAAQ,KAAA,EAAO,CAAA,EAAG,OAAO,CAAA;AAE3D;;;AC7DO,IAAM,iBAAA,GAAoB,GAAA;AAG1B,IAAM,iBAAA,GAAoB,oBAAA;AAG1B,IAAM,oBAAA,GAAuB,CAAA;AAEpC,SAAS,gBAAgB,GAAA,EAAsB;AAC7C,EAAA,IAAI,OAAO,GAAA,KAAQ,QAAA,EAAU,OAAO,EAAA;AACpC,EAAA,IAAI,GAAA,CAAI,MAAA,IAAU,iBAAA,EAAmB,OAAO,GAAA;AAK5C,EAAA,MAAM,WAAW,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,iBAAA,GAAoB,kBAAkB,MAAM,CAAA;AACzE,EAAA,OAAO,GAAA,CAAI,KAAA,CAAM,CAAA,EAAG,QAAQ,CAAA,GAAI,iBAAA;AAClC;AAYA,SAAS,cAAc,GAAA,EAAkC;AACvD,EAAA,IAAI,OAAO,GAAA,KAAQ,QAAA,EAAU,OAAO,MAAA;AACpC,EAAA,IAAI,GAAA,CAAI,MAAA,IAAU,iBAAA,EAAmB,OAAO,GAAA;AAC5C,EAAA,MAAM,WAAW,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,iBAAA,GAAoB,kBAAkB,MAAM,CAAA;AACzE,EAAA,OAAO,GAAA,CAAI,KAAA,CAAM,CAAA,EAAG,QAAQ,CAAA,GAAI,iBAAA;AAClC;AAkDO,IAAM,eAAA,GAAN,MAAM,gBAAA,SAAwB,KAAA,CAAM;AAAA;AAAA;AAAA,EAGhC,MAAA;AAAA;AAAA;AAAA;AAAA,EAKA,IAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAA;AAAA;AAAA;AAAA,EAIA,UAAA;AAAA;AAAA;AAAA,EAIA,SAAA;AAAA;AAAA,EAGA,KAAA;AAAA;AAAA,EAGA,KAAA;AAAA;AAAA,EAGA,IAAA;AAAA;AAAA;AAAA,EAIA,GAAA;AAAA;AAAA;AAAA,EAIA,KAAA;AAAA;AAAA;AAAA,EAIA,MAAA;AAAA;AAAA;AAAA,EAIA,QAAA;AAAA;AAAA;AAAA;AAAA,EAKS,KAAA;AAAA,EAElB,WAAA,CACE,SACA,IAAA,EAeA;AACA,IAAA,KAAA,CAAM,eAAA,CAAgB,OAAO,CAAC,CAAA;AAC9B,IAAA,IAAA,CAAK,IAAA,GAAO,iBAAA;AACZ,IAAA,IAAA,CAAK,SAAS,IAAA,CAAK,MAAA;AACnB,IAAA,IAAA,CAAK,OAAO,IAAA,CAAK,IAAA;AAOjB,IAAA,IAAA,CAAK,MAAA,GAAS,aAAA,CAAc,IAAA,CAAK,MAAM,CAAA;AACvC,IAAA,IAAA,CAAK,aAAa,IAAA,CAAK,UAAA;AACvB,IAAA,IAAA,CAAK,SAAA,GAAY,aAAA,CAAc,IAAA,CAAK,SAAS,CAAA;AAC7C,IAAA,IAAA,CAAK,QAAQ,IAAA,CAAK,KAAA;AAClB,IAAA,IAAA,CAAK,KAAA,GAAQ,aAAA,CAAc,IAAA,CAAK,KAAK,CAAA;AAIrC,IAAA,IAAA,CAAK,IAAA,GAAO,aAAA,CAAc,IAAA,CAAK,IAAI,CAAA;AACnC,IAAA,IAAA,CAAK,MAAM,IAAA,CAAK,GAAA;AAChB,IAAA,IAAA,CAAK,QAAQ,IAAA,CAAK,KAAA;AAClB,IAAA,IAAA,CAAK,MAAA,GAAS,aAAA,CAAc,IAAA,CAAK,MAAM,CAAA;AACvC,IAAA,IAAA,CAAK,QAAA,GAAW,aAAA,CAAc,IAAA,CAAK,QAAQ,CAAA;AAC3C,IAAA,IAAA,CAAK,QAAQ,IAAA,CAAK,KAAA;AAOlB,IAAA,MAAA,CAAO,cAAA,CAAe,IAAA,EAAM,gBAAA,CAAgB,SAAS,CAAA;AAIrD,IAAA,IACE,OAAQ,KAAA,CAAqD,iBAAA,KAAsB,UAAA,EACnF;AACA,MACE,KAAA,CAGA,iBAAA,CAAkB,IAAA,EAAM,gBAAe,CAAA;AAAA,IAC3C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,aAAA,GAAyB;AACvB,IAAA,OAAO,KAAK,IAAA,KAAS,cAAA;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,kBAAA,GAA8B;AAC5B,IAAA,OAAO,KAAK,IAAA,KAAS,oBAAA;AAAA,EACvB;AAAA;AAAA,EAGA,WAAA,GAAuB;AACrB,IAAA,OAAO,IAAA,CAAK,IAAA,KAAS,oBAAA,IAAwB,IAAA,CAAK,MAAA,KAAW,WAAA;AAAA,EAC/D;AAAA;AAAA,EAGA,MAAA,GAAkB;AAChB,IAAA,OAAO,IAAA,CAAK,IAAA,KAAS,cAAA,IAAkB,IAAA,CAAK,IAAA,KAAS,WAAA;AAAA,EACvD;AAAA;AAAA,EAGA,UAAA,GAAsB;AACpB,IAAA,OAAO,KAAK,IAAA,KAAS,WAAA;AAAA,EACvB;AAAA;AAAA,EAGA,aAAA,GAAyB;AACvB,IAAA,OAAO,KAAK,IAAA,KAAS,eAAA;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,WAAA,GAAuB;AACrB,IAAA,IAAI,IAAA,CAAK,IAAA,KAAS,eAAA,EAAiB,OAAO,IAAA;AAC1C,IAAA,IAAI,KAAK,MAAA,IAAU,GAAA,IAAO,IAAA,CAAK,MAAA,GAAS,KAAK,OAAO,IAAA;AACpD,IAAA,OAAO,KAAK,aAAA,EAAc;AAAA,EAC5B;AAAA;AAAA;AAAA,EAIA,UAAA,GAAsB;AACpB,IAAA,OAAO,KAAK,IAAA,KAAS,UAAA;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,OAAO,KAAK,IAAA,EAAgD;AAC1D,IAAA,MAAM,EAAE,MAAA,EAAQ,IAAA,EAAM,SAAA,EAAW,OAAM,GAAI,IAAA;AAK3C,IAAA,IAAI,QAAQ,IAAA,CAAK,EAAA,KAAO,SAAS,OAAO,IAAA,CAAK,UAAU,QAAA,EAAU;AAC/D,MAAA,OAAO,IAAI,gBAAA,CAAgB,IAAA,CAAK,WAAW,CAAA,gBAAA,EAAmB,IAAA,CAAK,KAAK,CAAA,CAAA,EAAI;AAAA,QAC1E,MAAA;AAAA,QACA,MAAM,IAAA,CAAK,KAAA;AAAA,QACX,QAAQ,IAAA,CAAK,MAAA;AAAA,QACb,YAAY,IAAA,CAAK,UAAA;AAAA,QACjB,OAAO,IAAA,CAAK,KAAA;AAAA,QACZ,OAAO,IAAA,CAAK,KAAA;AAAA;AAAA;AAAA,QAGZ,MAAM,IAAA,CAAK,IAAA;AAAA,QACX,KAAK,IAAA,CAAK,GAAA;AAAA,QACV,OAAO,IAAA,CAAK,KAAA;AAAA,QACZ,QAAQ,IAAA,CAAK,MAAA;AAAA,QACb,UAAU,IAAA,CAAK,QAAA;AAAA,QACf,SAAA;AAAA,QACA;AAAA,OACD,CAAA;AAAA,IACH;AAGA,IAAA,MAAM,IAAA,GAAO,cAAc,MAAM,CAAA;AACjC,IAAA,OAAO,IAAI,gBAAA,CAAgB,CAAA,2BAAA,EAA8B,MAAM,CAAA,CAAA,EAAI;AAAA,MACjE,MAAA;AAAA,MACA,IAAA;AAAA,MACA,SAAA;AAAA,MACA;AAAA,KACD,CAAA;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,OAAO,OAAA,CAAQ,OAAA,EAAiB,KAAA,EAAiC;AAC/D,IAAA,OAAO,IAAI,iBAAgB,OAAA,EAAS;AAAA,MAClC,MAAA,EAAQ,oBAAA;AAAA,MACR,IAAA,EAAM,eAAA;AAAA,MACN;AAAA,KACD,CAAA;AAAA,EACH;AAAA;AAAA,EAGA,OAAO,QAAQ,KAAA,EAAiC;AAC9C,IAAA,OAAO,IAAI,iBAAgB,iBAAA,EAAmB;AAAA,MAC5C,MAAA,EAAQ,oBAAA;AAAA,MACR,IAAA,EAAM,SAAA;AAAA,MACN;AAAA,KACD,CAAA;AAAA,EACH;AAAA;AAAA,EAGA,OAAO,QAAQ,SAAA,EAAoC;AACjD,IAAA,OAAO,IAAI,gBAAA,CAAgB,CAAA,wBAAA,EAA2B,SAAS,CAAA,EAAA,CAAA,EAAM;AAAA,MACnE,MAAA,EAAQ,oBAAA;AAAA,MACR,IAAA,EAAM;AAAA,KACP,CAAA;AAAA,EACH;AACF;AAGA,SAAS,cAAc,MAAA,EAAqC;AAC1D,EAAA,IAAI,MAAA,KAAW,KAAK,OAAO,cAAA;AAC3B,EAAA,IAAI,MAAA,KAAW,KAAK,OAAO,oBAAA;AAC3B,EAAA,IAAI,MAAA,KAAW,KAAK,OAAO,WAAA;AAC3B,EAAA,IAAI,MAAA,KAAW,KAAK,OAAO,WAAA;AAC3B,EAAA,IAAI,MAAA,KAAW,KAAK,OAAO,UAAA;AAC3B,EAAA,IAAI,MAAA,KAAW,KAAK,OAAO,eAAA;AAC3B,EAAA,IAAI,MAAA,KAAW,KAAK,OAAO,cAAA;AAC3B,EAAA,IAAI,MAAA,IAAU,KAAK,OAAO,gBAAA;AAC1B,EAAA,IAAI,MAAA,IAAU,KAAK,OAAO,eAAA;AAC1B,EAAA,OAAO,gBAAA;AACT;;;AC5WO,IAAM,mBAAA,GAAsB,CAAA;AAG5B,IAAM,aAAA,GAAgB,GAAA;AAGtB,IAAM,YAAA,GAAe,GAAA;AASrB,IAAM,mBAAA,GAAsB,EAAA;AAmB5B,SAAS,SAAA,CACd,OAAA,EACA,aAAA,EACA,MAAA,GAAuB,KAAK,MAAA,EACpB;AACR,EAAA,IACE,OAAO,aAAA,KAAkB,QAAA,IACzB,MAAA,CAAO,QAAA,CAAS,aAAa,CAAA,IAC7B,aAAA,IAAiB,CAAA,IACjB,aAAA,IAAiB,mBAAA,EACjB;AACA,IAAA,OAAO,IAAA,CAAK,KAAA,CAAM,aAAA,GAAgB,GAAI,CAAA;AAAA,EACxC;AAEA,EAAA,MAAM,cAAc,IAAA,CAAK,GAAA,CAAI,aAAA,GAAgB,CAAA,IAAK,SAAS,YAAY,CAAA;AACvE,EAAA,MAAM,YAAA,GAAe,GAAA,GAAM,MAAA,EAAO,GAAI,GAAA;AACtC,EAAA,OAAO,IAAA,CAAK,KAAA,CAAM,WAAA,GAAc,YAAY,CAAA;AAC9C;AASO,SAAS,kBAAkB,MAAA,EAAyB;AACzD,EAAA,IAAI,MAAA,KAAW,KAAK,OAAO,IAAA;AAC3B,EAAA,IAAI,MAAA,IAAU,GAAA,IAAO,MAAA,GAAS,GAAA,EAAK,OAAO,IAAA;AAC1C,EAAA,OAAO,KAAA;AACT;AAUO,SAAS,iBAAiB,GAAA,EAAuB;AACtD,EAAA,IAAI,eAAe,eAAA,EAAiB;AAClC,IAAA,OAAO,IAAI,IAAA,KAAS,eAAA;AAAA,EACtB;AACA,EAAA,OAAO,KAAA;AACT;AAeO,SAAS,sBAAA,GAAiC;AAC/C,EAAA,MAAM,IAAK,UAAA,CAA0D,MAAA;AACrE,EAAA,IAAI,CAAC,CAAA,IAAK,OAAO,CAAA,CAAE,eAAe,UAAA,EAAY;AAM5C,IAAA,MAAM,IAAI,eAAA;AAAA,MACR,mIAAA;AAAA,MAEA,EAAE,MAAA,EAAQ,CAAA,EAAG,IAAA,EAAM,gBAAA;AAAiB,KACtC;AAAA,EACF;AACA,EAAA,OAAO,EAAE,UAAA,EAAW;AACtB;AAUO,SAAS,KAAA,CAAM,IAAY,MAAA,EAAqC;AACrE,EAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,EAAS,MAAA,KAAW;AACtC,IAAA,IAAI,QAAQ,OAAA,EAAS;AACnB,MAAA,MAAA,CAAO,OAAO,MAAA,IAAU,IAAI,YAAA,CAAa,SAAA,EAAW,YAAY,CAAC,CAAA;AACjE,MAAA;AAAA,IACF;AACA,IAAA,MAAM,KAAA,GAAQ,WAAW,MAAM;AAC7B,MAAA,MAAA,EAAQ,mBAAA,CAAoB,SAAS,OAAO,CAAA;AAC5C,MAAA,OAAA,EAAQ;AAAA,IACV,GAAG,EAAE,CAAA;AACL,IAAA,MAAM,UAAU,MAAY;AAC1B,MAAA,YAAA,CAAa,KAAK,CAAA;AAClB,MAAA,MAAA,EAAQ,mBAAA,CAAoB,SAAS,OAAO,CAAA;AAC5C,MAAA,MAAA,CAAO,QAAQ,MAAA,IAAU,IAAI,YAAA,CAAa,SAAA,EAAW,YAAY,CAAC,CAAA;AAAA,IACpE,CAAA;AACA,IAAA,MAAA,EAAQ,iBAAiB,OAAA,EAAS,OAAA,EAAS,EAAE,IAAA,EAAM,MAAM,CAAA;AAAA,EAC3D,CAAC,CAAA;AACH;;;ACxHO,IAAM,kBAAA,GAAqB,GAAA;AA6ElC,eAAsB,QAAgC,IAAA,EAAkC;AACtF,EAAA,MAAM,SAAA,GAAuB,IAAA,CAAK,SAAA,IAAc,UAAA,CAAW,KAAA;AAC3D,EAAA,IAAI,OAAO,cAAc,UAAA,EAAY;AACnC,IAAA,MAAM,IAAI,KAAA;AAAA,MACR;AAAA,KAEF;AAAA,EACF;AAEA,EAAA,MAAM,GAAA,GAAM,QAAA,CAAS,IAAA,CAAK,OAAA,EAAS,KAAK,IAAI,CAAA;AAC5C,EAAA,MAAM,UAAA,GAAa,IAAA,CAAK,KAAA,EAAO,UAAA,IAAc,mBAAA;AAC7C,EAAA,MAAM,MAAA,GAAS,IAAA,CAAK,KAAA,EAAO,MAAA,IAAU,IAAA,CAAK,MAAA;AAC1C,EAAA,MAAM,SAAA,GAAY,IAAA,CAAK,KAAA,EAAO,SAAA,IAAa,KAAA;AAC3C,EAAA,MAAM,SAAA,GAAY,KAAK,SAAA,IAAa,kBAAA;AACpC,EAAA,IAAI,CAAC,MAAA,CAAO,QAAA,CAAS,SAAS,CAAA,IAAK,aAAa,CAAA,EAAG;AACjD,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,CAAA,4DAAA,EAA+D,MAAA,CAAO,SAAS,CAAC,CAAA,CAAA;AAAA,KAClF;AAAA,EACF;AAKA,EAAA,MAAM,UAAA,GAAa,OAAO,KAAA,KAAiC;AACzD,IAAA,IAAI;AACF,MAAA,MAAM,SAAA,CAAU,KAAA,EAAO,IAAA,CAAK,MAAM,CAAA;AAAA,IACpC,SAAS,KAAA,EAAO;AACd,MAAA,MAAM,eAAA,CAAgB,QAAQ,KAAK,CAAA;AAAA,IACrC;AAAA,EACF,CAAA;AAMA,EAAA,MAAM,cAAA,GAAiB,IAAA,CAAK,MAAA,KAAW,MAAA,GAAS,wBAAuB,GAAI,IAAA;AAE3E,EAAA,IAAI,SAAA;AAEJ,EAAA,KAAA,IAAS,OAAA,GAAU,CAAA,EAAG,OAAA,IAAW,UAAA,EAAY,OAAA,EAAA,EAAW;AACtD,IAAA,MAAM,QAAA,GAAW,yBAAA,CAA0B,IAAA,CAAK,MAAA,EAAQ,SAAS,CAAA;AASjE,IAAA,IAAI;AAKF,MAAA,MAAM,UAAA,GAAa,KAAK,IAAA,KAAS,KAAA,CAAA,GAAY,KAAK,SAAA,CAAU,IAAA,CAAK,IAAI,CAAA,GAAI,EAAA;AAMzE,MAAA,MAAM,oBAAoB,EAAE,GAAI,IAAA,CAAK,OAAA,IAAW,EAAC,EAAG;AACpD,MAAA,IAAI,KAAK,WAAA,EAAa;AACpB,QAAA,iBAAA,CAAkB,aAAA,GAAgB,MAAM,IAAA,CAAK,WAAA,CAAY;AAAA,UACvD,QAAQ,IAAA,CAAK,MAAA;AAAA,UACb,cAAc,IAAA,CAAK,IAAA;AAAA,UACnB,IAAA,EAAM;AAAA,SACP,CAAA;AAAA,MACH;AACA,MAAA,MAAM,IAAA,GAAoB;AAAA,QACxB,QAAQ,IAAA,CAAK,MAAA;AAAA,QACb,OAAA,EAAS,aAAa,EAAE,GAAG,MAAM,OAAA,EAAS,iBAAA,IAAqB,cAAc,CAAA;AAAA,QAC7E,QAAQ,QAAA,CAAS;AAAA,OACnB;AACA,MAAA,IAAI,IAAA,CAAK,SAAS,KAAA,CAAA,EAAW;AAC3B,QAAA,IAAA,CAAK,IAAA,GAAO,UAAA;AAAA,MACd;AACA,MAAA,MAAM,QAAA,GAAW,MAAM,SAAA,CAAU,GAAA,EAAK,IAAI,CAAA;AAE1C,MAAA,IAAI,SAAS,EAAA,EAAI;AAKf,QAAA,qBAAA,CAAsB,QAAA,EAAU,KAAK,QAAQ,CAAA;AAC7C,QAAA,OAAO,MAAM,UAAa,QAAQ,CAAA;AAAA,MACpC;AAGA,MAAA,MAAM,IAAA,GAAO,MAAM,oBAAA,CAAqB,QAAQ,CAAA;AAChD,MAAA,MAAM,GAAA,GAAM,gBAAgB,IAAA,CAAK;AAAA,QAC/B,QAAQ,QAAA,CAAS,MAAA;AAAA,QACjB,IAAA;AAAA,QACA,SAAA,EAAW,QAAA,CAAS,OAAA,CAAQ,GAAA,CAAI,cAAc,CAAA,IAAK,KAAA;AAAA,OACpD,CAAA;AAED,MAAA,IAAI,iBAAA,CAAkB,QAAA,CAAS,MAAM,CAAA,IAAK,UAAU,UAAA,EAAY;AAC9D,QAAA,MAAM,UAAA,GAAa,eAAe,QAAQ,CAAA;AAC1C,QAAA,MAAM,KAAA,GAAQ,SAAA,CAAU,OAAA,EAAS,UAAA,EAAY,MAAM,CAAA;AACnD,QAAA,MAAM,WAAW,KAAK,CAAA;AACtB,QAAA,SAAA,GAAY,GAAA;AACZ,QAAA;AAAA,MACF;AAEA,MAAA,MAAM,GAAA;AAAA,IACR,SAAS,MAAA,EAAiB;AAGxB,MAAA,IAAI,kBAAkB,eAAA,EAAiB;AACrC,QAAA,IAAI,gBAAA,CAAiB,MAAM,CAAA,IAAK,OAAA,GAAU,UAAA,EAAY;AACpD,UAAA,MAAM,KAAA,GAAQ,SAAA,CAAU,OAAA,EAAS,MAAA,EAAW,MAAM,CAAA;AAClD,UAAA,MAAM,WAAW,KAAK,CAAA;AACtB,UAAA,SAAA,GAAY,MAAA;AACZ,UAAA;AAAA,QACF;AACA,QAAA,MAAM,MAAA;AAAA,MACR;AAMA,MAAA,MAAM,SAAS,iBAAA,CAAkB,MAAA,EAAQ,IAAA,CAAK,MAAA,EAAQ,WAAW,QAAQ,CAAA;AACzE,MAAA,IAAI,gBAAA,CAAiB,MAAM,CAAA,IAAK,OAAA,GAAU,UAAA,EAAY;AACpD,QAAA,MAAM,KAAA,GAAQ,SAAA,CAAU,OAAA,EAAS,MAAA,EAAW,MAAM,CAAA;AAClD,QAAA,MAAM,WAAW,KAAK,CAAA;AACtB,QAAA,SAAA,GAAY,MAAA;AACZ,QAAA;AAAA,MACF;AACA,MAAA,MAAM,MAAA;AAAA,IACR,CAAA,SAAE;AACA,MAAA,QAAA,CAAS,OAAA,EAAQ;AAAA,IACnB;AAAA,EACF;AAIA,EAAA,MACE,SAAA,IACA,IAAI,eAAA,CAAgB,8BAAA,EAAgC;AAAA,IAClD,MAAA,EAAQ,CAAA;AAAA,IACR,IAAA,EAAM;AAAA,GACP,CAAA;AAEL;AAMA,SAAS,QAAA,CAAS,SAAiB,IAAA,EAAsB;AAIvD,EAAA,MAAM,IAAA,GAAO,QAAQ,QAAA,CAAS,GAAG,IAAI,OAAA,CAAQ,KAAA,CAAM,CAAA,EAAG,EAAE,CAAA,GAAI,OAAA;AAC5D,EAAA,OAAO,IAAA,GAAO,IAAA;AAChB;AAEA,SAAS,YAAA,CAAa,MAAsB,cAAA,EAAuD;AACjG,EAAA,MAAM,OAAA,GAAkC,EAAE,MAAA,EAAQ,kBAAA,EAAmB;AACrE,EAAA,IAAI,IAAA,CAAK,SAAS,MAAA,EAAW;AAC3B,IAAA,OAAA,CAAQ,cAAc,CAAA,GAAI,kBAAA;AAAA,EAC5B;AACA,EAAA,IAAI,mBAAmB,IAAA,EAAM;AAC3B,IAAA,OAAA,CAAQ,iBAAiB,CAAA,GAAI,cAAA;AAAA,EAC/B;AAGA,EAAA,IAAI,KAAK,OAAA,EAAS;AAChB,IAAA,KAAA,MAAW,CAAC,CAAA,EAAG,CAAC,CAAA,IAAK,MAAA,CAAO,OAAA,CAAQ,IAAA,CAAK,OAAO,CAAA,EAAG,OAAA,CAAQ,CAAC,CAAA,GAAI,CAAA;AAAA,EAClE;AACA,EAAA,OAAO,OAAA;AACT;AAqBA,eAAe,UAAkC,QAAA,EAAgC;AAC/E,EAAA,MAAM,SAAA,GAAY,QAAA,CAAS,OAAA,CAAQ,GAAA,CAAI,cAAc,CAAA,IAAK,MAAA;AAE1D,EAAA,IAAI,MAAA;AACJ,EAAA,IAAI;AACF,IAAA,MAAA,GAAS,MAAM,SAAS,IAAA,EAAK;AAAA,EAC/B,SAAS,KAAA,EAAO;AACd,IAAA,MAAM,IAAI,gBAAgB,kCAAA,EAAoC;AAAA,MAC5D,QAAQ,QAAA,CAAS,MAAA;AAAA,MACjB,IAAA,EAAM,cAAA;AAAA,MACN,SAAA;AAAA,MACA;AAAA,KACD,CAAA;AAAA,EACH;AAEA,EAAA,IAAI,MAAA,KAAW,IAAA,IAAQ,OAAO,MAAA,KAAW,QAAA,EAAU;AACjD,IAAA,MAAM,QAAA,GAAW,MAAA,KAAW,IAAA,GAAO,MAAA,GAAS,OAAO,MAAA;AACnD,IAAA,MAAM,IAAI,eAAA,CAAgB,CAAA,yCAAA,EAA4C,QAAQ,CAAA,CAAA,CAAA,EAAK;AAAA,MACjF,QAAQ,QAAA,CAAS,MAAA;AAAA,MACjB,IAAA,EAAM,cAAA;AAAA,MACN;AAAA,KACD,CAAA;AAAA,EACH;AAMA,EAAA,MAAM,UAAW,MAAA,CAA4B,EAAA;AAC7C,EAAA,IAAI,YAAY,IAAA,EAAM;AACpB,IAAA,MAAM,IAAI,eAAA;AAAA,MACR,CAAA,yEAAA,EAA4E,MAAA,CAAO,OAAO,CAAC,CAAA,CAAA,CAAA;AAAA,MAC3F;AAAA,QACE,QAAQ,QAAA,CAAS,MAAA;AAAA,QACjB,IAAA,EAAM,cAAA;AAAA,QACN;AAAA;AACF,KACF;AAAA,EACF;AAEA,EAAA,OAAO,MAAA;AACT;AAEA,eAAe,qBAAqB,QAAA,EAAmD;AAIrF,EAAA,IAAI;AACF,IAAA,MAAM,IAAA,GAAQ,MAAM,QAAA,CAAS,IAAA,EAAK;AAClC,IAAA,IAAI,IAAA,IAAQ,OAAO,IAAA,KAAS,QAAA,IAAY,QAAQ,IAAA,IAAQ,IAAA,CAAK,OAAO,KAAA,EAAO;AACzE,MAAA,OAAO,IAAA;AAAA,IACT;AACA,IAAA,OAAO,KAAA,CAAA;AAAA,EACT,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,MAAA;AAAA,EACT;AACF;AAEA,SAAS,eAAe,QAAA,EAAwC;AAC9D,EAAA,MAAM,GAAA,GAAM,QAAA,CAAS,OAAA,CAAQ,GAAA,CAAI,aAAa,CAAA;AAC9C,EAAA,IAAI,CAAC,KAAK,OAAO,MAAA;AACjB,EAAA,MAAM,CAAA,GAAI,OAAO,GAAG,CAAA;AACpB,EAAA,OAAO,OAAO,QAAA,CAAS,CAAC,CAAA,IAAK,CAAA,IAAK,IAAI,CAAA,GAAI,MAAA;AAC5C;AAcA,IAAM,gBAAA,uBAAuB,GAAA,EAAY;AACzC,SAAS,qBAAA,CAAsB,UAAoB,QAAA,EAA+C;AAChG,EAAA,MAAM,WAAA,GAAc,QAAA,CAAS,OAAA,CAAQ,GAAA,CAAI,aAAa,CAAA;AACtD,EAAA,MAAM,MAAA,GAAS,QAAA,CAAS,OAAA,CAAQ,GAAA,CAAI,QAAQ,CAAA;AAC5C,EAAA,IAAI,CAAC,WAAA,IAAe,CAAC,MAAA,EAAQ;AAC7B,EAAA,MAAM,IAAA,GAAO,QAAA,CAAS,OAAA,CAAQ,GAAA,CAAI,MAAM,CAAA,IAAK,EAAA;AAC7C,EAAA,MAAM,GAAA,GAAM,GAAG,WAAA,IAAe,EAAE,IAAI,MAAA,IAAU,EAAE,IAAI,IAAI,CAAA,CAAA;AACxD,EAAA,IAAI,gBAAA,CAAiB,GAAA,CAAI,GAAG,CAAA,EAAG;AAC/B,EAAA,gBAAA,CAAiB,IAAI,GAAG,CAAA;AAExB,EAAA,MAAM,SAAmB,EAAC;AAC1B,EAAA,IAAI,gBAAgB,MAAA,IAAU,WAAA,SAAoB,IAAA,CAAK,CAAA,aAAA,EAAgB,WAAW,CAAA,CAAE,CAAA;AACpF,EAAA,IAAI,MAAA,EAAQ,MAAA,CAAO,IAAA,CAAK,CAAA,QAAA,EAAW,MAAM,CAAA,CAAE,CAAA;AAC3C,EAAA,IAAI,IAAA,EAAM;AAER,IAAA,MAAM,CAAA,GAAI,IAAA,CAAK,KAAA,CAAM,WAAW,CAAA;AAChC,IAAA,IAAI,GAAG,MAAA,CAAO,IAAA,CAAK,SAAS,CAAA,CAAE,CAAC,CAAC,CAAA,CAAE,CAAA;AAAA,EACpC;AACA,EAAA,MAAM,OAAA,GACJ,CAAA,wDAAA,EAA2D,MAAA,CAAO,IAAA,CAAK,QAAK,CAAC,CAAA,0CAAA,CAAA;AAG/E,EAAA,IAAI,QAAA,EAAU;AACZ,IAAA,QAAA,CAAS,OAAO,CAAA;AAAA,EAClB,CAAA,MAAO;AAEL,IAAA,OAAA,CAAQ,KAAK,OAAO,CAAA;AAAA,EACtB;AACF;AAoBA,SAAS,yBAAA,CACP,QACA,SAAA,EACuE;AACvE,EAAA,MAAM,IAAA,GAAO,IAAI,eAAA,EAAgB;AACjC,EAAA,IAAI,UAAA,GAAa,KAAA;AAEjB,EAAA,IAAI,QAAQ,OAAA,EAAS;AACnB,IAAA,IAAA,CAAK,KAAA,CAAM,OAAO,MAAM,CAAA;AACxB,IAAA,OAAO,EAAE,MAAA,EAAQ,IAAA,CAAK,MAAA,EAAQ,SAAS,MAAM;AAAA,IAAC,CAAA,EAAG,QAAA,EAAU,MAAM,KAAA,EAAM;AAAA,EACzE;AAEA,EAAA,MAAM,gBAAgB,MAAY;AAChC,IAAA,IAAA,CAAK,KAAA,CAAM,QAAQ,MAAM,CAAA;AAAA,EAC3B,CAAA;AACA,EAAA,MAAA,EAAQ,iBAAiB,OAAA,EAAS,aAAA,EAAe,EAAE,IAAA,EAAM,MAAM,CAAA;AAE/D,EAAA,MAAM,KAAA,GAAQ,WAAW,MAAM;AAC7B,IAAA,UAAA,GAAa,IAAA;AACb,IAAA,IAAA,CAAK,MAAM,IAAI,YAAA,CAAa,2BAA2B,SAAS,CAAA,EAAA,CAAA,EAAM,cAAc,CAAC,CAAA;AAAA,EACvF,GAAG,SAAS,CAAA;AAEZ,EAAA,OAAO;AAAA,IACL,QAAQ,IAAA,CAAK,MAAA;AAAA,IACb,SAAS,MAAM;AACb,MAAA,YAAA,CAAa,KAAK,CAAA;AAClB,MAAA,MAAA,EAAQ,mBAAA,CAAoB,SAAS,aAAa,CAAA;AAAA,IACpD,CAAA;AAAA,IACA,UAAU,MAAM;AAAA,GAClB;AACF;AAEA,SAAS,iBAAA,CACP,MAAA,EACA,YAAA,EACA,SAAA,EACA,QAAA,EACiB;AAEjB,EAAA,IAAI,cAAc,OAAA,EAAS;AACzB,IAAA,OAAO,eAAA,CAAgB,OAAA,CAAQ,YAAA,CAAa,MAAA,IAAU,MAAM,CAAA;AAAA,EAC9D;AAEA,EAAA,IAAI,QAAA,CAAS,UAAS,EAAG;AACvB,IAAA,OAAO,eAAA,CAAgB,QAAQ,SAAS,CAAA;AAAA,EAC1C;AAEA,EAAA,MAAM,OAAA,GAAU,MAAA,YAAkB,KAAA,GAAQ,MAAA,CAAO,OAAA,GAAU,wBAAA;AAC3D,EAAA,OAAO,eAAA,CAAgB,OAAA,CAAQ,OAAA,EAAS,MAAM,CAAA;AAChD;;;ACvaO,SAAS,aAAA,CAAc,IAAiB,UAAA,EAAoC;AACjF,EAAA,IAAI,OAAO,CAAA,CAAE,GAAA,KAAQ,WAAA,EAAa,OAAO,KAAA;AACzC,EAAA,IAAI,OAAO,CAAA,CAAE,IAAA,KAAS,WAAA,EAAa,OAAO,MAAA;AAK1C,EAAA,IACE,OAAO,CAAA,CAAE,SAAA,EAAW,SAAA,KAAc,QAAA,IAClC,EAAE,SAAA,CAAU,SAAA,CAAU,QAAA,CAAS,oBAAoB,CAAA,EACnD;AACA,IAAA,OAAO,SAAA;AAAA,EACT;AAEA,EAAA,IAAI,OAAO,CAAA,CAAE,OAAA,EAAS,QAAA,EAAU,IAAA,KAAS,UAAU,OAAO,MAAA;AAC1D,EAAA,IAAI,OAAO,CAAA,CAAE,QAAA,KAAa,WAAA,EAAa,OAAO,SAAA;AAE9C,EAAA,OAAO,SAAA;AACT;AASO,SAAS,gBAAA,CAAiB,OAAA,EAAiB,OAAA,GAAmB,aAAA,EAAc,EAAW;AAC5F,EAAA,OAAO,CAAA,cAAA,EAAiB,OAAO,CAAA,EAAA,EAAK,OAAO,CAAA,CAAA,CAAA;AAC7C;;;ACxBA,eAAe,QAAA,GAAgC;AAC7C,EAAA,IAAI;AACF,IAAA,OAAO,MAAM,OAAO,MAAM,CAAA;AAAA,EAC5B,SAAS,KAAA,EAAO;AACd,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,mKAAA;AAAA,MAGA,EAAE,KAAA;AAAM,KACV;AAAA,EACF;AACF;AAEA,SAAS,mBAAmB,GAAA,EAA6B;AACvD,EAAA,MAAM,MAAA,GAAS,GAAA,CAAI,OAAA,CAAQ,GAAA,CAAI,eAAe,CAAA;AAC9C,EAAA,IAAI,CAAC,QAAQ,OAAO,IAAA;AACpB,EAAA,MAAM,OAAA,GAAU,OAAO,IAAA,EAAK;AAC5B,EAAA,IAAI,CAAC,aAAA,CAAc,IAAA,CAAK,OAAO,GAAG,OAAO,IAAA;AACzC,EAAA,OAAO,QAAQ,OAAA,CAAQ,aAAA,EAAe,EAAE,CAAA,CAAE,MAAK,IAAK,IAAA;AACtD;AAYO,SAAS,UAAU,OAAA,EAA4C;AACpE,EAAA,MAAM,KAAA,GAAQ,QAAQ,KAAA,IAAS,KAAA;AAG/B,EAAA,IAAI,MAAA,GAA8D,IAAA;AAElE,EAAA,OAAO,OAAO,GAAA,KAAmD;AAC/D,IAAA,MAAM,KAAA,GAAQ,mBAAmB,GAAG,CAAA;AACpC,IAAA,IAAI,KAAA,KAAU,MAAM,OAAO,IAAA;AAI3B,IAAA,MAAM,IAAA,GAAO,MAAM,QAAA,EAAS;AAC5B,IAAA,IAAI,WAAW,IAAA,EAAM;AACnB,MAAA,MAAA,GAAS,IAAA,CAAK,kBAAA;AAAA,QACZ,IAAI,GAAA,CAAI,OAAA,CAAQ,OAAO,CAAA;AAAA,QACvB,OAAA,CAAQ,QAAQ,EAAE,CAAC,KAAK,WAAW,GAAG,OAAA,CAAQ,KAAA,EAAM,GAAI;AAAA,OAC1D;AAAA,IACF;AAEA,IAAA,IAAI;AACF,MAAA,MAAM,EAAE,OAAA,EAAQ,GAAI,MAAM,IAAA,CAAK,SAAA,CAAU,OAAO,MAAA,EAAQ;AAAA,QACtD,GAAI,QAAQ,MAAA,KAAW,KAAA,CAAA,GAAY,EAAE,MAAA,EAAQ,OAAA,CAAQ,MAAA,EAAO,GAAI,EAAC;AAAA,QACjE,GAAI,QAAQ,QAAA,KAAa,KAAA,CAAA,GAAY,EAAE,QAAA,EAAU,OAAA,CAAQ,QAAA,EAAS,GAAI;AAAC,OACxE,CAAA;AACD,MAAA,MAAM,EAAA,GAAK,QAAQ,KAAK,CAAA;AACxB,MAAA,OAAO,OAAO,OAAO,QAAA,IAAY,EAAA,CAAG,SAAS,CAAA,GAAI,EAAE,QAAA,EAAU,EAAA,EAAG,GAAI,IAAA;AAAA,IACtE,CAAA,CAAA,MAAQ;AAEN,MAAA,OAAO,IAAA;AAAA,IACT;AAAA,EACF,CAAA;AACF;AAYO,SAAS,kBAAkB,OAAA,EAAoD;AACpF,EAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,WAAA,CAAY,OAAA,CAAQ,QAAQ,EAAE,CAAA;AACnD,EAAA,OAAO,SAAA,CAAU;AAAA,IACf,OAAA,EAAS,GAAG,IAAI,CAAA,8BAAA,CAAA;AAAA,IAChB,MAAA,EAAQ,GAAG,IAAI,CAAA,QAAA,CAAA;AAAA,IACf,QAAA,EAAU,eAAA;AAAA,IACV,GAAI,QAAQ,KAAA,KAAU,MAAA,GAAY,EAAE,KAAA,EAAO,OAAA,CAAQ,KAAA,EAAM,GAAI,EAAC;AAAA,IAC9D,GAAI,QAAQ,KAAA,KAAU,MAAA,GAAY,EAAE,KAAA,EAAO,OAAA,CAAQ,KAAA,EAAM,GAAI;AAAC,GAC/D,CAAA;AACH;AA2BO,SAAS,eAAe,OAAA,EAAiD;AAC9E,EAAA,MAAM,MAAA,GAAS,OAAA,CAAQ,MAAA,CAAO,OAAA,CAAQ,QAAQ,EAAE,CAAA;AAChD,EAAA,OAAO,SAAA,CAAU;AAAA,IACf,OAAA,EAAS,GAAG,MAAM,CAAA,sBAAA,CAAA;AAAA,IAClB,MAAA;AAAA,IACA,GAAI,QAAQ,QAAA,KAAa,MAAA,GAAY,EAAE,QAAA,EAAU,OAAA,CAAQ,QAAA,EAAS,GAAI,EAAC;AAAA,IACvE,GAAI,QAAQ,KAAA,KAAU,MAAA,GAAY,EAAE,KAAA,EAAO,OAAA,CAAQ,KAAA,EAAM,GAAI,EAAC;AAAA,IAC9D,GAAI,QAAQ,KAAA,KAAU,MAAA,GAAY,EAAE,KAAA,EAAO,OAAA,CAAQ,KAAA,EAAM,GAAI;AAAC,GAC/D,CAAA;AACH;AAoBO,SAAS,eAAe,OAAA,EAAiD;AAC9E,EAAA,MAAM,IAAA,GAAO,QAAQ,MAAA,CAAO,OAAA,CAAQ,gBAAgB,EAAE,CAAA,CAAE,OAAA,CAAQ,MAAA,EAAQ,EAAE,CAAA;AAC1E,EAAA,OAAO,SAAA,CAAU;AAAA,IACf,OAAA,EAAS,WAAW,IAAI,CAAA,sBAAA,CAAA;AAAA,IACxB,MAAA,EAAQ,WAAW,IAAI,CAAA,CAAA,CAAA;AAAA,IACvB,UAAU,OAAA,CAAQ,QAAA;AAAA,IAClB,GAAI,QAAQ,KAAA,KAAU,MAAA,GAAY,EAAE,KAAA,EAAO,OAAA,CAAQ,KAAA,EAAM,GAAI,EAAC;AAAA,IAC9D,GAAI,QAAQ,KAAA,KAAU,MAAA,GAAY,EAAE,KAAA,EAAO,OAAA,CAAQ,KAAA,EAAM,GAAI;AAAC,GAC/D,CAAA;AACH;AAMA,IAAM,iBAAA,GACJ,2FAAA;AAmBK,SAAS,sBAAsB,OAAA,EAAwD;AAC5F,EAAA,OAAO,SAAA,CAAU;AAAA,IACf,OAAA,EAAS,iBAAA;AAAA,IACT,MAAA,EAAQ,CAAA,+BAAA,EAAkC,OAAA,CAAQ,SAAS,CAAA,CAAA;AAAA,IAC3D,UAAU,OAAA,CAAQ,SAAA;AAAA,IAClB,GAAI,QAAQ,KAAA,KAAU,MAAA,GAAY,EAAE,KAAA,EAAO,OAAA,CAAQ,KAAA,EAAM,GAAI,EAAC;AAAA,IAC9D,GAAI,QAAQ,KAAA,KAAU,MAAA,GAAY,EAAE,KAAA,EAAO,OAAA,CAAQ,KAAA,EAAM,GAAI;AAAC,GAC/D,CAAA;AACH;;;AClNA,IAAM,gBAAA,GAAmB,6CAAA;AACzB,IAAM,eAAA,GAAkB,6BAAA;AAIxB,IAAM,cAAA,GAAiB,yBAAA;AAGvB,IAAM,UAAA,GAAa,6BAAA;AAKnB,IAAM,QAAA,GAAW,wBAAA;AACjB,IAAM,OAAA,GAAU,wBAAA;AA6BT,SAAS,yBACd,MAAA,EACoB;AACpB,EAAA,IAAI,OAAO,MAAA,CAAO,QAAA,KAAa,YAAY,MAAA,CAAO,QAAA,CAAS,WAAW,CAAA,EAAG;AACvE,IAAA,MAAM,IAAI,UAAU,iDAAiD,CAAA;AAAA,EACvE;AACA,EAAA,IAAI,OAAO,MAAA,CAAO,YAAA,KAAiB,YAAY,MAAA,CAAO,YAAA,CAAa,WAAW,CAAA,EAAG;AAC/E,IAAA,MAAM,IAAI,UAAU,qDAAqD,CAAA;AAAA,EAC3E;AACA,EAAA,IAAI,aAAA;AACJ,EAAA,IAAI;AACF,IAAA,MAAM,MAAA,GAAS,IAAI,GAAA,CAAI,MAAA,CAAO,aAAa,CAAA;AAG3C,IAAA,aAAA,GAAgB,MAAA,CAAO,MAAA;AACvB,IAAA,IAAI,aAAA,KAAkB,MAAA,EAAQ,MAAM,IAAI,MAAM,eAAe,CAAA;AAAA,EAC/D,CAAA,CAAA,MAAQ;AACN,IAAA,MAAM,IAAI,SAAA;AAAA,MACR,yGAAA,GAEE,IAAA,CAAK,SAAA,CAAU,MAAA,CAAO,aAAa,CAAA,GACnC;AAAA,KACJ;AAAA,EACF;AACA,EAAA,MAAM,SAAA,GAAuB,OAAO,KAAA,IAAS,KAAA;AAE7C,EAAA,OAAO,OAAO,GAAA,KAAoC;AAChD,IAAA,IAAI,GAAA,CAAI,WAAW,KAAA,EAAO;AACxB,MAAA,OAAO,IAAI,QAAA,CAAS,oBAAA,EAAsB,EAAE,MAAA,EAAQ,GAAA,EAAK,OAAA,EAAS,EAAE,KAAA,EAAO,KAAA,EAAM,EAAG,CAAA;AAAA,IACtF;AACA,IAAA,MAAM,GAAA,GAAM,IAAI,GAAA,CAAI,GAAA,CAAI,GAAG,CAAA;AAC3B,IAAA,MAAM,KAAA,GAAQ,GAAA,CAAI,YAAA,CAAa,GAAA,CAAI,OAAO,CAAA,IAAK,EAAA;AAC/C,IAAA,MAAM,IAAA,GAAO,GAAA,CAAI,YAAA,CAAa,GAAA,CAAI,MAAM,CAAA;AACxC,IAAA,MAAM,OAAA,GAAU,GAAA,CAAI,YAAA,CAAa,GAAA,CAAI,OAAO,CAAA;AAG5C,IAAA,IAAI,CAAC,QAAA,CAAS,IAAA,CAAK,KAAK,CAAA,EAAG;AACzB,MAAA,OAAO,IAAI,QAAA,CAAS,oCAAA,EAAsC,EAAE,MAAA,EAAQ,KAAK,CAAA;AAAA,IAC3E;AAIA,IAAA,IAAI,YAAY,IAAA,EAAM;AACpB,MAAA,OAAO,YAAA;AAAA,QACL,EAAE,KAAA,EAAO,KAAA,EAAO,OAAA,KAAY,eAAA,GAAkB,kBAAkB,iBAAA,EAAkB;AAAA,QAClF;AAAA,OACF;AAAA,IACF;AAEA,IAAA,IAAI,SAAS,IAAA,IAAQ,CAAC,OAAA,CAAQ,IAAA,CAAK,IAAI,CAAA,EAAG;AACxC,MAAA,OAAO,IAAI,QAAA,CAAS,mCAAA,EAAqC,EAAE,MAAA,EAAQ,KAAK,CAAA;AAAA,IAC1E;AAIA,IAAA,IAAI,WAAA;AACJ,IAAA,IAAI;AACF,MAAA,MAAM,QAAA,GAAW,MAAM,SAAA,CAAU,gBAAA,EAAkB;AAAA,QACjD,MAAA,EAAQ,MAAA;AAAA,QACR,OAAA,EAAS;AAAA,UACP,MAAA,EAAQ,kBAAA;AAAA,UACR,cAAA,EAAgB,mCAAA;AAAA,UAChB,YAAA,EAAc;AAAA,SAChB;AAAA,QACA,IAAA,EAAM,IAAI,eAAA,CAAgB;AAAA,UACxB,WAAW,MAAA,CAAO,QAAA;AAAA,UAClB,eAAe,MAAA,CAAO,YAAA;AAAA,UACtB;AAAA,SACD,EAAE,QAAA;AAAS,OACb,CAAA;AACD,MAAA,MAAM,SAAA,GAAa,MAAM,QAAA,CAAS,IAAA,EAAK;AACvC,MAAA,IAAI,CAAC,QAAA,CAAS,EAAA,IAAM,OAAO,SAAA,CAAU,iBAAiB,QAAA,EAAU;AAC9D,QAAA,OAAO,aAAa,EAAE,KAAA,EAAO,KAAA,EAAO,iBAAA,IAAqB,aAAa,CAAA;AAAA,MACxE;AACA,MAAA,WAAA,GAAc,SAAA,CAAU,YAAA;AAAA,IAC1B,CAAA,CAAA,MAAQ;AACN,MAAA,OAAO,aAAa,EAAE,KAAA,EAAO,KAAA,EAAO,iBAAA,IAAqB,aAAa,CAAA;AAAA,IACxE;AAIA,IAAA,IAAI;AACF,MAAA,MAAM,OAAA,GAAU,MAAM,SAAA,CAAU,eAAA,EAAiB;AAAA,QAC/C,MAAA,EAAQ,KAAA;AAAA,QACR,OAAA,EAAS;AAAA,UACP,aAAA,EAAe,UAAU,WAAW,CAAA,CAAA;AAAA,UACpC,MAAA,EAAQ,6BAAA;AAAA,UACR,YAAA,EAAc;AAAA;AAChB,OACD,CAAA;AACD,MAAA,IAAI,CAAC,QAAQ,EAAA,EAAI;AACf,QAAA,OAAO,aAAa,EAAE,KAAA,EAAO,KAAA,EAAO,iBAAA,IAAqB,aAAa,CAAA;AAAA,MACxE;AACA,MAAA,MAAM,IAAA,GAAQ,MAAM,OAAA,CAAQ,IAAA,EAAK;AACjC,MAAA,IAAI,OAAO,KAAK,EAAA,KAAO,QAAA,IAAY,CAAC,MAAA,CAAO,aAAA,CAAc,IAAA,CAAK,EAAE,CAAA,EAAG;AACjE,QAAA,OAAO,aAAa,EAAE,KAAA,EAAO,KAAA,EAAO,iBAAA,IAAqB,aAAa,CAAA;AAAA,MACxE;AACA,MAAA,OAAO,YAAA,CAAa,EAAE,KAAA,EAAO,EAAA,EAAI,OAAO,IAAA,CAAK,EAAE,CAAA,EAAE,EAAG,aAAa,CAAA;AAAA,IACnE,CAAA,CAAA,MAAQ;AACN,MAAA,OAAO,aAAa,EAAE,KAAA,EAAO,KAAA,EAAO,iBAAA,IAAqB,aAAa,CAAA;AAAA,IACxE;AAAA,EACF,CAAA;AACF;AASA,SAAS,YAAA,CACP,SACA,aAAA,EACU;AACV,EAAA,MAAM,OAAA,GAAU,KAAK,SAAA,CAAU,EAAE,QAAQ,cAAA,EAAgB,GAAG,SAAS,CAAA;AACrE,EAAA,MAAM,MAAA,GAAS,IAAA,CAAK,SAAA,CAAU,aAAa,CAAA;AAC3C,EAAA,MAAM,IAAA,GAAO,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,8BAAA,EAOiB,OAAO,KAAK,MAAM,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,OAAA,CAAA;AAYhD,EAAA,OAAO,IAAI,SAAS,IAAA,EAAM;AAAA,IACxB,MAAA,EAAQ,GAAA;AAAA,IACR,OAAA,EAAS;AAAA,MACP,cAAA,EAAgB,0BAAA;AAAA;AAAA,MAEhB,eAAA,EAAiB,UAAA;AAAA;AAAA,MAEjB,iBAAA,EAAmB,aAAA;AAAA;AAAA;AAAA,MAGnB,yBAAA,EAA2B,gDAAA;AAAA,MAC3B,wBAAA,EAA0B;AAAA;AAC5B,GACD,CAAA;AACH;;;ACpEO,IAAM,UAAA,GAAN,MAAM,WAAA,CAAW;AAAA;AAAA;AAAA;AAAA;AAAA,EAKtB,OAAgB,OAAA,GAAkB,OAAA;AAAA,EAEzB,MAAA;AAAA,EACA,OAAA;AAAA,EACA,QAAA;AAAA;AAAA;AAAA;AAAA,EAIA,KAAA;AAAA,EACA,UAAA;AAAA,EACA,UAAA;AAAA,EACA,WAAA;AAAA,EACA,UAAA;AAAA,EACA,SAAA;AAAA,EACA,UAAA;AAAA,EAET,YAAY,MAAA,EAAyB;AAiBnC,IAAA,IAAI,0BAAyB,EAAG;AAC9B,MAAA,MAAM,IAAI,KAAA;AAAA,QACR;AAAA,OAIF;AAAA,IACF;AAEA,IAAA,MAAM,QAAA,GAAW,kBAAkB,MAAM,CAAA;AACzC,IAAA,IAAA,CAAK,SAAS,QAAA,CAAS,KAAA;AACvB,IAAA,IAAA,CAAK,UAAU,QAAA,CAAS,MAAA;AACxB,IAAA,IAAA,CAAK,YAAY,MAAA,CAAO,OAAA,IAAW,gBAAA,EAAkB,OAAA,CAAQ,QAAQ,EAAE,CAAA;AAIvE,IAAA,IAAI;AACF,MAAA,IAAA,CAAK,KAAA,GAAQ,IAAI,GAAA,CAAI,IAAA,CAAK,QAAQ,CAAA,CAAE,IAAA;AAAA,IACtC,CAAA,CAAA,MAAQ;AACN,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,CAAA,8DAAA,EAAiE,KAAK,QAAQ,CAAA,CAAA;AAAA,OAChF;AAAA,IACF;AACA,IAAA,IAAA,CAAK,aAAa,MAAA,CAAO,KAAA;AACzB,IAAA,IAAA,CAAK,aAAa,MAAA,CAAO,SAAA;AACzB,IAAA,IAAA,CAAK,cAAc,MAAA,CAAO,UAAA;AAC1B,IAAA,IAAA,CAAK,aAAa,MAAA,CAAO,SAAA;AACzB,IAAA,IAAA,CAAK,YAAY,MAAA,CAAO,IAAA;AACxB,IAAA,IAAA,CAAK,UAAA,GAAa,MAAA,CAAO,SAAA,IAAa,gBAAA,CAAiB,YAAW,OAAO,CAAA;AAAA,EAC3E;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeA,MAAM,YAAY,KAAA,EAAmE;AACnF,IAAA,OAAO,KAAK,QAAA,CAA0C;AAAA,MACpD,MAAM,qBAAA,EAAsB;AAAA,MAC5B,MAAA,EAAQ,MAAA;AAAA,MACR,IAAA,EAAM;AAAA,QACJ,SAAS,KAAA,CAAM,OAAA;AAAA,QACf,UAAU,KAAA,CAAM,QAAA;AAAA,QAChB,OAAO,KAAA,CAAM,KAAA;AAAA,QACb,GAAI,MAAM,QAAA,KAAa,MAAA,GAAY,EAAE,QAAA,EAAU,KAAA,CAAM,QAAA,EAAS,GAAI;AAAC,OACrE;AAAA,MACA,QAAQ,KAAA,CAAM;AAAA,KACf,CAAA;AAAA,EACH;AAAA;AAAA,EAGA,MAAM,eAAe,KAAA,EAAsE;AACzF,IAAA,OAAO,KAAK,QAAA,CAA0C;AAAA,MACpD,IAAA,EAAM,kBAAA,CAAmB,KAAA,CAAM,OAAA,EAAS;AAAA,QACtC,GAAI,MAAM,GAAA,KAAQ,MAAA,GAAY,EAAE,GAAA,EAAK,KAAA,CAAM,GAAA,EAAI,GAAI,EAAC;AAAA,QACpD,GAAI,MAAM,MAAA,KAAW,MAAA,GAAY,EAAE,MAAA,EAAQ,KAAA,CAAM,MAAA,EAAO,GAAI;AAAC,OAC9D,CAAA;AAAA,MACD,MAAA,EAAQ,KAAA;AAAA,MACR,QAAQ,KAAA,CAAM;AAAA,KACf,CAAA;AAAA,EACH;AAAA;AAAA,EAGA,MAAM,cAAc,KAAA,EAAoE;AACtF,IAAA,OAAO,KAAK,QAAA,CAAyC;AAAA,MACnD,IAAA,EAAM,iBAAA,CAAkB,KAAA,CAAM,OAAA,EAAS,MAAM,QAAQ,CAAA;AAAA,MACrD,MAAA,EAAQ,KAAA;AAAA,MACR,QAAQ,KAAA,CAAM;AAAA,KACf,CAAA;AAAA,EACH;AAAA;AAAA,EAGA,MAAM,gBAAgB,KAAA,EAAwE;AAC5F,IAAA,OAAO,KAAK,QAAA,CAA2C;AAAA,MACrD,IAAA,EAAM,mBAAA,CAAoB,KAAA,CAAM,OAAA,EAAS,MAAM,QAAA,EAAU;AAAA,QACvD,GAAI,MAAM,MAAA,KAAW,MAAA,GAAY,EAAE,MAAA,EAAQ,KAAA,CAAM,MAAA,EAAO,GAAI,EAAC;AAAA,QAC7D,GAAI,MAAM,KAAA,KAAU,MAAA,GAAY,EAAE,KAAA,EAAO,KAAA,CAAM,KAAA,EAAM,GAAI;AAAC,OAC3D,CAAA;AAAA,MACD,MAAA,EAAQ,KAAA;AAAA,MACR,QAAQ,KAAA,CAAM;AAAA,KACf,CAAA;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,SACJ,IAAA,EACY;AACZ,IAAA,MAAM,WAAA,GAAsC;AAAA;AAAA;AAAA,MAG1C,cAAc,IAAA,CAAK,UAAA;AAAA,MACnB,uBAAuB,IAAA,CAAK;AAAA,KAC9B;AAEA,IAAA,MAAM,WAAA,GAA8B;AAAA,MAClC,SAAS,IAAA,CAAK,QAAA;AAAA,MACd,MAAM,IAAA,CAAK,IAAA;AAAA,MACX,QAAQ,IAAA,CAAK,MAAA;AAAA,MACb,OAAA,EAAS,WAAA;AAAA,MACT,aAAa,OAAO,EAAE,QAAQ,YAAA,EAAc,IAAA,OAC1C,mBAAA,CAAoB;AAAA,QAClB,OAAO,IAAA,CAAK,MAAA;AAAA,QACZ,QAAQ,IAAA,CAAK,OAAA;AAAA,QACb,MAAA;AAAA,QACA,YAAA;AAAA,QACA,MAAM,IAAA,CAAK,KAAA;AAAA,QACX;AAAA,OACD;AAAA,KACL;AACA,IAAA,IAAI,IAAA,CAAK,IAAA,KAAS,MAAA,EAAW,WAAA,CAAY,OAAO,IAAA,CAAK,IAAA;AACrD,IAAA,IAAI,IAAA,CAAK,MAAA,KAAW,MAAA,EAAW,WAAA,CAAY,SAAS,IAAA,CAAK,MAAA;AACzD,IAAA,IAAI,IAAA,CAAK,UAAA,KAAe,MAAA,EAAW,WAAA,CAAY,YAAY,IAAA,CAAK,UAAA;AAChE,IAAA,IAAI,IAAA,CAAK,SAAA,KAAc,MAAA,EAAW,WAAA,CAAY,WAAW,IAAA,CAAK,SAAA;AAC9D,IAAA,IAAI,IAAA,CAAK,UAAA,KAAe,MAAA,EAAW,WAAA,CAAY,YAAY,IAAA,CAAK,UAAA;AAChE,IAAA,IAAI,IAAA,CAAK,WAAA,KAAgB,MAAA,IAAa,IAAA,CAAK,eAAe,MAAA,EAAW;AACnE,MAAA,WAAA,CAAY,KAAA,GAAQ;AAAA,QAClB,GAAI,KAAK,WAAA,KAAgB,MAAA,GAAY,EAAE,UAAA,EAAY,IAAA,CAAK,WAAA,EAAY,GAAI,EAAC;AAAA,QACzE,GAAI,KAAK,UAAA,KAAe,MAAA,GAAY,EAAE,SAAA,EAAW,IAAA,CAAK,UAAA,EAAW,GAAI;AAAC,OACxE;AAAA,IACF;AAEA,IAAA,OAAO,QAAW,WAAW,CAAA;AAAA,EAC/B;AACF;AA0BA,SAAS,wBAAA,GAAoC;AAC3C,EAAA,MAAM,CAAA,GAAI,UAAA;AAOV,EAAA,MAAM,oBAAoB,OAAO,CAAA,CAAE,WAAW,WAAA,IAAe,OAAO,EAAE,QAAA,KAAa,WAAA;AACnF,EAAA,IAAI,CAAC,mBAAmB,OAAO,KAAA;AAC/B,EAAA,MAAM,eAAA,GACJ,OAAA,CAAQ,CAAA,CAAE,OAAA,EAAS,QAAA,EAAU,IAAI,CAAA,IACjC,OAAO,CAAA,CAAE,IAAA,KAAS,WAAA,IAClB,OAAO,EAAE,GAAA,KAAQ,WAAA;AACnB,EAAA,OAAO,CAAC,eAAA;AACV;AAgIO,SAAS,yBACd,MAAA,EACoB;AAEpB,EAAA,MAAM,EAAA,GAAK,IAAI,UAAA,CAAW;AAAA,IACxB,WAAW,MAAA,CAAO,SAAA;AAAA,IAClB,GAAI,OAAO,OAAA,KAAY,MAAA,GAAY,EAAE,OAAA,EAAS,MAAA,CAAO,OAAA,EAAQ,GAAI,EAAC;AAAA,IAClE,GAAI,OAAO,KAAA,KAAU,MAAA,GAAY,EAAE,KAAA,EAAO,MAAA,CAAO,KAAA,EAAM,GAAI,EAAC;AAAA,IAC5D,GAAI,OAAO,UAAA,KAAe,MAAA,GAAY,EAAE,UAAA,EAAY,MAAA,CAAO,UAAA,EAAW,GAAI,EAAC;AAAA,IAC3E,GAAI,OAAO,SAAA,KAAc,MAAA,GAAY,EAAE,SAAA,EAAW,MAAA,CAAO,SAAA,EAAU,GAAI;AAAC,GACzE,CAAA;AACD,EAAA,MAAM,KAAA,GAAQ,OAAO,eAAA,IAAmB,sBAAA;AAExC,EAAA,OAAO,OAAO,GAAA,KAAoC;AAChD,IAAA,MAAM,IAAA,GAAO,MAAA,CAAO,IAAA,GAAO,gBAAA,CAAiB,MAAA,CAAO,IAAA,EAAM,GAAA,CAAI,OAAA,CAAQ,GAAA,CAAI,QAAQ,CAAC,CAAA,GAAI,EAAC;AAEvF,IAAA,IAAI,GAAA,CAAI,MAAA,KAAW,SAAA,IAAa,MAAA,CAAO,IAAA,EAAM;AAC3C,MAAA,OAAO,IAAI,SAAS,IAAA,EAAM,EAAE,QAAQ,GAAA,EAAK,OAAA,EAAS,MAAM,CAAA;AAAA,IAC1D;AACA,IAAA,IAAI,GAAA,CAAI,WAAW,MAAA,EAAQ;AACzB,MAAA,OAAO,YAAA,CAAa,EAAE,EAAA,EAAI,KAAA,EAAO,OAAO,oBAAA,EAAqB,EAAG,KAAK,IAAI,CAAA;AAAA,IAC3E;AAEA,IAAA,IAAI,OAAO,SAAA,EAAW;AACpB,MAAA,MAAM,QAAA,GAAW,MAAM,MAAA,CAAO,SAAA,CAAU,GAAG,CAAA;AAC3C,MAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,QAAA,MAAM,OAAA,GAAU,EAAE,GAAG,IAAA,EAAK;AAC1B,QAAA,IAAI,QAAA,CAAS,sBAAsB,MAAA,EAAW;AAC5C,UAAA,OAAA,CAAQ,aAAa,CAAA,GAAI,MAAA,CAAO,QAAA,CAAS,iBAAiB,CAAA;AAAA,QAC5D;AACA,QAAA,OAAO,YAAA,CAAa,EAAE,EAAA,EAAI,KAAA,EAAO,OAAO,cAAA,EAAe,EAAG,KAAK,OAAO,CAAA;AAAA,MACxE;AAAA,IACF;AAEA,IAAA,IAAI,QAAA;AACJ,IAAA,IAAI;AACF,MAAA,QAAA,GAAW,MAAM,MAAA,CAAO,MAAA,CAAO,GAAG,CAAA;AAAA,IACpC,CAAA,CAAA,MAAQ;AAGN,MAAA,QAAA,GAAW,IAAA;AAAA,IACb;AACA,IAAA,IAAI,CAAC,YAAY,OAAO,QAAA,CAAS,aAAa,QAAA,IAAY,QAAA,CAAS,QAAA,CAAS,MAAA,KAAW,CAAA,EAAG;AACxF,MAAA,OAAO,YAAA,CAAa,EAAE,EAAA,EAAI,KAAA,EAAO,OAAO,cAAA,EAAe,EAAG,KAAK,IAAI,CAAA;AAAA,IACrE;AAEA,IAAA,IAAI,UAAA;AACJ,IAAA,IAAI;AACF,MAAA,UAAA,GAAa,MAAM,MAAM,GAAG,CAAA;AAAA,IAC9B,CAAA,CAAA,MAAQ;AACN,MAAA,UAAA,GAAa,IAAA;AAAA,IACf;AACA,IAAA,IAAI,CAAC,UAAA,IAAc,OAAO,UAAA,CAAW,KAAA,KAAU,QAAA,IAAY,CAAC,MAAA,CAAO,QAAA,CAAS,UAAA,CAAW,KAAK,CAAA,EAAG;AAC7F,MAAA,OAAO,YAAA;AAAA,QACL,EAAE,EAAA,EAAI,KAAA,EAAO,KAAA,EAAO,aAAA,EAAe,SAAS,0BAAA,EAA2B;AAAA,QACvE,GAAA;AAAA,QACA;AAAA,OACF;AAAA,IACF;AAEA,IAAA,MAAM,QAAA,GAAW,aAAA,CAAc,UAAA,CAAW,QAAA,EAAU,SAAS,QAAQ,CAAA;AAErE,IAAA,IAAI;AACF,MAAA,MAAM,MAAA,GAAS,MAAM,EAAA,CAAG,WAAA,CAAY;AAAA,QAClC,SAAS,MAAA,CAAO,OAAA;AAAA,QAChB,UAAU,QAAA,CAAS,QAAA;AAAA,QACnB,OAAO,UAAA,CAAW,KAAA;AAAA,QAClB,GAAI,QAAA,KAAa,KAAA,CAAA,GAAY,EAAE,QAAA,KAAa;AAAC,OAC9C,CAAA;AACD,MAAA,OAAO,YAAA;AAAA,QACL;AAAA,UACE,EAAA,EAAI,IAAA;AAAA,UACJ,MAAM,MAAA,CAAO,IAAA;AAAA,UACb,cAAc,MAAA,CAAO,YAAA;AAAA,UACrB,gBAAgB,MAAA,CAAO;AAAA,SACzB;AAAA,QACA,GAAA;AAAA,QACA;AAAA,OACF;AAAA,IACF,SAAS,GAAA,EAAc;AACrB,MAAA,OAAO,cAAA,CAAe,KAAK,IAAI,CAAA;AAAA,IACjC;AAAA,EACF,CAAA;AACF;AAEA,eAAe,uBAAuB,GAAA,EAAqD;AACzF,EAAA,MAAM,MAAe,MAAM,GAAA,CAAI,MAAK,CAAE,KAAA,CAAM,MAAM,IAAI,CAAA;AACtD,EAAA,IAAI,CAAC,aAAA,CAAc,GAAG,CAAA,EAAG,OAAO,IAAA;AAChC,EAAA,MAAM,QAAQ,GAAA,CAAI,KAAA;AAClB,EAAA,IAAI,OAAO,UAAU,QAAA,IAAY,CAAC,OAAO,QAAA,CAAS,KAAK,GAAG,OAAO,IAAA;AACjE,EAAA,OAAO,EAAE,OAAO,QAAA,EAAU,aAAA,CAAc,IAAI,QAAQ,CAAA,GAAI,GAAA,CAAI,QAAA,GAAW,MAAA,EAAU;AACnF;AAEA,SAAS,cAAc,KAAA,EAAkD;AACvE,EAAA,OAAO,OAAO,UAAU,QAAA,IAAY,KAAA,KAAU,QAAQ,CAAC,KAAA,CAAM,QAAQ,KAAK,CAAA;AAC5E;AAEA,SAAS,aAAA,CACP,QACA,QAAA,EACqC;AACrC,EAAA,IAAI,CAAC,MAAA,IAAU,CAAC,QAAA,EAAU,OAAO,MAAA;AAEjC,EAAA,OAAO,EAAE,GAAI,MAAA,IAAU,IAAK,GAAI,QAAA,IAAY,EAAC,EAAG;AAClD;AAEA,SAAS,YAAA,CAAa,IAAA,EAAe,MAAA,EAAgB,KAAA,EAAyC;AAC5F,EAAA,OAAO,IAAI,QAAA,CAAS,IAAA,CAAK,SAAA,CAAU,IAAI,CAAA,EAAG;AAAA,IACxC,MAAA;AAAA,IACA,OAAA,EAAS,EAAE,cAAA,EAAgB,iCAAA,EAAmC,GAAG,KAAA;AAAM,GACxE,CAAA;AACH;AAEA,SAAS,cAAA,CAAe,KAAc,IAAA,EAAwC;AAC5E,EAAA,IAAI,eAAe,eAAA,EAAiB;AAClC,IAAA,IAAI,GAAA,CAAI,eAAc,EAAG;AACvB,MAAA,MAAM,OAAA,GAAU,EAAE,GAAG,IAAA,EAAK;AAC1B,MAAA,IAAI,GAAA,CAAI,eAAe,MAAA,EAAW,OAAA,CAAQ,aAAa,CAAA,GAAI,MAAA,CAAO,IAAI,UAAU,CAAA;AAChF,MAAA,OAAO,YAAA,CAAa,EAAE,EAAA,EAAI,KAAA,EAAO,OAAO,cAAA,EAAe,EAAG,KAAK,OAAO,CAAA;AAAA,IACxE;AAGA,IAAA,IAAI,GAAA,CAAI,MAAA,IAAU,GAAA,IAAO,GAAA,CAAI,SAAS,GAAA,EAAK;AACzC,MAAA,OAAO,YAAA,CAAa,EAAE,EAAA,EAAI,KAAA,EAAO,KAAA,EAAO,GAAA,CAAI,IAAA,EAAM,OAAA,EAAS,GAAA,CAAI,OAAA,EAAQ,EAAG,GAAA,CAAI,QAAQ,IAAI,CAAA;AAAA,IAC5F;AACA,IAAA,OAAO,YAAA,CAAa,EAAE,EAAA,EAAI,KAAA,EAAO,OAAO,gBAAA,EAAiB,EAAG,KAAK,IAAI,CAAA;AAAA,EACvE;AACA,EAAA,OAAO,YAAA,CAAa,EAAE,EAAA,EAAI,KAAA,EAAO,OAAO,cAAA,EAAe,EAAG,KAAK,IAAI,CAAA;AACrE;AAEA,SAAS,gBAAA,CACP,MACA,MAAA,EACwB;AACxB,EAAA,MAAM,OAAA,GAAkC;AAAA,IACtC,8BAAA,EAAA,CAAiC,KAAK,OAAA,IAAW,CAAC,QAAQ,SAAS,CAAA,EAAG,KAAK,IAAI,CAAA;AAAA,IAC/E,8BAAA,EAAA,CAAiC,KAAK,OAAA,IAAW,CAAC,gBAAgB,eAAe,CAAA,EAAG,KAAK,IAAI,CAAA;AAAA,IAC7F,wBAAA,EAA0B,MAAA,CAAO,IAAA,CAAK,aAAA,IAAiB,GAAG,CAAA;AAAA,IAC1D,IAAA,EAAM;AAAA,GACR;AACA,EAAA,IAAI,WAAW,IAAA,IAAQ,mBAAA,CAAoB,IAAA,CAAK,MAAA,EAAQ,MAAM,CAAA,EAAG;AAC/D,IAAA,OAAA,CAAQ,6BAA6B,CAAA,GAAI,MAAA;AAAA,EAC3C;AACA,EAAA,OAAO,OAAA;AACT;AAEA,SAAS,mBAAA,CAAoB,MAAwC,MAAA,EAAyB;AAC5F,EAAA,IAAI,OAAO,IAAA,KAAS,SAAA,EAAW,OAAO,IAAA;AACtC,EAAA,IAAI,OAAO,IAAA,KAAS,QAAA,EAAU,OAAO,IAAA,KAAS,MAAA;AAC9C,EAAA,IAAI,OAAO,IAAA,KAAS,UAAA,EAAY,OAAO,KAAK,MAAM,CAAA;AAClD,EAAA,OAAO,IAAA,CAAK,SAAS,MAAM,CAAA;AAC7B","file":"server.js","sourcesContent":["/**\n * SDK configuration.\n *\n * The `ScorezillaConfig` is a TypeScript-level discriminated union of\n * `PublicKeyConfig` and `SecretKeyConfig`. The mutual-exclusivity (you may\n * pass `publicKey` OR `secretKey`, never both) is enforced at compile time:\n * passing both fields fails type-checking before the runtime check fires.\n *\n * The runtime check in {@link validateConfig} is the second line of defense\n * for consumers using plain JS or `as any` casts.\n */\n\nimport type { FetchImpl } from './transport';\n\n/** Production API URL. Override via `baseUrl` in {@link ScorezillaConfig} to\n * point at a development worker, staging environment, or a private\n * deployment. */\nexport const DEFAULT_BASE_URL = 'https://api.scorezilla.dev';\n\n/** Public key format: `pk_<slug>_<base62>`. Issued by the operator\n * dashboard. Slug is the game slug; base62 is the random suffix. */\nexport const PUBLIC_KEY_PATTERN = /^pk_[a-z0-9-]+_[A-Za-z0-9]+$/;\n\n/** Secret key prefix — secrets are `sk_live_<id>_<base62>`. Live-only for\n * v0.1.0; the SDK doesn't yet support a `sk_test_*` tier. */\nexport const SECRET_KEY_PREFIX = 'sk_live_';\n\n/** Shared options across both auth modes. */\nexport interface BaseConfig {\n /** API base URL (no trailing slash required). Defaults to {@link DEFAULT_BASE_URL}. */\n baseUrl?: string;\n /** Custom fetch implementation — defaults to `globalThis.fetch`. Pass\n * `node-fetch`, `undici`, or a mock here. The explicit signature\n * (`(RequestInfo | URL, init?) => Promise<Response>`) is broader than\n * `typeof fetch` so common polyfills typecheck cleanly. */\n fetch?: FetchImpl;\n /** Per-request timeout in milliseconds. Defaults to 30 s. */\n timeoutMs?: number;\n /** Maximum retry attempts on transient failures. Defaults to 2 (so the\n * worst-case total request count is 3). */\n maxRetries?: number;\n /** Override the default `User-Agent` header (Node/Workers/Bun/Deno —\n * browsers silently ignore the value). */\n userAgent?: string;\n /** Injectable sleep implementation for the retry loop's inter-attempt\n * pause. Exists for tests that need deterministic, zero-delay retries\n * rather than real wall-clock backoff. Production code should leave\n * this unset to use the default exponential backoff with jitter.\n * @internal */\n sleepImpl?: (ms: number, signal?: AbortSignal) => Promise<void>;\n /** Inject a sink for SDK deprecation warnings. Defaults to\n * `console.warn`. Pass your logger's `warn` to route SDK signals into\n * the rest of your observability stack, or pass `() => {}` to\n * suppress them. The SDK uses this ONLY for developer-visible\n * deprecation notices triggered by `Deprecation` / `Sunset` response\n * headers — never for runtime errors. */\n warn?: (...args: unknown[]) => void;\n}\n\n/** Public-key auth: browser-safe path. The key is fingerprinted to a game\n * on the server side via `pk_<gameSlug>_<base62>`. */\nexport type PublicKeyConfig = BaseConfig & {\n publicKey: string;\n secretKey?: never;\n};\n\n/** Secret-key auth: server-side HMAC. A single self-contained token of the\n * shape `sk_live_<keyId>_<random>`. The SDK parses the keyId out and uses\n * the whole string as the HMAC key. One value to copy, one to manage —\n * matches Stripe's design and the public-key client's single-string shape.\n *\n * Past versions of the SDK took `{ id, secret }` separately. That was an\n * unnecessary cognitive tax — the id was always derivable from a properly-\n * formatted secret. v0.1.0-next.2+ takes the single-string form. */\nexport type SecretKeyConfig = BaseConfig & {\n secretKey: string;\n publicKey?: never;\n};\n\n/** The top-level config type. The union is open for additional auth modes\n * in future major releases. */\nexport type ScorezillaConfig = PublicKeyConfig | SecretKeyConfig;\n\n/**\n * Internal post-validation shape. The client layer reads from this — every\n * field is non-optional with defaults applied, and `auth` is a clean\n * discriminated union (no leftover `publicKey?: never` cruft).\n */\nexport interface ResolvedConfig {\n readonly baseUrl: string;\n readonly fetch: FetchImpl | undefined;\n readonly timeoutMs: number | undefined;\n readonly maxRetries: number | undefined;\n readonly sleepImpl: ((ms: number, signal?: AbortSignal) => Promise<void>) | undefined;\n readonly warn: ((...args: unknown[]) => void) | undefined;\n readonly userAgent: string | undefined;\n readonly auth:\n | { kind: 'public'; key: string }\n | { kind: 'secret'; keyId: string; secret: string };\n}\n\n/**\n * Validate a `ScorezillaConfig` and return a normalized {@link ResolvedConfig}.\n *\n * Throws a plain `Error` (not `ScorezillaError`) on misuse — these are\n * caller bugs, not API failures, and shouldn't be confused with the\n * runtime error class.\n */\nexport function validateConfig(cfg: ScorezillaConfig): ResolvedConfig {\n if (!cfg || typeof cfg !== 'object') {\n throw new Error('scorezilla: config must be an object with publicKey or secretKey');\n }\n\n const hasPublic = 'publicKey' in cfg && cfg.publicKey !== undefined;\n const hasSecret = 'secretKey' in cfg && cfg.secretKey !== undefined;\n\n // Defensive runtime checks for consumers using `as any` or plain JS.\n if (hasPublic && hasSecret) {\n throw new Error('scorezilla: config must not contain both publicKey and secretKey');\n }\n if (!hasPublic && !hasSecret) {\n throw new Error('scorezilla: config must contain either publicKey or secretKey');\n }\n\n let auth: ResolvedConfig['auth'];\n if (hasPublic) {\n auth = { kind: 'public', key: validatePublicKeyValue((cfg as PublicKeyConfig).publicKey) };\n } else {\n const resolved = validateSecretKey(cfg as SecretKeyConfig);\n auth = { kind: 'secret', keyId: resolved.keyId, secret: resolved.secret };\n }\n\n const baseUrlRaw = cfg.baseUrl ?? DEFAULT_BASE_URL;\n if (typeof baseUrlRaw !== 'string' || baseUrlRaw.length === 0) {\n throw new Error('scorezilla: baseUrl must be a non-empty string when provided');\n }\n\n return {\n baseUrl: baseUrlRaw.replace(/\\/+$/, ''),\n fetch: cfg.fetch,\n timeoutMs: cfg.timeoutMs,\n maxRetries: cfg.maxRetries,\n sleepImpl: cfg.sleepImpl,\n warn: cfg.warn,\n userAgent: cfg.userAgent,\n auth,\n };\n}\n\n/**\n * Validate a `publicKey` string and return it. Throws a plain `Error` on\n * misuse — caller bug, not an API failure.\n *\n * Never echo any characters of the supplied key in the error message —\n * if a developer paste-mistakes a `sk_live_*` secret here, the previous\n * `pk.slice(0, 12)` would have leaked 12 chars of the secret to whatever\n * log aggregator catches the Error. Report only the shape.\n */\nfunction validatePublicKeyValue(pk: unknown): string {\n if (typeof pk !== 'string' || !PUBLIC_KEY_PATTERN.test(pk)) {\n const shape = typeof pk === 'string' ? `string of length ${pk.length}` : typeof pk;\n throw new Error(\n `scorezilla: publicKey must match ${PUBLIC_KEY_PATTERN.toString()} (got: ${shape})`,\n );\n }\n return pk;\n}\n\n/** Exact shape of the new secret-key format:\n *\n * `sk_live_<keyId>_<random>`\n *\n * - `<keyId>` is a UUID v4 (hyphenated, 36 chars). Used by the API for\n * row lookup and as the `keyId=` parameter in HMAC Authorization\n * headers. Non-sensitive; appears in logs and audit trails.\n * - `<random>` is a base62-encoded suffix from the operator dashboard's\n * issuance flow (~32 chars). The HMAC key is the WHOLE plaintext\n * string, so changing only the prefix doesn't weaken anything.\n *\n * Two-field `{ id, secret }` configs from pre-next.2 are NOT accepted —\n * `validateSecretKey` requires a single string.\n */\nexport const SECRET_KEY_PATTERN =\n /^sk_live_([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})_[A-Za-z0-9]+$/;\n\n/**\n * Validate a {@link SecretKeyConfig} and return a normalized `{ keyId,\n * secret }`. The input is a single self-contained string; we parse the\n * keyId out of it via {@link SECRET_KEY_PATTERN}.\n *\n * Throws a plain `Error` on misuse. The error never echoes any characters\n * of the secret — only the shape and prefix sanity, just like the\n * public-key validator.\n *\n * @stability internal — exposed for `scorezilla/server`'s constructor\n * and unit tests. Not part of the public API.\n */\nexport function validateSecretKey(cfg: SecretKeyConfig): { keyId: string; secret: string } {\n if (!cfg || typeof cfg !== 'object') {\n throw new Error('scorezilla/server: config must be an object with a secretKey field');\n }\n const sk = cfg.secretKey;\n if (typeof sk !== 'string') {\n throw new Error(\n `scorezilla/server: secretKey must be a single string of the shape ${SECRET_KEY_PREFIX}<keyId>_<random> (got: ${typeof sk})`,\n );\n }\n const match = SECRET_KEY_PATTERN.exec(sk);\n if (!match) {\n // Never echo the value. A typo'd publicKey paste or a pre-next.2\n // `{ id, secret }` object lands here.\n const shape = `string of length ${sk.length}`;\n throw new Error(\n `scorezilla/server: secretKey must match ${SECRET_KEY_PATTERN.toString()} ` +\n `(got: ${shape}). v0.1.0-next.2 switched to a single-token format — if you have a pre-next.2 ` +\n `pair, issue a fresh key in the dashboard to upgrade.`,\n );\n }\n return { keyId: match[1]!, secret: sk };\n}\n","/**\n * HMAC-SHA256 request signing for the secret-key path (`scorezilla/server`).\n *\n * The SDK side here MUST stay in lockstep with the API's verifier\n * (`apps/api/src/auth/hmac.ts` in the monorepo). The contract:\n *\n * Wire format\n * -----------\n * Authorization: Scorezilla-HMAC-SHA256 keyId=<id>, ts=<unix-seconds>,\n * nonce=<random>, signature=<base64url>\n *\n * Canonical signing string (newline-separated, 5 lines)\n * -----------------------------------------------------\n * {ts}\\n{nonce}\\n{METHOD}\\n{pathAndQuery}\\n{sha256_hex(body)}\n *\n * Algorithm: HMAC-SHA256 of the signing string with the raw secret\n * bytes as the key. Output: base64url (no padding).\n *\n * Everything is built on WebCrypto (`crypto.subtle`) — works in browsers,\n * Node ≥ 20, Workers, Bun, and Deno without a Node-only dependency.\n *\n * Stability: this module is internal — exported only for tests and the\n * server adapter. Consumers should always use `Scorezilla` from\n * `scorezilla/server` (which calls into here).\n */\n\nconst enc = new TextEncoder();\n\n/** Auth-scheme prefix. Mirrors the API's `AUTH_SCHEME` constant exactly. */\nexport const HMAC_AUTH_SCHEME = 'Scorezilla-HMAC-SHA256';\n\n/** Minimum acceptable length for a caller-supplied nonce. The default\n * path uses `crypto.randomUUID()` which is 36 characters; injectable\n * nonces (test paths, advanced custom-flow consumers) must clear a\n * conservative floor so a misconfigured caller can't accidentally\n * emit a signed header with a weak or empty nonce. 16 characters is\n * the documented minimum and matches the server's lower bound for\n * acceptable replay-protection entropy. */\nconst MIN_NONCE_LENGTH = 16;\n\n/** Latest signing-string format version this SDK emits. The API verifier\n * also accepts v=1 (legacy, no host binding) during the rollout window —\n * see `apps/api/src/auth/hmac.ts` in the monorepo. */\nexport const HMAC_SIGNING_VERSION_LATEST = 2 as const;\n\n/**\n * Construct the canonical signing string. Pure — no I/O. Both sender\n * (this module) and verifier (the API) call this with the same inputs\n * and must produce identical output.\n *\n * `pathAndQuery` is signed verbatim. If the SDK ever URL-encodes path\n * segments differently than the server does, signatures will mismatch.\n *\n * `host` MUST be the host portion of the URL the request is being sent\n * to. It's lowercased here per RFC 9110 §4.2.4 (case-insensitive host\n * comparison). With v=2 (current default), `host` is the 4th line of\n * the canonical string and binds the signature to the target origin so\n * a signature minted against staging cannot replay against prod.\n *\n * `version` defaults to {@link HMAC_SIGNING_VERSION_LATEST}. v=1 (legacy,\n * pre-A-H4) omits `host` from the canonical string — kept for compat\n * tests; production callers should not pass v=1.\n */\nexport async function buildSigningString(\n method: string,\n pathAndQuery: string,\n ts: number,\n nonce: string,\n body: string,\n host: string,\n version: number = HMAC_SIGNING_VERSION_LATEST,\n): Promise<string> {\n const bodyHash = await sha256Hex(body);\n const upperMethod = method.toUpperCase();\n if (version === 1) {\n return `${ts}\\n${nonce}\\n${upperMethod}\\n${pathAndQuery}\\n${bodyHash}`;\n }\n return `${ts}\\n${nonce}\\n${upperMethod}\\n${host.toLowerCase()}\\n${pathAndQuery}\\n${bodyHash}`;\n}\n\n/** HMAC-SHA-256 of `message` with `secret` (UTF-8 encoded), base64url. */\nexport async function hmacSha256B64u(secret: string, message: string): Promise<string> {\n const key = await crypto.subtle.importKey(\n 'raw',\n enc.encode(secret),\n { name: 'HMAC', hash: 'SHA-256' },\n false,\n ['sign'],\n );\n const sig = await crypto.subtle.sign('HMAC', key, enc.encode(message));\n return base64UrlEncode(new Uint8Array(sig));\n}\n\n/** SHA-256 of `message` (UTF-8), lowercase hex. Used inside the signing\n * string to hash the request body. */\nexport async function sha256Hex(message: string): Promise<string> {\n const digest = await crypto.subtle.digest('SHA-256', enc.encode(message));\n return Array.from(new Uint8Array(digest))\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('');\n}\n\n/**\n * Build the `Authorization` header value for a single request.\n *\n * Each call generates a fresh `ts` and `nonce`. Retries MUST call this\n * again — reusing a (ts, nonce) is what the server's replay protection\n * rejects.\n *\n * Emits v=2 by default (host-bound). The API verifier still accepts v=1\n * (no host binding) for pre-A-H4 SDK builds during the rollout window;\n * see `apps/api/src/auth/hmac.ts:parseAuthHeader`. New code paths should\n * use v=2 — the v=1 escape hatch exists only for legacy interop.\n *\n * @returns the full header value (including the scheme prefix)\n */\nexport async function buildHmacAuthHeader(args: {\n keyId: string;\n secret: string;\n method: string;\n pathAndQuery: string;\n /** Host portion of the request URL (e.g. `new URL(baseUrl).host`). v=2\n * signatures bind to this; v=1 ignores it. */\n host: string;\n body: string;\n /** Injectable for tests; defaults to `Math.floor(Date.now() / 1000)`. */\n nowSeconds?: number;\n /** Injectable for tests; defaults to `crypto.randomUUID()`. */\n nonce?: string;\n /** Signing-string version. Defaults to {@link HMAC_SIGNING_VERSION_LATEST}.\n * v=1 omits both the host from the canonical string AND the `v=` param\n * from the header (for byte-for-byte parity with pre-A-H4 SDKs). */\n version?: 1 | 2;\n}): Promise<string> {\n const ts = args.nowSeconds ?? Math.floor(Date.now() / 1000);\n // If a nonce was injected, validate it. The default path generates a\n // 36-char UUIDv4 which trivially clears the floor — only test or\n // advanced-custom-flow callers ever supply their own. Guarding here\n // means a misconfigured caller can't accidentally sign with an empty\n // or weak nonce that the server's replay protection might still\n // accept (`hmac.ts` on the API side has no minimum-length check).\n if (args.nonce !== undefined) {\n if (typeof args.nonce !== 'string' || args.nonce.length < MIN_NONCE_LENGTH) {\n throw new Error(\n `scorezilla: nonce must be a string of at least ${MIN_NONCE_LENGTH} characters; ` +\n 'use the default (UUIDv4 via crypto.randomUUID) unless you have a specific reason.',\n );\n }\n }\n const nonce = args.nonce ?? generateNonce();\n const version = args.version ?? HMAC_SIGNING_VERSION_LATEST;\n const signingString = await buildSigningString(\n args.method,\n args.pathAndQuery,\n ts,\n nonce,\n args.body,\n args.host,\n version,\n );\n const signature = await hmacSha256B64u(args.secret, signingString);\n // v=1: omit the `v=` param (back-compat byte parity).\n // v=2 (default): append `v=2` so the verifier knows to include host in\n // the canonical string. Future versions follow the same pattern.\n const vParam = version === 1 ? '' : `, v=${version}`;\n return `${HMAC_AUTH_SCHEME} keyId=${args.keyId}, ts=${ts}, nonce=${nonce}, signature=${signature}${vParam}`;\n}\n\n/**\n * Cryptographically-random nonce. The server enforces no-reuse within a\n * 10-minute window (per keyId), so a fresh random value per request is\n * required for retry correctness — if the same (keyId, nonce) pair lands\n * twice the second is rejected as a replay.\n */\nexport function generateNonce(): string {\n const c = (globalThis as { crypto?: { randomUUID?: () => string } }).crypto;\n if (!c || typeof c.randomUUID !== 'function') {\n // Same posture as `generateIdempotencyKey` in retry.ts — runtime\n // misconfiguration, surface a typed error consumers can branch on.\n throw new Error(\n 'scorezilla: globalThis.crypto.randomUUID is unavailable. ' +\n 'The HMAC server adapter requires Node ≥ 20 or a modern runtime.',\n );\n }\n return c.randomUUID();\n}\n\n/** URL-safe base64 without padding. Matches the API's `base64UrlEncode`. */\nexport function base64UrlEncode(bytes: Uint8Array): string {\n let bin = '';\n for (const b of bytes) bin += String.fromCharCode(b);\n return btoa(bin).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '');\n}\n","/**\n * URL path builders for the Scorezilla API at `/v1`.\n *\n * Every helper:\n * • URL-encodes segments via `encodeURIComponent` (boardIds and\n * playerIds may contain `/`, `#`, `?`, etc.).\n * • Rejects empty or non-string segments with a thrown `Error` (caller\n * bug, not an API failure — `ScorezillaError` is reserved for\n * network-layer outcomes).\n *\n * Each returned path:\n * • Starts with `/v1/`\n * • Has no trailing slash\n * • Includes the query string (if any) joined with `?`\n *\n * The transport's `buildUrl` strips any trailing slash from `baseUrl`\n * before joining, so the two never collide into `//`.\n */\n\nfunction encodeSegment(value: unknown, label: 'boardId' | 'playerId' | 'gameId'): string {\n if (typeof value !== 'string' || value.length === 0) {\n throw new Error(`scorezilla: ${label} must be a non-empty string`);\n }\n return encodeURIComponent(value);\n}\n\nfunction buildQueryString(params: Record<string, number | undefined>): string {\n const usp = new URLSearchParams();\n for (const [k, v] of Object.entries(params)) {\n if (v !== undefined) usp.set(k, String(v));\n }\n const qs = usp.toString();\n return qs.length > 0 ? `?${qs}` : '';\n}\n\n/** `POST /v1/boards/:boardId/scores` */\nexport function submitScorePath(boardId: string): string {\n return `/v1/boards/${encodeSegment(boardId, 'boardId')}/scores`;\n}\n\n/** `POST /v1/secure/scores` — the HMAC-signed submission endpoint used by\n * the `scorezilla/server` adapter. The boardId moves into the request\n * body rather than the path: every submission here signs over the body\n * hash, so the API resolves the board from the body and authorizes via\n * the verified keyId in the Authorization header. */\nexport function submitScoreSecurePath(): string {\n return '/v1/secure/scores';\n}\n\n/** Options for {@link getLeaderboardPath}. */\nexport interface LeaderboardQuery {\n /** Number of entries to return (the API caps at 1000). Defaults server-side to 100. */\n top?: number;\n /** Offset into the sorted board (the API caps at 1_000_000). Defaults server-side to 0. */\n offset?: number;\n}\n\n/** `GET /v1/boards/:boardId/leaderboard?top=&offset=` */\nexport function getLeaderboardPath(boardId: string, q?: LeaderboardQuery): string {\n return (\n `/v1/boards/${encodeSegment(boardId, 'boardId')}/leaderboard` +\n buildQueryString({ top: q?.top, offset: q?.offset })\n );\n}\n\n/** `GET /v1/boards/:boardId/players/:playerId/rank` */\nexport function getPlayerRankPath(boardId: string, playerId: string): string {\n return `/v1/boards/${encodeSegment(boardId, 'boardId')}/players/${encodeSegment(playerId, 'playerId')}/rank`;\n}\n\n/** Options for {@link getWindowAroundPath}. */\nexport interface WindowAroundQuery {\n /** Entries strictly above the player (the API caps at 100). Defaults server-side to 5. */\n before?: number;\n /** Entries strictly below the player (the API caps at 100). Defaults server-side to 5. */\n after?: number;\n}\n\n/** `GET /v1/boards/:boardId/players/:playerId/window?before=&after=` */\nexport function getWindowAroundPath(\n boardId: string,\n playerId: string,\n q?: WindowAroundQuery,\n): string {\n return (\n `/v1/boards/${encodeSegment(boardId, 'boardId')}/players/${encodeSegment(playerId, 'playerId')}/window` +\n buildQueryString({ before: q?.before, after: q?.after })\n );\n}\n","/**\n * SDK error type.\n *\n * Every non-2xx API response is normalized into a `ScorezillaError` instance\n * by the transport layer. Network failures and timeouts surface as the same\n * class (with `status: 0`) so callers have a single error type to catch.\n *\n * **Invariant — consumers MUST branch on `code` (and optionally `reason`),\n * never on `message`.** The English-language `message` is for operator\n * logging only and is explicitly **not** part of the SemVer contract; a\n * minor release MAY reword any message. Machine logic that depends on\n * message text will break silently across upgrades.\n */\nimport type {\n ApiError,\n BillingTier,\n OutOfBoundsReason,\n ScorezillaErrorCode,\n UsageCapReason,\n} from './types';\n\n/** Maximum length, in characters, that an error `message` may hold.\n *\n * Defense against a future server-side change that includes caller-controlled\n * strings in error messages — e.g., echoing back a malformed `playerId` of\n * arbitrary length. Capping at 500 keeps the thrown error printable in\n * devtools and bounded in memory usage. */\nexport const MESSAGE_MAX_CHARS = 500;\n\n/** Suffix appended when a server-supplied message exceeds {@link MESSAGE_MAX_CHARS}. */\nexport const TRUNCATION_SUFFIX = '… [truncated]';\n\n/** Sentinel `status` for network errors / timeouts (no HTTP response was received). */\nexport const STATUS_NETWORK_ERROR = 0;\n\nfunction truncateMessage(raw: unknown): string {\n if (typeof raw !== 'string') return '';\n if (raw.length <= MESSAGE_MAX_CHARS) return raw;\n // Safety against a future tweak that makes TRUNCATION_SUFFIX longer than\n // the cap — `slice(0, -n)` would silently chop from the end instead of\n // from the beginning, masking the bug. `Math.max(0, …)` keeps the\n // truncation honest.\n const sliceEnd = Math.max(0, MESSAGE_MAX_CHARS - TRUNCATION_SUFFIX.length);\n return raw.slice(0, sliceEnd) + TRUNCATION_SUFFIX;\n}\n\n/**\n * Truncate a server-supplied string field that lives on `ScorezillaError`\n * but isn't `message`. Returns `undefined` for non-strings so the field\n * type stays `string | undefined` rather than being coerced to `''`.\n *\n * Defense-in-depth: even though current API contracts treat these as small\n * identifiers/classifiers, the SDK shouldn't trust the server to keep them\n * bounded — a regression that echoes back caller-controlled input would\n * otherwise land unbounded strings in the thrown error object.\n */\nfunction truncateField(raw: unknown): string | undefined {\n if (typeof raw !== 'string') return undefined;\n if (raw.length <= MESSAGE_MAX_CHARS) return raw;\n const sliceEnd = Math.max(0, MESSAGE_MAX_CHARS - TRUNCATION_SUFFIX.length);\n return raw.slice(0, sliceEnd) + TRUNCATION_SUFFIX;\n}\n\n/**\n * Options for {@link ScorezillaError.from}.\n *\n * The fields mirror what's available after a fetch round-trip: the HTTP\n * status, the parsed JSON body (if any), the request ID from\n * `X-Request-Id`, and an optional `cause` for the underlying\n * network/abort error.\n */\nexport interface ScorezillaErrorFromInit {\n status: number;\n body?: ApiError | undefined;\n requestId?: string | undefined;\n cause?: unknown;\n}\n\n/**\n * Thrown by the SDK for every failure path — non-2xx responses, network\n * errors, aborts, and timeouts.\n *\n * Cross-realm `instanceof` is guaranteed: the class sets `Error.prototype`\n * explicitly so checks survive iframe / worker boundaries.\n *\n * @example\n * ```ts\n * try {\n * await sz.submitScore({ boardId, playerId, score });\n * } catch (e) {\n * if (!(e instanceof ScorezillaError)) throw e;\n *\n * if (e.isRateLimited()) {\n * await sleep((e.retryAfter ?? 30) * 1000);\n * return retry();\n * }\n * if (e.code === 'out_of_bounds') {\n * console.warn(`Score crosses ${e.reason} bound (limit ${e.bound})`);\n * return;\n * }\n * if (e.isAuth()) throw new Error('SDK misconfigured — bad publicKey');\n *\n * // Anything else: surface to your reporter with requestId for support.\n * console.error(`Scorezilla ${e.code} (${e.status}) — request ${e.requestId}`);\n * throw e;\n * }\n * ```\n *\n * @since 0.1.0\n * @stability stable\n */\nexport class ScorezillaError extends Error {\n /** HTTP status of the response, or {@link STATUS_NETWORK_ERROR} (0) for\n * network / abort / timeout. */\n readonly status: number;\n\n /** Machine-stable error code from the API. Open union — see\n * {@link ScorezillaErrorCode}. For network errors, this is `'network_error'`;\n * for aborts, `'aborted'`; for timeouts, `'timeout'`. */\n readonly code: ScorezillaErrorCode;\n\n /** Sub-classifier — present on:\n * - `out_of_bounds`: `'below_min' | 'above_max'`\n * - `usage_cap_exceeded`: `'over_cap' | 'suspended'`\n * and possibly other codes in future minor releases. */\n readonly reason: OutOfBoundsReason | UsageCapReason | string | undefined;\n\n /** Seconds — present on `rate_limited`. Honored by the transport's retry\n * policy (Step 2.4). */\n readonly retryAfter: number | undefined;\n\n /** Server-issued request ID, lifted from the `X-Request-Id` response\n * header. Pass this to support when filing bugs. */\n readonly requestId: string | undefined;\n\n /** The bound value crossed on `out_of_bounds`. */\n readonly bound: number | undefined;\n\n /** Which rate-limit layer fired on `rate_limited`. */\n readonly layer: string | undefined;\n\n /** Tenant's billing tier — present on `usage_cap_exceeded`. */\n readonly tier: BillingTier | undefined;\n\n /** The cap value crossed on `usage_cap_exceeded`. `0` indicates a\n * suspended tenant. `undefined` on all other error codes. */\n readonly cap: number | undefined;\n\n /** The post-increment submit count on `usage_cap_exceeded`. Always\n * `> cap` when `reason === 'over_cap'`. */\n readonly count: number | undefined;\n\n /** The period the count belongs to on `usage_cap_exceeded`, in `YYYY-MM`\n * UTC form. */\n readonly period: string | undefined;\n\n /** ISO-8601 timestamp of midnight UTC on the 1st of the next month —\n * the counter's natural reset point on `usage_cap_exceeded`. */\n readonly resetsAt: string | undefined;\n\n /** The underlying cause (e.g., a `TypeError: fetch failed`) for\n * network/abort/timeout paths. `undefined` when the error came from a\n * successfully-parsed API error body. */\n override readonly cause: unknown;\n\n constructor(\n message: string,\n init: {\n status: number;\n code: ScorezillaErrorCode;\n reason?: string | undefined;\n retryAfter?: number | undefined;\n requestId?: string | undefined;\n bound?: number | undefined;\n layer?: string | undefined;\n tier?: BillingTier | undefined;\n cap?: number | undefined;\n count?: number | undefined;\n period?: string | undefined;\n resetsAt?: string | undefined;\n cause?: unknown;\n },\n ) {\n super(truncateMessage(message));\n this.name = 'ScorezillaError';\n this.status = init.status;\n this.code = init.code;\n // String fields from the server side are length-capped. The cap is\n // generous — `MESSAGE_MAX_CHARS` is well above any legitimate\n // identifier or classifier — but defends against a future server\n // regression that echoes back caller-controlled input into these\n // fields. `requestId` typically a UUID; `reason`/`layer` typically a\n // short enum-like string; all three should sit far under the cap.\n this.reason = truncateField(init.reason);\n this.retryAfter = init.retryAfter;\n this.requestId = truncateField(init.requestId);\n this.bound = init.bound;\n this.layer = truncateField(init.layer);\n // Usage-cap fields. `tier` is a short enum-like string; field-trunc\n // is defense-in-depth in case the server ever leaks a longer value\n // through. The numeric fields don't need truncation.\n this.tier = truncateField(init.tier) as BillingTier | undefined;\n this.cap = init.cap;\n this.count = init.count;\n this.period = truncateField(init.period);\n this.resetsAt = truncateField(init.resetsAt);\n this.cause = init.cause;\n\n // Cross-realm instanceof: explicitly set the prototype. Without this,\n // an instance of ScorezillaError thrown in one realm (e.g., a worker)\n // and caught in another (the main thread) wouldn't satisfy\n // `e instanceof ScorezillaError` because the constructor lookup\n // crosses the realm boundary.\n Object.setPrototypeOf(this, ScorezillaError.prototype);\n\n // V8 stack capture — omits the constructor frame for cleaner traces.\n // No-op on engines without `captureStackTrace` (Safari, older Firefox).\n if (\n typeof (Error as unknown as { captureStackTrace?: unknown }).captureStackTrace === 'function'\n ) {\n (\n Error as unknown as {\n captureStackTrace: (target: object, ctor: unknown) => void;\n }\n ).captureStackTrace(this, ScorezillaError);\n }\n }\n\n // ─── Sub-message helpers ─────────────────────────────────────────────\n // Stable wrappers over the `code` discriminator so consumers can write\n // `if (err.isRateLimited())` instead of memorizing the code spelling.\n\n /** `true` when this error is a 429 / `rate_limited`. */\n isRateLimited(): boolean {\n return this.code === 'rate_limited';\n }\n\n /**\n * `true` when this error is a 402 / `usage_cap_exceeded`. The tenant\n * has either hit their tier's monthly submit cap (`reason ===\n * 'over_cap'`) or is suspended (`reason === 'suspended'`).\n *\n * Consumers SHOULD NOT auto-retry on this error — the cap doesn't lift\n * until `resetsAt`. Surface to the developer with an upgrade prompt\n * (over_cap) or contact-support message (suspended).\n */\n isUsageCapExceeded(): boolean {\n return this.code === 'usage_cap_exceeded';\n }\n\n /** `true` when this error is a 402 + reason 'suspended' (vs over-cap). */\n isSuspended(): boolean {\n return this.code === 'usage_cap_exceeded' && this.reason === 'suspended';\n }\n\n /** `true` when this error is a 401 / `unauthorized` (or 403 / `forbidden`). */\n isAuth(): boolean {\n return this.code === 'unauthorized' || this.code === 'forbidden';\n }\n\n /** `true` when this error is a 404 / `not_found`. */\n isNotFound(): boolean {\n return this.code === 'not_found';\n }\n\n /** `true` when this error is a 422 / `out_of_bounds` (score below/above board limit). */\n isOutOfBounds(): boolean {\n return this.code === 'out_of_bounds';\n }\n\n /** `true` for the SDK's retryable conditions: pure network errors, 5xx, and\n * 429. Deliberately excludes `timeout` and `aborted` — those are caller-\n * observable terminal states, not transient. Aligned with `shouldRetryError`\n * in `retry.ts` so a consumer mirroring the SDK's retry policy gets the\n * same answer the transport does. */\n isTransient(): boolean {\n if (this.code === 'network_error') return true;\n if (this.status >= 500 && this.status < 600) return true;\n return this.isRateLimited();\n }\n\n /** `true` when this error is a 409 / `conflict` (idempotency-key conflict\n * on retry). */\n isConflict(): boolean {\n return this.code === 'conflict';\n }\n\n // ─── Factory ─────────────────────────────────────────────────────────\n\n /**\n * Build a `ScorezillaError` from a fetch round-trip outcome.\n *\n * Prefer this over `new ScorezillaError(...)` from the transport layer —\n * it does the mapping from API response shape to error fields in one\n * place, so future fields like `correlationId` get added once here.\n *\n * @param init - status, optional parsed body, optional requestId, optional cause\n */\n static from(init: ScorezillaErrorFromInit): ScorezillaError {\n const { status, body, requestId, cause } = init;\n\n // If the body parsed as an API error, use its fields. Otherwise, fall\n // back to status-derived defaults so the SDK always returns a\n // typed error even when the server returns garbage.\n if (body && body.ok === false && typeof body.error === 'string') {\n return new ScorezillaError(body.message ?? `Request failed: ${body.error}`, {\n status,\n code: body.error,\n reason: body.reason,\n retryAfter: body.retryAfter,\n bound: body.bound,\n layer: body.layer,\n // Usage-cap fields from `ApiError` (populated by the server on\n // 402 responses; undefined on other errors).\n tier: body.tier,\n cap: body.cap,\n count: body.count,\n period: body.period,\n resetsAt: body.resetsAt,\n requestId,\n cause,\n });\n }\n\n // No usable body — synthesize from status code.\n const code = codeForStatus(status);\n return new ScorezillaError(`Request failed with status ${status}`, {\n status,\n code,\n requestId,\n cause,\n });\n }\n\n /**\n * Build a `ScorezillaError` for a transport-level failure (no HTTP\n * response received): network error, abort, or timeout.\n */\n static network(message: string, cause: unknown): ScorezillaError {\n return new ScorezillaError(message, {\n status: STATUS_NETWORK_ERROR,\n code: 'network_error',\n cause,\n });\n }\n\n /** Build a `ScorezillaError` for an `AbortSignal`-triggered cancellation. */\n static aborted(cause: unknown): ScorezillaError {\n return new ScorezillaError('Request aborted', {\n status: STATUS_NETWORK_ERROR,\n code: 'aborted',\n cause,\n });\n }\n\n /** Build a `ScorezillaError` for a request that exceeded its timeout budget. */\n static timeout(timeoutMs: number): ScorezillaError {\n return new ScorezillaError(`Request timed out after ${timeoutMs}ms`, {\n status: STATUS_NETWORK_ERROR,\n code: 'timeout',\n });\n }\n}\n\n/** Default `code` for a given HTTP status when the body didn't parse as ApiError. */\nfunction codeForStatus(status: number): ScorezillaErrorCode {\n if (status === 401) return 'unauthorized';\n if (status === 402) return 'usage_cap_exceeded';\n if (status === 403) return 'forbidden';\n if (status === 404) return 'not_found';\n if (status === 409) return 'conflict';\n if (status === 422) return 'out_of_bounds';\n if (status === 429) return 'rate_limited';\n if (status >= 500) return 'internal_error';\n if (status >= 400) return 'invalid_input';\n return 'internal_error';\n}\n","/**\n * Retry + backoff helpers used by the HTTP transport (src/transport.ts).\n *\n * Pure where possible — `nextDelay` and the predicate functions take no\n * side effects, so they're unit-testable without time mocks. The only\n * impure helpers are {@link sleep} and {@link generateIdempotencyKey},\n * both isolated so callers can swap them in tests.\n */\n\nimport { ScorezillaError } from './errors';\n\n/** Default cap on retry attempts (does not include the initial attempt). */\nexport const DEFAULT_MAX_RETRIES = 2;\n\n/** Base delay for exponential backoff, in milliseconds. */\nexport const BASE_DELAY_MS = 200;\n\n/** Hard ceiling on per-attempt backoff, in milliseconds. */\nexport const MAX_DELAY_MS = 4_000;\n\n/**\n * Maximum `Retry-After` value (in seconds) the SDK will honor. A misbehaving\n * server returning `Retry-After: 86400` won't park the caller for a day —\n * we treat anything over this as transient and fall back to exponential\n * backoff. The transport surfaces a `ScorezillaError` on the next attempt\n * if the server still rejects.\n */\nexport const MAX_RETRY_AFTER_SEC = 30;\n\n/**\n * Pure: compute the delay (in milliseconds) before the next retry.\n *\n * The algorithm is \"decorrelated exponential\" backoff: `BASE_DELAY_MS *\n * 2^attempt` capped at `MAX_DELAY_MS`, multiplied by a jitter factor in\n * `[0.5, 1.0]` to avoid thundering-herd retries from clients that all\n * receive the same 5xx at the same moment.\n *\n * If `retryAfterSec` is provided and `<= MAX_RETRY_AFTER_SEC`, that wins\n * over the exponential schedule (the server has told us a specific wait).\n * Values over the cap are ignored — we fall back to exponential.\n *\n * @param attempt Zero-based retry index (0 = first retry, 1 = second, …).\n * @param retryAfterSec `Retry-After` header value in seconds, if any.\n * @param random Injectable RNG for jitter — defaults to `Math.random`.\n * Pass a deterministic stub in tests.\n */\nexport function nextDelay(\n attempt: number,\n retryAfterSec: number | undefined,\n random: () => number = Math.random,\n): number {\n if (\n typeof retryAfterSec === 'number' &&\n Number.isFinite(retryAfterSec) &&\n retryAfterSec >= 0 &&\n retryAfterSec <= MAX_RETRY_AFTER_SEC\n ) {\n return Math.round(retryAfterSec * 1000);\n }\n\n const exponential = Math.min(BASE_DELAY_MS * 2 ** attempt, MAX_DELAY_MS);\n const jitterFactor = 0.5 + random() * 0.5; // [0.5, 1.0]\n return Math.round(exponential * jitterFactor);\n}\n\n/**\n * Pure: should an HTTP status code trigger a retry?\n *\n * 429 (rate limited) and 5xx (server error) are retryable. 4xx other than\n * 429 are caller errors and never retried — they won't succeed on\n * re-attempt and would waste budget.\n */\nexport function shouldRetryStatus(status: number): boolean {\n if (status === 429) return true;\n if (status >= 500 && status < 600) return true;\n return false;\n}\n\n/**\n * Pure: should a thrown error trigger a retry?\n *\n * A network-level failure (no HTTP response) is retryable. Timeouts are\n * NOT retried by default — the caller set the budget intentionally; retrying\n * would extend it past their intent. Aborts are never retried (signal was\n * explicit).\n */\nexport function shouldRetryError(err: unknown): boolean {\n if (err instanceof ScorezillaError) {\n return err.code === 'network_error';\n }\n return false;\n}\n\n/**\n * Generate an idempotency key for a POST request.\n *\n * Note: the workplan refers to \"UUID v7\" but `crypto.randomUUID()` returns\n * v4 universally (Node 19+, all modern browsers, Workers, Bun, Deno). v4 is\n * the correct choice for an idempotency key — we need uniqueness, not\n * time-ordering. v7's time prefix offers no benefit for keys that live for\n * one request lifetime.\n *\n * Throws if `crypto.randomUUID` isn't available on the platform — that's\n * always a misconfiguration (the SDK declares Node ≥ 20 / modern browsers\n * in `engines`).\n */\nexport function generateIdempotencyKey(): string {\n const c = (globalThis as { crypto?: { randomUUID?: () => string } }).crypto;\n if (!c || typeof c.randomUUID !== 'function') {\n // Throw a `ScorezillaError`, not a plain `Error`. The documented catch\n // pattern in README.md is `if (!(e instanceof ScorezillaError)) throw e;` —\n // a plain `Error` here would escape that guard and bubble up as\n // unhandled. `code: 'internal_error'` is the right category: this is\n // a runtime misconfiguration, not an API failure.\n throw new ScorezillaError(\n 'scorezilla: globalThis.crypto.randomUUID is unavailable. ' +\n 'The SDK requires Node ≥ 20 or a modern browser. Check your runtime.',\n { status: 0, code: 'internal_error' },\n );\n }\n return c.randomUUID();\n}\n\n/**\n * Sleep for `ms` milliseconds. Aborts immediately if the provided\n * `AbortSignal` fires — the returned promise rejects with the signal's\n * `reason` so the transport can map it to {@link ScorezillaError.aborted}.\n *\n * The handler unhooks itself when the timer settles, so a long-lived\n * signal can be reused across many sleeps without leaking listeners.\n */\nexport function sleep(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise((resolve, reject) => {\n if (signal?.aborted) {\n reject(signal.reason ?? new DOMException('Aborted', 'AbortError'));\n return;\n }\n const timer = setTimeout(() => {\n signal?.removeEventListener('abort', onAbort);\n resolve();\n }, ms);\n const onAbort = (): void => {\n clearTimeout(timer);\n signal?.removeEventListener('abort', onAbort);\n reject(signal?.reason ?? new DOMException('Aborted', 'AbortError'));\n };\n signal?.addEventListener('abort', onAbort, { once: true });\n });\n}\n","/**\n * HTTP transport for the Scorezilla SDK.\n *\n * Single entry point — {@link request} — wraps `fetch` with the SDK's\n * cross-cutting concerns:\n * • JSON serialization / parsing\n * • Idempotency-Key on retried POSTs (same key reused across attempts)\n * • Retry loop with exponential backoff + jitter on 5xx / 429 / network\n * • `Retry-After` honored when ≤ {@link MAX_RETRY_AFTER_SEC}\n * • Combined AbortSignal: caller-supplied + per-call timeout budget\n * • Uniform {@link ScorezillaError} for every failure path\n *\n * The function is fully fetch-impl-injectable so it tests cleanly with a\n * stub. No Node-only APIs; runs in browsers, Node, Workers, Bun, Deno.\n */\n\nimport { ScorezillaError } from './errors';\nimport {\n DEFAULT_MAX_RETRIES,\n generateIdempotencyKey,\n nextDelay,\n shouldRetryError,\n shouldRetryStatus,\n sleep,\n} from './retry';\nimport type { ApiError, ApiResponse } from './types';\n\n/** Default per-request timeout budget in milliseconds. */\nexport const DEFAULT_TIMEOUT_MS = 30_000;\n\n/** HTTP methods the SDK issues. */\nexport type HttpMethod = 'GET' | 'POST' | 'DELETE';\n\n/** Minimal fetch shape — broader than `typeof fetch` so polyfills and\n * test stubs (`vi.fn()`, `node-fetch`, etc.) typecheck cleanly. */\nexport type FetchImpl = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;\n\n/** Options for {@link request}. */\nexport interface RequestOptions {\n /** Base URL — typically the API origin, no trailing slash. */\n baseUrl: string;\n /** Path with leading `/` — typically built via the helpers in `src/paths.ts`. */\n path: string;\n /** HTTP method. */\n method: HttpMethod;\n /** Request body to JSON-stringify. `undefined` → no body, no Content-Type. */\n body?: Record<string, unknown> | undefined;\n /** Extra headers to merge on top of the SDK's defaults. The public-key\n * client passes a static `Authorization: Bearer pk_*` here. Leave\n * `Authorization` unset when using `signRequest` — the per-attempt\n * hook owns that header. */\n headers?: Record<string, string> | undefined;\n /** Per-attempt request-signing hook. Called fresh on every fetch attempt\n * (including each retry) with the canonicalized method, path-and-query,\n * and body, returning the `Authorization` header value.\n *\n * This is what the HMAC server adapter uses: each attempt needs a fresh\n * timestamp + nonce, so a static header would burn replay-protection\n * budget. The public-key client doesn't pass this — it uses `headers`\n * with a static Bearer token instead. Mutually exclusive in practice. */\n signRequest?:\n | ((args: { method: HttpMethod; pathAndQuery: string; body: string }) => Promise<string>)\n | undefined;\n /** Injectable fetch — defaults to `globalThis.fetch`. */\n fetchImpl?: FetchImpl | undefined;\n /** Injectable warn sink for deprecation notices. Defaults to\n * `console.warn`. Pass a function to route SDK warnings into your\n * logger of choice, or pass `() => {}` to suppress them entirely.\n * At million-integration scale, embedders shouldn't have to\n * console-filter our deprecation messages.\n *\n * Same signature as `console.warn`. The SDK never calls\n * `warnImpl` for anything other than developer-visible deprecations. */\n warnImpl?: ((...args: unknown[]) => void) | undefined;\n /** Caller-supplied AbortSignal — composed with the SDK's internal timeout signal. */\n signal?: AbortSignal | undefined;\n /** Per-request timeout in milliseconds. Defaults to {@link DEFAULT_TIMEOUT_MS}. */\n timeoutMs?: number | undefined;\n /** Retry policy overrides. */\n retry?:\n | {\n maxRetries?: number | undefined;\n /** Injectable RNG for jitter — used by tests for deterministic delays. */\n random?: (() => number) | undefined;\n /** Injectable sleep — used by tests to advance time without real waits. */\n sleepImpl?: ((ms: number, signal?: AbortSignal) => Promise<void>) | undefined;\n }\n | undefined;\n}\n\n/**\n * Make an HTTP request and return the parsed JSON body on success.\n *\n * Throws {@link ScorezillaError} on:\n * • non-2xx response (with status, code, reason, retryAfter, requestId)\n * • network failure (`code: 'network_error'`)\n * • timeout (`code: 'timeout'`)\n * • abort via caller's signal (`code: 'aborted'`)\n * • response JSON parsing failure (`code: 'invalid_json'`)\n *\n * @typeParam T - the per-route success payload shape — always an\n * `ApiSuccess<X> = { ok: true } & X`. The constraint enforces\n * that `parseJson`'s discriminator check applies to every\n * call site at compile time, with no escape hatch.\n */\nexport async function request<T extends { ok: true }>(opts: RequestOptions): Promise<T> {\n const fetchImpl: FetchImpl = opts.fetchImpl ?? (globalThis.fetch as FetchImpl);\n if (typeof fetchImpl !== 'function') {\n throw new Error(\n 'scorezilla: globalThis.fetch is unavailable. ' +\n 'Either upgrade your runtime (Node ≥ 20 has fetch built in) or pass `fetch: yourFetch` in the SDK config.',\n );\n }\n\n const url = buildUrl(opts.baseUrl, opts.path);\n const maxRetries = opts.retry?.maxRetries ?? DEFAULT_MAX_RETRIES;\n const random = opts.retry?.random ?? Math.random;\n const sleepImpl = opts.retry?.sleepImpl ?? sleep;\n const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {\n throw new Error(\n `scorezilla: timeoutMs must be a positive finite number (got ${String(timeoutMs)})`,\n );\n }\n\n // Wrapped retry sleep — if the caller's signal aborts during the inter-attempt\n // pause, the raw rejection (typically a DOMException) would otherwise leak\n // out of request() unwrapped. Normalize every abort path to a ScorezillaError.\n const retrySleep = async (delay: number): Promise<void> => {\n try {\n await sleepImpl(delay, opts.signal);\n } catch (cause) {\n throw ScorezillaError.aborted(cause);\n }\n };\n\n // Idempotency-Key is generated ONCE per logical request and reused across\n // all retry attempts. This makes server-side dedup (if/when added) safe:\n // the same logical write maps to one key, multiple network attempts.\n // GET / DELETE are already idempotent; no key needed.\n const idempotencyKey = opts.method === 'POST' ? generateIdempotencyKey() : null;\n\n let lastError: unknown;\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n const combined = combineSignalsWithTimeout(opts.signal, timeoutMs);\n\n // Cleanup is structural, not positional: a `try { … } finally { cleanup }`\n // wrapper guarantees the per-attempt signal+timer is detached on EVERY\n // exit path — return, throw, or `continue`. The earlier implementation\n // called `cleanup()` at two positional points (after fetch, in catch);\n // any future early-exit added between them would silently leak listeners\n // and timers on a long-lived caller signal. The current shape is\n // resilient to that class of edit.\n try {\n // Serialize the body ONCE per attempt — both the fetch and the\n // signRequest hook need identical bytes. Re-stringifying inside\n // the signer would be a subtle correctness hazard if Date.now /\n // any non-deterministic field ever crept into body construction.\n const bodyString = opts.body !== undefined ? JSON.stringify(opts.body) : '';\n\n // Headers + Authorization. The HMAC signer (if present) wins —\n // per-attempt fresh signing is the contract for that auth mode.\n // Path-and-query fed to the signer must match what the server\n // will see (`/v1/...?...`), without the baseUrl origin prefix.\n const perAttemptHeaders = { ...(opts.headers ?? {}) };\n if (opts.signRequest) {\n perAttemptHeaders.Authorization = await opts.signRequest({\n method: opts.method,\n pathAndQuery: opts.path,\n body: bodyString,\n });\n }\n const init: RequestInit = {\n method: opts.method,\n headers: buildHeaders({ ...opts, headers: perAttemptHeaders }, idempotencyKey),\n signal: combined.signal,\n };\n if (opts.body !== undefined) {\n init.body = bodyString;\n }\n const response = await fetchImpl(url, init);\n\n if (response.ok) {\n // PR R: surface API-level deprecation signals (RFC 8594 Sunset +\n // IETF draft Deprecation headers). The server emits these when\n // a deprecated request shape is in use. We log a warning\n // exactly once per SDK process per (code-path) to avoid spam.\n warnOnDeprecationOnce(response, opts.warnImpl);\n return await parseJson<T>(response);\n }\n\n // Non-2xx — try to parse the error body for structured fields.\n const body = await safelyParseErrorBody(response);\n const err = ScorezillaError.from({\n status: response.status,\n body,\n requestId: response.headers.get('X-Request-Id') ?? undefined,\n });\n\n if (shouldRetryStatus(response.status) && attempt < maxRetries) {\n const retryAfter = readRetryAfter(response);\n const delay = nextDelay(attempt, retryAfter, random);\n await retrySleep(delay);\n lastError = err;\n continue;\n }\n\n throw err;\n } catch (caught: unknown) {\n // ScorezillaError thrown by our own logic above (already typed) —\n // either retry or rethrow per the retry policy.\n if (caught instanceof ScorezillaError) {\n if (shouldRetryError(caught) && attempt < maxRetries) {\n const delay = nextDelay(attempt, undefined, random);\n await retrySleep(delay);\n lastError = caught;\n continue;\n }\n throw caught;\n }\n\n // Map raw fetch failures to ScorezillaError. `combined.timedOut()`\n // remains queryable after cleanup — the boolean is captured in the\n // closure regardless of timer state — so this works correctly even\n // though the `finally` below has already run by the time we get here.\n const mapped = mapTransportError(caught, opts.signal, timeoutMs, combined);\n if (shouldRetryError(mapped) && attempt < maxRetries) {\n const delay = nextDelay(attempt, undefined, random);\n await retrySleep(delay);\n lastError = mapped;\n continue;\n }\n throw mapped;\n } finally {\n combined.cleanup();\n }\n }\n\n // Unreachable in practice — every loop iteration either returns, throws,\n // or `continue`s. Keep as a typed fallback for the compiler.\n throw (\n lastError ??\n new ScorezillaError('Request failed after retries', {\n status: 0,\n code: 'internal_error',\n })\n );\n}\n\n// ───────────────────────────────────────────────────────────────────────────\n// Helpers\n// ───────────────────────────────────────────────────────────────────────────\n\nfunction buildUrl(baseUrl: string, path: string): string {\n // Trim a single trailing slash from baseUrl so `baseUrl + path` doesn't\n // produce double slashes. Path is expected to start with `/` (enforced by\n // the path-helper functions).\n const base = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl;\n return base + path;\n}\n\nfunction buildHeaders(opts: RequestOptions, idempotencyKey: string | null): Record<string, string> {\n const headers: Record<string, string> = { Accept: 'application/json' };\n if (opts.body !== undefined) {\n headers['Content-Type'] = 'application/json';\n }\n if (idempotencyKey !== null) {\n headers['Idempotency-Key'] = idempotencyKey;\n }\n // Caller-supplied headers (e.g., Authorization) override defaults. The\n // client layer is trusted; this is a public-API style merge, not security.\n if (opts.headers) {\n for (const [k, v] of Object.entries(opts.headers)) headers[k] = v;\n }\n return headers;\n}\n\n/**\n * Parse a successful response body and assert it matches the success envelope.\n *\n * The `T extends { ok: true }` constraint reflects that every API success\n * payload is shaped `ApiSuccess<X> = { ok: true } & X`. Asserting the\n * discriminator at runtime catches a class of silent contract violations:\n * a server-side regression that omits `ok` or returns a non-object on a\n * 2xx would otherwise produce `undefined` on typed-as-required fields far\n * from this fetch site, with no error message that pointed back here.\n *\n * Three distinct failure modes all map to `code: 'invalid_json'`:\n * 1. JSON parse error (malformed body)\n * 2. Non-object body (`null`, array, primitive)\n * 3. Object missing `ok: true` discriminator\n *\n * `'invalid_json'` is documented as a transport-layer code in errors.ts\n * and ScorezillaErrorCode; consumers can `if (e.code === 'invalid_json')`\n * to detect API/SDK contract drift.\n */\nasync function parseJson<T extends { ok: true }>(response: Response): Promise<T> {\n const requestId = response.headers.get('X-Request-Id') ?? undefined;\n\n let parsed: unknown;\n try {\n parsed = await response.json();\n } catch (cause) {\n throw new ScorezillaError('Response body was not valid JSON', {\n status: response.status,\n code: 'invalid_json',\n requestId,\n cause,\n });\n }\n\n if (parsed === null || typeof parsed !== 'object') {\n const observed = parsed === null ? 'null' : typeof parsed;\n throw new ScorezillaError(`Response body was not a JSON object (got ${observed})`, {\n status: response.status,\n code: 'invalid_json',\n requestId,\n });\n }\n\n // The `ok: true` discriminator must be present on a successful response.\n // If it isn't, the server has drifted from the API contract — surface\n // that as a typed error rather than letting the consumer's code crash on\n // `result.rank` being undefined three call frames away.\n const okField = (parsed as { ok?: unknown }).ok;\n if (okField !== true) {\n throw new ScorezillaError(\n `Response body on a 2xx is missing the \\`ok: true\\` discriminator (got ok=${String(okField)})`,\n {\n status: response.status,\n code: 'invalid_json',\n requestId,\n },\n );\n }\n\n return parsed as T;\n}\n\nasync function safelyParseErrorBody(response: Response): Promise<ApiError | undefined> {\n // Error responses may legitimately have empty body (e.g., some 5xx).\n // We try to parse, but a parse failure is non-fatal here — the caller\n // gets a status-derived code via ScorezillaError.from.\n try {\n const json = (await response.json()) as ApiResponse<unknown>;\n if (json && typeof json === 'object' && 'ok' in json && json.ok === false) {\n return json;\n }\n return undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction readRetryAfter(response: Response): number | undefined {\n const raw = response.headers.get('Retry-After');\n if (!raw) return undefined;\n const n = Number(raw);\n return Number.isFinite(n) && n >= 0 ? n : undefined;\n}\n\n/**\n * PR R: emit a once-per-process warning when an API response carries\n * the `Deprecation` header (per IETF draft) or a `Sunset` header\n * (RFC 8594). The dedupe key is the (Deprecation + Sunset + Link)\n * triplet, so different deprecation signals across the SDK lifetime\n * each surface once but the SAME signal across many requests fires\n * once.\n *\n * Quiet by design: this is a developer warning, not a runtime error.\n * Production loops shouldn't see this unless the SDK is genuinely\n * out-of-date.\n */\nconst seenDeprecations = new Set<string>();\nfunction warnOnDeprecationOnce(response: Response, warnImpl?: (...args: unknown[]) => void): void {\n const deprecation = response.headers.get('Deprecation');\n const sunset = response.headers.get('Sunset');\n if (!deprecation && !sunset) return;\n const link = response.headers.get('Link') ?? '';\n const key = `${deprecation ?? ''}|${sunset ?? ''}|${link}`;\n if (seenDeprecations.has(key)) return;\n seenDeprecations.add(key);\n\n const detail: string[] = [];\n if (deprecation === 'true' || deprecation) detail.push(`Deprecation: ${deprecation}`);\n if (sunset) detail.push(`Sunset: ${sunset}`);\n if (link) {\n // Pull the URL out of `<url>; rel=\"deprecation\"` per RFC 8288.\n const m = link.match(/<([^>]+)>/);\n if (m) detail.push(`Docs: ${m[1]}`);\n }\n const message =\n `[scorezilla-sdk] API responded with deprecation signal: ${detail.join(' · ')}. ` +\n `Upgrade your SDK before the sunset date.`;\n // Inject point — embedders can route via warnImpl or suppress with `() => {}`.\n if (warnImpl) {\n warnImpl(message);\n } else {\n // eslint-disable-next-line no-console -- developer-facing warning, intentional\n console.warn(message);\n }\n}\n\n/**\n * Test-only: clear the seen-deprecations dedupe set so unit tests can\n * exercise the warn-once behavior across cases. Not exported from the\n * public entry point; reachable only via the internal transport module\n * from inside the package.\n */\nexport function __resetDeprecationDedupe(): void {\n seenDeprecations.clear();\n}\n\n/**\n * Compose the caller's signal with a fresh timeout signal, returning a\n * single signal to pass to fetch plus a `cleanup` to detach the listeners.\n *\n * Implemented manually (not `AbortSignal.any`) because Safari 17.0–17.3\n * lacks that primitive. The cleanup is essential — without it, a long-lived\n * caller signal accumulates listeners every retry.\n */\nfunction combineSignalsWithTimeout(\n caller: AbortSignal | undefined,\n timeoutMs: number,\n): { signal: AbortSignal; cleanup: () => void; timedOut: () => boolean } {\n const ctrl = new AbortController();\n let didTimeOut = false;\n\n if (caller?.aborted) {\n ctrl.abort(caller.reason);\n return { signal: ctrl.signal, cleanup: () => {}, timedOut: () => false };\n }\n\n const onCallerAbort = (): void => {\n ctrl.abort(caller?.reason);\n };\n caller?.addEventListener('abort', onCallerAbort, { once: true });\n\n const timer = setTimeout(() => {\n didTimeOut = true;\n ctrl.abort(new DOMException(`Request timed out after ${timeoutMs}ms`, 'TimeoutError'));\n }, timeoutMs);\n\n return {\n signal: ctrl.signal,\n cleanup: () => {\n clearTimeout(timer);\n caller?.removeEventListener('abort', onCallerAbort);\n },\n timedOut: () => didTimeOut,\n };\n}\n\nfunction mapTransportError(\n caught: unknown,\n callerSignal: AbortSignal | undefined,\n timeoutMs: number,\n combined: { timedOut: () => boolean },\n): ScorezillaError {\n // If the caller's signal aborted, that wins (most specific).\n if (callerSignal?.aborted) {\n return ScorezillaError.aborted(callerSignal.reason ?? caught);\n }\n // If our internal timeout fired, surface that.\n if (combined.timedOut()) {\n return ScorezillaError.timeout(timeoutMs);\n }\n // Generic fetch-throws-everything path: TypeErrors, DOMExceptions, etc.\n const message = caught instanceof Error ? caught.message : 'Network request failed';\n return ScorezillaError.network(message, caught);\n}\n","/**\n * Runtime detection + `User-Agent` builder.\n *\n * **Privacy invariant:** detection happens via cheap probes on\n * `globalThis` only. The SDK never reads `navigator.userAgent` for\n * fingerprinting — only for the narrow case of distinguishing Cloudflare\n * Workers from a generic worker scope. No other DOM, hardware, or\n * timezone signals are touched. This is documented in COMPATIBILITY.md.\n *\n * Note on browsers: per the Fetch spec, browsers silently ignore the\n * `User-Agent` request header. Setting it has no effect there — but it\n * remains meaningful in Node, Bun, Deno, and Workers, where we want\n * server-side observability of which SDK version + runtime issued each\n * request. The client layer also sends a separate `X-Scorezilla-Client`\n * header that browsers do honor, so we get browser-side telemetry too.\n */\n\n/** Runtimes the SDK explicitly identifies. `unknown` is the fallback when\n * no signature matches (e.g., a new runtime, or one with all the right\n * globals stripped). */\nexport type Runtime = 'browser' | 'node' | 'bun' | 'deno' | 'workers' | 'unknown';\n\ninterface GlobalProbe {\n readonly Bun?: unknown;\n readonly Deno?: unknown;\n readonly process?: { readonly versions?: { readonly node?: string } };\n readonly document?: unknown;\n readonly WorkerGlobalScope?: unknown;\n readonly navigator?: { readonly userAgent?: string };\n}\n\n/**\n * Detect the current runtime by probing well-known globals. Pure function\n * — accepts an optional `g` override so tests can simulate any runtime.\n *\n * Order matters: Bun and Deno expose `process.versions.node`-like shims\n * for compat, so we check their own identifiers first.\n *\n * @example\n * ```ts\n * import { detectRuntime } from 'scorezilla';\n * const runtime = detectRuntime(); // → 'browser' | 'node' | 'bun' | 'deno' | 'workers' | 'unknown'\n * myTelemetry.track('app.start', { sdk_runtime: runtime });\n * ```\n *\n * @since 0.1.0\n * @stability stable\n */\nexport function detectRuntime(g: GlobalProbe = globalThis as GlobalProbe): Runtime {\n if (typeof g.Bun !== 'undefined') return 'bun';\n if (typeof g.Deno !== 'undefined') return 'deno';\n\n // Cloudflare Workers set `navigator.userAgent === 'Cloudflare-Workers'`.\n // Check this BEFORE the generic node check — Workers expose neither\n // `process` nor `document`, so the navigator probe is the unique signal.\n if (\n typeof g.navigator?.userAgent === 'string' &&\n g.navigator.userAgent.includes('Cloudflare-Workers')\n ) {\n return 'workers';\n }\n\n if (typeof g.process?.versions?.node === 'string') return 'node';\n if (typeof g.document !== 'undefined') return 'browser';\n\n return 'unknown';\n}\n\n/**\n * Build the SDK's default `User-Agent` header value.\n *\n * Shape: `scorezilla-js/<version> (<runtime>)`, e.g.\n * `scorezilla-js/0.1.0 (node)`. Version is the build-time-injected\n * `SDK_VERSION` so we don't read package.json at runtime.\n */\nexport function defaultUserAgent(version: string, runtime: Runtime = detectRuntime()): string {\n return `scorezilla-js/${version} (${runtime})`;\n}\n","/**\n * Built-in request verifiers for {@link createScoreSubmitHandler} (#211).\n *\n * These turn the common \"verify a JWT, derive the player id from a claim\"\n * shape into a one-liner. They produce a function with the same signature as\n * the handler's `verify` callback, so they drop straight in:\n *\n * ```ts\n * import { createScoreSubmitHandler, verifySupabaseJwt } from 'scorezilla/server';\n *\n * createScoreSubmitHandler({\n * secretKey, boardId,\n * verify: verifySupabaseJwt({ supabaseUrl: process.env.SUPABASE_URL! }),\n * });\n * ```\n *\n * **`jose` is an optional peer dependency.** Only these verifiers use it, and\n * only via a lazy `import('jose')` — so consumers who use the public-key\n * client, the factory with their own `verify`, or a provider backend SDK never\n * install or load it. If you call a built-in verifier without `jose` present,\n * it throws a clear \"install jose\" error.\n */\nimport type { VerifiedIdentity } from './server';\n\n/** Same shape as the handler's `verify` callback. */\nexport type RequestVerifier = (req: Request) => Promise<VerifiedIdentity | null>;\n\n/** Options for the generic JWKS verifier {@link verifyJwt}. */\nexport interface VerifyJwtOptions {\n /** JWKS endpoint, e.g. `https://issuer/.well-known/jwks.json`. */\n readonly jwksUrl: string | URL;\n /** Expected `iss` claim — strongly recommended. */\n readonly issuer?: string | string[];\n /** Expected `aud` claim — strongly recommended. */\n readonly audience?: string | string[];\n /** Which claim becomes the `playerId`. Default `'sub'`. */\n readonly claim?: string;\n /** Custom `fetch` for retrieving the JWKS (proxy / self-host / testing). */\n readonly fetch?: typeof fetch;\n}\n\n/** Options for the Supabase preset {@link verifySupabaseJwt}. */\nexport interface VerifySupabaseJwtOptions {\n /** Your Supabase project URL, e.g. `https://abcd.supabase.co`. */\n readonly supabaseUrl: string;\n /** Which claim becomes the `playerId`. Default `'sub'`. */\n readonly claim?: string;\n /** Custom `fetch` for retrieving the JWKS (proxy / self-host / testing). */\n readonly fetch?: typeof fetch;\n}\n\ntype JoseModule = typeof import('jose');\n\nasync function loadJose(): Promise<JoseModule> {\n try {\n return await import('jose');\n } catch (cause) {\n throw new Error(\n \"scorezilla/server: the optional peer dependency 'jose' is required for \" +\n 'verifyJwt() / verifySupabaseJwt(). Install it with `npm i jose` ' +\n '(or your package manager).',\n { cause },\n );\n }\n}\n\nfunction extractBearerToken(req: Request): string | null {\n const header = req.headers.get('authorization');\n if (!header) return null;\n const trimmed = header.trim();\n if (!/^bearer\\s+/i.test(trimmed)) return null;\n return trimmed.replace(/^bearer\\s+/i, '').trim() || null;\n}\n\n/**\n * Generic JWKS-backed JWT verifier. Verifies a `Bearer` token against the\n * given JWKS and returns `{ playerId }` from the configured claim (default\n * `sub`), or `null` if there's no token or verification fails.\n *\n * Covers the modern provider majority (Supabase, Clerk, Auth0, Firebase,\n * WorkOS, …) — they differ only by `jwksUrl` / `issuer` / `audience`.\n *\n * @since 0.3.0\n */\nexport function verifyJwt(options: VerifyJwtOptions): RequestVerifier {\n const claim = options.claim ?? 'sub';\n // Lazily built + memoized: the remote key set caches fetched keys and\n // refetches on unknown `kid`, so we create it once per verifier.\n let keySet: ReturnType<JoseModule['createRemoteJWKSet']> | null = null;\n\n return async (req: Request): Promise<VerifiedIdentity | null> => {\n const token = extractBearerToken(req);\n if (token === null) return null;\n\n // A missing `jose` surfaces here (not swallowed as a null/401) so the\n // misconfiguration is debuggable.\n const jose = await loadJose();\n if (keySet === null) {\n keySet = jose.createRemoteJWKSet(\n new URL(options.jwksUrl),\n options.fetch ? { [jose.customFetch]: options.fetch } : undefined,\n );\n }\n\n try {\n const { payload } = await jose.jwtVerify(token, keySet, {\n ...(options.issuer !== undefined ? { issuer: options.issuer } : {}),\n ...(options.audience !== undefined ? { audience: options.audience } : {}),\n });\n const id = payload[claim];\n return typeof id === 'string' && id.length > 0 ? { playerId: id } : null;\n } catch {\n // Bad signature / expired / wrong issuer-audience / unknown kid.\n return null;\n }\n };\n}\n\n/**\n * Supabase preset over {@link verifyJwt}. Verifies a Supabase user JWT via the\n * project's JWKS and derives the `playerId` from `sub`.\n *\n * ```ts\n * verify: verifySupabaseJwt({ supabaseUrl: process.env.SUPABASE_URL! })\n * ```\n *\n * @since 0.3.0\n */\nexport function verifySupabaseJwt(options: VerifySupabaseJwtOptions): RequestVerifier {\n const base = options.supabaseUrl.replace(/\\/+$/, '');\n return verifyJwt({\n jwksUrl: `${base}/auth/v1/.well-known/jwks.json`,\n issuer: `${base}/auth/v1`,\n audience: 'authenticated',\n ...(options.claim !== undefined ? { claim: options.claim } : {}),\n ...(options.fetch !== undefined ? { fetch: options.fetch } : {}),\n });\n}\n\n/** Options for the Clerk preset {@link verifyClerkJwt}. */\nexport interface VerifyClerkJwtOptions {\n /**\n * Your Clerk instance issuer (the token's `iss`), e.g.\n * `https://clerk.your-app.com` or `https://<slug>.clerk.accounts.dev`. The\n * JWKS URL is derived from it.\n */\n readonly issuer: string;\n /**\n * Expected `aud`. Clerk session tokens have **no** `aud` by default, so leave\n * this unset unless you added one via a custom JWT template.\n */\n readonly audience?: string | string[];\n /** Which claim becomes the `playerId`. Default `'sub'` (the Clerk user id). */\n readonly claim?: string;\n /** Custom `fetch` for retrieving the JWKS (proxy / self-host / testing). */\n readonly fetch?: typeof fetch;\n}\n\n/**\n * Clerk preset over {@link verifyJwt}. Verifies a Clerk session JWT against the\n * instance JWKS and derives the `playerId` from `sub` (the Clerk user id).\n *\n * @since 0.3.0\n */\nexport function verifyClerkJwt(options: VerifyClerkJwtOptions): RequestVerifier {\n const issuer = options.issuer.replace(/\\/+$/, '');\n return verifyJwt({\n jwksUrl: `${issuer}/.well-known/jwks.json`,\n issuer,\n ...(options.audience !== undefined ? { audience: options.audience } : {}),\n ...(options.claim !== undefined ? { claim: options.claim } : {}),\n ...(options.fetch !== undefined ? { fetch: options.fetch } : {}),\n });\n}\n\n/** Options for the Auth0 preset {@link verifyAuth0Jwt}. */\nexport interface VerifyAuth0JwtOptions {\n /** Your Auth0 domain, e.g. `your-tenant.us.auth0.com` (scheme optional). */\n readonly domain: string;\n /** Your API identifier — the access token's `aud`. */\n readonly audience: string | string[];\n /** Which claim becomes the `playerId`. Default `'sub'`. */\n readonly claim?: string;\n /** Custom `fetch` for retrieving the JWKS (proxy / self-host / testing). */\n readonly fetch?: typeof fetch;\n}\n\n/**\n * Auth0 preset over {@link verifyJwt}. Note Auth0's issuer carries a trailing\n * slash (`https://<domain>/`) — the preset adds it for you.\n *\n * @since 0.3.0\n */\nexport function verifyAuth0Jwt(options: VerifyAuth0JwtOptions): RequestVerifier {\n const host = options.domain.replace(/^https?:\\/\\//, '').replace(/\\/+$/, '');\n return verifyJwt({\n jwksUrl: `https://${host}/.well-known/jwks.json`,\n issuer: `https://${host}/`,\n audience: options.audience,\n ...(options.claim !== undefined ? { claim: options.claim } : {}),\n ...(options.fetch !== undefined ? { fetch: options.fetch } : {}),\n });\n}\n\n/**\n * JWK-set endpoint for Firebase ID tokens (the `securetoken` system service\n * account). Google publishes a standard JWK set here — no x509 import needed.\n */\nconst FIREBASE_JWKS_URL =\n 'https://www.googleapis.com/service_accounts/v1/jwk/securetoken@system.gserviceaccount.com';\n\n/** Options for the Firebase preset {@link verifyFirebaseIdToken}. */\nexport interface VerifyFirebaseIdTokenOptions {\n /** Your Firebase project id — both the token's `aud` and the issuer suffix. */\n readonly projectId: string;\n /** Which claim becomes the `playerId`. Default `'sub'` (the Firebase uid). */\n readonly claim?: string;\n /** Custom `fetch` for retrieving the JWKS (proxy / self-host / testing). */\n readonly fetch?: typeof fetch;\n}\n\n/**\n * Firebase Authentication preset over {@link verifyJwt}. Verifies a Firebase ID\n * token (`iss = https://securetoken.google.com/<projectId>`, `aud = projectId`)\n * and derives the `playerId` from `sub` (the Firebase uid).\n *\n * @since 0.3.0\n */\nexport function verifyFirebaseIdToken(options: VerifyFirebaseIdTokenOptions): RequestVerifier {\n return verifyJwt({\n jwksUrl: FIREBASE_JWKS_URL,\n issuer: `https://securetoken.google.com/${options.projectId}`,\n audience: options.projectId,\n ...(options.claim !== undefined ? { claim: options.claim } : {}),\n ...(options.fetch !== undefined ? { fetch: options.fetch } : {}),\n });\n}\n","/**\n * `createGitHubOAuthHandler` — the server-side callback leg of the GitHub\n * identity provider (`useAuthProvider({ provider: 'github' })`, ADR 0009).\n *\n * GitHub redirects the sign-in popup here with `?code=&state=`. This handler:\n * 1. validates the query strictly (formats are pinned — anything else is a\n * 400, never reflected);\n * 2. exchanges the code at GitHub's token endpoint — the client secret\n * stays on this server, and the resulting access token is used for ONE\n * `/user` lookup and then discarded;\n * 3. responds with a tiny HTML page that `postMessage`s\n * `{ source: 'scorezilla:github-oauth', state, id }` to `window.opener`,\n * pinned to `allowedOrigin`, and closes the popup.\n *\n * The browser side (`scorezilla/identity`) accepts the message only when the\n * origin matches its `exchangeUrl` and the `state` echoes the one it\n * generated — this page is the only party that can complete a sign-in.\n *\n * Returns a standard `(Request) => Promise<Response>`: deploy it on any web\n * runtime (a Next.js route handler, Hono, Deno, Bun, a Cloudflare Worker).\n * Configure the deployed URL as the OAuth app's callback URL on GitHub.\n *\n * @since 0.3.0\n */\nimport type { FetchImpl } from './transport';\n\nconst GITHUB_TOKEN_URL = 'https://github.com/login/oauth/access_token';\nconst GITHUB_USER_URL = 'https://api.github.com/user';\n\n/** Must match `GITHUB_MESSAGE_SOURCE` in `scorezilla/identity` — the marker\n * the browser half filters callback messages on. */\nconst MESSAGE_SOURCE = 'scorezilla:github-oauth';\n\n/** GitHub identifies the calling app via User-Agent and rejects without one. */\nconst USER_AGENT = 'scorezilla-sdk-github-oauth';\n\n// Strict input formats. `state` is generated by the SDK client (base64url\n// alphabet); `code` is GitHub-issued. Anything outside these shapes is\n// rejected up front and NEVER echoed into the HTML response.\nconst STATE_RE = /^[A-Za-z0-9_-]{8,128}$/;\nconst CODE_RE = /^[A-Za-z0-9_-]{1,128}$/;\n\nexport interface CreateGitHubOAuthHandlerConfig {\n /** Your GitHub OAuth app client ID. */\n readonly clientId: string;\n /** Your GitHub OAuth app client secret. Server-only — never ships to a browser. */\n readonly clientSecret: string;\n /**\n * The exact origin of the GAME page that opens the sign-in popup, e.g.\n * `https://mygame.example`. Used as the `postMessage` target origin so the\n * sign-in result can only be delivered to your page — never `*`.\n */\n readonly allowedOrigin: string;\n /** Inject a `fetch` (testing / custom transport). */\n readonly fetch?: FetchImpl;\n}\n\n/** The web-standard request handler returned by {@link createGitHubOAuthHandler}. */\nexport type GitHubOAuthHandler = (req: Request) => Promise<Response>;\n\n/**\n * Build the GitHub OAuth callback endpoint. See module docs for the flow;\n * see `GitHubAuthProviderOptions` in `scorezilla/identity` for the matching\n * client half.\n *\n * **Construction patterns.** In Node/Next, secrets are in `process.env`, so\n * build the handler once at module scope. In Cloudflare Workers, secrets\n * live on the per-request `env` binding, so build it inside `fetch`.\n */\nexport function createGitHubOAuthHandler(\n config: CreateGitHubOAuthHandlerConfig,\n): GitHubOAuthHandler {\n if (typeof config.clientId !== 'string' || config.clientId.length === 0) {\n throw new TypeError('createGitHubOAuthHandler: clientId is required.');\n }\n if (typeof config.clientSecret !== 'string' || config.clientSecret.length === 0) {\n throw new TypeError('createGitHubOAuthHandler: clientSecret is required.');\n }\n let allowedOrigin: string;\n try {\n const parsed = new URL(config.allowedOrigin);\n // `origin` normalizes (drops paths, lowercases the host) — and throws\n // above on anything that isn't an absolute URL.\n allowedOrigin = parsed.origin;\n if (allowedOrigin === 'null') throw new Error('opaque origin');\n } catch {\n throw new TypeError(\n 'createGitHubOAuthHandler: allowedOrigin must be an absolute origin, ' +\n \"e.g. 'https://mygame.example' (got \" +\n JSON.stringify(config.allowedOrigin) +\n ').',\n );\n }\n const fetchImpl: FetchImpl = config.fetch ?? fetch;\n\n return async (req: Request): Promise<Response> => {\n if (req.method !== 'GET') {\n return new Response('method not allowed', { status: 405, headers: { allow: 'GET' } });\n }\n const url = new URL(req.url);\n const state = url.searchParams.get('state') ?? '';\n const code = url.searchParams.get('code');\n const ghError = url.searchParams.get('error');\n\n // `state` gates EVERY response that echoes anything — validate first.\n if (!STATE_RE.test(state)) {\n return new Response('invalid or missing state parameter', { status: 400 });\n }\n\n // GitHub-side denial (player cancelled on the consent screen): relay it\n // so the client resolves null. No exchange to attempt.\n if (ghError !== null) {\n return callbackPage(\n { state, error: ghError === 'access_denied' ? 'access_denied' : 'exchange_failed' },\n allowedOrigin,\n );\n }\n\n if (code === null || !CODE_RE.test(code)) {\n return new Response('invalid or missing code parameter', { status: 400 });\n }\n\n // Leg 1: code → access token. The secret stays here; the token never\n // leaves this function.\n let accessToken: string;\n try {\n const tokenRes = await fetchImpl(GITHUB_TOKEN_URL, {\n method: 'POST',\n headers: {\n accept: 'application/json',\n 'content-type': 'application/x-www-form-urlencoded',\n 'user-agent': USER_AGENT,\n },\n body: new URLSearchParams({\n client_id: config.clientId,\n client_secret: config.clientSecret,\n code,\n }).toString(),\n });\n const tokenBody = (await tokenRes.json()) as { access_token?: unknown; error?: unknown };\n if (!tokenRes.ok || typeof tokenBody.access_token !== 'string') {\n return callbackPage({ state, error: 'exchange_failed' }, allowedOrigin);\n }\n accessToken = tokenBody.access_token;\n } catch {\n return callbackPage({ state, error: 'exchange_failed' }, allowedOrigin);\n }\n\n // Leg 2: token → numeric user id. Only `id` is read; the token is\n // dropped when this function returns.\n try {\n const userRes = await fetchImpl(GITHUB_USER_URL, {\n method: 'GET',\n headers: {\n authorization: `Bearer ${accessToken}`,\n accept: 'application/vnd.github+json',\n 'user-agent': USER_AGENT,\n },\n });\n if (!userRes.ok) {\n return callbackPage({ state, error: 'exchange_failed' }, allowedOrigin);\n }\n const user = (await userRes.json()) as { id?: unknown };\n if (typeof user.id !== 'number' || !Number.isSafeInteger(user.id)) {\n return callbackPage({ state, error: 'exchange_failed' }, allowedOrigin);\n }\n return callbackPage({ state, id: String(user.id) }, allowedOrigin);\n } catch {\n return callbackPage({ state, error: 'exchange_failed' }, allowedOrigin);\n }\n };\n}\n\n/**\n * The popup's terminal page: deliver the payload to the opener (pinned to\n * `allowedOrigin`) and close. Every interpolated value is JSON.stringify-ed\n * AND pre-validated upstream (`state` against STATE_RE, `id` digits-only,\n * `error` from a fixed vocabulary), so no caller-controlled byte can break\n * out of the script context.\n */\nfunction callbackPage(\n payload: { state: string; id?: string; error?: string },\n allowedOrigin: string,\n): Response {\n const message = JSON.stringify({ source: MESSAGE_SOURCE, ...payload });\n const target = JSON.stringify(allowedOrigin);\n const html = `<!doctype html>\n<html>\n<head><meta charset=\"utf-8\"><title>Signing in…</title></head>\n<body>\n<script>\n(function () {\n if (window.opener) {\n window.opener.postMessage(${message}, ${target});\n window.close();\n } else {\n document.body.textContent =\n 'Sign-in handled — you can close this window. (If this keeps appearing, ' +\n 'the game page may be setting Cross-Origin-Opener-Policy: same-origin, ' +\n 'which severs the popup link; use same-origin-allow-popups.)';\n }\n})();\n</script>\n</body>\n</html>`;\n return new Response(html, {\n status: 200,\n headers: {\n 'content-type': 'text/html; charset=utf-8',\n // One-shot page embedding a one-shot state — never cache it.\n 'cache-control': 'no-store',\n // The URL carried the OAuth `code`; nothing on this page may leak it.\n 'referrer-policy': 'no-referrer',\n // Defense in depth for the inline script: nothing else may load or\n // run on this page even if a future regression reflected input here.\n 'content-security-policy': \"default-src 'none'; script-src 'unsafe-inline'\",\n 'x-content-type-options': 'nosniff',\n },\n });\n}\n","/**\n * `scorezilla/server` — HMAC-signed adapter for game backends (#17, v0.2.0).\n *\n * Why this exists\n * ---------------\n * The default `Scorezilla` from `'scorezilla'` uses a public key\n * (`pk_*`) and is browser-safe. That model is client-authoritative —\n * any player can submit any score from devtools. Fine for casual\n * leaderboards; not fine for anything where the ranking matters.\n *\n * This adapter is the opposite: the game backend signs each request\n * with a secret key (`sk_live_*`). The Scorezilla API verifies the\n * signature server-side. Players can't forge submissions even with\n * full client-side access.\n *\n * Surface parity with the public-key client\n * -----------------------------------------\n * The method shape is intentionally identical — `submitScore`,\n * `getLeaderboard`, `getPlayerRank`, `getWindowAround`. The only\n * difference at the call site is the constructor argument: a single\n * `sk_live_<keyId>_<random>` token replaces the public key (Stripe-\n * style single-token format; the keyId is embedded in the plaintext\n * so consumers manage one value, not two):\n *\n * import { Scorezilla } from 'scorezilla/server';\n * const sz = new Scorezilla({\n * secretKey: process.env.SCOREZILLA_SECRET_KEY!, // sk_live_<keyId>_<random>\n * });\n *\n * Behind the scenes:\n * - `submitScore` posts to `/v1/secure/scores` (different from the\n * public-key submit endpoint, which carries the boardId in the\n * path). The HMAC signing string covers method + path + ts +\n * nonce + sha256(body), so the API verifies before any DO read.\n * - Read methods hit the same `/v1/boards/…/leaderboard` etc.\n * endpoints as the public-key client.\n *\n * Browser hard-stop\n * -----------------\n * The package's exports map routes `\"./server\"` through\n * `src/server-browser-stub.ts` when the bundler honors the `browser`\n * condition, so a browser-side import throws at module evaluation. The\n * secret key MUST NEVER leave the server.\n */\n\nimport { validateSecretKey, DEFAULT_BASE_URL, type SecretKeyConfig } from './config';\nimport { buildHmacAuthHeader } from './hmac';\nimport {\n getLeaderboardPath,\n getPlayerRankPath,\n getWindowAroundPath,\n submitScoreSecurePath,\n} from './paths';\nimport { request, type FetchImpl, type RequestOptions } from './transport';\nimport type {\n ApiSuccess,\n LeaderboardResponse,\n PlayerRankResponse,\n SubmitScoreResponse,\n WindowAroundResponse,\n} from './types';\nimport { defaultUserAgent } from './user-agent';\nimport { ScorezillaError } from './errors';\n\n// ---------------------------------------------------------------------------\n// Public input types\n// ---------------------------------------------------------------------------\n// Intentionally mirror the public-key client's input shapes (see\n// src/client.ts). Kept as a separate set of declarations rather than\n// re-exported to keep the `scorezilla/server` surface self-contained —\n// consumers of this entry point shouldn't need to import from\n// `scorezilla` core to get types.\n\n/** Caller-cancellable common shape — server-side too. */\nexport interface CancellableInput {\n /** Optional `AbortSignal` to cancel mid-flight. The transport composes\n * it with the per-attempt timeout, so aborting always wins. */\n signal?: AbortSignal | undefined;\n}\n\n/** Input for {@link Scorezilla.submitScore}. */\nexport interface SubmitScoreInput extends CancellableInput {\n /** UUID-typed board identifier — issued by the operator dashboard. */\n boardId: string;\n /** Stable per-player identifier (UUID, your account ID, etc.). Avoid PII. */\n playerId: string;\n /** Finite number. Rejected with `out_of_bounds` if outside the board's\n * configured `[minScore, maxScore]` range. */\n score: number;\n /** Optional structured context attached to the submission. ≤ 4 KB JSON. */\n metadata?: Record<string, unknown> | undefined;\n}\n\n/** Input for {@link Scorezilla.getLeaderboard}. */\nexport interface GetLeaderboardInput extends CancellableInput {\n boardId: string;\n /** Number of entries (API caps at 1000; default 100). */\n top?: number | undefined;\n /** Offset into the sorted board (API caps at 1_000_000; default 0). */\n offset?: number | undefined;\n}\n\n/** Input for {@link Scorezilla.getPlayerRank}. */\nexport interface GetPlayerRankInput extends CancellableInput {\n boardId: string;\n playerId: string;\n}\n\n/** Input for {@link Scorezilla.getWindowAround}. */\nexport interface GetWindowAroundInput extends CancellableInput {\n boardId: string;\n playerId: string;\n /** Entries strictly above the player (API caps at 100; default 5). */\n before?: number | undefined;\n /** Entries strictly below the player (API caps at 100; default 5). */\n after?: number | undefined;\n}\n\n// ---------------------------------------------------------------------------\n// The Scorezilla server client\n// ---------------------------------------------------------------------------\n\n/**\n * Server-side, HMAC-signing Scorezilla client.\n *\n * Construct once at process boot with your `sk_live_*` secret and reuse\n * the instance across requests — there's no per-request state in here\n * other than the freshly-generated timestamp + nonce computed inside\n * each HTTP attempt.\n *\n * @example\n * ```ts\n * import { Scorezilla, ScorezillaError } from 'scorezilla/server';\n *\n * const sz = new Scorezilla({\n * secretKey: process.env.SCOREZILLA_SECRET_KEY!, // sk_live_<keyId>_<random>\n * });\n *\n * try {\n * const r = await sz.submitScore({ boardId, playerId, score, metadata });\n * if (r.isPersonalBest) notifyPlayer(r.rank);\n * } catch (e) {\n * if (e instanceof ScorezillaError && e.isRateLimited()) {\n * await delay((e.retryAfter ?? 30) * 1000);\n * } else throw e;\n * }\n * ```\n *\n * @since 0.2.0\n * @stability stable\n */\nexport class Scorezilla {\n /** The package version, injected at build time from `package.json`.\n * Mirrors the static on the public-key client so consumers can log\n * the running SDK build the same way regardless of which surface\n * they imported. */\n static readonly version: string = __SCOREZILLA_SDK_VERSION__;\n\n readonly #keyId: string;\n readonly #secret: string;\n readonly #baseUrl: string;\n /** Host portion of `#baseUrl` (e.g. \"api.scorezilla.dev\"). Captured at\n * construction so every signed request binds to this exact origin —\n * see `buildSigningString` v=2 in `hmac.ts`. */\n readonly #host: string;\n readonly #fetchImpl: FetchImpl | undefined;\n readonly #timeoutMs: number | undefined;\n readonly #maxRetries: number | undefined;\n readonly #sleepImpl: ((ms: number, signal?: AbortSignal) => Promise<void>) | undefined;\n readonly #warnImpl: ((...args: unknown[]) => void) | undefined;\n readonly #userAgent: string;\n\n constructor(config: SecretKeyConfig) {\n // Belt-and-suspenders browser guard. The package's exports map routes\n // `scorezilla/server` to `server-browser-stub.ts` when the bundler\n // honors the `browser` condition — which closes the issue cleanly for\n // modern bundlers (Vite, esbuild, Rollup, Webpack 5 with the right\n // resolve config). But misconfigured older bundlers (Webpack 4 without\n // `resolve.conditionNames`, certain custom Rollup setups) may bundle\n // this file directly into a browser bundle. The secret would leak.\n // Throwing at construction time is a non-negotiable runtime fence\n // against that misconfiguration.\n //\n // Detection has to distinguish a *real browser* from *Node-with-jsdom*\n // (the latter is what vitest's `environment: 'jsdom'` produces — it\n // sets `window` + `document` but is fundamentally a Node process).\n // Strategy: if we have a Node-like host (Node, Bun, Deno, or a\n // Workers runtime with `nodejs_compat`), the secret is safe; otherwise\n // if we see browser globals, refuse to instantiate.\n if (isRealBrowserEnvironment()) {\n throw new Error(\n 'scorezilla/server: this adapter is server-only and must not run in browsers. ' +\n 'Your bundler is shipping `scorezilla/server` into a browser bundle — check that it ' +\n 'honors the `browser` export condition in package.json. Use the public-key client ' +\n \"(`import { Scorezilla } from 'scorezilla'`) from browser code.\",\n );\n }\n\n const resolved = validateSecretKey(config);\n this.#keyId = resolved.keyId;\n this.#secret = resolved.secret;\n this.#baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, '');\n // Derive host once. URL parsing is also a soft validation of baseUrl —\n // a malformed baseUrl (no scheme, etc.) would throw here at boot rather\n // than surface as a confusing \"signature mismatch\" 401 on every request.\n try {\n this.#host = new URL(this.#baseUrl).host;\n } catch {\n throw new Error(\n `scorezilla/server: baseUrl must be a valid absolute URL (got: ${this.#baseUrl})`,\n );\n }\n this.#fetchImpl = config.fetch;\n this.#timeoutMs = config.timeoutMs;\n this.#maxRetries = config.maxRetries;\n this.#sleepImpl = config.sleepImpl;\n this.#warnImpl = config.warn;\n this.#userAgent = config.userAgent ?? defaultUserAgent(Scorezilla.version);\n }\n\n /**\n * Submit a score to a board. Signed end-to-end — the API verifies\n * before any state change.\n *\n * **Behavioral note vs. the public-key client**: the server adapter\n * does NOT perform local `metadata` validation. The public-key\n * client (`scorezilla`) validates size + structure client-side and\n * fails fast; the server adapter relies on the API to reject\n * malformed metadata with `invalid_input`. Trade-off: smaller bundle\n * + simpler server-side logic vs. one extra network round-trip on\n * caller mistakes. If you want fast-fail behavior, validate metadata\n * yourself before calling this method.\n */\n async submitScore(input: SubmitScoreInput): Promise<ApiSuccess<SubmitScoreResponse>> {\n return this.#request<ApiSuccess<SubmitScoreResponse>>({\n path: submitScoreSecurePath(),\n method: 'POST',\n body: {\n boardId: input.boardId,\n playerId: input.playerId,\n score: input.score,\n ...(input.metadata !== undefined ? { metadata: input.metadata } : {}),\n },\n signal: input.signal,\n });\n }\n\n /** Fetch the top-N entries on a board. */\n async getLeaderboard(input: GetLeaderboardInput): Promise<ApiSuccess<LeaderboardResponse>> {\n return this.#request<ApiSuccess<LeaderboardResponse>>({\n path: getLeaderboardPath(input.boardId, {\n ...(input.top !== undefined ? { top: input.top } : {}),\n ...(input.offset !== undefined ? { offset: input.offset } : {}),\n }),\n method: 'GET',\n signal: input.signal,\n });\n }\n\n /** Look up a single player's rank on a board. */\n async getPlayerRank(input: GetPlayerRankInput): Promise<ApiSuccess<PlayerRankResponse>> {\n return this.#request<ApiSuccess<PlayerRankResponse>>({\n path: getPlayerRankPath(input.boardId, input.playerId),\n method: 'GET',\n signal: input.signal,\n });\n }\n\n /** Fetch the slice of entries surrounding a player. */\n async getWindowAround(input: GetWindowAroundInput): Promise<ApiSuccess<WindowAroundResponse>> {\n return this.#request<ApiSuccess<WindowAroundResponse>>({\n path: getWindowAroundPath(input.boardId, input.playerId, {\n ...(input.before !== undefined ? { before: input.before } : {}),\n ...(input.after !== undefined ? { after: input.after } : {}),\n }),\n method: 'GET',\n signal: input.signal,\n });\n }\n\n /**\n * Thin wrapper around `transport.request` that wires the HMAC signer\n * for every attempt. Each retry calls `signRequest` again, producing\n * a fresh `(ts, nonce)` pair — the server's replay protection (10-min\n * KV) requires this.\n */\n async #request<T extends { ok: true }>(\n opts: Pick<RequestOptions, 'path' | 'method' | 'body' | 'signal'>,\n ): Promise<T> {\n const baseHeaders: Record<string, string> = {\n // User-Agent: useful in Node/Bun/Deno/Workers for server observability.\n // (The browser stub blocks this code path from running browser-side.)\n 'User-Agent': this.#userAgent,\n 'X-Scorezilla-Client': this.#userAgent,\n };\n\n const requestOpts: RequestOptions = {\n baseUrl: this.#baseUrl,\n path: opts.path,\n method: opts.method,\n headers: baseHeaders,\n signRequest: async ({ method, pathAndQuery, body }) =>\n buildHmacAuthHeader({\n keyId: this.#keyId,\n secret: this.#secret,\n method,\n pathAndQuery,\n host: this.#host,\n body,\n }),\n };\n if (opts.body !== undefined) requestOpts.body = opts.body;\n if (opts.signal !== undefined) requestOpts.signal = opts.signal;\n if (this.#fetchImpl !== undefined) requestOpts.fetchImpl = this.#fetchImpl;\n if (this.#warnImpl !== undefined) requestOpts.warnImpl = this.#warnImpl;\n if (this.#timeoutMs !== undefined) requestOpts.timeoutMs = this.#timeoutMs;\n if (this.#maxRetries !== undefined || this.#sleepImpl !== undefined) {\n requestOpts.retry = {\n ...(this.#maxRetries !== undefined ? { maxRetries: this.#maxRetries } : {}),\n ...(this.#sleepImpl !== undefined ? { sleepImpl: this.#sleepImpl } : {}),\n };\n }\n\n return request<T>(requestOpts);\n }\n}\n\n/**\n * Distinguish a real browser from a Node-with-jsdom test environment.\n *\n * Browser globals (`window`, `document`) appear in both contexts. The\n * differentiator is the presence of a recognizable server runtime:\n * - Node + Bun: `process.versions.node`\n * - Cloudflare Workers\n * w/ nodejs_compat: `process.versions.node` too\n * - Deno: `globalThis.Deno`\n *\n * `globalThis.EdgeRuntime` is intentionally NOT on the trust list. It's\n * a Vercel-Edge convention that can be polyfilled by browser extensions\n * or bundler misconfiguration; trusting it would let an adversarial\n * page bypass the runtime guard by setting `globalThis.EdgeRuntime =\n * 'edge'`. The package's `exports.browser` condition remains the\n * primary gate against browser loading; this runtime check is\n * defense-in-depth and should err on the side of REFUSING.\n *\n * Real Vercel Edge code typically lacks `window` and `document` so it\n * never reaches the disqualifier branch — no false positive.\n *\n * If ANY trusted server runtime is detected we trust the caller.\n * Otherwise, if browser globals exist, refuse.\n */\nfunction isRealBrowserEnvironment(): boolean {\n const g = globalThis as {\n window?: unknown;\n document?: unknown;\n Deno?: unknown;\n Bun?: unknown;\n process?: { versions?: { node?: string } };\n };\n const hasBrowserGlobals = typeof g.window !== 'undefined' && typeof g.document !== 'undefined';\n if (!hasBrowserGlobals) return false;\n const hasNodeLikeHost =\n Boolean(g.process?.versions?.node) ||\n typeof g.Deno !== 'undefined' ||\n typeof g.Bun !== 'undefined';\n return !hasNodeLikeHost;\n}\n\n// ---------------------------------------------------------------------------\n// createScoreSubmitHandler — turnkey secure-submit endpoint (#211)\n// ---------------------------------------------------------------------------\n\n/** A value or a promise of it. */\ntype Awaitable<T> = T | Promise<T>;\n\n/**\n * The trusted identity produced by your `verify` callback. `playerId` is what\n * gets submitted — derived from the *verified* request, never the request body.\n */\nexport interface VerifiedIdentity {\n /** Stable, trusted per-player id (e.g. your auth user id). Avoid PII. */\n readonly playerId: string;\n /** Optional trusted metadata merged into the submission (wins over the body). */\n readonly metadata?: Record<string, unknown> | undefined;\n}\n\n/** The score payload extracted from the request body. */\nexport interface ParsedScoreSubmission {\n readonly score: number;\n readonly metadata?: Record<string, unknown> | undefined;\n}\n\n/** Decision returned by an optional pre-verify rate-limit gate. */\nexport interface RateLimitDecision {\n readonly ok: boolean;\n readonly retryAfterSeconds?: number | undefined;\n}\n\n/** CORS config for the handler. Omit entirely for same-origin endpoints. */\nexport interface ScoreSubmitCorsOptions {\n /**\n * Allowed origin(s): an exact string, an array of strings, a predicate, or\n * `true` to reflect any `Origin`. `false` disables reflection.\n */\n readonly origin: string | readonly string[] | boolean | ((origin: string | null) => boolean);\n /** Methods for the preflight. Default `['POST', 'OPTIONS']`. */\n readonly methods?: readonly string[];\n /** Request headers for the preflight. Default `['content-type', 'authorization']`. */\n readonly headers?: readonly string[];\n /** `Access-Control-Max-Age` seconds. Default `600`. */\n readonly maxAgeSeconds?: number;\n}\n\n/** Configuration for {@link createScoreSubmitHandler}. */\nexport interface CreateScoreSubmitHandlerConfig {\n /** Your `sk_live_*` secret. Server-only — never ship to a browser. */\n readonly secretKey: string;\n /** The board UUID this handler submits to. */\n readonly boardId: string;\n /**\n * Authenticate the request and return the **trusted** `playerId` (and any\n * trusted metadata). Return `null` to reject (→ 401); throwing also rejects.\n * Read identity from headers/cookies — the request **body** is reserved for\n * the score payload (see `parseSubmission`). This callback is the universal\n * seam: wire any auth (provider SDK, JWT verify, DB session lookup) here.\n */\n readonly verify: (req: Request) => Awaitable<VerifiedIdentity | null>;\n /**\n * Extract the score (+ optional client metadata) from the request. Defaults\n * to JSON `{ score: number, metadata?: object }`. Return `null` (or throw)\n * to reject as a bad request (→ 400). Note: a `playerId` in the body is\n * always ignored — identity comes only from `verify`.\n */\n readonly parseSubmission?: (req: Request) => Awaitable<ParsedScoreSubmission | null>;\n /**\n * Optional gate that runs **before** `verify` (cheap defense — e.g. a per-IP\n * rate limit, so unauthenticated spam can't drive auth/crypto work). Return\n * `{ ok: false }` to reject with 429. Per-user limits belong inside `verify`.\n */\n readonly rateLimit?: (req: Request) => Awaitable<RateLimitDecision>;\n /** Optional CORS handling (OPTIONS preflight + reflected `Access-Control-Allow-Origin`). */\n readonly cors?: ScoreSubmitCorsOptions;\n /** Override the API base URL (self-host / testing). */\n readonly baseUrl?: string;\n /** Inject a `fetch` (testing / custom transport). */\n readonly fetch?: FetchImpl;\n /** Max transport retries (default SDK policy). Set `0` to disable. */\n readonly maxRetries?: number;\n /** Per-attempt timeout in ms. */\n readonly timeoutMs?: number;\n}\n\n/** The web-standard request handler returned by {@link createScoreSubmitHandler}. */\nexport type ScoreSubmitHandler = (req: Request) => Promise<Response>;\n\n/**\n * Build a turnkey, framework-agnostic secure score-submit endpoint.\n *\n * Returns a standard `(Request) => Promise<Response>` handler — drop it into a\n * Cloudflare Worker, a Next.js route handler, Hono, Deno, Bun, or any runtime\n * that speaks web `Request`/`Response`. You supply only what's app-specific:\n * the `secretKey`, the `boardId`, and a `verify` callback that proves identity\n * and returns the trusted `playerId`. The handler owns parsing/validation, the\n * \"playerId comes from `verify`, never the body\" guarantee, signing via the\n * HMAC server client, and error → HTTP mapping.\n *\n * **Construction patterns.** In Node/Next, secrets are in `process.env`, so\n * build the handler once at module scope. In Cloudflare Workers, secrets live\n * on the per-request `env` binding, so build it inside `fetch` (closing over\n * `env`) — the construction is cheap (no I/O).\n *\n * @example Cloudflare Worker\n * ```ts\n * import { createScoreSubmitHandler } from 'scorezilla/server';\n *\n * export default {\n * fetch(req, env) {\n * const handler = createScoreSubmitHandler({\n * secretKey: env.SCOREZILLA_SECRET_KEY,\n * boardId: env.SCOREZILLA_BOARD_ID,\n * verify: async (r) => {\n * const user = await verifyMyAuth(r, env); // your auth: SDK / JWT / DB\n * return user ? { playerId: user.id } : null;\n * },\n * cors: { origin: 'https://mygame.example' },\n * });\n * return handler(req);\n * },\n * };\n * ```\n *\n * @since 0.3.0\n * @stability stable\n */\nexport function createScoreSubmitHandler(\n config: CreateScoreSubmitHandlerConfig,\n): ScoreSubmitHandler {\n // Construct the signing client once; reuse across requests.\n const sz = new Scorezilla({\n secretKey: config.secretKey,\n ...(config.baseUrl !== undefined ? { baseUrl: config.baseUrl } : {}),\n ...(config.fetch !== undefined ? { fetch: config.fetch } : {}),\n ...(config.maxRetries !== undefined ? { maxRetries: config.maxRetries } : {}),\n ...(config.timeoutMs !== undefined ? { timeoutMs: config.timeoutMs } : {}),\n });\n const parse = config.parseSubmission ?? defaultParseSubmission;\n\n return async (req: Request): Promise<Response> => {\n const cors = config.cors ? buildCorsHeaders(config.cors, req.headers.get('Origin')) : {};\n\n if (req.method === 'OPTIONS' && config.cors) {\n return new Response(null, { status: 204, headers: cors });\n }\n if (req.method !== 'POST') {\n return jsonResponse({ ok: false, error: 'method_not_allowed' }, 405, cors);\n }\n\n if (config.rateLimit) {\n const decision = await config.rateLimit(req);\n if (!decision.ok) {\n const headers = { ...cors };\n if (decision.retryAfterSeconds !== undefined) {\n headers['Retry-After'] = String(decision.retryAfterSeconds);\n }\n return jsonResponse({ ok: false, error: 'rate_limited' }, 429, headers);\n }\n }\n\n let identity: VerifiedIdentity | null;\n try {\n identity = await config.verify(req);\n } catch {\n // A throwing verify is treated as a rejection — it should catch its own\n // errors. We never surface its message (it may carry token internals).\n identity = null;\n }\n if (!identity || typeof identity.playerId !== 'string' || identity.playerId.length === 0) {\n return jsonResponse({ ok: false, error: 'unauthorized' }, 401, cors);\n }\n\n let submission: ParsedScoreSubmission | null;\n try {\n submission = await parse(req);\n } catch {\n submission = null;\n }\n if (!submission || typeof submission.score !== 'number' || !Number.isFinite(submission.score)) {\n return jsonResponse(\n { ok: false, error: 'bad_request', message: 'invalid score submission' },\n 400,\n cors,\n );\n }\n\n const metadata = mergeMetadata(submission.metadata, identity.metadata);\n\n try {\n const result = await sz.submitScore({\n boardId: config.boardId,\n playerId: identity.playerId,\n score: submission.score,\n ...(metadata !== undefined ? { metadata } : {}),\n });\n return jsonResponse(\n {\n ok: true,\n rank: result.rank,\n totalEntries: result.totalEntries,\n isPersonalBest: result.isPersonalBest,\n },\n 200,\n cors,\n );\n } catch (err: unknown) {\n return mapSubmitError(err, cors);\n }\n };\n}\n\nasync function defaultParseSubmission(req: Request): Promise<ParsedScoreSubmission | null> {\n const raw: unknown = await req.json().catch(() => null);\n if (!isPlainObject(raw)) return null;\n const score = raw.score;\n if (typeof score !== 'number' || !Number.isFinite(score)) return null;\n return { score, metadata: isPlainObject(raw.metadata) ? raw.metadata : undefined };\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction mergeMetadata(\n client: Record<string, unknown> | undefined,\n verified: Record<string, unknown> | undefined,\n): Record<string, unknown> | undefined {\n if (!client && !verified) return undefined;\n // Verified (trusted) values win over client-supplied ones on conflict.\n return { ...(client ?? {}), ...(verified ?? {}) };\n}\n\nfunction jsonResponse(body: unknown, status: number, extra: Record<string, string>): Response {\n return new Response(JSON.stringify(body), {\n status,\n headers: { 'Content-Type': 'application/json; charset=utf-8', ...extra },\n });\n}\n\nfunction mapSubmitError(err: unknown, cors: Record<string, string>): Response {\n if (err instanceof ScorezillaError) {\n if (err.isRateLimited()) {\n const headers = { ...cors };\n if (err.retryAfter !== undefined) headers['Retry-After'] = String(err.retryAfter);\n return jsonResponse({ ok: false, error: 'rate_limited' }, 429, headers);\n }\n // Echo genuine client errors (e.g. out_of_bounds, invalid_input); treat\n // everything else (5xx, network) as an upstream failure.\n if (err.status >= 400 && err.status < 500) {\n return jsonResponse({ ok: false, error: err.code, message: err.message }, err.status, cors);\n }\n return jsonResponse({ ok: false, error: 'upstream_error' }, 502, cors);\n }\n return jsonResponse({ ok: false, error: 'server_error' }, 500, cors);\n}\n\nfunction buildCorsHeaders(\n cors: ScoreSubmitCorsOptions,\n origin: string | null,\n): Record<string, string> {\n const headers: Record<string, string> = {\n 'Access-Control-Allow-Methods': (cors.methods ?? ['POST', 'OPTIONS']).join(', '),\n 'Access-Control-Allow-Headers': (cors.headers ?? ['content-type', 'authorization']).join(', '),\n 'Access-Control-Max-Age': String(cors.maxAgeSeconds ?? 600),\n Vary: 'Origin',\n };\n if (origin !== null && isCorsOriginAllowed(cors.origin, origin)) {\n headers['Access-Control-Allow-Origin'] = origin;\n }\n return headers;\n}\n\nfunction isCorsOriginAllowed(rule: ScoreSubmitCorsOptions['origin'], origin: string): boolean {\n if (typeof rule === 'boolean') return rule;\n if (typeof rule === 'string') return rule === origin;\n if (typeof rule === 'function') return rule(origin);\n return rule.includes(origin);\n}\n\n// Mirror the public-key client's pattern: re-export error + response\n// types so consumers of `'scorezilla/server'` get everything they need\n// for typed catch blocks without a second import from the core package.\nexport { ScorezillaError } from './errors';\nexport type {\n ApiSuccess,\n LeaderboardResponse,\n PlayerRankResponse,\n RankedEntry,\n ScorezillaErrorCode,\n SubmitScoreResponse,\n WindowAroundResponse,\n} from './types';\n\n// Built-in `verify` helpers for createScoreSubmitHandler (#211). `jose` is an\n// optional peer dependency, loaded lazily — only consumers of these pay for it.\nexport {\n verifyJwt,\n verifySupabaseJwt,\n verifyClerkJwt,\n verifyAuth0Jwt,\n verifyFirebaseIdToken,\n} from './verifiers';\nexport type {\n RequestVerifier,\n VerifyJwtOptions,\n VerifySupabaseJwtOptions,\n VerifyClerkJwtOptions,\n VerifyAuth0JwtOptions,\n VerifyFirebaseIdTokenOptions,\n} from './verifiers';\n\n// GitHub OAuth callback endpoint — the server half of\n// `useAuthProvider({ provider: 'github' })` (ADR 0009, #194).\nexport { createGitHubOAuthHandler } from './github-oauth';\nexport type { CreateGitHubOAuthHandlerConfig, GitHubOAuthHandler } from './github-oauth';\n"]}