@openkeyai/sdk 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/errors.ts","../src/_internal/jwks.ts","../src/session.ts","../src/secure-key.ts","../src/keys.ts","../src/index.ts"],"names":["createRemoteJWKSet","jwtVerify","joseErrors","decodeJwt"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Typed errors.\n *\n * The error `code` strings are part of the FROZEN public contract — see the\n * key-fetch endpoint's documentation in\n * https://github.com/Scott-Builds-AI/hub/blob/main/docs/phases/05-tools-keyfetch.md\n *\n * Adding a new code is a minor-version bump. Renaming or removing one is a\n * major (with 60-day notice).\n *\n * Tools catch these to surface precise UX:\n *\n * try {\n * await keys.get(jwt, \"openai\");\n * } catch (e) {\n * if (e instanceof SubscriptionInactiveError) showPaywall();\n * else if (e instanceof RateLimitedError) showRetryToast(e.retryAfter);\n * else throw e;\n * }\n */\n\nexport type HubSdkErrorCode =\n | \"missing_token\"\n | \"bad_token\"\n | \"missing_scope\"\n | \"subscription_inactive\"\n | \"tool_not_found\"\n | \"not_subscribed\"\n | \"provider_not_granted\"\n | \"rate_limited\"\n | \"key_not_found\"\n | \"internal\"\n | \"network\"\n | \"secure_key_consumed\";\n\n/** Base class for every typed error in the SDK. */\nexport class HubSdkError extends Error {\n readonly code: HubSdkErrorCode;\n /** HTTP status from the hub, when applicable. 0 for client-only errors. */\n readonly status: number;\n\n constructor(code: HubSdkErrorCode, message: string, status = 0) {\n super(message);\n this.name = \"HubSdkError\";\n this.code = code;\n this.status = status;\n }\n}\n\n// ─── Wire-level errors (returned by the hub) ────────────────────────────────\n\nexport class MissingTokenError extends HubSdkError {\n constructor() {\n super(\"missing_token\", \"No Authorization token was provided.\", 401);\n this.name = \"MissingTokenError\";\n }\n}\n\nexport class BadTokenError extends HubSdkError {\n constructor(message = \"Token signature / issuer / audience / expiry check failed.\") {\n super(\"bad_token\", message, 401);\n this.name = \"BadTokenError\";\n }\n}\n\nexport class MissingScopeError extends HubSdkError {\n constructor(needed: string) {\n super(\"missing_scope\", `Token is missing the required scope: ${needed}.`, 403);\n this.name = \"MissingScopeError\";\n }\n}\n\nexport class SubscriptionInactiveError extends HubSdkError {\n constructor() {\n super(\n \"subscription_inactive\",\n \"The user's subscription is not active. Surface a paywall — don't retry.\",\n 402,\n );\n this.name = \"SubscriptionInactiveError\";\n }\n}\n\nexport class ToolNotFoundError extends HubSdkError {\n constructor() {\n super(\"tool_not_found\", \"Tool unknown or not approved.\", 404);\n this.name = \"ToolNotFoundError\";\n }\n}\n\nexport class NotSubscribedError extends HubSdkError {\n constructor() {\n super(\n \"not_subscribed\",\n \"The user has not enabled this tool in their hub settings.\",\n 403,\n );\n this.name = \"NotSubscribedError\";\n }\n}\n\nexport class ProviderNotGrantedError extends HubSdkError {\n constructor(provider: string) {\n super(\n \"provider_not_granted\",\n `User has not granted this tool access to the ${provider} provider.`,\n 403,\n );\n this.name = \"ProviderNotGrantedError\";\n }\n}\n\nexport class RateLimitedError extends HubSdkError {\n readonly retryAfter: number;\n constructor(retryAfter: number) {\n super(\n \"rate_limited\",\n `Rate limit hit. Retry after ${retryAfter} seconds.`,\n 429,\n );\n this.name = \"RateLimitedError\";\n this.retryAfter = retryAfter;\n }\n}\n\nexport class KeyNotFoundError extends HubSdkError {\n constructor(provider: string) {\n super(\n \"key_not_found\",\n `No ${provider} key configured for this user. The tool should prompt the user to add one.`,\n 404,\n );\n this.name = \"KeyNotFoundError\";\n }\n}\n\nexport class InternalError extends HubSdkError {\n constructor(status: number, message = \"The hub returned an internal error.\") {\n super(\"internal\", message, status);\n this.name = \"InternalError\";\n }\n}\n\n// ─── Client-only errors ──────────────────────────────────────────────────────\n\nexport class NetworkError extends HubSdkError {\n constructor(cause: unknown) {\n super(\n \"network\",\n `Could not reach the hub: ${cause instanceof Error ? cause.message : String(cause)}`,\n 0,\n );\n this.name = \"NetworkError\";\n this.cause = cause;\n }\n}\n\nexport class SecureKeyConsumedError extends HubSdkError {\n constructor() {\n super(\n \"secure_key_consumed\",\n \"SecureKey has already been used. Each instance is single-use; call keys.get() again to fetch a fresh one.\",\n 0,\n );\n this.name = \"SecureKeyConsumedError\";\n }\n}\n\n// ─── Wire → error mapping ────────────────────────────────────────────────────\n\n/**\n * Build the right HubSdkError subclass from a hub JSON error response. Used\n * by every fetch wrapper so the typed errors stay consistent.\n */\nexport function errorFromResponse(\n status: number,\n body: { error?: string } | null,\n context: { provider?: string; scopeNeeded?: string; retryAfter?: number },\n): HubSdkError {\n const code = body?.error ?? \"internal\";\n switch (code) {\n case \"missing_token\":\n return new MissingTokenError();\n case \"bad_token\":\n return new BadTokenError();\n case \"missing_scope\":\n return new MissingScopeError(context.scopeNeeded ?? \"unknown\");\n case \"subscription_inactive\":\n return new SubscriptionInactiveError();\n case \"tool_not_found\":\n return new ToolNotFoundError();\n case \"not_subscribed\":\n return new NotSubscribedError();\n case \"provider_not_granted\":\n return new ProviderNotGrantedError(context.provider ?? \"unknown\");\n case \"rate_limited\":\n return new RateLimitedError(context.retryAfter ?? 60);\n case \"key_not_found\":\n return new KeyNotFoundError(context.provider ?? \"unknown\");\n case \"internal\":\n default:\n return new InternalError(status);\n }\n}\n","import { createRemoteJWKSet, type JWTVerifyGetKey } from \"jose\";\n\n/**\n * Per-hub-URL JWKS cache.\n *\n * Each call to `keys.get` / `session.verify` needs a key-resolver\n * (`jose.JWTVerifyGetKey`) to feed into `jwtVerify`. Building a fresh\n * resolver per request would re-fetch the JWKS document every time.\n * `createRemoteJWKSet` handles caching internally, but only if we hand\n * back the SAME resolver instance for the same URL.\n *\n * Cache key is the hub URL because the same SDK build might be used by\n * tools that point at staging vs production hubs (different keys, different\n * kids).\n *\n * The cache has no eviction — there's at most a handful of distinct hub\n * URLs in any sane setup. If a tool author somehow constructs thousands of\n * URL variants this would leak memory; that's not a realistic path.\n */\nconst resolvers = new Map<string, JWTVerifyGetKey>();\n\nexport function getJwksResolver(hubUrl: string): JWTVerifyGetKey {\n const cached = resolvers.get(hubUrl);\n if (cached) return cached;\n const url = new URL(\"/.well-known/jwks.json\", hubUrl);\n // jose's createRemoteJWKSet:\n // - fetches lazily on the first verify\n // - caches for `cacheMaxAge` (default 10 minutes)\n // - revalidates after `cooldownDuration` (default 30s)\n // - re-fetches automatically when a verify hits an unknown kid (rotation)\n const resolver = createRemoteJWKSet(url, {\n // Respect the hub's stated cache window (5 min strong + 10 min SWR).\n cacheMaxAge: 5 * 60 * 1000,\n cooldownDuration: 30 * 1000,\n });\n resolvers.set(hubUrl, resolver);\n return resolver;\n}\n\n/** Test helper — drops the cache between cases. Not part of public API. */\nexport function _resetJwksCacheForTests(): void {\n resolvers.clear();\n}\n","import { jwtVerify, errors as joseErrors } from \"jose\";\nimport { BadTokenError, MissingTokenError } from \"./errors\";\nimport { getJwksResolver } from \"./_internal/jwks\";\nimport type { HubCallOptions, ToolJwtClaims, ToolJwtScope } from \"./types\";\n\n/**\n * `session.verify(jwt, opts?)`\n *\n * Verifies a hub-issued JWT against the hub's public JWKS, then validates\n * the claim shape (`iss`, `sub`, `aud`, `scopes`, `subscription_active`).\n *\n * Returns the typed claims on success.\n * Throws `BadTokenError` on any failure — signature, expiry, issuer,\n * audience, missing/malformed custom claims.\n * Throws `MissingTokenError` if `jwt` is empty / null.\n *\n * The verifier:\n * - fetches `${hubUrl}/.well-known/jwks.json` (cached per hub URL)\n * - re-fetches on `kid` rotation (jose handles this transparently)\n * - DOES NOT validate `aud` here — the caller specifies which audience\n * they expect (the tool's own slug, OR a wildcard for tools that\n * legitimately accept multiple audiences). `keys.get` validates\n * audience against the tool slug derived from the route.\n *\n * @param jwt The bearer token string (no `Bearer ` prefix).\n * @param opts.hubUrl override the hub root (default: `https://openkeyai.com`)\n * @param opts.expectedAudience tool slug the token must be addressed to.\n * When omitted, audience is not checked here — the caller MUST do it\n * themselves before granting any scope-derived privilege.\n */\nexport async function verify(\n jwt: string,\n opts: HubCallOptions & { expectedAudience?: string } = {},\n): Promise<ToolJwtClaims> {\n if (!jwt || typeof jwt !== \"string\") {\n throw new MissingTokenError();\n }\n\n const hubUrl = opts.hubUrl ?? \"https://openkeyai.com\";\n const resolver = getJwksResolver(hubUrl);\n\n let payload: Record<string, unknown>;\n try {\n const result = await jwtVerify(jwt, resolver, {\n issuer: \"https://openkeyai.com\",\n algorithms: [\"EdDSA\"],\n ...(opts.expectedAudience ? { audience: opts.expectedAudience } : {}),\n });\n payload = result.payload as Record<string, unknown>;\n } catch (err) {\n if (err instanceof joseErrors.JWTExpired) {\n throw new BadTokenError(\"Token expired.\");\n }\n if (err instanceof joseErrors.JWTClaimValidationFailed) {\n throw new BadTokenError(`Claim validation failed: ${err.message}`);\n }\n if (err instanceof joseErrors.JWSSignatureVerificationFailed) {\n throw new BadTokenError(\"Signature did not verify.\");\n }\n if (err instanceof joseErrors.JWKSNoMatchingKey) {\n throw new BadTokenError(\"Token kid is not in the hub's active JWKS.\");\n }\n if (err instanceof joseErrors.JOSEError) {\n throw new BadTokenError(err.message);\n }\n // Network / unknown — surface as BadToken too rather than leak details.\n throw new BadTokenError(\"Token verification failed.\");\n }\n\n // Custom-claim shape validation. `jose` only validates standard claims.\n const sub = payload.sub;\n const aud = payload.aud;\n const scopes = payload.scopes;\n const subscriptionActive = payload.subscription_active;\n const jti = payload.jti;\n const iat = payload.iat;\n const exp = payload.exp;\n\n if (typeof sub !== \"string\" || sub.length === 0) {\n throw new BadTokenError(\"sub claim missing or invalid.\");\n }\n if (typeof aud !== \"string\" || aud.length === 0) {\n throw new BadTokenError(\"aud claim missing or invalid.\");\n }\n if (!Array.isArray(scopes) || scopes.length === 0) {\n throw new BadTokenError(\"scopes claim must be a non-empty array.\");\n }\n if (typeof subscriptionActive !== \"boolean\") {\n throw new BadTokenError(\"subscription_active claim must be boolean.\");\n }\n if (typeof jti !== \"string\" || jti.length === 0) {\n throw new BadTokenError(\"jti claim missing or invalid.\");\n }\n if (typeof iat !== \"number\" || typeof exp !== \"number\") {\n throw new BadTokenError(\"iat / exp claims missing or invalid.\");\n }\n\n return {\n iss: \"https://openkeyai.com\",\n sub,\n aud,\n scopes: scopes as ToolJwtScope[],\n subscription_active: subscriptionActive,\n iat,\n exp,\n jti,\n };\n}\n","import { SecureKeyConsumedError } from \"./errors\";\n\n/**\n * SecureKey — the only way the SDK hands a plaintext credential to a tool.\n *\n * Design goals (per docs/SECURITY.md in the hub repo):\n *\n * 1. The plaintext is reachable from EXACTLY ONE place: inside a callback\n * passed to `use(fn)`. Outside that callback, no public method or\n * property returns the value.\n *\n * 2. After the callback runs (or throws), the held reference is set to\n * null. Subsequent `use()` calls throw `SecureKeyConsumedError`. The\n * pattern is one-shot — get a fresh SecureKey for the next request.\n *\n * 3. `JSON.stringify`, `toString`, `console.log` (via util.inspect), and\n * template-literal coercion all return the literal string\n * `\"[SecureKey]\"` — never the underlying value, even by accident.\n *\n * #plaintext is a true private field (Stage 3 syntax) so it doesn't appear\n * in `Object.keys()`, isn't accessible via bracket-notation, and is not\n * enumerable for serialisation. The frozen overrides below cover the\n * coercion paths.\n *\n * What we deliberately do NOT do:\n *\n * - WeakRef + FinalizationRegistry. They're observable from the same realm,\n * and we have no useful action to take on GC. Single-use + manual null\n * is the simpler, more deterministic guarantee.\n *\n * - Buffer.alloc + .fill(0) \"zeroising\". V8 and modern runtimes can keep\n * copies of strings in cache; we can't truly zeroise from JS. The\n * useful guarantee we CAN give is reference-clearing, which we do.\n */\nexport class SecureKey {\n #plaintext: string | null;\n\n /** Provider slug the key was fetched for. Public — not sensitive. */\n readonly provider: string;\n\n /** @internal — tools should use `keys.get()`, never construct directly. */\n constructor(plaintext: string, provider: string) {\n this.#plaintext = plaintext;\n this.provider = provider;\n }\n\n /**\n * Pass the plaintext into a callback. Returns whatever the callback\n * returns. After the callback resolves (or throws), the SecureKey is\n * consumed — subsequent calls throw `SecureKeyConsumedError`.\n *\n * @example\n * const k = await keys.get(jwt, \"openai\");\n * const response = await k.use((apiKey) => fetch(\"...\", {\n * headers: { \"Authorization\": `Bearer ${apiKey}` },\n * }));\n */\n async use<T>(fn: (plaintext: string) => T | Promise<T>): Promise<T> {\n const plaintext = this.#plaintext;\n if (plaintext === null) {\n throw new SecureKeyConsumedError();\n }\n try {\n return await fn(plaintext);\n } finally {\n // Always clear the held reference, even if `fn` threw. The single\n // legitimate consumer already had the value during the callback;\n // anything after that is leakage we don't want to enable.\n this.#plaintext = null;\n }\n }\n\n /** Returns true once `use()` has been called and the reference cleared. */\n get isConsumed(): boolean {\n return this.#plaintext === null;\n }\n\n /** Always `[SecureKey]`. Never the underlying value. */\n toString(): string {\n return \"[SecureKey]\";\n }\n\n /** Always `[SecureKey]`. Catches `JSON.stringify` and friends. */\n toJSON(): string {\n return \"[SecureKey]\";\n }\n\n /** Catches `console.log` on Node and Workers (which use util.inspect). */\n [Symbol.for(\"nodejs.util.inspect.custom\")](): string {\n return \"[SecureKey]\";\n }\n}\n","import { decodeJwt } from \"jose\";\nimport {\n BadTokenError,\n InternalError,\n MissingScopeError,\n NetworkError,\n errorFromResponse,\n} from \"./errors\";\nimport { SecureKey } from \"./secure-key\";\nimport type { HubCallOptions, ProviderSlug } from \"./types\";\n\n/**\n * `keys.get(jwt, provider, opts?)`\n *\n * Fetches a credential for the user identified by `jwt` and returns a\n * single-use SecureKey. The hub:\n *\n * 1. Verifies the JWT (signature + iss + aud + exp)\n * 2. Confirms `keys.read` scope, active subscription, and that the tool +\n * user are both subscribed to this provider\n * 3. Decrypts the user's stored API key via KMS\n * 4. Returns the plaintext, logged to the audit trail\n *\n * On the client side we:\n * - Decode (no verify) the JWT locally to read the `aud` claim — that's\n * the tool slug the hub will scope the lookup against\n * - Pre-check the `keys.read` scope so we can return a typed error\n * without a round-trip\n * - Issue the GET, map the hub's frozen error codes to typed exceptions\n * - Wrap the plaintext in a SecureKey and return\n *\n * IMPORTANT: a SecureKey is single-use. Don't call `.use()` more than once;\n * call `keys.get` again for the next request. The audit trail records every\n * fetch.\n */\nexport async function get(\n jwt: string,\n provider: ProviderSlug,\n opts: HubCallOptions = {},\n): Promise<SecureKey> {\n if (!jwt || typeof jwt !== \"string\") {\n throw new BadTokenError(\"No JWT provided.\");\n }\n if (!provider || typeof provider !== \"string\") {\n throw new BadTokenError(\"Missing provider slug.\");\n }\n\n // Decode (no verify) to learn the audience — that's the tool slug for the\n // route. The hub will re-verify; we don't need to here.\n let aud: string;\n let scopes: unknown;\n try {\n const claims = decodeJwt(jwt);\n aud = String(claims.aud ?? \"\");\n scopes = claims.scopes;\n } catch (err) {\n throw new BadTokenError(\n `JWT could not be decoded: ${err instanceof Error ? err.message : \"unknown\"}`,\n );\n }\n if (!aud) {\n throw new BadTokenError(\"JWT is missing the aud claim.\");\n }\n\n // Local scope pre-check. Cheap, and lets the tool surface the right UX\n // without a network round-trip when the scope is just missing.\n if (Array.isArray(scopes) && !scopes.includes(\"keys.read\")) {\n throw new MissingScopeError(\"keys.read\");\n }\n\n const hubUrl = opts.hubUrl ?? \"https://openkeyai.com\";\n const url = new URL(\n `/api/tools/${encodeURIComponent(aud)}/keys/${encodeURIComponent(provider)}`,\n hubUrl,\n );\n\n let response: Response;\n try {\n response = await fetch(url.toString(), {\n method: \"GET\",\n headers: {\n accept: \"application/json\",\n authorization: `Bearer ${jwt}`,\n },\n signal: opts.signal,\n });\n } catch (err) {\n if (err instanceof DOMException && err.name === \"AbortError\") {\n throw err; // propagate as-is so callers can detect abort.\n }\n throw new NetworkError(err);\n }\n\n if (response.ok) {\n let body: { provider?: string; secret?: string };\n try {\n body = (await response.json()) as { provider?: string; secret?: string };\n } catch (err) {\n throw new InternalError(\n response.status,\n `Could not parse hub response body: ${err instanceof Error ? err.message : \"unknown\"}`,\n );\n }\n if (typeof body.secret !== \"string\" || body.secret.length === 0) {\n throw new InternalError(\n response.status,\n \"Hub returned 200 OK but no secret in the body.\",\n );\n }\n return new SecureKey(body.secret, body.provider ?? provider);\n }\n\n // Error path — let the typed-error builder do the right thing.\n let errorBody: { error?: string } | null = null;\n try {\n errorBody = (await response.json()) as { error?: string };\n } catch {\n // Body wasn't JSON. The status alone is informative; carry on with null.\n }\n\n const retryAfterHeader = response.headers.get(\"retry-after\");\n const retryAfter = retryAfterHeader ? parseInt(retryAfterHeader, 10) : 60;\n\n throw errorFromResponse(response.status, errorBody, {\n provider,\n scopeNeeded: \"keys.read\",\n retryAfter: Number.isFinite(retryAfter) ? retryAfter : 60,\n });\n}\n","/**\n * `@openkeyai/sdk` — public entry.\n *\n * Tools install this and import only from the package root:\n *\n * import { session, keys, SecureKey, SubscriptionInactiveError } from \"@openkeyai/sdk\";\n *\n * The five-module surface (session / keys / user / billing / webhooks) is\n * defined in\n * https://github.com/Scott-Builds-AI/hub/blob/main/docs/TOOL_SDK.md\n *\n * Status by module in 0.1.0:\n * - session.verify ✓\n * - keys.get → SecureKey ✓\n * - user — deferred until the hub ships /api/me (issue TBD)\n * - billing — deferred until the hub ships /api/billing/status\n * - webhooks — deferred until Phase 16 (the hub's webhook delivery layer)\n *\n * Internal helpers live under `_internal/`. They are NOT part of the\n * public API and may change without notice — the tool-manifest scanner\n * (Phase 9) treats `@openkeyai/sdk/_internal` imports as a CI failure.\n */\n\nimport { verify } from \"./session\";\nimport { get } from \"./keys\";\n\n/** session module — JWT verification + (future) refresh. */\nexport const session = {\n verify,\n} as const;\n\n/** keys module — credential fetch returning a single-use SecureKey. */\nexport const keys = {\n get,\n} as const;\n\n// Re-exports — the SecureKey class + every typed error, so tools can\n// `instanceof` check without reaching into submodules.\nexport { SecureKey } from \"./secure-key\";\nexport {\n HubSdkError,\n MissingTokenError,\n BadTokenError,\n MissingScopeError,\n SubscriptionInactiveError,\n ToolNotFoundError,\n NotSubscribedError,\n ProviderNotGrantedError,\n RateLimitedError,\n KeyNotFoundError,\n InternalError,\n NetworkError,\n SecureKeyConsumedError,\n} from \"./errors\";\nexport type { HubSdkErrorCode } from \"./errors\";\n\n// Type re-exports for tools that want to annotate their own helpers.\nexport type {\n ToolJwtClaims,\n ToolJwtScope,\n ProviderSlug,\n HubCallOptions,\n} from \"./types\";\n\n/** Bumped on each release. Tools log this on boot. */\nexport const SDK_VERSION = \"0.1.0\";\n"]}
1
+ {"version":3,"sources":["../src/errors.ts","../src/_internal/jwks.ts","../src/session.ts","../src/secure-key.ts","../src/keys.ts","../src/proxy.ts","../src/providers/openai.ts","../src/providers/anthropic.ts","../src/providers/replicate.ts","../src/index.ts"],"names":["createRemoteJWKSet","jwtVerify","joseErrors","decodeJwt"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Typed errors.\n *\n * The error `code` strings are part of the FROZEN public contract — see the\n * key-fetch endpoint's documentation in\n * https://github.com/Scott-Builds-AI/hub/blob/main/docs/phases/05-tools-keyfetch.md\n *\n * Adding a new code is a minor-version bump. Renaming or removing one is a\n * major (with 60-day notice).\n *\n * Tools catch these to surface precise UX:\n *\n * try {\n * await keys.get(jwt, \"openai\");\n * } catch (e) {\n * if (e instanceof SubscriptionInactiveError) showPaywall();\n * else if (e instanceof RateLimitedError) showRetryToast(e.retryAfter);\n * else throw e;\n * }\n */\n\nexport type HubSdkErrorCode =\n | \"missing_token\"\n | \"bad_token\"\n | \"missing_scope\"\n | \"subscription_inactive\"\n | \"tool_not_found\"\n | \"not_subscribed\"\n | \"provider_not_granted\"\n | \"rate_limited\"\n | \"key_not_found\"\n | \"internal\"\n | \"network\"\n | \"secure_key_consumed\"\n | \"provider_error\"\n | \"provider_not_configured\";\n\n/** Base class for every typed error in the SDK. */\nexport class HubSdkError extends Error {\n readonly code: HubSdkErrorCode;\n /** HTTP status from the hub, when applicable. 0 for client-only errors. */\n readonly status: number;\n\n constructor(code: HubSdkErrorCode, message: string, status = 0) {\n super(message);\n this.name = \"HubSdkError\";\n this.code = code;\n this.status = status;\n }\n}\n\n// ─── Wire-level errors (returned by the hub) ────────────────────────────────\n\nexport class MissingTokenError extends HubSdkError {\n constructor() {\n super(\"missing_token\", \"No Authorization token was provided.\", 401);\n this.name = \"MissingTokenError\";\n }\n}\n\nexport class BadTokenError extends HubSdkError {\n constructor(message = \"Token signature / issuer / audience / expiry check failed.\") {\n super(\"bad_token\", message, 401);\n this.name = \"BadTokenError\";\n }\n}\n\nexport class MissingScopeError extends HubSdkError {\n constructor(needed: string) {\n super(\"missing_scope\", `Token is missing the required scope: ${needed}.`, 403);\n this.name = \"MissingScopeError\";\n }\n}\n\nexport class SubscriptionInactiveError extends HubSdkError {\n constructor() {\n super(\n \"subscription_inactive\",\n \"The user's subscription is not active. Surface a paywall — don't retry.\",\n 402,\n );\n this.name = \"SubscriptionInactiveError\";\n }\n}\n\nexport class ToolNotFoundError extends HubSdkError {\n constructor() {\n super(\"tool_not_found\", \"Tool unknown or not approved.\", 404);\n this.name = \"ToolNotFoundError\";\n }\n}\n\nexport class NotSubscribedError extends HubSdkError {\n constructor() {\n super(\n \"not_subscribed\",\n \"The user has not enabled this tool in their hub settings.\",\n 403,\n );\n this.name = \"NotSubscribedError\";\n }\n}\n\nexport class ProviderNotGrantedError extends HubSdkError {\n constructor(provider: string) {\n super(\n \"provider_not_granted\",\n `User has not granted this tool access to the ${provider} provider.`,\n 403,\n );\n this.name = \"ProviderNotGrantedError\";\n }\n}\n\nexport class RateLimitedError extends HubSdkError {\n readonly retryAfter: number;\n constructor(retryAfter: number) {\n super(\n \"rate_limited\",\n `Rate limit hit. Retry after ${retryAfter} seconds.`,\n 429,\n );\n this.name = \"RateLimitedError\";\n this.retryAfter = retryAfter;\n }\n}\n\nexport class KeyNotFoundError extends HubSdkError {\n constructor(provider: string) {\n super(\n \"key_not_found\",\n `No ${provider} key configured for this user. The tool should prompt the user to add one.`,\n 404,\n );\n this.name = \"KeyNotFoundError\";\n }\n}\n\nexport class InternalError extends HubSdkError {\n constructor(status: number, message = \"The hub returned an internal error.\") {\n super(\"internal\", message, status);\n this.name = \"InternalError\";\n }\n}\n\n// ─── Client-only errors ──────────────────────────────────────────────────────\n\nexport class NetworkError extends HubSdkError {\n constructor(cause: unknown) {\n super(\n \"network\",\n `Could not reach the hub: ${cause instanceof Error ? cause.message : String(cause)}`,\n 0,\n );\n this.name = \"NetworkError\";\n this.cause = cause;\n }\n}\n\nexport class SecureKeyConsumedError extends HubSdkError {\n constructor() {\n super(\n \"secure_key_consumed\",\n \"SecureKey has already been used. Each instance is single-use; call keys.get() again to fetch a fresh one.\",\n 0,\n );\n this.name = \"SecureKeyConsumedError\";\n }\n}\n\n// ─── Phase 19 proxy errors ──────────────────────────────────────────────────\n\n/**\n * The proxy was asked to forward to a provider the hub doesn't have\n * configured. Distinct from `provider_not_granted` (which means the tool\n * isn't permitted to use a known provider). Fix: add the provider to\n * `src/lib/proxy/providers.ts` on the hub, or use a registered slug.\n */\nexport class ProviderNotConfiguredError extends HubSdkError {\n constructor(provider: string) {\n super(\n \"provider_not_configured\",\n `Provider \"${provider}\" is not registered with the hub proxy. Available providers are listed at /api/proxy (coming) or in the hub's src/lib/proxy/providers.ts.`,\n 404,\n );\n this.name = \"ProviderNotConfiguredError\";\n }\n}\n\n/**\n * The upstream provider (OpenAI / Anthropic / etc.) returned a non-2xx\n * response. The hub relays it unchanged — `body` holds the parsed JSON\n * body if the response was JSON, or the raw text otherwise, so the tool\n * can inspect the provider's native error shape.\n *\n * This is the catch-all for \"the platform did its job correctly; the\n * upstream rejected the request\" — wrong key (relayed 401), model not\n * available (provider 400), upstream rate limit (provider 429), etc.\n *\n * Distinguish from `RateLimitedError` (hub-side rate limit) by checking\n * `instanceof` first; the typed hub errors take precedence.\n */\nexport class ProviderError extends HubSdkError {\n /** The provider slug we tried to call. */\n readonly provider: string;\n /** The path on the provider that returned non-2xx. */\n readonly path: string;\n /**\n * The upstream response body. Parsed as JSON when the upstream's\n * content-type was JSON; raw text otherwise.\n */\n readonly body: unknown;\n /** The upstream response status code (relayed unchanged). */\n readonly upstreamStatus: number;\n\n constructor(\n provider: string,\n path: string,\n upstreamStatus: number,\n body: unknown,\n ) {\n super(\n \"provider_error\",\n `${provider} ${path} returned ${upstreamStatus}.`,\n upstreamStatus,\n );\n this.name = \"ProviderError\";\n this.provider = provider;\n this.path = path;\n this.upstreamStatus = upstreamStatus;\n this.body = body;\n }\n}\n\n// ─── Wire → error mapping ────────────────────────────────────────────────────\n\n/**\n * Build the right HubSdkError subclass from a hub JSON error response. Used\n * by every fetch wrapper so the typed errors stay consistent.\n */\nexport function errorFromResponse(\n status: number,\n body: { error?: string } | null,\n context: { provider?: string; scopeNeeded?: string; retryAfter?: number },\n): HubSdkError {\n const code = body?.error ?? \"internal\";\n switch (code) {\n case \"missing_token\":\n return new MissingTokenError();\n case \"bad_token\":\n return new BadTokenError();\n case \"missing_scope\":\n return new MissingScopeError(context.scopeNeeded ?? \"unknown\");\n case \"subscription_inactive\":\n return new SubscriptionInactiveError();\n case \"tool_not_found\":\n return new ToolNotFoundError();\n case \"not_subscribed\":\n return new NotSubscribedError();\n case \"provider_not_granted\":\n return new ProviderNotGrantedError(context.provider ?? \"unknown\");\n case \"provider_not_configured\":\n return new ProviderNotConfiguredError(context.provider ?? \"unknown\");\n case \"rate_limited\":\n return new RateLimitedError(context.retryAfter ?? 60);\n case \"key_not_found\":\n return new KeyNotFoundError(context.provider ?? \"unknown\");\n case \"internal\":\n default:\n return new InternalError(status);\n }\n}\n\n/**\n * Distinguish hub-shaped errors (`{ error: \"snake_case_code\" }`) from\n * upstream-provider error shapes (anything else — OpenAI uses\n * `{ error: { message, type, code } }`, Anthropic uses `{ type: \"error\",\n * error: { type, message } }`, plain text, etc.).\n *\n * Returns true when the body looks like a hub-emitted error, in which case\n * the caller should hand it to `errorFromResponse`. Returns false when the\n * caller should construct a `ProviderError` and surface the body to the\n * tool author.\n */\nexport function isHubErrorBody(\n body: unknown,\n): body is { error: HubSdkErrorCode } {\n if (typeof body !== \"object\" || body === null) return false;\n const errorField = (body as { error?: unknown }).error;\n if (typeof errorField !== \"string\") return false;\n const knownCodes: HubSdkErrorCode[] = [\n \"missing_token\",\n \"bad_token\",\n \"missing_scope\",\n \"subscription_inactive\",\n \"tool_not_found\",\n \"not_subscribed\",\n \"provider_not_granted\",\n \"rate_limited\",\n \"key_not_found\",\n \"internal\",\n \"provider_not_configured\",\n ];\n return (knownCodes as string[]).includes(errorField);\n}\n","import { createRemoteJWKSet, type JWTVerifyGetKey } from \"jose\";\n\n/**\n * Per-hub-URL JWKS cache.\n *\n * Each call to `keys.get` / `session.verify` needs a key-resolver\n * (`jose.JWTVerifyGetKey`) to feed into `jwtVerify`. Building a fresh\n * resolver per request would re-fetch the JWKS document every time.\n * `createRemoteJWKSet` handles caching internally, but only if we hand\n * back the SAME resolver instance for the same URL.\n *\n * Cache key is the hub URL because the same SDK build might be used by\n * tools that point at staging vs production hubs (different keys, different\n * kids).\n *\n * The cache has no eviction — there's at most a handful of distinct hub\n * URLs in any sane setup. If a tool author somehow constructs thousands of\n * URL variants this would leak memory; that's not a realistic path.\n */\nconst resolvers = new Map<string, JWTVerifyGetKey>();\n\nexport function getJwksResolver(hubUrl: string): JWTVerifyGetKey {\n const cached = resolvers.get(hubUrl);\n if (cached) return cached;\n const url = new URL(\"/.well-known/jwks.json\", hubUrl);\n // jose's createRemoteJWKSet:\n // - fetches lazily on the first verify\n // - caches for `cacheMaxAge` (default 10 minutes)\n // - revalidates after `cooldownDuration` (default 30s)\n // - re-fetches automatically when a verify hits an unknown kid (rotation)\n const resolver = createRemoteJWKSet(url, {\n // Respect the hub's stated cache window (5 min strong + 10 min SWR).\n cacheMaxAge: 5 * 60 * 1000,\n cooldownDuration: 30 * 1000,\n });\n resolvers.set(hubUrl, resolver);\n return resolver;\n}\n\n/** Test helper — drops the cache between cases. Not part of public API. */\nexport function _resetJwksCacheForTests(): void {\n resolvers.clear();\n}\n","import { jwtVerify, errors as joseErrors } from \"jose\";\nimport { BadTokenError, MissingTokenError } from \"./errors\";\nimport { getJwksResolver } from \"./_internal/jwks\";\nimport type { HubCallOptions, ToolJwtClaims, ToolJwtScope } from \"./types\";\n\n/**\n * `session.verify(jwt, opts?)`\n *\n * Verifies a hub-issued JWT against the hub's public JWKS, then validates\n * the claim shape (`iss`, `sub`, `aud`, `scopes`, `subscription_active`).\n *\n * Returns the typed claims on success.\n * Throws `BadTokenError` on any failure — signature, expiry, issuer,\n * audience, missing/malformed custom claims.\n * Throws `MissingTokenError` if `jwt` is empty / null.\n *\n * The verifier:\n * - fetches `${hubUrl}/.well-known/jwks.json` (cached per hub URL)\n * - re-fetches on `kid` rotation (jose handles this transparently)\n * - DOES NOT validate `aud` here — the caller specifies which audience\n * they expect (the tool's own slug, OR a wildcard for tools that\n * legitimately accept multiple audiences). `keys.get` validates\n * audience against the tool slug derived from the route.\n *\n * @param jwt The bearer token string (no `Bearer ` prefix).\n * @param opts.hubUrl override the hub root (default: `https://openkeyai.com`)\n * @param opts.expectedAudience tool slug the token must be addressed to.\n * When omitted, audience is not checked here — the caller MUST do it\n * themselves before granting any scope-derived privilege.\n */\nexport async function verify(\n jwt: string,\n opts: HubCallOptions & { expectedAudience?: string } = {},\n): Promise<ToolJwtClaims> {\n if (!jwt || typeof jwt !== \"string\") {\n throw new MissingTokenError();\n }\n\n const hubUrl = opts.hubUrl ?? \"https://openkeyai.com\";\n const resolver = getJwksResolver(hubUrl);\n\n let payload: Record<string, unknown>;\n try {\n const result = await jwtVerify(jwt, resolver, {\n issuer: \"https://openkeyai.com\",\n algorithms: [\"EdDSA\"],\n ...(opts.expectedAudience ? { audience: opts.expectedAudience } : {}),\n });\n payload = result.payload as Record<string, unknown>;\n } catch (err) {\n if (err instanceof joseErrors.JWTExpired) {\n throw new BadTokenError(\"Token expired.\");\n }\n if (err instanceof joseErrors.JWTClaimValidationFailed) {\n throw new BadTokenError(`Claim validation failed: ${err.message}`);\n }\n if (err instanceof joseErrors.JWSSignatureVerificationFailed) {\n throw new BadTokenError(\"Signature did not verify.\");\n }\n if (err instanceof joseErrors.JWKSNoMatchingKey) {\n throw new BadTokenError(\"Token kid is not in the hub's active JWKS.\");\n }\n if (err instanceof joseErrors.JOSEError) {\n throw new BadTokenError(err.message);\n }\n // Network / unknown — surface as BadToken too rather than leak details.\n throw new BadTokenError(\"Token verification failed.\");\n }\n\n // Custom-claim shape validation. `jose` only validates standard claims.\n const sub = payload.sub;\n const aud = payload.aud;\n const scopes = payload.scopes;\n const subscriptionActive = payload.subscription_active;\n const jti = payload.jti;\n const iat = payload.iat;\n const exp = payload.exp;\n const rawMode = payload.mode;\n\n if (typeof sub !== \"string\" || sub.length === 0) {\n throw new BadTokenError(\"sub claim missing or invalid.\");\n }\n if (typeof aud !== \"string\" || aud.length === 0) {\n throw new BadTokenError(\"aud claim missing or invalid.\");\n }\n if (!Array.isArray(scopes) || scopes.length === 0) {\n throw new BadTokenError(\"scopes claim must be a non-empty array.\");\n }\n if (typeof subscriptionActive !== \"boolean\") {\n throw new BadTokenError(\"subscription_active claim must be boolean.\");\n }\n if (typeof jti !== \"string\" || jti.length === 0) {\n throw new BadTokenError(\"jti claim missing or invalid.\");\n }\n if (typeof iat !== \"number\" || typeof exp !== \"number\") {\n throw new BadTokenError(\"iat / exp claims missing or invalid.\");\n }\n\n // Mode claim (Phase 13.4). Tokens minted before that phase don't carry it\n // — default to 'production' so in-flight sessions still verify cleanly\n // during a hub deploy. Anything other than the two known values is a\n // shape error.\n const mode =\n typeof rawMode === \"string\" && (rawMode === \"production\" || rawMode === \"owner_test\")\n ? rawMode\n : rawMode === undefined\n ? \"production\"\n : null;\n if (mode === null) {\n throw new BadTokenError(\n `mode claim must be 'production' or 'owner_test' (got ${JSON.stringify(rawMode)}).`,\n );\n }\n\n // Phase 22 — pass through optional `name` claim when present so tools\n // can render the real user display name. Validated as a non-empty\n // string; anything else is dropped silently (forward-compatible).\n const rawName = payload.name;\n const name =\n typeof rawName === \"string\" && rawName.length > 0 ? rawName : undefined;\n\n return {\n iss: \"https://openkeyai.com\",\n sub,\n aud,\n scopes: scopes as ToolJwtScope[],\n subscription_active: subscriptionActive,\n mode,\n ...(name ? { name } : {}),\n iat,\n exp,\n jti,\n };\n}\n","import { SecureKeyConsumedError } from \"./errors\";\n\n/**\n * SecureKey — the only way the SDK hands a plaintext credential to a tool.\n *\n * Design goals (per docs/SECURITY.md in the hub repo):\n *\n * 1. The plaintext is reachable from EXACTLY ONE place: inside a callback\n * passed to `use(fn)`. Outside that callback, no public method or\n * property returns the value.\n *\n * 2. After the callback runs (or throws), the held reference is set to\n * null. Subsequent `use()` calls throw `SecureKeyConsumedError`. The\n * pattern is one-shot — get a fresh SecureKey for the next request.\n *\n * 3. `JSON.stringify`, `toString`, `console.log` (via util.inspect), and\n * template-literal coercion all return the literal string\n * `\"[SecureKey]\"` — never the underlying value, even by accident.\n *\n * #plaintext is a true private field (Stage 3 syntax) so it doesn't appear\n * in `Object.keys()`, isn't accessible via bracket-notation, and is not\n * enumerable for serialisation. The frozen overrides below cover the\n * coercion paths.\n *\n * What we deliberately do NOT do:\n *\n * - WeakRef + FinalizationRegistry. They're observable from the same realm,\n * and we have no useful action to take on GC. Single-use + manual null\n * is the simpler, more deterministic guarantee.\n *\n * - Buffer.alloc + .fill(0) \"zeroising\". V8 and modern runtimes can keep\n * copies of strings in cache; we can't truly zeroise from JS. The\n * useful guarantee we CAN give is reference-clearing, which we do.\n */\nexport class SecureKey {\n #plaintext: string | null;\n\n /** Provider slug the key was fetched for. Public — not sensitive. */\n readonly provider: string;\n\n /** @internal — tools should use `keys.get()`, never construct directly. */\n constructor(plaintext: string, provider: string) {\n this.#plaintext = plaintext;\n this.provider = provider;\n }\n\n /**\n * Pass the plaintext into a callback. Returns whatever the callback\n * returns. After the callback resolves (or throws), the SecureKey is\n * consumed — subsequent calls throw `SecureKeyConsumedError`.\n *\n * @example\n * const k = await keys.get(jwt, \"openai\");\n * const response = await k.use((apiKey) => fetch(\"...\", {\n * headers: { \"Authorization\": `Bearer ${apiKey}` },\n * }));\n */\n async use<T>(fn: (plaintext: string) => T | Promise<T>): Promise<T> {\n const plaintext = this.#plaintext;\n if (plaintext === null) {\n throw new SecureKeyConsumedError();\n }\n try {\n return await fn(plaintext);\n } finally {\n // Always clear the held reference, even if `fn` threw. The single\n // legitimate consumer already had the value during the callback;\n // anything after that is leakage we don't want to enable.\n this.#plaintext = null;\n }\n }\n\n /** Returns true once `use()` has been called and the reference cleared. */\n get isConsumed(): boolean {\n return this.#plaintext === null;\n }\n\n /** Always `[SecureKey]`. Never the underlying value. */\n toString(): string {\n return \"[SecureKey]\";\n }\n\n /** Always `[SecureKey]`. Catches `JSON.stringify` and friends. */\n toJSON(): string {\n return \"[SecureKey]\";\n }\n\n /** Catches `console.log` on Node and Workers (which use util.inspect). */\n [Symbol.for(\"nodejs.util.inspect.custom\")](): string {\n return \"[SecureKey]\";\n }\n}\n","import { decodeJwt } from \"jose\";\nimport {\n BadTokenError,\n InternalError,\n MissingScopeError,\n NetworkError,\n errorFromResponse,\n} from \"./errors\";\nimport { SecureKey } from \"./secure-key\";\nimport type { HubCallOptions, ProviderSlug } from \"./types\";\n\n/**\n * `keys.get(jwt, provider, opts?)`\n *\n * Fetches a credential for the user identified by `jwt` and returns a\n * single-use SecureKey. The hub:\n *\n * 1. Verifies the JWT (signature + iss + aud + exp)\n * 2. Confirms `keys.read` scope, active subscription, and that the tool +\n * user are both subscribed to this provider\n * 3. Decrypts the user's stored API key via KMS\n * 4. Returns the plaintext, logged to the audit trail\n *\n * On the client side we:\n * - Decode (no verify) the JWT locally to read the `aud` claim — that's\n * the tool slug the hub will scope the lookup against\n * - Pre-check the `keys.read` scope so we can return a typed error\n * without a round-trip\n * - Issue the GET, map the hub's frozen error codes to typed exceptions\n * - Wrap the plaintext in a SecureKey and return\n *\n * IMPORTANT: a SecureKey is single-use. Don't call `.use()` more than once;\n * call `keys.get` again for the next request. The audit trail records every\n * fetch.\n */\nexport async function get(\n jwt: string,\n provider: ProviderSlug,\n opts: HubCallOptions = {},\n): Promise<SecureKey> {\n if (!jwt || typeof jwt !== \"string\") {\n throw new BadTokenError(\"No JWT provided.\");\n }\n if (!provider || typeof provider !== \"string\") {\n throw new BadTokenError(\"Missing provider slug.\");\n }\n\n // Decode (no verify) to learn the audience — that's the tool slug for the\n // route. The hub will re-verify; we don't need to here.\n let aud: string;\n let scopes: unknown;\n try {\n const claims = decodeJwt(jwt);\n aud = String(claims.aud ?? \"\");\n scopes = claims.scopes;\n } catch (err) {\n throw new BadTokenError(\n `JWT could not be decoded: ${err instanceof Error ? err.message : \"unknown\"}`,\n );\n }\n if (!aud) {\n throw new BadTokenError(\"JWT is missing the aud claim.\");\n }\n\n // Local scope pre-check. Cheap, and lets the tool surface the right UX\n // without a network round-trip when the scope is just missing.\n if (Array.isArray(scopes) && !scopes.includes(\"keys.read\")) {\n throw new MissingScopeError(\"keys.read\");\n }\n\n const hubUrl = opts.hubUrl ?? \"https://openkeyai.com\";\n const url = new URL(\n `/api/tools/${encodeURIComponent(aud)}/keys/${encodeURIComponent(provider)}`,\n hubUrl,\n );\n\n let response: Response;\n try {\n response = await fetch(url.toString(), {\n method: \"GET\",\n headers: {\n accept: \"application/json\",\n authorization: `Bearer ${jwt}`,\n },\n signal: opts.signal,\n });\n } catch (err) {\n if (err instanceof DOMException && err.name === \"AbortError\") {\n throw err; // propagate as-is so callers can detect abort.\n }\n throw new NetworkError(err);\n }\n\n if (response.ok) {\n let body: { provider?: string; secret?: string };\n try {\n body = (await response.json()) as { provider?: string; secret?: string };\n } catch (err) {\n throw new InternalError(\n response.status,\n `Could not parse hub response body: ${err instanceof Error ? err.message : \"unknown\"}`,\n );\n }\n if (typeof body.secret !== \"string\" || body.secret.length === 0) {\n throw new InternalError(\n response.status,\n \"Hub returned 200 OK but no secret in the body.\",\n );\n }\n return new SecureKey(body.secret, body.provider ?? provider);\n }\n\n // Error path — let the typed-error builder do the right thing.\n let errorBody: { error?: string } | null = null;\n try {\n errorBody = (await response.json()) as { error?: string };\n } catch {\n // Body wasn't JSON. The status alone is informative; carry on with null.\n }\n\n const retryAfterHeader = response.headers.get(\"retry-after\");\n const retryAfter = retryAfterHeader ? parseInt(retryAfterHeader, 10) : 60;\n\n throw errorFromResponse(response.status, errorBody, {\n provider,\n scopeNeeded: \"keys.read\",\n retryAfter: Number.isFinite(retryAfter) ? retryAfter : 60,\n });\n}\n","import {\n BadTokenError,\n NetworkError,\n ProviderError,\n errorFromResponse,\n isHubErrorBody,\n} from \"./errors\";\nimport type { ProxyCallOptions } from \"./types\";\n\n/**\n * Phase 19 zero-trust proxy client.\n *\n * Tools call provider APIs via the hub instead of using `keys.get()` +\n * `SecureKey.use()`. The hub authenticates the JWT, decrypts the user's\n * key, injects the upstream `Authorization` header, forwards the request,\n * and relays the response. The plaintext key never leaves the hub Worker.\n *\n * Three entry points, all sharing the same gate stack:\n *\n * proxy.call(token, opts) — JSON-in JSON-out, the 80% case\n * proxy.callRaw(token, opts) — raw Response (for binary, multipart)\n * proxy.callStream(token, opts) — ReadableStream<Uint8Array> for SSE /\n * chunked responses (chat streaming etc.)\n *\n * All three share the same flexibility promise: any method, any path, any\n * body shape, any registered provider. The route on the hub side is one\n * universal handler (see Phase 19 doc); these helpers just shape the\n * request and response on the SDK side.\n */\n\nconst PROXY_PATH = \"/api/proxy\";\n\nfunction ensureBearer(token: string): void {\n if (!token || typeof token !== \"string\") {\n throw new BadTokenError(\"No JWT provided.\");\n }\n}\n\nfunction buildUrl(opts: ProxyCallOptions): URL {\n if (!opts.provider) {\n throw new BadTokenError(\"ProxyCallOptions.provider is required.\");\n }\n if (!opts.path || !opts.path.startsWith(\"/\")) {\n throw new BadTokenError(\n \"ProxyCallOptions.path must start with '/' (e.g. '/v1/chat/completions').\",\n );\n }\n const hubUrl = opts.hubUrl ?? \"https://openkeyai.com\";\n return new URL(\n `${PROXY_PATH}/${encodeURIComponent(opts.provider)}${opts.path}`,\n hubUrl,\n );\n}\n\nfunction buildRequestInit(token: string, opts: ProxyCallOptions): RequestInit {\n const headers = new Headers();\n if (opts.headers) {\n for (const [k, v] of Object.entries(opts.headers)) {\n headers.set(k, v);\n }\n }\n headers.set(\"authorization\", `Bearer ${token}`);\n\n let body: BodyInit | undefined;\n if (opts.method === \"GET\" || opts.method === \"DELETE\" || opts.body == null) {\n body = undefined;\n } else if (\n typeof opts.body === \"string\" ||\n opts.body instanceof Blob ||\n opts.body instanceof FormData ||\n opts.body instanceof ArrayBuffer ||\n opts.body instanceof ReadableStream\n ) {\n body = opts.body as BodyInit;\n } else {\n body = JSON.stringify(opts.body);\n if (!headers.has(\"content-type\")) {\n headers.set(\"content-type\", \"application/json\");\n }\n }\n\n if (!headers.has(\"accept\")) {\n headers.set(\"accept\", \"application/json\");\n }\n\n return {\n method: opts.method,\n headers,\n body,\n signal: opts.signal,\n // @ts-expect-error duplex is part of fetch's RequestInit on Workers + recent Node\n duplex: body instanceof ReadableStream ? \"half\" : undefined,\n };\n}\n\nasync function rawFetch(\n token: string,\n opts: ProxyCallOptions,\n): Promise<Response> {\n ensureBearer(token);\n const url = buildUrl(opts);\n try {\n return await fetch(url.toString(), buildRequestInit(token, opts));\n } catch (err) {\n if (err instanceof DOMException && err.name === \"AbortError\") {\n throw err;\n }\n throw new NetworkError(err);\n }\n}\n\nasync function parseBodyByContentType(response: Response): Promise<unknown> {\n const ct = response.headers.get(\"content-type\") ?? \"\";\n if (ct.includes(\"application/json\")) {\n try {\n return await response.json();\n } catch {\n return null;\n }\n }\n try {\n return await response.text();\n } catch {\n return null;\n }\n}\n\n/**\n * Handle the response shape — relay 2xx as JSON, distinguish hub errors\n * from provider errors on non-2xx, throw the right typed exception.\n *\n * `expectJson` controls whether we parse the success body. Used by\n * `proxy.call` (true) vs `proxy.callRaw` (false — caller wants the\n * Response directly).\n */\nasync function handleResponse<T>(\n response: Response,\n opts: ProxyCallOptions,\n expectJson: true,\n): Promise<T>;\nasync function handleResponse(\n response: Response,\n opts: ProxyCallOptions,\n expectJson: false,\n): Promise<Response>;\nasync function handleResponse<T>(\n response: Response,\n opts: ProxyCallOptions,\n expectJson: boolean,\n): Promise<T | Response> {\n if (response.ok) {\n if (!expectJson) return response;\n return (await response.json()) as T;\n }\n\n const body = await parseBodyByContentType(response);\n\n if (isHubErrorBody(body)) {\n const retryAfter = parseInt(response.headers.get(\"retry-after\") ?? \"60\", 10);\n throw errorFromResponse(\n response.status,\n { error: body.error },\n {\n provider: opts.provider,\n scopeNeeded: \"keys.read\",\n retryAfter: Number.isFinite(retryAfter) ? retryAfter : 60,\n },\n );\n }\n\n throw new ProviderError(opts.provider, opts.path, response.status, body);\n}\n\n/**\n * Generic proxy call — JSON in, JSON out. Most tools want this.\n *\n * const completion = await proxy.call<ChatCompletionResponse>(token, {\n * provider: \"openai\",\n * method: \"POST\",\n * path: \"/v1/chat/completions\",\n * body: { model: \"gpt-4o-mini\", messages: [{ role: \"user\", content: \"hi\" }] },\n * });\n *\n * Throws typed HubSdkError subclasses for hub-side failures (missing\n * scope, rate limited, etc.) and `ProviderError` for upstream non-2xx\n * (wrong key, model gone, provider 5xx, etc.).\n */\nexport async function call<T = unknown>(\n token: string,\n opts: ProxyCallOptions,\n): Promise<T> {\n const response = await rawFetch(token, opts);\n return handleResponse<T>(response, opts, true);\n}\n\n/**\n * Raw-response proxy call. Used when the upstream returns non-JSON —\n * binary audio (TTS), image bytes (DALL-E with response_format=url is\n * JSON, but other endpoints may stream binary), multipart, etc.\n *\n * const response = await proxy.callRaw(token, {\n * provider: \"openai\",\n * method: \"POST\",\n * path: \"/v1/audio/speech\",\n * body: { model: \"tts-1\", input: \"Hello\", voice: \"alloy\" },\n * });\n * const audio = await response.arrayBuffer();\n *\n * Returns the upstream Response with status / headers intact — the tool\n * decides how to consume the body. Throws on hub-side errors before the\n * Response is returned.\n */\nexport async function callRaw(\n token: string,\n opts: ProxyCallOptions,\n): Promise<Response> {\n const response = await rawFetch(token, opts);\n return handleResponse(response, opts, false);\n}\n\n/**\n * Streaming proxy call — returns a ReadableStream of the upstream\n * response body. Used for SSE (chat completion streaming), chunked\n * downloads, large response bodies you want to process as they arrive.\n *\n * const stream = await proxy.callStream(token, {\n * provider: \"openai\",\n * method: \"POST\",\n * path: \"/v1/chat/completions\",\n * body: { model: \"gpt-4o\", messages: [...], stream: true },\n * });\n * const reader = stream.getReader();\n * while (true) {\n * const { value, done } = await reader.read();\n * if (done) break;\n * // parse SSE chunks here — typed SSE iterator comes in M1.5\n * }\n *\n * Hub-side errors (auth, rate-limit) still throw before the stream is\n * returned. Upstream errors are surfaced via the stream itself — the\n * caller should check `response.status` before reading if a provider 4xx\n * matters; in M1.5 we'll wrap this in `ProviderError` if the upstream\n * status is non-2xx before any chunks are read.\n */\nexport async function callStream(\n token: string,\n opts: ProxyCallOptions,\n): Promise<ReadableStream<Uint8Array>> {\n const response = await rawFetch(token, opts);\n\n if (!response.ok) {\n const body = await parseBodyByContentType(response);\n if (isHubErrorBody(body)) {\n const retryAfter = parseInt(\n response.headers.get(\"retry-after\") ?? \"60\",\n 10,\n );\n throw errorFromResponse(\n response.status,\n { error: body.error },\n {\n provider: opts.provider,\n scopeNeeded: \"keys.read\",\n retryAfter: Number.isFinite(retryAfter) ? retryAfter : 60,\n },\n );\n }\n throw new ProviderError(opts.provider, opts.path, response.status, body);\n }\n\n if (response.body == null) {\n throw new BadTokenError(\"Upstream returned 2xx with no body to stream.\");\n }\n return response.body;\n}\n","import { call, callRaw, callStream } from \"../proxy\";\nimport type { HubCallOptions } from \"../types\";\n\n/**\n * Typed convenience wrappers for OpenAI's most-used endpoints. Thin\n * wrappers around `proxy.call(token, opts)` — same gates, same errors,\n * just better DX for the common cases.\n *\n * Tools that need an endpoint not covered here can drop to the generic\n * `proxy.call(token, { provider: \"openai\", method, path, body })`. The\n * proxy supports every OpenAI endpoint without us shipping wrappers for\n * each one.\n *\n * Types here are pragmatic, not exhaustive — we hit the fields the YT\n * thumbnail tool and other early reference tools need. As more tools land\n * we'll grow these. The escape hatch (`proxy.call`) means tools never wait\n * on the SDK to update types when a new model ships.\n */\n\n// ─── /v1/images/generations ─────────────────────────────────────────────────\n\nexport type OpenaiImageModel =\n | \"gpt-image-1\"\n | \"dall-e-3\"\n | \"dall-e-2\"\n | (string & {});\n\nexport type OpenaiImageSize =\n | \"1024x1024\"\n | \"1024x1536\"\n | \"1536x1024\"\n | \"1792x1024\"\n | \"1024x1792\"\n | \"256x256\"\n | \"512x512\"\n | \"auto\"\n | (string & {});\n\nexport type OpenaiImageQuality =\n | \"high\"\n | \"medium\"\n | \"low\"\n | \"auto\"\n | \"hd\"\n | \"standard\"\n | (string & {});\n\nexport type OpenaiImageStyle = \"vivid\" | \"natural\" | (string & {});\n\nexport type OpenaiImageGenerateParams = {\n model?: OpenaiImageModel;\n prompt: string;\n n?: number;\n size?: OpenaiImageSize;\n quality?: OpenaiImageQuality;\n style?: OpenaiImageStyle;\n /**\n * `b64_json` returns base64-encoded image bytes inline in the response.\n * `url` returns a hosted URL the client can fetch. gpt-image-1 always\n * returns b64.\n */\n response_format?: \"url\" | \"b64_json\";\n user?: string;\n background?: \"transparent\" | \"opaque\" | \"auto\" | (string & {});\n moderation?: \"low\" | \"auto\" | (string & {});\n output_compression?: number;\n output_format?: \"png\" | \"jpeg\" | \"webp\" | (string & {});\n};\n\nexport type OpenaiImageData = {\n url?: string;\n b64_json?: string;\n revised_prompt?: string;\n};\n\nexport type OpenaiImageGenerateResponse = {\n created: number;\n data: OpenaiImageData[];\n usage?: {\n total_tokens?: number;\n input_tokens?: number;\n output_tokens?: number;\n input_tokens_details?: { text_tokens?: number; image_tokens?: number };\n };\n};\n\n// ─── /v1/chat/completions ──────────────────────────────────────────────────\n\nexport type OpenaiChatRole = \"system\" | \"user\" | \"assistant\" | \"tool\";\n\nexport type OpenaiChatMessageContentPart =\n | { type: \"text\"; text: string }\n | {\n type: \"image_url\";\n image_url: { url: string; detail?: \"low\" | \"high\" | \"auto\" };\n };\n\nexport type OpenaiChatMessage = {\n role: OpenaiChatRole;\n content: string | OpenaiChatMessageContentPart[];\n name?: string;\n tool_call_id?: string;\n};\n\nexport type OpenaiChatCompletionParams = {\n model: string;\n messages: OpenaiChatMessage[];\n temperature?: number;\n top_p?: number;\n n?: number;\n max_tokens?: number;\n max_completion_tokens?: number;\n stream?: boolean;\n stop?: string | string[];\n presence_penalty?: number;\n frequency_penalty?: number;\n seed?: number;\n response_format?: { type: \"text\" | \"json_object\" | \"json_schema\" };\n tools?: Array<{\n type: \"function\";\n function: { name: string; description?: string; parameters?: unknown };\n }>;\n tool_choice?: \"none\" | \"auto\" | \"required\" | { type: \"function\"; function: { name: string } };\n user?: string;\n};\n\nexport type OpenaiChatCompletionResponse = {\n id: string;\n object: \"chat.completion\";\n created: number;\n model: string;\n choices: Array<{\n index: number;\n message: { role: \"assistant\"; content: string | null; tool_calls?: unknown[] };\n finish_reason: \"stop\" | \"length\" | \"tool_calls\" | \"content_filter\" | string;\n }>;\n usage?: {\n prompt_tokens: number;\n completion_tokens: number;\n total_tokens: number;\n };\n};\n\n// ─── /v1/embeddings ─────────────────────────────────────────────────────────\n\nexport type OpenaiEmbeddingsParams = {\n model: string;\n input: string | string[];\n dimensions?: number;\n encoding_format?: \"float\" | \"base64\";\n user?: string;\n};\n\nexport type OpenaiEmbeddingsResponse = {\n object: \"list\";\n data: Array<{ object: \"embedding\"; index: number; embedding: number[] }>;\n model: string;\n usage: { prompt_tokens: number; total_tokens: number };\n};\n\n// ─── /v1/audio/transcriptions (multipart upload) ───────────────────────────\n\nexport type OpenaiTranscriptionParams = {\n file: Blob;\n model: string;\n language?: string;\n prompt?: string;\n response_format?: \"json\" | \"text\" | \"srt\" | \"verbose_json\" | \"vtt\";\n temperature?: number;\n /** Filename to attach to the multipart upload. Defaults to \"audio.webm\". */\n filename?: string;\n};\n\nexport type OpenaiTranscriptionResponse = {\n text: string;\n language?: string;\n duration?: number;\n segments?: Array<{ id: number; start: number; end: number; text: string }>;\n};\n\n// ─── /v1/audio/speech (binary response) ─────────────────────────────────────\n\nexport type OpenaiSpeechParams = {\n model: string;\n input: string;\n voice: \"alloy\" | \"echo\" | \"fable\" | \"onyx\" | \"nova\" | \"shimmer\" | (string & {});\n response_format?: \"mp3\" | \"opus\" | \"aac\" | \"flac\" | \"wav\" | \"pcm\";\n speed?: number;\n instructions?: string;\n};\n\n// ─── Exported helpers ───────────────────────────────────────────────────────\n\n/**\n * The OpenAI typed convenience surface. Wraps `proxy.call` / `callRaw` /\n * `callStream` with provider=\"openai\" pre-set and per-endpoint typings.\n *\n * const result = await openai.images.generate(token, {\n * model: \"gpt-image-1\",\n * prompt: \"...\",\n * n: 4,\n * });\n */\nexport const openai = {\n images: {\n generate(\n token: string,\n params: OpenaiImageGenerateParams,\n opts: HubCallOptions = {},\n ): Promise<OpenaiImageGenerateResponse> {\n return call<OpenaiImageGenerateResponse>(token, {\n ...opts,\n provider: \"openai\",\n method: \"POST\",\n path: \"/v1/images/generations\",\n body: params as unknown as Record<string, unknown>,\n });\n },\n },\n chat: {\n completions: {\n create(\n token: string,\n params: OpenaiChatCompletionParams,\n opts: HubCallOptions = {},\n ): Promise<OpenaiChatCompletionResponse> {\n return call<OpenaiChatCompletionResponse>(token, {\n ...opts,\n provider: \"openai\",\n method: \"POST\",\n path: \"/v1/chat/completions\",\n body: params as unknown as Record<string, unknown>,\n });\n },\n stream(\n token: string,\n params: Omit<OpenaiChatCompletionParams, \"stream\">,\n opts: HubCallOptions = {},\n ): Promise<ReadableStream<Uint8Array>> {\n return callStream(token, {\n ...opts,\n provider: \"openai\",\n method: \"POST\",\n path: \"/v1/chat/completions\",\n body: { ...params, stream: true } as unknown as Record<string, unknown>,\n });\n },\n },\n },\n embeddings: {\n create(\n token: string,\n params: OpenaiEmbeddingsParams,\n opts: HubCallOptions = {},\n ): Promise<OpenaiEmbeddingsResponse> {\n return call<OpenaiEmbeddingsResponse>(token, {\n ...opts,\n provider: \"openai\",\n method: \"POST\",\n path: \"/v1/embeddings\",\n body: params as unknown as Record<string, unknown>,\n });\n },\n },\n audio: {\n transcriptions: {\n create(\n token: string,\n params: OpenaiTranscriptionParams,\n opts: HubCallOptions = {},\n ): Promise<OpenaiTranscriptionResponse> {\n const fd = new FormData();\n fd.append(\"file\", params.file, params.filename ?? \"audio.webm\");\n fd.append(\"model\", params.model);\n if (params.language) fd.append(\"language\", params.language);\n if (params.prompt) fd.append(\"prompt\", params.prompt);\n if (params.response_format)\n fd.append(\"response_format\", params.response_format);\n if (params.temperature !== undefined)\n fd.append(\"temperature\", String(params.temperature));\n return call<OpenaiTranscriptionResponse>(token, {\n ...opts,\n provider: \"openai\",\n method: \"POST\",\n path: \"/v1/audio/transcriptions\",\n body: fd,\n });\n },\n },\n speech: {\n create(\n token: string,\n params: OpenaiSpeechParams,\n opts: HubCallOptions = {},\n ): Promise<Response> {\n return callRaw(token, {\n ...opts,\n provider: \"openai\",\n method: \"POST\",\n path: \"/v1/audio/speech\",\n body: params as unknown as Record<string, unknown>,\n });\n },\n },\n },\n} as const;\n","import { call, callStream } from \"../proxy\";\nimport type { HubCallOptions } from \"../types\";\n\n/**\n * Typed convenience wrappers for Anthropic's Messages API.\n *\n * Hub-side handles the per-provider auth quirk (Anthropic uses `x-api-key`\n * not `Authorization: Bearer`) and injects the required\n * `anthropic-version: 2023-06-01` header automatically — see\n * `src/lib/proxy/providers.ts` on the hub for the config.\n */\n\nexport type AnthropicTextBlock = { type: \"text\"; text: string };\nexport type AnthropicImageBlock = {\n type: \"image\";\n source:\n | { type: \"base64\"; media_type: string; data: string }\n | { type: \"url\"; url: string };\n};\nexport type AnthropicToolUseBlock = {\n type: \"tool_use\";\n id: string;\n name: string;\n input: Record<string, unknown>;\n};\nexport type AnthropicToolResultBlock = {\n type: \"tool_result\";\n tool_use_id: string;\n content: string | AnthropicTextBlock[];\n is_error?: boolean;\n};\nexport type AnthropicContentBlock =\n | AnthropicTextBlock\n | AnthropicImageBlock\n | AnthropicToolUseBlock\n | AnthropicToolResultBlock;\n\nexport type AnthropicMessage = {\n role: \"user\" | \"assistant\";\n content: string | AnthropicContentBlock[];\n};\n\nexport type AnthropicMessagesParams = {\n model: string;\n messages: AnthropicMessage[];\n max_tokens: number;\n system?: string | AnthropicTextBlock[];\n temperature?: number;\n top_p?: number;\n top_k?: number;\n stop_sequences?: string[];\n stream?: boolean;\n tools?: Array<{\n name: string;\n description?: string;\n input_schema: Record<string, unknown>;\n }>;\n tool_choice?:\n | { type: \"auto\" }\n | { type: \"any\" }\n | { type: \"tool\"; name: string };\n metadata?: { user_id?: string };\n};\n\nexport type AnthropicMessagesResponse = {\n id: string;\n type: \"message\";\n role: \"assistant\";\n model: string;\n content: AnthropicContentBlock[];\n stop_reason: \"end_turn\" | \"max_tokens\" | \"stop_sequence\" | \"tool_use\" | string;\n stop_sequence: string | null;\n usage: {\n input_tokens: number;\n output_tokens: number;\n cache_creation_input_tokens?: number;\n cache_read_input_tokens?: number;\n };\n};\n\nexport const anthropic = {\n messages: {\n create(\n token: string,\n params: AnthropicMessagesParams,\n opts: HubCallOptions = {},\n ): Promise<AnthropicMessagesResponse> {\n return call<AnthropicMessagesResponse>(token, {\n ...opts,\n provider: \"anthropic\",\n method: \"POST\",\n path: \"/v1/messages\",\n body: params as unknown as Record<string, unknown>,\n });\n },\n stream(\n token: string,\n params: Omit<AnthropicMessagesParams, \"stream\">,\n opts: HubCallOptions = {},\n ): Promise<ReadableStream<Uint8Array>> {\n return callStream(token, {\n ...opts,\n provider: \"anthropic\",\n method: \"POST\",\n path: \"/v1/messages\",\n body: { ...params, stream: true } as unknown as Record<string, unknown>,\n });\n },\n },\n} as const;\n","import { call } from \"../proxy\";\nimport type { HubCallOptions } from \"../types\";\n\n/**\n * Typed convenience wrappers for Replicate's Predictions API.\n *\n * Replicate uses an async lifecycle: POST to create a prediction, GET to\n * poll its status, optionally cancel. We surface all three plus a small\n * `predictions.run()` helper that polls until the prediction is final.\n *\n * For per-model deployments (Replicate's hosted models with stable URLs),\n * use `proxy.call(token, { provider: \"replicate\", path: \"/v1/models/.../predictions\", ... })`\n * directly — the generic passthrough handles every Replicate endpoint we\n * haven't typed here yet.\n */\n\nexport type ReplicatePredictionStatus =\n | \"starting\"\n | \"processing\"\n | \"succeeded\"\n | \"failed\"\n | \"canceled\";\n\nexport type ReplicatePrediction<TOutput = unknown> = {\n id: string;\n version: string;\n status: ReplicatePredictionStatus;\n input: Record<string, unknown>;\n output: TOutput | null;\n error: string | null;\n logs: string;\n created_at: string;\n started_at: string | null;\n completed_at: string | null;\n urls: { get: string; cancel: string; stream?: string };\n metrics?: { predict_time?: number };\n};\n\nexport type ReplicateCreatePredictionParams = {\n /** Model version hash. Mutually exclusive with the model-deployment URL form. */\n version: string;\n input: Record<string, unknown>;\n webhook?: string;\n webhook_events_filter?: Array<\"start\" | \"output\" | \"logs\" | \"completed\">;\n stream?: boolean;\n};\n\nexport const replicate = {\n predictions: {\n create<TOutput = unknown>(\n token: string,\n params: ReplicateCreatePredictionParams,\n opts: HubCallOptions = {},\n ): Promise<ReplicatePrediction<TOutput>> {\n return call<ReplicatePrediction<TOutput>>(token, {\n ...opts,\n provider: \"replicate\",\n method: \"POST\",\n path: \"/v1/predictions\",\n body: params as unknown as Record<string, unknown>,\n });\n },\n get<TOutput = unknown>(\n token: string,\n predictionId: string,\n opts: HubCallOptions = {},\n ): Promise<ReplicatePrediction<TOutput>> {\n return call<ReplicatePrediction<TOutput>>(token, {\n ...opts,\n provider: \"replicate\",\n method: \"GET\",\n path: `/v1/predictions/${encodeURIComponent(predictionId)}`,\n });\n },\n cancel<TOutput = unknown>(\n token: string,\n predictionId: string,\n opts: HubCallOptions = {},\n ): Promise<ReplicatePrediction<TOutput>> {\n return call<ReplicatePrediction<TOutput>>(token, {\n ...opts,\n provider: \"replicate\",\n method: \"POST\",\n path: `/v1/predictions/${encodeURIComponent(predictionId)}/cancel`,\n });\n },\n /**\n * Convenience: create + poll until the prediction reaches a terminal\n * status. Polls every `pollIntervalMs` (default 1000ms) with the\n * provided AbortSignal honoured.\n *\n * For long-running predictions consider using webhooks via\n * `create({ webhook, webhook_events_filter })` instead so you're not\n * holding open a long fetch.\n */\n async run<TOutput = unknown>(\n token: string,\n params: ReplicateCreatePredictionParams,\n opts: HubCallOptions & { pollIntervalMs?: number } = {},\n ): Promise<ReplicatePrediction<TOutput>> {\n const interval = opts.pollIntervalMs ?? 1000;\n let prediction = await this.create<TOutput>(token, params, opts);\n while (\n prediction.status === \"starting\" ||\n prediction.status === \"processing\"\n ) {\n if (opts.signal?.aborted) {\n throw opts.signal.reason ?? new DOMException(\"Aborted\", \"AbortError\");\n }\n await new Promise<void>((resolve) => setTimeout(resolve, interval));\n prediction = await this.get<TOutput>(token, prediction.id, opts);\n }\n return prediction;\n },\n },\n} as const;\n","/**\n * `@openkeyai/sdk` — public entry.\n *\n * Tools install this and import only from the package root:\n *\n * import { session, openai, anthropic, proxy, ProviderError } from \"@openkeyai/sdk\";\n *\n * The seven-module surface (session / keys / proxy / openai / anthropic /\n * replicate / webhooks) is defined in\n * https://github.com/Scott-Builds-AI/hub/blob/main/docs/TOOL_SDK.md\n *\n * Status by module in 0.2.0:\n * - session.verify ✓\n * - keys.get → SecureKey ✓ (kept for endpoints the proxy doesn't typeset yet)\n * - proxy.call / .callRaw / .callStream ✓ ← Phase 19 universal passthrough\n * - openai.{images,chat,embeddings,audio} ✓ ← typed convenience\n * - anthropic.messages ✓ ← typed convenience\n * - replicate.predictions ✓ ← typed convenience\n * - user — deferred until the hub ships /api/me\n * - billing — deferred until the hub ships /api/billing/status\n * - webhooks — deferred until Phase 16 (hub's webhook delivery layer)\n *\n * Internal helpers live under `_internal/`. They are NOT part of the\n * public API and may change without notice — the tool-manifest scanner\n * (Phase 9) treats `@openkeyai/sdk/_internal` imports as a CI failure.\n *\n * Migration note (Phase 19):\n * The `keys.get(jwt, provider).use(callback)` SecureKey pattern still\n * works and is the only path for endpoints we haven't typed in the\n * proxy yet. For canonical model calls (images.generate, chat,\n * embeddings, etc.) prefer the proxy — the plaintext key never enters\n * your Worker process.\n */\n\nimport { verify } from \"./session\";\nimport { get } from \"./keys\";\nimport { call, callRaw, callStream } from \"./proxy\";\n\n/** session module — JWT verification + (future) refresh. */\nexport const session = {\n verify,\n} as const;\n\n/** keys module — credential fetch returning a single-use SecureKey. */\nexport const keys = {\n get,\n} as const;\n\n/**\n * proxy module — Phase 19 zero-trust universal forwarder. Plaintext keys\n * never leave the hub. Supports any HTTP method, any path on any\n * registered provider, any body shape, streaming and binary responses.\n */\nexport const proxy = {\n call,\n callRaw,\n callStream,\n} as const;\n\n/** Typed convenience surfaces — thin wrappers over `proxy.call`. */\nexport { openai } from \"./providers/openai\";\nexport { anthropic } from \"./providers/anthropic\";\nexport { replicate } from \"./providers/replicate\";\n\n// Re-exports — the SecureKey class + every typed error, so tools can\n// `instanceof` check without reaching into submodules.\nexport { SecureKey } from \"./secure-key\";\nexport {\n HubSdkError,\n MissingTokenError,\n BadTokenError,\n MissingScopeError,\n SubscriptionInactiveError,\n ToolNotFoundError,\n NotSubscribedError,\n ProviderNotGrantedError,\n ProviderNotConfiguredError,\n ProviderError,\n RateLimitedError,\n KeyNotFoundError,\n InternalError,\n NetworkError,\n SecureKeyConsumedError,\n} from \"./errors\";\nexport type { HubSdkErrorCode } from \"./errors\";\n\n// Type re-exports for tools that want to annotate their own helpers.\nexport type {\n ToolJwtClaims,\n ToolJwtScope,\n ToolJwtMode,\n ProviderSlug,\n HubCallOptions,\n ProxyCallOptions,\n} from \"./types\";\n\n// Per-provider type re-exports — for tools that want to type their own\n// request/response shapes.\nexport type {\n OpenaiImageModel,\n OpenaiImageSize,\n OpenaiImageQuality,\n OpenaiImageStyle,\n OpenaiImageGenerateParams,\n OpenaiImageGenerateResponse,\n OpenaiImageData,\n OpenaiChatRole,\n OpenaiChatMessage,\n OpenaiChatMessageContentPart,\n OpenaiChatCompletionParams,\n OpenaiChatCompletionResponse,\n OpenaiEmbeddingsParams,\n OpenaiEmbeddingsResponse,\n OpenaiTranscriptionParams,\n OpenaiTranscriptionResponse,\n OpenaiSpeechParams,\n} from \"./providers/openai\";\n\nexport type {\n AnthropicMessage,\n AnthropicMessagesParams,\n AnthropicMessagesResponse,\n AnthropicContentBlock,\n AnthropicTextBlock,\n AnthropicImageBlock,\n AnthropicToolUseBlock,\n AnthropicToolResultBlock,\n} from \"./providers/anthropic\";\n\nexport type {\n ReplicatePrediction,\n ReplicatePredictionStatus,\n ReplicateCreatePredictionParams,\n} from \"./providers/replicate\";\n\n/** Bumped on each release. Tools log this on boot. */\nexport const SDK_VERSION = \"0.2.0\";\n"]}