@earendil-works/pi-ai 0.83.0 → 0.84.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (191) hide show
  1. package/README.md +16 -7
  2. package/dist/api/anthropic-messages.d.ts.map +1 -1
  3. package/dist/api/anthropic-messages.js +3 -3
  4. package/dist/api/anthropic-messages.js.map +1 -1
  5. package/dist/api/azure-openai-responses.d.ts.map +1 -1
  6. package/dist/api/azure-openai-responses.js +5 -1
  7. package/dist/api/azure-openai-responses.js.map +1 -1
  8. package/dist/api/bedrock-converse-stream.d.ts.map +1 -1
  9. package/dist/api/bedrock-converse-stream.js +48 -0
  10. package/dist/api/bedrock-converse-stream.js.map +1 -1
  11. package/dist/api/google-generative-ai.d.ts.map +1 -1
  12. package/dist/api/google-generative-ai.js +2 -2
  13. package/dist/api/google-generative-ai.js.map +1 -1
  14. package/dist/api/google-shared.d.ts +11 -1
  15. package/dist/api/google-shared.d.ts.map +1 -1
  16. package/dist/api/google-shared.js +44 -7
  17. package/dist/api/google-shared.js.map +1 -1
  18. package/dist/api/google-vertex.d.ts.map +1 -1
  19. package/dist/api/google-vertex.js +2 -2
  20. package/dist/api/google-vertex.js.map +1 -1
  21. package/dist/api/lazy.d.ts +5 -1
  22. package/dist/api/lazy.d.ts.map +1 -1
  23. package/dist/api/lazy.js +19 -7
  24. package/dist/api/lazy.js.map +1 -1
  25. package/dist/api/openai-codex-responses.d.ts.map +1 -1
  26. package/dist/api/openai-codex-responses.js +39 -19
  27. package/dist/api/openai-codex-responses.js.map +1 -1
  28. package/dist/api/openai-completions.d.ts +5 -2
  29. package/dist/api/openai-completions.d.ts.map +1 -1
  30. package/dist/api/openai-completions.js +57 -8
  31. package/dist/api/openai-completions.js.map +1 -1
  32. package/dist/api/openai-responses-shared.d.ts.map +1 -1
  33. package/dist/api/openai-responses-shared.js +22 -9
  34. package/dist/api/openai-responses-shared.js.map +1 -1
  35. package/dist/api/openai-responses.d.ts.map +1 -1
  36. package/dist/api/openai-responses.js +5 -1
  37. package/dist/api/openai-responses.js.map +1 -1
  38. package/dist/api/simple-options.d.ts +2 -0
  39. package/dist/api/simple-options.d.ts.map +1 -1
  40. package/dist/api/simple-options.js +8 -2
  41. package/dist/api/simple-options.js.map +1 -1
  42. package/dist/auth/credential-store.d.ts +6 -6
  43. package/dist/auth/credential-store.d.ts.map +1 -1
  44. package/dist/auth/credential-store.js +22 -11
  45. package/dist/auth/credential-store.js.map +1 -1
  46. package/dist/auth/helpers.d.ts +1 -0
  47. package/dist/auth/helpers.d.ts.map +1 -1
  48. package/dist/auth/helpers.js +7 -2
  49. package/dist/auth/helpers.js.map +1 -1
  50. package/dist/auth/oauth/anthropic.d.ts.map +1 -1
  51. package/dist/auth/oauth/anthropic.js +14 -8
  52. package/dist/auth/oauth/anthropic.js.map +1 -1
  53. package/dist/auth/oauth/device-code.d.ts +1 -1
  54. package/dist/auth/oauth/device-code.d.ts.map +1 -1
  55. package/dist/auth/oauth/device-code.js +4 -4
  56. package/dist/auth/oauth/device-code.js.map +1 -1
  57. package/dist/auth/oauth/github-copilot.d.ts.map +1 -1
  58. package/dist/auth/oauth/github-copilot.js +43 -30
  59. package/dist/auth/oauth/github-copilot.js.map +1 -1
  60. package/dist/auth/oauth/kimi-coding.d.ts.map +1 -1
  61. package/dist/auth/oauth/kimi-coding.js +17 -5
  62. package/dist/auth/oauth/kimi-coding.js.map +1 -1
  63. package/dist/auth/oauth/openai-codex.d.ts.map +1 -1
  64. package/dist/auth/oauth/openai-codex.js +12 -5
  65. package/dist/auth/oauth/openai-codex.js.map +1 -1
  66. package/dist/auth/oauth/openrouter.d.ts.map +1 -1
  67. package/dist/auth/oauth/openrouter.js +10 -10
  68. package/dist/auth/oauth/openrouter.js.map +1 -1
  69. package/dist/auth/oauth/radius.d.ts.map +1 -1
  70. package/dist/auth/oauth/radius.js +8 -7
  71. package/dist/auth/oauth/radius.js.map +1 -1
  72. package/dist/auth/oauth/xai.d.ts.map +1 -1
  73. package/dist/auth/oauth/xai.js +3 -2
  74. package/dist/auth/oauth/xai.js.map +1 -1
  75. package/dist/auth/resolve.d.ts +1 -0
  76. package/dist/auth/resolve.d.ts.map +1 -1
  77. package/dist/auth/resolve.js +24 -13
  78. package/dist/auth/resolve.js.map +1 -1
  79. package/dist/auth/types.d.ts +20 -8
  80. package/dist/auth/types.d.ts.map +1 -1
  81. package/dist/auth/types.js.map +1 -1
  82. package/dist/cli.d.ts.map +1 -1
  83. package/dist/cli.js +1 -0
  84. package/dist/cli.js.map +1 -1
  85. package/dist/env-api-keys.d.ts.map +1 -1
  86. package/dist/env-api-keys.js +1 -0
  87. package/dist/env-api-keys.js.map +1 -1
  88. package/dist/image-models.generated.d.ts +30 -0
  89. package/dist/image-models.generated.d.ts.map +1 -1
  90. package/dist/image-models.generated.js +32 -2
  91. package/dist/image-models.generated.js.map +1 -1
  92. package/dist/images-models.d.ts.map +1 -1
  93. package/dist/images-models.js +1 -0
  94. package/dist/images-models.js.map +1 -1
  95. package/dist/models-store.d.ts +9 -12
  96. package/dist/models-store.d.ts.map +1 -1
  97. package/dist/models-store.js +6 -3
  98. package/dist/models-store.js.map +1 -1
  99. package/dist/models.d.ts +40 -18
  100. package/dist/models.d.ts.map +1 -1
  101. package/dist/models.generated.d.ts +2 -0
  102. package/dist/models.generated.d.ts.map +1 -1
  103. package/dist/models.generated.js +2 -0
  104. package/dist/models.generated.js.map +1 -1
  105. package/dist/models.js +245 -89
  106. package/dist/models.js.map +1 -1
  107. package/dist/providers/all.d.ts.map +1 -1
  108. package/dist/providers/all.js +2 -0
  109. package/dist/providers/all.js.map +1 -1
  110. package/dist/providers/amazon-bedrock.d.ts.map +1 -1
  111. package/dist/providers/amazon-bedrock.js +15 -7
  112. package/dist/providers/amazon-bedrock.js.map +1 -1
  113. package/dist/providers/anthropic.d.ts.map +1 -1
  114. package/dist/providers/anthropic.js +15 -6
  115. package/dist/providers/anthropic.js.map +1 -1
  116. package/dist/providers/baseten.d.ts +3 -0
  117. package/dist/providers/baseten.d.ts.map +1 -0
  118. package/dist/providers/baseten.js +15 -0
  119. package/dist/providers/baseten.js.map +1 -0
  120. package/dist/providers/baseten.models.d.ts +4 -0
  121. package/dist/providers/baseten.models.d.ts.map +1 -0
  122. package/dist/providers/baseten.models.js +6 -0
  123. package/dist/providers/baseten.models.js.map +1 -0
  124. package/dist/providers/cloudflare-auth.d.ts.map +1 -1
  125. package/dist/providers/cloudflare-auth.js +15 -10
  126. package/dist/providers/cloudflare-auth.js.map +1 -1
  127. package/dist/providers/data/.manifest.json +1 -1
  128. package/dist/providers/data/amazon-bedrock.json +1 -1
  129. package/dist/providers/data/anthropic.json +1 -1
  130. package/dist/providers/data/azure-openai-responses.json +1 -1
  131. package/dist/providers/data/baseten.json +1 -0
  132. package/dist/providers/data/cloudflare-ai-gateway.json +1 -1
  133. package/dist/providers/data/fireworks.json +1 -1
  134. package/dist/providers/data/github-copilot.json +1 -1
  135. package/dist/providers/data/groq.json +1 -1
  136. package/dist/providers/data/huggingface.json +1 -1
  137. package/dist/providers/data/mistral.json +1 -1
  138. package/dist/providers/data/openai-codex.json +1 -1
  139. package/dist/providers/data/openai.json +1 -1
  140. package/dist/providers/data/opencode-go.json +1 -1
  141. package/dist/providers/data/opencode.json +1 -1
  142. package/dist/providers/data/openrouter.json +1 -1
  143. package/dist/providers/data/qwen-token-plan-cn.json +1 -1
  144. package/dist/providers/data/qwen-token-plan.json +1 -1
  145. package/dist/providers/data/together.json +1 -1
  146. package/dist/providers/data/vercel-ai-gateway.json +1 -1
  147. package/dist/providers/data/zai-coding-cn.json +1 -1
  148. package/dist/providers/data/zai.json +1 -1
  149. package/dist/providers/faux.d.ts +18 -13
  150. package/dist/providers/faux.d.ts.map +1 -1
  151. package/dist/providers/faux.js +95 -5
  152. package/dist/providers/faux.js.map +1 -1
  153. package/dist/providers/github-copilot.d.ts.map +1 -1
  154. package/dist/providers/github-copilot.js +1 -1
  155. package/dist/providers/github-copilot.js.map +1 -1
  156. package/dist/providers/google-vertex.d.ts.map +1 -1
  157. package/dist/providers/google-vertex.js +15 -7
  158. package/dist/providers/google-vertex.js.map +1 -1
  159. package/dist/providers/kimi-coding.d.ts.map +1 -1
  160. package/dist/providers/kimi-coding.js +1 -0
  161. package/dist/providers/kimi-coding.js.map +1 -1
  162. package/dist/providers/openai-codex.d.ts.map +1 -1
  163. package/dist/providers/openai-codex.js +5 -1
  164. package/dist/providers/openai-codex.js.map +1 -1
  165. package/dist/providers/opencode-go.d.ts.map +1 -1
  166. package/dist/providers/opencode-go.js +1 -1
  167. package/dist/providers/opencode-go.js.map +1 -1
  168. package/dist/providers/radius.d.ts.map +1 -1
  169. package/dist/providers/radius.js +36 -26
  170. package/dist/providers/radius.js.map +1 -1
  171. package/dist/providers/xai.d.ts.map +1 -1
  172. package/dist/providers/xai.js +1 -0
  173. package/dist/providers/xai.js.map +1 -1
  174. package/dist/types.d.ts +96 -80
  175. package/dist/types.d.ts.map +1 -1
  176. package/dist/types.js.map +1 -1
  177. package/dist/utils/abort.d.ts +8 -0
  178. package/dist/utils/abort.d.ts.map +1 -0
  179. package/dist/utils/abort.js +49 -0
  180. package/dist/utils/abort.js.map +1 -0
  181. package/dist/utils/error-body.d.ts.map +1 -1
  182. package/dist/utils/error-body.js +23 -4
  183. package/dist/utils/error-body.js.map +1 -1
  184. package/dist/utils/overflow.d.ts +10 -1
  185. package/dist/utils/overflow.d.ts.map +1 -1
  186. package/dist/utils/overflow.js +12 -1
  187. package/dist/utils/overflow.js.map +1 -1
  188. package/dist/utils/validation.d.ts.map +1 -1
  189. package/dist/utils/validation.js +6 -0
  190. package/dist/utils/validation.js.map +1 -1
  191. package/package.json +2 -1
@@ -1 +1 @@
1
- {"version":3,"file":"openai-responses.js","sourceRoot":"","sources":["../../src/api/openai-responses.ts"],"names":[],"mappings":"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","sourcesContent":["import OpenAI from \"openai\";\nimport type { ResponseCreateParamsStreaming } from \"openai/resources/responses/responses.js\";\nimport { clampThinkingLevel } from \"../models.ts\";\nimport type {\n\tApi,\n\tAssistantMessage,\n\tCacheRetention,\n\tContext,\n\tModel,\n\tOpenAIResponsesCompat,\n\tProviderEnv,\n\tProviderHeaders,\n\tSimpleStreamOptions,\n\tStreamFunction,\n\tStreamOptions,\n\tUsage,\n} from \"../types.ts\";\nimport { splitDeferredTools } from \"../utils/deferred-tools.ts\";\nimport { formatProviderError, normalizeProviderError } from \"../utils/error-body.ts\";\nimport { AssistantMessageEventStream } from \"../utils/event-stream.ts\";\nimport { headersToRecord } from \"../utils/headers.ts\";\nimport { getProviderEnvValue } from \"../utils/provider-env.ts\";\nimport { retryProviderRequest } from \"../utils/provider-retry.ts\";\nimport { createGrammarToolInputProperties } from \"./constrained-sampling.ts\";\nimport { buildCopilotDynamicHeaders, hasCopilotVisionInput } from \"./github-copilot-headers.ts\";\nimport { clampOpenAIPromptCacheKey } from \"./openai-prompt-cache.ts\";\nimport { convertResponsesMessages, convertResponsesTools, processResponsesStream } from \"./openai-responses-shared.ts\";\nimport { buildBaseOptions } from \"./simple-options.ts\";\n\nconst OPENAI_TOOL_CALL_PROVIDERS = new Set([\"openai\", \"openai-codex\", \"opencode\"]);\n// OpenAI Responses rejects max_output_tokens below 16: https://github.com/earendil-works/pi/issues/6265\nconst OPENAI_RESPONSES_MIN_OUTPUT_TOKENS = 16;\n\nfunction hasHeader(headers: ProviderHeaders | undefined, name: string): boolean {\n\tif (!headers) return false;\n\tconst expected = name.toLowerCase();\n\tfor (const [key, value] of Object.entries(headers)) {\n\t\tif (key.toLowerCase() === expected && value !== null && value.trim().length > 0) return true;\n\t}\n\treturn false;\n}\n\nfunction getClientApiKey(provider: string, apiKey: string | undefined, headers: ProviderHeaders | undefined): string {\n\tif (apiKey) return apiKey;\n\tif (hasHeader(headers, \"authorization\") || hasHeader(headers, \"cf-aig-authorization\")) return \"unused\";\n\tthrow new Error(`No API key for provider: ${provider}`);\n}\n\nfunction detectSessionAffinityFormat(model: Pick<Model<\"openai-responses\">, \"provider\" | \"baseUrl\">) {\n\treturn model.provider === \"openrouter\" || model.baseUrl.includes(\"openrouter.ai\") ? \"openrouter\" : \"openai\";\n}\n\n/**\n * Resolve cache retention preference.\n * Defaults to \"short\" and uses PI_CACHE_RETENTION for backward compatibility.\n */\nfunction resolveCacheRetention(cacheRetention?: CacheRetention, env?: ProviderEnv): CacheRetention {\n\tif (cacheRetention) {\n\t\treturn cacheRetention;\n\t}\n\tif (getProviderEnvValue(\"PI_CACHE_RETENTION\", env) === \"long\") {\n\t\treturn \"long\";\n\t}\n\treturn \"short\";\n}\n\nfunction getCompat(model: Model<\"openai-responses\">): Required<OpenAIResponsesCompat> {\n\treturn {\n\t\tsupportsDeveloperRole: model.compat?.supportsDeveloperRole ?? true,\n\t\tsessionAffinityFormat: model.compat?.sessionAffinityFormat ?? detectSessionAffinityFormat(model),\n\t\tsupportsLongCacheRetention: model.compat?.supportsLongCacheRetention ?? true,\n\t\tsupportsStrictMode: model.compat?.supportsStrictMode ?? false,\n\t\tsupportsOpenAIGrammarTools: model.compat?.supportsOpenAIGrammarTools ?? false,\n\t\tsupportsToolSearch: model.compat?.supportsToolSearch ?? false,\n\t\tsupportsExplicitPromptCacheMode: model.compat?.supportsExplicitPromptCacheMode ?? false,\n\t};\n}\n\nfunction getPromptCacheRetention(\n\tcompat: Required<OpenAIResponsesCompat>,\n\tcacheRetention: CacheRetention,\n): \"24h\" | undefined {\n\treturn cacheRetention === \"long\" && compat.supportsLongCacheRetention ? \"24h\" : undefined;\n}\n\nfunction formatOpenAIResponsesError(error: unknown): string {\n\treturn formatProviderError(normalizeProviderError(error), \"OpenAI API error\");\n}\n\n// OpenAI Responses-specific options\nexport interface OpenAIResponsesOptions extends StreamOptions {\n\treasoningEffort?: \"minimal\" | \"low\" | \"medium\" | \"high\" | \"xhigh\" | \"max\";\n\treasoningSummary?: \"auto\" | \"detailed\" | \"concise\" | null;\n\tserviceTier?: ResponseCreateParamsStreaming[\"service_tier\"];\n\ttoolChoice?: ResponseCreateParamsStreaming[\"tool_choice\"];\n}\n\n/**\n * Generate function for OpenAI Responses API\n */\nexport const stream: StreamFunction<\"openai-responses\", OpenAIResponsesOptions> = (\n\tmodel: Model<\"openai-responses\">,\n\tcontext: Context,\n\toptions?: OpenAIResponsesOptions,\n): AssistantMessageEventStream => {\n\tconst stream = new AssistantMessageEventStream();\n\n\t// Start async processing\n\t(async () => {\n\t\tconst output: AssistantMessage = {\n\t\t\trole: \"assistant\",\n\t\t\tcontent: [],\n\t\t\tapi: model.api as Api,\n\t\t\tprovider: model.provider,\n\t\t\tmodel: model.id,\n\t\t\tusage: {\n\t\t\t\tinput: 0,\n\t\t\t\toutput: 0,\n\t\t\t\tcacheRead: 0,\n\t\t\t\tcacheWrite: 0,\n\t\t\t\ttotalTokens: 0,\n\t\t\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n\t\t\t},\n\t\t\tstopReason: \"pending\",\n\t\t\ttimestamp: Date.now(),\n\t\t};\n\n\t\ttry {\n\t\t\t// Create OpenAI client\n\t\t\tconst apiKey = getClientApiKey(model.provider, options?.apiKey, options?.headers);\n\t\t\tconst cacheRetention = resolveCacheRetention(options?.cacheRetention, options?.env);\n\t\t\tconst cacheSessionId = cacheRetention === \"none\" ? undefined : options?.sessionId;\n\t\t\tconst compat = getCompat(model);\n\t\t\tconst grammarToolInputProperties = createGrammarToolInputProperties(\n\t\t\t\tcontext.tools,\n\t\t\t\tcompat.supportsOpenAIGrammarTools,\n\t\t\t);\n\t\t\tconst client = createClient(model, context, apiKey, options?.headers, options?.fetch, cacheSessionId);\n\t\t\tlet params = buildParams(model, context, options, compat, grammarToolInputProperties);\n\t\t\tconst nextParams = await options?.onPayload?.(params, model);\n\t\t\tif (nextParams !== undefined) {\n\t\t\t\tparams = nextParams as ResponseCreateParamsStreaming;\n\t\t\t}\n\t\t\tconst requestOptions = {\n\t\t\t\t...(options?.signal ? { signal: options.signal } : {}),\n\t\t\t\t...(options?.timeoutMs !== undefined ? { timeout: options.timeoutMs } : {}),\n\t\t\t\tmaxRetries: 0,\n\t\t\t};\n\t\t\tconst { data: openaiStream, response } = await retryProviderRequest(\n\t\t\t\t() => client.responses.create(params, requestOptions).withResponse(),\n\t\t\t\t{\n\t\t\t\t\tmaxRetries: options?.maxRetries,\n\t\t\t\t\tmaxRetryDelayMs: options?.maxRetryDelayMs,\n\t\t\t\t\tsignal: options?.signal,\n\t\t\t\t},\n\t\t\t);\n\t\t\tawait options?.onResponse?.({ status: response.status, headers: headersToRecord(response.headers) }, model);\n\t\t\tstream.push({ type: \"start\", partial: output });\n\n\t\t\tawait processResponsesStream(openaiStream, output, stream, model, {\n\t\t\t\tserviceTier: options?.serviceTier,\n\t\t\t\tgrammarToolInputProperties,\n\t\t\t\tapplyServiceTierPricing: (usage, serviceTier) => applyServiceTierPricing(usage, serviceTier, model),\n\t\t\t});\n\n\t\t\tif (options?.signal?.aborted) {\n\t\t\t\tthrow new Error(\"Request was aborted\");\n\t\t\t}\n\n\t\t\tif (output.stopReason === \"pending\") {\n\t\t\t\tthrow new Error(\"OpenAI Responses stream ended without a stop reason\");\n\t\t\t}\n\t\t\tif (output.stopReason === \"aborted\" || output.stopReason === \"error\") {\n\t\t\t\tthrow new Error(\"An unknown error occurred\");\n\t\t\t}\n\n\t\t\tstream.push({ type: \"done\", reason: output.stopReason, message: output });\n\t\t\tstream.end();\n\t\t} catch (error) {\n\t\t\tfor (const block of output.content) {\n\t\t\t\tdelete (block as { index?: number }).index;\n\t\t\t\t// Streaming scratch buffers are only used during parsing; never persist them.\n\t\t\t\tdelete (block as { partialJson?: string }).partialJson;\n\t\t\t\tdelete (block as { customInput?: unknown }).customInput;\n\t\t\t}\n\t\t\toutput.stopReason = options?.signal?.aborted ? \"aborted\" : \"error\";\n\t\t\toutput.errorMessage = formatOpenAIResponsesError(error);\n\t\t\tstream.push({ type: \"error\", reason: output.stopReason, error: output });\n\t\t\tstream.end();\n\t\t}\n\t})();\n\n\treturn stream;\n};\n\nexport const streamSimple: StreamFunction<\"openai-responses\", SimpleStreamOptions> = (\n\tmodel: Model<\"openai-responses\">,\n\tcontext: Context,\n\toptions?: SimpleStreamOptions,\n): AssistantMessageEventStream => {\n\tgetClientApiKey(model.provider, options?.apiKey, options?.headers);\n\n\tconst base = buildBaseOptions(model, context, options, options?.apiKey);\n\tconst clampedReasoning = options?.reasoning ? clampThinkingLevel(model, options.reasoning) : undefined;\n\tconst reasoningEffort = clampedReasoning === \"off\" ? undefined : clampedReasoning;\n\n\treturn stream(model, context, {\n\t\t...base,\n\t\treasoningEffort,\n\t} satisfies OpenAIResponsesOptions);\n};\n\nfunction createClient(\n\tmodel: Model<\"openai-responses\">,\n\tcontext: Context,\n\tapiKey: string,\n\toptionsHeaders?: ProviderHeaders,\n\tfetch?: typeof globalThis.fetch,\n\tsessionId?: string,\n) {\n\tconst compat = getCompat(model);\n\tconst headers: ProviderHeaders = { ...model.headers };\n\tif (model.provider === \"github-copilot\") {\n\t\tconst hasImages = hasCopilotVisionInput(context.messages);\n\t\tconst copilotHeaders = buildCopilotDynamicHeaders({\n\t\t\tmessages: context.messages,\n\t\t\thasImages,\n\t\t});\n\t\tObject.assign(headers, copilotHeaders);\n\t}\n\n\tif (sessionId) {\n\t\tif (compat.sessionAffinityFormat === \"openrouter\") {\n\t\t\theaders[\"x-session-id\"] = sessionId;\n\t\t} else {\n\t\t\tif (compat.sessionAffinityFormat === \"openai\") {\n\t\t\t\theaders.session_id = sessionId;\n\t\t\t}\n\t\t\theaders[\"x-client-request-id\"] = sessionId;\n\t\t}\n\t}\n\n\t// Merge options headers last so they can override defaults\n\tif (optionsHeaders) {\n\t\tObject.assign(headers, optionsHeaders);\n\t}\n\n\treturn new OpenAI({\n\t\tapiKey,\n\t\tbaseURL: model.baseUrl,\n\t\tdangerouslyAllowBrowser: true,\n\t\tfetch,\n\t\tdefaultHeaders: headers,\n\t});\n}\n\nfunction buildParams(\n\tmodel: Model<\"openai-responses\">,\n\tcontext: Context,\n\toptions: OpenAIResponsesOptions | undefined,\n\tcompat: Required<OpenAIResponsesCompat> = getCompat(model),\n\tgrammarToolInputProperties: ReadonlyMap<string, string> = createGrammarToolInputProperties(\n\t\tcontext.tools,\n\t\tcompat.supportsOpenAIGrammarTools,\n\t),\n) {\n\tconst toolPlacement = splitDeferredTools(context, compat.supportsToolSearch);\n\tconst messages = convertResponsesMessages(model, context, OPENAI_TOOL_CALL_PROVIDERS, {\n\t\tgrammarToolInputProperties,\n\t\tdeferredTools: toolPlacement.deferred,\n\t\ttoolOptions: {\n\t\t\tsupportsStrictMode: compat.supportsStrictMode,\n\t\t\tsupportsOpenAIGrammarTools: compat.supportsOpenAIGrammarTools,\n\t\t},\n\t});\n\n\tconst cacheRetention = resolveCacheRetention(options?.cacheRetention, options?.env);\n\tconst disableImplicitPromptCache = cacheRetention === \"none\" && compat.supportsExplicitPromptCacheMode;\n\tconst params: ResponseCreateParamsStreaming & { prompt_cache_options?: { mode: \"explicit\" } } = {\n\t\tmodel: model.id,\n\t\tinput: messages,\n\t\tstream: true,\n\t\tprompt_cache_key: cacheRetention === \"none\" ? undefined : clampOpenAIPromptCacheKey(options?.sessionId),\n\t\tprompt_cache_retention: getPromptCacheRetention(compat, cacheRetention),\n\t\tprompt_cache_options: disableImplicitPromptCache ? { mode: \"explicit\" } : undefined,\n\t\tstore: false,\n\t};\n\n\tif (options?.maxTokens) {\n\t\tparams.max_output_tokens = Math.max(options.maxTokens, OPENAI_RESPONSES_MIN_OUTPUT_TOKENS);\n\t}\n\n\tif (options?.temperature !== undefined) {\n\t\tparams.temperature = options?.temperature;\n\t}\n\n\tif (options?.serviceTier !== undefined) {\n\t\tparams.service_tier = options.serviceTier;\n\t}\n\n\tif (toolPlacement.immediate.length > 0) {\n\t\tparams.tools = convertResponsesTools(toolPlacement.immediate, {\n\t\t\tsupportsStrictMode: compat.supportsStrictMode,\n\t\t\tsupportsOpenAIGrammarTools: compat.supportsOpenAIGrammarTools,\n\t\t});\n\t}\n\n\tif (options?.toolChoice !== undefined) {\n\t\tparams.tool_choice = options.toolChoice;\n\t}\n\n\tif (model.reasoning) {\n\t\tif (options?.reasoningEffort || options?.reasoningSummary) {\n\t\t\tconst effort = options?.reasoningEffort\n\t\t\t\t? (model.thinkingLevelMap?.[options.reasoningEffort] ?? options.reasoningEffort)\n\t\t\t\t: \"medium\";\n\t\t\tparams.reasoning = {\n\t\t\t\teffort: effort as NonNullable<typeof params.reasoning>[\"effort\"],\n\t\t\t\tsummary: options?.reasoningSummary || \"auto\",\n\t\t\t};\n\t\t\tparams.include = [\"reasoning.encrypted_content\"];\n\t\t} else if (model.provider !== \"github-copilot\" && model.thinkingLevelMap?.off !== null) {\n\t\t\tparams.reasoning = {\n\t\t\t\teffort: (model.thinkingLevelMap?.off ?? \"none\") as NonNullable<typeof params.reasoning>[\"effort\"],\n\t\t\t};\n\t\t}\n\t\tif (model.provider === \"xai\") params.include = [\"reasoning.encrypted_content\"];\n\t}\n\n\treturn params;\n}\n\nfunction getServiceTierCostMultiplier(\n\tmodel: Pick<Model<\"openai-responses\">, \"id\">,\n\tserviceTier: ResponseCreateParamsStreaming[\"service_tier\"] | undefined,\n): number {\n\tswitch (serviceTier) {\n\t\tcase \"flex\":\n\t\t\treturn 0.5;\n\t\tcase \"priority\":\n\t\t\treturn model.id === \"gpt-5.5\" ? 2.5 : 2;\n\t\tdefault:\n\t\t\treturn 1;\n\t}\n}\n\nfunction applyServiceTierPricing(\n\tusage: Usage,\n\tserviceTier: ResponseCreateParamsStreaming[\"service_tier\"] | undefined,\n\tmodel: Pick<Model<\"openai-responses\">, \"id\">,\n) {\n\tconst multiplier = getServiceTierCostMultiplier(model, serviceTier);\n\tif (multiplier === 1) return;\n\n\tusage.cost.input *= multiplier;\n\tusage.cost.output *= multiplier;\n\tusage.cost.cacheRead *= multiplier;\n\tusage.cost.cacheWrite *= multiplier;\n\tusage.cost.total = usage.cost.input + usage.cost.output + usage.cost.cacheRead + usage.cost.cacheWrite;\n}\n"]}
1
+ {"version":3,"file":"openai-responses.js","sourceRoot":"","sources":["../../src/api/openai-responses.ts"],"names":[],"mappings":"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","sourcesContent":["import OpenAI from \"openai\";\nimport type { ResponseCreateParamsStreaming } from \"openai/resources/responses/responses.js\";\nimport { clampThinkingLevel } from \"../models.ts\";\nimport type {\n\tApi,\n\tAssistantMessage,\n\tCacheRetention,\n\tContext,\n\tModel,\n\tOpenAIResponsesCompat,\n\tProviderEnv,\n\tProviderHeaders,\n\tSimpleStreamOptions,\n\tStreamFunction,\n\tStreamOptions,\n\tUsage,\n} from \"../types.ts\";\nimport { splitDeferredTools } from \"../utils/deferred-tools.ts\";\nimport { formatProviderError, normalizeProviderError } from \"../utils/error-body.ts\";\nimport { AssistantMessageEventStream } from \"../utils/event-stream.ts\";\nimport { headersToRecord } from \"../utils/headers.ts\";\nimport { getProviderEnvValue } from \"../utils/provider-env.ts\";\nimport { retryProviderRequest } from \"../utils/provider-retry.ts\";\nimport { createGrammarToolInputProperties } from \"./constrained-sampling.ts\";\nimport { buildCopilotDynamicHeaders, hasCopilotVisionInput } from \"./github-copilot-headers.ts\";\nimport { clampOpenAIPromptCacheKey } from \"./openai-prompt-cache.ts\";\nimport { convertResponsesMessages, convertResponsesTools, processResponsesStream } from \"./openai-responses-shared.ts\";\nimport { buildBaseOptions } from \"./simple-options.ts\";\n\nconst OPENAI_TOOL_CALL_PROVIDERS = new Set([\"openai\", \"openai-codex\", \"opencode\"]);\n// OpenAI Responses rejects max_output_tokens below 16: https://github.com/earendil-works/pi/issues/6265\nconst OPENAI_RESPONSES_MIN_OUTPUT_TOKENS = 16;\n\nfunction hasHeader(headers: ProviderHeaders | undefined, name: string): boolean {\n\tif (!headers) return false;\n\tconst expected = name.toLowerCase();\n\tfor (const [key, value] of Object.entries(headers)) {\n\t\tif (key.toLowerCase() === expected && value !== null && value.trim().length > 0) return true;\n\t}\n\treturn false;\n}\n\nfunction getClientApiKey(provider: string, apiKey: string | undefined, headers: ProviderHeaders | undefined): string {\n\tif (apiKey) return apiKey;\n\tif (hasHeader(headers, \"authorization\") || hasHeader(headers, \"cf-aig-authorization\")) return \"unused\";\n\tthrow new Error(`No API key for provider: ${provider}`);\n}\n\nfunction detectSessionAffinityFormat(model: Pick<Model<\"openai-responses\">, \"provider\" | \"baseUrl\">) {\n\treturn model.provider === \"openrouter\" || model.baseUrl.includes(\"openrouter.ai\") ? \"openrouter\" : \"openai\";\n}\n\n/**\n * Resolve cache retention preference.\n * Defaults to \"short\" and uses PI_CACHE_RETENTION for backward compatibility.\n */\nfunction resolveCacheRetention(cacheRetention?: CacheRetention, env?: ProviderEnv): CacheRetention {\n\tif (cacheRetention) {\n\t\treturn cacheRetention;\n\t}\n\tif (getProviderEnvValue(\"PI_CACHE_RETENTION\", env) === \"long\") {\n\t\treturn \"long\";\n\t}\n\treturn \"short\";\n}\n\nfunction getCompat(model: Model<\"openai-responses\">): Required<OpenAIResponsesCompat> {\n\treturn {\n\t\tsupportsDeveloperRole: model.compat?.supportsDeveloperRole ?? true,\n\t\tsessionAffinityFormat: model.compat?.sessionAffinityFormat ?? detectSessionAffinityFormat(model),\n\t\tsupportsLongCacheRetention: model.compat?.supportsLongCacheRetention ?? true,\n\t\tsupportsStrictMode: model.compat?.supportsStrictMode ?? false,\n\t\tsupportsOpenAIGrammarTools: model.compat?.supportsOpenAIGrammarTools ?? false,\n\t\tsupportsToolSearch: model.compat?.supportsToolSearch ?? false,\n\t\tsupportsExplicitPromptCacheMode: model.compat?.supportsExplicitPromptCacheMode ?? false,\n\t};\n}\n\nfunction getPromptCacheRetention(\n\tcompat: Required<OpenAIResponsesCompat>,\n\tcacheRetention: CacheRetention,\n): \"24h\" | undefined {\n\treturn cacheRetention === \"long\" && compat.supportsLongCacheRetention ? \"24h\" : undefined;\n}\n\nfunction formatOpenAIResponsesError(error: unknown): string {\n\treturn formatProviderError(normalizeProviderError(error), \"OpenAI API error\");\n}\n\n// OpenAI Responses-specific options\nexport interface OpenAIResponsesOptions extends StreamOptions {\n\treasoningEffort?: \"minimal\" | \"low\" | \"medium\" | \"high\" | \"xhigh\" | \"max\";\n\treasoningSummary?: \"auto\" | \"detailed\" | \"concise\" | null;\n\tserviceTier?: ResponseCreateParamsStreaming[\"service_tier\"];\n\ttoolChoice?: ResponseCreateParamsStreaming[\"tool_choice\"];\n}\n\n/**\n * Generate function for OpenAI Responses API\n */\nexport const stream: StreamFunction<\"openai-responses\", OpenAIResponsesOptions> = (\n\tmodel: Model<\"openai-responses\">,\n\tcontext: Context,\n\toptions?: OpenAIResponsesOptions,\n): AssistantMessageEventStream => {\n\tconst stream = new AssistantMessageEventStream();\n\n\t// Start async processing\n\t(async () => {\n\t\tconst output: AssistantMessage = {\n\t\t\trole: \"assistant\",\n\t\t\tcontent: [],\n\t\t\tapi: model.api as Api,\n\t\t\tprovider: model.provider,\n\t\t\tmodel: model.id,\n\t\t\tusage: {\n\t\t\t\tinput: 0,\n\t\t\t\toutput: 0,\n\t\t\t\tcacheRead: 0,\n\t\t\t\tcacheWrite: 0,\n\t\t\t\ttotalTokens: 0,\n\t\t\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n\t\t\t},\n\t\t\tstopReason: \"pending\",\n\t\t\ttimestamp: Date.now(),\n\t\t};\n\n\t\ttry {\n\t\t\t// Create OpenAI client\n\t\t\tconst apiKey = getClientApiKey(model.provider, options?.apiKey, options?.headers);\n\t\t\tconst cacheRetention = resolveCacheRetention(options?.cacheRetention, options?.env);\n\t\t\tconst cacheSessionId = cacheRetention === \"none\" ? undefined : options?.sessionId;\n\t\t\tconst compat = getCompat(model);\n\t\t\tconst grammarToolInputProperties = createGrammarToolInputProperties(\n\t\t\t\tcontext.tools,\n\t\t\t\tcompat.supportsOpenAIGrammarTools,\n\t\t\t);\n\t\t\tconst client = createClient(model, context, apiKey, options?.headers, options?.fetch, cacheSessionId);\n\t\t\tlet params = buildParams(model, context, options, compat, grammarToolInputProperties);\n\t\t\tconst nextParams = await options?.onPayload?.(params, model);\n\t\t\tif (nextParams !== undefined) {\n\t\t\t\tparams = nextParams as ResponseCreateParamsStreaming;\n\t\t\t}\n\t\t\tconst requestOptions = {\n\t\t\t\t...(options?.signal ? { signal: options.signal } : {}),\n\t\t\t\t...(options?.timeoutMs !== undefined ? { timeout: options.timeoutMs } : {}),\n\t\t\t\tmaxRetries: 0,\n\t\t\t};\n\t\t\tconst { data: openaiStream, response } = await retryProviderRequest(\n\t\t\t\t() => client.responses.create(params, requestOptions).withResponse(),\n\t\t\t\t{\n\t\t\t\t\tmaxRetries: options?.maxRetries,\n\t\t\t\t\tmaxRetryDelayMs: options?.maxRetryDelayMs,\n\t\t\t\t\tsignal: options?.signal,\n\t\t\t\t},\n\t\t\t);\n\t\t\tawait options?.onResponse?.({ status: response.status, headers: headersToRecord(response.headers) }, model);\n\t\t\tstream.push({ type: \"start\", partial: output });\n\n\t\t\tawait processResponsesStream(openaiStream, output, stream, model, {\n\t\t\t\tserviceTier: options?.serviceTier,\n\t\t\t\tgrammarToolInputProperties,\n\t\t\t\tapplyServiceTierPricing: (usage, serviceTier) => applyServiceTierPricing(usage, serviceTier, model),\n\t\t\t});\n\n\t\t\tif (options?.signal?.aborted) {\n\t\t\t\tthrow new Error(\"Request was aborted\");\n\t\t\t}\n\n\t\t\tif (output.stopReason === \"pending\") {\n\t\t\t\tthrow new Error(\"OpenAI Responses stream ended without a stop reason\");\n\t\t\t}\n\t\t\tif (output.stopReason === \"aborted\" || output.stopReason === \"error\") {\n\t\t\t\tthrow new Error(output.errorMessage || \"An unknown error occurred\");\n\t\t\t}\n\n\t\t\tstream.push({ type: \"done\", reason: output.stopReason, message: output });\n\t\t\tstream.end();\n\t\t} catch (error) {\n\t\t\tfor (const block of output.content) {\n\t\t\t\tdelete (block as { index?: number }).index;\n\t\t\t\t// Streaming scratch buffers are only used during parsing; never persist them.\n\t\t\t\tdelete (block as { partialJson?: string }).partialJson;\n\t\t\t\tdelete (block as { customInput?: unknown }).customInput;\n\t\t\t}\n\t\t\toutput.stopReason = options?.signal?.aborted ? \"aborted\" : \"error\";\n\t\t\toutput.errorMessage = formatOpenAIResponsesError(error);\n\t\t\tstream.push({ type: \"error\", reason: output.stopReason, error: output });\n\t\t\tstream.end();\n\t\t}\n\t})();\n\n\treturn stream;\n};\n\nexport const streamSimple: StreamFunction<\"openai-responses\", SimpleStreamOptions> = (\n\tmodel: Model<\"openai-responses\">,\n\tcontext: Context,\n\toptions?: SimpleStreamOptions,\n): AssistantMessageEventStream => {\n\tgetClientApiKey(model.provider, options?.apiKey, options?.headers);\n\n\tconst base = buildBaseOptions(model, context, options, options?.apiKey);\n\tconst clampedReasoning = options?.reasoning ? clampThinkingLevel(model, options.reasoning) : undefined;\n\tconst reasoningEffort = clampedReasoning === \"off\" ? undefined : clampedReasoning;\n\n\treturn stream(model, context, {\n\t\t...base,\n\t\treasoningEffort,\n\t} satisfies OpenAIResponsesOptions);\n};\n\nfunction createClient(\n\tmodel: Model<\"openai-responses\">,\n\tcontext: Context,\n\tapiKey: string,\n\toptionsHeaders?: ProviderHeaders,\n\tfetch?: typeof globalThis.fetch,\n\tsessionId?: string,\n) {\n\tconst compat = getCompat(model);\n\tconst headers: ProviderHeaders = { ...model.headers };\n\tif (model.provider === \"github-copilot\") {\n\t\tconst hasImages = hasCopilotVisionInput(context.messages);\n\t\tconst copilotHeaders = buildCopilotDynamicHeaders({\n\t\t\tmessages: context.messages,\n\t\t\thasImages,\n\t\t});\n\t\tObject.assign(headers, copilotHeaders);\n\t}\n\n\tif (sessionId) {\n\t\tif (compat.sessionAffinityFormat === \"openrouter\") {\n\t\t\theaders[\"x-session-id\"] = sessionId;\n\t\t} else {\n\t\t\tif (compat.sessionAffinityFormat === \"openai\") {\n\t\t\t\theaders.session_id = sessionId;\n\t\t\t}\n\t\t\theaders[\"x-client-request-id\"] = sessionId;\n\t\t}\n\t}\n\n\t// Merge options headers last so they can override defaults\n\tif (optionsHeaders) {\n\t\tObject.assign(headers, optionsHeaders);\n\t}\n\n\treturn new OpenAI({\n\t\tapiKey,\n\t\tbaseURL: model.baseUrl,\n\t\tdangerouslyAllowBrowser: true,\n\t\tfetch,\n\t\tdefaultHeaders: headers,\n\t});\n}\n\nfunction buildParams(\n\tmodel: Model<\"openai-responses\">,\n\tcontext: Context,\n\toptions: OpenAIResponsesOptions | undefined,\n\tcompat: Required<OpenAIResponsesCompat> = getCompat(model),\n\tgrammarToolInputProperties: ReadonlyMap<string, string> = createGrammarToolInputProperties(\n\t\tcontext.tools,\n\t\tcompat.supportsOpenAIGrammarTools,\n\t),\n) {\n\tconst toolPlacement = splitDeferredTools(context, compat.supportsToolSearch);\n\tconst messages = convertResponsesMessages(model, context, OPENAI_TOOL_CALL_PROVIDERS, {\n\t\tgrammarToolInputProperties,\n\t\tdeferredTools: toolPlacement.deferred,\n\t\ttoolOptions: {\n\t\t\tsupportsStrictMode: compat.supportsStrictMode,\n\t\t\tsupportsOpenAIGrammarTools: compat.supportsOpenAIGrammarTools,\n\t\t},\n\t});\n\n\tconst cacheRetention = resolveCacheRetention(options?.cacheRetention, options?.env);\n\tconst disableImplicitPromptCache = cacheRetention === \"none\" && compat.supportsExplicitPromptCacheMode;\n\tconst params: ResponseCreateParamsStreaming & { prompt_cache_options?: { mode: \"explicit\" } } = {\n\t\tmodel: model.id,\n\t\tinput: messages,\n\t\tstream: true,\n\t\tprompt_cache_key: cacheRetention === \"none\" ? undefined : clampOpenAIPromptCacheKey(options?.sessionId),\n\t\tprompt_cache_retention: getPromptCacheRetention(compat, cacheRetention),\n\t\tprompt_cache_options: disableImplicitPromptCache ? { mode: \"explicit\" } : undefined,\n\t\tstore: false,\n\t};\n\n\tif (options?.maxTokens) {\n\t\tparams.max_output_tokens = Math.max(options.maxTokens, OPENAI_RESPONSES_MIN_OUTPUT_TOKENS);\n\t}\n\n\tif (options?.temperature !== undefined) {\n\t\tparams.temperature = options?.temperature;\n\t}\n\n\tif (options?.serviceTier !== undefined) {\n\t\tparams.service_tier = options.serviceTier;\n\t}\n\n\tif (toolPlacement.immediate.length > 0) {\n\t\tparams.tools = convertResponsesTools(toolPlacement.immediate, {\n\t\t\tsupportsStrictMode: compat.supportsStrictMode,\n\t\t\tsupportsOpenAIGrammarTools: compat.supportsOpenAIGrammarTools,\n\t\t});\n\t}\n\n\tif (options?.toolChoice !== undefined) {\n\t\tparams.tool_choice = options.toolChoice;\n\t}\n\n\tif (model.reasoning) {\n\t\tif (options?.reasoningEffort || options?.reasoningSummary) {\n\t\t\tconst effort = options?.reasoningEffort\n\t\t\t\t? (model.thinkingLevelMap?.[options.reasoningEffort] ?? options.reasoningEffort)\n\t\t\t\t: \"medium\";\n\t\t\tparams.reasoning = {\n\t\t\t\teffort: effort as NonNullable<typeof params.reasoning>[\"effort\"],\n\t\t\t\tsummary: options?.reasoningSummary || \"auto\",\n\t\t\t};\n\t\t\tparams.include = [\"reasoning.encrypted_content\"];\n\t\t} else if (model.provider !== \"github-copilot\" && model.thinkingLevelMap?.off !== null) {\n\t\t\tparams.reasoning = {\n\t\t\t\teffort: (model.thinkingLevelMap?.off ?? \"none\") as NonNullable<typeof params.reasoning>[\"effort\"],\n\t\t\t};\n\t\t}\n\t\tif (model.provider === \"xai\") params.include = [\"reasoning.encrypted_content\"];\n\t}\n\n\t// Last so custom keys override the named request fields.\n\tif (options?.samplingParams) {\n\t\tObject.assign(params, options.samplingParams);\n\t}\n\n\treturn params;\n}\n\nfunction getServiceTierCostMultiplier(\n\tmodel: Pick<Model<\"openai-responses\">, \"id\">,\n\tserviceTier: ResponseCreateParamsStreaming[\"service_tier\"] | undefined,\n): number {\n\tswitch (serviceTier) {\n\t\tcase \"flex\":\n\t\t\treturn 0.5;\n\t\tcase \"priority\":\n\t\t\treturn model.id === \"gpt-5.5\" ? 2.5 : 2;\n\t\tdefault:\n\t\t\treturn 1;\n\t}\n}\n\nfunction applyServiceTierPricing(\n\tusage: Usage,\n\tserviceTier: ResponseCreateParamsStreaming[\"service_tier\"] | undefined,\n\tmodel: Pick<Model<\"openai-responses\">, \"id\">,\n) {\n\tconst multiplier = getServiceTierCostMultiplier(model, serviceTier);\n\tif (multiplier === 1) return;\n\n\tusage.cost.input *= multiplier;\n\tusage.cost.output *= multiplier;\n\tusage.cost.cacheRead *= multiplier;\n\tusage.cost.cacheWrite *= multiplier;\n\tusage.cost.total = usage.cost.input + usage.cost.output + usage.cost.cacheRead + usage.cost.cacheWrite;\n}\n"]}
@@ -1,6 +1,8 @@
1
1
  import type { Api, Context, Model, SimpleStreamOptions, StreamOptions, ThinkingBudgets, ThinkingLevel } from "../types.ts";
2
2
  export declare function clampMaxTokensToContext(model: Model<Api>, context: Context, maxTokens: number): number;
3
3
  export declare function buildBaseOptions(model: Model<Api>, context: Context, options?: SimpleStreamOptions, apiKey?: string): StreamOptions;
4
+ /** Tokens always left for the answer when a thinking budget shares the response ceiling. */
5
+ export declare const MIN_ANSWER_TOKENS = 1024;
4
6
  export declare function clampReasoning(effort: ThinkingLevel | undefined): Exclude<ThinkingLevel, "xhigh" | "max"> | undefined;
5
7
  export declare function adjustMaxTokensForThinking(baseMaxTokens: number | undefined, modelMaxTokens: number, reasoningLevel: ThinkingLevel, customBudgets?: ThinkingBudgets): {
6
8
  maxTokens: number;
@@ -1 +1 @@
1
- {"version":3,"file":"simple-options.d.ts","sourceRoot":"","sources":["../../src/api/simple-options.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,GAAG,EACH,OAAO,EACP,KAAK,EACL,mBAAmB,EACnB,aAAa,EACb,eAAe,EACf,aAAa,EACb,MAAM,aAAa,CAAC;AAMrB,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAItG;AAED,wBAAgB,gBAAgB,CAC/B,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EACjB,OAAO,EAAE,OAAO,EAChB,OAAO,CAAC,EAAE,mBAAmB,EAC7B,MAAM,CAAC,EAAE,MAAM,GACb,aAAa,CAoBf;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,aAAa,GAAG,SAAS,GAAG,OAAO,CAAC,aAAa,EAAE,OAAO,GAAG,KAAK,CAAC,GAAG,SAAS,CAErH;AAED,wBAAgB,0BAA0B,CAEzC,aAAa,EAAE,MAAM,GAAG,SAAS,EACjC,cAAc,EAAE,MAAM,EACtB,cAAc,EAAE,aAAa,EAC7B,aAAa,CAAC,EAAE,eAAe,GAC7B;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,MAAM,CAAA;CAAE,CAoB/C","sourcesContent":["import type {\n\tApi,\n\tContext,\n\tModel,\n\tSimpleStreamOptions,\n\tStreamOptions,\n\tThinkingBudgets,\n\tThinkingLevel,\n} from \"../types.ts\";\nimport { estimateContextTokens } from \"../utils/estimate.ts\";\n\nconst CONTEXT_SAFETY_TOKENS = 4096;\nconst MIN_MAX_TOKENS = 1;\n\nexport function clampMaxTokensToContext(model: Model<Api>, context: Context, maxTokens: number): number {\n\tif (model.contextWindow <= 0) return Math.max(MIN_MAX_TOKENS, maxTokens);\n\tconst available = model.contextWindow - estimateContextTokens(context).tokens - CONTEXT_SAFETY_TOKENS;\n\treturn Math.min(maxTokens, Math.max(MIN_MAX_TOKENS, available));\n}\n\nexport function buildBaseOptions(\n\tmodel: Model<Api>,\n\tcontext: Context,\n\toptions?: SimpleStreamOptions,\n\tapiKey?: string,\n): StreamOptions {\n\treturn {\n\t\ttemperature: options?.temperature,\n\t\tmaxTokens: clampMaxTokensToContext(model, context, options?.maxTokens ?? model.maxTokens),\n\t\tsignal: options?.signal,\n\t\tapiKey: apiKey || options?.apiKey,\n\t\tfetch: options?.fetch,\n\t\ttransport: options?.transport,\n\t\tcacheRetention: options?.cacheRetention,\n\t\tsessionId: options?.sessionId,\n\t\theaders: options?.headers,\n\t\tonPayload: options?.onPayload,\n\t\tonResponse: options?.onResponse,\n\t\ttimeoutMs: options?.timeoutMs,\n\t\twebsocketConnectTimeoutMs: options?.websocketConnectTimeoutMs,\n\t\tmaxRetries: options?.maxRetries,\n\t\tmaxRetryDelayMs: options?.maxRetryDelayMs,\n\t\tmetadata: options?.metadata,\n\t\tenv: options?.env,\n\t};\n}\n\nexport function clampReasoning(effort: ThinkingLevel | undefined): Exclude<ThinkingLevel, \"xhigh\" | \"max\"> | undefined {\n\treturn effort === \"xhigh\" || effort === \"max\" ? \"high\" : effort;\n}\n\nexport function adjustMaxTokensForThinking(\n\t// Undefined means no explicit caller cap. Use the model cap and fit thinking inside it.\n\tbaseMaxTokens: number | undefined,\n\tmodelMaxTokens: number,\n\treasoningLevel: ThinkingLevel,\n\tcustomBudgets?: ThinkingBudgets,\n): { maxTokens: number; thinkingBudget: number } {\n\tconst defaultBudgets: ThinkingBudgets = {\n\t\tminimal: 1024,\n\t\tlow: 2048,\n\t\tmedium: 8192,\n\t\thigh: 16384,\n\t};\n\tconst budgets = { ...defaultBudgets, ...customBudgets };\n\n\tconst minOutputTokens = 1024;\n\tconst level = clampReasoning(reasoningLevel)!;\n\tlet thinkingBudget = budgets[level]!;\n\tconst maxTokens =\n\t\tbaseMaxTokens === undefined ? modelMaxTokens : Math.min(baseMaxTokens + thinkingBudget, modelMaxTokens);\n\n\tif (maxTokens <= thinkingBudget) {\n\t\tthinkingBudget = Math.max(0, maxTokens - minOutputTokens);\n\t}\n\n\treturn { maxTokens, thinkingBudget };\n}\n"]}
1
+ {"version":3,"file":"simple-options.d.ts","sourceRoot":"","sources":["../../src/api/simple-options.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,GAAG,EACH,OAAO,EACP,KAAK,EACL,mBAAmB,EACnB,aAAa,EACb,eAAe,EACf,aAAa,EACb,MAAM,aAAa,CAAC;AAMrB,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAItG;AAED,wBAAgB,gBAAgB,CAC/B,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EACjB,OAAO,EAAE,OAAO,EAChB,OAAO,CAAC,EAAE,mBAAmB,EAC7B,MAAM,CAAC,EAAE,MAAM,GACb,aAAa,CA0Bf;AAED,4FAA4F;AAC5F,eAAO,MAAM,iBAAiB,OAAO,CAAC;AAEtC,wBAAgB,cAAc,CAAC,MAAM,EAAE,aAAa,GAAG,SAAS,GAAG,OAAO,CAAC,aAAa,EAAE,OAAO,GAAG,KAAK,CAAC,GAAG,SAAS,CAErH;AAED,wBAAgB,0BAA0B,CAEzC,aAAa,EAAE,MAAM,GAAG,SAAS,EACjC,cAAc,EAAE,MAAM,EACtB,cAAc,EAAE,aAAa,EAC7B,aAAa,CAAC,EAAE,eAAe,GAC7B;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,MAAM,CAAA;CAAE,CAmB/C","sourcesContent":["import type {\n\tApi,\n\tContext,\n\tModel,\n\tSimpleStreamOptions,\n\tStreamOptions,\n\tThinkingBudgets,\n\tThinkingLevel,\n} from \"../types.ts\";\nimport { estimateContextTokens } from \"../utils/estimate.ts\";\n\nconst CONTEXT_SAFETY_TOKENS = 4096;\nconst MIN_MAX_TOKENS = 1;\n\nexport function clampMaxTokensToContext(model: Model<Api>, context: Context, maxTokens: number): number {\n\tif (model.contextWindow <= 0) return Math.max(MIN_MAX_TOKENS, maxTokens);\n\tconst available = model.contextWindow - estimateContextTokens(context).tokens - CONTEXT_SAFETY_TOKENS;\n\treturn Math.min(maxTokens, Math.max(MIN_MAX_TOKENS, available));\n}\n\nexport function buildBaseOptions(\n\tmodel: Model<Api>,\n\tcontext: Context,\n\toptions?: SimpleStreamOptions,\n\tapiKey?: string,\n): StreamOptions {\n\tconst samplingParams =\n\t\tmodel.samplingParams || options?.samplingParams\n\t\t\t? { ...model.samplingParams, ...options?.samplingParams }\n\t\t\t: undefined;\n\treturn {\n\t\ttemperature: options?.temperature,\n\t\tsamplingParams,\n\t\tmaxTokens: clampMaxTokensToContext(model, context, options?.maxTokens ?? model.maxTokens),\n\t\tsignal: options?.signal,\n\t\ttelemetryContext: options?.telemetryContext,\n\t\tapiKey: apiKey || options?.apiKey,\n\t\tfetch: options?.fetch,\n\t\ttransport: options?.transport,\n\t\tcacheRetention: options?.cacheRetention,\n\t\tsessionId: options?.sessionId,\n\t\theaders: options?.headers,\n\t\tonPayload: options?.onPayload,\n\t\tonResponse: options?.onResponse,\n\t\ttimeoutMs: options?.timeoutMs,\n\t\twebsocketConnectTimeoutMs: options?.websocketConnectTimeoutMs,\n\t\tmaxRetries: options?.maxRetries,\n\t\tmaxRetryDelayMs: options?.maxRetryDelayMs,\n\t\tmetadata: options?.metadata,\n\t\tenv: options?.env,\n\t};\n}\n\n/** Tokens always left for the answer when a thinking budget shares the response ceiling. */\nexport const MIN_ANSWER_TOKENS = 1024;\n\nexport function clampReasoning(effort: ThinkingLevel | undefined): Exclude<ThinkingLevel, \"xhigh\" | \"max\"> | undefined {\n\treturn effort === \"xhigh\" || effort === \"max\" ? \"high\" : effort;\n}\n\nexport function adjustMaxTokensForThinking(\n\t// Undefined means no explicit caller cap. Use the model cap and fit thinking inside it.\n\tbaseMaxTokens: number | undefined,\n\tmodelMaxTokens: number,\n\treasoningLevel: ThinkingLevel,\n\tcustomBudgets?: ThinkingBudgets,\n): { maxTokens: number; thinkingBudget: number } {\n\tconst defaultBudgets: ThinkingBudgets = {\n\t\tminimal: 1024,\n\t\tlow: 2048,\n\t\tmedium: 8192,\n\t\thigh: 16384,\n\t};\n\tconst budgets = { ...defaultBudgets, ...customBudgets };\n\n\tconst level = clampReasoning(reasoningLevel)!;\n\tlet thinkingBudget = budgets[level]!;\n\tconst maxTokens =\n\t\tbaseMaxTokens === undefined ? modelMaxTokens : Math.min(baseMaxTokens + thinkingBudget, modelMaxTokens);\n\n\tif (maxTokens <= thinkingBudget) {\n\t\tthinkingBudget = Math.max(0, maxTokens - MIN_ANSWER_TOKENS);\n\t}\n\n\treturn { maxTokens, thinkingBudget };\n}\n"]}
@@ -8,10 +8,15 @@ export function clampMaxTokensToContext(model, context, maxTokens) {
8
8
  return Math.min(maxTokens, Math.max(MIN_MAX_TOKENS, available));
9
9
  }
10
10
  export function buildBaseOptions(model, context, options, apiKey) {
11
+ const samplingParams = model.samplingParams || options?.samplingParams
12
+ ? { ...model.samplingParams, ...options?.samplingParams }
13
+ : undefined;
11
14
  return {
12
15
  temperature: options?.temperature,
16
+ samplingParams,
13
17
  maxTokens: clampMaxTokensToContext(model, context, options?.maxTokens ?? model.maxTokens),
14
18
  signal: options?.signal,
19
+ telemetryContext: options?.telemetryContext,
15
20
  apiKey: apiKey || options?.apiKey,
16
21
  fetch: options?.fetch,
17
22
  transport: options?.transport,
@@ -28,6 +33,8 @@ export function buildBaseOptions(model, context, options, apiKey) {
28
33
  env: options?.env,
29
34
  };
30
35
  }
36
+ /** Tokens always left for the answer when a thinking budget shares the response ceiling. */
37
+ export const MIN_ANSWER_TOKENS = 1024;
31
38
  export function clampReasoning(effort) {
32
39
  return effort === "xhigh" || effort === "max" ? "high" : effort;
33
40
  }
@@ -41,12 +48,11 @@ baseMaxTokens, modelMaxTokens, reasoningLevel, customBudgets) {
41
48
  high: 16384,
42
49
  };
43
50
  const budgets = { ...defaultBudgets, ...customBudgets };
44
- const minOutputTokens = 1024;
45
51
  const level = clampReasoning(reasoningLevel);
46
52
  let thinkingBudget = budgets[level];
47
53
  const maxTokens = baseMaxTokens === undefined ? modelMaxTokens : Math.min(baseMaxTokens + thinkingBudget, modelMaxTokens);
48
54
  if (maxTokens <= thinkingBudget) {
49
- thinkingBudget = Math.max(0, maxTokens - minOutputTokens);
55
+ thinkingBudget = Math.max(0, maxTokens - MIN_ANSWER_TOKENS);
50
56
  }
51
57
  return { maxTokens, thinkingBudget };
52
58
  }
@@ -1 +1 @@
1
- {"version":3,"file":"simple-options.js","sourceRoot":"","sources":["../../src/api/simple-options.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAE7D,MAAM,qBAAqB,GAAG,IAAI,CAAC;AACnC,MAAM,cAAc,GAAG,CAAC,CAAC;AAEzB,MAAM,UAAU,uBAAuB,CAAC,KAAiB,EAAE,OAAgB,EAAE,SAAiB,EAAU;IACvG,IAAI,KAAK,CAAC,aAAa,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC,GAAG,CAAC,cAAc,EAAE,SAAS,CAAC,CAAC;IACzE,MAAM,SAAS,GAAG,KAAK,CAAC,aAAa,GAAG,qBAAqB,CAAC,OAAO,CAAC,CAAC,MAAM,GAAG,qBAAqB,CAAC;IACtG,OAAO,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC,GAAG,CAAC,cAAc,EAAE,SAAS,CAAC,CAAC,CAAC;AAAA,CAChE;AAED,MAAM,UAAU,gBAAgB,CAC/B,KAAiB,EACjB,OAAgB,EAChB,OAA6B,EAC7B,MAAe,EACC;IAChB,OAAO;QACN,WAAW,EAAE,OAAO,EAAE,WAAW;QACjC,SAAS,EAAE,uBAAuB,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,IAAI,KAAK,CAAC,SAAS,CAAC;QACzF,MAAM,EAAE,OAAO,EAAE,MAAM;QACvB,MAAM,EAAE,MAAM,IAAI,OAAO,EAAE,MAAM;QACjC,KAAK,EAAE,OAAO,EAAE,KAAK;QACrB,SAAS,EAAE,OAAO,EAAE,SAAS;QAC7B,cAAc,EAAE,OAAO,EAAE,cAAc;QACvC,SAAS,EAAE,OAAO,EAAE,SAAS;QAC7B,OAAO,EAAE,OAAO,EAAE,OAAO;QACzB,SAAS,EAAE,OAAO,EAAE,SAAS;QAC7B,UAAU,EAAE,OAAO,EAAE,UAAU;QAC/B,SAAS,EAAE,OAAO,EAAE,SAAS;QAC7B,yBAAyB,EAAE,OAAO,EAAE,yBAAyB;QAC7D,UAAU,EAAE,OAAO,EAAE,UAAU;QAC/B,eAAe,EAAE,OAAO,EAAE,eAAe;QACzC,QAAQ,EAAE,OAAO,EAAE,QAAQ;QAC3B,GAAG,EAAE,OAAO,EAAE,GAAG;KACjB,CAAC;AAAA,CACF;AAED,MAAM,UAAU,cAAc,CAAC,MAAiC,EAAuD;IACtH,OAAO,MAAM,KAAK,OAAO,IAAI,MAAM,KAAK,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC;AAAA,CAChE;AAED,MAAM,UAAU,0BAA0B;AACzC,wFAAwF;AACxF,aAAiC,EACjC,cAAsB,EACtB,cAA6B,EAC7B,aAA+B,EACiB;IAChD,MAAM,cAAc,GAAoB;QACvC,OAAO,EAAE,IAAI;QACb,GAAG,EAAE,IAAI;QACT,MAAM,EAAE,IAAI;QACZ,IAAI,EAAE,KAAK;KACX,CAAC;IACF,MAAM,OAAO,GAAG,EAAE,GAAG,cAAc,EAAE,GAAG,aAAa,EAAE,CAAC;IAExD,MAAM,eAAe,GAAG,IAAI,CAAC;IAC7B,MAAM,KAAK,GAAG,cAAc,CAAC,cAAc,CAAE,CAAC;IAC9C,IAAI,cAAc,GAAG,OAAO,CAAC,KAAK,CAAE,CAAC;IACrC,MAAM,SAAS,GACd,aAAa,KAAK,SAAS,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,aAAa,GAAG,cAAc,EAAE,cAAc,CAAC,CAAC;IAEzG,IAAI,SAAS,IAAI,cAAc,EAAE,CAAC;QACjC,cAAc,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,GAAG,eAAe,CAAC,CAAC;IAC3D,CAAC;IAED,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,CAAC;AAAA,CACrC","sourcesContent":["import type {\n\tApi,\n\tContext,\n\tModel,\n\tSimpleStreamOptions,\n\tStreamOptions,\n\tThinkingBudgets,\n\tThinkingLevel,\n} from \"../types.ts\";\nimport { estimateContextTokens } from \"../utils/estimate.ts\";\n\nconst CONTEXT_SAFETY_TOKENS = 4096;\nconst MIN_MAX_TOKENS = 1;\n\nexport function clampMaxTokensToContext(model: Model<Api>, context: Context, maxTokens: number): number {\n\tif (model.contextWindow <= 0) return Math.max(MIN_MAX_TOKENS, maxTokens);\n\tconst available = model.contextWindow - estimateContextTokens(context).tokens - CONTEXT_SAFETY_TOKENS;\n\treturn Math.min(maxTokens, Math.max(MIN_MAX_TOKENS, available));\n}\n\nexport function buildBaseOptions(\n\tmodel: Model<Api>,\n\tcontext: Context,\n\toptions?: SimpleStreamOptions,\n\tapiKey?: string,\n): StreamOptions {\n\treturn {\n\t\ttemperature: options?.temperature,\n\t\tmaxTokens: clampMaxTokensToContext(model, context, options?.maxTokens ?? model.maxTokens),\n\t\tsignal: options?.signal,\n\t\tapiKey: apiKey || options?.apiKey,\n\t\tfetch: options?.fetch,\n\t\ttransport: options?.transport,\n\t\tcacheRetention: options?.cacheRetention,\n\t\tsessionId: options?.sessionId,\n\t\theaders: options?.headers,\n\t\tonPayload: options?.onPayload,\n\t\tonResponse: options?.onResponse,\n\t\ttimeoutMs: options?.timeoutMs,\n\t\twebsocketConnectTimeoutMs: options?.websocketConnectTimeoutMs,\n\t\tmaxRetries: options?.maxRetries,\n\t\tmaxRetryDelayMs: options?.maxRetryDelayMs,\n\t\tmetadata: options?.metadata,\n\t\tenv: options?.env,\n\t};\n}\n\nexport function clampReasoning(effort: ThinkingLevel | undefined): Exclude<ThinkingLevel, \"xhigh\" | \"max\"> | undefined {\n\treturn effort === \"xhigh\" || effort === \"max\" ? \"high\" : effort;\n}\n\nexport function adjustMaxTokensForThinking(\n\t// Undefined means no explicit caller cap. Use the model cap and fit thinking inside it.\n\tbaseMaxTokens: number | undefined,\n\tmodelMaxTokens: number,\n\treasoningLevel: ThinkingLevel,\n\tcustomBudgets?: ThinkingBudgets,\n): { maxTokens: number; thinkingBudget: number } {\n\tconst defaultBudgets: ThinkingBudgets = {\n\t\tminimal: 1024,\n\t\tlow: 2048,\n\t\tmedium: 8192,\n\t\thigh: 16384,\n\t};\n\tconst budgets = { ...defaultBudgets, ...customBudgets };\n\n\tconst minOutputTokens = 1024;\n\tconst level = clampReasoning(reasoningLevel)!;\n\tlet thinkingBudget = budgets[level]!;\n\tconst maxTokens =\n\t\tbaseMaxTokens === undefined ? modelMaxTokens : Math.min(baseMaxTokens + thinkingBudget, modelMaxTokens);\n\n\tif (maxTokens <= thinkingBudget) {\n\t\tthinkingBudget = Math.max(0, maxTokens - minOutputTokens);\n\t}\n\n\treturn { maxTokens, thinkingBudget };\n}\n"]}
1
+ {"version":3,"file":"simple-options.js","sourceRoot":"","sources":["../../src/api/simple-options.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n\tApi,\n\tContext,\n\tModel,\n\tSimpleStreamOptions,\n\tStreamOptions,\n\tThinkingBudgets,\n\tThinkingLevel,\n} from \"../types.ts\";\nimport { estimateContextTokens } from \"../utils/estimate.ts\";\n\nconst CONTEXT_SAFETY_TOKENS = 4096;\nconst MIN_MAX_TOKENS = 1;\n\nexport function clampMaxTokensToContext(model: Model<Api>, context: Context, maxTokens: number): number {\n\tif (model.contextWindow <= 0) return Math.max(MIN_MAX_TOKENS, maxTokens);\n\tconst available = model.contextWindow - estimateContextTokens(context).tokens - CONTEXT_SAFETY_TOKENS;\n\treturn Math.min(maxTokens, Math.max(MIN_MAX_TOKENS, available));\n}\n\nexport function buildBaseOptions(\n\tmodel: Model<Api>,\n\tcontext: Context,\n\toptions?: SimpleStreamOptions,\n\tapiKey?: string,\n): StreamOptions {\n\tconst samplingParams =\n\t\tmodel.samplingParams || options?.samplingParams\n\t\t\t? { ...model.samplingParams, ...options?.samplingParams }\n\t\t\t: undefined;\n\treturn {\n\t\ttemperature: options?.temperature,\n\t\tsamplingParams,\n\t\tmaxTokens: clampMaxTokensToContext(model, context, options?.maxTokens ?? model.maxTokens),\n\t\tsignal: options?.signal,\n\t\ttelemetryContext: options?.telemetryContext,\n\t\tapiKey: apiKey || options?.apiKey,\n\t\tfetch: options?.fetch,\n\t\ttransport: options?.transport,\n\t\tcacheRetention: options?.cacheRetention,\n\t\tsessionId: options?.sessionId,\n\t\theaders: options?.headers,\n\t\tonPayload: options?.onPayload,\n\t\tonResponse: options?.onResponse,\n\t\ttimeoutMs: options?.timeoutMs,\n\t\twebsocketConnectTimeoutMs: options?.websocketConnectTimeoutMs,\n\t\tmaxRetries: options?.maxRetries,\n\t\tmaxRetryDelayMs: options?.maxRetryDelayMs,\n\t\tmetadata: options?.metadata,\n\t\tenv: options?.env,\n\t};\n}\n\n/** Tokens always left for the answer when a thinking budget shares the response ceiling. */\nexport const MIN_ANSWER_TOKENS = 1024;\n\nexport function clampReasoning(effort: ThinkingLevel | undefined): Exclude<ThinkingLevel, \"xhigh\" | \"max\"> | undefined {\n\treturn effort === \"xhigh\" || effort === \"max\" ? \"high\" : effort;\n}\n\nexport function adjustMaxTokensForThinking(\n\t// Undefined means no explicit caller cap. Use the model cap and fit thinking inside it.\n\tbaseMaxTokens: number | undefined,\n\tmodelMaxTokens: number,\n\treasoningLevel: ThinkingLevel,\n\tcustomBudgets?: ThinkingBudgets,\n): { maxTokens: number; thinkingBudget: number } {\n\tconst defaultBudgets: ThinkingBudgets = {\n\t\tminimal: 1024,\n\t\tlow: 2048,\n\t\tmedium: 8192,\n\t\thigh: 16384,\n\t};\n\tconst budgets = { ...defaultBudgets, ...customBudgets };\n\n\tconst level = clampReasoning(reasoningLevel)!;\n\tlet thinkingBudget = budgets[level]!;\n\tconst maxTokens =\n\t\tbaseMaxTokens === undefined ? modelMaxTokens : Math.min(baseMaxTokens + thinkingBudget, modelMaxTokens);\n\n\tif (maxTokens <= thinkingBudget) {\n\t\tthinkingBudget = Math.max(0, maxTokens - MIN_ANSWER_TOKENS);\n\t}\n\n\treturn { maxTokens, thinkingBudget };\n}\n"]}
@@ -1,4 +1,4 @@
1
- import type { Credential, CredentialInfo, CredentialStore } from "./types.ts";
1
+ import type { AuthOperationOptions, Credential, CredentialInfo, CredentialStore } from "./types.ts";
2
2
  /**
3
3
  * Default in-memory credential store. Apps inject persistent stores.
4
4
  * Keyed by `Provider.id`, one credential per provider; see `CredentialStore`.
@@ -7,11 +7,11 @@ import type { Credential, CredentialInfo, CredentialStore } from "./types.ts";
7
7
  export declare class InMemoryCredentialStore implements CredentialStore {
8
8
  private credentials;
9
9
  private chains;
10
- /** Serialize tasks per provider id. */
10
+ /** Serialize tasks per provider id without releasing the chain before active work settles. */
11
11
  private enqueue;
12
- read(providerId: string): Promise<Credential | undefined>;
13
- list(): Promise<readonly CredentialInfo[]>;
14
- modify(providerId: string, fn: (current: Credential | undefined) => Promise<Credential | undefined>): Promise<Credential | undefined>;
15
- delete(providerId: string): Promise<void>;
12
+ read(providerId: string, options?: AuthOperationOptions): Promise<Credential | undefined>;
13
+ list(options?: AuthOperationOptions): Promise<readonly CredentialInfo[]>;
14
+ modify(providerId: string, fn: (current: Credential | undefined) => Promise<Credential | undefined>, options?: AuthOperationOptions): Promise<Credential | undefined>;
15
+ delete(providerId: string, options?: AuthOperationOptions): Promise<void>;
16
16
  }
17
17
  //# sourceMappingURL=credential-store.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"credential-store.d.ts","sourceRoot":"","sources":["../../src/auth/credential-store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAE9E;;;;GAIG;AACH,qBAAa,uBAAwB,YAAW,eAAe;IAC9D,OAAO,CAAC,WAAW,CAAiC;IACpD,OAAO,CAAC,MAAM,CAAuC;IAErD,uCAAuC;IACvC,OAAO,CAAC,OAAO;IAaT,IAAI,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAE9D;IAEK,IAAI,IAAI,OAAO,CAAC,SAAS,cAAc,EAAE,CAAC,CAE/C;IAED,MAAM,CACL,UAAU,EAAE,MAAM,EAClB,EAAE,EAAE,CAAC,OAAO,EAAE,UAAU,GAAG,SAAS,KAAK,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,GACtE,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAOjC;IAED,MAAM,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAIxC;CACD","sourcesContent":["import type { Credential, CredentialInfo, CredentialStore } from \"./types.ts\";\n\n/**\n * Default in-memory credential store. Apps inject persistent stores.\n * Keyed by `Provider.id`, one credential per provider; see `CredentialStore`.\n * Writes are serialized per provider through a promise chain.\n */\nexport class InMemoryCredentialStore implements CredentialStore {\n\tprivate credentials = new Map<string, Credential>();\n\tprivate chains = new Map<string, Promise<unknown>>();\n\n\t/** Serialize tasks per provider id. */\n\tprivate enqueue<T>(providerId: string, task: () => Promise<T>): Promise<T> {\n\t\tconst previous = this.chains.get(providerId) ?? Promise.resolve();\n\t\tconst next = (async () => {\n\t\t\tawait previous.catch(() => {});\n\t\t\treturn task();\n\t\t})();\n\t\tthis.chains.set(\n\t\t\tproviderId,\n\t\t\tnext.catch(() => {}),\n\t\t);\n\t\treturn next;\n\t}\n\n\tasync read(providerId: string): Promise<Credential | undefined> {\n\t\treturn this.credentials.get(providerId);\n\t}\n\n\tasync list(): Promise<readonly CredentialInfo[]> {\n\t\treturn [...this.credentials].map(([providerId, credential]) => ({ providerId, type: credential.type }));\n\t}\n\n\tmodify(\n\t\tproviderId: string,\n\t\tfn: (current: Credential | undefined) => Promise<Credential | undefined>,\n\t): Promise<Credential | undefined> {\n\t\treturn this.enqueue(providerId, async () => {\n\t\t\tconst current = this.credentials.get(providerId);\n\t\t\tconst next = await fn(current);\n\t\t\tif (next !== undefined) this.credentials.set(providerId, next);\n\t\t\treturn next ?? current;\n\t\t});\n\t}\n\n\tdelete(providerId: string): Promise<void> {\n\t\treturn this.enqueue(providerId, async () => {\n\t\t\tthis.credentials.delete(providerId);\n\t\t});\n\t}\n}\n"]}
1
+ {"version":3,"file":"credential-store.d.ts","sourceRoot":"","sources":["../../src/auth/credential-store.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,oBAAoB,EAAE,UAAU,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAEpG;;;;GAIG;AACH,qBAAa,uBAAwB,YAAW,eAAe;IAC9D,OAAO,CAAC,WAAW,CAAiC;IACpD,OAAO,CAAC,MAAM,CAAuC;IAErD,8FAA8F;IAC9F,OAAO,CAAC,OAAO;IAgBT,IAAI,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAG9F;IAEK,IAAI,CAAC,OAAO,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,SAAS,cAAc,EAAE,CAAC,CAG7E;IAED,MAAM,CACL,UAAU,EAAE,MAAM,EAClB,EAAE,EAAE,CAAC,OAAO,EAAE,UAAU,GAAG,SAAS,KAAK,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,EACxE,OAAO,CAAC,EAAE,oBAAoB,GAC5B,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAYjC;IAED,MAAM,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,CAQxE;CACD","sourcesContent":["import { operationSignal, raceWithAbortSignal } from \"../utils/abort.ts\";\nimport type { AuthOperationOptions, Credential, CredentialInfo, CredentialStore } from \"./types.ts\";\n\n/**\n * Default in-memory credential store. Apps inject persistent stores.\n * Keyed by `Provider.id`, one credential per provider; see `CredentialStore`.\n * Writes are serialized per provider through a promise chain.\n */\nexport class InMemoryCredentialStore implements CredentialStore {\n\tprivate credentials = new Map<string, Credential>();\n\tprivate chains = new Map<string, Promise<unknown>>();\n\n\t/** Serialize tasks per provider id without releasing the chain before active work settles. */\n\tprivate enqueue<T>(providerId: string, task: () => Promise<T>, options?: AuthOperationOptions): Promise<T> {\n\t\tconst signal = operationSignal(options?.signal);\n\t\tconst previous = this.chains.get(providerId) ?? Promise.resolve();\n\t\tconst queued = (async () => {\n\t\t\tawait previous.catch(() => {});\n\t\t\tsignal.throwIfAborted();\n\t\t\treturn task();\n\t\t})();\n\t\tconst tail = queued.catch(() => {});\n\t\tthis.chains.set(providerId, tail);\n\t\tvoid tail.then(() => {\n\t\t\tif (this.chains.get(providerId) === tail) this.chains.delete(providerId);\n\t\t});\n\t\treturn raceWithAbortSignal(queued, signal);\n\t}\n\n\tasync read(providerId: string, options?: AuthOperationOptions): Promise<Credential | undefined> {\n\t\toptions?.signal?.throwIfAborted();\n\t\treturn this.credentials.get(providerId);\n\t}\n\n\tasync list(options?: AuthOperationOptions): Promise<readonly CredentialInfo[]> {\n\t\toptions?.signal?.throwIfAborted();\n\t\treturn [...this.credentials].map(([providerId, credential]) => ({ providerId, type: credential.type }));\n\t}\n\n\tmodify(\n\t\tproviderId: string,\n\t\tfn: (current: Credential | undefined) => Promise<Credential | undefined>,\n\t\toptions?: AuthOperationOptions,\n\t): Promise<Credential | undefined> {\n\t\treturn this.enqueue(\n\t\t\tproviderId,\n\t\t\tasync () => {\n\t\t\t\tconst current = this.credentials.get(providerId);\n\t\t\t\tconst next = await fn(current);\n\t\t\t\toptions?.signal?.throwIfAborted();\n\t\t\t\tif (next !== undefined) this.credentials.set(providerId, next);\n\t\t\t\treturn next ?? current;\n\t\t\t},\n\t\t\toptions,\n\t\t);\n\t}\n\n\tdelete(providerId: string, options?: AuthOperationOptions): Promise<void> {\n\t\treturn this.enqueue(\n\t\t\tproviderId,\n\t\t\tasync () => {\n\t\t\t\tthis.credentials.delete(providerId);\n\t\t\t},\n\t\t\toptions,\n\t\t);\n\t}\n}\n"]}
@@ -1,3 +1,4 @@
1
+ import { operationSignal, raceWithAbortSignal } from "../utils/abort.js";
1
2
  /**
2
3
  * Default in-memory credential store. Apps inject persistent stores.
3
4
  * Keyed by `Provider.id`, one credential per provider; see `CredentialStore`.
@@ -6,35 +7,45 @@
6
7
  export class InMemoryCredentialStore {
7
8
  credentials = new Map();
8
9
  chains = new Map();
9
- /** Serialize tasks per provider id. */
10
- enqueue(providerId, task) {
10
+ /** Serialize tasks per provider id without releasing the chain before active work settles. */
11
+ enqueue(providerId, task, options) {
12
+ const signal = operationSignal(options?.signal);
11
13
  const previous = this.chains.get(providerId) ?? Promise.resolve();
12
- const next = (async () => {
14
+ const queued = (async () => {
13
15
  await previous.catch(() => { });
16
+ signal.throwIfAborted();
14
17
  return task();
15
18
  })();
16
- this.chains.set(providerId, next.catch(() => { }));
17
- return next;
19
+ const tail = queued.catch(() => { });
20
+ this.chains.set(providerId, tail);
21
+ void tail.then(() => {
22
+ if (this.chains.get(providerId) === tail)
23
+ this.chains.delete(providerId);
24
+ });
25
+ return raceWithAbortSignal(queued, signal);
18
26
  }
19
- async read(providerId) {
27
+ async read(providerId, options) {
28
+ options?.signal?.throwIfAborted();
20
29
  return this.credentials.get(providerId);
21
30
  }
22
- async list() {
31
+ async list(options) {
32
+ options?.signal?.throwIfAborted();
23
33
  return [...this.credentials].map(([providerId, credential]) => ({ providerId, type: credential.type }));
24
34
  }
25
- modify(providerId, fn) {
35
+ modify(providerId, fn, options) {
26
36
  return this.enqueue(providerId, async () => {
27
37
  const current = this.credentials.get(providerId);
28
38
  const next = await fn(current);
39
+ options?.signal?.throwIfAborted();
29
40
  if (next !== undefined)
30
41
  this.credentials.set(providerId, next);
31
42
  return next ?? current;
32
- });
43
+ }, options);
33
44
  }
34
- delete(providerId) {
45
+ delete(providerId, options) {
35
46
  return this.enqueue(providerId, async () => {
36
47
  this.credentials.delete(providerId);
37
- });
48
+ }, options);
38
49
  }
39
50
  }
40
51
  //# sourceMappingURL=credential-store.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"credential-store.js","sourceRoot":"","sources":["../../src/auth/credential-store.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,MAAM,OAAO,uBAAuB;IAC3B,WAAW,GAAG,IAAI,GAAG,EAAsB,CAAC;IAC5C,MAAM,GAAG,IAAI,GAAG,EAA4B,CAAC;IAErD,uCAAuC;IAC/B,OAAO,CAAI,UAAkB,EAAE,IAAsB,EAAc;QAC1E,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;QAClE,MAAM,IAAI,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC;YACzB,MAAM,QAAQ,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAC,CAAC,CAAC,CAAC;YAC/B,OAAO,IAAI,EAAE,CAAC;QAAA,CACd,CAAC,EAAE,CAAC;QACL,IAAI,CAAC,MAAM,CAAC,GAAG,CACd,UAAU,EACV,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAC,CAAC,CAAC,CACpB,CAAC;QACF,OAAO,IAAI,CAAC;IAAA,CACZ;IAED,KAAK,CAAC,IAAI,CAAC,UAAkB,EAAmC;QAC/D,OAAO,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IAAA,CACxC;IAED,KAAK,CAAC,IAAI,GAAuC;QAChD,OAAO,CAAC,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,EAAE,UAAU,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IAAA,CACxG;IAED,MAAM,CACL,UAAkB,EAClB,EAAwE,EACtC;QAClC,OAAO,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,KAAK,IAAI,EAAE,CAAC;YAC3C,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;YACjD,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,CAAC;YAC/B,IAAI,IAAI,KAAK,SAAS;gBAAE,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;YAC/D,OAAO,IAAI,IAAI,OAAO,CAAC;QAAA,CACvB,CAAC,CAAC;IAAA,CACH;IAED,MAAM,CAAC,UAAkB,EAAiB;QACzC,OAAO,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,KAAK,IAAI,EAAE,CAAC;YAC3C,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QAAA,CACpC,CAAC,CAAC;IAAA,CACH;CACD","sourcesContent":["import type { Credential, CredentialInfo, CredentialStore } from \"./types.ts\";\n\n/**\n * Default in-memory credential store. Apps inject persistent stores.\n * Keyed by `Provider.id`, one credential per provider; see `CredentialStore`.\n * Writes are serialized per provider through a promise chain.\n */\nexport class InMemoryCredentialStore implements CredentialStore {\n\tprivate credentials = new Map<string, Credential>();\n\tprivate chains = new Map<string, Promise<unknown>>();\n\n\t/** Serialize tasks per provider id. */\n\tprivate enqueue<T>(providerId: string, task: () => Promise<T>): Promise<T> {\n\t\tconst previous = this.chains.get(providerId) ?? Promise.resolve();\n\t\tconst next = (async () => {\n\t\t\tawait previous.catch(() => {});\n\t\t\treturn task();\n\t\t})();\n\t\tthis.chains.set(\n\t\t\tproviderId,\n\t\t\tnext.catch(() => {}),\n\t\t);\n\t\treturn next;\n\t}\n\n\tasync read(providerId: string): Promise<Credential | undefined> {\n\t\treturn this.credentials.get(providerId);\n\t}\n\n\tasync list(): Promise<readonly CredentialInfo[]> {\n\t\treturn [...this.credentials].map(([providerId, credential]) => ({ providerId, type: credential.type }));\n\t}\n\n\tmodify(\n\t\tproviderId: string,\n\t\tfn: (current: Credential | undefined) => Promise<Credential | undefined>,\n\t): Promise<Credential | undefined> {\n\t\treturn this.enqueue(providerId, async () => {\n\t\t\tconst current = this.credentials.get(providerId);\n\t\t\tconst next = await fn(current);\n\t\t\tif (next !== undefined) this.credentials.set(providerId, next);\n\t\t\treturn next ?? current;\n\t\t});\n\t}\n\n\tdelete(providerId: string): Promise<void> {\n\t\treturn this.enqueue(providerId, async () => {\n\t\t\tthis.credentials.delete(providerId);\n\t\t});\n\t}\n}\n"]}
1
+ {"version":3,"file":"credential-store.js","sourceRoot":"","sources":["../../src/auth/credential-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAGzE;;;;GAIG;AACH,MAAM,OAAO,uBAAuB;IAC3B,WAAW,GAAG,IAAI,GAAG,EAAsB,CAAC;IAC5C,MAAM,GAAG,IAAI,GAAG,EAA4B,CAAC;IAErD,8FAA8F;IACtF,OAAO,CAAI,UAAkB,EAAE,IAAsB,EAAE,OAA8B,EAAc;QAC1G,MAAM,MAAM,GAAG,eAAe,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAChD,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;QAClE,MAAM,MAAM,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC;YAC3B,MAAM,QAAQ,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAC,CAAC,CAAC,CAAC;YAC/B,MAAM,CAAC,cAAc,EAAE,CAAC;YACxB,OAAO,IAAI,EAAE,CAAC;QAAA,CACd,CAAC,EAAE,CAAC;QACL,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAC,CAAC,CAAC,CAAC;QACpC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;QAClC,KAAK,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;YACpB,IAAI,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,IAAI;gBAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QAAA,CACzE,CAAC,CAAC;QACH,OAAO,mBAAmB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAAA,CAC3C;IAED,KAAK,CAAC,IAAI,CAAC,UAAkB,EAAE,OAA8B,EAAmC;QAC/F,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,CAAC;QAClC,OAAO,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IAAA,CACxC;IAED,KAAK,CAAC,IAAI,CAAC,OAA8B,EAAsC;QAC9E,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,CAAC;QAClC,OAAO,CAAC,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,EAAE,UAAU,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IAAA,CACxG;IAED,MAAM,CACL,UAAkB,EAClB,EAAwE,EACxE,OAA8B,EACI;QAClC,OAAO,IAAI,CAAC,OAAO,CAClB,UAAU,EACV,KAAK,IAAI,EAAE,CAAC;YACX,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;YACjD,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,CAAC;YAC/B,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,CAAC;YAClC,IAAI,IAAI,KAAK,SAAS;gBAAE,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;YAC/D,OAAO,IAAI,IAAI,OAAO,CAAC;QAAA,CACvB,EACD,OAAO,CACP,CAAC;IAAA,CACF;IAED,MAAM,CAAC,UAAkB,EAAE,OAA8B,EAAiB;QACzE,OAAO,IAAI,CAAC,OAAO,CAClB,UAAU,EACV,KAAK,IAAI,EAAE,CAAC;YACX,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QAAA,CACpC,EACD,OAAO,CACP,CAAC;IAAA,CACF;CACD","sourcesContent":["import { operationSignal, raceWithAbortSignal } from \"../utils/abort.ts\";\nimport type { AuthOperationOptions, Credential, CredentialInfo, CredentialStore } from \"./types.ts\";\n\n/**\n * Default in-memory credential store. Apps inject persistent stores.\n * Keyed by `Provider.id`, one credential per provider; see `CredentialStore`.\n * Writes are serialized per provider through a promise chain.\n */\nexport class InMemoryCredentialStore implements CredentialStore {\n\tprivate credentials = new Map<string, Credential>();\n\tprivate chains = new Map<string, Promise<unknown>>();\n\n\t/** Serialize tasks per provider id without releasing the chain before active work settles. */\n\tprivate enqueue<T>(providerId: string, task: () => Promise<T>, options?: AuthOperationOptions): Promise<T> {\n\t\tconst signal = operationSignal(options?.signal);\n\t\tconst previous = this.chains.get(providerId) ?? Promise.resolve();\n\t\tconst queued = (async () => {\n\t\t\tawait previous.catch(() => {});\n\t\t\tsignal.throwIfAborted();\n\t\t\treturn task();\n\t\t})();\n\t\tconst tail = queued.catch(() => {});\n\t\tthis.chains.set(providerId, tail);\n\t\tvoid tail.then(() => {\n\t\t\tif (this.chains.get(providerId) === tail) this.chains.delete(providerId);\n\t\t});\n\t\treturn raceWithAbortSignal(queued, signal);\n\t}\n\n\tasync read(providerId: string, options?: AuthOperationOptions): Promise<Credential | undefined> {\n\t\toptions?.signal?.throwIfAborted();\n\t\treturn this.credentials.get(providerId);\n\t}\n\n\tasync list(options?: AuthOperationOptions): Promise<readonly CredentialInfo[]> {\n\t\toptions?.signal?.throwIfAborted();\n\t\treturn [...this.credentials].map(([providerId, credential]) => ({ providerId, type: credential.type }));\n\t}\n\n\tmodify(\n\t\tproviderId: string,\n\t\tfn: (current: Credential | undefined) => Promise<Credential | undefined>,\n\t\toptions?: AuthOperationOptions,\n\t): Promise<Credential | undefined> {\n\t\treturn this.enqueue(\n\t\t\tproviderId,\n\t\t\tasync () => {\n\t\t\t\tconst current = this.credentials.get(providerId);\n\t\t\t\tconst next = await fn(current);\n\t\t\t\toptions?.signal?.throwIfAborted();\n\t\t\t\tif (next !== undefined) this.credentials.set(providerId, next);\n\t\t\t\treturn next ?? current;\n\t\t\t},\n\t\t\toptions,\n\t\t);\n\t}\n\n\tdelete(providerId: string, options?: AuthOperationOptions): Promise<void> {\n\t\treturn this.enqueue(\n\t\t\tproviderId,\n\t\t\tasync () => {\n\t\t\t\tthis.credentials.delete(providerId);\n\t\t\t},\n\t\t\toptions,\n\t\t);\n\t}\n}\n"]}
@@ -15,6 +15,7 @@ export declare function envApiKeyAuth(name: string, envVars: readonly string[]):
15
15
  */
16
16
  export declare function lazyOAuth(input: {
17
17
  name: string;
18
+ isSubscription?: boolean;
18
19
  loginLabel?: string;
19
20
  load: () => Promise<OAuthAuth>;
20
21
  }): OAuthAuth;
@@ -1 +1 @@
1
- {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../src/auth/helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAExD;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,MAAM,EAAE,GAAG,UAAU,CAkBlF;AAED;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,OAAO,CAAC,SAAS,CAAC,CAAA;CAAE,GAAG,SAAS,CAajH","sourcesContent":["import type { ApiKeyAuth, OAuthAuth } from \"./types.ts\";\n\n/**\n * Standard api-key auth: a stored credential key wins, otherwise the first\n * set env var resolves. Includes a `login` that prompts for the key.\n * Providers with non-standard resolution (provider env, ambient files, IAM)\n * write their own `ApiKeyAuth`.\n */\nexport function envApiKeyAuth(name: string, envVars: readonly string[]): ApiKeyAuth {\n\treturn {\n\t\tname,\n\t\tlogin: async (interaction) => {\n\t\t\tconst key = await interaction.prompt({ type: \"secret\", message: `Enter ${name}` });\n\t\t\treturn { type: \"api_key\", key };\n\t\t},\n\t\tresolve: async ({ ctx, credential }) => {\n\t\t\tif (credential?.key) {\n\t\t\t\treturn { auth: { apiKey: credential.key }, env: credential.env, source: \"stored credential\" };\n\t\t\t}\n\t\t\tfor (const envVar of envVars) {\n\t\t\t\tconst value = await ctx.env(envVar);\n\t\t\t\tif (value) return { auth: { apiKey: value }, source: envVar };\n\t\t\t}\n\t\t\treturn undefined;\n\t\t},\n\t};\n}\n\n/**\n * Wraps a dynamically imported `OAuthAuth` so provider definitions can\n * advertise OAuth without importing the implementation. The flow loads on\n * first `login`/`refresh`/`toAuth` call; callers keep Node-only flow code out\n * of bundles by loading through a bundler-opaque dynamic import (variable\n * specifier, see the bedrock lazy wrapper).\n */\nexport function lazyOAuth(input: { name: string; loginLabel?: string; load: () => Promise<OAuthAuth> }): OAuthAuth {\n\tlet promise: Promise<OAuthAuth> | undefined;\n\tconst loaded = () => {\n\t\tpromise ??= input.load();\n\t\treturn promise;\n\t};\n\treturn {\n\t\tname: input.name,\n\t\tloginLabel: input.loginLabel,\n\t\tlogin: async (interaction) => (await loaded()).login(interaction),\n\t\trefresh: async (credential) => (await loaded()).refresh(credential),\n\t\ttoAuth: async (credential) => (await loaded()).toAuth(credential),\n\t};\n}\n"]}
1
+ {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../src/auth/helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAExD;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,MAAM,EAAE,GAAG,UAAU,CAsBlF;AAED;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,OAAO,CAAC,SAAS,CAAC,CAAC;CAC/B,GAAG,SAAS,CAcZ","sourcesContent":["import type { ApiKeyAuth, OAuthAuth } from \"./types.ts\";\n\n/**\n * Standard api-key auth: a stored credential key wins, otherwise the first\n * set env var resolves. Includes a `login` that prompts for the key.\n * Providers with non-standard resolution (provider env, ambient files, IAM)\n * write their own `ApiKeyAuth`.\n */\nexport function envApiKeyAuth(name: string, envVars: readonly string[]): ApiKeyAuth {\n\treturn {\n\t\tname,\n\t\tlogin: async (interaction) => {\n\t\t\tinteraction.signal.throwIfAborted();\n\t\t\tconst key = await interaction.prompt({ type: \"secret\", message: `Enter ${name}` });\n\t\t\tinteraction.signal.throwIfAborted();\n\t\t\treturn { type: \"api_key\", key };\n\t\t},\n\t\tresolve: async ({ ctx, credential, signal }) => {\n\t\t\tsignal.throwIfAborted();\n\t\t\tif (credential?.key) {\n\t\t\t\treturn { auth: { apiKey: credential.key }, env: credential.env, source: \"stored credential\" };\n\t\t\t}\n\t\t\tfor (const envVar of envVars) {\n\t\t\t\tconst value = await ctx.env(envVar);\n\t\t\t\tsignal.throwIfAborted();\n\t\t\t\tif (value) return { auth: { apiKey: value }, source: envVar };\n\t\t\t}\n\t\t\treturn undefined;\n\t\t},\n\t};\n}\n\n/**\n * Wraps a dynamically imported `OAuthAuth` so provider definitions can\n * advertise OAuth without importing the implementation. The flow loads on\n * first `login`/`refresh`/`toAuth` call; callers keep Node-only flow code out\n * of bundles by loading through a bundler-opaque dynamic import (variable\n * specifier, see the bedrock lazy wrapper).\n */\nexport function lazyOAuth(input: {\n\tname: string;\n\tisSubscription?: boolean;\n\tloginLabel?: string;\n\tload: () => Promise<OAuthAuth>;\n}): OAuthAuth {\n\tlet promise: Promise<OAuthAuth> | undefined;\n\tconst loaded = () => {\n\t\tpromise ??= input.load();\n\t\treturn promise;\n\t};\n\treturn {\n\t\tname: input.name,\n\t\tisSubscription: input.isSubscription,\n\t\tloginLabel: input.loginLabel,\n\t\tlogin: async (interaction) => (await loaded()).login(interaction),\n\t\trefresh: async (credential, signal) => (await loaded()).refresh(credential, signal),\n\t\ttoAuth: async (credential) => (await loaded()).toAuth(credential),\n\t};\n}\n"]}
@@ -8,15 +8,19 @@ export function envApiKeyAuth(name, envVars) {
8
8
  return {
9
9
  name,
10
10
  login: async (interaction) => {
11
+ interaction.signal.throwIfAborted();
11
12
  const key = await interaction.prompt({ type: "secret", message: `Enter ${name}` });
13
+ interaction.signal.throwIfAborted();
12
14
  return { type: "api_key", key };
13
15
  },
14
- resolve: async ({ ctx, credential }) => {
16
+ resolve: async ({ ctx, credential, signal }) => {
17
+ signal.throwIfAborted();
15
18
  if (credential?.key) {
16
19
  return { auth: { apiKey: credential.key }, env: credential.env, source: "stored credential" };
17
20
  }
18
21
  for (const envVar of envVars) {
19
22
  const value = await ctx.env(envVar);
23
+ signal.throwIfAborted();
20
24
  if (value)
21
25
  return { auth: { apiKey: value }, source: envVar };
22
26
  }
@@ -39,9 +43,10 @@ export function lazyOAuth(input) {
39
43
  };
40
44
  return {
41
45
  name: input.name,
46
+ isSubscription: input.isSubscription,
42
47
  loginLabel: input.loginLabel,
43
48
  login: async (interaction) => (await loaded()).login(interaction),
44
- refresh: async (credential) => (await loaded()).refresh(credential),
49
+ refresh: async (credential, signal) => (await loaded()).refresh(credential, signal),
45
50
  toAuth: async (credential) => (await loaded()).toAuth(credential),
46
51
  };
47
52
  }
@@ -1 +1 @@
1
- {"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../src/auth/helpers.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,IAAY,EAAE,OAA0B,EAAc;IACnF,OAAO;QACN,IAAI;QACJ,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE,CAAC;YAC7B,MAAM,GAAG,GAAG,MAAM,WAAW,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,SAAS,IAAI,EAAE,EAAE,CAAC,CAAC;YACnF,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC;QAAA,CAChC;QACD,OAAO,EAAE,KAAK,EAAE,EAAE,GAAG,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC;YACvC,IAAI,UAAU,EAAE,GAAG,EAAE,CAAC;gBACrB,OAAO,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,UAAU,CAAC,GAAG,EAAE,EAAE,GAAG,EAAE,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,mBAAmB,EAAE,CAAC;YAC/F,CAAC;YACD,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;gBAC9B,MAAM,KAAK,GAAG,MAAM,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;gBACpC,IAAI,KAAK;oBAAE,OAAO,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;YAC/D,CAAC;YACD,OAAO,SAAS,CAAC;QAAA,CACjB;KACD,CAAC;AAAA,CACF;AAED;;;;;;GAMG;AACH,MAAM,UAAU,SAAS,CAAC,KAA4E,EAAa;IAClH,IAAI,OAAuC,CAAC;IAC5C,MAAM,MAAM,GAAG,GAAG,EAAE,CAAC;QACpB,OAAO,KAAK,KAAK,CAAC,IAAI,EAAE,CAAC;QACzB,OAAO,OAAO,CAAC;IAAA,CACf,CAAC;IACF,OAAO;QACN,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,UAAU,EAAE,KAAK,CAAC,UAAU;QAC5B,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE,CAAC,CAAC,MAAM,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC;QACjE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,EAAE,CAAC,CAAC,MAAM,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC;QACnE,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,EAAE,CAAC,CAAC,MAAM,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC;KACjE,CAAC;AAAA,CACF","sourcesContent":["import type { ApiKeyAuth, OAuthAuth } from \"./types.ts\";\n\n/**\n * Standard api-key auth: a stored credential key wins, otherwise the first\n * set env var resolves. Includes a `login` that prompts for the key.\n * Providers with non-standard resolution (provider env, ambient files, IAM)\n * write their own `ApiKeyAuth`.\n */\nexport function envApiKeyAuth(name: string, envVars: readonly string[]): ApiKeyAuth {\n\treturn {\n\t\tname,\n\t\tlogin: async (interaction) => {\n\t\t\tconst key = await interaction.prompt({ type: \"secret\", message: `Enter ${name}` });\n\t\t\treturn { type: \"api_key\", key };\n\t\t},\n\t\tresolve: async ({ ctx, credential }) => {\n\t\t\tif (credential?.key) {\n\t\t\t\treturn { auth: { apiKey: credential.key }, env: credential.env, source: \"stored credential\" };\n\t\t\t}\n\t\t\tfor (const envVar of envVars) {\n\t\t\t\tconst value = await ctx.env(envVar);\n\t\t\t\tif (value) return { auth: { apiKey: value }, source: envVar };\n\t\t\t}\n\t\t\treturn undefined;\n\t\t},\n\t};\n}\n\n/**\n * Wraps a dynamically imported `OAuthAuth` so provider definitions can\n * advertise OAuth without importing the implementation. The flow loads on\n * first `login`/`refresh`/`toAuth` call; callers keep Node-only flow code out\n * of bundles by loading through a bundler-opaque dynamic import (variable\n * specifier, see the bedrock lazy wrapper).\n */\nexport function lazyOAuth(input: { name: string; loginLabel?: string; load: () => Promise<OAuthAuth> }): OAuthAuth {\n\tlet promise: Promise<OAuthAuth> | undefined;\n\tconst loaded = () => {\n\t\tpromise ??= input.load();\n\t\treturn promise;\n\t};\n\treturn {\n\t\tname: input.name,\n\t\tloginLabel: input.loginLabel,\n\t\tlogin: async (interaction) => (await loaded()).login(interaction),\n\t\trefresh: async (credential) => (await loaded()).refresh(credential),\n\t\ttoAuth: async (credential) => (await loaded()).toAuth(credential),\n\t};\n}\n"]}
1
+ {"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../src/auth/helpers.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,IAAY,EAAE,OAA0B,EAAc;IACnF,OAAO;QACN,IAAI;QACJ,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE,CAAC;YAC7B,WAAW,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC;YACpC,MAAM,GAAG,GAAG,MAAM,WAAW,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,SAAS,IAAI,EAAE,EAAE,CAAC,CAAC;YACnF,WAAW,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC;YACpC,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC;QAAA,CAChC;QACD,OAAO,EAAE,KAAK,EAAE,EAAE,GAAG,EAAE,UAAU,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;YAC/C,MAAM,CAAC,cAAc,EAAE,CAAC;YACxB,IAAI,UAAU,EAAE,GAAG,EAAE,CAAC;gBACrB,OAAO,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,UAAU,CAAC,GAAG,EAAE,EAAE,GAAG,EAAE,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,mBAAmB,EAAE,CAAC;YAC/F,CAAC;YACD,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;gBAC9B,MAAM,KAAK,GAAG,MAAM,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;gBACpC,MAAM,CAAC,cAAc,EAAE,CAAC;gBACxB,IAAI,KAAK;oBAAE,OAAO,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;YAC/D,CAAC;YACD,OAAO,SAAS,CAAC;QAAA,CACjB;KACD,CAAC;AAAA,CACF;AAED;;;;;;GAMG;AACH,MAAM,UAAU,SAAS,CAAC,KAKzB,EAAa;IACb,IAAI,OAAuC,CAAC;IAC5C,MAAM,MAAM,GAAG,GAAG,EAAE,CAAC;QACpB,OAAO,KAAK,KAAK,CAAC,IAAI,EAAE,CAAC;QACzB,OAAO,OAAO,CAAC;IAAA,CACf,CAAC;IACF,OAAO;QACN,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,cAAc,EAAE,KAAK,CAAC,cAAc;QACpC,UAAU,EAAE,KAAK,CAAC,UAAU;QAC5B,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE,CAAC,CAAC,MAAM,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC;QACjE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,UAAU,EAAE,MAAM,CAAC;QACnF,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,EAAE,CAAC,CAAC,MAAM,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC;KACjE,CAAC;AAAA,CACF","sourcesContent":["import type { ApiKeyAuth, OAuthAuth } from \"./types.ts\";\n\n/**\n * Standard api-key auth: a stored credential key wins, otherwise the first\n * set env var resolves. Includes a `login` that prompts for the key.\n * Providers with non-standard resolution (provider env, ambient files, IAM)\n * write their own `ApiKeyAuth`.\n */\nexport function envApiKeyAuth(name: string, envVars: readonly string[]): ApiKeyAuth {\n\treturn {\n\t\tname,\n\t\tlogin: async (interaction) => {\n\t\t\tinteraction.signal.throwIfAborted();\n\t\t\tconst key = await interaction.prompt({ type: \"secret\", message: `Enter ${name}` });\n\t\t\tinteraction.signal.throwIfAborted();\n\t\t\treturn { type: \"api_key\", key };\n\t\t},\n\t\tresolve: async ({ ctx, credential, signal }) => {\n\t\t\tsignal.throwIfAborted();\n\t\t\tif (credential?.key) {\n\t\t\t\treturn { auth: { apiKey: credential.key }, env: credential.env, source: \"stored credential\" };\n\t\t\t}\n\t\t\tfor (const envVar of envVars) {\n\t\t\t\tconst value = await ctx.env(envVar);\n\t\t\t\tsignal.throwIfAborted();\n\t\t\t\tif (value) return { auth: { apiKey: value }, source: envVar };\n\t\t\t}\n\t\t\treturn undefined;\n\t\t},\n\t};\n}\n\n/**\n * Wraps a dynamically imported `OAuthAuth` so provider definitions can\n * advertise OAuth without importing the implementation. The flow loads on\n * first `login`/`refresh`/`toAuth` call; callers keep Node-only flow code out\n * of bundles by loading through a bundler-opaque dynamic import (variable\n * specifier, see the bedrock lazy wrapper).\n */\nexport function lazyOAuth(input: {\n\tname: string;\n\tisSubscription?: boolean;\n\tloginLabel?: string;\n\tload: () => Promise<OAuthAuth>;\n}): OAuthAuth {\n\tlet promise: Promise<OAuthAuth> | undefined;\n\tconst loaded = () => {\n\t\tpromise ??= input.load();\n\t\treturn promise;\n\t};\n\treturn {\n\t\tname: input.name,\n\t\tisSubscription: input.isSubscription,\n\t\tloginLabel: input.loginLabel,\n\t\tlogin: async (interaction) => (await loaded()).login(interaction),\n\t\trefresh: async (credential, signal) => (await loaded()).refresh(credential, signal),\n\t\ttoAuth: async (credential) => (await loaded()).toAuth(credential),\n\t};\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"anthropic.d.ts","sourceRoot":"","sources":["../../../src/auth/oauth/anthropic.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAmB,SAAS,EAAmB,MAAM,aAAa,CAAC;AA4U/E,eAAO,MAAM,cAAc,EAAE,SAQ5B,CAAC","sourcesContent":["/**\n * Anthropic OAuth flow (Claude Pro/Max)\n *\n * NOTE: This module uses Node.js http.createServer for the OAuth callback server.\n * It is only intended for CLI use, not browser environments.\n */\n\nimport type { Server } from \"node:http\";\nimport { getProviderEnvValue } from \"../../utils/provider-env.ts\";\nimport type { AuthInteraction, OAuthAuth, OAuthCredential } from \"../types.ts\";\nimport { oauthErrorHtml, oauthSuccessHtml } from \"./oauth-page.ts\";\nimport { generatePKCE } from \"./pkce.ts\";\n\ntype CallbackServerInfo = {\n\tserver: Server;\n\tredirectUri: string;\n\tcancelWait: () => void;\n\twaitForCode: () => Promise<{ code: string; state: string } | null>;\n};\n\ntype NodeApis = {\n\tcreateServer: typeof import(\"node:http\").createServer;\n};\n\nlet nodeApis: NodeApis | null = null;\nlet nodeApisPromise: Promise<NodeApis> | null = null;\n\nconst decode = (s: string) => atob(s);\nconst CLIENT_ID = decode(\"OWQxYzI1MGEtZTYxYi00NGQ5LTg4ZWQtNTk0NGQxOTYyZjVl\");\nconst AUTHORIZE_URL = \"https://claude.ai/oauth/authorize\";\nconst TOKEN_URL = \"https://platform.claude.com/v1/oauth/token\";\nconst CALLBACK_HOST = getProviderEnvValue(\"PI_OAUTH_CALLBACK_HOST\") || \"127.0.0.1\";\nconst CALLBACK_PORT = 53692;\nconst CALLBACK_PATH = \"/callback\";\nconst REDIRECT_URI = `http://localhost:${CALLBACK_PORT}${CALLBACK_PATH}`;\nconst SCOPES =\n\t\"org:create_api_key user:profile user:inference user:sessions:claude_code user:mcp_servers user:file_upload\";\nasync function getNodeApis(): Promise<NodeApis> {\n\tif (nodeApis) return nodeApis;\n\tif (!nodeApisPromise) {\n\t\tif (typeof process === \"undefined\" || (!process.versions?.node && !process.versions?.bun)) {\n\t\t\tthrow new Error(\"Anthropic OAuth is only available in Node.js environments\");\n\t\t}\n\t\tnodeApisPromise = import(\"node:http\").then((httpModule) => ({\n\t\t\tcreateServer: httpModule.createServer,\n\t\t}));\n\t}\n\tnodeApis = await nodeApisPromise;\n\treturn nodeApis;\n}\n\nfunction parseAuthorizationInput(input: string): { code?: string; state?: string } {\n\tconst value = input.trim();\n\tif (!value) return {};\n\n\ttry {\n\t\tconst url = new URL(value);\n\t\treturn {\n\t\t\tcode: url.searchParams.get(\"code\") ?? undefined,\n\t\t\tstate: url.searchParams.get(\"state\") ?? undefined,\n\t\t};\n\t} catch {\n\t\t// not a URL\n\t}\n\n\tif (value.includes(\"#\")) {\n\t\tconst [code, state] = value.split(\"#\", 2);\n\t\treturn { code, state };\n\t}\n\n\tif (value.includes(\"code=\")) {\n\t\tconst params = new URLSearchParams(value);\n\t\treturn {\n\t\t\tcode: params.get(\"code\") ?? undefined,\n\t\t\tstate: params.get(\"state\") ?? undefined,\n\t\t};\n\t}\n\n\treturn { code: value };\n}\n\nfunction formatErrorDetails(error: unknown): string {\n\tif (error instanceof Error) {\n\t\tconst details: string[] = [`${error.name}: ${error.message}`];\n\t\tconst errorWithCode = error as Error & { code?: string; errno?: number | string; cause?: unknown };\n\t\tif (errorWithCode.code) details.push(`code=${errorWithCode.code}`);\n\t\tif (typeof errorWithCode.errno !== \"undefined\") details.push(`errno=${String(errorWithCode.errno)}`);\n\t\tif (typeof error.cause !== \"undefined\") {\n\t\t\tdetails.push(`cause=${formatErrorDetails(error.cause)}`);\n\t\t}\n\t\tif (error.stack) {\n\t\t\tdetails.push(`stack=${error.stack}`);\n\t\t}\n\t\treturn details.join(\"; \");\n\t}\n\treturn String(error);\n}\n\nasync function startCallbackServer(expectedState: string): Promise<CallbackServerInfo> {\n\tconst { createServer } = await getNodeApis();\n\n\treturn new Promise((resolve, reject) => {\n\t\tlet settleWait: ((value: { code: string; state: string } | null) => void) | undefined;\n\t\tconst waitForCodePromise = new Promise<{ code: string; state: string } | null>((resolveWait) => {\n\t\t\tlet settled = false;\n\t\t\tsettleWait = (value) => {\n\t\t\t\tif (settled) return;\n\t\t\t\tsettled = true;\n\t\t\t\tresolveWait(value);\n\t\t\t};\n\t\t});\n\n\t\tconst server = createServer((req, res) => {\n\t\t\ttry {\n\t\t\t\tconst url = new URL(req.url || \"\", \"http://localhost\");\n\t\t\t\tif (url.pathname !== CALLBACK_PATH) {\n\t\t\t\t\tres.writeHead(404, { \"Content-Type\": \"text/html; charset=utf-8\" });\n\t\t\t\t\tres.end(oauthErrorHtml(\"Callback route not found.\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst code = url.searchParams.get(\"code\");\n\t\t\t\tconst state = url.searchParams.get(\"state\");\n\t\t\t\tconst error = url.searchParams.get(\"error\");\n\n\t\t\t\tif (error) {\n\t\t\t\t\tres.writeHead(400, { \"Content-Type\": \"text/html; charset=utf-8\" });\n\t\t\t\t\tres.end(oauthErrorHtml(\"Anthropic authentication did not complete.\", `Error: ${error}`));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (!code || !state) {\n\t\t\t\t\tres.writeHead(400, { \"Content-Type\": \"text/html; charset=utf-8\" });\n\t\t\t\t\tres.end(oauthErrorHtml(\"Missing code or state parameter.\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (state !== expectedState) {\n\t\t\t\t\tres.writeHead(400, { \"Content-Type\": \"text/html; charset=utf-8\" });\n\t\t\t\t\tres.end(oauthErrorHtml(\"State mismatch.\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tres.writeHead(200, { \"Content-Type\": \"text/html; charset=utf-8\" });\n\t\t\t\tres.end(oauthSuccessHtml(\"Anthropic authentication completed. You can close this window.\"));\n\t\t\t\tsettleWait?.({ code, state });\n\t\t\t} catch {\n\t\t\t\tres.writeHead(500, { \"Content-Type\": \"text/plain; charset=utf-8\" });\n\t\t\t\tres.end(\"Internal error\");\n\t\t\t}\n\t\t});\n\n\t\tserver.on(\"error\", (err) => {\n\t\t\treject(err);\n\t\t});\n\n\t\tserver.listen(CALLBACK_PORT, CALLBACK_HOST, () => {\n\t\t\tresolve({\n\t\t\t\tserver,\n\t\t\t\tredirectUri: REDIRECT_URI,\n\t\t\t\tcancelWait: () => {\n\t\t\t\t\tsettleWait?.(null);\n\t\t\t\t},\n\t\t\t\twaitForCode: () => waitForCodePromise,\n\t\t\t});\n\t\t});\n\t});\n}\n\nasync function postJson(url: string, body: Record<string, string | number>): Promise<string> {\n\tconst response = await fetch(url, {\n\t\tmethod: \"POST\",\n\t\theaders: {\n\t\t\t\"Content-Type\": \"application/json\",\n\t\t\tAccept: \"application/json\",\n\t\t},\n\t\tbody: JSON.stringify(body),\n\t\tsignal: AbortSignal.timeout(30_000),\n\t});\n\n\tconst responseBody = await response.text();\n\n\tif (!response.ok) {\n\t\tthrow new Error(`HTTP request failed. status=${response.status}; url=${url}; body=${responseBody}`);\n\t}\n\n\treturn responseBody;\n}\n\nasync function exchangeAuthorizationCode(\n\tcode: string,\n\tstate: string,\n\tverifier: string,\n\tredirectUri: string,\n): Promise<OAuthCredential> {\n\tlet responseBody: string;\n\ttry {\n\t\tresponseBody = await postJson(TOKEN_URL, {\n\t\t\tgrant_type: \"authorization_code\",\n\t\t\tclient_id: CLIENT_ID,\n\t\t\tcode,\n\t\t\tstate,\n\t\t\tredirect_uri: redirectUri,\n\t\t\tcode_verifier: verifier,\n\t\t});\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`Token exchange request failed. url=${TOKEN_URL}; redirect_uri=${redirectUri}; response_type=authorization_code; details=${formatErrorDetails(error)}`,\n\t\t);\n\t}\n\n\tlet tokenData: { access_token: string; refresh_token: string; expires_in: number };\n\ttry {\n\t\ttokenData = JSON.parse(responseBody) as { access_token: string; refresh_token: string; expires_in: number };\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`Token exchange returned invalid JSON. url=${TOKEN_URL}; body=${responseBody}; details=${formatErrorDetails(error)}`,\n\t\t);\n\t}\n\n\treturn {\n\t\ttype: \"oauth\",\n\t\trefresh: tokenData.refresh_token,\n\t\taccess: tokenData.access_token,\n\t\texpires: Date.now() + tokenData.expires_in * 1000 - 5 * 60 * 1000,\n\t};\n}\n\nasync function loginAnthropic(interaction: AuthInteraction): Promise<OAuthCredential> {\n\tconst { verifier, challenge } = await generatePKCE();\n\tconst server = await startCallbackServer(verifier);\n\tconst manualAbort = new AbortController();\n\tlet code: string | undefined;\n\tlet state: string | undefined;\n\tlet manualInput: string | undefined;\n\tlet manualError: Error | undefined;\n\n\ttry {\n\t\tconst authParams = new URLSearchParams({\n\t\t\tcode: \"true\",\n\t\t\tclient_id: CLIENT_ID,\n\t\t\tresponse_type: \"code\",\n\t\t\tredirect_uri: REDIRECT_URI,\n\t\t\tscope: SCOPES,\n\t\t\tcode_challenge: challenge,\n\t\t\tcode_challenge_method: \"S256\",\n\t\t\tstate: verifier,\n\t\t});\n\t\tinteraction.notify({\n\t\t\ttype: \"auth_url\",\n\t\t\turl: `${AUTHORIZE_URL}?${authParams.toString()}`,\n\t\t\tinstructions:\n\t\t\t\t\"Complete login in your browser. If the browser is on another machine, paste the final redirect URL here.\",\n\t\t});\n\n\t\tconst manualPromise = interaction\n\t\t\t.prompt({\n\t\t\t\ttype: \"manual_code\",\n\t\t\t\tmessage: \"Complete login in your browser, or paste the authorization code / redirect URL here:\",\n\t\t\t\tplaceholder: REDIRECT_URI,\n\t\t\t\tsignal: manualAbort.signal,\n\t\t\t})\n\t\t\t.then((input) => {\n\t\t\t\tmanualInput = input;\n\t\t\t\tserver.cancelWait();\n\t\t\t})\n\t\t\t.catch((error) => {\n\t\t\t\tmanualError = error instanceof Error ? error : new Error(String(error));\n\t\t\t\tserver.cancelWait();\n\t\t\t});\n\n\t\tconst result = await server.waitForCode();\n\t\tif (manualError) throw manualError;\n\t\tif (result?.code) {\n\t\t\tcode = result.code;\n\t\t\tstate = result.state;\n\t\t} else if (manualInput) {\n\t\t\tconst parsed = parseAuthorizationInput(manualInput);\n\t\t\tif (parsed.state && parsed.state !== verifier) throw new Error(\"OAuth state mismatch\");\n\t\t\tcode = parsed.code;\n\t\t\tstate = parsed.state ?? verifier;\n\t\t}\n\n\t\tif (!code) {\n\t\t\tawait manualPromise;\n\t\t\tif (manualError) throw manualError;\n\t\t\tif (manualInput) {\n\t\t\t\tconst parsed = parseAuthorizationInput(manualInput);\n\t\t\t\tif (parsed.state && parsed.state !== verifier) throw new Error(\"OAuth state mismatch\");\n\t\t\t\tcode = parsed.code;\n\t\t\t\tstate = parsed.state ?? verifier;\n\t\t\t}\n\t\t}\n\n\t\tif (!code) throw new Error(\"Missing authorization code\");\n\t\tif (!state) throw new Error(\"Missing OAuth state\");\n\t\tinteraction.notify({ type: \"progress\", message: \"Exchanging authorization code for tokens...\" });\n\t\treturn exchangeAuthorizationCode(code, state, verifier, REDIRECT_URI);\n\t} finally {\n\t\tmanualAbort.abort();\n\t\tserver.server.close();\n\t}\n}\n\n/**\n * Refresh Anthropic OAuth token\n */\nasync function refreshAnthropicToken(refreshToken: string): Promise<OAuthCredential> {\n\tlet responseBody: string;\n\ttry {\n\t\tresponseBody = await postJson(TOKEN_URL, {\n\t\t\tgrant_type: \"refresh_token\",\n\t\t\tclient_id: CLIENT_ID,\n\t\t\trefresh_token: refreshToken,\n\t\t});\n\t} catch (error) {\n\t\tthrow new Error(`Anthropic token refresh request failed. url=${TOKEN_URL}; details=${formatErrorDetails(error)}`);\n\t}\n\n\tlet data: { access_token: string; refresh_token: string; expires_in: number; scope?: string };\n\ttry {\n\t\tdata = JSON.parse(responseBody) as {\n\t\t\taccess_token: string;\n\t\t\trefresh_token: string;\n\t\t\texpires_in: number;\n\t\t\tscope?: string;\n\t\t};\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`Anthropic token refresh returned invalid JSON. url=${TOKEN_URL}; body=${responseBody}; details=${formatErrorDetails(error)}`,\n\t\t);\n\t}\n\n\treturn {\n\t\ttype: \"oauth\",\n\t\trefresh: data.refresh_token,\n\t\taccess: data.access_token,\n\t\texpires: Date.now() + data.expires_in * 1000 - 5 * 60 * 1000,\n\t};\n}\n\nexport const anthropicOAuth: OAuthAuth = {\n\tname: \"Anthropic (Claude Pro/Max)\",\n\tlogin: loginAnthropic,\n\trefresh: (credential) => refreshAnthropicToken(credential.refresh),\n\n\tasync toAuth(credential) {\n\t\treturn { apiKey: credential.access };\n\t},\n};\n"]}
1
+ {"version":3,"file":"anthropic.d.ts","sourceRoot":"","sources":["../../../src/auth/oauth/anthropic.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,SAAS,EAA4C,MAAM,aAAa,CAAC;AAyVvF,eAAO,MAAM,cAAc,EAAE,SAS5B,CAAC","sourcesContent":["/**\n * Anthropic OAuth flow (Claude Pro/Max)\n *\n * NOTE: This module uses Node.js http.createServer for the OAuth callback server.\n * It is only intended for CLI use, not browser environments.\n */\n\nimport type { Server } from \"node:http\";\nimport { getProviderEnvValue } from \"../../utils/provider-env.ts\";\nimport type { OAuthAuth, OAuthCredential, ProviderAuthInteraction } from \"../types.ts\";\nimport { oauthErrorHtml, oauthSuccessHtml } from \"./oauth-page.ts\";\nimport { generatePKCE } from \"./pkce.ts\";\n\ntype CallbackServerInfo = {\n\tserver: Server;\n\tredirectUri: string;\n\tcancelWait: () => void;\n\twaitForCode: () => Promise<{ code: string; state: string } | null>;\n};\n\ntype NodeApis = {\n\tcreateServer: typeof import(\"node:http\").createServer;\n};\n\nlet nodeApis: NodeApis | null = null;\nlet nodeApisPromise: Promise<NodeApis> | null = null;\n\nconst decode = (s: string) => atob(s);\nconst CLIENT_ID = decode(\"OWQxYzI1MGEtZTYxYi00NGQ5LTg4ZWQtNTk0NGQxOTYyZjVl\");\nconst AUTHORIZE_URL = \"https://claude.ai/oauth/authorize\";\nconst TOKEN_URL = \"https://platform.claude.com/v1/oauth/token\";\nconst CALLBACK_HOST = getProviderEnvValue(\"PI_OAUTH_CALLBACK_HOST\") || \"127.0.0.1\";\nconst CALLBACK_PORT = 53692;\nconst CALLBACK_PATH = \"/callback\";\nconst REDIRECT_URI = `http://localhost:${CALLBACK_PORT}${CALLBACK_PATH}`;\nconst SCOPES =\n\t\"org:create_api_key user:profile user:inference user:sessions:claude_code user:mcp_servers user:file_upload\";\nasync function getNodeApis(): Promise<NodeApis> {\n\tif (nodeApis) return nodeApis;\n\tif (!nodeApisPromise) {\n\t\tif (typeof process === \"undefined\" || (!process.versions?.node && !process.versions?.bun)) {\n\t\t\tthrow new Error(\"Anthropic OAuth is only available in Node.js environments\");\n\t\t}\n\t\tnodeApisPromise = import(\"node:http\").then((httpModule) => ({\n\t\t\tcreateServer: httpModule.createServer,\n\t\t}));\n\t}\n\tnodeApis = await nodeApisPromise;\n\treturn nodeApis;\n}\n\nfunction parseAuthorizationInput(input: string): { code?: string; state?: string } {\n\tconst value = input.trim();\n\tif (!value) return {};\n\n\ttry {\n\t\tconst url = new URL(value);\n\t\treturn {\n\t\t\tcode: url.searchParams.get(\"code\") ?? undefined,\n\t\t\tstate: url.searchParams.get(\"state\") ?? undefined,\n\t\t};\n\t} catch {\n\t\t// not a URL\n\t}\n\n\tif (value.includes(\"#\")) {\n\t\tconst [code, state] = value.split(\"#\", 2);\n\t\treturn { code, state };\n\t}\n\n\tif (value.includes(\"code=\")) {\n\t\tconst params = new URLSearchParams(value);\n\t\treturn {\n\t\t\tcode: params.get(\"code\") ?? undefined,\n\t\t\tstate: params.get(\"state\") ?? undefined,\n\t\t};\n\t}\n\n\treturn { code: value };\n}\n\nfunction formatErrorDetails(error: unknown): string {\n\tif (error instanceof Error) {\n\t\tconst details: string[] = [`${error.name}: ${error.message}`];\n\t\tconst errorWithCode = error as Error & { code?: string; errno?: number | string; cause?: unknown };\n\t\tif (errorWithCode.code) details.push(`code=${errorWithCode.code}`);\n\t\tif (typeof errorWithCode.errno !== \"undefined\") details.push(`errno=${String(errorWithCode.errno)}`);\n\t\tif (typeof error.cause !== \"undefined\") {\n\t\t\tdetails.push(`cause=${formatErrorDetails(error.cause)}`);\n\t\t}\n\t\tif (error.stack) {\n\t\t\tdetails.push(`stack=${error.stack}`);\n\t\t}\n\t\treturn details.join(\"; \");\n\t}\n\treturn String(error);\n}\n\nasync function startCallbackServer(expectedState: string): Promise<CallbackServerInfo> {\n\tconst { createServer } = await getNodeApis();\n\n\treturn new Promise((resolve, reject) => {\n\t\tlet settleWait: ((value: { code: string; state: string } | null) => void) | undefined;\n\t\tconst waitForCodePromise = new Promise<{ code: string; state: string } | null>((resolveWait) => {\n\t\t\tlet settled = false;\n\t\t\tsettleWait = (value) => {\n\t\t\t\tif (settled) return;\n\t\t\t\tsettled = true;\n\t\t\t\tresolveWait(value);\n\t\t\t};\n\t\t});\n\n\t\tconst server = createServer((req, res) => {\n\t\t\ttry {\n\t\t\t\tconst url = new URL(req.url || \"\", \"http://localhost\");\n\t\t\t\tif (url.pathname !== CALLBACK_PATH) {\n\t\t\t\t\tres.writeHead(404, { \"Content-Type\": \"text/html; charset=utf-8\" });\n\t\t\t\t\tres.end(oauthErrorHtml(\"Callback route not found.\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst code = url.searchParams.get(\"code\");\n\t\t\t\tconst state = url.searchParams.get(\"state\");\n\t\t\t\tconst error = url.searchParams.get(\"error\");\n\n\t\t\t\tif (error) {\n\t\t\t\t\tres.writeHead(400, { \"Content-Type\": \"text/html; charset=utf-8\" });\n\t\t\t\t\tres.end(oauthErrorHtml(\"Anthropic authentication did not complete.\", `Error: ${error}`));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (!code || !state) {\n\t\t\t\t\tres.writeHead(400, { \"Content-Type\": \"text/html; charset=utf-8\" });\n\t\t\t\t\tres.end(oauthErrorHtml(\"Missing code or state parameter.\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (state !== expectedState) {\n\t\t\t\t\tres.writeHead(400, { \"Content-Type\": \"text/html; charset=utf-8\" });\n\t\t\t\t\tres.end(oauthErrorHtml(\"State mismatch.\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tres.writeHead(200, { \"Content-Type\": \"text/html; charset=utf-8\" });\n\t\t\t\tres.end(oauthSuccessHtml(\"Anthropic authentication completed. You can close this window.\"));\n\t\t\t\tsettleWait?.({ code, state });\n\t\t\t} catch {\n\t\t\t\tres.writeHead(500, { \"Content-Type\": \"text/plain; charset=utf-8\" });\n\t\t\t\tres.end(\"Internal error\");\n\t\t\t}\n\t\t});\n\n\t\tserver.on(\"error\", (err) => {\n\t\t\treject(err);\n\t\t});\n\n\t\tserver.listen(CALLBACK_PORT, CALLBACK_HOST, () => {\n\t\t\tresolve({\n\t\t\t\tserver,\n\t\t\t\tredirectUri: REDIRECT_URI,\n\t\t\t\tcancelWait: () => {\n\t\t\t\t\tsettleWait?.(null);\n\t\t\t\t},\n\t\t\t\twaitForCode: () => waitForCodePromise,\n\t\t\t});\n\t\t});\n\t});\n}\n\nasync function postJson(url: string, body: Record<string, string | number>, signal: AbortSignal): Promise<string> {\n\tconst response = await fetch(url, {\n\t\tmethod: \"POST\",\n\t\theaders: {\n\t\t\t\"Content-Type\": \"application/json\",\n\t\t\tAccept: \"application/json\",\n\t\t},\n\t\tbody: JSON.stringify(body),\n\t\tsignal: AbortSignal.any([signal, AbortSignal.timeout(30_000)]),\n\t});\n\n\tconst responseBody = await response.text();\n\n\tif (!response.ok) {\n\t\tthrow new Error(`HTTP request failed. status=${response.status}; url=${url}; body=${responseBody}`);\n\t}\n\n\treturn responseBody;\n}\n\nasync function exchangeAuthorizationCode(\n\tcode: string,\n\tstate: string,\n\tverifier: string,\n\tredirectUri: string,\n\tsignal: AbortSignal,\n): Promise<OAuthCredential> {\n\tlet responseBody: string;\n\ttry {\n\t\tresponseBody = await postJson(\n\t\t\tTOKEN_URL,\n\t\t\t{\n\t\t\t\tgrant_type: \"authorization_code\",\n\t\t\t\tclient_id: CLIENT_ID,\n\t\t\t\tcode,\n\t\t\t\tstate,\n\t\t\t\tredirect_uri: redirectUri,\n\t\t\t\tcode_verifier: verifier,\n\t\t\t},\n\t\t\tsignal,\n\t\t);\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`Token exchange request failed. url=${TOKEN_URL}; redirect_uri=${redirectUri}; response_type=authorization_code; details=${formatErrorDetails(error)}`,\n\t\t);\n\t}\n\n\tlet tokenData: { access_token: string; refresh_token: string; expires_in: number };\n\ttry {\n\t\ttokenData = JSON.parse(responseBody) as { access_token: string; refresh_token: string; expires_in: number };\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`Token exchange returned invalid JSON. url=${TOKEN_URL}; body=${responseBody}; details=${formatErrorDetails(error)}`,\n\t\t);\n\t}\n\n\treturn {\n\t\ttype: \"oauth\",\n\t\trefresh: tokenData.refresh_token,\n\t\taccess: tokenData.access_token,\n\t\texpires: Date.now() + tokenData.expires_in * 1000 - 5 * 60 * 1000,\n\t};\n}\n\nasync function loginAnthropic(interaction: ProviderAuthInteraction): Promise<OAuthCredential> {\n\tconst { verifier, challenge } = await generatePKCE();\n\tconst server = await startCallbackServer(verifier);\n\tconst manualAbort = new AbortController();\n\tconst onAbort = () => server.cancelWait();\n\tinteraction.signal.addEventListener(\"abort\", onAbort, { once: true });\n\tif (interaction.signal.aborted) onAbort();\n\tlet code: string | undefined;\n\tlet state: string | undefined;\n\tlet manualInput: string | undefined;\n\tlet manualError: Error | undefined;\n\n\ttry {\n\t\tconst authParams = new URLSearchParams({\n\t\t\tcode: \"true\",\n\t\t\tclient_id: CLIENT_ID,\n\t\t\tresponse_type: \"code\",\n\t\t\tredirect_uri: REDIRECT_URI,\n\t\t\tscope: SCOPES,\n\t\t\tcode_challenge: challenge,\n\t\t\tcode_challenge_method: \"S256\",\n\t\t\tstate: verifier,\n\t\t});\n\t\tinteraction.notify({\n\t\t\ttype: \"auth_url\",\n\t\t\turl: `${AUTHORIZE_URL}?${authParams.toString()}`,\n\t\t\tinstructions:\n\t\t\t\t\"Complete login in your browser. If the browser is on another machine, paste the final redirect URL here.\",\n\t\t});\n\n\t\tconst manualPromise = interaction\n\t\t\t.prompt({\n\t\t\t\ttype: \"manual_code\",\n\t\t\t\tmessage: \"Complete login in your browser, or paste the authorization code / redirect URL here:\",\n\t\t\t\tplaceholder: REDIRECT_URI,\n\t\t\t\tsignal: manualAbort.signal,\n\t\t\t})\n\t\t\t.then((input) => {\n\t\t\t\tmanualInput = input;\n\t\t\t\tserver.cancelWait();\n\t\t\t})\n\t\t\t.catch((error) => {\n\t\t\t\tmanualError = error instanceof Error ? error : new Error(String(error));\n\t\t\t\tserver.cancelWait();\n\t\t\t});\n\n\t\tconst result = await server.waitForCode();\n\t\tif (manualError) throw manualError;\n\t\tif (result?.code) {\n\t\t\tcode = result.code;\n\t\t\tstate = result.state;\n\t\t} else if (manualInput) {\n\t\t\tconst parsed = parseAuthorizationInput(manualInput);\n\t\t\tif (parsed.state && parsed.state !== verifier) throw new Error(\"OAuth state mismatch\");\n\t\t\tcode = parsed.code;\n\t\t\tstate = parsed.state ?? verifier;\n\t\t}\n\n\t\tif (!code) {\n\t\t\tawait manualPromise;\n\t\t\tif (manualError) throw manualError;\n\t\t\tif (manualInput) {\n\t\t\t\tconst parsed = parseAuthorizationInput(manualInput);\n\t\t\t\tif (parsed.state && parsed.state !== verifier) throw new Error(\"OAuth state mismatch\");\n\t\t\t\tcode = parsed.code;\n\t\t\t\tstate = parsed.state ?? verifier;\n\t\t\t}\n\t\t}\n\n\t\tif (!code) throw new Error(\"Missing authorization code\");\n\t\tif (!state) throw new Error(\"Missing OAuth state\");\n\t\tinteraction.notify({ type: \"progress\", message: \"Exchanging authorization code for tokens...\" });\n\t\treturn exchangeAuthorizationCode(code, state, verifier, REDIRECT_URI, interaction.signal);\n\t} finally {\n\t\tinteraction.signal.removeEventListener(\"abort\", onAbort);\n\t\tmanualAbort.abort();\n\t\tserver.server.close();\n\t}\n}\n\n/**\n * Refresh Anthropic OAuth token\n */\nasync function refreshAnthropicToken(refreshToken: string, signal: AbortSignal): Promise<OAuthCredential> {\n\tlet responseBody: string;\n\ttry {\n\t\tresponseBody = await postJson(\n\t\t\tTOKEN_URL,\n\t\t\t{\n\t\t\t\tgrant_type: \"refresh_token\",\n\t\t\t\tclient_id: CLIENT_ID,\n\t\t\t\trefresh_token: refreshToken,\n\t\t\t},\n\t\t\tsignal,\n\t\t);\n\t} catch (error) {\n\t\tthrow new Error(`Anthropic token refresh request failed. url=${TOKEN_URL}; details=${formatErrorDetails(error)}`);\n\t}\n\n\tlet data: { access_token: string; refresh_token: string; expires_in: number; scope?: string };\n\ttry {\n\t\tdata = JSON.parse(responseBody) as {\n\t\t\taccess_token: string;\n\t\t\trefresh_token: string;\n\t\t\texpires_in: number;\n\t\t\tscope?: string;\n\t\t};\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`Anthropic token refresh returned invalid JSON. url=${TOKEN_URL}; body=${responseBody}; details=${formatErrorDetails(error)}`,\n\t\t);\n\t}\n\n\treturn {\n\t\ttype: \"oauth\",\n\t\trefresh: data.refresh_token,\n\t\taccess: data.access_token,\n\t\texpires: Date.now() + data.expires_in * 1000 - 5 * 60 * 1000,\n\t};\n}\n\nexport const anthropicOAuth: OAuthAuth = {\n\tname: \"Anthropic (Claude Pro/Max)\",\n\tisSubscription: true,\n\tlogin: loginAnthropic,\n\trefresh: (credential, signal) => refreshAnthropicToken(credential.refresh, signal),\n\n\tasync toAuth(credential) {\n\t\treturn { apiKey: credential.access };\n\t},\n};\n"]}
@@ -140,7 +140,7 @@ async function startCallbackServer(expectedState) {
140
140
  });
141
141
  });
142
142
  }
143
- async function postJson(url, body) {
143
+ async function postJson(url, body, signal) {
144
144
  const response = await fetch(url, {
145
145
  method: "POST",
146
146
  headers: {
@@ -148,7 +148,7 @@ async function postJson(url, body) {
148
148
  Accept: "application/json",
149
149
  },
150
150
  body: JSON.stringify(body),
151
- signal: AbortSignal.timeout(30_000),
151
+ signal: AbortSignal.any([signal, AbortSignal.timeout(30_000)]),
152
152
  });
153
153
  const responseBody = await response.text();
154
154
  if (!response.ok) {
@@ -156,7 +156,7 @@ async function postJson(url, body) {
156
156
  }
157
157
  return responseBody;
158
158
  }
159
- async function exchangeAuthorizationCode(code, state, verifier, redirectUri) {
159
+ async function exchangeAuthorizationCode(code, state, verifier, redirectUri, signal) {
160
160
  let responseBody;
161
161
  try {
162
162
  responseBody = await postJson(TOKEN_URL, {
@@ -166,7 +166,7 @@ async function exchangeAuthorizationCode(code, state, verifier, redirectUri) {
166
166
  state,
167
167
  redirect_uri: redirectUri,
168
168
  code_verifier: verifier,
169
- });
169
+ }, signal);
170
170
  }
171
171
  catch (error) {
172
172
  throw new Error(`Token exchange request failed. url=${TOKEN_URL}; redirect_uri=${redirectUri}; response_type=authorization_code; details=${formatErrorDetails(error)}`);
@@ -189,6 +189,10 @@ async function loginAnthropic(interaction) {
189
189
  const { verifier, challenge } = await generatePKCE();
190
190
  const server = await startCallbackServer(verifier);
191
191
  const manualAbort = new AbortController();
192
+ const onAbort = () => server.cancelWait();
193
+ interaction.signal.addEventListener("abort", onAbort, { once: true });
194
+ if (interaction.signal.aborted)
195
+ onAbort();
192
196
  let code;
193
197
  let state;
194
198
  let manualInput;
@@ -255,9 +259,10 @@ async function loginAnthropic(interaction) {
255
259
  if (!state)
256
260
  throw new Error("Missing OAuth state");
257
261
  interaction.notify({ type: "progress", message: "Exchanging authorization code for tokens..." });
258
- return exchangeAuthorizationCode(code, state, verifier, REDIRECT_URI);
262
+ return exchangeAuthorizationCode(code, state, verifier, REDIRECT_URI, interaction.signal);
259
263
  }
260
264
  finally {
265
+ interaction.signal.removeEventListener("abort", onAbort);
261
266
  manualAbort.abort();
262
267
  server.server.close();
263
268
  }
@@ -265,14 +270,14 @@ async function loginAnthropic(interaction) {
265
270
  /**
266
271
  * Refresh Anthropic OAuth token
267
272
  */
268
- async function refreshAnthropicToken(refreshToken) {
273
+ async function refreshAnthropicToken(refreshToken, signal) {
269
274
  let responseBody;
270
275
  try {
271
276
  responseBody = await postJson(TOKEN_URL, {
272
277
  grant_type: "refresh_token",
273
278
  client_id: CLIENT_ID,
274
279
  refresh_token: refreshToken,
275
- });
280
+ }, signal);
276
281
  }
277
282
  catch (error) {
278
283
  throw new Error(`Anthropic token refresh request failed. url=${TOKEN_URL}; details=${formatErrorDetails(error)}`);
@@ -293,8 +298,9 @@ async function refreshAnthropicToken(refreshToken) {
293
298
  }
294
299
  export const anthropicOAuth = {
295
300
  name: "Anthropic (Claude Pro/Max)",
301
+ isSubscription: true,
296
302
  login: loginAnthropic,
297
- refresh: (credential) => refreshAnthropicToken(credential.refresh),
303
+ refresh: (credential, signal) => refreshAnthropicToken(credential.refresh, signal),
298
304
  async toAuth(credential) {
299
305
  return { apiKey: credential.access };
300
306
  },