scorezilla 0.2.0 → 0.3.0-next.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/paths.ts","../src/errors.ts","../src/retry.ts","../src/transport.ts","../src/user-agent.ts","../src/client.ts","../src/index.ts"],"names":[],"mappings":"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","file":"index.cjs","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 * 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 * `Scorezilla` — the public-key client for v0.1.0.\n *\n * Composes the substrate modules (transport, retry, errors, config,\n * paths, user-agent) into the four documented public methods:\n *\n * • {@link Scorezilla.submitScore}\n * • {@link Scorezilla.getLeaderboard}\n * • {@link Scorezilla.getPlayerRank}\n * • {@link Scorezilla.getWindowAround}\n *\n * Every method returns a parsed, typed response on the success path and\n * throws {@link ScorezillaError} on every failure path (HTTP non-2xx,\n * network failures, aborts, timeouts, invalid JSON).\n *\n * **Input contract — `playerId` only.** The SDK does NOT accept a `player`\n * alias. TypeScript discriminated unions that differ only in key name\n * produce no narrowing benefit and create friction for callers spreading\n * existing types. v0.1.0 is the moment to be strict.\n *\n * **Auth — v0.1.0 is public-key only.** A `ScorezillaConfig` with\n * `secretKey` is accepted by `validateConfig` (since the type union covers\n * both kinds) but the constructor throws a clear `Error` pointing to the\n * future `scorezilla/server` adapter (v0.2.0). This prevents accidental\n * browser leakage of secret keys via the public-key surface.\n */\n\nimport { validateConfig, type ResolvedConfig, type ScorezillaConfig } from './config';\nimport {\n getLeaderboardPath,\n getPlayerRankPath,\n getWindowAroundPath,\n submitScorePath,\n} from './paths';\nimport { request, type RequestOptions } from './transport';\nimport type {\n ApiSuccess,\n LeaderboardResponse,\n PlayerRankResponse,\n SubmitScoreResponse,\n WindowAroundResponse,\n} from './types';\nimport { defaultUserAgent } from './user-agent';\n\n// ---------------------------------------------------------------------------\n// Public input types\n//\n// Each input field uses `?: T | undefined` (with explicit `| undefined`) so\n// callers under `exactOptionalPropertyTypes: true` can pass a maybe-undefined\n// variable without a spread workaround. See COMPATIBILITY.md for the\n// detailed callout.\n// ---------------------------------------------------------------------------\n\n/** Caller-cancellable common shape. All public methods accept an\n * `AbortSignal` so framework consumers (Next.js route handlers, Hono,\n * Express request lifecycles, React effect cleanup) can propagate\n * cancellation through to the underlying `fetch`. The signal is wired\n * into the transport's per-attempt timeout composition — aborting the\n * caller signal cancels any in-flight retry. */\nexport interface CancellableInput {\n /** Optional `AbortSignal` to cancel the request mid-flight. The SDK\n * composes this with its per-attempt timeout, so aborting always wins\n * over the SDK's own timer. */\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 /** The SDK accepts ONLY `playerId`. Pass your stable per-player identifier\n * (UUID, account id, anonymous-session id). Avoid PII. */\n playerId: string;\n /** Finite number. The API rejects NaN, Infinity, and values outside the\n * board's configured `[minScore, maxScore]` range with `out_of_bounds`. */\n score: number;\n /** Optional structured context attached to the submission. Validated\n * locally before send: no functions, no symbols, no circular refs;\n * ≤ 4 KB UTF-8 bytes when JSON-stringified. */\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 to return. 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// Metadata validation\n//\n// Local pre-flight checks so callers fail fast on programmer errors rather\n// than receiving a vague 400 from the API. Two failure modes:\n// 1. Structural — functions, symbols, circular refs aren't serializable.\n// 2. Size — JSON.stringify result exceeds 4 KB UTF-8 bytes.\n//\n// Returns the canonicalized JSON string the validator produced. Callers\n// that pass it through to the transport avoid a second JSON.stringify on\n// the same object — meaningful for submit hot paths in high-frequency\n// games. Tests can assert on the string directly.\n// ---------------------------------------------------------------------------\n\n/** Maximum size, in UTF-8 bytes, of a metadata payload. */\nexport const METADATA_MAX_BYTES = 4096;\n\nfunction validateMetadata(metadata: Record<string, unknown>): string {\n if (metadata === null || typeof metadata !== 'object' || Array.isArray(metadata)) {\n throw new Error(\n 'scorezilla: metadata must be a plain object (got ' +\n (Array.isArray(metadata) ? 'array' : typeof metadata) +\n ')',\n );\n }\n\n let serialized: string;\n try {\n serialized = JSON.stringify(metadata, (_key, value): unknown => {\n if (typeof value === 'function') {\n throw new Error('scorezilla: metadata may not contain functions');\n }\n if (typeof value === 'symbol') {\n throw new Error('scorezilla: metadata may not contain symbols');\n }\n if (typeof value === 'bigint') {\n // BigInt isn't representable in JSON; without this check, JSON.stringify\n // would throw a confusing TypeError. Fail fast with a clear message.\n throw new Error('scorezilla: metadata may not contain BigInt');\n }\n return value;\n });\n } catch (cause) {\n if (cause instanceof Error) {\n // The replacer's explicit Errors propagate; re-throw verbatim.\n if (cause.message.startsWith('scorezilla:')) throw cause;\n // JSON.stringify on a circular structure throws TypeError with\n // engine-specific messages — normalize to a single clear error.\n if (/circular|convert|cyclic/i.test(cause.message)) {\n throw new Error('scorezilla: metadata contains circular references');\n }\n }\n throw cause;\n }\n\n // UTF-8 byte length, NOT character length. The wire format is JSON, and\n // the API gates on bytes. Avoids the surprise of a 4000-char string with\n // emoji weighing 12 000 bytes.\n const byteLength = new TextEncoder().encode(serialized).length;\n if (byteLength > METADATA_MAX_BYTES) {\n throw new Error(\n `scorezilla: metadata exceeds ${METADATA_MAX_BYTES} bytes (got ${byteLength} bytes when JSON-stringified)`,\n );\n }\n return serialized;\n}\n\n// ---------------------------------------------------------------------------\n// Scorezilla class\n// ---------------------------------------------------------------------------\n\n/**\n * Public-key client for the Scorezilla API.\n *\n * ```ts\n * const sz = new Scorezilla({ publicKey: 'pk_mygame_aBcDeF…' });\n * const { rank, isPersonalBest } = await sz.submitScore({\n * boardId: 'board-uuid',\n * playerId: 'player-uuid',\n * score: 9001,\n * });\n * ```\n *\n * @since 0.1.0\n * @stability stable\n */\nexport class Scorezilla {\n /** The package version, injected at build time from `package.json`. */\n static readonly version: string = __SCOREZILLA_SDK_VERSION__;\n\n readonly #config: ResolvedConfig;\n readonly #userAgent: string;\n readonly #authHeader: string;\n\n /**\n * @param config - public-key configuration. Passing `secretKey` throws —\n * use the `scorezilla/server` adapter (v0.2.0) for HMAC.\n */\n constructor(config: ScorezillaConfig) {\n const resolved = validateConfig(config);\n if (resolved.auth.kind !== 'public') {\n throw new Error(\n 'scorezilla: the default `Scorezilla` client is public-key only. ' +\n 'Secret-key (HMAC) auth ships in v0.2.0 via the `scorezilla/server` adapter — ' +\n 'use that for server-side code; use `publicKey` for browser / public clients.',\n );\n }\n this.#config = resolved;\n this.#userAgent = resolved.userAgent ?? defaultUserAgent(Scorezilla.version);\n this.#authHeader = `Bearer ${resolved.auth.key}`;\n }\n\n /**\n * Submit a score to a board.\n *\n * Maps to `POST /v1/boards/:boardId/scores`. See [API.md](../API.md#submitscore)\n * for the full contract.\n *\n * @example\n * ```ts\n * try {\n * const r = await sz.submitScore({ boardId, playerId: 'alice', score: 9001 });\n * if (r.isPersonalBest) console.log(`PB! Rank ${r.rank} of ${r.totalEntries}`);\n * } catch (e) {\n * if (e instanceof ScorezillaError && e.code === 'out_of_bounds') {\n * console.warn(`Score outside board bounds (${e.reason}, limit ${e.bound})`);\n * } else throw e;\n * }\n * ```\n *\n * @throws {ScorezillaError} `unauthorized` (bad publicKey), `forbidden`\n * (key not bound to this board), `not_found` (board doesn't exist),\n * `out_of_bounds` (score outside board's min/max), `rate_limited`\n * (Layer 2/3 throttle hit), `invalid_input`, `network_error`, `timeout`.\n * @since 0.1.0\n * @stability stable\n */\n async submitScore(input: SubmitScoreInput): Promise<ApiSuccess<SubmitScoreResponse>> {\n if (input.metadata !== undefined) {\n validateMetadata(input.metadata);\n }\n\n const body: Record<string, unknown> = {\n playerId: input.playerId,\n score: input.score,\n };\n if (input.metadata !== undefined) {\n body.metadata = input.metadata;\n }\n\n return this.#request<ApiSuccess<SubmitScoreResponse>>({\n path: submitScorePath(input.boardId),\n method: 'POST',\n body,\n signal: input.signal,\n });\n }\n\n /**\n * Fetch the top-N leaderboard for a board.\n *\n * Maps to `GET /v1/boards/:boardId/leaderboard`.\n *\n * @example\n * ```ts\n * const { entries } = await sz.getLeaderboard({ boardId, top: 25 });\n * for (const e of entries) console.log(`${e.rank}. ${e.playerId}: ${e.score}`);\n * ```\n *\n * @throws {ScorezillaError} `not_found`, `network_error`, `timeout`.\n * @since 0.1.0\n * @stability stable\n */\n async getLeaderboard(input: GetLeaderboardInput): Promise<ApiSuccess<LeaderboardResponse>> {\n const q: { top?: number; offset?: number } = {};\n if (input.top !== undefined) q.top = input.top;\n if (input.offset !== undefined) q.offset = input.offset;\n return this.#request<ApiSuccess<LeaderboardResponse>>({\n path: getLeaderboardPath(input.boardId, q),\n method: 'GET',\n signal: input.signal,\n });\n }\n\n /**\n * Fetch a single player's rank on a board.\n *\n * Maps to `GET /v1/boards/:boardId/players/:playerId/rank`. Returns 404\n * (`not_found`) if the player has no entry yet.\n *\n * @example\n * ```ts\n * try {\n * const { rank, score } = await sz.getPlayerRank({ boardId, playerId: 'alice' });\n * console.log(`Alice is rank ${rank} with score ${score}`);\n * } catch (e) {\n * if (e instanceof ScorezillaError && e.isNotFound()) {\n * console.log('Alice has no submission on this board yet.');\n * } else throw e;\n * }\n * ```\n *\n * @throws {ScorezillaError} `not_found` (player has no submission),\n * `network_error`, `timeout`.\n * @since 0.1.0\n * @stability stable\n */\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 /**\n * Fetch the slice of entries surrounding a player.\n *\n * Maps to `GET /v1/boards/:boardId/players/:playerId/window?before=&after=`.\n *\n * @example\n * ```ts\n * const { entries } = await sz.getWindowAround({\n * boardId, playerId: 'alice', before: 2, after: 2,\n * });\n * ```\n *\n * @throws {ScorezillaError} `network_error`, `timeout`.\n * @since 0.1.0\n * @stability stable\n */\n async getWindowAround(input: GetWindowAroundInput): Promise<ApiSuccess<WindowAroundResponse>> {\n const q: { before?: number; after?: number } = {};\n if (input.before !== undefined) q.before = input.before;\n if (input.after !== undefined) q.after = input.after;\n return this.#request<ApiSuccess<WindowAroundResponse>>({\n path: getWindowAroundPath(input.boardId, input.playerId, q),\n method: 'GET',\n signal: input.signal,\n });\n }\n\n // ─── Internal ────────────────────────────────────────────────────────\n\n /**\n * Common request wiring — auth header, default fetch impl, timeout, retry.\n * Each public method composes its `path`, `method`, and (optionally) `body`\n * and hands them to this thin pass-through. Keeps the four method bodies\n * boilerplate-free and ensures every call shares identical defaults.\n */\n async #request<T extends { ok: true }>(\n opts: Pick<RequestOptions, 'path' | 'method' | 'body' | 'signal'>,\n ): Promise<T> {\n const headers: Record<string, string> = {\n Authorization: this.#authHeader,\n // User-Agent: ignored by browsers (per Fetch spec), useful in\n // Node/Bun/Deno/Workers for server-side observability.\n 'User-Agent': this.#userAgent,\n // X-Scorezilla-Client: browser-honored, mirrors the UA for telemetry\n // parity across runtimes.\n 'X-Scorezilla-Client': this.#userAgent,\n };\n\n const requestOpts: RequestOptions = {\n baseUrl: this.#config.baseUrl,\n path: opts.path,\n method: opts.method,\n headers,\n };\n if (opts.body !== undefined) requestOpts.body = opts.body;\n if (opts.signal !== undefined) requestOpts.signal = opts.signal;\n if (this.#config.fetch !== undefined) requestOpts.fetchImpl = this.#config.fetch;\n if (this.#config.warn !== undefined) requestOpts.warnImpl = this.#config.warn;\n if (this.#config.timeoutMs !== undefined) requestOpts.timeoutMs = this.#config.timeoutMs;\n // Build the `retry` block only if at least one knob is set. Two\n // distinct config options (`maxRetries`, `sleepImpl`) collapse into\n // the single `retry: { ... }` shape transport expects.\n if (this.#config.maxRetries !== undefined || this.#config.sleepImpl !== undefined) {\n requestOpts.retry = {\n ...(this.#config.maxRetries !== undefined ? { maxRetries: this.#config.maxRetries } : {}),\n ...(this.#config.sleepImpl !== undefined ? { sleepImpl: this.#config.sleepImpl } : {}),\n };\n }\n\n return request<T>(requestOpts);\n }\n}\n\n/**\n * Convenience factory for users who prefer a functional API.\n *\n * Functionally equivalent to `new Scorezilla(config)` — same auth rules,\n * same validation, same instance type. The only reason to prefer one over\n * the other is code style.\n *\n * @example\n * ```ts\n * import { createClient, ScorezillaError } from 'scorezilla';\n *\n * const sz = createClient({ publicKey: 'pk_mygame_…' });\n * try {\n * await sz.submitScore({ boardId, playerId: 'alice', score: 9001 });\n * } catch (e) {\n * if (e instanceof ScorezillaError && e.isRateLimited()) {\n * await new Promise((r) => setTimeout(r, (e.retryAfter ?? 30) * 1000));\n * } else throw e;\n * }\n * ```\n *\n * @throws Plain `Error` if the config is malformed (e.g. invalid\n * `publicKey` format, or `secretKey` passed to the public-key client).\n * See `validateConfig`.\n * @since 0.1.0\n * @stability stable\n */\nexport function createClient(config: ScorezillaConfig): Scorezilla {\n return new Scorezilla(config);\n}\n\n// Re-export the error class here too so consumers can `import { Scorezilla,\n// ScorezillaError } from 'scorezilla'` in one statement.\nexport { ScorezillaError } from './errors';\n","/**\n * Scorezilla SDK — public entry.\n *\n * Surface (v0.1.0):\n * • `Scorezilla` — public-key client (browser + Node ≥ 20 + Workers + Bun + Deno)\n * • `createClient` — convenience factory\n * • `ScorezillaError` — the single error type the SDK throws\n * • `SDK_VERSION` — exported for support / bug-reporting\n * • All wire types — `SubmitScoreResponse`, `LeaderboardResponse`, etc.\n * • All input types — `SubmitScoreInput`, `GetLeaderboardInput`, etc.\n * • Config types — `ScorezillaConfig`, `PublicKeyConfig`, `SecretKeyConfig`\n *\n * The HMAC server-side client (`scorezilla/server`), React adapter\n * (`scorezilla/react`), and Phaser plugin (`scorezilla/phaser`) ship in\n * later minor releases — see CHANGELOG.md.\n */\n\n// Re-export the class + convenience factory + error type.\nexport { createClient, Scorezilla, ScorezillaError } from './client';\n\n// Re-export public input types.\nexport type {\n GetLeaderboardInput,\n GetPlayerRankInput,\n GetWindowAroundInput,\n SubmitScoreInput,\n} from './client';\n\n// Re-export config types so consumers can typed-store the config object.\nexport type { BaseConfig, PublicKeyConfig, ScorezillaConfig, SecretKeyConfig } from './config';\n\n// Re-export wire types — consumers ARE the API contract; expose every shape.\nexport type {\n ApiError,\n ApiResponse,\n ApiSuccess,\n LeaderboardResponse,\n OutOfBoundsReason,\n PlayerRankResponse,\n RankedEntry,\n ScorezillaErrorCode,\n SubmitScoreResponse,\n WindowAroundResponse,\n} from './types';\n\n// Re-export the runtime-detection helper — opt-in observability for\n// consumers who want to label their own telemetry.\nexport { detectRuntime, type Runtime } from './user-agent';\n\n// Build-time-injected version constant — see global.d.ts.\nexport const SDK_VERSION: string = __SCOREZILLA_SDK_VERSION__;\n"]}
1
+ {"version":3,"sources":["../src/config.ts","../src/paths.ts","../src/errors.ts","../src/retry.ts","../src/transport.ts","../src/user-agent.ts","../src/client.ts","../src/index.ts"],"names":[],"mappings":"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","file":"index.cjs","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 * 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 * `Scorezilla` — the public-key client for v0.1.0.\n *\n * Composes the substrate modules (transport, retry, errors, config,\n * paths, user-agent) into the four documented public methods:\n *\n * • {@link Scorezilla.submitScore}\n * • {@link Scorezilla.getLeaderboard}\n * • {@link Scorezilla.getPlayerRank}\n * • {@link Scorezilla.getWindowAround}\n *\n * Every method returns a parsed, typed response on the success path and\n * throws {@link ScorezillaError} on every failure path (HTTP non-2xx,\n * network failures, aborts, timeouts, invalid JSON).\n *\n * **Input contract — `playerId` only.** The SDK does NOT accept a `player`\n * alias. TypeScript discriminated unions that differ only in key name\n * produce no narrowing benefit and create friction for callers spreading\n * existing types. v0.1.0 is the moment to be strict.\n *\n * **Auth — v0.1.0 is public-key only.** A `ScorezillaConfig` with\n * `secretKey` is accepted by `validateConfig` (since the type union covers\n * both kinds) but the constructor throws a clear `Error` pointing to the\n * future `scorezilla/server` adapter (v0.2.0). This prevents accidental\n * browser leakage of secret keys via the public-key surface.\n */\n\nimport { validateConfig, type ResolvedConfig, type ScorezillaConfig } from './config';\nimport {\n getLeaderboardPath,\n getPlayerRankPath,\n getWindowAroundPath,\n submitScorePath,\n} from './paths';\nimport { request, type RequestOptions } from './transport';\nimport type {\n ApiSuccess,\n LeaderboardResponse,\n PlayerRankResponse,\n SubmitScoreResponse,\n WindowAroundResponse,\n} from './types';\nimport { defaultUserAgent } from './user-agent';\n\n// ---------------------------------------------------------------------------\n// Public input types\n//\n// Each input field uses `?: T | undefined` (with explicit `| undefined`) so\n// callers under `exactOptionalPropertyTypes: true` can pass a maybe-undefined\n// variable without a spread workaround. See COMPATIBILITY.md for the\n// detailed callout.\n// ---------------------------------------------------------------------------\n\n/** Caller-cancellable common shape. All public methods accept an\n * `AbortSignal` so framework consumers (Next.js route handlers, Hono,\n * Express request lifecycles, React effect cleanup) can propagate\n * cancellation through to the underlying `fetch`. The signal is wired\n * into the transport's per-attempt timeout composition — aborting the\n * caller signal cancels any in-flight retry. */\nexport interface CancellableInput {\n /** Optional `AbortSignal` to cancel the request mid-flight. The SDK\n * composes this with its per-attempt timeout, so aborting always wins\n * over the SDK's own timer. */\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 /** The SDK accepts ONLY `playerId`. Pass your stable per-player identifier\n * (UUID, account id, anonymous-session id). Avoid PII. */\n playerId: string;\n /** Finite number. The API rejects NaN, Infinity, and values outside the\n * board's configured `[minScore, maxScore]` range with `out_of_bounds`. */\n score: number;\n /** Optional structured context attached to the submission. Validated\n * locally before send: no functions, no symbols, no circular refs;\n * ≤ 4 KB UTF-8 bytes when JSON-stringified. */\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 to return. 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// Metadata validation\n//\n// Local pre-flight checks so callers fail fast on programmer errors rather\n// than receiving a vague 400 from the API. Two failure modes:\n// 1. Structural — functions, symbols, circular refs aren't serializable.\n// 2. Size — JSON.stringify result exceeds 4 KB UTF-8 bytes.\n//\n// Returns the canonicalized JSON string the validator produced. Callers\n// that pass it through to the transport avoid a second JSON.stringify on\n// the same object — meaningful for submit hot paths in high-frequency\n// games. Tests can assert on the string directly.\n// ---------------------------------------------------------------------------\n\n/** Maximum size, in UTF-8 bytes, of a metadata payload. */\nexport const METADATA_MAX_BYTES = 4096;\n\nfunction validateMetadata(metadata: Record<string, unknown>): string {\n if (metadata === null || typeof metadata !== 'object' || Array.isArray(metadata)) {\n throw new Error(\n 'scorezilla: metadata must be a plain object (got ' +\n (Array.isArray(metadata) ? 'array' : typeof metadata) +\n ')',\n );\n }\n\n let serialized: string;\n try {\n serialized = JSON.stringify(metadata, (_key, value): unknown => {\n if (typeof value === 'function') {\n throw new Error('scorezilla: metadata may not contain functions');\n }\n if (typeof value === 'symbol') {\n throw new Error('scorezilla: metadata may not contain symbols');\n }\n if (typeof value === 'bigint') {\n // BigInt isn't representable in JSON; without this check, JSON.stringify\n // would throw a confusing TypeError. Fail fast with a clear message.\n throw new Error('scorezilla: metadata may not contain BigInt');\n }\n return value;\n });\n } catch (cause) {\n if (cause instanceof Error) {\n // The replacer's explicit Errors propagate; re-throw verbatim.\n if (cause.message.startsWith('scorezilla:')) throw cause;\n // JSON.stringify on a circular structure throws TypeError with\n // engine-specific messages — normalize to a single clear error.\n if (/circular|convert|cyclic/i.test(cause.message)) {\n throw new Error('scorezilla: metadata contains circular references');\n }\n }\n throw cause;\n }\n\n // UTF-8 byte length, NOT character length. The wire format is JSON, and\n // the API gates on bytes. Avoids the surprise of a 4000-char string with\n // emoji weighing 12 000 bytes.\n const byteLength = new TextEncoder().encode(serialized).length;\n if (byteLength > METADATA_MAX_BYTES) {\n throw new Error(\n `scorezilla: metadata exceeds ${METADATA_MAX_BYTES} bytes (got ${byteLength} bytes when JSON-stringified)`,\n );\n }\n return serialized;\n}\n\n// ---------------------------------------------------------------------------\n// Scorezilla class\n// ---------------------------------------------------------------------------\n\n/**\n * Public-key client for the Scorezilla API.\n *\n * ```ts\n * const sz = new Scorezilla({ publicKey: 'pk_mygame_aBcDeF…' });\n * const { rank, isPersonalBest } = await sz.submitScore({\n * boardId: 'board-uuid',\n * playerId: 'player-uuid',\n * score: 9001,\n * });\n * ```\n *\n * @since 0.1.0\n * @stability stable\n */\nexport class Scorezilla {\n /** The package version, injected at build time from `package.json`. */\n static readonly version: string = __SCOREZILLA_SDK_VERSION__;\n\n readonly #config: ResolvedConfig;\n readonly #userAgent: string;\n readonly #authHeader: string;\n\n /**\n * @param config - public-key configuration. Passing `secretKey` throws —\n * use the `scorezilla/server` adapter (v0.2.0) for HMAC.\n */\n constructor(config: ScorezillaConfig) {\n const resolved = validateConfig(config);\n if (resolved.auth.kind !== 'public') {\n throw new Error(\n 'scorezilla: the default `Scorezilla` client is public-key only. ' +\n 'Secret-key (HMAC) auth ships in v0.2.0 via the `scorezilla/server` adapter — ' +\n 'use that for server-side code; use `publicKey` for browser / public clients.',\n );\n }\n this.#config = resolved;\n this.#userAgent = resolved.userAgent ?? defaultUserAgent(Scorezilla.version);\n this.#authHeader = `Bearer ${resolved.auth.key}`;\n }\n\n /**\n * Submit a score to a board.\n *\n * Maps to `POST /v1/boards/:boardId/scores`. See [API.md](../API.md#submitscore)\n * for the full contract.\n *\n * @example\n * ```ts\n * try {\n * const r = await sz.submitScore({ boardId, playerId: 'alice', score: 9001 });\n * if (r.isPersonalBest) console.log(`PB! Rank ${r.rank} of ${r.totalEntries}`);\n * } catch (e) {\n * if (e instanceof ScorezillaError && e.code === 'out_of_bounds') {\n * console.warn(`Score outside board bounds (${e.reason}, limit ${e.bound})`);\n * } else throw e;\n * }\n * ```\n *\n * @throws {ScorezillaError} `unauthorized` (bad publicKey), `forbidden`\n * (key not bound to this board), `not_found` (board doesn't exist),\n * `out_of_bounds` (score outside board's min/max), `rate_limited`\n * (Layer 2/3 throttle hit), `invalid_input`, `network_error`, `timeout`.\n * @since 0.1.0\n * @stability stable\n */\n async submitScore(input: SubmitScoreInput): Promise<ApiSuccess<SubmitScoreResponse>> {\n if (input.metadata !== undefined) {\n validateMetadata(input.metadata);\n }\n\n const body: Record<string, unknown> = {\n playerId: input.playerId,\n score: input.score,\n };\n if (input.metadata !== undefined) {\n body.metadata = input.metadata;\n }\n\n return this.#request<ApiSuccess<SubmitScoreResponse>>({\n path: submitScorePath(input.boardId),\n method: 'POST',\n body,\n signal: input.signal,\n });\n }\n\n /**\n * Fetch the top-N leaderboard for a board.\n *\n * Maps to `GET /v1/boards/:boardId/leaderboard`.\n *\n * @example\n * ```ts\n * const { entries } = await sz.getLeaderboard({ boardId, top: 25 });\n * for (const e of entries) console.log(`${e.rank}. ${e.playerId}: ${e.score}`);\n * ```\n *\n * @throws {ScorezillaError} `not_found`, `network_error`, `timeout`.\n * @since 0.1.0\n * @stability stable\n */\n async getLeaderboard(input: GetLeaderboardInput): Promise<ApiSuccess<LeaderboardResponse>> {\n const q: { top?: number; offset?: number } = {};\n if (input.top !== undefined) q.top = input.top;\n if (input.offset !== undefined) q.offset = input.offset;\n return this.#request<ApiSuccess<LeaderboardResponse>>({\n path: getLeaderboardPath(input.boardId, q),\n method: 'GET',\n signal: input.signal,\n });\n }\n\n /**\n * Fetch a single player's rank on a board.\n *\n * Maps to `GET /v1/boards/:boardId/players/:playerId/rank`. Returns 404\n * (`not_found`) if the player has no entry yet.\n *\n * @example\n * ```ts\n * try {\n * const { rank, score } = await sz.getPlayerRank({ boardId, playerId: 'alice' });\n * console.log(`Alice is rank ${rank} with score ${score}`);\n * } catch (e) {\n * if (e instanceof ScorezillaError && e.isNotFound()) {\n * console.log('Alice has no submission on this board yet.');\n * } else throw e;\n * }\n * ```\n *\n * @throws {ScorezillaError} `not_found` (player has no submission),\n * `network_error`, `timeout`.\n * @since 0.1.0\n * @stability stable\n */\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 /**\n * Fetch the slice of entries surrounding a player.\n *\n * Maps to `GET /v1/boards/:boardId/players/:playerId/window?before=&after=`.\n *\n * @example\n * ```ts\n * const { entries } = await sz.getWindowAround({\n * boardId, playerId: 'alice', before: 2, after: 2,\n * });\n * ```\n *\n * @throws {ScorezillaError} `network_error`, `timeout`.\n * @since 0.1.0\n * @stability stable\n */\n async getWindowAround(input: GetWindowAroundInput): Promise<ApiSuccess<WindowAroundResponse>> {\n const q: { before?: number; after?: number } = {};\n if (input.before !== undefined) q.before = input.before;\n if (input.after !== undefined) q.after = input.after;\n return this.#request<ApiSuccess<WindowAroundResponse>>({\n path: getWindowAroundPath(input.boardId, input.playerId, q),\n method: 'GET',\n signal: input.signal,\n });\n }\n\n // ─── Internal ────────────────────────────────────────────────────────\n\n /**\n * Common request wiring — auth header, default fetch impl, timeout, retry.\n * Each public method composes its `path`, `method`, and (optionally) `body`\n * and hands them to this thin pass-through. Keeps the four method bodies\n * boilerplate-free and ensures every call shares identical defaults.\n */\n async #request<T extends { ok: true }>(\n opts: Pick<RequestOptions, 'path' | 'method' | 'body' | 'signal'>,\n ): Promise<T> {\n const headers: Record<string, string> = {\n Authorization: this.#authHeader,\n // User-Agent: ignored by browsers (per Fetch spec), useful in\n // Node/Bun/Deno/Workers for server-side observability.\n 'User-Agent': this.#userAgent,\n // X-Scorezilla-Client: browser-honored, mirrors the UA for telemetry\n // parity across runtimes.\n 'X-Scorezilla-Client': this.#userAgent,\n };\n\n const requestOpts: RequestOptions = {\n baseUrl: this.#config.baseUrl,\n path: opts.path,\n method: opts.method,\n headers,\n };\n if (opts.body !== undefined) requestOpts.body = opts.body;\n if (opts.signal !== undefined) requestOpts.signal = opts.signal;\n if (this.#config.fetch !== undefined) requestOpts.fetchImpl = this.#config.fetch;\n if (this.#config.warn !== undefined) requestOpts.warnImpl = this.#config.warn;\n if (this.#config.timeoutMs !== undefined) requestOpts.timeoutMs = this.#config.timeoutMs;\n // Build the `retry` block only if at least one knob is set. Two\n // distinct config options (`maxRetries`, `sleepImpl`) collapse into\n // the single `retry: { ... }` shape transport expects.\n if (this.#config.maxRetries !== undefined || this.#config.sleepImpl !== undefined) {\n requestOpts.retry = {\n ...(this.#config.maxRetries !== undefined ? { maxRetries: this.#config.maxRetries } : {}),\n ...(this.#config.sleepImpl !== undefined ? { sleepImpl: this.#config.sleepImpl } : {}),\n };\n }\n\n return request<T>(requestOpts);\n }\n}\n\n/**\n * Convenience factory for users who prefer a functional API.\n *\n * Functionally equivalent to `new Scorezilla(config)` — same auth rules,\n * same validation, same instance type. The only reason to prefer one over\n * the other is code style.\n *\n * @example\n * ```ts\n * import { createClient, ScorezillaError } from 'scorezilla';\n *\n * const sz = createClient({ publicKey: 'pk_mygame_…' });\n * try {\n * await sz.submitScore({ boardId, playerId: 'alice', score: 9001 });\n * } catch (e) {\n * if (e instanceof ScorezillaError && e.isRateLimited()) {\n * await new Promise((r) => setTimeout(r, (e.retryAfter ?? 30) * 1000));\n * } else throw e;\n * }\n * ```\n *\n * @throws Plain `Error` if the config is malformed (e.g. invalid\n * `publicKey` format, or `secretKey` passed to the public-key client).\n * See `validateConfig`.\n * @since 0.1.0\n * @stability stable\n */\nexport function createClient(config: ScorezillaConfig): Scorezilla {\n return new Scorezilla(config);\n}\n\n// Re-export the error class here too so consumers can `import { Scorezilla,\n// ScorezillaError } from 'scorezilla'` in one statement.\nexport { ScorezillaError } from './errors';\n","/**\n * Scorezilla SDK — public entry.\n *\n * Surface (v0.1.0):\n * • `Scorezilla` — public-key client (browser + Node ≥ 20 + Workers + Bun + Deno)\n * • `createClient` — convenience factory\n * • `ScorezillaError` — the single error type the SDK throws\n * • `SDK_VERSION` — exported for support / bug-reporting\n * • All wire types — `SubmitScoreResponse`, `LeaderboardResponse`, etc.\n * • All input types — `SubmitScoreInput`, `GetLeaderboardInput`, etc.\n * • Config types — `ScorezillaConfig`, `PublicKeyConfig`, `SecretKeyConfig`\n *\n * The HMAC server-side client (`scorezilla/server`), React adapter\n * (`scorezilla/react`), and Phaser plugin (`scorezilla/phaser`) ship in\n * later minor releases — see CHANGELOG.md.\n */\n\n// Re-export the class + convenience factory + error type.\nexport { createClient, Scorezilla, ScorezillaError } from './client';\n\n// Re-export public input types.\nexport type {\n GetLeaderboardInput,\n GetPlayerRankInput,\n GetWindowAroundInput,\n SubmitScoreInput,\n} from './client';\n\n// Re-export config types so consumers can typed-store the config object.\nexport type { BaseConfig, PublicKeyConfig, ScorezillaConfig, SecretKeyConfig } from './config';\n\n// Re-export wire types — consumers ARE the API contract; expose every shape.\nexport type {\n ApiError,\n ApiResponse,\n ApiSuccess,\n LeaderboardResponse,\n OutOfBoundsReason,\n PlayerRankResponse,\n RankedEntry,\n ScorezillaErrorCode,\n SubmitScoreResponse,\n WindowAroundResponse,\n} from './types';\n\n// Re-export the runtime-detection helper — opt-in observability for\n// consumers who want to label their own telemetry.\nexport { detectRuntime, type Runtime } from './user-agent';\n\n// Build-time-injected version constant — see global.d.ts.\nexport const SDK_VERSION: string = __SCOREZILLA_SDK_VERSION__;\n"]}
package/dist/index.js CHANGED
@@ -631,7 +631,7 @@ function validateMetadata(metadata) {
631
631
  }
632
632
  var Scorezilla = class _Scorezilla {
633
633
  /** The package version, injected at build time from `package.json`. */
634
- static version = "0.2.0";
634
+ static version = "0.3.0-next.0";
635
635
  #config;
636
636
  #userAgent;
637
637
  #authHeader;
@@ -816,7 +816,7 @@ function createClient(config) {
816
816
  }
817
817
 
818
818
  // src/index.ts
819
- var SDK_VERSION = "0.2.0";
819
+ var SDK_VERSION = "0.3.0-next.0";
820
820
 
821
821
  export { SDK_VERSION, Scorezilla, ScorezillaError, createClient, detectRuntime };
822
822
  //# sourceMappingURL=index.js.map