@earendil-works/pi-ai 1.3.0 → 1.5.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 (304) hide show
  1. package/README.md +113 -38
  2. package/dist/api/anthropic-messages.d.ts.map +1 -1
  3. package/dist/api/anthropic-messages.js +66 -81
  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 +8 -10
  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 +137 -103
  10. package/dist/api/bedrock-converse-stream.js.map +1 -1
  11. package/dist/api/classifier-shared.d.ts.map +1 -1
  12. package/dist/api/classifier-shared.js +4 -3
  13. package/dist/api/classifier-shared.js.map +1 -1
  14. package/dist/api/cloudflare-workers-ai-system-one.d.ts.map +1 -1
  15. package/dist/api/cloudflare-workers-ai-system-one.js +8 -0
  16. package/dist/api/cloudflare-workers-ai-system-one.js.map +1 -1
  17. package/dist/api/constrained-sampling.d.ts +15 -1
  18. package/dist/api/constrained-sampling.d.ts.map +1 -1
  19. package/dist/api/constrained-sampling.js +51 -18
  20. package/dist/api/constrained-sampling.js.map +1 -1
  21. package/dist/api/google-generative-ai.d.ts.map +1 -1
  22. package/dist/api/google-generative-ai.js +4 -10
  23. package/dist/api/google-generative-ai.js.map +1 -1
  24. package/dist/api/google-shared.d.ts +2 -1
  25. package/dist/api/google-shared.d.ts.map +1 -1
  26. package/dist/api/google-shared.js +58 -3
  27. package/dist/api/google-shared.js.map +1 -1
  28. package/dist/api/google-vertex.d.ts.map +1 -1
  29. package/dist/api/google-vertex.js +9 -15
  30. package/dist/api/google-vertex.js.map +1 -1
  31. package/dist/api/lazy.d.ts +7 -2
  32. package/dist/api/lazy.d.ts.map +1 -1
  33. package/dist/api/lazy.js +24 -5
  34. package/dist/api/lazy.js.map +1 -1
  35. package/dist/api/llama-cpp-classify.d.ts.map +1 -1
  36. package/dist/api/llama-cpp-classify.js +2 -1
  37. package/dist/api/llama-cpp-classify.js.map +1 -1
  38. package/dist/api/mistral-conversations.d.ts.map +1 -1
  39. package/dist/api/mistral-conversations.js +19 -46
  40. package/dist/api/mistral-conversations.js.map +1 -1
  41. package/dist/api/openai-codex-responses.d.ts.map +1 -1
  42. package/dist/api/openai-codex-responses.js +17 -16
  43. package/dist/api/openai-codex-responses.js.map +1 -1
  44. package/dist/api/openai-completions.d.ts.map +1 -1
  45. package/dist/api/openai-completions.js +56 -62
  46. package/dist/api/openai-completions.js.map +1 -1
  47. package/dist/api/openai-responses-shared.d.ts +16 -0
  48. package/dist/api/openai-responses-shared.d.ts.map +1 -1
  49. package/dist/api/openai-responses-shared.js +119 -66
  50. package/dist/api/openai-responses-shared.js.map +1 -1
  51. package/dist/api/openai-responses.d.ts.map +1 -1
  52. package/dist/api/openai-responses.js +17 -15
  53. package/dist/api/openai-responses.js.map +1 -1
  54. package/dist/api/openrouter-images.d.ts.map +1 -1
  55. package/dist/api/openrouter-images.js +5 -3
  56. package/dist/api/openrouter-images.js.map +1 -1
  57. package/dist/api/pi-messages.d.ts +2 -0
  58. package/dist/api/pi-messages.d.ts.map +1 -1
  59. package/dist/api/pi-messages.js +27 -12
  60. package/dist/api/pi-messages.js.map +1 -1
  61. package/dist/api/simple-options.d.ts.map +1 -1
  62. package/dist/api/simple-options.js +2 -1
  63. package/dist/api/simple-options.js.map +1 -1
  64. package/dist/api/system-one-shared.d.ts +29 -2
  65. package/dist/api/system-one-shared.d.ts.map +1 -1
  66. package/dist/api/system-one-shared.js +55 -3
  67. package/dist/api/system-one-shared.js.map +1 -1
  68. package/dist/api/typesafe-system-one.d.ts.map +1 -1
  69. package/dist/api/typesafe-system-one.js +10 -0
  70. package/dist/api/typesafe-system-one.js.map +1 -1
  71. package/dist/auth/oauth/github-copilot.d.ts.map +1 -1
  72. package/dist/auth/oauth/github-copilot.js +4 -11
  73. package/dist/auth/oauth/github-copilot.js.map +1 -1
  74. package/dist/auth/oauth/kimi-coding.d.ts.map +1 -1
  75. package/dist/auth/oauth/kimi-coding.js +4 -22
  76. package/dist/auth/oauth/kimi-coding.js.map +1 -1
  77. package/dist/auth/oauth/meta.d.ts.map +1 -1
  78. package/dist/auth/oauth/meta.js +1 -14
  79. package/dist/auth/oauth/meta.js.map +1 -1
  80. package/dist/auth/oauth/radius.d.ts.map +1 -1
  81. package/dist/auth/oauth/radius.js +9 -3
  82. package/dist/auth/oauth/radius.js.map +1 -1
  83. package/dist/auth/oauth/trusted-url.d.ts +7 -0
  84. package/dist/auth/oauth/trusted-url.d.ts.map +1 -0
  85. package/dist/auth/oauth/trusted-url.js +12 -0
  86. package/dist/auth/oauth/trusted-url.js.map +1 -0
  87. package/dist/auth/types.d.ts +4 -0
  88. package/dist/auth/types.d.ts.map +1 -1
  89. package/dist/auth/types.js.map +1 -1
  90. package/dist/cli.js +6 -2
  91. package/dist/cli.js.map +1 -1
  92. package/dist/compat/extension-oauth-types.d.ts +4 -0
  93. package/dist/compat/extension-oauth-types.d.ts.map +1 -1
  94. package/dist/compat/extension-oauth-types.js.map +1 -1
  95. package/dist/index.d.ts +4 -3
  96. package/dist/index.d.ts.map +1 -1
  97. package/dist/index.js +4 -2
  98. package/dist/index.js.map +1 -1
  99. package/dist/models.d.ts +4 -0
  100. package/dist/models.d.ts.map +1 -1
  101. package/dist/models.generated.js +1 -1
  102. package/dist/models.generated.js.map +1 -1
  103. package/dist/models.js +20 -6
  104. package/dist/models.js.map +1 -1
  105. package/dist/providers/amazon-bedrock.models.js +1 -1
  106. package/dist/providers/amazon-bedrock.models.js.map +1 -1
  107. package/dist/providers/ant-ling.models.js +1 -1
  108. package/dist/providers/ant-ling.models.js.map +1 -1
  109. package/dist/providers/anthropic.models.js +1 -1
  110. package/dist/providers/anthropic.models.js.map +1 -1
  111. package/dist/providers/azure.models.js +1 -1
  112. package/dist/providers/azure.models.js.map +1 -1
  113. package/dist/providers/baseten.models.js +1 -1
  114. package/dist/providers/baseten.models.js.map +1 -1
  115. package/dist/providers/cerebras.models.js +1 -1
  116. package/dist/providers/cerebras.models.js.map +1 -1
  117. package/dist/providers/cloudflare-ai-gateway.models.js +1 -1
  118. package/dist/providers/cloudflare-ai-gateway.models.js.map +1 -1
  119. package/dist/providers/cloudflare-workers-ai.models.js +1 -1
  120. package/dist/providers/cloudflare-workers-ai.models.js.map +1 -1
  121. package/dist/providers/compat-schema.d.ts +444 -304
  122. package/dist/providers/compat-schema.d.ts.map +1 -1
  123. package/dist/providers/compat-schema.js +155 -109
  124. package/dist/providers/compat-schema.js.map +1 -1
  125. package/dist/providers/data/.manifest.json +1 -1
  126. package/dist/providers/data/amazon-bedrock.json +1 -1
  127. package/dist/providers/data/anthropic.json +1 -1
  128. package/dist/providers/data/azure.json +1 -1
  129. package/dist/providers/data/baseten.json +1 -1
  130. package/dist/providers/data/cerebras.json +1 -1
  131. package/dist/providers/data/cloudflare-ai-gateway.json +1 -1
  132. package/dist/providers/data/cloudflare-workers-ai.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/google-vertex.json +1 -1
  136. package/dist/providers/data/google.json +1 -1
  137. package/dist/providers/data/groq.json +1 -1
  138. package/dist/providers/data/huggingface.json +1 -1
  139. package/dist/providers/data/kimi-coding.json +1 -1
  140. package/dist/providers/data/minimax-cn.json +1 -1
  141. package/dist/providers/data/minimax.json +1 -1
  142. package/dist/providers/data/mistral.json +1 -1
  143. package/dist/providers/data/moonshotai-cn.json +1 -1
  144. package/dist/providers/data/moonshotai.json +1 -1
  145. package/dist/providers/data/nvidia.json +1 -1
  146. package/dist/providers/data/openai-codex.json +1 -1
  147. package/dist/providers/data/openai.json +1 -1
  148. package/dist/providers/data/opencode-go.json +1 -1
  149. package/dist/providers/data/opencode.json +1 -1
  150. package/dist/providers/data/openrouter.json +1 -1
  151. package/dist/providers/data/qwen-token-plan-cn.json +1 -1
  152. package/dist/providers/data/qwen-token-plan-individual.json +1 -1
  153. package/dist/providers/data/qwen-token-plan.json +1 -1
  154. package/dist/providers/data/radius.json +1 -1
  155. package/dist/providers/data/together.json +1 -1
  156. package/dist/providers/data/typesafe.json +1 -1
  157. package/dist/providers/data/vercel-ai-gateway.json +1 -1
  158. package/dist/providers/data/xai.json +1 -1
  159. package/dist/providers/data/xiaomi-token-plan-ams.json +1 -1
  160. package/dist/providers/data/xiaomi-token-plan-cn.json +1 -1
  161. package/dist/providers/data/xiaomi-token-plan-sgp.json +1 -1
  162. package/dist/providers/data/xiaomi.json +1 -1
  163. package/dist/providers/data/zai-coding-cn.json +1 -1
  164. package/dist/providers/data/zai.json +1 -1
  165. package/dist/providers/deepseek.models.js +1 -1
  166. package/dist/providers/deepseek.models.js.map +1 -1
  167. package/dist/providers/faux.d.ts.map +1 -1
  168. package/dist/providers/faux.js +7 -2
  169. package/dist/providers/faux.js.map +1 -1
  170. package/dist/providers/fireworks.models.js +1 -1
  171. package/dist/providers/fireworks.models.js.map +1 -1
  172. package/dist/providers/github-copilot.models.js +1 -1
  173. package/dist/providers/github-copilot.models.js.map +1 -1
  174. package/dist/providers/google-vertex.models.js +1 -1
  175. package/dist/providers/google-vertex.models.js.map +1 -1
  176. package/dist/providers/google.models.js +1 -1
  177. package/dist/providers/google.models.js.map +1 -1
  178. package/dist/providers/groq.models.js +1 -1
  179. package/dist/providers/groq.models.js.map +1 -1
  180. package/dist/providers/huggingface.models.js +1 -1
  181. package/dist/providers/huggingface.models.js.map +1 -1
  182. package/dist/providers/kimi-coding.models.js +1 -1
  183. package/dist/providers/kimi-coding.models.js.map +1 -1
  184. package/dist/providers/meta.models.js +1 -1
  185. package/dist/providers/meta.models.js.map +1 -1
  186. package/dist/providers/minimax-cn.models.js +1 -1
  187. package/dist/providers/minimax-cn.models.js.map +1 -1
  188. package/dist/providers/minimax.models.js +1 -1
  189. package/dist/providers/minimax.models.js.map +1 -1
  190. package/dist/providers/mistral.models.js +1 -1
  191. package/dist/providers/mistral.models.js.map +1 -1
  192. package/dist/providers/model-schema.d.ts +65 -65
  193. package/dist/providers/model-schema.d.ts.map +1 -1
  194. package/dist/providers/model-schema.js +44 -31
  195. package/dist/providers/model-schema.js.map +1 -1
  196. package/dist/providers/moonshotai-cn.models.js +1 -1
  197. package/dist/providers/moonshotai-cn.models.js.map +1 -1
  198. package/dist/providers/moonshotai.models.js +1 -1
  199. package/dist/providers/moonshotai.models.js.map +1 -1
  200. package/dist/providers/nvidia.models.js +1 -1
  201. package/dist/providers/nvidia.models.js.map +1 -1
  202. package/dist/providers/openai-codex.models.js +1 -1
  203. package/dist/providers/openai-codex.models.js.map +1 -1
  204. package/dist/providers/openai.models.js +1 -1
  205. package/dist/providers/openai.models.js.map +1 -1
  206. package/dist/providers/opencode-go.models.js +1 -1
  207. package/dist/providers/opencode-go.models.js.map +1 -1
  208. package/dist/providers/opencode.js +1 -1
  209. package/dist/providers/opencode.js.map +1 -1
  210. package/dist/providers/opencode.models.js +1 -1
  211. package/dist/providers/opencode.models.js.map +1 -1
  212. package/dist/providers/openrouter.models.js +1 -1
  213. package/dist/providers/openrouter.models.js.map +1 -1
  214. package/dist/providers/qwen-token-plan-cn.models.js +1 -1
  215. package/dist/providers/qwen-token-plan-cn.models.js.map +1 -1
  216. package/dist/providers/qwen-token-plan-individual.models.js +1 -1
  217. package/dist/providers/qwen-token-plan-individual.models.js.map +1 -1
  218. package/dist/providers/qwen-token-plan.models.js +1 -1
  219. package/dist/providers/qwen-token-plan.models.js.map +1 -1
  220. package/dist/providers/radius-config.d.ts.map +1 -1
  221. package/dist/providers/radius-config.js +2 -1
  222. package/dist/providers/radius-config.js.map +1 -1
  223. package/dist/providers/radius.models.js +1 -1
  224. package/dist/providers/radius.models.js.map +1 -1
  225. package/dist/providers/schema-builders.d.ts +10 -0
  226. package/dist/providers/schema-builders.d.ts.map +1 -0
  227. package/dist/providers/schema-builders.js +18 -0
  228. package/dist/providers/schema-builders.js.map +1 -0
  229. package/dist/providers/together.models.js +1 -1
  230. package/dist/providers/together.models.js.map +1 -1
  231. package/dist/providers/typesafe.models.js +1 -1
  232. package/dist/providers/typesafe.models.js.map +1 -1
  233. package/dist/providers/vercel-ai-gateway.models.js +1 -1
  234. package/dist/providers/vercel-ai-gateway.models.js.map +1 -1
  235. package/dist/providers/xai.models.js +1 -1
  236. package/dist/providers/xai.models.js.map +1 -1
  237. package/dist/providers/xiaomi-token-plan-ams.models.js +1 -1
  238. package/dist/providers/xiaomi-token-plan-ams.models.js.map +1 -1
  239. package/dist/providers/xiaomi-token-plan-cn.models.js +1 -1
  240. package/dist/providers/xiaomi-token-plan-cn.models.js.map +1 -1
  241. package/dist/providers/xiaomi-token-plan-sgp.models.js +1 -1
  242. package/dist/providers/xiaomi-token-plan-sgp.models.js.map +1 -1
  243. package/dist/providers/xiaomi.models.js +1 -1
  244. package/dist/providers/xiaomi.models.js.map +1 -1
  245. package/dist/providers/zai-coding-cn.models.js +1 -1
  246. package/dist/providers/zai-coding-cn.models.js.map +1 -1
  247. package/dist/providers/zai.models.js +1 -1
  248. package/dist/providers/zai.models.js.map +1 -1
  249. package/dist/telemetry.d.ts +288 -0
  250. package/dist/telemetry.d.ts.map +1 -0
  251. package/dist/telemetry.js +192 -0
  252. package/dist/telemetry.js.map +1 -0
  253. package/dist/types.d.ts +25 -7
  254. package/dist/types.d.ts.map +1 -1
  255. package/dist/types.js.map +1 -1
  256. package/dist/utils/error-body.d.ts.map +1 -1
  257. package/dist/utils/error-body.js +2 -1
  258. package/dist/utils/error-body.js.map +1 -1
  259. package/dist/utils/identity.d.ts +65 -0
  260. package/dist/utils/identity.d.ts.map +1 -0
  261. package/dist/utils/identity.js +141 -0
  262. package/dist/utils/identity.js.map +1 -0
  263. package/dist/utils/openrouter-cost.d.ts +24 -0
  264. package/dist/utils/openrouter-cost.d.ts.map +1 -0
  265. package/dist/utils/openrouter-cost.js +34 -0
  266. package/dist/utils/openrouter-cost.js.map +1 -0
  267. package/dist/utils/overflow.d.ts +1 -0
  268. package/dist/utils/overflow.d.ts.map +1 -1
  269. package/dist/utils/overflow.js +8 -1
  270. package/dist/utils/overflow.js.map +1 -1
  271. package/dist/utils/retry.d.ts.map +1 -1
  272. package/dist/utils/retry.js +19 -7
  273. package/dist/utils/retry.js.map +1 -1
  274. package/dist/utils/streaming-json.d.ts +84 -0
  275. package/dist/utils/streaming-json.d.ts.map +1 -0
  276. package/dist/utils/streaming-json.js +513 -0
  277. package/dist/utils/streaming-json.js.map +1 -0
  278. package/dist/utils/{typebox-helpers.d.ts → string-enum.d.ts} +5 -5
  279. package/dist/utils/string-enum.d.ts.map +1 -0
  280. package/dist/utils/{typebox-helpers.js → string-enum.js} +5 -6
  281. package/dist/utils/string-enum.js.map +1 -0
  282. package/dist/utils/text.d.ts +7 -0
  283. package/dist/utils/text.d.ts.map +1 -1
  284. package/dist/utils/text.js +9 -0
  285. package/dist/utils/text.js.map +1 -1
  286. package/dist/utils/transcript.d.ts +23 -9
  287. package/dist/utils/transcript.d.ts.map +1 -1
  288. package/dist/utils/transcript.js +30 -19
  289. package/dist/utils/transcript.js.map +1 -1
  290. package/dist/utils/validation.d.ts +5 -3
  291. package/dist/utils/validation.d.ts.map +1 -1
  292. package/dist/utils/validation.js +27 -277
  293. package/dist/utils/validation.js.map +1 -1
  294. package/dist/utils/version.d.ts +2 -0
  295. package/dist/utils/version.d.ts.map +1 -0
  296. package/dist/utils/version.js +3 -0
  297. package/dist/utils/version.js.map +1 -0
  298. package/package.json +11 -10
  299. package/dist/utils/pi-user-agent.d.ts +0 -2
  300. package/dist/utils/pi-user-agent.d.ts.map +0 -1
  301. package/dist/utils/pi-user-agent.js +0 -12
  302. package/dist/utils/pi-user-agent.js.map +0 -1
  303. package/dist/utils/typebox-helpers.d.ts.map +0 -1
  304. package/dist/utils/typebox-helpers.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"system-one-shared.js","sourceRoot":"","sources":["../../src/api/system-one-shared.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n\tClassifierAnswer,\n\tClassifierApi,\n\tClassifierContext,\n\tClassifierModel,\n\tClassifierOptions,\n\tClassifierResult,\n} from \"../types.ts\";\nimport { formatProviderError, normalizeProviderError } from \"../utils/error-body.ts\";\nimport { isRecord, parseClassifierUsage, postClassifierRequest, requiredNumber } from \"./classifier-shared.ts\";\n\n/** TypeSafe System One request body without the transport-specific envelope. */\nexport interface SystemOneWireRequest {\n\tstate: ClassifierContext[\"state\"];\n\tquestions: Record<string, unknown>;\n}\n\n/** Differences between services that serve System One models. */\nexport interface SystemOneTransport {\n\t/** Classifier API implemented by this transport. */\n\tapi: ClassifierApi;\n\t/** Service name used in error messages. */\n\tlabel: string;\n\t/** Absolute request URL. */\n\turl(model: ClassifierModel<ClassifierApi>): URL;\n\t/** Wraps the System One request in the service's request envelope. */\n\tpayload(model: ClassifierModel<ClassifierApi>, request: SystemOneWireRequest): unknown;\n\t/** Extracts the System One output (`{ answers, usage }`) from the service's response envelope. */\n\toutput(body: unknown): Record<string, unknown>;\n}\n\nfunction probabilities(label: string, value: unknown, id: string): Record<string, number> {\n\tif (!isRecord(value)) throw new Error(`${label} returned invalid probabilities for ${id}`);\n\treturn Object.fromEntries(\n\t\tObject.entries(value).map(([key, probability]) => [\n\t\t\tkey,\n\t\t\trequiredNumber(label, probability, `probability for ${id}.${key}`),\n\t\t]),\n\t);\n}\n\nfunction parseAnswers(label: string, value: unknown, context: ClassifierContext): Record<string, ClassifierAnswer> {\n\tif (!isRecord(value)) throw new Error(`${label} returned an unexpected response`);\n\tconst answers: Array<[string, ClassifierAnswer]> = [];\n\tfor (const [id, question] of Object.entries(context.questions)) {\n\t\tconst answer = value[id];\n\t\tif (!isRecord(answer)) throw new Error(`${label} did not return an answer for ${id}`);\n\t\tif (question.type === \"choice\") {\n\t\t\tif (answer.type !== \"choice\" || typeof answer.choice !== \"string\") {\n\t\t\t\tthrow new Error(`${label} did not return a choice answer for ${id}`);\n\t\t\t}\n\t\t\tanswers.push([\n\t\t\t\tid,\n\t\t\t\t{\n\t\t\t\t\ttype: \"choice\",\n\t\t\t\t\tchoice: answer.choice,\n\t\t\t\t\tprobabilities: probabilities(label, answer.probabilities, id),\n\t\t\t\t\tconfidence: requiredNumber(label, answer.confidence, `confidence for ${id}`),\n\t\t\t\t},\n\t\t\t]);\n\t\t} else if (question.type === \"score\") {\n\t\t\tif (answer.type !== \"score\") throw new Error(`${label} did not return a score answer for ${id}`);\n\t\t\tanswers.push([\n\t\t\t\tid,\n\t\t\t\t{\n\t\t\t\t\ttype: \"score\",\n\t\t\t\t\tscore: requiredNumber(label, answer.score, `score for ${id}`),\n\t\t\t\t\tconfidence: requiredNumber(label, answer.confidence, `confidence for ${id}`),\n\t\t\t\t},\n\t\t\t]);\n\t\t} else {\n\t\t\tif (answer.type !== \"noul\") throw new Error(`${label} did not return a bool answer for ${id}`);\n\t\t\tanswers.push([\n\t\t\t\tid,\n\t\t\t\t{\n\t\t\t\t\ttype: \"bool\",\n\t\t\t\t\tprobability: requiredNumber(label, answer.noul, `probability for ${id}`),\n\t\t\t\t},\n\t\t\t]);\n\t\t}\n\t}\n\treturn Object.fromEntries(answers);\n}\n\n/** Maps public `bool` questions to TypeSafe's wire-level `noul` type. */\nfunction wireRequest(context: ClassifierContext): SystemOneWireRequest {\n\treturn {\n\t\tstate: context.state,\n\t\tquestions: Object.fromEntries(\n\t\t\tObject.entries(context.questions).map(([id, question]) => [\n\t\t\t\tid,\n\t\t\t\tquestion.type === \"bool\" ? { ...question, type: \"noul\" } : question,\n\t\t\t]),\n\t\t),\n\t};\n}\n\n/** Runs one System One classification over the given transport. */\nexport async function classifySystemOne(\n\ttransport: SystemOneTransport,\n\tmodel: ClassifierModel<ClassifierApi>,\n\tcontext: ClassifierContext,\n\toptions: ClassifierOptions | undefined,\n): Promise<ClassifierResult> {\n\tconst output: ClassifierResult = {\n\t\tapi: model.api,\n\t\tprovider: model.provider,\n\t\tmodel: model.id,\n\t\tanswers: {},\n\t\tstopReason: \"stop\",\n\t\ttimestamp: Date.now(),\n\t};\n\n\ttry {\n\t\tif (model.api !== transport.api) throw new Error(`Unsupported classifier API: ${model.api}`);\n\t\tif (context.images?.length) throw new Error(`${transport.label} does not support image input`);\n\t\tconst body = await postClassifierRequest(\n\t\t\ttransport.label,\n\t\t\ttransport.url(model),\n\t\t\tmodel,\n\t\t\ttransport.payload(model, wireRequest(context)),\n\t\t\toptions,\n\t\t);\n\t\tconst result = transport.output(body);\n\t\t// Set before parsing answers: a request with malformed answers was still billed.\n\t\tconst usage = parseClassifierUsage(result.usage, model);\n\t\tif (usage) output.usage = usage;\n\t\toutput.answers = parseAnswers(transport.label, result.answers, context);\n\t\treturn output;\n\t} catch (error) {\n\t\toutput.stopReason = options?.signal?.aborted ? \"aborted\" : \"error\";\n\t\toutput.errorMessage = formatProviderError(normalizeProviderError(error), `${transport.label} error`);\n\t\treturn output;\n\t}\n}\n"]}
1
+ {"version":3,"file":"system-one-shared.js","sourceRoot":"","sources":["../../src/api/system-one-shared.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n\tClassifierAnswer,\n\tClassifierApi,\n\tClassifierContext,\n\tClassifierModel,\n\tClassifierOptions,\n\tClassifierResult,\n\tImageContent,\n\tSystemOneCompat,\n} from \"../types.ts\";\nimport { formatProviderError, normalizeProviderError } from \"../utils/error-body.ts\";\nimport { isRecord, parseClassifierUsage, postClassifierRequest, requiredNumber } from \"./classifier-shared.ts\";\n\n/** A System One image asset: base64 file bytes, referenced by its name from the state. */\ninterface SystemOneImageAsset {\n\ttype: \"image\";\n\tformat: \"png\" | \"jpeg\";\n\tdata_base64: string;\n}\n\n/** An image in the state, OpenRouter's form. */\ninterface SystemOneImageUrlPart {\n\ttype: \"image_url\";\n\timage_url: { url: string };\n}\n\n/** TypeSafe System One request body without the transport-specific envelope. */\nexport interface SystemOneWireRequest {\n\t/** The context state, or with images a list of the images or their asset names followed by the state. */\n\tstate: unknown;\n\tquestions: Record<string, unknown>;\n\t/** Images as System One assets, keyed by the names the state references. */\n\tassets?: Record<string, SystemOneImageAsset>;\n\t/** Images as data URLs, Clef's extension to System One. */\n\timages?: string[];\n}\n\n/**\n * How a service takes images (`SystemOneCompat.imageInput`):\n * - `assets`: TypeSafe's `assets` map, `{ \"<image-1>\": { type: \"image\", format, data_base64 } }`,\n * with the names placed before the state: `state: [\"<image-1>\", state]`. PNG and JPEG only.\n * - `images`: Clef's `images` list of data URLs, which the model reads before the state.\n * PNG, JPEG, and WebP, at most four.\n * - `state-image-urls`: OpenRouter's form, data URL parts placed before the state:\n * `state: [{ type: \"image_url\", image_url: { url } }, state]`. OpenRouter accepts this for every\n * model, and drops `assets` silently.\n */\nexport type SystemOneImageInput = NonNullable<SystemOneCompat[\"imageInput\"]>;\n\n/** System One compatibility settings with every field resolved. */\nexport type ResolvedSystemOneCompat = Required<SystemOneCompat>;\n\n/** TypeSafe's opt-in header for its experimental image input. */\nconst IMAGE_OPT_IN_HEADERS = { \"TypeSafe-Danger-Zone-Images\": \"true\" };\n\n/** Differences between services that serve System One models. */\nexport interface SystemOneTransport {\n\t/** Classifier API implemented by this transport. */\n\tapi: ClassifierApi;\n\t/** Service name used in error messages. */\n\tlabel: string;\n\t/** Compatibility settings for models that do not set them in `compat`. */\n\tdetectCompat(model: ClassifierModel<ClassifierApi>): ResolvedSystemOneCompat;\n\t/** Absolute request URL. */\n\turl(model: ClassifierModel<ClassifierApi>): URL;\n\t/** Wraps the System One request in the service's request envelope. */\n\tpayload(model: ClassifierModel<ClassifierApi>, request: SystemOneWireRequest): unknown;\n\t/** Extracts the System One output (`{ answers, usage }`) from the service's response envelope. */\n\toutput(body: unknown): Record<string, unknown>;\n}\n\nfunction probabilities(label: string, value: unknown, id: string): Record<string, number> {\n\tif (!isRecord(value)) throw new Error(`${label} returned invalid probabilities for ${id}`);\n\treturn Object.fromEntries(\n\t\tObject.entries(value).map(([key, probability]) => [\n\t\t\tkey,\n\t\t\trequiredNumber(label, probability, `probability for ${id}.${key}`),\n\t\t]),\n\t);\n}\n\nfunction parseAnswers(label: string, value: unknown, context: ClassifierContext): Record<string, ClassifierAnswer> {\n\tif (!isRecord(value)) throw new Error(`${label} returned an unexpected response`);\n\tconst answers: Array<[string, ClassifierAnswer]> = [];\n\tfor (const [id, question] of Object.entries(context.questions)) {\n\t\tconst answer = value[id];\n\t\tif (!isRecord(answer)) throw new Error(`${label} did not return an answer for ${id}`);\n\t\tif (question.type === \"choice\") {\n\t\t\tif (answer.type !== \"choice\" || typeof answer.choice !== \"string\") {\n\t\t\t\tthrow new Error(`${label} did not return a choice answer for ${id}`);\n\t\t\t}\n\t\t\tanswers.push([\n\t\t\t\tid,\n\t\t\t\t{\n\t\t\t\t\ttype: \"choice\",\n\t\t\t\t\tchoice: answer.choice,\n\t\t\t\t\tprobabilities: probabilities(label, answer.probabilities, id),\n\t\t\t\t\tconfidence: requiredNumber(label, answer.confidence, `confidence for ${id}`),\n\t\t\t\t},\n\t\t\t]);\n\t\t} else if (question.type === \"score\") {\n\t\t\tif (answer.type !== \"score\") throw new Error(`${label} did not return a score answer for ${id}`);\n\t\t\tanswers.push([\n\t\t\t\tid,\n\t\t\t\t{\n\t\t\t\t\ttype: \"score\",\n\t\t\t\t\tscore: requiredNumber(label, answer.score, `score for ${id}`),\n\t\t\t\t\tconfidence: requiredNumber(label, answer.confidence, `confidence for ${id}`),\n\t\t\t\t},\n\t\t\t]);\n\t\t} else {\n\t\t\tif (answer.type !== \"noul\") throw new Error(`${label} did not return a bool answer for ${id}`);\n\t\t\tanswers.push([\n\t\t\t\tid,\n\t\t\t\t{\n\t\t\t\t\ttype: \"bool\",\n\t\t\t\t\tprobability: requiredNumber(label, answer.noul, `probability for ${id}`),\n\t\t\t\t},\n\t\t\t]);\n\t\t}\n\t}\n\treturn Object.fromEntries(answers);\n}\n\nconst ASSET_FORMATS: Record<string, SystemOneImageAsset[\"format\"]> = { \"image/png\": \"png\", \"image/jpeg\": \"jpeg\" };\nconst DATA_URL_TYPES = new Set([\"image/png\", \"image/jpeg\", \"image/webp\"]);\n/** Clef accepts at most this many images per request. */\nconst MAX_DATA_URL_IMAGES = 4;\n\n/** Adds the context images to `request` in the service's form. */\nfunction addImages(\n\tlabel: string,\n\tmodel: ClassifierModel<ClassifierApi>,\n\tinput: SystemOneImageInput,\n\timages: ImageContent[],\n\trequest: SystemOneWireRequest,\n): void {\n\tif (input === \"images\") {\n\t\tif (images.length > MAX_DATA_URL_IMAGES) {\n\t\t\tthrow new Error(\n\t\t\t\t`${label} accepts at most ${MAX_DATA_URL_IMAGES} images for ${model.id}, got ${images.length}`,\n\t\t\t);\n\t\t}\n\t\trequest.images = images.map((image) => {\n\t\t\tif (!DATA_URL_TYPES.has(image.mimeType)) {\n\t\t\t\tthrow new Error(`${label} accepts PNG, JPEG, and WebP images for ${model.id}, got ${image.mimeType}`);\n\t\t\t}\n\t\t\treturn `data:${image.mimeType};base64,${image.data}`;\n\t\t});\n\t\treturn;\n\t}\n\tif (input === \"state-image-urls\") {\n\t\t// OpenRouter validates the images against the model that serves the request.\n\t\tconst parts = images.map(\n\t\t\t(image): SystemOneImageUrlPart => ({\n\t\t\t\ttype: \"image_url\",\n\t\t\t\timage_url: { url: `data:${image.mimeType};base64,${image.data}` },\n\t\t\t}),\n\t\t);\n\t\trequest.state = [...parts, request.state];\n\t\treturn;\n\t}\n\tconst assets: Record<string, SystemOneImageAsset> = {};\n\timages.forEach((image, index) => {\n\t\tconst format = ASSET_FORMATS[image.mimeType];\n\t\tif (!format) throw new Error(`${label} accepts PNG and JPEG images for ${model.id}, got ${image.mimeType}`);\n\t\tassets[`<image-${index + 1}>`] = { type: \"image\", format, data_base64: image.data };\n\t});\n\trequest.assets = assets;\n\t// Every asset must be referenced from the request. The names go before the state, where Clef\n\t// also places its images.\n\trequest.state = [...Object.keys(assets), request.state];\n}\n\n/** Maps public `bool` questions to TypeSafe's wire-level `noul` type. */\nfunction wireRequest(context: ClassifierContext): SystemOneWireRequest {\n\treturn {\n\t\tstate: context.state,\n\t\tquestions: Object.fromEntries(\n\t\t\tObject.entries(context.questions).map(([id, question]) => [\n\t\t\t\tid,\n\t\t\t\tquestion.type === \"bool\" ? { ...question, type: \"noul\" } : question,\n\t\t\t]),\n\t\t),\n\t};\n}\n\n/** Runs one System One classification over the given transport. */\nexport async function classifySystemOne(\n\ttransport: SystemOneTransport,\n\tmodel: ClassifierModel<ClassifierApi>,\n\tcontext: ClassifierContext,\n\toptions: ClassifierOptions | undefined,\n): Promise<ClassifierResult> {\n\tconst output: ClassifierResult = {\n\t\tapi: model.api,\n\t\tprovider: model.provider,\n\t\tmodel: model.id,\n\t\tanswers: {},\n\t\tstopReason: \"stop\",\n\t\ttimestamp: Date.now(),\n\t};\n\n\ttry {\n\t\tif (model.api !== transport.api) throw new Error(`Unsupported classifier API: ${model.api}`);\n\t\tconst request = wireRequest(context);\n\t\tlet requestOptions = options;\n\t\tif (context.images?.length) {\n\t\t\tif (!model.input.includes(\"image\")) {\n\t\t\t\tthrow new Error(`${transport.label} does not support image input for ${model.id}`);\n\t\t\t}\n\t\t\tconst detected = transport.detectCompat(model);\n\t\t\tconst imageInput = model.compat?.imageInput ?? detected.imageInput;\n\t\t\taddImages(transport.label, model, imageInput, context.images, request);\n\t\t\tif (model.compat?.sendImageOptInHeader ?? detected.sendImageOptInHeader) {\n\t\t\t\trequestOptions = { ...options, headers: { ...IMAGE_OPT_IN_HEADERS, ...options?.headers } };\n\t\t\t}\n\t\t}\n\t\tconst body = await postClassifierRequest(\n\t\t\ttransport.label,\n\t\t\ttransport.url(model),\n\t\t\tmodel,\n\t\t\ttransport.payload(model, request),\n\t\t\trequestOptions,\n\t\t);\n\t\tconst result = transport.output(body);\n\t\t// Set before parsing answers: a request with malformed answers was still billed.\n\t\tconst usage = parseClassifierUsage(result.usage, model);\n\t\tif (usage) output.usage = usage;\n\t\toutput.answers = parseAnswers(transport.label, result.answers, context);\n\t\treturn output;\n\t} catch (error) {\n\t\toutput.stopReason = options?.signal?.aborted ? \"aborted\" : \"error\";\n\t\toutput.errorMessage = formatProviderError(normalizeProviderError(error), `${transport.label} error`);\n\t\treturn output;\n\t}\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"typesafe-system-one.d.ts","sourceRoot":"","sources":["../../src/api/typesafe-system-one.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAmBzE,gGAAgG;AAChG,eAAO,MAAM,QAAQ,EAAE,kBAAkB,CAAC,iBAAiB,CACL,CAAC"}
1
+ {"version":3,"file":"typesafe-system-one.d.ts","sourceRoot":"","sources":["../../src/api/typesafe-system-one.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AA8BzE,gGAAgG;AAChG,eAAO,MAAM,QAAQ,EAAE,kBAAkB,CAAC,iBAAiB,CACL,CAAC"}
@@ -3,10 +3,20 @@ import { classifySystemOne } from "./system-one-shared.js";
3
3
  /**
4
4
  * TypeSafe's native System One protocol. OpenRouter serves the same protocol,
5
5
  * so both providers use this API with different base URLs.
6
+ *
7
+ * TypeSafe takes images as `assets`. They are experimental and need the
8
+ * `TypeSafe-Danger-Zone-Images` opt-in header; without it the API answers 400.
9
+ * OpenRouter drops `assets` silently and takes images as `image_url` parts in the state instead.
10
+ * Models behind a proxy that hides both the provider ID and the OpenRouter host must set
11
+ * `compat.imageInput`.
6
12
  */
7
13
  const transport = {
8
14
  api: "typesafe-system-one",
9
15
  label: "System One API",
16
+ // OpenRouter by provider ID, which survives baseUrl overrides, or by host, which covers regional endpoints.
17
+ detectCompat: (model) => model.provider === "openrouter" || model.baseUrl.includes("openrouter.ai")
18
+ ? { imageInput: "state-image-urls", sendImageOptInHeader: false }
19
+ : { imageInput: "assets", sendImageOptInHeader: true },
10
20
  url: (model) => new URL("systemone", `${model.baseUrl.replace(/\/+$/u, "")}/`),
11
21
  payload: (model, request) => ({ model: model.id, ...request }),
12
22
  output: (body) => {
@@ -1 +1 @@
1
- {"version":3,"file":"typesafe-system-one.js","sourceRoot":"","sources":["../../src/api/typesafe-system-one.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAA2B,MAAM,wBAAwB,CAAC;AAEpF;;;GAGG;AACH,MAAM,SAAS,GAAuB;IACrC,GAAG,EAAE,qBAAqB;IAC1B,KAAK,EAAE,gBAAgB;IACvB,GAAG,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC,WAAW,EAAE,GAAG,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,GAAG,CAAC;IAC9E,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,EAAE,EAAE,GAAG,OAAO,EAAE,CAAC;IAC9D,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;QAChB,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;QACvF,OAAO,IAAI,CAAC;IACb,CAAC;CACD,CAAC;AAEF,gGAAgG;AAChG,MAAM,CAAC,MAAM,QAAQ,GAA0C,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,CAC1F,iBAAiB,CAAC,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC","sourcesContent":["import type { ClassifierFunction, ClassifierOptions } from \"../types.ts\";\nimport { isRecord } from \"./classifier-shared.ts\";\nimport { classifySystemOne, type SystemOneTransport } from \"./system-one-shared.ts\";\n\n/**\n * TypeSafe's native System One protocol. OpenRouter serves the same protocol,\n * so both providers use this API with different base URLs.\n */\nconst transport: SystemOneTransport = {\n\tapi: \"typesafe-system-one\",\n\tlabel: \"System One API\",\n\turl: (model) => new URL(\"systemone\", `${model.baseUrl.replace(/\\/+$/u, \"\")}/`),\n\tpayload: (model, request) => ({ model: model.id, ...request }),\n\toutput: (body) => {\n\t\tif (!isRecord(body)) throw new Error(\"System One API returned an unexpected response\");\n\t\treturn body;\n\t},\n};\n\n/** TypeSafe System One classification with public `bool` values mapped to wire-level `noul`. */\nexport const classify: ClassifierFunction<ClassifierOptions> = (model, context, options) =>\n\tclassifySystemOne(transport, model, context, options);\n"]}
1
+ {"version":3,"file":"typesafe-system-one.js","sourceRoot":"","sources":["../../src/api/typesafe-system-one.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAA2B,MAAM,wBAAwB,CAAC;AAEpF;;;;;;;;;GASG;AACH,MAAM,SAAS,GAAuB;IACrC,GAAG,EAAE,qBAAqB;IAC1B,KAAK,EAAE,gBAAgB;IACvB,4GAA4G;IAC5G,YAAY,EAAE,CAAC,KAAK,EAAE,EAAE,CACvB,KAAK,CAAC,QAAQ,KAAK,YAAY,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAC;QACzE,CAAC,CAAC,EAAE,UAAU,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,KAAK,EAAE;QACjE,CAAC,CAAC,EAAE,UAAU,EAAE,QAAQ,EAAE,oBAAoB,EAAE,IAAI,EAAE;IACxD,GAAG,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC,WAAW,EAAE,GAAG,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,GAAG,CAAC;IAC9E,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,EAAE,EAAE,GAAG,OAAO,EAAE,CAAC;IAC9D,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;QAChB,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;QACvF,OAAO,IAAI,CAAC;IACb,CAAC;CACD,CAAC;AAEF,gGAAgG;AAChG,MAAM,CAAC,MAAM,QAAQ,GAA0C,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,CAC1F,iBAAiB,CAAC,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC","sourcesContent":["import type { ClassifierFunction, ClassifierOptions } from \"../types.ts\";\nimport { isRecord } from \"./classifier-shared.ts\";\nimport { classifySystemOne, type SystemOneTransport } from \"./system-one-shared.ts\";\n\n/**\n * TypeSafe's native System One protocol. OpenRouter serves the same protocol,\n * so both providers use this API with different base URLs.\n *\n * TypeSafe takes images as `assets`. They are experimental and need the\n * `TypeSafe-Danger-Zone-Images` opt-in header; without it the API answers 400.\n * OpenRouter drops `assets` silently and takes images as `image_url` parts in the state instead.\n * Models behind a proxy that hides both the provider ID and the OpenRouter host must set\n * `compat.imageInput`.\n */\nconst transport: SystemOneTransport = {\n\tapi: \"typesafe-system-one\",\n\tlabel: \"System One API\",\n\t// OpenRouter by provider ID, which survives baseUrl overrides, or by host, which covers regional endpoints.\n\tdetectCompat: (model) =>\n\t\tmodel.provider === \"openrouter\" || model.baseUrl.includes(\"openrouter.ai\")\n\t\t\t? { imageInput: \"state-image-urls\", sendImageOptInHeader: false }\n\t\t\t: { imageInput: \"assets\", sendImageOptInHeader: true },\n\turl: (model) => new URL(\"systemone\", `${model.baseUrl.replace(/\\/+$/u, \"\")}/`),\n\tpayload: (model, request) => ({ model: model.id, ...request }),\n\toutput: (body) => {\n\t\tif (!isRecord(body)) throw new Error(\"System One API returned an unexpected response\");\n\t\treturn body;\n\t},\n};\n\n/** TypeSafe System One classification with public `bool` values mapped to wire-level `noul`. */\nexport const classify: ClassifierFunction<ClassifierOptions> = (model, context, options) =>\n\tclassifySystemOne(transport, model, context, options);\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"github-copilot.d.ts","sourceRoot":"","sources":["../../../src/auth/oauth/github-copilot.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,KAAK,EAAE,SAAS,EAA4C,MAAM,aAAa,CAAC;AAsevF,eAAO,MAAM,kBAAkB,EAAE,SAchC,CAAC"}
1
+ {"version":3,"file":"github-copilot.d.ts","sourceRoot":"","sources":["../../../src/auth/oauth/github-copilot.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,KAAK,EAAE,SAAS,EAA4C,MAAM,aAAa,CAAC;AAgevF,eAAO,MAAM,kBAAkB,EAAE,SAchC,CAAC"}
@@ -4,6 +4,7 @@
4
4
  import { GITHUB_COPILOT_MODELS } from "../../providers/github-copilot.models.js";
5
5
  import { sleep } from "../../utils/sleep.js";
6
6
  import { pollOAuthDeviceCodeFlow } from "./device-code.js";
7
+ import { trustedHttpUrl } from "./trusted-url.js";
7
8
  const decode = (s) => atob(s);
8
9
  const CLIENT_ID = decode("SXYxLmI1MDdhMDhjODdlY2ZlOTg=");
9
10
  const COPILOT_HEADERS = {
@@ -181,22 +182,14 @@ async function startDeviceFlow(domain, signal) {
181
182
  typeof expiresIn !== "number") {
182
183
  throw new Error("Invalid device code response fields");
183
184
  }
184
- // The verification URI is opened in the user's browser and to prevent `open` from
185
- // opening an executable or similar, we force it to be a URL.
186
- let parsedUri;
187
- try {
188
- parsedUri = new URL(verificationUri);
189
- }
190
- catch {
191
- throw new Error("Untrusted verification_uri in device code response");
192
- }
193
- if (parsedUri.protocol !== "https:" && parsedUri.protocol !== "http:") {
185
+ const trustedVerificationUri = trustedHttpUrl(verificationUri);
186
+ if (!trustedVerificationUri) {
194
187
  throw new Error("Untrusted verification_uri in device code response");
195
188
  }
196
189
  return {
197
190
  device_code: deviceCode,
198
191
  user_code: userCode,
199
- verification_uri: parsedUri.href,
192
+ verification_uri: trustedVerificationUri,
200
193
  interval,
201
194
  expires_in: expiresIn,
202
195
  };
@@ -1 +1 @@
1
- {"version":3,"file":"github-copilot.js","sourceRoot":"","sources":["../../../src/auth/oauth/github-copilot.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * GitHub Copilot OAuth flow\n */\n\nimport { GITHUB_COPILOT_MODELS } from \"../../providers/github-copilot.models.ts\";\nimport { sleep } from \"../../utils/sleep.ts\";\nimport type { OAuthAuth, OAuthCredential, ProviderAuthInteraction } from \"../types.ts\";\nimport { pollOAuthDeviceCodeFlow } from \"./device-code.ts\";\n\nconst decode = (s: string) => atob(s);\nconst CLIENT_ID = decode(\"SXYxLmI1MDdhMDhjODdlY2ZlOTg=\");\n\nconst COPILOT_HEADERS = {\n\t\"User-Agent\": \"GitHubCopilotChat/0.35.0\",\n\t\"Editor-Version\": \"vscode/1.107.0\",\n\t\"Editor-Plugin-Version\": \"copilot-chat/0.35.0\",\n\t\"Copilot-Integration-Id\": \"vscode-chat\",\n} as const;\nconst COPILOT_API_VERSION = \"2026-06-01\";\n\ntype DeviceCodeResponse = {\n\tdevice_code: string;\n\tuser_code: string;\n\tverification_uri: string;\n\tinterval?: number;\n\texpires_in: number;\n};\n\ntype DeviceTokenSuccessResponse = {\n\taccess_token: string;\n\ttoken_type?: string;\n\tscope?: string;\n};\n\ntype DeviceTokenErrorResponse = {\n\terror: string;\n\terror_description?: string;\n\tinterval?: number;\n};\n\nfunction normalizeDomain(input: string): string | null {\n\tconst trimmed = input.trim();\n\tif (!trimmed) return null;\n\ttry {\n\t\tconst url = trimmed.includes(\"://\") ? new URL(trimmed) : new URL(`https://${trimmed}`);\n\t\treturn url.hostname;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction getUrls(domain: string): {\n\tdeviceCodeUrl: string;\n\taccessTokenUrl: string;\n\tcopilotTokenUrl: string;\n} {\n\treturn {\n\t\tdeviceCodeUrl: `https://${domain}/login/device/code`,\n\t\taccessTokenUrl: `https://${domain}/login/oauth/access_token`,\n\t\tcopilotTokenUrl: `https://api.${domain}/copilot_internal/v2/token`,\n\t};\n}\n\n/**\n * Parse the proxy-ep from a Copilot token and convert to API base URL.\n * Token format: tid=...;exp=...;proxy-ep=proxy.individual.githubcopilot.com;...\n * Returns API URL like https://api.individual.githubcopilot.com\n */\nfunction getBaseUrlFromToken(token: string): string | null {\n\tconst match = token.match(/proxy-ep=([^;]+)/);\n\tif (!match) return null;\n\tconst proxyHost = match[1];\n\t// Convert proxy.xxx to api.xxx\n\tconst apiHost = proxyHost.replace(/^proxy\\./, \"api.\");\n\treturn `https://${apiHost}`;\n}\n\nfunction getGitHubCopilotBaseUrl(token?: string, enterpriseDomain?: string): string {\n\t// If we have a token, extract the base URL from proxy-ep\n\tif (token) {\n\t\tconst urlFromToken = getBaseUrlFromToken(token);\n\t\tif (urlFromToken) return urlFromToken;\n\t}\n\t// Fallback for enterprise or if token parsing fails\n\tif (enterpriseDomain) return `https://copilot-api.${enterpriseDomain}`;\n\treturn \"https://api.individual.githubcopilot.com\";\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> | undefined {\n\treturn value && typeof value === \"object\" ? (value as Record<string, unknown>) : undefined;\n}\n\nfunction parseGitHubCopilotModelCatalog(raw: unknown, allowPolicyFallback: boolean) {\n\tconst data = asRecord(raw)?.data;\n\tif (!Array.isArray(data)) {\n\t\tthrow new Error(\"Invalid Copilot models response\");\n\t}\n\n\tconst accountModels = data.flatMap((rawItem) => {\n\t\tconst item = asRecord(rawItem);\n\t\tconst id = item?.id;\n\t\tif (!item || typeof id !== \"string\") return [];\n\n\t\tconst capabilities = asRecord(item.capabilities);\n\t\tconst supports = asRecord(capabilities?.supports);\n\t\tif (supports?.tool_calls === false) return [];\n\n\t\treturn [\n\t\t\t{\n\t\t\t\tid,\n\t\t\t\tpickerEnabled: item.model_picker_enabled === true,\n\t\t\t\tpolicyState: asRecord(item.policy)?.state,\n\t\t\t},\n\t\t];\n\t});\n\tconst pickerModelIds = accountModels\n\t\t.filter((model) => model.pickerEnabled && model.policyState !== \"disabled\")\n\t\t.map((model) => model.id);\n\tconst usePolicyFallback = allowPolicyFallback && pickerModelIds.length === 0;\n\tconst availableModelIds =\n\t\tpickerModelIds.length > 0 || !allowPolicyFallback\n\t\t\t? pickerModelIds\n\t\t\t: accountModels.filter((model) => model.policyState === \"enabled\").map((model) => model.id);\n\tconst policyModelIds = accountModels\n\t\t.filter(\n\t\t\t(model) =>\n\t\t\t\tmodel.policyState === \"unconfigured\" &&\n\t\t\t\tObject.hasOwn(GITHUB_COPILOT_MODELS, model.id) &&\n\t\t\t\t(model.pickerEnabled || usePolicyFallback),\n\t\t)\n\t\t.map((model) => model.id);\n\treturn { availableModelIds, policyModelIds };\n}\n\nasync function fetchWithRateLimitRetry(\n\turl: string,\n\tinit: RequestInit,\n\tsignal: AbortSignal,\n\tretryPolicy: { maxRetries: number; maxElapsedMs: number },\n): Promise<Response> {\n\tconst retryBudgetSignal =\n\t\tretryPolicy.maxRetries > 0 && retryPolicy.maxElapsedMs > 0\n\t\t\t? AbortSignal.timeout(retryPolicy.maxElapsedMs)\n\t\t\t: undefined;\n\tconst requestSignal = retryBudgetSignal ? AbortSignal.any([signal, retryBudgetSignal]) : signal;\n\tconst retryDeadline = retryBudgetSignal ? Date.now() + retryPolicy.maxElapsedMs : undefined;\n\tfor (let retry = 0; ; retry++) {\n\t\tconst response = await fetch(url, {\n\t\t\t...init,\n\t\t\tsignal: AbortSignal.any([requestSignal, AbortSignal.timeout(5000)]),\n\t\t});\n\t\tif (response.status !== 429 || retry === retryPolicy.maxRetries) return response;\n\n\t\tconst retryAfter = response.headers.get(\"retry-after\");\n\t\tlet delayMs = 500 * 2 ** retry;\n\t\tif (retryAfter) {\n\t\t\tconst seconds = Number.parseFloat(retryAfter);\n\t\t\tdelayMs = Number.isNaN(seconds) ? Date.parse(retryAfter) - Date.now() : seconds * 1000;\n\t\t\tif (!Number.isFinite(delayMs)) return response;\n\t\t}\n\t\tdelayMs = Math.max(0, delayMs);\n\t\tif (retryDeadline !== undefined && delayMs >= retryDeadline - Date.now()) return response;\n\t\tawait response.body?.cancel();\n\t\tawait sleep(delayMs, requestSignal);\n\t}\n}\n\nasync function fetchGitHubCopilotModels(\n\tcopilotToken: string,\n\tenterpriseDomain: string | undefined,\n\tsignal: AbortSignal,\n\tretryPolicy: { maxRetries: number; maxElapsedMs: number },\n) {\n\tconst baseUrl = getGitHubCopilotBaseUrl(copilotToken, enterpriseDomain);\n\t// Some Individual accounts return false for every picker flag despite explicit enabled policies.\n\t// Limit the fallback to that endpoint so other account types keep strict picker semantics.\n\tconst allowPolicyFallback = baseUrl === \"https://api.individual.githubcopilot.com\";\n\tconst response = await fetchWithRateLimitRetry(\n\t\t`${baseUrl}/models`,\n\t\t{\n\t\t\theaders: {\n\t\t\t\tAccept: \"application/json\",\n\t\t\t\tAuthorization: `Bearer ${copilotToken}`,\n\t\t\t\t...COPILOT_HEADERS,\n\t\t\t\t\"X-GitHub-Api-Version\": COPILOT_API_VERSION,\n\t\t\t},\n\t\t},\n\t\tsignal,\n\t\tretryPolicy,\n\t);\n\tif (!response.ok) {\n\t\tthrow new Error(`${response.status} ${response.statusText}: ${await response.text()}`);\n\t}\n\treturn parseGitHubCopilotModelCatalog(await response.json(), allowPolicyFallback);\n}\n\nasync function fetchJson(url: string, init: RequestInit): Promise<unknown> {\n\tconst response = await fetch(url, init);\n\tif (!response.ok) {\n\t\tconst text = await response.text();\n\t\tthrow new Error(`${response.status} ${response.statusText}: ${text}`);\n\t}\n\treturn response.json();\n}\n\nasync function startDeviceFlow(domain: string, signal: AbortSignal): Promise<DeviceCodeResponse> {\n\tconst urls = getUrls(domain);\n\tconst data = await fetchJson(urls.deviceCodeUrl, {\n\t\tmethod: \"POST\",\n\t\theaders: {\n\t\t\tAccept: \"application/json\",\n\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\t\"User-Agent\": \"GitHubCopilotChat/0.35.0\",\n\t\t},\n\t\tbody: new URLSearchParams({\n\t\t\tclient_id: CLIENT_ID,\n\t\t\tscope: \"read:user\",\n\t\t}),\n\t\tsignal,\n\t});\n\n\tif (!data || typeof data !== \"object\") {\n\t\tthrow new Error(\"Invalid device code response\");\n\t}\n\n\tconst deviceCode = (data as Record<string, unknown>).device_code;\n\tconst userCode = (data as Record<string, unknown>).user_code;\n\tconst verificationUri = (data as Record<string, unknown>).verification_uri;\n\tconst interval = (data as Record<string, unknown>).interval;\n\tconst expiresIn = (data as Record<string, unknown>).expires_in;\n\n\tif (\n\t\ttypeof deviceCode !== \"string\" ||\n\t\ttypeof userCode !== \"string\" ||\n\t\ttypeof verificationUri !== \"string\" ||\n\t\t(interval !== undefined && typeof interval !== \"number\") ||\n\t\ttypeof expiresIn !== \"number\"\n\t) {\n\t\tthrow new Error(\"Invalid device code response fields\");\n\t}\n\n\t// The verification URI is opened in the user's browser and to prevent `open` from\n\t// opening an executable or similar, we force it to be a URL.\n\tlet parsedUri: URL;\n\ttry {\n\t\tparsedUri = new URL(verificationUri);\n\t} catch {\n\t\tthrow new Error(\"Untrusted verification_uri in device code response\");\n\t}\n\tif (parsedUri.protocol !== \"https:\" && parsedUri.protocol !== \"http:\") {\n\t\tthrow new Error(\"Untrusted verification_uri in device code response\");\n\t}\n\n\treturn {\n\t\tdevice_code: deviceCode,\n\t\tuser_code: userCode,\n\t\tverification_uri: parsedUri.href,\n\t\tinterval,\n\t\texpires_in: expiresIn,\n\t};\n}\n\nasync function pollForGitHubAccessToken(\n\tdomain: string,\n\tdevice: DeviceCodeResponse,\n\tsignal: AbortSignal,\n): Promise<string> {\n\tconst urls = getUrls(domain);\n\treturn pollOAuthDeviceCodeFlow<string>({\n\t\tintervalSeconds: device.interval,\n\t\texpiresInSeconds: device.expires_in,\n\t\twaitBeforeFirstPoll: true,\n\t\tsignal,\n\t\tpoll: async () => {\n\t\t\tconst raw = await fetchJson(urls.accessTokenUrl, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: {\n\t\t\t\t\tAccept: \"application/json\",\n\t\t\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\t\t\t\"User-Agent\": \"GitHubCopilotChat/0.35.0\",\n\t\t\t\t},\n\t\t\t\tbody: new URLSearchParams({\n\t\t\t\t\tclient_id: CLIENT_ID,\n\t\t\t\t\tdevice_code: device.device_code,\n\t\t\t\t\tgrant_type: \"urn:ietf:params:oauth:grant-type:device_code\",\n\t\t\t\t}),\n\t\t\t\tsignal,\n\t\t\t});\n\n\t\t\tif (raw && typeof raw === \"object\" && typeof (raw as DeviceTokenSuccessResponse).access_token === \"string\") {\n\t\t\t\treturn { status: \"complete\", value: (raw as DeviceTokenSuccessResponse).access_token };\n\t\t\t}\n\n\t\t\tif (raw && typeof raw === \"object\" && typeof (raw as DeviceTokenErrorResponse).error === \"string\") {\n\t\t\t\tconst { error, error_description: description, interval } = raw as DeviceTokenErrorResponse;\n\t\t\t\tif (error === \"authorization_pending\") {\n\t\t\t\t\treturn { status: \"pending\" };\n\t\t\t\t}\n\n\t\t\t\tif (error === \"slow_down\") {\n\t\t\t\t\treturn { status: \"slow_down\", intervalSeconds: typeof interval === \"number\" ? interval : undefined };\n\t\t\t\t}\n\n\t\t\t\tconst descriptionSuffix = description ? `: ${description}` : \"\";\n\t\t\t\treturn { status: \"failed\", message: `Device flow failed: ${error}${descriptionSuffix}` };\n\t\t\t}\n\n\t\t\treturn { status: \"failed\", message: \"Invalid device token response\" };\n\t\t},\n\t});\n}\n\nasync function refreshGitHubCopilotAccessToken(\n\trefreshToken: string,\n\tenterpriseDomain: string | undefined,\n\tsignal: AbortSignal,\n): Promise<OAuthCredential> {\n\tconst domain = enterpriseDomain || \"github.com\";\n\tconst urls = getUrls(domain);\n\n\tconst raw = await fetchJson(urls.copilotTokenUrl, {\n\t\theaders: {\n\t\t\tAccept: \"application/json\",\n\t\t\tAuthorization: `Bearer ${refreshToken}`,\n\t\t\t...COPILOT_HEADERS,\n\t\t},\n\t\tsignal,\n\t});\n\n\tif (!raw || typeof raw !== \"object\") {\n\t\tthrow new Error(\"Invalid Copilot token response\");\n\t}\n\n\tconst token = (raw as Record<string, unknown>).token;\n\tconst expiresAt = (raw as Record<string, unknown>).expires_at;\n\n\tif (typeof token !== \"string\" || typeof expiresAt !== \"number\") {\n\t\tthrow new Error(\"Invalid Copilot token response fields\");\n\t}\n\n\treturn {\n\t\ttype: \"oauth\",\n\t\trefresh: refreshToken,\n\t\taccess: token,\n\t\texpires: expiresAt * 1000 - 5 * 60 * 1000,\n\t\tenterpriseUrl: enterpriseDomain,\n\t};\n}\n\n/**\n * Refresh GitHub Copilot token\n */\nasync function refreshGitHubCopilotToken(\n\trefreshToken: string,\n\tenterpriseDomain: string | undefined,\n\tsignal: AbortSignal,\n): Promise<OAuthCredential> {\n\tconst credentials = await refreshGitHubCopilotAccessToken(refreshToken, enterpriseDomain, signal);\n\tconst { availableModelIds } = await fetchGitHubCopilotModels(credentials.access, enterpriseDomain, signal, {\n\t\tmaxRetries: 0,\n\t\tmaxElapsedMs: 0,\n\t});\n\treturn {\n\t\t...credentials,\n\t\tavailableModelIds,\n\t};\n}\n\n/**\n * Enable a model for the user's GitHub Copilot account.\n * This is required for some models (like Claude, Grok) before they can be used.\n */\nasync function enableGitHubCopilotModel(\n\ttoken: string,\n\tmodelId: string,\n\tenterpriseDomain: string | undefined,\n\tsignal: AbortSignal,\n): Promise<boolean> {\n\tconst baseUrl = getGitHubCopilotBaseUrl(token, enterpriseDomain);\n\tconst url = `${baseUrl}/models/${modelId}/policy`;\n\n\tlet response: Response;\n\ttry {\n\t\tresponse = await fetchWithRateLimitRetry(\n\t\t\turl,\n\t\t\t{\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: {\n\t\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t\tAuthorization: `Bearer ${token}`,\n\t\t\t\t\t...COPILOT_HEADERS,\n\t\t\t\t\t\"openai-intent\": \"chat-policy\",\n\t\t\t\t\t\"x-interaction-type\": \"chat-policy\",\n\t\t\t\t},\n\t\t\t\tbody: JSON.stringify({ state: \"enabled\" }),\n\t\t\t},\n\t\t\tsignal,\n\t\t\t{ maxRetries: 2, maxElapsedMs: 5000 },\n\t\t);\n\t} catch (error) {\n\t\tif (signal.aborted) throw error;\n\t\treturn false;\n\t}\n\tif (response.status === 429) {\n\t\tthrow new Error(`${response.status} ${response.statusText}: ${await response.text()}`);\n\t}\n\treturn response.ok;\n}\n\n/**\n * Enable the requested GitHub Copilot models and return the successful IDs.\n * Policy updates are best effort; exhausted rate limiting stops the batch.\n */\nasync function enableGitHubCopilotModels(\n\ttoken: string,\n\tmodelIds: readonly string[],\n\tenterpriseDomain: string | undefined,\n\tsignal: AbortSignal,\n): Promise<string[]> {\n\tconst enabledModelIds: string[] = [];\n\tfor (const modelId of modelIds) {\n\t\ttry {\n\t\t\tif (await enableGitHubCopilotModel(token, modelId, enterpriseDomain, signal)) {\n\t\t\t\tenabledModelIds.push(modelId);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tif (signal.aborted) throw error;\n\t\t\tbreak;\n\t\t}\n\t}\n\treturn enabledModelIds;\n}\n\nasync function loginGitHubCopilot(interaction: ProviderAuthInteraction): Promise<OAuthCredential> {\n\tconst input = await interaction.prompt({\n\t\ttype: \"text\",\n\t\tmessage: \"GitHub Enterprise URL/domain (blank for github.com)\",\n\t\tplaceholder: \"company.ghe.com\",\n\t});\n\tif (interaction.signal.aborted) throw new Error(\"Login cancelled\");\n\n\tconst trimmed = input.trim();\n\tconst enterpriseDomain = normalizeDomain(input);\n\tif (trimmed && !enterpriseDomain) throw new Error(\"Invalid GitHub Enterprise URL/domain\");\n\tconst domain = enterpriseDomain || \"github.com\";\n\n\tconst device = await startDeviceFlow(domain, interaction.signal);\n\tinteraction.notify({\n\t\ttype: \"device_code\",\n\t\tuserCode: device.user_code,\n\t\tverificationUri: device.verification_uri,\n\t\tintervalSeconds: device.interval,\n\t\texpiresInSeconds: device.expires_in,\n\t});\n\n\tconst githubAccessToken = await pollForGitHubAccessToken(domain, device, interaction.signal);\n\tconst credentials = await refreshGitHubCopilotAccessToken(\n\t\tgithubAccessToken,\n\t\tenterpriseDomain ?? undefined,\n\t\tinteraction.signal,\n\t);\n\tconst models = await fetchGitHubCopilotModels(\n\t\tcredentials.access,\n\t\tenterpriseDomain ?? undefined,\n\t\tinteraction.signal,\n\t\t{\n\t\t\tmaxRetries: 2,\n\t\t\tmaxElapsedMs: 5000,\n\t\t},\n\t);\n\tlet enabledModelIds: string[] = [];\n\tif (models.policyModelIds.length > 0) {\n\t\tinteraction.notify({ type: \"progress\", message: \"Enabling models...\" });\n\t\tenabledModelIds = await enableGitHubCopilotModels(\n\t\t\tcredentials.access,\n\t\t\tmodels.policyModelIds,\n\t\t\tenterpriseDomain ?? undefined,\n\t\t\tinteraction.signal,\n\t\t);\n\t}\n\treturn {\n\t\t...credentials,\n\t\tavailableModelIds: [...new Set([...models.availableModelIds, ...enabledModelIds])],\n\t};\n}\n\nfunction copilotEnterpriseDomain(credential: OAuthCredential): string | undefined {\n\tconst enterpriseUrl = credential.enterpriseUrl;\n\tif (typeof enterpriseUrl !== \"string\" || !enterpriseUrl) return undefined;\n\treturn normalizeDomain(enterpriseUrl) ?? undefined;\n}\n\nexport const githubCopilotOAuth: OAuthAuth = {\n\tname: \"GitHub Copilot\",\n\tisSubscription: true,\n\tlogin: loginGitHubCopilot,\n\trefresh: (credential, signal) =>\n\t\trefreshGitHubCopilotToken(credential.refresh, copilotEnterpriseDomain(credential), signal),\n\n\t/** Derive the credential-specific proxy endpoint for each request. */\n\tasync toAuth(credential) {\n\t\treturn {\n\t\t\tapiKey: credential.access,\n\t\t\tbaseUrl: getGitHubCopilotBaseUrl(credential.access, copilotEnterpriseDomain(credential)),\n\t\t};\n\t},\n};\n"]}
1
+ {"version":3,"file":"github-copilot.js","sourceRoot":"","sources":["../../../src/auth/oauth/github-copilot.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * GitHub Copilot OAuth flow\n */\n\nimport { GITHUB_COPILOT_MODELS } from \"../../providers/github-copilot.models.ts\";\nimport { sleep } from \"../../utils/sleep.ts\";\nimport type { OAuthAuth, OAuthCredential, ProviderAuthInteraction } from \"../types.ts\";\nimport { pollOAuthDeviceCodeFlow } from \"./device-code.ts\";\nimport { trustedHttpUrl } from \"./trusted-url.ts\";\n\nconst decode = (s: string) => atob(s);\nconst CLIENT_ID = decode(\"SXYxLmI1MDdhMDhjODdlY2ZlOTg=\");\n\nconst COPILOT_HEADERS = {\n\t\"User-Agent\": \"GitHubCopilotChat/0.35.0\",\n\t\"Editor-Version\": \"vscode/1.107.0\",\n\t\"Editor-Plugin-Version\": \"copilot-chat/0.35.0\",\n\t\"Copilot-Integration-Id\": \"vscode-chat\",\n} as const;\nconst COPILOT_API_VERSION = \"2026-06-01\";\n\ntype DeviceCodeResponse = {\n\tdevice_code: string;\n\tuser_code: string;\n\tverification_uri: string;\n\tinterval?: number;\n\texpires_in: number;\n};\n\ntype DeviceTokenSuccessResponse = {\n\taccess_token: string;\n\ttoken_type?: string;\n\tscope?: string;\n};\n\ntype DeviceTokenErrorResponse = {\n\terror: string;\n\terror_description?: string;\n\tinterval?: number;\n};\n\nfunction normalizeDomain(input: string): string | null {\n\tconst trimmed = input.trim();\n\tif (!trimmed) return null;\n\ttry {\n\t\tconst url = trimmed.includes(\"://\") ? new URL(trimmed) : new URL(`https://${trimmed}`);\n\t\treturn url.hostname;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction getUrls(domain: string): {\n\tdeviceCodeUrl: string;\n\taccessTokenUrl: string;\n\tcopilotTokenUrl: string;\n} {\n\treturn {\n\t\tdeviceCodeUrl: `https://${domain}/login/device/code`,\n\t\taccessTokenUrl: `https://${domain}/login/oauth/access_token`,\n\t\tcopilotTokenUrl: `https://api.${domain}/copilot_internal/v2/token`,\n\t};\n}\n\n/**\n * Parse the proxy-ep from a Copilot token and convert to API base URL.\n * Token format: tid=...;exp=...;proxy-ep=proxy.individual.githubcopilot.com;...\n * Returns API URL like https://api.individual.githubcopilot.com\n */\nfunction getBaseUrlFromToken(token: string): string | null {\n\tconst match = token.match(/proxy-ep=([^;]+)/);\n\tif (!match) return null;\n\tconst proxyHost = match[1];\n\t// Convert proxy.xxx to api.xxx\n\tconst apiHost = proxyHost.replace(/^proxy\\./, \"api.\");\n\treturn `https://${apiHost}`;\n}\n\nfunction getGitHubCopilotBaseUrl(token?: string, enterpriseDomain?: string): string {\n\t// If we have a token, extract the base URL from proxy-ep\n\tif (token) {\n\t\tconst urlFromToken = getBaseUrlFromToken(token);\n\t\tif (urlFromToken) return urlFromToken;\n\t}\n\t// Fallback for enterprise or if token parsing fails\n\tif (enterpriseDomain) return `https://copilot-api.${enterpriseDomain}`;\n\treturn \"https://api.individual.githubcopilot.com\";\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> | undefined {\n\treturn value && typeof value === \"object\" ? (value as Record<string, unknown>) : undefined;\n}\n\nfunction parseGitHubCopilotModelCatalog(raw: unknown, allowPolicyFallback: boolean) {\n\tconst data = asRecord(raw)?.data;\n\tif (!Array.isArray(data)) {\n\t\tthrow new Error(\"Invalid Copilot models response\");\n\t}\n\n\tconst accountModels = data.flatMap((rawItem) => {\n\t\tconst item = asRecord(rawItem);\n\t\tconst id = item?.id;\n\t\tif (!item || typeof id !== \"string\") return [];\n\n\t\tconst capabilities = asRecord(item.capabilities);\n\t\tconst supports = asRecord(capabilities?.supports);\n\t\tif (supports?.tool_calls === false) return [];\n\n\t\treturn [\n\t\t\t{\n\t\t\t\tid,\n\t\t\t\tpickerEnabled: item.model_picker_enabled === true,\n\t\t\t\tpolicyState: asRecord(item.policy)?.state,\n\t\t\t},\n\t\t];\n\t});\n\tconst pickerModelIds = accountModels\n\t\t.filter((model) => model.pickerEnabled && model.policyState !== \"disabled\")\n\t\t.map((model) => model.id);\n\tconst usePolicyFallback = allowPolicyFallback && pickerModelIds.length === 0;\n\tconst availableModelIds =\n\t\tpickerModelIds.length > 0 || !allowPolicyFallback\n\t\t\t? pickerModelIds\n\t\t\t: accountModels.filter((model) => model.policyState === \"enabled\").map((model) => model.id);\n\tconst policyModelIds = accountModels\n\t\t.filter(\n\t\t\t(model) =>\n\t\t\t\tmodel.policyState === \"unconfigured\" &&\n\t\t\t\tObject.hasOwn(GITHUB_COPILOT_MODELS, model.id) &&\n\t\t\t\t(model.pickerEnabled || usePolicyFallback),\n\t\t)\n\t\t.map((model) => model.id);\n\treturn { availableModelIds, policyModelIds };\n}\n\nasync function fetchWithRateLimitRetry(\n\turl: string,\n\tinit: RequestInit,\n\tsignal: AbortSignal,\n\tretryPolicy: { maxRetries: number; maxElapsedMs: number },\n): Promise<Response> {\n\tconst retryBudgetSignal =\n\t\tretryPolicy.maxRetries > 0 && retryPolicy.maxElapsedMs > 0\n\t\t\t? AbortSignal.timeout(retryPolicy.maxElapsedMs)\n\t\t\t: undefined;\n\tconst requestSignal = retryBudgetSignal ? AbortSignal.any([signal, retryBudgetSignal]) : signal;\n\tconst retryDeadline = retryBudgetSignal ? Date.now() + retryPolicy.maxElapsedMs : undefined;\n\tfor (let retry = 0; ; retry++) {\n\t\tconst response = await fetch(url, {\n\t\t\t...init,\n\t\t\tsignal: AbortSignal.any([requestSignal, AbortSignal.timeout(5000)]),\n\t\t});\n\t\tif (response.status !== 429 || retry === retryPolicy.maxRetries) return response;\n\n\t\tconst retryAfter = response.headers.get(\"retry-after\");\n\t\tlet delayMs = 500 * 2 ** retry;\n\t\tif (retryAfter) {\n\t\t\tconst seconds = Number.parseFloat(retryAfter);\n\t\t\tdelayMs = Number.isNaN(seconds) ? Date.parse(retryAfter) - Date.now() : seconds * 1000;\n\t\t\tif (!Number.isFinite(delayMs)) return response;\n\t\t}\n\t\tdelayMs = Math.max(0, delayMs);\n\t\tif (retryDeadline !== undefined && delayMs >= retryDeadline - Date.now()) return response;\n\t\tawait response.body?.cancel();\n\t\tawait sleep(delayMs, requestSignal);\n\t}\n}\n\nasync function fetchGitHubCopilotModels(\n\tcopilotToken: string,\n\tenterpriseDomain: string | undefined,\n\tsignal: AbortSignal,\n\tretryPolicy: { maxRetries: number; maxElapsedMs: number },\n) {\n\tconst baseUrl = getGitHubCopilotBaseUrl(copilotToken, enterpriseDomain);\n\t// Some Individual accounts return false for every picker flag despite explicit enabled policies.\n\t// Limit the fallback to that endpoint so other account types keep strict picker semantics.\n\tconst allowPolicyFallback = baseUrl === \"https://api.individual.githubcopilot.com\";\n\tconst response = await fetchWithRateLimitRetry(\n\t\t`${baseUrl}/models`,\n\t\t{\n\t\t\theaders: {\n\t\t\t\tAccept: \"application/json\",\n\t\t\t\tAuthorization: `Bearer ${copilotToken}`,\n\t\t\t\t...COPILOT_HEADERS,\n\t\t\t\t\"X-GitHub-Api-Version\": COPILOT_API_VERSION,\n\t\t\t},\n\t\t},\n\t\tsignal,\n\t\tretryPolicy,\n\t);\n\tif (!response.ok) {\n\t\tthrow new Error(`${response.status} ${response.statusText}: ${await response.text()}`);\n\t}\n\treturn parseGitHubCopilotModelCatalog(await response.json(), allowPolicyFallback);\n}\n\nasync function fetchJson(url: string, init: RequestInit): Promise<unknown> {\n\tconst response = await fetch(url, init);\n\tif (!response.ok) {\n\t\tconst text = await response.text();\n\t\tthrow new Error(`${response.status} ${response.statusText}: ${text}`);\n\t}\n\treturn response.json();\n}\n\nasync function startDeviceFlow(domain: string, signal: AbortSignal): Promise<DeviceCodeResponse> {\n\tconst urls = getUrls(domain);\n\tconst data = await fetchJson(urls.deviceCodeUrl, {\n\t\tmethod: \"POST\",\n\t\theaders: {\n\t\t\tAccept: \"application/json\",\n\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\t\"User-Agent\": \"GitHubCopilotChat/0.35.0\",\n\t\t},\n\t\tbody: new URLSearchParams({\n\t\t\tclient_id: CLIENT_ID,\n\t\t\tscope: \"read:user\",\n\t\t}),\n\t\tsignal,\n\t});\n\n\tif (!data || typeof data !== \"object\") {\n\t\tthrow new Error(\"Invalid device code response\");\n\t}\n\n\tconst deviceCode = (data as Record<string, unknown>).device_code;\n\tconst userCode = (data as Record<string, unknown>).user_code;\n\tconst verificationUri = (data as Record<string, unknown>).verification_uri;\n\tconst interval = (data as Record<string, unknown>).interval;\n\tconst expiresIn = (data as Record<string, unknown>).expires_in;\n\n\tif (\n\t\ttypeof deviceCode !== \"string\" ||\n\t\ttypeof userCode !== \"string\" ||\n\t\ttypeof verificationUri !== \"string\" ||\n\t\t(interval !== undefined && typeof interval !== \"number\") ||\n\t\ttypeof expiresIn !== \"number\"\n\t) {\n\t\tthrow new Error(\"Invalid device code response fields\");\n\t}\n\n\tconst trustedVerificationUri = trustedHttpUrl(verificationUri);\n\tif (!trustedVerificationUri) {\n\t\tthrow new Error(\"Untrusted verification_uri in device code response\");\n\t}\n\n\treturn {\n\t\tdevice_code: deviceCode,\n\t\tuser_code: userCode,\n\t\tverification_uri: trustedVerificationUri,\n\t\tinterval,\n\t\texpires_in: expiresIn,\n\t};\n}\n\nasync function pollForGitHubAccessToken(\n\tdomain: string,\n\tdevice: DeviceCodeResponse,\n\tsignal: AbortSignal,\n): Promise<string> {\n\tconst urls = getUrls(domain);\n\treturn pollOAuthDeviceCodeFlow<string>({\n\t\tintervalSeconds: device.interval,\n\t\texpiresInSeconds: device.expires_in,\n\t\twaitBeforeFirstPoll: true,\n\t\tsignal,\n\t\tpoll: async () => {\n\t\t\tconst raw = await fetchJson(urls.accessTokenUrl, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: {\n\t\t\t\t\tAccept: \"application/json\",\n\t\t\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\t\t\t\"User-Agent\": \"GitHubCopilotChat/0.35.0\",\n\t\t\t\t},\n\t\t\t\tbody: new URLSearchParams({\n\t\t\t\t\tclient_id: CLIENT_ID,\n\t\t\t\t\tdevice_code: device.device_code,\n\t\t\t\t\tgrant_type: \"urn:ietf:params:oauth:grant-type:device_code\",\n\t\t\t\t}),\n\t\t\t\tsignal,\n\t\t\t});\n\n\t\t\tif (raw && typeof raw === \"object\" && typeof (raw as DeviceTokenSuccessResponse).access_token === \"string\") {\n\t\t\t\treturn { status: \"complete\", value: (raw as DeviceTokenSuccessResponse).access_token };\n\t\t\t}\n\n\t\t\tif (raw && typeof raw === \"object\" && typeof (raw as DeviceTokenErrorResponse).error === \"string\") {\n\t\t\t\tconst { error, error_description: description, interval } = raw as DeviceTokenErrorResponse;\n\t\t\t\tif (error === \"authorization_pending\") {\n\t\t\t\t\treturn { status: \"pending\" };\n\t\t\t\t}\n\n\t\t\t\tif (error === \"slow_down\") {\n\t\t\t\t\treturn { status: \"slow_down\", intervalSeconds: typeof interval === \"number\" ? interval : undefined };\n\t\t\t\t}\n\n\t\t\t\tconst descriptionSuffix = description ? `: ${description}` : \"\";\n\t\t\t\treturn { status: \"failed\", message: `Device flow failed: ${error}${descriptionSuffix}` };\n\t\t\t}\n\n\t\t\treturn { status: \"failed\", message: \"Invalid device token response\" };\n\t\t},\n\t});\n}\n\nasync function refreshGitHubCopilotAccessToken(\n\trefreshToken: string,\n\tenterpriseDomain: string | undefined,\n\tsignal: AbortSignal,\n): Promise<OAuthCredential> {\n\tconst domain = enterpriseDomain || \"github.com\";\n\tconst urls = getUrls(domain);\n\n\tconst raw = await fetchJson(urls.copilotTokenUrl, {\n\t\theaders: {\n\t\t\tAccept: \"application/json\",\n\t\t\tAuthorization: `Bearer ${refreshToken}`,\n\t\t\t...COPILOT_HEADERS,\n\t\t},\n\t\tsignal,\n\t});\n\n\tif (!raw || typeof raw !== \"object\") {\n\t\tthrow new Error(\"Invalid Copilot token response\");\n\t}\n\n\tconst token = (raw as Record<string, unknown>).token;\n\tconst expiresAt = (raw as Record<string, unknown>).expires_at;\n\n\tif (typeof token !== \"string\" || typeof expiresAt !== \"number\") {\n\t\tthrow new Error(\"Invalid Copilot token response fields\");\n\t}\n\n\treturn {\n\t\ttype: \"oauth\",\n\t\trefresh: refreshToken,\n\t\taccess: token,\n\t\texpires: expiresAt * 1000 - 5 * 60 * 1000,\n\t\tenterpriseUrl: enterpriseDomain,\n\t};\n}\n\n/**\n * Refresh GitHub Copilot token\n */\nasync function refreshGitHubCopilotToken(\n\trefreshToken: string,\n\tenterpriseDomain: string | undefined,\n\tsignal: AbortSignal,\n): Promise<OAuthCredential> {\n\tconst credentials = await refreshGitHubCopilotAccessToken(refreshToken, enterpriseDomain, signal);\n\tconst { availableModelIds } = await fetchGitHubCopilotModels(credentials.access, enterpriseDomain, signal, {\n\t\tmaxRetries: 0,\n\t\tmaxElapsedMs: 0,\n\t});\n\treturn {\n\t\t...credentials,\n\t\tavailableModelIds,\n\t};\n}\n\n/**\n * Enable a model for the user's GitHub Copilot account.\n * This is required for some models (like Claude, Grok) before they can be used.\n */\nasync function enableGitHubCopilotModel(\n\ttoken: string,\n\tmodelId: string,\n\tenterpriseDomain: string | undefined,\n\tsignal: AbortSignal,\n): Promise<boolean> {\n\tconst baseUrl = getGitHubCopilotBaseUrl(token, enterpriseDomain);\n\tconst url = `${baseUrl}/models/${modelId}/policy`;\n\n\tlet response: Response;\n\ttry {\n\t\tresponse = await fetchWithRateLimitRetry(\n\t\t\turl,\n\t\t\t{\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: {\n\t\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t\tAuthorization: `Bearer ${token}`,\n\t\t\t\t\t...COPILOT_HEADERS,\n\t\t\t\t\t\"openai-intent\": \"chat-policy\",\n\t\t\t\t\t\"x-interaction-type\": \"chat-policy\",\n\t\t\t\t},\n\t\t\t\tbody: JSON.stringify({ state: \"enabled\" }),\n\t\t\t},\n\t\t\tsignal,\n\t\t\t{ maxRetries: 2, maxElapsedMs: 5000 },\n\t\t);\n\t} catch (error) {\n\t\tif (signal.aborted) throw error;\n\t\treturn false;\n\t}\n\tif (response.status === 429) {\n\t\tthrow new Error(`${response.status} ${response.statusText}: ${await response.text()}`);\n\t}\n\treturn response.ok;\n}\n\n/**\n * Enable the requested GitHub Copilot models and return the successful IDs.\n * Policy updates are best effort; exhausted rate limiting stops the batch.\n */\nasync function enableGitHubCopilotModels(\n\ttoken: string,\n\tmodelIds: readonly string[],\n\tenterpriseDomain: string | undefined,\n\tsignal: AbortSignal,\n): Promise<string[]> {\n\tconst enabledModelIds: string[] = [];\n\tfor (const modelId of modelIds) {\n\t\ttry {\n\t\t\tif (await enableGitHubCopilotModel(token, modelId, enterpriseDomain, signal)) {\n\t\t\t\tenabledModelIds.push(modelId);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tif (signal.aborted) throw error;\n\t\t\tbreak;\n\t\t}\n\t}\n\treturn enabledModelIds;\n}\n\nasync function loginGitHubCopilot(interaction: ProviderAuthInteraction): Promise<OAuthCredential> {\n\tconst input = await interaction.prompt({\n\t\ttype: \"text\",\n\t\tmessage: \"GitHub Enterprise URL/domain (blank for github.com)\",\n\t\tplaceholder: \"company.ghe.com\",\n\t});\n\tif (interaction.signal.aborted) throw new Error(\"Login cancelled\");\n\n\tconst trimmed = input.trim();\n\tconst enterpriseDomain = normalizeDomain(input);\n\tif (trimmed && !enterpriseDomain) throw new Error(\"Invalid GitHub Enterprise URL/domain\");\n\tconst domain = enterpriseDomain || \"github.com\";\n\n\tconst device = await startDeviceFlow(domain, interaction.signal);\n\tinteraction.notify({\n\t\ttype: \"device_code\",\n\t\tuserCode: device.user_code,\n\t\tverificationUri: device.verification_uri,\n\t\tintervalSeconds: device.interval,\n\t\texpiresInSeconds: device.expires_in,\n\t});\n\n\tconst githubAccessToken = await pollForGitHubAccessToken(domain, device, interaction.signal);\n\tconst credentials = await refreshGitHubCopilotAccessToken(\n\t\tgithubAccessToken,\n\t\tenterpriseDomain ?? undefined,\n\t\tinteraction.signal,\n\t);\n\tconst models = await fetchGitHubCopilotModels(\n\t\tcredentials.access,\n\t\tenterpriseDomain ?? undefined,\n\t\tinteraction.signal,\n\t\t{\n\t\t\tmaxRetries: 2,\n\t\t\tmaxElapsedMs: 5000,\n\t\t},\n\t);\n\tlet enabledModelIds: string[] = [];\n\tif (models.policyModelIds.length > 0) {\n\t\tinteraction.notify({ type: \"progress\", message: \"Enabling models...\" });\n\t\tenabledModelIds = await enableGitHubCopilotModels(\n\t\t\tcredentials.access,\n\t\t\tmodels.policyModelIds,\n\t\t\tenterpriseDomain ?? undefined,\n\t\t\tinteraction.signal,\n\t\t);\n\t}\n\treturn {\n\t\t...credentials,\n\t\tavailableModelIds: [...new Set([...models.availableModelIds, ...enabledModelIds])],\n\t};\n}\n\nfunction copilotEnterpriseDomain(credential: OAuthCredential): string | undefined {\n\tconst enterpriseUrl = credential.enterpriseUrl;\n\tif (typeof enterpriseUrl !== \"string\" || !enterpriseUrl) return undefined;\n\treturn normalizeDomain(enterpriseUrl) ?? undefined;\n}\n\nexport const githubCopilotOAuth: OAuthAuth = {\n\tname: \"GitHub Copilot\",\n\tisSubscription: true,\n\tlogin: loginGitHubCopilot,\n\trefresh: (credential, signal) =>\n\t\trefreshGitHubCopilotToken(credential.refresh, copilotEnterpriseDomain(credential), signal),\n\n\t/** Derive the credential-specific proxy endpoint for each request. */\n\tasync toAuth(credential) {\n\t\treturn {\n\t\t\tapiKey: credential.access,\n\t\t\tbaseUrl: getGitHubCopilotBaseUrl(credential.access, copilotEnterpriseDomain(credential)),\n\t\t};\n\t},\n};\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"kimi-coding.d.ts","sourceRoot":"","sources":["../../../src/auth/oauth/kimi-coding.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,KAAK,EAAE,SAAS,EAA4C,MAAM,aAAa,CAAC;AA8QvF,eAAO,MAAM,eAAe,EAAE,SAe7B,CAAC"}
1
+ {"version":3,"file":"kimi-coding.d.ts","sourceRoot":"","sources":["../../../src/auth/oauth/kimi-coding.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,KAAK,EAAE,SAAS,EAA4C,MAAM,aAAa,CAAC;AA4PvF,eAAO,MAAM,eAAe,EAAE,SAe7B,CAAC"}
@@ -8,6 +8,7 @@
8
8
  import { getProviderEnvValue } from "../../utils/provider-env.js";
9
9
  import { sleep } from "../../utils/sleep.js";
10
10
  import { pollOAuthDeviceCodeFlow } from "./device-code.js";
11
+ import { trustedHttpUrl } from "./trusted-url.js";
11
12
  const CLIENT_ID = "17e5f671-d194-4dfb-9706-5516cb48c098";
12
13
  const DEFAULT_OAUTH_HOST = "https://auth.kimi.com";
13
14
  const DEVICE_CODE_TIMEOUT_SECONDS = 15 * 60;
@@ -33,20 +34,6 @@ async function readJson(response) {
33
34
  return null;
34
35
  }
35
36
  }
36
- /** The verification URI is opened in the user's browser; only http(s) URLs are trusted. */
37
- function trustedHttpUrl(value) {
38
- if (typeof value !== "string" || !value)
39
- return null;
40
- try {
41
- const url = new URL(value);
42
- if (url.protocol !== "https:" && url.protocol !== "http:")
43
- return null;
44
- return url.href;
45
- }
46
- catch {
47
- return null;
48
- }
49
- }
50
37
  async function startDeviceAuthorization(oauthHost, signal) {
51
38
  const response = await fetch(`${oauthHost}/api/oauth/device_authorization`, {
52
39
  method: "POST",
@@ -64,14 +51,9 @@ async function startDeviceAuthorization(oauthHost, signal) {
64
51
  const json = await readJson(response);
65
52
  const deviceCode = json?.device_code;
66
53
  const userCode = json?.user_code;
67
- const verificationUri = json?.verification_uri;
68
- const verificationUriComplete = json?.verification_uri_complete;
69
- if (typeof deviceCode !== "string" ||
70
- typeof userCode !== "string" ||
71
- typeof verificationUri !== "string" ||
72
- typeof verificationUriComplete !== "string" ||
73
- !trustedHttpUrl(verificationUriComplete) ||
74
- !trustedHttpUrl(verificationUri)) {
54
+ const verificationUri = trustedHttpUrl(json?.verification_uri);
55
+ const verificationUriComplete = trustedHttpUrl(json?.verification_uri_complete);
56
+ if (typeof deviceCode !== "string" || typeof userCode !== "string" || !verificationUri || !verificationUriComplete) {
75
57
  throw new Error(`Invalid Kimi Code device authorization response: ${JSON.stringify(json)}`);
76
58
  }
77
59
  const interval = json?.interval;
@@ -1 +1 @@
1
- {"version":3,"file":"kimi-coding.js","sourceRoot":"","sources":["../../../src/auth/oauth/kimi-coding.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Kimi Code (subscription) OAuth flow\n *\n * RFC 8628 device authorization grant against https://auth.kimi.com with JSON\n * responses. The access token authenticates requests to\n * https://api.kimi.com/coding as an `Authorization: Bearer` header.\n */\n\nimport { getProviderEnvValue } from \"../../utils/provider-env.ts\";\nimport { sleep } from \"../../utils/sleep.ts\";\nimport type { OAuthAuth, OAuthCredential, ProviderAuthInteraction } from \"../types.ts\";\nimport { pollOAuthDeviceCodeFlow } from \"./device-code.ts\";\n\nconst CLIENT_ID = \"17e5f671-d194-4dfb-9706-5516cb48c098\";\nconst DEFAULT_OAUTH_HOST = \"https://auth.kimi.com\";\nconst DEVICE_CODE_TIMEOUT_SECONDS = 15 * 60;\nconst DEFAULT_POLL_INTERVAL_SECONDS = 5;\nconst REQUEST_TIMEOUT_MS = 30 * 1000;\nconst REFRESH_MAX_RETRIES = 3;\n\ntype DeviceAuthorization = {\n\tdeviceCode: string;\n\tuserCode: string;\n\tverificationUri: string;\n\tverificationUriComplete: string;\n\tintervalSeconds: number;\n\texpiresInSeconds: number;\n};\n\ntype TokenResponse = {\n\taccess: string;\n\trefresh: string;\n\texpires: number;\n};\n\nfunction getOauthHost(): string {\n\tconst override = getProviderEnvValue(\"KIMI_CODE_OAUTH_HOST\") || getProviderEnvValue(\"KIMI_OAUTH_HOST\");\n\treturn (override || DEFAULT_OAUTH_HOST).replace(/\\/+$/, \"\");\n}\n\nfunction requestSignal(signal: AbortSignal): AbortSignal {\n\treturn AbortSignal.any([AbortSignal.timeout(REQUEST_TIMEOUT_MS), signal]);\n}\n\nfunction formUrlEncode(fields: Record<string, string>): string {\n\treturn new URLSearchParams(fields).toString();\n}\n\nasync function readJson(response: Response): Promise<Record<string, unknown> | null> {\n\ttry {\n\t\tconst json = await response.json();\n\t\treturn json && typeof json === \"object\" ? (json as Record<string, unknown>) : null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\n/** The verification URI is opened in the user's browser; only http(s) URLs are trusted. */\nfunction trustedHttpUrl(value: unknown): string | null {\n\tif (typeof value !== \"string\" || !value) return null;\n\ttry {\n\t\tconst url = new URL(value);\n\t\tif (url.protocol !== \"https:\" && url.protocol !== \"http:\") return null;\n\t\treturn url.href;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nasync function startDeviceAuthorization(oauthHost: string, signal: AbortSignal): Promise<DeviceAuthorization> {\n\tconst response = await fetch(`${oauthHost}/api/oauth/device_authorization`, {\n\t\tmethod: \"POST\",\n\t\theaders: {\n\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\tAccept: \"application/json\",\n\t\t},\n\t\tbody: formUrlEncode({ client_id: CLIENT_ID }),\n\t\tsignal: requestSignal(signal),\n\t});\n\n\tif (!response.ok) {\n\t\tconst text = await response.text().catch(() => \"\");\n\t\tthrow new Error(`Kimi Code device authorization failed with status ${response.status}${text ? `: ${text}` : \"\"}`);\n\t}\n\n\tconst json = await readJson(response);\n\tconst deviceCode = json?.device_code;\n\tconst userCode = json?.user_code;\n\tconst verificationUri = json?.verification_uri;\n\tconst verificationUriComplete = json?.verification_uri_complete;\n\tif (\n\t\ttypeof deviceCode !== \"string\" ||\n\t\ttypeof userCode !== \"string\" ||\n\t\ttypeof verificationUri !== \"string\" ||\n\t\ttypeof verificationUriComplete !== \"string\" ||\n\t\t!trustedHttpUrl(verificationUriComplete) ||\n\t\t!trustedHttpUrl(verificationUri)\n\t) {\n\t\tthrow new Error(`Invalid Kimi Code device authorization response: ${JSON.stringify(json)}`);\n\t}\n\n\tconst interval = json?.interval;\n\tconst expiresIn = json?.expires_in;\n\treturn {\n\t\tdeviceCode,\n\t\tuserCode,\n\t\tverificationUri,\n\t\tverificationUriComplete,\n\t\tintervalSeconds:\n\t\t\ttypeof interval === \"number\" && Number.isFinite(interval) && interval > 0\n\t\t\t\t? interval\n\t\t\t\t: DEFAULT_POLL_INTERVAL_SECONDS,\n\t\texpiresInSeconds:\n\t\t\ttypeof expiresIn === \"number\" && Number.isFinite(expiresIn) && expiresIn > 0\n\t\t\t\t? expiresIn\n\t\t\t\t: DEVICE_CODE_TIMEOUT_SECONDS,\n\t};\n}\n\nfunction parseTokenResponse(json: Record<string, unknown> | null, operation: string): TokenResponse {\n\tconst accessToken = json?.access_token;\n\tconst refreshToken = json?.refresh_token;\n\tconst expiresIn = json?.expires_in;\n\tif (\n\t\ttypeof accessToken !== \"string\" ||\n\t\t!accessToken ||\n\t\ttypeof refreshToken !== \"string\" ||\n\t\t!refreshToken ||\n\t\ttypeof expiresIn !== \"number\" ||\n\t\t!Number.isFinite(expiresIn) ||\n\t\texpiresIn <= 0\n\t) {\n\t\tthrow new Error(`Kimi Code token ${operation} response missing fields: ${JSON.stringify(json)}`);\n\t}\n\treturn {\n\t\taccess: accessToken,\n\t\trefresh: refreshToken,\n\t\texpires: Date.now() + expiresIn * 1000,\n\t};\n}\n\nasync function pollForToken(\n\toauthHost: string,\n\tdevice: DeviceAuthorization,\n\tsignal: AbortSignal,\n): Promise<TokenResponse> {\n\treturn pollOAuthDeviceCodeFlow<TokenResponse>({\n\t\tintervalSeconds: device.intervalSeconds,\n\t\texpiresInSeconds: device.expiresInSeconds,\n\t\twaitBeforeFirstPoll: true,\n\t\tsignal,\n\t\tpoll: async () => {\n\t\t\tconst response = await fetch(`${oauthHost}/api/oauth/token`, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: {\n\t\t\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\t\t\tAccept: \"application/json\",\n\t\t\t\t},\n\t\t\t\tbody: formUrlEncode({\n\t\t\t\t\tclient_id: CLIENT_ID,\n\t\t\t\t\tdevice_code: device.deviceCode,\n\t\t\t\t\tgrant_type: \"urn:ietf:params:oauth:grant-type:device_code\",\n\t\t\t\t}),\n\t\t\t\tsignal: requestSignal(signal),\n\t\t\t});\n\n\t\t\tif (response.status >= 500) {\n\t\t\t\tconst text = await response.text().catch(() => \"\");\n\t\t\t\treturn {\n\t\t\t\t\tstatus: \"failed\",\n\t\t\t\t\tmessage: `Kimi Code device token request failed with status ${response.status}${text ? `: ${text}` : \"\"}`,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tconst json = await readJson(response);\n\t\t\tif (response.ok && typeof json?.access_token === \"string\") {\n\t\t\t\ttry {\n\t\t\t\t\treturn { status: \"complete\", value: parseTokenResponse(json, \"poll\") };\n\t\t\t\t} catch (error) {\n\t\t\t\t\treturn { status: \"failed\", message: error instanceof Error ? error.message : String(error) };\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst error = json?.error;\n\t\t\tconst description = typeof json?.error_description === \"string\" ? `: ${json.error_description}` : \"\";\n\t\t\tif (error === \"authorization_pending\") {\n\t\t\t\treturn { status: \"pending\" };\n\t\t\t}\n\t\t\tif (error === \"slow_down\") {\n\t\t\t\tconst interval = json?.interval;\n\t\t\t\treturn {\n\t\t\t\t\tstatus: \"slow_down\",\n\t\t\t\t\tintervalSeconds: typeof interval === \"number\" && interval > 0 ? interval : undefined,\n\t\t\t\t};\n\t\t\t}\n\t\t\tif (error === \"expired_token\") {\n\t\t\t\treturn { status: \"failed\", message: \"Kimi Code device authorization expired. Please restart login.\" };\n\t\t\t}\n\t\t\tif (error === \"access_denied\") {\n\t\t\t\treturn { status: \"failed\", message: \"Kimi Code login was denied.\" };\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tstatus: \"failed\",\n\t\t\t\tmessage: `Kimi Code device token request failed (status ${response.status})${typeof error === \"string\" ? `: ${error}${description}` : \"\"}`,\n\t\t\t};\n\t\t},\n\t});\n}\n\nfunction isRetryableRefreshFailure(response: Response): boolean {\n\treturn response.status === 429 || response.status >= 500;\n}\n\nasync function refreshToken(oauthHost: string, refreshTokenValue: string, signal: AbortSignal): Promise<TokenResponse> {\n\tlet lastError: Error | undefined;\n\tfor (let attempt = 0; attempt <= REFRESH_MAX_RETRIES; attempt++) {\n\t\tif (attempt > 0) {\n\t\t\tawait sleep(1000 * 2 ** (attempt - 1), signal);\n\t\t}\n\t\tif (signal.aborted) {\n\t\t\tthrow new Error(\"Kimi Code token refresh aborted\");\n\t\t}\n\n\t\tlet response: Response;\n\t\ttry {\n\t\t\tresponse = await fetch(`${oauthHost}/api/oauth/token`, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: {\n\t\t\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\t\t\tAccept: \"application/json\",\n\t\t\t\t},\n\t\t\t\tbody: formUrlEncode({\n\t\t\t\t\tclient_id: CLIENT_ID,\n\t\t\t\t\tgrant_type: \"refresh_token\",\n\t\t\t\t\trefresh_token: refreshTokenValue,\n\t\t\t\t}),\n\t\t\t\tsignal: requestSignal(signal),\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tlastError = error instanceof Error ? error : new Error(String(error));\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst json = await readJson(response);\n\t\tif (response.ok) {\n\t\t\treturn parseTokenResponse(json, \"refresh\");\n\t\t}\n\n\t\t// Unauthorized: the stored credential is dead; Models clears it and prompts re-login.\n\t\tif (response.status === 401 || response.status === 403 || json?.error === \"invalid_grant\") {\n\t\t\tconst description = typeof json?.error_description === \"string\" ? `: ${json.error_description}` : \"\";\n\t\t\tthrow new Error(`Kimi Code token refresh unauthorized (status ${response.status})${description}`);\n\t\t}\n\n\t\tif (isRetryableRefreshFailure(response) && attempt < REFRESH_MAX_RETRIES) {\n\t\t\tlastError = new Error(`Kimi Code token refresh failed with status ${response.status}`);\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst text = JSON.stringify(json);\n\t\tthrow new Error(`Kimi Code token refresh failed with status ${response.status}${text ? `: ${text}` : \"\"}`);\n\t}\n\n\tthrow lastError ?? new Error(\"Kimi Code token refresh failed\");\n}\n\nasync function loginKimiCoding(interaction: ProviderAuthInteraction): Promise<OAuthCredential> {\n\tconst oauthHost = getOauthHost();\n\tconst device = await startDeviceAuthorization(oauthHost, interaction.signal);\n\tinteraction.notify({\n\t\ttype: \"device_code\",\n\t\tuserCode: device.userCode,\n\t\tverificationUri: device.verificationUriComplete,\n\t\tintervalSeconds: device.intervalSeconds,\n\t\texpiresInSeconds: device.expiresInSeconds,\n\t});\n\tconst token = await pollForToken(oauthHost, device, interaction.signal);\n\treturn { type: \"oauth\", access: token.access, refresh: token.refresh, expires: token.expires };\n}\n\nexport const kimiCodingOAuth: OAuthAuth = {\n\tname: \"Kimi Code (subscription)\",\n\tisSubscription: true,\n\tloginLabel: \"Sign in with Kimi Code\",\n\n\tlogin: loginKimiCoding,\n\n\trefresh: async (credential, signal) => {\n\t\tconst token = await refreshToken(getOauthHost(), credential.refresh, signal);\n\t\treturn { type: \"oauth\", access: token.access, refresh: token.refresh, expires: token.expires };\n\t},\n\n\tasync toAuth(credential) {\n\t\treturn { headers: { Authorization: `Bearer ${credential.access}` } };\n\t},\n};\n"]}
1
+ {"version":3,"file":"kimi-coding.js","sourceRoot":"","sources":["../../../src/auth/oauth/kimi-coding.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Kimi Code (subscription) OAuth flow\n *\n * RFC 8628 device authorization grant against https://auth.kimi.com with JSON\n * responses. The access token authenticates requests to\n * https://api.kimi.com/coding as an `Authorization: Bearer` header.\n */\n\nimport { getProviderEnvValue } from \"../../utils/provider-env.ts\";\nimport { sleep } from \"../../utils/sleep.ts\";\nimport type { OAuthAuth, OAuthCredential, ProviderAuthInteraction } from \"../types.ts\";\nimport { pollOAuthDeviceCodeFlow } from \"./device-code.ts\";\nimport { trustedHttpUrl } from \"./trusted-url.ts\";\n\nconst CLIENT_ID = \"17e5f671-d194-4dfb-9706-5516cb48c098\";\nconst DEFAULT_OAUTH_HOST = \"https://auth.kimi.com\";\nconst DEVICE_CODE_TIMEOUT_SECONDS = 15 * 60;\nconst DEFAULT_POLL_INTERVAL_SECONDS = 5;\nconst REQUEST_TIMEOUT_MS = 30 * 1000;\nconst REFRESH_MAX_RETRIES = 3;\n\ntype DeviceAuthorization = {\n\tdeviceCode: string;\n\tuserCode: string;\n\tverificationUri: string;\n\tverificationUriComplete: string;\n\tintervalSeconds: number;\n\texpiresInSeconds: number;\n};\n\ntype TokenResponse = {\n\taccess: string;\n\trefresh: string;\n\texpires: number;\n};\n\nfunction getOauthHost(): string {\n\tconst override = getProviderEnvValue(\"KIMI_CODE_OAUTH_HOST\") || getProviderEnvValue(\"KIMI_OAUTH_HOST\");\n\treturn (override || DEFAULT_OAUTH_HOST).replace(/\\/+$/, \"\");\n}\n\nfunction requestSignal(signal: AbortSignal): AbortSignal {\n\treturn AbortSignal.any([AbortSignal.timeout(REQUEST_TIMEOUT_MS), signal]);\n}\n\nfunction formUrlEncode(fields: Record<string, string>): string {\n\treturn new URLSearchParams(fields).toString();\n}\n\nasync function readJson(response: Response): Promise<Record<string, unknown> | null> {\n\ttry {\n\t\tconst json = await response.json();\n\t\treturn json && typeof json === \"object\" ? (json as Record<string, unknown>) : null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nasync function startDeviceAuthorization(oauthHost: string, signal: AbortSignal): Promise<DeviceAuthorization> {\n\tconst response = await fetch(`${oauthHost}/api/oauth/device_authorization`, {\n\t\tmethod: \"POST\",\n\t\theaders: {\n\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\tAccept: \"application/json\",\n\t\t},\n\t\tbody: formUrlEncode({ client_id: CLIENT_ID }),\n\t\tsignal: requestSignal(signal),\n\t});\n\n\tif (!response.ok) {\n\t\tconst text = await response.text().catch(() => \"\");\n\t\tthrow new Error(`Kimi Code device authorization failed with status ${response.status}${text ? `: ${text}` : \"\"}`);\n\t}\n\n\tconst json = await readJson(response);\n\tconst deviceCode = json?.device_code;\n\tconst userCode = json?.user_code;\n\tconst verificationUri = trustedHttpUrl(json?.verification_uri);\n\tconst verificationUriComplete = trustedHttpUrl(json?.verification_uri_complete);\n\tif (typeof deviceCode !== \"string\" || typeof userCode !== \"string\" || !verificationUri || !verificationUriComplete) {\n\t\tthrow new Error(`Invalid Kimi Code device authorization response: ${JSON.stringify(json)}`);\n\t}\n\n\tconst interval = json?.interval;\n\tconst expiresIn = json?.expires_in;\n\treturn {\n\t\tdeviceCode,\n\t\tuserCode,\n\t\tverificationUri,\n\t\tverificationUriComplete,\n\t\tintervalSeconds:\n\t\t\ttypeof interval === \"number\" && Number.isFinite(interval) && interval > 0\n\t\t\t\t? interval\n\t\t\t\t: DEFAULT_POLL_INTERVAL_SECONDS,\n\t\texpiresInSeconds:\n\t\t\ttypeof expiresIn === \"number\" && Number.isFinite(expiresIn) && expiresIn > 0\n\t\t\t\t? expiresIn\n\t\t\t\t: DEVICE_CODE_TIMEOUT_SECONDS,\n\t};\n}\n\nfunction parseTokenResponse(json: Record<string, unknown> | null, operation: string): TokenResponse {\n\tconst accessToken = json?.access_token;\n\tconst refreshToken = json?.refresh_token;\n\tconst expiresIn = json?.expires_in;\n\tif (\n\t\ttypeof accessToken !== \"string\" ||\n\t\t!accessToken ||\n\t\ttypeof refreshToken !== \"string\" ||\n\t\t!refreshToken ||\n\t\ttypeof expiresIn !== \"number\" ||\n\t\t!Number.isFinite(expiresIn) ||\n\t\texpiresIn <= 0\n\t) {\n\t\tthrow new Error(`Kimi Code token ${operation} response missing fields: ${JSON.stringify(json)}`);\n\t}\n\treturn {\n\t\taccess: accessToken,\n\t\trefresh: refreshToken,\n\t\texpires: Date.now() + expiresIn * 1000,\n\t};\n}\n\nasync function pollForToken(\n\toauthHost: string,\n\tdevice: DeviceAuthorization,\n\tsignal: AbortSignal,\n): Promise<TokenResponse> {\n\treturn pollOAuthDeviceCodeFlow<TokenResponse>({\n\t\tintervalSeconds: device.intervalSeconds,\n\t\texpiresInSeconds: device.expiresInSeconds,\n\t\twaitBeforeFirstPoll: true,\n\t\tsignal,\n\t\tpoll: async () => {\n\t\t\tconst response = await fetch(`${oauthHost}/api/oauth/token`, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: {\n\t\t\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\t\t\tAccept: \"application/json\",\n\t\t\t\t},\n\t\t\t\tbody: formUrlEncode({\n\t\t\t\t\tclient_id: CLIENT_ID,\n\t\t\t\t\tdevice_code: device.deviceCode,\n\t\t\t\t\tgrant_type: \"urn:ietf:params:oauth:grant-type:device_code\",\n\t\t\t\t}),\n\t\t\t\tsignal: requestSignal(signal),\n\t\t\t});\n\n\t\t\tif (response.status >= 500) {\n\t\t\t\tconst text = await response.text().catch(() => \"\");\n\t\t\t\treturn {\n\t\t\t\t\tstatus: \"failed\",\n\t\t\t\t\tmessage: `Kimi Code device token request failed with status ${response.status}${text ? `: ${text}` : \"\"}`,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tconst json = await readJson(response);\n\t\t\tif (response.ok && typeof json?.access_token === \"string\") {\n\t\t\t\ttry {\n\t\t\t\t\treturn { status: \"complete\", value: parseTokenResponse(json, \"poll\") };\n\t\t\t\t} catch (error) {\n\t\t\t\t\treturn { status: \"failed\", message: error instanceof Error ? error.message : String(error) };\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst error = json?.error;\n\t\t\tconst description = typeof json?.error_description === \"string\" ? `: ${json.error_description}` : \"\";\n\t\t\tif (error === \"authorization_pending\") {\n\t\t\t\treturn { status: \"pending\" };\n\t\t\t}\n\t\t\tif (error === \"slow_down\") {\n\t\t\t\tconst interval = json?.interval;\n\t\t\t\treturn {\n\t\t\t\t\tstatus: \"slow_down\",\n\t\t\t\t\tintervalSeconds: typeof interval === \"number\" && interval > 0 ? interval : undefined,\n\t\t\t\t};\n\t\t\t}\n\t\t\tif (error === \"expired_token\") {\n\t\t\t\treturn { status: \"failed\", message: \"Kimi Code device authorization expired. Please restart login.\" };\n\t\t\t}\n\t\t\tif (error === \"access_denied\") {\n\t\t\t\treturn { status: \"failed\", message: \"Kimi Code login was denied.\" };\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tstatus: \"failed\",\n\t\t\t\tmessage: `Kimi Code device token request failed (status ${response.status})${typeof error === \"string\" ? `: ${error}${description}` : \"\"}`,\n\t\t\t};\n\t\t},\n\t});\n}\n\nfunction isRetryableRefreshFailure(response: Response): boolean {\n\treturn response.status === 429 || response.status >= 500;\n}\n\nasync function refreshToken(oauthHost: string, refreshTokenValue: string, signal: AbortSignal): Promise<TokenResponse> {\n\tlet lastError: Error | undefined;\n\tfor (let attempt = 0; attempt <= REFRESH_MAX_RETRIES; attempt++) {\n\t\tif (attempt > 0) {\n\t\t\tawait sleep(1000 * 2 ** (attempt - 1), signal);\n\t\t}\n\t\tif (signal.aborted) {\n\t\t\tthrow new Error(\"Kimi Code token refresh aborted\");\n\t\t}\n\n\t\tlet response: Response;\n\t\ttry {\n\t\t\tresponse = await fetch(`${oauthHost}/api/oauth/token`, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: {\n\t\t\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\t\t\tAccept: \"application/json\",\n\t\t\t\t},\n\t\t\t\tbody: formUrlEncode({\n\t\t\t\t\tclient_id: CLIENT_ID,\n\t\t\t\t\tgrant_type: \"refresh_token\",\n\t\t\t\t\trefresh_token: refreshTokenValue,\n\t\t\t\t}),\n\t\t\t\tsignal: requestSignal(signal),\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tlastError = error instanceof Error ? error : new Error(String(error));\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst json = await readJson(response);\n\t\tif (response.ok) {\n\t\t\treturn parseTokenResponse(json, \"refresh\");\n\t\t}\n\n\t\t// Unauthorized: the stored credential is dead; Models clears it and prompts re-login.\n\t\tif (response.status === 401 || response.status === 403 || json?.error === \"invalid_grant\") {\n\t\t\tconst description = typeof json?.error_description === \"string\" ? `: ${json.error_description}` : \"\";\n\t\t\tthrow new Error(`Kimi Code token refresh unauthorized (status ${response.status})${description}`);\n\t\t}\n\n\t\tif (isRetryableRefreshFailure(response) && attempt < REFRESH_MAX_RETRIES) {\n\t\t\tlastError = new Error(`Kimi Code token refresh failed with status ${response.status}`);\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst text = JSON.stringify(json);\n\t\tthrow new Error(`Kimi Code token refresh failed with status ${response.status}${text ? `: ${text}` : \"\"}`);\n\t}\n\n\tthrow lastError ?? new Error(\"Kimi Code token refresh failed\");\n}\n\nasync function loginKimiCoding(interaction: ProviderAuthInteraction): Promise<OAuthCredential> {\n\tconst oauthHost = getOauthHost();\n\tconst device = await startDeviceAuthorization(oauthHost, interaction.signal);\n\tinteraction.notify({\n\t\ttype: \"device_code\",\n\t\tuserCode: device.userCode,\n\t\tverificationUri: device.verificationUriComplete,\n\t\tintervalSeconds: device.intervalSeconds,\n\t\texpiresInSeconds: device.expiresInSeconds,\n\t});\n\tconst token = await pollForToken(oauthHost, device, interaction.signal);\n\treturn { type: \"oauth\", access: token.access, refresh: token.refresh, expires: token.expires };\n}\n\nexport const kimiCodingOAuth: OAuthAuth = {\n\tname: \"Kimi Code (subscription)\",\n\tisSubscription: true,\n\tloginLabel: \"Sign in with Kimi Code\",\n\n\tlogin: loginKimiCoding,\n\n\trefresh: async (credential, signal) => {\n\t\tconst token = await refreshToken(getOauthHost(), credential.refresh, signal);\n\t\treturn { type: \"oauth\", access: token.access, refresh: token.refresh, expires: token.expires };\n\t},\n\n\tasync toAuth(credential) {\n\t\treturn { headers: { Authorization: `Bearer ${credential.access}` } };\n\t},\n};\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"meta.d.ts","sourceRoot":"","sources":["../../../src/auth/oauth/meta.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,SAAS,EAA4C,MAAM,aAAa,CAAC;AAoLvF,eAAO,MAAM,SAAS,EAAE,SAYvB,CAAC"}
1
+ {"version":3,"file":"meta.d.ts","sourceRoot":"","sources":["../../../src/auth/oauth/meta.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,SAAS,EAA4C,MAAM,aAAa,CAAC;AAyKvF,eAAO,MAAM,SAAS,EAAE,SAYvB,CAAC"}
@@ -13,6 +13,7 @@
13
13
  * user must sign in again.
14
14
  */
15
15
  import { pollOAuthDeviceCodeFlow } from "./device-code.js";
16
+ import { trustedHttpUrl } from "./trusted-url.js";
16
17
  // Muse Code CLI client id.
17
18
  const CLIENT_ID = "1031625952748946";
18
19
  const AUTH_HOST = "https://auth.meta.com";
@@ -41,20 +42,6 @@ function errorDetail(json) {
41
42
  }
42
43
  return "";
43
44
  }
44
- /** The verification URI is opened in the user's browser; only http(s) URLs are trusted. */
45
- function trustedHttpUrl(value) {
46
- if (typeof value !== "string" || !value)
47
- return null;
48
- try {
49
- const url = new URL(value);
50
- if (url.protocol !== "https:" && url.protocol !== "http:")
51
- return null;
52
- return url.href;
53
- }
54
- catch {
55
- return null;
56
- }
57
- }
58
45
  function positiveNumber(value) {
59
46
  return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : undefined;
60
47
  }
@@ -1 +1 @@
1
- {"version":3,"file":"meta.js","sourceRoot":"","sources":["../../../src/auth/oauth/meta.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Meta Model API OAuth flow\n *\n * RFC 8628 device authorization grant against https://auth.meta.com (JSON\n * responses). Meta splits identity from API access: the resulting identity\n * token is not accepted for inference, so it is exchanged for a Model API\n * key via the Muse Code key-mint endpoint (minted keys live about a day).\n * The identity token is stored as `refresh` and the minted key as `access`,\n * so the standard OAuth scheduler re-mints the key when it expires with no\n * bespoke renewal machinery. The identity token itself is not renewable\n * (auth.meta.com answers grant_type=refresh_token with 404 and issues no\n * refresh_token), so a 401/403 from mint means the session is dead and the\n * user must sign in again.\n */\n\nimport type { OAuthAuth, OAuthCredential, ProviderAuthInteraction } from \"../types.ts\";\nimport { pollOAuthDeviceCodeFlow } from \"./device-code.ts\";\n\n// Muse Code CLI client id.\nconst CLIENT_ID = \"1031625952748946\";\nconst AUTH_HOST = \"https://auth.meta.com\";\nconst DEVICE_AUTHORIZATION_URL = `${AUTH_HOST}/oidc/device/authorization/`;\nconst DEVICE_TOKEN_URL = `${AUTH_HOST}/oidc/device/token/`;\nconst API_KEY_MINT_URL = \"https://api.meta.ai/muse-code/key\";\nconst API_KEY_LIFETIME_MS = 24 * 60 * 60 * 1000;\nconst REQUEST_TIMEOUT_MS = 30 * 1000;\n\ntype DeviceAuthorization = {\n\tdeviceCode: string;\n\tuserCode: string;\n\tverificationUri: string;\n\tintervalSeconds?: number;\n\texpiresInSeconds?: number;\n};\n\nfunction requestSignal(signal: AbortSignal): AbortSignal {\n\treturn AbortSignal.any([AbortSignal.timeout(REQUEST_TIMEOUT_MS), signal]);\n}\n\nasync function readJson(response: Response): Promise<Record<string, unknown> | null> {\n\ttry {\n\t\tconst json = await response.json();\n\t\treturn json && typeof json === \"object\" ? (json as Record<string, unknown>) : null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction errorDetail(json: Record<string, unknown> | null): string {\n\tfor (const key of [\"error_description\", \"detail\", \"message\", \"error\"]) {\n\t\tconst value = json?.[key];\n\t\tif (typeof value === \"string\" && value.trim()) return `: ${value.trim()}`;\n\t}\n\treturn \"\";\n}\n\n/** The verification URI is opened in the user's browser; only http(s) URLs are trusted. */\nfunction trustedHttpUrl(value: unknown): string | null {\n\tif (typeof value !== \"string\" || !value) return null;\n\ttry {\n\t\tconst url = new URL(value);\n\t\tif (url.protocol !== \"https:\" && url.protocol !== \"http:\") return null;\n\t\treturn url.href;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction positiveNumber(value: unknown): number | undefined {\n\treturn typeof value === \"number\" && Number.isFinite(value) && value > 0 ? value : undefined;\n}\n\nasync function startDeviceAuthorization(signal: AbortSignal): Promise<DeviceAuthorization> {\n\tconst response = await fetch(DEVICE_AUTHORIZATION_URL, {\n\t\tmethod: \"POST\",\n\t\theaders: {\n\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\tAccept: \"application/json\",\n\t\t},\n\t\tbody: new URLSearchParams({ client_id: CLIENT_ID }).toString(),\n\t\tsignal: requestSignal(signal),\n\t});\n\tconst json = await readJson(response);\n\tif (!response.ok) {\n\t\tthrow new Error(`Meta device authorization failed with status ${response.status}${errorDetail(json)}`);\n\t}\n\tconst deviceCode = json?.device_code;\n\tconst userCode = json?.user_code;\n\tconst verificationUri = trustedHttpUrl(json?.verification_uri_complete) ?? trustedHttpUrl(json?.verification_uri);\n\tif (typeof deviceCode !== \"string\" || !deviceCode || typeof userCode !== \"string\" || !userCode || !verificationUri) {\n\t\tthrow new Error(`Invalid Meta device authorization response: ${JSON.stringify(json)}`);\n\t}\n\treturn {\n\t\tdeviceCode,\n\t\tuserCode,\n\t\tverificationUri,\n\t\tintervalSeconds: positiveNumber(json?.interval),\n\t\texpiresInSeconds: positiveNumber(json?.expires_in),\n\t};\n}\n\nasync function pollForIdentityToken(device: DeviceAuthorization, signal: AbortSignal): Promise<string> {\n\treturn pollOAuthDeviceCodeFlow<string>({\n\t\tintervalSeconds: device.intervalSeconds,\n\t\texpiresInSeconds: device.expiresInSeconds,\n\t\twaitBeforeFirstPoll: true,\n\t\tsignal,\n\t\tpoll: async () => {\n\t\t\tconst response = await fetch(DEVICE_TOKEN_URL, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: {\n\t\t\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\t\t\tAccept: \"application/json\",\n\t\t\t\t},\n\t\t\t\tbody: new URLSearchParams({\n\t\t\t\t\tgrant_type: \"urn:ietf:params:oauth:grant-type:device_code\",\n\t\t\t\t\tdevice_code: device.deviceCode,\n\t\t\t\t\tclient_id: CLIENT_ID,\n\t\t\t\t}).toString(),\n\t\t\t\tsignal: requestSignal(signal),\n\t\t\t});\n\t\t\tconst json = await readJson(response);\n\t\t\tif (response.ok && typeof json?.access_token === \"string\" && json.access_token) {\n\t\t\t\treturn { status: \"complete\", value: json.access_token };\n\t\t\t}\n\t\t\tswitch (json?.error) {\n\t\t\t\tcase \"authorization_pending\":\n\t\t\t\t\treturn { status: \"pending\" };\n\t\t\t\tcase \"slow_down\":\n\t\t\t\t\treturn { status: \"slow_down\", intervalSeconds: positiveNumber(json?.interval) };\n\t\t\t\tcase \"access_denied\":\n\t\t\t\t\treturn { status: \"failed\", message: \"Meta login was denied.\" };\n\t\t\t\tcase \"expired_token\":\n\t\t\t\t\treturn { status: \"failed\", message: \"Meta device authorization expired. Please restart login.\" };\n\t\t\t\tdefault:\n\t\t\t\t\treturn {\n\t\t\t\t\t\tstatus: \"failed\",\n\t\t\t\t\t\tmessage: `Meta device token request failed with status ${response.status}${errorDetail(json)}`,\n\t\t\t\t\t};\n\t\t\t}\n\t\t},\n\t});\n}\n\n/** Exchange an identity token for a Model API key. Keys are valid for about a day. */\nasync function mintApiKey(identityToken: string, signal: AbortSignal): Promise<OAuthCredential> {\n\tconst response = await fetch(API_KEY_MINT_URL, {\n\t\tmethod: \"POST\",\n\t\theaders: {\n\t\t\tAccept: \"application/json\",\n\t\t\tAuthorization: `Bearer ${identityToken}`,\n\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\"x-api-version\": \"1.0.0\",\n\t\t},\n\t\tbody: \"{}\",\n\t\tsignal: requestSignal(signal),\n\t});\n\tconst json = await readJson(response);\n\tif (response.status === 401 || response.status === 403) {\n\t\t// Identity token is not renewable (see file header); only a fresh device flow helps.\n\t\tthrow new Error(\n\t\t\t`Meta session expired (status ${response.status}). Run \\`/login meta\\` to sign in again.${errorDetail(json)}`,\n\t\t);\n\t}\n\tif (!response.ok) {\n\t\tthrow new Error(`Meta API key mint failed with status ${response.status}${errorDetail(json)}`);\n\t}\n\tconst apiKey = json?.api_key;\n\tif (typeof apiKey !== \"string\" || !apiKey) {\n\t\tconst actionUrl = trustedHttpUrl(json?.action_url);\n\t\tthrow new Error(`Meta did not issue an API key.${actionUrl ? ` Complete setup at ${actionUrl}` : \"\"}`);\n\t}\n\treturn { type: \"oauth\", refresh: identityToken, access: apiKey, expires: Date.now() + API_KEY_LIFETIME_MS };\n}\n\nasync function loginMeta(interaction: ProviderAuthInteraction): Promise<OAuthCredential> {\n\ttry {\n\t\tconst device = await startDeviceAuthorization(interaction.signal);\n\t\tinteraction.notify({\n\t\t\ttype: \"device_code\",\n\t\t\tuserCode: device.userCode,\n\t\t\tverificationUri: device.verificationUri,\n\t\t\tintervalSeconds: device.intervalSeconds,\n\t\t\texpiresInSeconds: device.expiresInSeconds,\n\t\t});\n\t\tconst identityToken = await pollForIdentityToken(device, interaction.signal);\n\t\tinteraction.notify({ type: \"progress\", message: \"Enabling Meta Model API access...\" });\n\t\treturn await mintApiKey(identityToken, interaction.signal);\n\t} catch (e) {\n\t\t// An in-flight fetch rejects with a DOMException on abort; the login UI matches on this message.\n\t\tif (interaction.signal.aborted) throw new Error(\"Login cancelled\");\n\t\tthrow e;\n\t}\n}\n\nexport const metaOAuth: OAuthAuth = {\n\tname: \"Meta (Muse subscription)\",\n\tisSubscription: true,\n\tloginLabel: \"Sign in with Meta\",\n\n\tlogin: loginMeta,\n\n\trefresh: (credential, signal) => mintApiKey(credential.refresh, signal),\n\n\tasync toAuth(credential) {\n\t\treturn { apiKey: credential.access };\n\t},\n};\n"]}
1
+ {"version":3,"file":"meta.js","sourceRoot":"","sources":["../../../src/auth/oauth/meta.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Meta Model API OAuth flow\n *\n * RFC 8628 device authorization grant against https://auth.meta.com (JSON\n * responses). Meta splits identity from API access: the resulting identity\n * token is not accepted for inference, so it is exchanged for a Model API\n * key via the Muse Code key-mint endpoint (minted keys live about a day).\n * The identity token is stored as `refresh` and the minted key as `access`,\n * so the standard OAuth scheduler re-mints the key when it expires with no\n * bespoke renewal machinery. The identity token itself is not renewable\n * (auth.meta.com answers grant_type=refresh_token with 404 and issues no\n * refresh_token), so a 401/403 from mint means the session is dead and the\n * user must sign in again.\n */\n\nimport type { OAuthAuth, OAuthCredential, ProviderAuthInteraction } from \"../types.ts\";\nimport { pollOAuthDeviceCodeFlow } from \"./device-code.ts\";\nimport { trustedHttpUrl } from \"./trusted-url.ts\";\n\n// Muse Code CLI client id.\nconst CLIENT_ID = \"1031625952748946\";\nconst AUTH_HOST = \"https://auth.meta.com\";\nconst DEVICE_AUTHORIZATION_URL = `${AUTH_HOST}/oidc/device/authorization/`;\nconst DEVICE_TOKEN_URL = `${AUTH_HOST}/oidc/device/token/`;\nconst API_KEY_MINT_URL = \"https://api.meta.ai/muse-code/key\";\nconst API_KEY_LIFETIME_MS = 24 * 60 * 60 * 1000;\nconst REQUEST_TIMEOUT_MS = 30 * 1000;\n\ntype DeviceAuthorization = {\n\tdeviceCode: string;\n\tuserCode: string;\n\tverificationUri: string;\n\tintervalSeconds?: number;\n\texpiresInSeconds?: number;\n};\n\nfunction requestSignal(signal: AbortSignal): AbortSignal {\n\treturn AbortSignal.any([AbortSignal.timeout(REQUEST_TIMEOUT_MS), signal]);\n}\n\nasync function readJson(response: Response): Promise<Record<string, unknown> | null> {\n\ttry {\n\t\tconst json = await response.json();\n\t\treturn json && typeof json === \"object\" ? (json as Record<string, unknown>) : null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction errorDetail(json: Record<string, unknown> | null): string {\n\tfor (const key of [\"error_description\", \"detail\", \"message\", \"error\"]) {\n\t\tconst value = json?.[key];\n\t\tif (typeof value === \"string\" && value.trim()) return `: ${value.trim()}`;\n\t}\n\treturn \"\";\n}\n\nfunction positiveNumber(value: unknown): number | undefined {\n\treturn typeof value === \"number\" && Number.isFinite(value) && value > 0 ? value : undefined;\n}\n\nasync function startDeviceAuthorization(signal: AbortSignal): Promise<DeviceAuthorization> {\n\tconst response = await fetch(DEVICE_AUTHORIZATION_URL, {\n\t\tmethod: \"POST\",\n\t\theaders: {\n\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\tAccept: \"application/json\",\n\t\t},\n\t\tbody: new URLSearchParams({ client_id: CLIENT_ID }).toString(),\n\t\tsignal: requestSignal(signal),\n\t});\n\tconst json = await readJson(response);\n\tif (!response.ok) {\n\t\tthrow new Error(`Meta device authorization failed with status ${response.status}${errorDetail(json)}`);\n\t}\n\tconst deviceCode = json?.device_code;\n\tconst userCode = json?.user_code;\n\tconst verificationUri = trustedHttpUrl(json?.verification_uri_complete) ?? trustedHttpUrl(json?.verification_uri);\n\tif (typeof deviceCode !== \"string\" || !deviceCode || typeof userCode !== \"string\" || !userCode || !verificationUri) {\n\t\tthrow new Error(`Invalid Meta device authorization response: ${JSON.stringify(json)}`);\n\t}\n\treturn {\n\t\tdeviceCode,\n\t\tuserCode,\n\t\tverificationUri,\n\t\tintervalSeconds: positiveNumber(json?.interval),\n\t\texpiresInSeconds: positiveNumber(json?.expires_in),\n\t};\n}\n\nasync function pollForIdentityToken(device: DeviceAuthorization, signal: AbortSignal): Promise<string> {\n\treturn pollOAuthDeviceCodeFlow<string>({\n\t\tintervalSeconds: device.intervalSeconds,\n\t\texpiresInSeconds: device.expiresInSeconds,\n\t\twaitBeforeFirstPoll: true,\n\t\tsignal,\n\t\tpoll: async () => {\n\t\t\tconst response = await fetch(DEVICE_TOKEN_URL, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: {\n\t\t\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\t\t\tAccept: \"application/json\",\n\t\t\t\t},\n\t\t\t\tbody: new URLSearchParams({\n\t\t\t\t\tgrant_type: \"urn:ietf:params:oauth:grant-type:device_code\",\n\t\t\t\t\tdevice_code: device.deviceCode,\n\t\t\t\t\tclient_id: CLIENT_ID,\n\t\t\t\t}).toString(),\n\t\t\t\tsignal: requestSignal(signal),\n\t\t\t});\n\t\t\tconst json = await readJson(response);\n\t\t\tif (response.ok && typeof json?.access_token === \"string\" && json.access_token) {\n\t\t\t\treturn { status: \"complete\", value: json.access_token };\n\t\t\t}\n\t\t\tswitch (json?.error) {\n\t\t\t\tcase \"authorization_pending\":\n\t\t\t\t\treturn { status: \"pending\" };\n\t\t\t\tcase \"slow_down\":\n\t\t\t\t\treturn { status: \"slow_down\", intervalSeconds: positiveNumber(json?.interval) };\n\t\t\t\tcase \"access_denied\":\n\t\t\t\t\treturn { status: \"failed\", message: \"Meta login was denied.\" };\n\t\t\t\tcase \"expired_token\":\n\t\t\t\t\treturn { status: \"failed\", message: \"Meta device authorization expired. Please restart login.\" };\n\t\t\t\tdefault:\n\t\t\t\t\treturn {\n\t\t\t\t\t\tstatus: \"failed\",\n\t\t\t\t\t\tmessage: `Meta device token request failed with status ${response.status}${errorDetail(json)}`,\n\t\t\t\t\t};\n\t\t\t}\n\t\t},\n\t});\n}\n\n/** Exchange an identity token for a Model API key. Keys are valid for about a day. */\nasync function mintApiKey(identityToken: string, signal: AbortSignal): Promise<OAuthCredential> {\n\tconst response = await fetch(API_KEY_MINT_URL, {\n\t\tmethod: \"POST\",\n\t\theaders: {\n\t\t\tAccept: \"application/json\",\n\t\t\tAuthorization: `Bearer ${identityToken}`,\n\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\"x-api-version\": \"1.0.0\",\n\t\t},\n\t\tbody: \"{}\",\n\t\tsignal: requestSignal(signal),\n\t});\n\tconst json = await readJson(response);\n\tif (response.status === 401 || response.status === 403) {\n\t\t// Identity token is not renewable (see file header); only a fresh device flow helps.\n\t\tthrow new Error(\n\t\t\t`Meta session expired (status ${response.status}). Run \\`/login meta\\` to sign in again.${errorDetail(json)}`,\n\t\t);\n\t}\n\tif (!response.ok) {\n\t\tthrow new Error(`Meta API key mint failed with status ${response.status}${errorDetail(json)}`);\n\t}\n\tconst apiKey = json?.api_key;\n\tif (typeof apiKey !== \"string\" || !apiKey) {\n\t\tconst actionUrl = trustedHttpUrl(json?.action_url);\n\t\tthrow new Error(`Meta did not issue an API key.${actionUrl ? ` Complete setup at ${actionUrl}` : \"\"}`);\n\t}\n\treturn { type: \"oauth\", refresh: identityToken, access: apiKey, expires: Date.now() + API_KEY_LIFETIME_MS };\n}\n\nasync function loginMeta(interaction: ProviderAuthInteraction): Promise<OAuthCredential> {\n\ttry {\n\t\tconst device = await startDeviceAuthorization(interaction.signal);\n\t\tinteraction.notify({\n\t\t\ttype: \"device_code\",\n\t\t\tuserCode: device.userCode,\n\t\t\tverificationUri: device.verificationUri,\n\t\t\tintervalSeconds: device.intervalSeconds,\n\t\t\texpiresInSeconds: device.expiresInSeconds,\n\t\t});\n\t\tconst identityToken = await pollForIdentityToken(device, interaction.signal);\n\t\tinteraction.notify({ type: \"progress\", message: \"Enabling Meta Model API access...\" });\n\t\treturn await mintApiKey(identityToken, interaction.signal);\n\t} catch (e) {\n\t\t// An in-flight fetch rejects with a DOMException on abort; the login UI matches on this message.\n\t\tif (interaction.signal.aborted) throw new Error(\"Login cancelled\");\n\t\tthrow e;\n\t}\n}\n\nexport const metaOAuth: OAuthAuth = {\n\tname: \"Meta (Muse subscription)\",\n\tisSubscription: true,\n\tloginLabel: \"Sign in with Meta\",\n\n\tlogin: loginMeta,\n\n\trefresh: (credential, signal) => mintApiKey(credential.refresh, signal),\n\n\tasync toAuth(credential) {\n\t\treturn { apiKey: credential.access };\n\t},\n};\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"radius.d.ts","sourceRoot":"","sources":["../../../src/auth/oauth/radius.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,KAAK,EAAE,SAAS,EAA4C,MAAM,aAAa,CAAC;AAiQvF,MAAM,WAAW,kBAAkB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,kBAAkB,GAAG,SAAS,CA8CxE"}
1
+ {"version":3,"file":"radius.d.ts","sourceRoot":"","sources":["../../../src/auth/oauth/radius.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,KAAK,EAAE,SAAS,EAA4C,MAAM,aAAa,CAAC;AAuQvF,MAAM,WAAW,kBAAkB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,kBAAkB,GAAG,SAAS,CA8CxE"}
@@ -12,6 +12,7 @@ import { normalizeRadiusGatewayUrl } from "../../providers/radius-config.js";
12
12
  import { startOAuthCallbackServer } from "./callback-server.js";
13
13
  import { pollOAuthDeviceCodeFlow } from "./device-code.js";
14
14
  import { generatePKCE } from "./pkce.js";
15
+ import { trustedHttpUrl } from "./trusted-url.js";
15
16
  const CALLBACK_HOST = "127.0.0.1";
16
17
  const CALLBACK_PORT = 1456;
17
18
  const CALLBACK_PATH = "/oauth/callback";
@@ -31,10 +32,11 @@ async function loadRadiusOAuthDiscovery(gateway, signal) {
31
32
  throw new Error(`Could not load Radius OAuth config from ${gateway}: ${response.status} ${await response.text()}`);
32
33
  }
33
34
  const discovery = (await response.json());
34
- if (typeof discovery.authorizationEndpoint !== "string") {
35
+ const authorizationEndpoint = trustedHttpUrl(discovery.authorizationEndpoint);
36
+ if (!authorizationEndpoint) {
35
37
  throw new Error(`Invalid Radius OAuth config from ${gateway}`);
36
38
  }
37
- return { authorizationEndpoint: discovery.authorizationEndpoint };
39
+ return { authorizationEndpoint };
38
40
  }
39
41
  class OAuthResponseError extends Error {
40
42
  status;
@@ -162,10 +164,14 @@ async function requestDeviceAuthorization(gateway, signal) {
162
164
  if (!data.device_code || !data.user_code || !data.verification_uri || !data.expires_in) {
163
165
  throw new Error("Radius OAuth device authorization response is missing required fields");
164
166
  }
167
+ const verificationUri = trustedHttpUrl(data.verification_uri);
168
+ if (!verificationUri) {
169
+ throw new Error("Untrusted verification_uri in Radius OAuth device authorization response");
170
+ }
165
171
  return {
166
172
  device_code: data.device_code,
167
173
  user_code: data.user_code,
168
- verification_uri: data.verification_uri,
174
+ verification_uri: verificationUri,
169
175
  expires_in: data.expires_in,
170
176
  interval: data.interval,
171
177
  };