@theokit/sdk 4.11.0 → 4.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/internal/auth/credential-store.ts","../../src/server/auth/errors.ts","../../src/internal/auth/oauth-engine.ts","../../src/internal/auth/oauth-device.ts","../../src/internal/auth/resolve-credential.ts"],"names":["fresh"],"mappings":"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","file":"index.js","sourcesContent":["import { randomBytes } from \"node:crypto\";\nimport {\n chmodSync,\n closeSync,\n fsyncSync,\n mkdirSync,\n openSync,\n readFileSync,\n renameSync,\n statSync,\n unlinkSync,\n writeFileSync,\n} from \"node:fs\";\nimport { join } from \"node:path\";\n\nimport { z } from \"zod\";\n\n/**\n * M42 — the SDK credential store. Promoted DOWN from agent-builder's hardened `agents/lib/credentials.ts`\n * (M37), generalized from a closed `openrouter|anthropic|openai` union to an open `provider: string` and\n * driven by a caller-supplied {@link CredentialStoreConfig} (no hardcoded `.agent-builder`/`auth.json` /\n * `AGENT_BUILDER_HOME`). The security-critical file mechanics are ported VERBATIM (ADR D3 of the M42 plan):\n * atomic O_EXCL + rename + fsync write, 0700/0600 mode gates, `env` is always a PARAMETER (never an ambient\n * `process.env` read). Contract SHAPE adapted from OpenCode's provider `auth.loader` (MIT © 2025 opencode).\n *\n * The env-precedence + key-prefix-inference + declared-provider rungs of the agent-builder resolver are\n * APP POLICY and deliberately stay UP in the consumer; this module owns only the on-disk store + the\n * `api|oauth` discriminated union. See {@link resolveCredential} (SDK) for the store-read + refresh path.\n *\n * @internal\n */\nimport type {\n CredentialStoreConfig,\n StoredCredential,\n StoredOAuthCredential,\n} from \"./auth-types.js\";\n\n/** The store directory, honoring an optional `homeEnvVar` override. */\nexport function credentialHome(\n config: CredentialStoreConfig,\n env: Record<string, string | undefined> = {},\n): string {\n const override = config.homeEnvVar !== undefined ? env[config.homeEnvVar]?.trim() : undefined;\n return override !== undefined && override.length > 0\n ? override\n : join(config.home, config.dirName);\n}\n\n/** The credential file path inside the (possibly overridden) store directory. */\nexport function authFilePath(\n config: CredentialStoreConfig,\n env: Record<string, string | undefined> = {},\n): string {\n return join(credentialHome(config, env), config.fileName);\n}\n\n/** A credential problem the caller can act on. Never carries the key value. */\nexport class CredentialError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"CredentialError\";\n }\n}\n\n/**\n * The on-disk store — a discriminated union on `type` (OpenCode `Info` shape). A legacy file with NO\n * `type` (or `type: 'api'`) is the API-key variant — read unchanged, no migration. The `oauth` variant\n * carries the token pair + expiry.\n */\nconst apiFileSchema = z\n .object({\n type: z.literal(\"api\").optional(),\n provider: z.string().min(1).optional(),\n api_key: z.string(),\n })\n .strict();\n\nconst oauthFileSchema = z\n .object({\n type: z.literal(\"oauth\"),\n provider: z.string().min(1),\n access: z.string().min(1),\n refresh: z.string().min(1),\n expires: z.number(),\n account_id: z.string().optional(),\n })\n .strict();\n\n// oauth first (it requires `type: 'oauth'`); a legacy `{provider?, api_key}` falls through to api.\nconst fileSchema = z.union([oauthFileSchema, apiFileSchema]);\n\n/**\n * Read the credential file. Absent ⇒ `undefined` (the normal case). Present-but-wrong is a typed error\n * naming the file: a malformed credential store must not surface as a raw parse crash. Enforces the\n * 0700 dir / 0600 file mode gates (ported verbatim — a writable dir lets an attacker swap the file for a\n * symlink to their own account).\n */\n/**\n * The 0700-dir / 0600-file mode gates (ported verbatim). The DIRECTORY matters as much as the file:\n * `mkdirSync(mode)` applies only at creation, so a pre-existing store dir keeps whatever mode it had, and a\n * writable dir lets an attacker replace the credential file with a symlink to their own 0600 file — the\n * agent then runs on THEIR account.\n */\nfunction assertSecureModes(dirPath: string, path: string): void {\n const dirMode = statSync(dirPath).mode & 0o777;\n if ((dirMode & 0o022) !== 0) {\n throw new CredentialError(\n `${dirPath} is writable by other users (mode ${dirMode.toString(8)}), so the credential file ` +\n `inside it can be replaced. Fix it with: chmod 700 ${dirPath}`,\n );\n }\n const mode = statSync(path).mode & 0o777;\n if ((mode & 0o077) !== 0) {\n throw new CredentialError(\n `${path} is readable by other users (mode ${mode.toString(8)}). ` +\n `A credential file must not be. Fix it with: chmod 600 ${path}`,\n );\n }\n}\n\n/**\n * A `z.union` reports a generic \"Invalid input\" at the root, hiding WHAT is wrong. Pick the sub-schema the\n * file was CLEARLY aiming at (by its `type` discriminant) and surface that schema's specific issue.\n */\nfunction describeUnionError(parsed: unknown, err: unknown, path: string): CredentialError {\n const looksOAuth =\n typeof parsed === \"object\" &&\n parsed !== null &&\n (parsed as { type?: unknown }).type === \"oauth\";\n const specific = looksOAuth ? oauthFileSchema.safeParse(parsed) : apiFileSchema.safeParse(parsed);\n let issue: z.ZodIssue | undefined;\n if (!specific.success) {\n issue = specific.error.issues[0];\n } else if (err instanceof z.ZodError) {\n issue = err.issues[0];\n }\n return new CredentialError(\n `${path}: ${issue?.message ?? String(err)} [${issue?.path.join(\".\") || \"root\"}]`,\n );\n}\n\n/** Parse the raw file into the store union, surfacing the SPECIFIC sub-schema issue (not a generic union error). */\nfunction parseStoredFile(raw: string, path: string): StoredCredential {\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n // The parser's message embeds a snippet of the INPUT — up to the raw key when a user pastes the bare\n // key instead of JSON. The position is not actionable anyway, so the expected shape is more useful.\n throw new CredentialError(\n `${path} is not valid JSON. Expected: {\"provider\": \"<name>\", \"api_key\": \"...\"}`,\n );\n }\n try {\n return fileSchema.parse(parsed);\n } catch (err) {\n throw describeUnionError(parsed, err, path);\n }\n}\n\nexport function readAuthFile(\n config: CredentialStoreConfig,\n env: Record<string, string | undefined> = {},\n): StoredCredential | undefined {\n const path = authFilePath(config, env);\n\n let raw: string;\n try {\n raw = readFileSync(path, \"utf8\");\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") return undefined;\n throw new CredentialError(`cannot read ${path}: ${(err as Error).message}`);\n }\n\n assertSecureModes(credentialHome(config, env), path);\n return parseStoredFile(raw, path);\n}\n\n/**\n * Read the stored OAuth credential (with its refresh token), or `undefined` when the store is absent or\n * holds an api credential. The oauth engine needs the refresh token, which the resolved bearer does not\n * carry. Enforces the same 0600/0700 gates as every other read.\n */\nexport function readStoredOAuth(\n config: CredentialStoreConfig,\n env: Record<string, string | undefined> = {},\n): StoredOAuthCredential | undefined {\n const stored = readAuthFile(config, env);\n return stored !== undefined && stored.type === \"oauth\" ? stored : undefined;\n}\n\n/** Narrows a writable credential to the oauth variant. */\nfunction isOAuthWrite(\n c: { provider: string; apiKey: string } | StoredOAuthCredential,\n): c is StoredOAuthCredential {\n return \"type\" in c && c.type === \"oauth\";\n}\n\n/**\n * Persist a credential atomically at mode `0600`. Ported VERBATIM (ADR D3): write to a random-named temp\n * file in the same directory with `wx` (O_EXCL), fsync, close, chmod, then `rename` (atomic on POSIX) —\n * so a crash mid-write leaves whatever was there untouched, and a pre-planted symlink cannot capture the\n * key. The api variant persists the unchanged `{provider, api_key}` (back-compat, no `type` key); the\n * oauth variant persists `{type:'oauth', provider, access, refresh, expires, account_id?}`.\n */\n/** Build the on-disk JSON payload for the credential variant, validating non-empty tokens. */\nfunction buildStorePayload(\n cred: { provider: string; apiKey: string } | StoredOAuthCredential,\n): Record<string, unknown> {\n if (isOAuthWrite(cred)) {\n if (cred.access.length === 0 || cred.refresh.length === 0) {\n throw new CredentialError(\n \"refusing to write an oauth credential with an empty access/refresh token\",\n );\n }\n return {\n type: \"oauth\",\n provider: cred.provider,\n access: cred.access,\n refresh: cred.refresh,\n expires: cred.expires,\n ...(cred.account_id !== undefined ? { account_id: cred.account_id } : {}),\n };\n }\n if (typeof cred.apiKey !== \"string\" || cred.apiKey.length === 0) {\n throw new CredentialError(\"refusing to write an empty API key\");\n }\n return { provider: cred.provider, api_key: cred.apiKey };\n}\n\nexport function writeCredential(\n cred: { provider: string; apiKey: string } | StoredOAuthCredential,\n config: CredentialStoreConfig,\n env: Record<string, string | undefined> = {},\n): string {\n const payload = buildStorePayload(cred);\n\n const dir = credentialHome(config, env);\n mkdirSync(dir, { recursive: true, mode: 0o700 });\n chmodSync(dir, 0o700); // unconditional: mkdirSync's mode applies only at creation\n\n const path = authFilePath(config, env);\n // RANDOM name + `wx` (O_EXCL): a predictable temp name with a plain write follows a pre-planted SYMLINK,\n // landing the key in an attacker's file while reporting success. O_EXCL refuses any pre-existing file or\n // link; the random suffix also removes the pid collision two containers sharing a bind-mounted home make.\n const tmp = `${path}.tmp-${randomBytes(8).toString(\"hex\")}`;\n try {\n const fd = openSync(tmp, \"wx\", 0o600);\n try {\n writeFileSync(fd, `${JSON.stringify(payload, null, 2)}\\n`);\n fsyncSync(fd);\n } finally {\n closeSync(fd);\n }\n chmodSync(tmp, 0o600); // explicit: the mode argument is subject to umask\n renameSync(tmp, path);\n } catch (err) {\n try {\n unlinkSync(tmp);\n } catch {\n // the temp file may not exist; its absence is not a failure of the write\n }\n throw new CredentialError(`cannot write ${path}: ${(err as Error).message}`);\n }\n return path;\n}\n","/**\n * @theokit/sdk/server/auth — typed error classes\n *\n * Plan T1.2 + v1.1 EC-1 (AuthCancelledError for OAuth provider error response RFC 6749 §4.1.2.1).\n */\n\n/**\n * Thrown at `defineAuth()` time when configuration is invalid\n * (e.g., duplicate provider name, invalid email shape per EC-V1-12).\n */\nexport class AuthConfigError extends Error {\n override readonly name = \"AuthConfigError\";\n readonly code: string;\n\n constructor(code: string, message: string) {\n super(`[${code}] ${message}`);\n this.code = code;\n }\n}\n\n/**\n * Thrown at `startSignIn(providerName, ...)` or `finishSignIn(providerName, ...)`\n * when the named provider is not registered in `providers[]`.\n */\nexport class AuthProviderNotFoundError extends Error {\n override readonly name = \"AuthProviderNotFoundError\";\n readonly providerName: string;\n\n constructor(providerName: string) {\n super(\n `Auth provider not found: '${providerName}'. Register it in defineAuth({ providers: [...] }).`,\n );\n this.providerName = providerName;\n }\n}\n\n/**\n * Thrown during OAuth callback handling for state mismatches, expired\n * transactions, missing query params, or provider 4xx/5xx errors.\n *\n * Typed `code` field lets consumers branch on cause:\n * - 'oauth_transaction_expired' — cookie tx > 10min old (per ADR D5)\n * - 'oauth_state_mismatch' — query state ≠ cookie state (CSRF defense per RFC 6749 §10.12)\n * - 'oauth_provider_error' — non-access_denied error in callback URL\n * - 'oauth_token_exchange_failed' — provider rejected code-for-tokens swap\n * - 'oauth_userinfo_failed' — userinfo endpoint returned error\n * - 'oauth_missing_code_or_state' — required query params absent\n */\nexport class AuthCallbackError extends Error {\n override readonly name: string = \"AuthCallbackError\";\n readonly code: string;\n\n constructor(code: string, message?: string) {\n super(message ?? `OAuth callback error: ${code}`);\n this.code = code;\n }\n}\n\n/**\n * Per v1.1 EC-1 MUST FIX — typed subclass of AuthCallbackError for the\n * specific case where user declined consent at provider screen.\n *\n * OAuth 2.0 RFC 6749 §4.1.2.1: provider redirects with `?error=access_denied`.\n * Apps can catch this distinctly from network/server errors to render\n * \"Login cancelled — try again\" UX instead of opaque \"callback failed\".\n */\nexport class AuthCancelledError extends AuthCallbackError {\n override readonly name: string = \"AuthCancelledError\";\n readonly errorDescription?: string;\n\n constructor(errorDescription?: string) {\n super(\"user_declined_consent\", errorDescription ?? \"User declined consent at provider\");\n this.errorDescription = errorDescription;\n }\n}\n","/**\n * M42 — the SDK OAuth engine. Promoted DOWN from agent-builder's hardened `agents/lib/oauth.ts` +\n * `oauth-device.ts` (M37), generalized to `provider: string` + a caller-supplied {@link CredentialStoreConfig}\n * (no hardcoded client IDs — the caller declares its provider's endpoints). Ported VERBATIM (ADR D3): the\n * refresh coalescing lock, the no-token-in-error discipline, and the RFC 8628 device grant.\n *\n * Reuses the SDK's typed error taxonomy (`AuthCallbackError` from `server/auth`) for exchange/refresh\n * failures. All network I/O + clock + sleep are INJECTED so the flow is deterministic.\n *\n * ─── ADAPTED FROM OpenCode (MIT License, Copyright (c) 2025 opencode — https://github.com/sst/opencode) ───\n * - the device-grant poll loop (device_code → authorization_pending / slow_down) is adapted from\n * `packages/opencode/src/plugin/github-copilot/copilot.ts`;\n * - the JWT-claim / account-id extraction + the OpenAI two-step headless flow are adapted from\n * `packages/opencode/src/plugin/openai/codex.ts`.\n * The MIT license permits this reuse with attribution; this notice + the NOTICE file are that attribution.\n *\n * @internal\n */\nimport { AuthCallbackError } from \"../../server/auth/errors.js\";\n\nimport type {\n CredentialStoreConfig,\n HttpDeps,\n OAuthProviderConfig,\n OAuthTokens,\n ResolvedCredential,\n} from \"./auth-types.js\";\nimport { authFilePath, readStoredOAuth, writeCredential } from \"./credential-store.js\";\n\n/** Refresh a token this many ms BEFORE it actually expires (avoid a last-second, mid-request expiry). */\nconst REFRESH_SKEW_MS = 60_000;\n\n/** Parse an OAuth token endpoint response into our token triple. Throws a typed error on a bad shape. */\nfunction parseTokenResponse(body: unknown, now: number): OAuthTokens {\n const b = body as {\n access_token?: unknown;\n refresh_token?: unknown;\n expires_in?: unknown;\n account_id?: unknown;\n };\n if (typeof b.access_token !== \"string\" || b.access_token.length === 0) {\n throw new AuthCallbackError(\n \"oauth_token_exchange_failed\",\n \"token response had no access_token\",\n );\n }\n if (typeof b.refresh_token !== \"string\" || b.refresh_token.length === 0) {\n throw new AuthCallbackError(\n \"oauth_token_exchange_failed\",\n \"token response had no refresh_token\",\n );\n }\n const expiresIn = typeof b.expires_in === \"number\" ? b.expires_in : 3600;\n return {\n access: b.access_token,\n refresh: b.refresh_token,\n expires: now + expiresIn * 1000,\n ...(typeof b.account_id === \"string\" ? { accountId: b.account_id } : {}),\n };\n}\n\n/** POST a form-encoded grant to the token endpoint; return the parsed JSON or throw a typed error. */\nasync function postGrant(\n config: OAuthProviderConfig,\n form: Record<string, string>,\n deps: HttpDeps,\n): Promise<OAuthTokens> {\n let res: Response;\n try {\n res = await deps.fetch(config.tokenEndpoint, {\n method: \"POST\",\n headers: { \"content-type\": \"application/x-www-form-urlencoded\", accept: \"application/json\" },\n body: new URLSearchParams(form).toString(),\n });\n } catch (err) {\n throw new AuthCallbackError(\n \"oauth_token_exchange_failed\",\n `token endpoint request failed: ${(err as Error).message}`,\n );\n }\n if (!res.ok) {\n // The body may carry an OAuth `error` code, but never echo it verbatim — it can contain a token in\n // some providers' error payloads. Report the status only.\n throw new AuthCallbackError(\n \"oauth_token_exchange_failed\",\n `token endpoint returned HTTP ${res.status}`,\n );\n }\n let json: unknown;\n try {\n json = await res.json();\n } catch {\n // Do NOT echo the parser message — on a 200 non-JSON body it embeds a snippet of the response, which\n // in a token context can contain access/refresh material.\n throw new AuthCallbackError(\"oauth_token_exchange_failed\", \"token response was not valid JSON\");\n }\n return parseTokenResponse(json, deps.now());\n}\n\n/** Exchange an authorization `code` (+ PKCE verifier) for the token pair. */\nexport function exchangeCode(\n config: OAuthProviderConfig,\n input: { code: string; verifier: string },\n deps: HttpDeps,\n): Promise<OAuthTokens> {\n return postGrant(\n config,\n {\n grant_type: \"authorization_code\",\n code: input.code,\n redirect_uri: config.redirectUri,\n client_id: config.clientId,\n code_verifier: input.verifier,\n },\n deps,\n );\n}\n\n/** Swap a refresh token for a fresh access (and possibly rotated refresh) token. */\nexport function refreshOAuthTokens(\n config: OAuthProviderConfig,\n refresh: string,\n deps: HttpDeps,\n): Promise<OAuthTokens> {\n return postGrant(\n config,\n { grant_type: \"refresh_token\", refresh_token: refresh, client_id: config.clientId },\n deps,\n );\n}\n\n/** Persist a token triple to the store's oauth variant through the hardened 0600 writer. */\nexport function persistOAuthTokens(\n provider: string,\n tokens: OAuthTokens,\n store: CredentialStoreConfig,\n env: Record<string, string | undefined> = {},\n): string {\n return writeCredential(\n {\n type: \"oauth\",\n provider,\n access: tokens.access,\n refresh: tokens.refresh,\n expires: tokens.expires,\n ...(tokens.accountId !== undefined ? { account_id: tokens.accountId } : {}),\n },\n store,\n env,\n );\n}\n\n/**\n * In-flight refreshes, keyed by the auth-file path. Refresh tokens ROTATE (single-use) on many providers,\n * so two concurrent turns must NOT both POST the same refresh token — the second would present an\n * already-consumed token and fail. This coalesces concurrent refreshes of the same store onto one promise.\n * Process-local — the single-credential store is per-user; a cross-process lock would be over-engineering.\n */\nconst inFlightRefresh = new Map<string, Promise<OAuthTokens>>();\n\n/**\n * Return a credential guaranteed fresh enough to use. An `api` credential passes through untouched. An\n * `oauth` credential still valid (beyond the skew window) passes through; an expired one is refreshed,\n * re-persisted 0600, and returned with the new access token. Concurrent refreshes of the same store are\n * coalesced (single-use refresh tokens); the rejected promise is evicted so a failure is not cached-poison.\n */\nexport async function ensureFreshCredential(\n resolved: ResolvedCredential,\n opts: {\n config: OAuthProviderConfig;\n store: CredentialStoreConfig;\n env?: Record<string, string | undefined>;\n },\n deps: HttpDeps,\n): Promise<ResolvedCredential> {\n if (resolved.kind !== \"oauth\") return resolved;\n\n const now = deps.now();\n if (resolved.expiresAt !== undefined && resolved.expiresAt > now + REFRESH_SKEW_MS) {\n return resolved; // still valid — no network, no rewrite\n }\n\n const env = opts.env ?? {};\n const path = authFilePath(opts.store, env);\n let refresh = inFlightRefresh.get(path);\n if (refresh === undefined) {\n refresh = (async (): Promise<OAuthTokens> => {\n const stored = readStoredOAuth(opts.store, env);\n if (stored === undefined) {\n // The resolved credential said oauth but the store no longer holds it — do not fabricate; surface it.\n throw new AuthCallbackError(\n \"oauth_token_exchange_failed\",\n \"no stored oauth credential to refresh\",\n );\n }\n const fresh = await refreshOAuthTokens(opts.config, stored.refresh, deps);\n persistOAuthTokens(resolved.provider, fresh, opts.store, env);\n return fresh;\n })();\n inFlightRefresh.set(path, refresh);\n refresh.finally(() => inFlightRefresh.delete(path)).catch(() => {});\n }\n\n const fresh = await refresh;\n return {\n kind: \"oauth\",\n provider: resolved.provider,\n apiKey: fresh.access,\n source: resolved.source,\n inferred: false,\n expiresAt: fresh.expires,\n };\n}\n","/**\n * M42 — the SDK OAuth device-authorization flows (RFC 8628 + OpenAI two-step headless). Split out of\n * oauth-engine.ts to respect the 500-line file budget; a sibling of the core engine. Promoted DOWN from\n * agent-builder's hardened `agents/lib/oauth-device.ts` (M37).\n *\n * ─── ADAPTED FROM OpenCode (MIT License, Copyright (c) 2025 opencode — https://github.com/sst/opencode) ───\n * - the device-grant poll loop (device_code → authorization_pending / slow_down) is adapted from\n * `packages/opencode/src/plugin/github-copilot/copilot.ts`;\n * - the JWT-claim / account-id extraction + the OpenAI two-step headless flow are adapted from\n * `packages/opencode/src/plugin/openai/codex.ts`.\n * The MIT license permits this reuse with attribution; this notice + the NOTICE file are that attribution.\n * Adaptations: network I/O + clock + sleep are INJECTED (deterministic tests), failures raise the SDK's\n * typed `AuthCallbackError`, and a device-code expiry DEADLINE guards each poll loop (upstream loops unbounded).\n *\n * @internal\n */\nimport { AuthCallbackError } from \"../../server/auth/errors.js\";\n\nimport type {\n DeviceCodeGrant,\n DeviceDeps,\n DeviceOAuthConfig,\n OAuthTokens,\n OpenAIDeviceConfig,\n} from \"./auth-types.js\";\nimport { exchangeCode } from \"./oauth-engine.js\";\n\n// ─── OAuth 2.0 Device Authorization Grant (RFC 8628) — terminal-first / headless login ───\n\n/** Buffer added to every poll interval to avoid hitting the server a hair early (from OpenCode). */\nconst POLLING_SAFETY_MARGIN_MS = 3000;\n\n/** Step 1 — request a device code. POSTs `{client_id, scope}` to the device endpoint. */\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: RFC 8628 device-code request — cohesive network response parser ported verbatim (ADR D3).\nexport async function requestDeviceCode(\n config: DeviceOAuthConfig,\n deps: Pick<DeviceDeps, \"fetch\">,\n): Promise<DeviceCodeGrant> {\n let res: Response;\n try {\n res = await deps.fetch(config.deviceCodeEndpoint, {\n method: \"POST\",\n headers: { \"content-type\": \"application/x-www-form-urlencoded\", accept: \"application/json\" },\n body: new URLSearchParams({\n client_id: config.clientId,\n scope: config.scopes.join(\" \"),\n }).toString(),\n });\n } catch (err) {\n throw new AuthCallbackError(\n \"oauth_device_authorization_failed\",\n `device request failed: ${(err as Error).message}`,\n );\n }\n if (!res.ok) {\n throw new AuthCallbackError(\n \"oauth_device_authorization_failed\",\n `device endpoint returned HTTP ${res.status}`,\n );\n }\n const data = (await res.json()) as {\n device_code?: unknown;\n user_code?: unknown;\n verification_uri?: unknown;\n verification_uri_complete?: unknown;\n interval?: unknown;\n expires_in?: unknown;\n };\n if (typeof data.device_code !== \"string\" || typeof data.user_code !== \"string\") {\n throw new AuthCallbackError(\n \"oauth_device_authorization_failed\",\n \"device response missing device_code/user_code\",\n );\n }\n const verification =\n typeof data.verification_uri === \"string\"\n ? data.verification_uri\n : typeof data.verification_uri_complete === \"string\"\n ? data.verification_uri_complete\n : \"\";\n return {\n deviceCode: data.device_code,\n userCode: data.user_code,\n verificationUri: verification,\n interval: typeof data.interval === \"number\" && data.interval > 0 ? data.interval : 5,\n expiresIn: typeof data.expires_in === \"number\" && data.expires_in > 0 ? data.expires_in : 900,\n };\n}\n\n/**\n * Step 2 — poll the token endpoint until the user approves (or the code expires). Handles RFC 8628\n * `authorization_pending` (keep waiting) and `slow_down` (back off), with an expiry deadline so it cannot\n * spin forever.\n */\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: RFC 8628 poll state machine (authorization_pending / slow_down / success / expiry) — a cohesive loop ported verbatim (ADR D3); fragmenting it would obscure the protocol.\nexport async function pollDeviceToken(\n config: DeviceOAuthConfig,\n grant: DeviceCodeGrant,\n deps: DeviceDeps,\n): Promise<OAuthTokens> {\n const deadline = deps.now() + grant.expiresIn * 1000;\n let intervalMs = grant.interval * 1000;\n\n while (deps.now() < deadline) {\n let res: Response;\n try {\n res = await deps.fetch(config.tokenEndpoint, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/x-www-form-urlencoded\",\n accept: \"application/json\",\n },\n body: new URLSearchParams({\n client_id: config.clientId,\n device_code: grant.deviceCode,\n grant_type: \"urn:ietf:params:oauth:grant-type:device_code\",\n }).toString(),\n });\n } catch (err) {\n throw new AuthCallbackError(\n \"oauth_token_exchange_failed\",\n `device token poll failed: ${(err as Error).message}`,\n );\n }\n // RFC 8628 §3.5: `authorization_pending` / `slow_down` arrive as a 400 with an `error` body — so the\n // body MUST be read before deciding failure. Parse first; only a non-OAuth-shaped body on a non-2xx fails.\n const data = (await res.json().catch(() => ({}))) as {\n access_token?: string;\n refresh_token?: string;\n expires_in?: number;\n id_token?: string;\n error?: string;\n interval?: number;\n };\n if (!res.ok && typeof data.error !== \"string\") {\n throw new AuthCallbackError(\n \"oauth_token_exchange_failed\",\n `device token endpoint returned HTTP ${res.status}`,\n );\n }\n\n if (typeof data.access_token === \"string\" && data.access_token.length > 0) {\n const expiresIn = typeof data.expires_in === \"number\" ? data.expires_in : 0;\n const accountId = extractAccountId({\n access_token: data.access_token,\n id_token: data.id_token,\n });\n return {\n access: data.access_token,\n // Some device-grant providers (e.g. GitHub) issue no separate refresh token — reuse the access\n // token as the refresh handle, mirroring OpenCode's copilot flow.\n refresh: data.refresh_token ?? data.access_token,\n expires: deps.now() + expiresIn * 1000,\n ...(accountId !== undefined ? { accountId } : {}),\n };\n }\n\n if (data.error === \"authorization_pending\") {\n await deps.sleep(intervalMs + POLLING_SAFETY_MARGIN_MS);\n continue;\n }\n if (data.error === \"slow_down\") {\n // RFC 8628 §3.5: add 5s to the interval, or honor a server-provided one.\n intervalMs =\n (typeof data.interval === \"number\" && data.interval > 0\n ? data.interval\n : grant.interval + 5) * 1000;\n await deps.sleep(intervalMs + POLLING_SAFETY_MARGIN_MS);\n continue;\n }\n if (typeof data.error === \"string\") {\n throw new AuthCallbackError(\n \"oauth_token_exchange_failed\",\n `device authorization rejected: ${data.error}`,\n );\n }\n await deps.sleep(intervalMs + POLLING_SAFETY_MARGIN_MS);\n }\n throw new AuthCallbackError(\n \"oauth_device_code_expired\",\n \"the device code expired before it was approved\",\n );\n}\n\n/**\n * The full device login: request a code, hand the user the verification URL + user code via `onPrompt`\n * (never printed here — the caller renders it, keeping this module output-free), then poll to completion.\n */\nexport async function deviceLogin(\n config: DeviceOAuthConfig,\n deps: DeviceDeps,\n hooks: {\n onPrompt: (p: { userCode: string; verificationUri: string; expiresIn: number }) => void;\n },\n): Promise<OAuthTokens> {\n const grant = await requestDeviceCode(config, deps);\n hooks.onPrompt({\n userCode: grant.userCode,\n verificationUri: grant.verificationUri,\n expiresIn: grant.expiresIn,\n });\n return pollDeviceToken(config, grant, deps);\n}\n\n// ─── OpenAI / ChatGPT \"headless\" device flow (two-step; ADAPTED FROM OpenCode codex.ts, MIT © 2025) ───\n\n/** The OpenAI two-step device config: usercode + poll endpoints return an authorization_code (not tokens). */\n/** Step 1 (OpenAI) — request the user code. */\nexport async function requestOpenAIUsercode(\n config: OpenAIDeviceConfig,\n deps: Pick<DeviceDeps, \"fetch\">,\n): Promise<{ deviceAuthId: string; userCode: string; interval: number }> {\n let res: Response;\n try {\n res = await deps.fetch(config.deviceUsercodeEndpoint, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\", accept: \"application/json\" },\n body: JSON.stringify({ client_id: config.clientId }),\n });\n } catch (err) {\n throw new AuthCallbackError(\n \"oauth_device_authorization_failed\",\n `usercode request failed: ${(err as Error).message}`,\n );\n }\n if (!res.ok) {\n throw new AuthCallbackError(\n \"oauth_device_authorization_failed\",\n `usercode endpoint returned HTTP ${res.status}`,\n );\n }\n const data = (await res.json()) as {\n device_auth_id?: unknown;\n user_code?: unknown;\n interval?: unknown;\n };\n if (typeof data.device_auth_id !== \"string\" || typeof data.user_code !== \"string\") {\n throw new AuthCallbackError(\n \"oauth_device_authorization_failed\",\n \"usercode response missing device_auth_id/user_code\",\n );\n }\n const interval = Math.max(\n typeof data.interval === \"string\" ? parseInt(data.interval, 10) || 5 : 5,\n 1,\n );\n return { deviceAuthId: data.device_auth_id, userCode: data.user_code, interval };\n}\n\n/**\n * Step 2+3 (OpenAI) — poll for the authorization code (200 = ready; 403/404 = pending; else fail), then\n * exchange it for tokens at the standard `/oauth/token` endpoint (reuses `exchangeCode`).\n */\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: OpenAI two-step headless poll loop (200 ready / 403,404 pending / else fail) — cohesive network state machine ported verbatim (ADR D3).\nexport async function openaiDeviceLogin(\n config: OpenAIDeviceConfig,\n deps: DeviceDeps,\n hooks: { onPrompt: (p: { userCode: string; verificationUri: string }) => void },\n): Promise<OAuthTokens> {\n const { deviceAuthId, userCode, interval } = await requestOpenAIUsercode(config, deps);\n hooks.onPrompt({ userCode, verificationUri: config.verificationUri });\n\n const intervalMs = interval * 1000;\n // Bound the loop so it cannot spin forever if the provider never resolves (upstream loops unbounded).\n const deadline = deps.now() + 15 * 60 * 1000;\n while (deps.now() < deadline) {\n let res: Response;\n try {\n res = await deps.fetch(config.devicePollEndpoint, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\", accept: \"application/json\" },\n body: JSON.stringify({ device_auth_id: deviceAuthId, user_code: userCode }),\n });\n } catch (err) {\n throw new AuthCallbackError(\n \"oauth_token_exchange_failed\",\n `device poll failed: ${(err as Error).message}`,\n );\n }\n if (res.ok) {\n const data = (await res.json()) as {\n authorization_code?: unknown;\n code_verifier?: unknown;\n };\n if (typeof data.authorization_code !== \"string\" || typeof data.code_verifier !== \"string\") {\n throw new AuthCallbackError(\n \"oauth_token_exchange_failed\",\n \"device poll returned no authorization_code\",\n );\n }\n return exchangeCode(\n config,\n { code: data.authorization_code, verifier: data.code_verifier },\n deps,\n );\n }\n // 403/404 = still pending (user has not approved yet); anything else is a hard failure.\n if (res.status !== 403 && res.status !== 404) {\n throw new AuthCallbackError(\n \"oauth_token_exchange_failed\",\n `device poll returned HTTP ${res.status}`,\n );\n }\n await deps.sleep(intervalMs + POLLING_SAFETY_MARGIN_MS);\n }\n throw new AuthCallbackError(\n \"oauth_device_code_expired\",\n \"the device authorization expired before approval\",\n );\n}\n\n/** JWT id/access-token claims we read to attribute an account. Adapted from OpenCode's codex plugin. */\ninterface IdTokenClaims {\n chatgpt_account_id?: string;\n organizations?: Array<{ id: string }>;\n \"https://api.openai.com/auth\"?: { chatgpt_account_id?: string };\n}\n\n/** Decode a JWT's claim set (no signature verification — used only to read a self-reported account id). */\nexport function parseJwtClaims(token: string): IdTokenClaims | undefined {\n const parts = token.split(\".\");\n if (parts.length !== 3) return undefined;\n try {\n return JSON.parse(Buffer.from(parts[1] as string, \"base64url\").toString()) as IdTokenClaims;\n } catch {\n return undefined;\n }\n}\n\n/** Best-effort account id from an id/access token's claims (OpenAI/ChatGPT shape). Adapted from OpenCode. */\nexport function extractAccountId(tokens: {\n id_token?: string;\n access_token?: string;\n}): string | undefined {\n for (const token of [tokens.id_token, tokens.access_token]) {\n if (token === undefined) continue;\n const claims = parseJwtClaims(token);\n const id =\n claims?.chatgpt_account_id ??\n claims?.[\"https://api.openai.com/auth\"]?.chatgpt_account_id ??\n claims?.organizations?.[0]?.id;\n if (id !== undefined) return id;\n }\n return undefined;\n}\n","/**\n * M42 — `resolveCredential`: the public composition entrypoint over the credential store + oauth engine.\n * Given a provider name + a {@link CredentialStoreConfig} (and, for oauth, an {@link OAuthProviderConfig}),\n * read the store and return a FRESH `ResolvedCredential` — an api credential passes through by identity; an\n * oauth credential is transparently refreshed when its access token is within the skew window. Returns\n * `undefined` when the store holds no credential for `provider` (the caller then falls back to env / apiKeys).\n *\n * Mirrors agent-builder's `resolveFreshCredential` composition (store read → oauth → ensureFreshCredential),\n * defaulting `fetch`/`now` to globals. This is the async surface an oauth provider's M41 `transform.fetch`\n * calls at stream time, so a mid-turn token expiry refreshes without rebuilding the agent.\n *\n * @internal (re-exported from the package barrel as public)\n */\nimport type {\n CredentialStoreConfig,\n HttpDeps,\n OAuthProviderConfig,\n ResolvedCredential,\n} from \"./auth-types.js\";\nimport { authFilePath, readAuthFile } from \"./credential-store.js\";\nimport { ensureFreshCredential } from \"./oauth-engine.js\";\n\nexport interface ResolveCredentialOptions {\n /** The provider whose stored credential to resolve. */\n provider: string;\n /** Where the credential store lives. */\n store: CredentialStoreConfig;\n /** Env for the store's optional `homeEnvVar` override. Never an ambient read. */\n env?: Record<string, string | undefined>;\n /** Required to refresh an oauth credential; omit for an api-only store. */\n oauth?: OAuthProviderConfig;\n /** Injected HTTP + clock for deterministic tests; default globals. */\n deps?: { fetch?: typeof fetch; now?: () => number };\n}\n\n/**\n * Resolve a fresh credential for `provider` from the store, or `undefined` if the store holds none for it.\n * oauth credentials are auto-refreshed when `opts.oauth` is supplied; api credentials pass through.\n */\n/** Resolve (and, when a config is supplied, refresh) the oauth variant for the requested provider. */\nasync function resolveOAuth(\n stored: { provider: string; access: string; expires: number },\n path: string,\n opts: ResolveCredentialOptions,\n env: Record<string, string | undefined>,\n): Promise<ResolvedCredential | undefined> {\n if (stored.provider !== opts.provider) return undefined;\n const base: ResolvedCredential = {\n kind: \"oauth\",\n provider: opts.provider,\n apiKey: stored.access,\n source: path,\n inferred: false,\n expiresAt: stored.expires,\n };\n if (opts.oauth === undefined) return base; // no config to refresh with — return the stored access token\n const deps: HttpDeps = {\n fetch: opts.deps?.fetch ?? fetch,\n now: opts.deps?.now ?? (() => Date.now()),\n };\n return ensureFreshCredential(base, { config: opts.oauth, store: opts.store, env }, deps);\n}\n\nexport async function resolveCredential(\n opts: ResolveCredentialOptions,\n): Promise<ResolvedCredential | undefined> {\n const env = opts.env ?? {};\n const stored = readAuthFile(opts.store, env);\n if (stored === undefined) return undefined;\n\n const path = authFilePath(opts.store, env);\n\n if (stored.type === \"oauth\") {\n return resolveOAuth(stored, path, opts, env);\n }\n\n // api variant: honor an explicit provider filter; a provider-less legacy file resolves as inferred.\n if (stored.api_key.length === 0) return undefined;\n if (stored.provider !== undefined && stored.provider !== opts.provider) return undefined;\n return {\n kind: \"api\",\n provider: opts.provider,\n apiKey: stored.api_key,\n source: path,\n inferred: stored.provider === undefined,\n };\n}\n"]}
1
+ {"version":3,"sources":["../../src/internal/auth/credential-store.ts","../../src/server/auth/errors.ts","../../src/internal/auth/oauth-engine.ts","../../src/internal/auth/oauth-device.ts","../../src/internal/auth/resolve-credential.ts"],"names":["fresh"],"mappings":";;;;;;AAsCO,SAAS,cAAA,CACd,MAAA,EACA,GAAA,GAA0C,EAAC,EACnC;AACR,EAAA,MAAM,QAAA,GAAW,OAAO,UAAA,KAAe,MAAA,GAAY,IAAI,MAAA,CAAO,UAAU,CAAA,EAAG,IAAA,EAAK,GAAI,MAAA;AACpF,EAAA,OAAO,QAAA,KAAa,MAAA,IAAa,QAAA,CAAS,MAAA,GAAS,CAAA,GAC/C,WACA,IAAA,CAAK,MAAA,CAAO,IAAA,EAAM,MAAA,CAAO,OAAO,CAAA;AACtC;AAGO,SAAS,YAAA,CACd,MAAA,EACA,GAAA,GAA0C,EAAC,EACnC;AACR,EAAA,OAAO,KAAK,cAAA,CAAe,MAAA,EAAQ,GAAG,CAAA,EAAG,OAAO,QAAQ,CAAA;AAC1D;AAGO,IAAM,eAAA,GAAN,cAA8B,KAAA,CAAM;AAAA,EACzC,YAAY,OAAA,EAAiB;AAC3B,IAAA,KAAA,CAAM,OAAO,CAAA;AACb,IAAA,IAAA,CAAK,IAAA,GAAO,iBAAA;AAAA,EACd;AACF;AAOA,IAAM,aAAA,GAAgB,EACnB,MAAA,CAAO;AAAA,EACN,IAAA,EAAM,CAAA,CAAE,OAAA,CAAQ,KAAK,EAAE,QAAA,EAAS;AAAA,EAChC,UAAU,CAAA,CAAE,MAAA,GAAS,GAAA,CAAI,CAAC,EAAE,QAAA,EAAS;AAAA,EACrC,OAAA,EAAS,EAAE,MAAA;AACb,CAAC,EACA,MAAA,EAAO;AAEV,IAAM,eAAA,GAAkB,EACrB,MAAA,CAAO;AAAA,EACN,IAAA,EAAM,CAAA,CAAE,OAAA,CAAQ,OAAO,CAAA;AAAA,EACvB,QAAA,EAAU,CAAA,CAAE,MAAA,EAAO,CAAE,IAAI,CAAC,CAAA;AAAA,EAC1B,MAAA,EAAQ,CAAA,CAAE,MAAA,EAAO,CAAE,IAAI,CAAC,CAAA;AAAA,EACxB,OAAA,EAAS,CAAA,CAAE,MAAA,EAAO,CAAE,IAAI,CAAC,CAAA;AAAA,EACzB,OAAA,EAAS,EAAE,MAAA,EAAO;AAAA,EAClB,UAAA,EAAY,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA;AACzB,CAAC,EACA,MAAA,EAAO;AAGV,IAAM,aAAa,CAAA,CAAE,KAAA,CAAM,CAAC,eAAA,EAAiB,aAAa,CAAC,CAAA;AAc3D,SAAS,iBAAA,CAAkB,SAAiB,IAAA,EAAoB;AAC9D,EAAA,MAAM,OAAA,GAAU,QAAA,CAAS,OAAO,CAAA,CAAE,IAAA,GAAO,GAAA;AACzC,EAAA,IAAA,CAAK,OAAA,GAAU,QAAW,CAAA,EAAG;AAC3B,IAAA,MAAM,IAAI,eAAA;AAAA,MACR,CAAA,EAAG,OAAO,CAAA,kCAAA,EAAqC,OAAA,CAAQ,SAAS,CAAC,CAAC,gFACV,OAAO,CAAA;AAAA,KACjE;AAAA,EACF;AACA,EAAA,MAAM,IAAA,GAAO,QAAA,CAAS,IAAI,CAAA,CAAE,IAAA,GAAO,GAAA;AACnC,EAAA,IAAA,CAAK,IAAA,GAAO,QAAW,CAAA,EAAG;AACxB,IAAA,MAAM,IAAI,eAAA;AAAA,MACR,CAAA,EAAG,IAAI,CAAA,kCAAA,EAAqC,IAAA,CAAK,SAAS,CAAC,CAAC,6DACA,IAAI,CAAA;AAAA,KAClE;AAAA,EACF;AACF;AAMA,SAAS,kBAAA,CAAmB,MAAA,EAAiB,GAAA,EAAc,IAAA,EAA+B;AACxF,EAAA,MAAM,aACJ,OAAO,MAAA,KAAW,YAClB,MAAA,KAAW,IAAA,IACV,OAA8B,IAAA,KAAS,OAAA;AAC1C,EAAA,MAAM,QAAA,GAAW,aAAa,eAAA,CAAgB,SAAA,CAAU,MAAM,CAAA,GAAI,aAAA,CAAc,UAAU,MAAM,CAAA;AAChG,EAAA,IAAI,KAAA;AACJ,EAAA,IAAI,CAAC,SAAS,OAAA,EAAS;AACrB,IAAA,KAAA,GAAQ,QAAA,CAAS,KAAA,CAAM,MAAA,CAAO,CAAC,CAAA;AAAA,EACjC,CAAA,MAAA,IAAW,GAAA,YAAe,CAAA,CAAE,QAAA,EAAU;AACpC,IAAA,KAAA,GAAQ,GAAA,CAAI,OAAO,CAAC,CAAA;AAAA,EACtB;AACA,EAAA,OAAO,IAAI,eAAA;AAAA,IACT,CAAA,EAAG,IAAI,CAAA,EAAA,EAAK,KAAA,EAAO,WAAW,MAAA,CAAO,GAAG,CAAC,CAAA,EAAA,EAAK,KAAA,EAAO,IAAA,CAAK,IAAA,CAAK,GAAG,KAAK,MAAM,CAAA,CAAA;AAAA,GAC/E;AACF;AAGA,SAAS,eAAA,CAAgB,KAAa,IAAA,EAAgC;AACpE,EAAA,IAAI,MAAA;AACJ,EAAA,IAAI;AACF,IAAA,MAAA,GAAS,IAAA,CAAK,MAAM,GAAG,CAAA;AAAA,EACzB,CAAA,CAAA,MAAQ;AAGN,IAAA,MAAM,IAAI,eAAA;AAAA,MACR,GAAG,IAAI,CAAA,uEAAA;AAAA,KACT;AAAA,EACF;AACA,EAAA,IAAI;AACF,IAAA,OAAO,UAAA,CAAW,MAAM,MAAM,CAAA;AAAA,EAChC,SAAS,GAAA,EAAK;AACZ,IAAA,MAAM,kBAAA,CAAmB,MAAA,EAAQ,GAAA,EAAK,IAAI,CAAA;AAAA,EAC5C;AACF;AAEO,SAAS,YAAA,CACd,MAAA,EACA,GAAA,GAA0C,EAAC,EACb;AAC9B,EAAA,MAAM,IAAA,GAAO,YAAA,CAAa,MAAA,EAAQ,GAAG,CAAA;AAErC,EAAA,IAAI,GAAA;AACJ,EAAA,IAAI;AACF,IAAA,GAAA,GAAM,YAAA,CAAa,MAAM,MAAM,CAAA;AAAA,EACjC,SAAS,GAAA,EAAK;AACZ,IAAA,IAAK,GAAA,CAA8B,IAAA,KAAS,QAAA,EAAU,OAAO,MAAA;AAC7D,IAAA,MAAM,IAAI,eAAA,CAAgB,CAAA,YAAA,EAAe,IAAI,CAAA,EAAA,EAAM,GAAA,CAAc,OAAO,CAAA,CAAE,CAAA;AAAA,EAC5E;AAEA,EAAA,iBAAA,CAAkB,cAAA,CAAe,MAAA,EAAQ,GAAG,CAAA,EAAG,IAAI,CAAA;AACnD,EAAA,OAAO,eAAA,CAAgB,KAAK,IAAI,CAAA;AAClC;AAOO,SAAS,eAAA,CACd,MAAA,EACA,GAAA,GAA0C,EAAC,EACR;AACnC,EAAA,MAAM,MAAA,GAAS,YAAA,CAAa,MAAA,EAAQ,GAAG,CAAA;AACvC,EAAA,OAAO,MAAA,KAAW,MAAA,IAAa,MAAA,CAAO,IAAA,KAAS,UAAU,MAAA,GAAS,MAAA;AACpE;AAGA,SAAS,aACP,CAAA,EAC4B;AAC5B,EAAA,OAAO,MAAA,IAAU,CAAA,IAAK,CAAA,CAAE,IAAA,KAAS,OAAA;AACnC;AAUA,SAAS,kBACP,IAAA,EACyB;AACzB,EAAA,IAAI,YAAA,CAAa,IAAI,CAAA,EAAG;AACtB,IAAA,IAAI,KAAK,MAAA,CAAO,MAAA,KAAW,KAAK,IAAA,CAAK,OAAA,CAAQ,WAAW,CAAA,EAAG;AACzD,MAAA,MAAM,IAAI,eAAA;AAAA,QACR;AAAA,OACF;AAAA,IACF;AACA,IAAA,OAAO;AAAA,MACL,IAAA,EAAM,OAAA;AAAA,MACN,UAAU,IAAA,CAAK,QAAA;AAAA,MACf,QAAQ,IAAA,CAAK,MAAA;AAAA,MACb,SAAS,IAAA,CAAK,OAAA;AAAA,MACd,SAAS,IAAA,CAAK,OAAA;AAAA,MACd,GAAI,KAAK,UAAA,KAAe,MAAA,GAAY,EAAE,UAAA,EAAY,IAAA,CAAK,UAAA,EAAW,GAAI;AAAC,KACzE;AAAA,EACF;AACA,EAAA,IAAI,OAAO,IAAA,CAAK,MAAA,KAAW,YAAY,IAAA,CAAK,MAAA,CAAO,WAAW,CAAA,EAAG;AAC/D,IAAA,MAAM,IAAI,gBAAgB,oCAAoC,CAAA;AAAA,EAChE;AACA,EAAA,OAAO,EAAE,QAAA,EAAU,IAAA,CAAK,QAAA,EAAU,OAAA,EAAS,KAAK,MAAA,EAAO;AACzD;AAEO,SAAS,eAAA,CACd,IAAA,EACA,MAAA,EACA,GAAA,GAA0C,EAAC,EACnC;AACR,EAAA,MAAM,OAAA,GAAU,kBAAkB,IAAI,CAAA;AAEtC,EAAA,MAAM,GAAA,GAAM,cAAA,CAAe,MAAA,EAAQ,GAAG,CAAA;AACtC,EAAA,SAAA,CAAU,KAAK,EAAE,SAAA,EAAW,IAAA,EAAM,IAAA,EAAM,KAAO,CAAA;AAC/C,EAAA,SAAA,CAAU,KAAK,GAAK,CAAA;AAEpB,EAAA,MAAM,IAAA,GAAO,YAAA,CAAa,MAAA,EAAQ,GAAG,CAAA;AAIrC,EAAA,MAAM,GAAA,GAAM,GAAG,IAAI,CAAA,KAAA,EAAQ,YAAY,CAAC,CAAA,CAAE,QAAA,CAAS,KAAK,CAAC,CAAA,CAAA;AACzD,EAAA,IAAI;AACF,IAAA,MAAM,EAAA,GAAK,QAAA,CAAS,GAAA,EAAK,IAAA,EAAM,GAAK,CAAA;AACpC,IAAA,IAAI;AACF,MAAA,aAAA,CAAc,IAAI,CAAA,EAAG,IAAA,CAAK,UAAU,OAAA,EAAS,IAAA,EAAM,CAAC,CAAC;AAAA,CAAI,CAAA;AACzD,MAAA,SAAA,CAAU,EAAE,CAAA;AAAA,IACd,CAAA,SAAE;AACA,MAAA,SAAA,CAAU,EAAE,CAAA;AAAA,IACd;AACA,IAAA,SAAA,CAAU,KAAK,GAAK,CAAA;AACpB,IAAA,UAAA,CAAW,KAAK,IAAI,CAAA;AAAA,EACtB,SAAS,GAAA,EAAK;AACZ,IAAA,IAAI;AACF,MAAA,UAAA,CAAW,GAAG,CAAA;AAAA,IAChB,CAAA,CAAA,MAAQ;AAAA,IAER;AACA,IAAA,MAAM,IAAI,eAAA,CAAgB,CAAA,aAAA,EAAgB,IAAI,CAAA,EAAA,EAAM,GAAA,CAAc,OAAO,CAAA,CAAE,CAAA;AAAA,EAC7E;AACA,EAAA,OAAO,IAAA;AACT;;;ACzNO,IAAM,iBAAA,GAAN,cAAgC,KAAA,CAAM;AAAA,EACzB,IAAA,GAAe,mBAAA;AAAA,EACxB,IAAA;AAAA,EAET,WAAA,CAAY,MAAc,OAAA,EAAkB;AAC1C,IAAA,KAAA,CAAM,OAAA,IAAW,CAAA,sBAAA,EAAyB,IAAI,CAAA,CAAE,CAAA;AAChD,IAAA,IAAA,CAAK,IAAA,GAAO,IAAA;AAAA,EACd;AACF,CAAA;;;AC1BA,IAAM,eAAA,GAAkB,GAAA;AAGxB,SAAS,kBAAA,CAAmB,MAAe,GAAA,EAA0B;AACnE,EAAA,MAAM,CAAA,GAAI,IAAA;AAMV,EAAA,IAAI,OAAO,CAAA,CAAE,YAAA,KAAiB,YAAY,CAAA,CAAE,YAAA,CAAa,WAAW,CAAA,EAAG;AACrE,IAAA,MAAM,IAAI,iBAAA;AAAA,MACR,6BAAA;AAAA,MACA;AAAA,KACF;AAAA,EACF;AACA,EAAA,IAAI,OAAO,CAAA,CAAE,aAAA,KAAkB,YAAY,CAAA,CAAE,aAAA,CAAc,WAAW,CAAA,EAAG;AACvE,IAAA,MAAM,IAAI,iBAAA;AAAA,MACR,6BAAA;AAAA,MACA;AAAA,KACF;AAAA,EACF;AACA,EAAA,MAAM,YAAY,OAAO,CAAA,CAAE,UAAA,KAAe,QAAA,GAAW,EAAE,UAAA,GAAa,IAAA;AACpE,EAAA,OAAO;AAAA,IACL,QAAQ,CAAA,CAAE,YAAA;AAAA,IACV,SAAS,CAAA,CAAE,aAAA;AAAA,IACX,OAAA,EAAS,MAAM,SAAA,GAAY,GAAA;AAAA,IAC3B,GAAI,OAAO,CAAA,CAAE,UAAA,KAAe,QAAA,GAAW,EAAE,SAAA,EAAW,CAAA,CAAE,UAAA,EAAW,GAAI;AAAC,GACxE;AACF;AAGA,eAAe,SAAA,CACb,MAAA,EACA,IAAA,EACA,IAAA,EACsB;AACtB,EAAA,IAAI,GAAA;AACJ,EAAA,IAAI;AACF,IAAA,GAAA,GAAM,MAAM,IAAA,CAAK,KAAA,CAAM,MAAA,CAAO,aAAA,EAAe;AAAA,MAC3C,MAAA,EAAQ,MAAA;AAAA,MACR,OAAA,EAAS,EAAE,cAAA,EAAgB,mCAAA,EAAqC,QAAQ,kBAAA,EAAmB;AAAA,MAC3F,IAAA,EAAM,IAAI,eAAA,CAAgB,IAAI,EAAE,QAAA;AAAS,KAC1C,CAAA;AAAA,EACH,SAAS,GAAA,EAAK;AACZ,IAAA,MAAM,IAAI,iBAAA;AAAA,MACR,6BAAA;AAAA,MACA,CAAA,+BAAA,EAAmC,IAAc,OAAO,CAAA;AAAA,KAC1D;AAAA,EACF;AACA,EAAA,IAAI,CAAC,IAAI,EAAA,EAAI;AAGX,IAAA,MAAM,IAAI,iBAAA;AAAA,MACR,6BAAA;AAAA,MACA,CAAA,6BAAA,EAAgC,IAAI,MAAM,CAAA;AAAA,KAC5C;AAAA,EACF;AACA,EAAA,IAAI,IAAA;AACJ,EAAA,IAAI;AACF,IAAA,IAAA,GAAO,MAAM,IAAI,IAAA,EAAK;AAAA,EACxB,CAAA,CAAA,MAAQ;AAGN,IAAA,MAAM,IAAI,iBAAA,CAAkB,6BAAA,EAA+B,mCAAmC,CAAA;AAAA,EAChG;AACA,EAAA,OAAO,kBAAA,CAAmB,IAAA,EAAM,IAAA,CAAK,GAAA,EAAK,CAAA;AAC5C;AAGO,SAAS,YAAA,CACd,MAAA,EACA,KAAA,EACA,IAAA,EACsB;AACtB,EAAA,OAAO,SAAA;AAAA,IACL,MAAA;AAAA,IACA;AAAA,MACE,UAAA,EAAY,oBAAA;AAAA,MACZ,MAAM,KAAA,CAAM,IAAA;AAAA,MACZ,cAAc,MAAA,CAAO,WAAA;AAAA,MACrB,WAAW,MAAA,CAAO,QAAA;AAAA,MAClB,eAAe,KAAA,CAAM;AAAA,KACvB;AAAA,IACA;AAAA,GACF;AACF;AAGO,SAAS,kBAAA,CACd,MAAA,EACA,OAAA,EACA,IAAA,EACsB;AACtB,EAAA,OAAO,SAAA;AAAA,IACL,MAAA;AAAA,IACA,EAAE,UAAA,EAAY,eAAA,EAAiB,eAAe,OAAA,EAAS,SAAA,EAAW,OAAO,QAAA,EAAS;AAAA,IAClF;AAAA,GACF;AACF;AAGO,SAAS,mBACd,QAAA,EACA,MAAA,EACA,KAAA,EACA,GAAA,GAA0C,EAAC,EACnC;AACR,EAAA,OAAO,eAAA;AAAA,IACL;AAAA,MACE,IAAA,EAAM,OAAA;AAAA,MACN,QAAA;AAAA,MACA,QAAQ,MAAA,CAAO,MAAA;AAAA,MACf,SAAS,MAAA,CAAO,OAAA;AAAA,MAChB,SAAS,MAAA,CAAO,OAAA;AAAA,MAChB,GAAI,OAAO,SAAA,KAAc,MAAA,GAAY,EAAE,UAAA,EAAY,MAAA,CAAO,SAAA,EAAU,GAAI;AAAC,KAC3E;AAAA,IACA,KAAA;AAAA,IACA;AAAA,GACF;AACF;AAQA,IAAM,eAAA,uBAAsB,GAAA,EAAkC;AAQ9D,eAAsB,qBAAA,CACpB,QAAA,EACA,IAAA,EAKA,IAAA,EAC6B;AAC7B,EAAA,IAAI,QAAA,CAAS,IAAA,KAAS,OAAA,EAAS,OAAO,QAAA;AAEtC,EAAA,MAAM,GAAA,GAAM,KAAK,GAAA,EAAI;AACrB,EAAA,IAAI,SAAS,SAAA,KAAc,MAAA,IAAa,QAAA,CAAS,SAAA,GAAY,MAAM,eAAA,EAAiB;AAClF,IAAA,OAAO,QAAA;AAAA,EACT;AAEA,EAAA,MAAM,GAAA,GAAM,IAAA,CAAK,GAAA,IAAO,EAAC;AACzB,EAAA,MAAM,IAAA,GAAO,YAAA,CAAa,IAAA,CAAK,KAAA,EAAO,GAAG,CAAA;AACzC,EAAA,IAAI,OAAA,GAAU,eAAA,CAAgB,GAAA,CAAI,IAAI,CAAA;AACtC,EAAA,IAAI,YAAY,MAAA,EAAW;AACzB,IAAA,OAAA,GAAA,CAAW,YAAkC;AAC3C,MAAA,MAAM,MAAA,GAAS,eAAA,CAAgB,IAAA,CAAK,KAAA,EAAO,GAAG,CAAA;AAC9C,MAAA,IAAI,WAAW,MAAA,EAAW;AAExB,QAAA,MAAM,IAAI,iBAAA;AAAA,UACR,6BAAA;AAAA,UACA;AAAA,SACF;AAAA,MACF;AACA,MAAA,MAAMA,SAAQ,MAAM,kBAAA,CAAmB,KAAK,MAAA,EAAQ,MAAA,CAAO,SAAS,IAAI,CAAA;AACxE,MAAA,kBAAA,CAAmB,QAAA,CAAS,QAAA,EAAUA,MAAAA,EAAO,IAAA,CAAK,OAAO,GAAG,CAAA;AAC5D,MAAA,OAAOA,MAAAA;AAAA,IACT,CAAA,GAAG;AACH,IAAA,eAAA,CAAgB,GAAA,CAAI,MAAM,OAAO,CAAA;AACjC,IAAA,OAAA,CAAQ,OAAA,CAAQ,MAAM,eAAA,CAAgB,MAAA,CAAO,IAAI,CAAC,CAAA,CAAE,MAAM,MAAM;AAAA,IAAC,CAAC,CAAA;AAAA,EACpE;AAEA,EAAA,MAAM,QAAQ,MAAM,OAAA;AACpB,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,OAAA;AAAA,IACN,UAAU,QAAA,CAAS,QAAA;AAAA,IACnB,QAAQ,KAAA,CAAM,MAAA;AAAA,IACd,QAAQ,QAAA,CAAS,MAAA;AAAA,IACjB,QAAA,EAAU,KAAA;AAAA,IACV,WAAW,KAAA,CAAM;AAAA,GACnB;AACF;;;ACtLA,IAAM,wBAAA,GAA2B,GAAA;AAIjC,eAAsB,iBAAA,CACpB,QACA,IAAA,EAC0B;AAC1B,EAAA,IAAI,GAAA;AACJ,EAAA,IAAI;AACF,IAAA,GAAA,GAAM,MAAM,IAAA,CAAK,KAAA,CAAM,MAAA,CAAO,kBAAA,EAAoB;AAAA,MAChD,MAAA,EAAQ,MAAA;AAAA,MACR,OAAA,EAAS,EAAE,cAAA,EAAgB,mCAAA,EAAqC,QAAQ,kBAAA,EAAmB;AAAA,MAC3F,IAAA,EAAM,IAAI,eAAA,CAAgB;AAAA,QACxB,WAAW,MAAA,CAAO,QAAA;AAAA,QAClB,KAAA,EAAO,MAAA,CAAO,MAAA,CAAO,IAAA,CAAK,GAAG;AAAA,OAC9B,EAAE,QAAA;AAAS,KACb,CAAA;AAAA,EACH,SAAS,GAAA,EAAK;AACZ,IAAA,MAAM,IAAI,iBAAA;AAAA,MACR,mCAAA;AAAA,MACA,CAAA,uBAAA,EAA2B,IAAc,OAAO,CAAA;AAAA,KAClD;AAAA,EACF;AACA,EAAA,IAAI,CAAC,IAAI,EAAA,EAAI;AACX,IAAA,MAAM,IAAI,iBAAA;AAAA,MACR,mCAAA;AAAA,MACA,CAAA,8BAAA,EAAiC,IAAI,MAAM,CAAA;AAAA,KAC7C;AAAA,EACF;AACA,EAAA,MAAM,IAAA,GAAQ,MAAM,GAAA,CAAI,IAAA,EAAK;AAQ7B,EAAA,IAAI,OAAO,IAAA,CAAK,WAAA,KAAgB,YAAY,OAAO,IAAA,CAAK,cAAc,QAAA,EAAU;AAC9E,IAAA,MAAM,IAAI,iBAAA;AAAA,MACR,mCAAA;AAAA,MACA;AAAA,KACF;AAAA,EACF;AACA,EAAA,MAAM,YAAA,GACJ,OAAO,IAAA,CAAK,gBAAA,KAAqB,QAAA,GAC7B,IAAA,CAAK,gBAAA,GACL,OAAO,IAAA,CAAK,yBAAA,KAA8B,QAAA,GACxC,IAAA,CAAK,yBAAA,GACL,EAAA;AACR,EAAA,OAAO;AAAA,IACL,YAAY,IAAA,CAAK,WAAA;AAAA,IACjB,UAAU,IAAA,CAAK,SAAA;AAAA,IACf,eAAA,EAAiB,YAAA;AAAA,IACjB,QAAA,EAAU,OAAO,IAAA,CAAK,QAAA,KAAa,YAAY,IAAA,CAAK,QAAA,GAAW,CAAA,GAAI,IAAA,CAAK,QAAA,GAAW,CAAA;AAAA,IACnF,SAAA,EAAW,OAAO,IAAA,CAAK,UAAA,KAAe,YAAY,IAAA,CAAK,UAAA,GAAa,CAAA,GAAI,IAAA,CAAK,UAAA,GAAa;AAAA,GAC5F;AACF;AAQA,eAAsB,eAAA,CACpB,MAAA,EACA,KAAA,EACA,IAAA,EACsB;AACtB,EAAA,MAAM,QAAA,GAAW,IAAA,CAAK,GAAA,EAAI,GAAI,MAAM,SAAA,GAAY,GAAA;AAChD,EAAA,IAAI,UAAA,GAAa,MAAM,QAAA,GAAW,GAAA;AAElC,EAAA,OAAO,IAAA,CAAK,GAAA,EAAI,GAAI,QAAA,EAAU;AAC5B,IAAA,IAAI,GAAA;AACJ,IAAA,IAAI;AACF,MAAA,GAAA,GAAM,MAAM,IAAA,CAAK,KAAA,CAAM,MAAA,CAAO,aAAA,EAAe;AAAA,QAC3C,MAAA,EAAQ,MAAA;AAAA,QACR,OAAA,EAAS;AAAA,UACP,cAAA,EAAgB,mCAAA;AAAA,UAChB,MAAA,EAAQ;AAAA,SACV;AAAA,QACA,IAAA,EAAM,IAAI,eAAA,CAAgB;AAAA,UACxB,WAAW,MAAA,CAAO,QAAA;AAAA,UAClB,aAAa,KAAA,CAAM,UAAA;AAAA,UACnB,UAAA,EAAY;AAAA,SACb,EAAE,QAAA;AAAS,OACb,CAAA;AAAA,IACH,SAAS,GAAA,EAAK;AACZ,MAAA,MAAM,IAAI,iBAAA;AAAA,QACR,6BAAA;AAAA,QACA,CAAA,0BAAA,EAA8B,IAAc,OAAO,CAAA;AAAA,OACrD;AAAA,IACF;AAGA,IAAA,MAAM,IAAA,GAAQ,MAAM,GAAA,CAAI,IAAA,GAAO,KAAA,CAAM,OAAO,EAAC,CAAE,CAAA;AAQ/C,IAAA,IAAI,CAAC,GAAA,CAAI,EAAA,IAAM,OAAO,IAAA,CAAK,UAAU,QAAA,EAAU;AAC7C,MAAA,MAAM,IAAI,iBAAA;AAAA,QACR,6BAAA;AAAA,QACA,CAAA,oCAAA,EAAuC,IAAI,MAAM,CAAA;AAAA,OACnD;AAAA,IACF;AAEA,IAAA,IAAI,OAAO,IAAA,CAAK,YAAA,KAAiB,YAAY,IAAA,CAAK,YAAA,CAAa,SAAS,CAAA,EAAG;AACzE,MAAA,MAAM,YAAY,OAAO,IAAA,CAAK,UAAA,KAAe,QAAA,GAAW,KAAK,UAAA,GAAa,CAAA;AAC1E,MAAA,MAAM,YAAY,gBAAA,CAAiB;AAAA,QACjC,cAAc,IAAA,CAAK,YAAA;AAAA,QACnB,UAAU,IAAA,CAAK;AAAA,OAChB,CAAA;AACD,MAAA,OAAO;AAAA,QACL,QAAQ,IAAA,CAAK,YAAA;AAAA;AAAA;AAAA,QAGb,OAAA,EAAS,IAAA,CAAK,aAAA,IAAiB,IAAA,CAAK,YAAA;AAAA,QACpC,OAAA,EAAS,IAAA,CAAK,GAAA,EAAI,GAAI,SAAA,GAAY,GAAA;AAAA,QAClC,GAAI,SAAA,KAAc,MAAA,GAAY,EAAE,SAAA,KAAc;AAAC,OACjD;AAAA,IACF;AAEA,IAAA,IAAI,IAAA,CAAK,UAAU,uBAAA,EAAyB;AAC1C,MAAA,MAAM,IAAA,CAAK,KAAA,CAAM,UAAA,GAAa,wBAAwB,CAAA;AACtD,MAAA;AAAA,IACF;AACA,IAAA,IAAI,IAAA,CAAK,UAAU,WAAA,EAAa;AAE9B,MAAA,UAAA,GAAA,CACG,OAAO,IAAA,CAAK,QAAA,KAAa,QAAA,IAAY,IAAA,CAAK,QAAA,GAAW,CAAA,GAClD,IAAA,CAAK,QAAA,GACL,KAAA,CAAM,QAAA,GAAW,CAAA,IAAK,GAAA;AAC5B,MAAA,MAAM,IAAA,CAAK,KAAA,CAAM,UAAA,GAAa,wBAAwB,CAAA;AACtD,MAAA;AAAA,IACF;AACA,IAAA,IAAI,OAAO,IAAA,CAAK,KAAA,KAAU,QAAA,EAAU;AAClC,MAAA,MAAM,IAAI,iBAAA;AAAA,QACR,6BAAA;AAAA,QACA,CAAA,+BAAA,EAAkC,KAAK,KAAK,CAAA;AAAA,OAC9C;AAAA,IACF;AACA,IAAA,MAAM,IAAA,CAAK,KAAA,CAAM,UAAA,GAAa,wBAAwB,CAAA;AAAA,EACxD;AACA,EAAA,MAAM,IAAI,iBAAA;AAAA,IACR,2BAAA;AAAA,IACA;AAAA,GACF;AACF;AAMA,eAAsB,WAAA,CACpB,MAAA,EACA,IAAA,EACA,KAAA,EAGsB;AACtB,EAAA,MAAM,KAAA,GAAQ,MAAM,iBAAA,CAAkB,MAAA,EAAQ,IAAI,CAAA;AAClD,EAAA,KAAA,CAAM,QAAA,CAAS;AAAA,IACb,UAAU,KAAA,CAAM,QAAA;AAAA,IAChB,iBAAiB,KAAA,CAAM,eAAA;AAAA,IACvB,WAAW,KAAA,CAAM;AAAA,GAClB,CAAA;AACD,EAAA,OAAO,eAAA,CAAgB,MAAA,EAAQ,KAAA,EAAO,IAAI,CAAA;AAC5C;AAMA,eAAsB,qBAAA,CACpB,QACA,IAAA,EACuE;AACvE,EAAA,IAAI,GAAA;AACJ,EAAA,IAAI;AACF,IAAA,GAAA,GAAM,MAAM,IAAA,CAAK,KAAA,CAAM,MAAA,CAAO,sBAAA,EAAwB;AAAA,MACpD,MAAA,EAAQ,MAAA;AAAA,MACR,OAAA,EAAS,EAAE,cAAA,EAAgB,kBAAA,EAAoB,QAAQ,kBAAA,EAAmB;AAAA,MAC1E,MAAM,IAAA,CAAK,SAAA,CAAU,EAAE,SAAA,EAAW,MAAA,CAAO,UAAU;AAAA,KACpD,CAAA;AAAA,EACH,SAAS,GAAA,EAAK;AACZ,IAAA,MAAM,IAAI,iBAAA;AAAA,MACR,mCAAA;AAAA,MACA,CAAA,yBAAA,EAA6B,IAAc,OAAO,CAAA;AAAA,KACpD;AAAA,EACF;AACA,EAAA,IAAI,CAAC,IAAI,EAAA,EAAI;AACX,IAAA,MAAM,IAAI,iBAAA;AAAA,MACR,mCAAA;AAAA,MACA,CAAA,gCAAA,EAAmC,IAAI,MAAM,CAAA;AAAA,KAC/C;AAAA,EACF;AACA,EAAA,MAAM,IAAA,GAAQ,MAAM,GAAA,CAAI,IAAA,EAAK;AAK7B,EAAA,IAAI,OAAO,IAAA,CAAK,cAAA,KAAmB,YAAY,OAAO,IAAA,CAAK,cAAc,QAAA,EAAU;AACjF,IAAA,MAAM,IAAI,iBAAA;AAAA,MACR,mCAAA;AAAA,MACA;AAAA,KACF;AAAA,EACF;AACA,EAAA,MAAM,WAAW,IAAA,CAAK,GAAA;AAAA,IACpB,OAAO,KAAK,QAAA,KAAa,QAAA,GAAW,SAAS,IAAA,CAAK,QAAA,EAAU,EAAE,CAAA,IAAK,CAAA,GAAI,CAAA;AAAA,IACvE;AAAA,GACF;AACA,EAAA,OAAO,EAAE,YAAA,EAAc,IAAA,CAAK,gBAAgB,QAAA,EAAU,IAAA,CAAK,WAAW,QAAA,EAAS;AACjF;AAOA,eAAsB,iBAAA,CACpB,MAAA,EACA,IAAA,EACA,KAAA,EACsB;AACtB,EAAA,MAAM,EAAE,cAAc,QAAA,EAAU,QAAA,KAAa,MAAM,qBAAA,CAAsB,QAAQ,IAAI,CAAA;AACrF,EAAA,KAAA,CAAM,SAAS,EAAE,QAAA,EAAU,eAAA,EAAiB,MAAA,CAAO,iBAAiB,CAAA;AAEpE,EAAA,MAAM,aAAa,QAAA,GAAW,GAAA;AAE9B,EAAA,MAAM,QAAA,GAAW,IAAA,CAAK,GAAA,EAAI,GAAI,KAAK,EAAA,GAAK,GAAA;AACxC,EAAA,OAAO,IAAA,CAAK,GAAA,EAAI,GAAI,QAAA,EAAU;AAC5B,IAAA,IAAI,GAAA;AACJ,IAAA,IAAI;AACF,MAAA,GAAA,GAAM,MAAM,IAAA,CAAK,KAAA,CAAM,MAAA,CAAO,kBAAA,EAAoB;AAAA,QAChD,MAAA,EAAQ,MAAA;AAAA,QACR,OAAA,EAAS,EAAE,cAAA,EAAgB,kBAAA,EAAoB,QAAQ,kBAAA,EAAmB;AAAA,QAC1E,IAAA,EAAM,KAAK,SAAA,CAAU,EAAE,gBAAgB,YAAA,EAAc,SAAA,EAAW,UAAU;AAAA,OAC3E,CAAA;AAAA,IACH,SAAS,GAAA,EAAK;AACZ,MAAA,MAAM,IAAI,iBAAA;AAAA,QACR,6BAAA;AAAA,QACA,CAAA,oBAAA,EAAwB,IAAc,OAAO,CAAA;AAAA,OAC/C;AAAA,IACF;AACA,IAAA,IAAI,IAAI,EAAA,EAAI;AACV,MAAA,MAAM,IAAA,GAAQ,MAAM,GAAA,CAAI,IAAA,EAAK;AAI7B,MAAA,IAAI,OAAO,IAAA,CAAK,kBAAA,KAAuB,YAAY,OAAO,IAAA,CAAK,kBAAkB,QAAA,EAAU;AACzF,QAAA,MAAM,IAAI,iBAAA;AAAA,UACR,6BAAA;AAAA,UACA;AAAA,SACF;AAAA,MACF;AACA,MAAA,OAAO,YAAA;AAAA,QACL,MAAA;AAAA,QACA,EAAE,IAAA,EAAM,IAAA,CAAK,kBAAA,EAAoB,QAAA,EAAU,KAAK,aAAA,EAAc;AAAA,QAC9D;AAAA,OACF;AAAA,IACF;AAEA,IAAA,IAAI,GAAA,CAAI,MAAA,KAAW,GAAA,IAAO,GAAA,CAAI,WAAW,GAAA,EAAK;AAC5C,MAAA,MAAM,IAAI,iBAAA;AAAA,QACR,6BAAA;AAAA,QACA,CAAA,0BAAA,EAA6B,IAAI,MAAM,CAAA;AAAA,OACzC;AAAA,IACF;AACA,IAAA,MAAM,IAAA,CAAK,KAAA,CAAM,UAAA,GAAa,wBAAwB,CAAA;AAAA,EACxD;AACA,EAAA,MAAM,IAAI,iBAAA;AAAA,IACR,2BAAA;AAAA,IACA;AAAA,GACF;AACF;AAUO,SAAS,eAAe,KAAA,EAA0C;AACvE,EAAA,MAAM,KAAA,GAAQ,KAAA,CAAM,KAAA,CAAM,GAAG,CAAA;AAC7B,EAAA,IAAI,KAAA,CAAM,MAAA,KAAW,CAAA,EAAG,OAAO,MAAA;AAC/B,EAAA,IAAI;AACF,IAAA,OAAO,IAAA,CAAK,KAAA,CAAM,MAAA,CAAO,IAAA,CAAK,KAAA,CAAM,CAAC,CAAA,EAAa,WAAW,CAAA,CAAE,QAAA,EAAU,CAAA;AAAA,EAC3E,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,MAAA;AAAA,EACT;AACF;AAGO,SAAS,iBAAiB,MAAA,EAGV;AACrB,EAAA,KAAA,MAAW,SAAS,CAAC,MAAA,CAAO,QAAA,EAAU,MAAA,CAAO,YAAY,CAAA,EAAG;AAC1D,IAAA,IAAI,UAAU,MAAA,EAAW;AACzB,IAAA,MAAM,MAAA,GAAS,eAAe,KAAK,CAAA;AACnC,IAAA,MAAM,EAAA,GACJ,MAAA,EAAQ,kBAAA,IACR,MAAA,GAAS,6BAA6B,GAAG,kBAAA,IACzC,MAAA,EAAQ,aAAA,GAAgB,CAAC,CAAA,EAAG,EAAA;AAC9B,IAAA,IAAI,EAAA,KAAO,QAAW,OAAO,EAAA;AAAA,EAC/B;AACA,EAAA,OAAO,MAAA;AACT;;;AChTA,eAAe,YAAA,CACb,MAAA,EACA,IAAA,EACA,IAAA,EACA,GAAA,EACyC;AACzC,EAAA,IAAI,MAAA,CAAO,QAAA,KAAa,IAAA,CAAK,QAAA,EAAU,OAAO,MAAA;AAC9C,EAAA,MAAM,IAAA,GAA2B;AAAA,IAC/B,IAAA,EAAM,OAAA;AAAA,IACN,UAAU,IAAA,CAAK,QAAA;AAAA,IACf,QAAQ,MAAA,CAAO,MAAA;AAAA,IACf,MAAA,EAAQ,IAAA;AAAA,IACR,QAAA,EAAU,KAAA;AAAA,IACV,WAAW,MAAA,CAAO;AAAA,GACpB;AACA,EAAA,IAAI,IAAA,CAAK,KAAA,KAAU,MAAA,EAAW,OAAO,IAAA;AACrC,EAAA,MAAM,IAAA,GAAiB;AAAA,IACrB,KAAA,EAAO,IAAA,CAAK,IAAA,EAAM,KAAA,IAAS,KAAA;AAAA,IAC3B,KAAK,IAAA,CAAK,IAAA,EAAM,GAAA,KAAQ,MAAM,KAAK,GAAA,EAAI;AAAA,GACzC;AACA,EAAA,OAAO,qBAAA,CAAsB,IAAA,EAAM,EAAE,MAAA,EAAQ,IAAA,CAAK,KAAA,EAAO,KAAA,EAAO,IAAA,CAAK,KAAA,EAAO,GAAA,EAAI,EAAG,IAAI,CAAA;AACzF;AAEA,eAAsB,kBACpB,IAAA,EACyC;AACzC,EAAA,MAAM,GAAA,GAAM,IAAA,CAAK,GAAA,IAAO,EAAC;AACzB,EAAA,MAAM,MAAA,GAAS,YAAA,CAAa,IAAA,CAAK,KAAA,EAAO,GAAG,CAAA;AAC3C,EAAA,IAAI,MAAA,KAAW,QAAW,OAAO,MAAA;AAEjC,EAAA,MAAM,IAAA,GAAO,YAAA,CAAa,IAAA,CAAK,KAAA,EAAO,GAAG,CAAA;AAEzC,EAAA,IAAI,MAAA,CAAO,SAAS,OAAA,EAAS;AAC3B,IAAA,OAAO,YAAA,CAAa,MAAA,EAAQ,IAAA,EAAM,IAAA,EAAM,GAAG,CAAA;AAAA,EAC7C;AAOA,EAAA,IAAI,MAAA,CAAO,OAAA,CAAQ,MAAA,KAAW,CAAA,EAAG,OAAO,MAAA;AACxC,EAAA,IAAI,MAAA,CAAO,QAAA,KAAa,IAAA,CAAK,QAAA,EAAU,OAAO,MAAA;AAC9C,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,KAAA;AAAA,IACN,UAAU,IAAA,CAAK,QAAA;AAAA,IACf,QAAQ,MAAA,CAAO,OAAA;AAAA,IACf,MAAA,EAAQ,IAAA;AAAA,IACR,QAAA,EAAU;AAAA,GACZ;AACF","file":"index.js","sourcesContent":["import { randomBytes } from \"node:crypto\";\nimport {\n chmodSync,\n closeSync,\n fsyncSync,\n mkdirSync,\n openSync,\n readFileSync,\n renameSync,\n statSync,\n unlinkSync,\n writeFileSync,\n} from \"node:fs\";\nimport { join } from \"node:path\";\n\nimport { z } from \"zod\";\n\n/**\n * M42 — the SDK credential store. Promoted DOWN from agent-builder's hardened `agents/lib/credentials.ts`\n * (M37), generalized from a closed `openrouter|anthropic|openai` union to an open `provider: string` and\n * driven by a caller-supplied {@link CredentialStoreConfig} (no hardcoded `.agent-builder`/`auth.json` /\n * `AGENT_BUILDER_HOME`). The security-critical file mechanics are ported VERBATIM (ADR D3 of the M42 plan):\n * atomic O_EXCL + rename + fsync write, 0700/0600 mode gates, `env` is always a PARAMETER (never an ambient\n * `process.env` read). Contract SHAPE adapted from OpenCode's provider `auth.loader` (MIT © 2025 opencode).\n *\n * The env-precedence + key-prefix-inference + declared-provider rungs of the agent-builder resolver are\n * APP POLICY and deliberately stay UP in the consumer; this module owns only the on-disk store + the\n * `api|oauth` discriminated union. See {@link resolveCredential} (SDK) for the store-read + refresh path.\n *\n * @internal\n */\nimport type {\n CredentialStoreConfig,\n StoredCredential,\n StoredOAuthCredential,\n} from \"./auth-types.js\";\n\n/** The store directory, honoring an optional `homeEnvVar` override. */\nexport function credentialHome(\n config: CredentialStoreConfig,\n env: Record<string, string | undefined> = {},\n): string {\n const override = config.homeEnvVar !== undefined ? env[config.homeEnvVar]?.trim() : undefined;\n return override !== undefined && override.length > 0\n ? override\n : join(config.home, config.dirName);\n}\n\n/** The credential file path inside the (possibly overridden) store directory. */\nexport function authFilePath(\n config: CredentialStoreConfig,\n env: Record<string, string | undefined> = {},\n): string {\n return join(credentialHome(config, env), config.fileName);\n}\n\n/** A credential problem the caller can act on. Never carries the key value. */\nexport class CredentialError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"CredentialError\";\n }\n}\n\n/**\n * The on-disk store — a discriminated union on `type` (OpenCode `Info` shape). A legacy file with NO\n * `type` (or `type: 'api'`) is the API-key variant — read unchanged, no migration. The `oauth` variant\n * carries the token pair + expiry.\n */\nconst apiFileSchema = z\n .object({\n type: z.literal(\"api\").optional(),\n provider: z.string().min(1).optional(),\n api_key: z.string(),\n })\n .strict();\n\nconst oauthFileSchema = z\n .object({\n type: z.literal(\"oauth\"),\n provider: z.string().min(1),\n access: z.string().min(1),\n refresh: z.string().min(1),\n expires: z.number(),\n account_id: z.string().optional(),\n })\n .strict();\n\n// oauth first (it requires `type: 'oauth'`); a legacy `{provider?, api_key}` falls through to api.\nconst fileSchema = z.union([oauthFileSchema, apiFileSchema]);\n\n/**\n * Read the credential file. Absent ⇒ `undefined` (the normal case). Present-but-wrong is a typed error\n * naming the file: a malformed credential store must not surface as a raw parse crash. Enforces the\n * 0700 dir / 0600 file mode gates (ported verbatim — a writable dir lets an attacker swap the file for a\n * symlink to their own account).\n */\n/**\n * The 0700-dir / 0600-file mode gates (ported verbatim). The DIRECTORY matters as much as the file:\n * `mkdirSync(mode)` applies only at creation, so a pre-existing store dir keeps whatever mode it had, and a\n * writable dir lets an attacker replace the credential file with a symlink to their own 0600 file — the\n * agent then runs on THEIR account.\n */\nfunction assertSecureModes(dirPath: string, path: string): void {\n const dirMode = statSync(dirPath).mode & 0o777;\n if ((dirMode & 0o022) !== 0) {\n throw new CredentialError(\n `${dirPath} is writable by other users (mode ${dirMode.toString(8)}), so the credential file ` +\n `inside it can be replaced. Fix it with: chmod 700 ${dirPath}`,\n );\n }\n const mode = statSync(path).mode & 0o777;\n if ((mode & 0o077) !== 0) {\n throw new CredentialError(\n `${path} is readable by other users (mode ${mode.toString(8)}). ` +\n `A credential file must not be. Fix it with: chmod 600 ${path}`,\n );\n }\n}\n\n/**\n * A `z.union` reports a generic \"Invalid input\" at the root, hiding WHAT is wrong. Pick the sub-schema the\n * file was CLEARLY aiming at (by its `type` discriminant) and surface that schema's specific issue.\n */\nfunction describeUnionError(parsed: unknown, err: unknown, path: string): CredentialError {\n const looksOAuth =\n typeof parsed === \"object\" &&\n parsed !== null &&\n (parsed as { type?: unknown }).type === \"oauth\";\n const specific = looksOAuth ? oauthFileSchema.safeParse(parsed) : apiFileSchema.safeParse(parsed);\n let issue: z.ZodIssue | undefined;\n if (!specific.success) {\n issue = specific.error.issues[0];\n } else if (err instanceof z.ZodError) {\n issue = err.issues[0];\n }\n return new CredentialError(\n `${path}: ${issue?.message ?? String(err)} [${issue?.path.join(\".\") || \"root\"}]`,\n );\n}\n\n/** Parse the raw file into the store union, surfacing the SPECIFIC sub-schema issue (not a generic union error). */\nfunction parseStoredFile(raw: string, path: string): StoredCredential {\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n // The parser's message embeds a snippet of the INPUT — up to the raw key when a user pastes the bare\n // key instead of JSON. The position is not actionable anyway, so the expected shape is more useful.\n throw new CredentialError(\n `${path} is not valid JSON. Expected: {\"provider\": \"<name>\", \"api_key\": \"...\"}`,\n );\n }\n try {\n return fileSchema.parse(parsed);\n } catch (err) {\n throw describeUnionError(parsed, err, path);\n }\n}\n\nexport function readAuthFile(\n config: CredentialStoreConfig,\n env: Record<string, string | undefined> = {},\n): StoredCredential | undefined {\n const path = authFilePath(config, env);\n\n let raw: string;\n try {\n raw = readFileSync(path, \"utf8\");\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") return undefined;\n throw new CredentialError(`cannot read ${path}: ${(err as Error).message}`);\n }\n\n assertSecureModes(credentialHome(config, env), path);\n return parseStoredFile(raw, path);\n}\n\n/**\n * Read the stored OAuth credential (with its refresh token), or `undefined` when the store is absent or\n * holds an api credential. The oauth engine needs the refresh token, which the resolved bearer does not\n * carry. Enforces the same 0600/0700 gates as every other read.\n */\nexport function readStoredOAuth(\n config: CredentialStoreConfig,\n env: Record<string, string | undefined> = {},\n): StoredOAuthCredential | undefined {\n const stored = readAuthFile(config, env);\n return stored !== undefined && stored.type === \"oauth\" ? stored : undefined;\n}\n\n/** Narrows a writable credential to the oauth variant. */\nfunction isOAuthWrite(\n c: { provider: string; apiKey: string } | StoredOAuthCredential,\n): c is StoredOAuthCredential {\n return \"type\" in c && c.type === \"oauth\";\n}\n\n/**\n * Persist a credential atomically at mode `0600`. Ported VERBATIM (ADR D3): write to a random-named temp\n * file in the same directory with `wx` (O_EXCL), fsync, close, chmod, then `rename` (atomic on POSIX) —\n * so a crash mid-write leaves whatever was there untouched, and a pre-planted symlink cannot capture the\n * key. The api variant persists the unchanged `{provider, api_key}` (back-compat, no `type` key); the\n * oauth variant persists `{type:'oauth', provider, access, refresh, expires, account_id?}`.\n */\n/** Build the on-disk JSON payload for the credential variant, validating non-empty tokens. */\nfunction buildStorePayload(\n cred: { provider: string; apiKey: string } | StoredOAuthCredential,\n): Record<string, unknown> {\n if (isOAuthWrite(cred)) {\n if (cred.access.length === 0 || cred.refresh.length === 0) {\n throw new CredentialError(\n \"refusing to write an oauth credential with an empty access/refresh token\",\n );\n }\n return {\n type: \"oauth\",\n provider: cred.provider,\n access: cred.access,\n refresh: cred.refresh,\n expires: cred.expires,\n ...(cred.account_id !== undefined ? { account_id: cred.account_id } : {}),\n };\n }\n if (typeof cred.apiKey !== \"string\" || cred.apiKey.length === 0) {\n throw new CredentialError(\"refusing to write an empty API key\");\n }\n return { provider: cred.provider, api_key: cred.apiKey };\n}\n\nexport function writeCredential(\n cred: { provider: string; apiKey: string } | StoredOAuthCredential,\n config: CredentialStoreConfig,\n env: Record<string, string | undefined> = {},\n): string {\n const payload = buildStorePayload(cred);\n\n const dir = credentialHome(config, env);\n mkdirSync(dir, { recursive: true, mode: 0o700 });\n chmodSync(dir, 0o700); // unconditional: mkdirSync's mode applies only at creation\n\n const path = authFilePath(config, env);\n // RANDOM name + `wx` (O_EXCL): a predictable temp name with a plain write follows a pre-planted SYMLINK,\n // landing the key in an attacker's file while reporting success. O_EXCL refuses any pre-existing file or\n // link; the random suffix also removes the pid collision two containers sharing a bind-mounted home make.\n const tmp = `${path}.tmp-${randomBytes(8).toString(\"hex\")}`;\n try {\n const fd = openSync(tmp, \"wx\", 0o600);\n try {\n writeFileSync(fd, `${JSON.stringify(payload, null, 2)}\\n`);\n fsyncSync(fd);\n } finally {\n closeSync(fd);\n }\n chmodSync(tmp, 0o600); // explicit: the mode argument is subject to umask\n renameSync(tmp, path);\n } catch (err) {\n try {\n unlinkSync(tmp);\n } catch {\n // the temp file may not exist; its absence is not a failure of the write\n }\n throw new CredentialError(`cannot write ${path}: ${(err as Error).message}`);\n }\n return path;\n}\n","/**\n * @theokit/sdk/server/auth — typed error classes\n *\n * Plan T1.2 + v1.1 EC-1 (AuthCancelledError for OAuth provider error response RFC 6749 §4.1.2.1).\n */\n\n/**\n * Thrown at `defineAuth()` time when configuration is invalid\n * (e.g., duplicate provider name, invalid email shape per EC-V1-12).\n */\nexport class AuthConfigError extends Error {\n override readonly name = \"AuthConfigError\";\n readonly code: string;\n\n constructor(code: string, message: string) {\n super(`[${code}] ${message}`);\n this.code = code;\n }\n}\n\n/**\n * Thrown at `startSignIn(providerName, ...)` or `finishSignIn(providerName, ...)`\n * when the named provider is not registered in `providers[]`.\n */\nexport class AuthProviderNotFoundError extends Error {\n override readonly name = \"AuthProviderNotFoundError\";\n readonly providerName: string;\n\n constructor(providerName: string) {\n super(\n `Auth provider not found: '${providerName}'. Register it in defineAuth({ providers: [...] }).`,\n );\n this.providerName = providerName;\n }\n}\n\n/**\n * Thrown during OAuth callback handling for state mismatches, expired\n * transactions, missing query params, or provider 4xx/5xx errors.\n *\n * Typed `code` field lets consumers branch on cause:\n * - 'oauth_transaction_expired' — cookie tx > 10min old (per ADR D5)\n * - 'oauth_state_mismatch' — query state ≠ cookie state (CSRF defense per RFC 6749 §10.12)\n * - 'oauth_provider_error' — non-access_denied error in callback URL\n * - 'oauth_token_exchange_failed' — provider rejected code-for-tokens swap\n * - 'oauth_userinfo_failed' — userinfo endpoint returned error\n * - 'oauth_missing_code_or_state' — required query params absent\n */\nexport class AuthCallbackError extends Error {\n override readonly name: string = \"AuthCallbackError\";\n readonly code: string;\n\n constructor(code: string, message?: string) {\n super(message ?? `OAuth callback error: ${code}`);\n this.code = code;\n }\n}\n\n/**\n * Per v1.1 EC-1 MUST FIX — typed subclass of AuthCallbackError for the\n * specific case where user declined consent at provider screen.\n *\n * OAuth 2.0 RFC 6749 §4.1.2.1: provider redirects with `?error=access_denied`.\n * Apps can catch this distinctly from network/server errors to render\n * \"Login cancelled — try again\" UX instead of opaque \"callback failed\".\n */\nexport class AuthCancelledError extends AuthCallbackError {\n override readonly name: string = \"AuthCancelledError\";\n readonly errorDescription?: string;\n\n constructor(errorDescription?: string) {\n super(\"user_declined_consent\", errorDescription ?? \"User declined consent at provider\");\n this.errorDescription = errorDescription;\n }\n}\n","/**\n * M42 — the SDK OAuth engine. Promoted DOWN from agent-builder's hardened `agents/lib/oauth.ts` +\n * `oauth-device.ts` (M37), generalized to `provider: string` + a caller-supplied {@link CredentialStoreConfig}\n * (no hardcoded client IDs — the caller declares its provider's endpoints). Ported VERBATIM (ADR D3): the\n * refresh coalescing lock, the no-token-in-error discipline, and the RFC 8628 device grant.\n *\n * Reuses the SDK's typed error taxonomy (`AuthCallbackError` from `server/auth`) for exchange/refresh\n * failures. All network I/O + clock + sleep are INJECTED so the flow is deterministic.\n *\n * ─── ADAPTED FROM OpenCode (MIT License, Copyright (c) 2025 opencode — https://github.com/sst/opencode) ───\n * - the device-grant poll loop (device_code → authorization_pending / slow_down) is adapted from\n * `packages/opencode/src/plugin/github-copilot/copilot.ts`;\n * - the JWT-claim / account-id extraction + the OpenAI two-step headless flow are adapted from\n * `packages/opencode/src/plugin/openai/codex.ts`.\n * The MIT license permits this reuse with attribution; this notice + the NOTICE file are that attribution.\n *\n * @internal\n */\nimport { AuthCallbackError } from \"../../server/auth/errors.js\";\n\nimport type {\n CredentialStoreConfig,\n HttpDeps,\n OAuthProviderConfig,\n OAuthTokens,\n ResolvedCredential,\n} from \"./auth-types.js\";\nimport { authFilePath, readStoredOAuth, writeCredential } from \"./credential-store.js\";\n\n/** Refresh a token this many ms BEFORE it actually expires (avoid a last-second, mid-request expiry). */\nconst REFRESH_SKEW_MS = 60_000;\n\n/** Parse an OAuth token endpoint response into our token triple. Throws a typed error on a bad shape. */\nfunction parseTokenResponse(body: unknown, now: number): OAuthTokens {\n const b = body as {\n access_token?: unknown;\n refresh_token?: unknown;\n expires_in?: unknown;\n account_id?: unknown;\n };\n if (typeof b.access_token !== \"string\" || b.access_token.length === 0) {\n throw new AuthCallbackError(\n \"oauth_token_exchange_failed\",\n \"token response had no access_token\",\n );\n }\n if (typeof b.refresh_token !== \"string\" || b.refresh_token.length === 0) {\n throw new AuthCallbackError(\n \"oauth_token_exchange_failed\",\n \"token response had no refresh_token\",\n );\n }\n const expiresIn = typeof b.expires_in === \"number\" ? b.expires_in : 3600;\n return {\n access: b.access_token,\n refresh: b.refresh_token,\n expires: now + expiresIn * 1000,\n ...(typeof b.account_id === \"string\" ? { accountId: b.account_id } : {}),\n };\n}\n\n/** POST a form-encoded grant to the token endpoint; return the parsed JSON or throw a typed error. */\nasync function postGrant(\n config: OAuthProviderConfig,\n form: Record<string, string>,\n deps: HttpDeps,\n): Promise<OAuthTokens> {\n let res: Response;\n try {\n res = await deps.fetch(config.tokenEndpoint, {\n method: \"POST\",\n headers: { \"content-type\": \"application/x-www-form-urlencoded\", accept: \"application/json\" },\n body: new URLSearchParams(form).toString(),\n });\n } catch (err) {\n throw new AuthCallbackError(\n \"oauth_token_exchange_failed\",\n `token endpoint request failed: ${(err as Error).message}`,\n );\n }\n if (!res.ok) {\n // The body may carry an OAuth `error` code, but never echo it verbatim — it can contain a token in\n // some providers' error payloads. Report the status only.\n throw new AuthCallbackError(\n \"oauth_token_exchange_failed\",\n `token endpoint returned HTTP ${res.status}`,\n );\n }\n let json: unknown;\n try {\n json = await res.json();\n } catch {\n // Do NOT echo the parser message — on a 200 non-JSON body it embeds a snippet of the response, which\n // in a token context can contain access/refresh material.\n throw new AuthCallbackError(\"oauth_token_exchange_failed\", \"token response was not valid JSON\");\n }\n return parseTokenResponse(json, deps.now());\n}\n\n/** Exchange an authorization `code` (+ PKCE verifier) for the token pair. */\nexport function exchangeCode(\n config: OAuthProviderConfig,\n input: { code: string; verifier: string },\n deps: HttpDeps,\n): Promise<OAuthTokens> {\n return postGrant(\n config,\n {\n grant_type: \"authorization_code\",\n code: input.code,\n redirect_uri: config.redirectUri,\n client_id: config.clientId,\n code_verifier: input.verifier,\n },\n deps,\n );\n}\n\n/** Swap a refresh token for a fresh access (and possibly rotated refresh) token. */\nexport function refreshOAuthTokens(\n config: OAuthProviderConfig,\n refresh: string,\n deps: HttpDeps,\n): Promise<OAuthTokens> {\n return postGrant(\n config,\n { grant_type: \"refresh_token\", refresh_token: refresh, client_id: config.clientId },\n deps,\n );\n}\n\n/** Persist a token triple to the store's oauth variant through the hardened 0600 writer. */\nexport function persistOAuthTokens(\n provider: string,\n tokens: OAuthTokens,\n store: CredentialStoreConfig,\n env: Record<string, string | undefined> = {},\n): string {\n return writeCredential(\n {\n type: \"oauth\",\n provider,\n access: tokens.access,\n refresh: tokens.refresh,\n expires: tokens.expires,\n ...(tokens.accountId !== undefined ? { account_id: tokens.accountId } : {}),\n },\n store,\n env,\n );\n}\n\n/**\n * In-flight refreshes, keyed by the auth-file path. Refresh tokens ROTATE (single-use) on many providers,\n * so two concurrent turns must NOT both POST the same refresh token — the second would present an\n * already-consumed token and fail. This coalesces concurrent refreshes of the same store onto one promise.\n * Process-local — the single-credential store is per-user; a cross-process lock would be over-engineering.\n */\nconst inFlightRefresh = new Map<string, Promise<OAuthTokens>>();\n\n/**\n * Return a credential guaranteed fresh enough to use. An `api` credential passes through untouched. An\n * `oauth` credential still valid (beyond the skew window) passes through; an expired one is refreshed,\n * re-persisted 0600, and returned with the new access token. Concurrent refreshes of the same store are\n * coalesced (single-use refresh tokens); the rejected promise is evicted so a failure is not cached-poison.\n */\nexport async function ensureFreshCredential(\n resolved: ResolvedCredential,\n opts: {\n config: OAuthProviderConfig;\n store: CredentialStoreConfig;\n env?: Record<string, string | undefined>;\n },\n deps: HttpDeps,\n): Promise<ResolvedCredential> {\n if (resolved.kind !== \"oauth\") return resolved;\n\n const now = deps.now();\n if (resolved.expiresAt !== undefined && resolved.expiresAt > now + REFRESH_SKEW_MS) {\n return resolved; // still valid — no network, no rewrite\n }\n\n const env = opts.env ?? {};\n const path = authFilePath(opts.store, env);\n let refresh = inFlightRefresh.get(path);\n if (refresh === undefined) {\n refresh = (async (): Promise<OAuthTokens> => {\n const stored = readStoredOAuth(opts.store, env);\n if (stored === undefined) {\n // The resolved credential said oauth but the store no longer holds it — do not fabricate; surface it.\n throw new AuthCallbackError(\n \"oauth_token_exchange_failed\",\n \"no stored oauth credential to refresh\",\n );\n }\n const fresh = await refreshOAuthTokens(opts.config, stored.refresh, deps);\n persistOAuthTokens(resolved.provider, fresh, opts.store, env);\n return fresh;\n })();\n inFlightRefresh.set(path, refresh);\n refresh.finally(() => inFlightRefresh.delete(path)).catch(() => {});\n }\n\n const fresh = await refresh;\n return {\n kind: \"oauth\",\n provider: resolved.provider,\n apiKey: fresh.access,\n source: resolved.source,\n inferred: false,\n expiresAt: fresh.expires,\n };\n}\n","/**\n * M42 — the SDK OAuth device-authorization flows (RFC 8628 + OpenAI two-step headless). Split out of\n * oauth-engine.ts to respect the 500-line file budget; a sibling of the core engine. Promoted DOWN from\n * agent-builder's hardened `agents/lib/oauth-device.ts` (M37).\n *\n * ─── ADAPTED FROM OpenCode (MIT License, Copyright (c) 2025 opencode — https://github.com/sst/opencode) ───\n * - the device-grant poll loop (device_code → authorization_pending / slow_down) is adapted from\n * `packages/opencode/src/plugin/github-copilot/copilot.ts`;\n * - the JWT-claim / account-id extraction + the OpenAI two-step headless flow are adapted from\n * `packages/opencode/src/plugin/openai/codex.ts`.\n * The MIT license permits this reuse with attribution; this notice + the NOTICE file are that attribution.\n * Adaptations: network I/O + clock + sleep are INJECTED (deterministic tests), failures raise the SDK's\n * typed `AuthCallbackError`, and a device-code expiry DEADLINE guards each poll loop (upstream loops unbounded).\n *\n * @internal\n */\nimport { AuthCallbackError } from \"../../server/auth/errors.js\";\n\nimport type {\n DeviceCodeGrant,\n DeviceDeps,\n DeviceOAuthConfig,\n OAuthTokens,\n OpenAIDeviceConfig,\n} from \"./auth-types.js\";\nimport { exchangeCode } from \"./oauth-engine.js\";\n\n// ─── OAuth 2.0 Device Authorization Grant (RFC 8628) — terminal-first / headless login ───\n\n/** Buffer added to every poll interval to avoid hitting the server a hair early (from OpenCode). */\nconst POLLING_SAFETY_MARGIN_MS = 3000;\n\n/** Step 1 — request a device code. POSTs `{client_id, scope}` to the device endpoint. */\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: RFC 8628 device-code request — cohesive network response parser ported verbatim (ADR D3).\nexport async function requestDeviceCode(\n config: DeviceOAuthConfig,\n deps: Pick<DeviceDeps, \"fetch\">,\n): Promise<DeviceCodeGrant> {\n let res: Response;\n try {\n res = await deps.fetch(config.deviceCodeEndpoint, {\n method: \"POST\",\n headers: { \"content-type\": \"application/x-www-form-urlencoded\", accept: \"application/json\" },\n body: new URLSearchParams({\n client_id: config.clientId,\n scope: config.scopes.join(\" \"),\n }).toString(),\n });\n } catch (err) {\n throw new AuthCallbackError(\n \"oauth_device_authorization_failed\",\n `device request failed: ${(err as Error).message}`,\n );\n }\n if (!res.ok) {\n throw new AuthCallbackError(\n \"oauth_device_authorization_failed\",\n `device endpoint returned HTTP ${res.status}`,\n );\n }\n const data = (await res.json()) as {\n device_code?: unknown;\n user_code?: unknown;\n verification_uri?: unknown;\n verification_uri_complete?: unknown;\n interval?: unknown;\n expires_in?: unknown;\n };\n if (typeof data.device_code !== \"string\" || typeof data.user_code !== \"string\") {\n throw new AuthCallbackError(\n \"oauth_device_authorization_failed\",\n \"device response missing device_code/user_code\",\n );\n }\n const verification =\n typeof data.verification_uri === \"string\"\n ? data.verification_uri\n : typeof data.verification_uri_complete === \"string\"\n ? data.verification_uri_complete\n : \"\";\n return {\n deviceCode: data.device_code,\n userCode: data.user_code,\n verificationUri: verification,\n interval: typeof data.interval === \"number\" && data.interval > 0 ? data.interval : 5,\n expiresIn: typeof data.expires_in === \"number\" && data.expires_in > 0 ? data.expires_in : 900,\n };\n}\n\n/**\n * Step 2 — poll the token endpoint until the user approves (or the code expires). Handles RFC 8628\n * `authorization_pending` (keep waiting) and `slow_down` (back off), with an expiry deadline so it cannot\n * spin forever.\n */\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: RFC 8628 poll state machine (authorization_pending / slow_down / success / expiry) — a cohesive loop ported verbatim (ADR D3); fragmenting it would obscure the protocol.\nexport async function pollDeviceToken(\n config: DeviceOAuthConfig,\n grant: DeviceCodeGrant,\n deps: DeviceDeps,\n): Promise<OAuthTokens> {\n const deadline = deps.now() + grant.expiresIn * 1000;\n let intervalMs = grant.interval * 1000;\n\n while (deps.now() < deadline) {\n let res: Response;\n try {\n res = await deps.fetch(config.tokenEndpoint, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/x-www-form-urlencoded\",\n accept: \"application/json\",\n },\n body: new URLSearchParams({\n client_id: config.clientId,\n device_code: grant.deviceCode,\n grant_type: \"urn:ietf:params:oauth:grant-type:device_code\",\n }).toString(),\n });\n } catch (err) {\n throw new AuthCallbackError(\n \"oauth_token_exchange_failed\",\n `device token poll failed: ${(err as Error).message}`,\n );\n }\n // RFC 8628 §3.5: `authorization_pending` / `slow_down` arrive as a 400 with an `error` body — so the\n // body MUST be read before deciding failure. Parse first; only a non-OAuth-shaped body on a non-2xx fails.\n const data = (await res.json().catch(() => ({}))) as {\n access_token?: string;\n refresh_token?: string;\n expires_in?: number;\n id_token?: string;\n error?: string;\n interval?: number;\n };\n if (!res.ok && typeof data.error !== \"string\") {\n throw new AuthCallbackError(\n \"oauth_token_exchange_failed\",\n `device token endpoint returned HTTP ${res.status}`,\n );\n }\n\n if (typeof data.access_token === \"string\" && data.access_token.length > 0) {\n const expiresIn = typeof data.expires_in === \"number\" ? data.expires_in : 0;\n const accountId = extractAccountId({\n access_token: data.access_token,\n id_token: data.id_token,\n });\n return {\n access: data.access_token,\n // Some device-grant providers (e.g. GitHub) issue no separate refresh token — reuse the access\n // token as the refresh handle, mirroring OpenCode's copilot flow.\n refresh: data.refresh_token ?? data.access_token,\n expires: deps.now() + expiresIn * 1000,\n ...(accountId !== undefined ? { accountId } : {}),\n };\n }\n\n if (data.error === \"authorization_pending\") {\n await deps.sleep(intervalMs + POLLING_SAFETY_MARGIN_MS);\n continue;\n }\n if (data.error === \"slow_down\") {\n // RFC 8628 §3.5: add 5s to the interval, or honor a server-provided one.\n intervalMs =\n (typeof data.interval === \"number\" && data.interval > 0\n ? data.interval\n : grant.interval + 5) * 1000;\n await deps.sleep(intervalMs + POLLING_SAFETY_MARGIN_MS);\n continue;\n }\n if (typeof data.error === \"string\") {\n throw new AuthCallbackError(\n \"oauth_token_exchange_failed\",\n `device authorization rejected: ${data.error}`,\n );\n }\n await deps.sleep(intervalMs + POLLING_SAFETY_MARGIN_MS);\n }\n throw new AuthCallbackError(\n \"oauth_device_code_expired\",\n \"the device code expired before it was approved\",\n );\n}\n\n/**\n * The full device login: request a code, hand the user the verification URL + user code via `onPrompt`\n * (never printed here — the caller renders it, keeping this module output-free), then poll to completion.\n */\nexport async function deviceLogin(\n config: DeviceOAuthConfig,\n deps: DeviceDeps,\n hooks: {\n onPrompt: (p: { userCode: string; verificationUri: string; expiresIn: number }) => void;\n },\n): Promise<OAuthTokens> {\n const grant = await requestDeviceCode(config, deps);\n hooks.onPrompt({\n userCode: grant.userCode,\n verificationUri: grant.verificationUri,\n expiresIn: grant.expiresIn,\n });\n return pollDeviceToken(config, grant, deps);\n}\n\n// ─── OpenAI / ChatGPT \"headless\" device flow (two-step; ADAPTED FROM OpenCode codex.ts, MIT © 2025) ───\n\n/** The OpenAI two-step device config: usercode + poll endpoints return an authorization_code (not tokens). */\n/** Step 1 (OpenAI) — request the user code. */\nexport async function requestOpenAIUsercode(\n config: OpenAIDeviceConfig,\n deps: Pick<DeviceDeps, \"fetch\">,\n): Promise<{ deviceAuthId: string; userCode: string; interval: number }> {\n let res: Response;\n try {\n res = await deps.fetch(config.deviceUsercodeEndpoint, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\", accept: \"application/json\" },\n body: JSON.stringify({ client_id: config.clientId }),\n });\n } catch (err) {\n throw new AuthCallbackError(\n \"oauth_device_authorization_failed\",\n `usercode request failed: ${(err as Error).message}`,\n );\n }\n if (!res.ok) {\n throw new AuthCallbackError(\n \"oauth_device_authorization_failed\",\n `usercode endpoint returned HTTP ${res.status}`,\n );\n }\n const data = (await res.json()) as {\n device_auth_id?: unknown;\n user_code?: unknown;\n interval?: unknown;\n };\n if (typeof data.device_auth_id !== \"string\" || typeof data.user_code !== \"string\") {\n throw new AuthCallbackError(\n \"oauth_device_authorization_failed\",\n \"usercode response missing device_auth_id/user_code\",\n );\n }\n const interval = Math.max(\n typeof data.interval === \"string\" ? parseInt(data.interval, 10) || 5 : 5,\n 1,\n );\n return { deviceAuthId: data.device_auth_id, userCode: data.user_code, interval };\n}\n\n/**\n * Step 2+3 (OpenAI) — poll for the authorization code (200 = ready; 403/404 = pending; else fail), then\n * exchange it for tokens at the standard `/oauth/token` endpoint (reuses `exchangeCode`).\n */\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: OpenAI two-step headless poll loop (200 ready / 403,404 pending / else fail) — cohesive network state machine ported verbatim (ADR D3).\nexport async function openaiDeviceLogin(\n config: OpenAIDeviceConfig,\n deps: DeviceDeps,\n hooks: { onPrompt: (p: { userCode: string; verificationUri: string }) => void },\n): Promise<OAuthTokens> {\n const { deviceAuthId, userCode, interval } = await requestOpenAIUsercode(config, deps);\n hooks.onPrompt({ userCode, verificationUri: config.verificationUri });\n\n const intervalMs = interval * 1000;\n // Bound the loop so it cannot spin forever if the provider never resolves (upstream loops unbounded).\n const deadline = deps.now() + 15 * 60 * 1000;\n while (deps.now() < deadline) {\n let res: Response;\n try {\n res = await deps.fetch(config.devicePollEndpoint, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\", accept: \"application/json\" },\n body: JSON.stringify({ device_auth_id: deviceAuthId, user_code: userCode }),\n });\n } catch (err) {\n throw new AuthCallbackError(\n \"oauth_token_exchange_failed\",\n `device poll failed: ${(err as Error).message}`,\n );\n }\n if (res.ok) {\n const data = (await res.json()) as {\n authorization_code?: unknown;\n code_verifier?: unknown;\n };\n if (typeof data.authorization_code !== \"string\" || typeof data.code_verifier !== \"string\") {\n throw new AuthCallbackError(\n \"oauth_token_exchange_failed\",\n \"device poll returned no authorization_code\",\n );\n }\n return exchangeCode(\n config,\n { code: data.authorization_code, verifier: data.code_verifier },\n deps,\n );\n }\n // 403/404 = still pending (user has not approved yet); anything else is a hard failure.\n if (res.status !== 403 && res.status !== 404) {\n throw new AuthCallbackError(\n \"oauth_token_exchange_failed\",\n `device poll returned HTTP ${res.status}`,\n );\n }\n await deps.sleep(intervalMs + POLLING_SAFETY_MARGIN_MS);\n }\n throw new AuthCallbackError(\n \"oauth_device_code_expired\",\n \"the device authorization expired before approval\",\n );\n}\n\n/** JWT id/access-token claims we read to attribute an account. Adapted from OpenCode's codex plugin. */\ninterface IdTokenClaims {\n chatgpt_account_id?: string;\n organizations?: Array<{ id: string }>;\n \"https://api.openai.com/auth\"?: { chatgpt_account_id?: string };\n}\n\n/** Decode a JWT's claim set (no signature verification — used only to read a self-reported account id). */\nexport function parseJwtClaims(token: string): IdTokenClaims | undefined {\n const parts = token.split(\".\");\n if (parts.length !== 3) return undefined;\n try {\n return JSON.parse(Buffer.from(parts[1] as string, \"base64url\").toString()) as IdTokenClaims;\n } catch {\n return undefined;\n }\n}\n\n/** Best-effort account id from an id/access token's claims (OpenAI/ChatGPT shape). Adapted from OpenCode. */\nexport function extractAccountId(tokens: {\n id_token?: string;\n access_token?: string;\n}): string | undefined {\n for (const token of [tokens.id_token, tokens.access_token]) {\n if (token === undefined) continue;\n const claims = parseJwtClaims(token);\n const id =\n claims?.chatgpt_account_id ??\n claims?.[\"https://api.openai.com/auth\"]?.chatgpt_account_id ??\n claims?.organizations?.[0]?.id;\n if (id !== undefined) return id;\n }\n return undefined;\n}\n","/**\n * M42 — `resolveCredential`: the public composition entrypoint over the credential store + oauth engine.\n * Given a provider name + a {@link CredentialStoreConfig} (and, for oauth, an {@link OAuthProviderConfig}),\n * read the store and return a FRESH `ResolvedCredential` — an api credential passes through by identity; an\n * oauth credential is transparently refreshed when its access token is within the skew window. Returns\n * `undefined` when the store holds no credential for `provider` (the caller then falls back to env / apiKeys).\n *\n * Mirrors agent-builder's `resolveFreshCredential` composition (store read → oauth → ensureFreshCredential),\n * defaulting `fetch`/`now` to globals. This is the async surface an oauth provider's M41 `transform.fetch`\n * calls at stream time, so a mid-turn token expiry refreshes without rebuilding the agent.\n *\n * @internal (re-exported from the package barrel as public)\n */\nimport type {\n CredentialStoreConfig,\n HttpDeps,\n OAuthProviderConfig,\n ResolvedCredential,\n} from \"./auth-types.js\";\nimport { authFilePath, readAuthFile } from \"./credential-store.js\";\nimport { ensureFreshCredential } from \"./oauth-engine.js\";\n\nexport interface ResolveCredentialOptions {\n /** The provider whose stored credential to resolve. */\n provider: string;\n /** Where the credential store lives. */\n store: CredentialStoreConfig;\n /** Env for the store's optional `homeEnvVar` override. Never an ambient read. */\n env?: Record<string, string | undefined>;\n /** Required to refresh an oauth credential; omit for an api-only store. */\n oauth?: OAuthProviderConfig;\n /** Injected HTTP + clock for deterministic tests; default globals. */\n deps?: { fetch?: typeof fetch; now?: () => number };\n}\n\n/**\n * Resolve a fresh credential for `provider` from the store, or `undefined` if the store holds none for it.\n * oauth credentials are auto-refreshed when `opts.oauth` is supplied; api credentials pass through.\n */\n/** Resolve (and, when a config is supplied, refresh) the oauth variant for the requested provider. */\nasync function resolveOAuth(\n stored: { provider: string; access: string; expires: number },\n path: string,\n opts: ResolveCredentialOptions,\n env: Record<string, string | undefined>,\n): Promise<ResolvedCredential | undefined> {\n if (stored.provider !== opts.provider) return undefined;\n const base: ResolvedCredential = {\n kind: \"oauth\",\n provider: opts.provider,\n apiKey: stored.access,\n source: path,\n inferred: false,\n expiresAt: stored.expires,\n };\n if (opts.oauth === undefined) return base; // no config to refresh with — return the stored access token\n const deps: HttpDeps = {\n fetch: opts.deps?.fetch ?? fetch,\n now: opts.deps?.now ?? (() => Date.now()),\n };\n return ensureFreshCredential(base, { config: opts.oauth, store: opts.store, env }, deps);\n}\n\nexport async function resolveCredential(\n opts: ResolveCredentialOptions,\n): Promise<ResolvedCredential | undefined> {\n const env = opts.env ?? {};\n const stored = readAuthFile(opts.store, env);\n if (stored === undefined) return undefined;\n\n const path = authFilePath(opts.store, env);\n\n if (stored.type === \"oauth\") {\n return resolveOAuth(stored, path, opts, env);\n }\n\n // api variant: require the stored `provider` to MATCH the requested provider (M42 review MEDIUM-2).\n // The generic SDK cannot infer a provider from a key prefix (that was agent-builder app policy), so a\n // provider-less or mismatched stored key is NOT attributed to the requested provider — otherwise a legacy\n // `{api_key:\"sk-ant-…\"}` file could be POSTed to the wrong vendor's endpoint (cross-vendor key exposure).\n // Fail-closed, mirroring OpenCode, whose credential resolution never attributes a key across providers.\n if (stored.api_key.length === 0) return undefined;\n if (stored.provider !== opts.provider) return undefined;\n return {\n kind: \"api\",\n provider: opts.provider,\n apiKey: stored.api_key,\n source: path,\n inferred: false,\n };\n}\n"]}
package/dist/cron.cjs CHANGED
@@ -13694,6 +13694,15 @@ function selectTransport(profile, apiKey) {
13694
13694
  const ctx = { apiKey };
13695
13695
  return { fetch: profile.transform.fetch?.(ctx), headers: profile.transform.headers?.(ctx) };
13696
13696
  };
13697
+ const assertOAuthResolved = (t) => {
13698
+ if (apiKey !== "__oauth_lazy_token__") return;
13699
+ const auth = t.headers?.authorization ?? t.headers?.Authorization;
13700
+ if (t.fetch === void 0 && auth === void 0) {
13701
+ throw new ConfigurationError(
13702
+ `provider "${profile.name}" uses OAuth (authType: ${profile.authType}) but no credential was resolved. Register a ProviderProfile.transform whose fetch (or headers.authorization) supplies the bearer \u2014 typically via resolveCredential() from "@theokit/sdk/auth".`
13703
+ );
13704
+ }
13705
+ };
13697
13706
  if (profile.apiMode === "chat_completions") {
13698
13707
  if (profile.name === "ollama") {
13699
13708
  const ollamaBase = process.env.OLLAMA_HOST ?? profile.baseUrl;
@@ -13711,6 +13720,7 @@ function selectTransport(profile, apiKey) {
13711
13720
  const envOverride = resolveBaseUrlEnvOverride(profile.name);
13712
13721
  if (envOverride !== void 0) opts.baseUrl = envOverride;
13713
13722
  const t = applyTransform();
13723
+ assertOAuthResolved(t);
13714
13724
  if (t.fetch !== void 0) opts.fetch = t.fetch;
13715
13725
  const merged = profile.extraHeaders !== void 0 || t.headers !== void 0 ? { ...profile.extraHeaders, ...t.headers } : void 0;
13716
13726
  if (merged !== void 0) opts.extraHeaders = merged;
@@ -13731,6 +13741,7 @@ function selectTransport(profile, apiKey) {
13731
13741
  }
13732
13742
  if (profile.apiMode === "responses_api") {
13733
13743
  const t = applyTransform();
13744
+ assertOAuthResolved(t);
13734
13745
  const mergedHeaders = profile.extraHeaders !== void 0 || t.headers !== void 0 ? { ...profile.extraHeaders, ...t.headers } : void 0;
13735
13746
  return new ResponsesApiClient({
13736
13747
  apiKey,