cartethyia 2.7.4 → 2.7.5

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 (553) hide show
  1. package/.env.example +2 -0
  2. package/README.md +17 -5
  3. package/dist/dashboard/assets/{BannedPage-ChG5svFb.js → BannedPage-Cj15GsMp.js} +1 -1
  4. package/dist/dashboard/assets/BannedPage-Cj15GsMp.js.gz +0 -0
  5. package/dist/dashboard/assets/ClaimGiftsButton-D83pBJ6J.js +1 -0
  6. package/dist/dashboard/assets/ClaimGiftsButton-D83pBJ6J.js.gz +0 -0
  7. package/dist/dashboard/assets/{CliToolDetailPage-BIcWQun7.js → CliToolDetailPage-DZKmVuJN.js} +1 -1
  8. package/dist/dashboard/assets/CliToolDetailPage-DZKmVuJN.js.gz +0 -0
  9. package/dist/dashboard/assets/{CliToolsPage-Bf2VelDe.js → CliToolsPage-BIccZmeL.js} +1 -1
  10. package/dist/dashboard/assets/CliToolsPage-BIccZmeL.js.gz +0 -0
  11. package/dist/dashboard/assets/CombosPage-DEEKkYD-.js +1 -0
  12. package/dist/dashboard/assets/CombosPage-DEEKkYD-.js.gz +0 -0
  13. package/dist/dashboard/assets/ConsoleLogPage-D5rol2j2.js +1 -0
  14. package/dist/dashboard/assets/ConsoleLogPage-D5rol2j2.js.gz +0 -0
  15. package/dist/dashboard/assets/{CustomizationPage-ggeMSjte.js → CustomizationPage-BKj_r0rp.js} +1 -1
  16. package/dist/dashboard/assets/CustomizationPage-BKj_r0rp.js.gz +0 -0
  17. package/dist/dashboard/assets/InjectSystemPromptPanel-B5nZvmf0.js +656 -0
  18. package/dist/dashboard/assets/InjectSystemPromptPanel-B5nZvmf0.js.gz +0 -0
  19. package/dist/dashboard/assets/{LoginPage-U6AKaJcF.js → LoginPage-DkXb6dx-.js} +1 -1
  20. package/dist/dashboard/assets/LoginPage-DkXb6dx-.js.gz +0 -0
  21. package/dist/dashboard/assets/{ModelPicker-BMS2t8BA.js → ModelPicker-DnQPSIA8.js} +1 -1
  22. package/dist/dashboard/assets/ModelPicker-DnQPSIA8.js.gz +0 -0
  23. package/dist/dashboard/assets/OverviewPage-Ci2wQKUz.js +1 -0
  24. package/dist/dashboard/assets/OverviewPage-Ci2wQKUz.js.gz +0 -0
  25. package/dist/dashboard/assets/ProviderDetailPage-odlgYrOg.js +5 -0
  26. package/dist/dashboard/assets/ProviderDetailPage-odlgYrOg.js.gz +0 -0
  27. package/dist/dashboard/assets/ProviderIcon-EfeloBn4.js +1 -0
  28. package/dist/dashboard/assets/ProviderIcon-EfeloBn4.js.gz +0 -0
  29. package/dist/dashboard/assets/ProvidersPage-CqFBQEB8.js +1 -0
  30. package/dist/dashboard/assets/ProvidersPage-CqFBQEB8.js.gz +0 -0
  31. package/dist/dashboard/assets/{ProxyPage-lsrx7NYg.js → ProxyPage-5SnUSy3j.js} +1 -1
  32. package/dist/dashboard/assets/ProxyPage-5SnUSy3j.js.gz +0 -0
  33. package/dist/dashboard/assets/QuotaPage-CmnMDzhP.js +1 -0
  34. package/dist/dashboard/assets/QuotaPage-CmnMDzhP.js.gz +0 -0
  35. package/dist/dashboard/assets/SettingsPage-BJtRZ4qD.js +1 -0
  36. package/dist/dashboard/assets/SettingsPage-BJtRZ4qD.js.gz +0 -0
  37. package/dist/dashboard/assets/{SetupPage-f0DE1h0-.js → SetupPage-WTa0sktC.js} +1 -1
  38. package/dist/dashboard/assets/SetupPage-WTa0sktC.js.gz +0 -0
  39. package/dist/dashboard/assets/{StudioPage-Cq5tW7hW.js → StudioPage-BfAb5-o_.js} +3 -3
  40. package/dist/dashboard/assets/StudioPage-BfAb5-o_.js.gz +0 -0
  41. package/dist/dashboard/assets/UsagePage-BNzeZ2Vk.js +56 -0
  42. package/dist/dashboard/assets/UsagePage-BNzeZ2Vk.js.gz +0 -0
  43. package/dist/dashboard/assets/api-keys-l29JROPv.js +1 -0
  44. package/dist/dashboard/assets/api-keys-l29JROPv.js.gz +0 -0
  45. package/dist/dashboard/assets/app--PJWq8_C.css +2 -0
  46. package/dist/dashboard/assets/app--PJWq8_C.css.gz +0 -0
  47. package/dist/dashboard/assets/assert-C0K-c4eo.js +1 -0
  48. package/dist/dashboard/assets/assert-C0K-c4eo.js.gz +0 -0
  49. package/dist/dashboard/assets/{badge-D9CS6dZk.js → badge-DfbhQU4k.js} +1 -1
  50. package/dist/dashboard/assets/badge-DfbhQU4k.js.gz +0 -0
  51. package/dist/dashboard/assets/{banner-DympBNq4.js → banner-BllT4LcF.js} +1 -1
  52. package/dist/dashboard/assets/banner-BllT4LcF.js.gz +0 -0
  53. package/dist/dashboard/assets/brand/login_register.jpg +0 -0
  54. package/dist/dashboard/assets/brand/login_register_initial.jpg +0 -0
  55. package/dist/dashboard/assets/brand/og_bansos.jpg +0 -0
  56. package/dist/dashboard/assets/brand/og_image.jpg +0 -0
  57. package/dist/dashboard/assets/{card-ibRWU_uT.js → card-CtkX66Wd.js} +1 -1
  58. package/dist/dashboard/assets/card-CtkX66Wd.js.gz +0 -0
  59. package/dist/dashboard/assets/chevron-left-Bf6CaTSJ.js +1 -0
  60. package/dist/dashboard/assets/chevron-left-Bf6CaTSJ.js.gz +0 -0
  61. package/dist/dashboard/assets/cli-tools-CQXVMn4P.js +1 -0
  62. package/dist/dashboard/assets/cli-tools-CQXVMn4P.js.gz +0 -0
  63. package/dist/dashboard/assets/{clipboard-button-DJm-9pz7.js → clipboard-button-BQqBQd2n.js} +1 -1
  64. package/dist/dashboard/assets/clipboard-button-BQqBQd2n.js.gz +0 -0
  65. package/dist/dashboard/assets/{dialog-8fiE6tec.js → dialog-BEK7KP0H.js} +1 -1
  66. package/dist/dashboard/assets/dialog-BEK7KP0H.js.gz +0 -0
  67. package/dist/dashboard/assets/{drawer-CqGYeOrd.js → drawer-BrTEZ8zu.js} +1 -1
  68. package/dist/dashboard/assets/drawer-BrTEZ8zu.js.gz +0 -0
  69. package/dist/dashboard/assets/entry-CHWxbS56.js +1 -0
  70. package/dist/dashboard/assets/entry-CHWxbS56.js.gz +0 -0
  71. package/dist/dashboard/assets/{entry-BSAsYsmV.js → entry-EBHJ3DrE.js} +1 -1
  72. package/dist/dashboard/assets/entry-EBHJ3DrE.js.gz +0 -0
  73. package/dist/dashboard/assets/entry-LCS85hiq.js +4 -0
  74. package/dist/dashboard/assets/entry-LCS85hiq.js.gz +0 -0
  75. package/dist/dashboard/assets/{formatters-D-MTJxMr.js → formatters-BAACA727.js} +1 -1
  76. package/dist/dashboard/assets/formatters-BAACA727.js.gz +0 -0
  77. package/dist/dashboard/assets/{github-badge-CPK47xQx.js → github-badge-YSCE4UC2.js} +1 -1
  78. package/dist/dashboard/assets/github-badge-YSCE4UC2.js.gz +0 -0
  79. package/dist/dashboard/assets/{index-DBNPOfhV.js → index-FQlj0HUT.js} +2 -2
  80. package/dist/dashboard/assets/index-FQlj0HUT.js.gz +0 -0
  81. package/dist/dashboard/assets/{inline-BT0zntEr.js → inline-C4gU5iOL.js} +1 -1
  82. package/dist/dashboard/assets/inline-C4gU5iOL.js.gz +0 -0
  83. package/dist/dashboard/assets/{input-Da2ZViWg.js → input-BHHX_Tmm.js} +1 -1
  84. package/dist/dashboard/assets/input-BHHX_Tmm.js.gz +0 -0
  85. package/dist/dashboard/assets/{layout-BXNeLw6M.js → layout-CajrYUnD.js} +1 -1
  86. package/dist/dashboard/assets/layout-CajrYUnD.js.gz +0 -0
  87. package/dist/dashboard/assets/{list-row-BycOrrIV.js → list-row-Bx2I7XUe.js} +1 -1
  88. package/dist/dashboard/assets/list-row-Bx2I7XUe.js.gz +0 -0
  89. package/dist/dashboard/assets/live-DNNqRbj2.js +1 -0
  90. package/dist/dashboard/assets/live-DNNqRbj2.js.gz +0 -0
  91. package/dist/dashboard/assets/network-C5UBACrJ.js +1 -0
  92. package/dist/dashboard/assets/network-C5UBACrJ.js.gz +0 -0
  93. package/dist/dashboard/assets/numbers-CUWAZK4J.js +2 -0
  94. package/dist/dashboard/assets/numbers-CUWAZK4J.js.gz +0 -0
  95. package/dist/dashboard/assets/pagination-Xsi9Qx04.js +1 -0
  96. package/dist/dashboard/assets/pagination-Xsi9Qx04.js.gz +0 -0
  97. package/dist/dashboard/assets/quota-DvQbD_sr.js +1 -0
  98. package/dist/dashboard/assets/quota-DvQbD_sr.js.gz +0 -0
  99. package/dist/dashboard/assets/routing-in0f_IfK.js +1 -0
  100. package/dist/dashboard/assets/routing-in0f_IfK.js.gz +0 -0
  101. package/dist/dashboard/assets/{select-BIYIBkMU.js → select-BLULNqTp.js} +1 -1
  102. package/dist/dashboard/assets/select-BLULNqTp.js.gz +0 -0
  103. package/dist/dashboard/assets/settings-CcGczj6I.js +1 -0
  104. package/dist/dashboard/assets/settings-CcGczj6I.js.gz +0 -0
  105. package/dist/dashboard/assets/shield-BMQNxORh.js +1 -0
  106. package/dist/dashboard/assets/shield-BMQNxORh.js.gz +0 -0
  107. package/dist/dashboard/assets/{stack-DfgnFDWY.js → stack-D2lIR0tg.js} +1 -1
  108. package/dist/dashboard/assets/stack-D2lIR0tg.js.gz +0 -0
  109. package/dist/dashboard/assets/{state-CkfdYWel.js → state-DTARjfiW.js} +1 -1
  110. package/dist/dashboard/assets/state-DTARjfiW.js.gz +0 -0
  111. package/dist/dashboard/assets/{switch-SYm237HG.js → switch-c0oPSnqW.js} +1 -1
  112. package/dist/dashboard/assets/switch-c0oPSnqW.js.gz +0 -0
  113. package/dist/dashboard/assets/{useMutation-BQqCRNIi.js → useMutation-m8WGNPrz.js} +1 -1
  114. package/dist/dashboard/assets/useMutation-m8WGNPrz.js.gz +0 -0
  115. package/dist/dashboard/console-backgrounds.jpg +0 -0
  116. package/dist/dashboard/console-backgrounds_initial.jpg +0 -0
  117. package/dist/dashboard/index.html +2 -2
  118. package/dist/dashboard/index.html.gz +0 -0
  119. package/dist/dashboard/precompressed-assets.json +56 -55
  120. package/migrations/full-postgres/0036_system_prompt_presets_refs.sql +10 -0
  121. package/migrations/full-postgres/0037_share_concurrency_scope.sql +3 -0
  122. package/migrations/full-postgres/0038_add_accounts_quota_snapshot.sql +7 -0
  123. package/migrations/full-postgres/0039_add_telemetry_provider_model_indexes.sql +13 -0
  124. package/migrations/full-postgres/0040_add_models_dialect.sql +3 -0
  125. package/migrations/full-postgres/0041_add_daily_checkin_ledger_account_fk.sql +7 -0
  126. package/migrations/lite-sqlite3/0036_system_prompt_presets_refs.sql +14 -0
  127. package/migrations/lite-sqlite3/0037_share_concurrency_scope.sql +3 -0
  128. package/migrations/lite-sqlite3/0038_add_accounts_quota_snapshot.sql +4 -0
  129. package/migrations/lite-sqlite3/0039_add_telemetry_provider_model_indexes.sql +6 -0
  130. package/migrations/lite-sqlite3/0040_add_models_dialect.sql +3 -0
  131. package/migrations/lite-sqlite3/0041_add_daily_checkin_ledger_account_fk.sql +26 -0
  132. package/package.json +4 -6
  133. package/scripts/cli/update.ts +15 -41
  134. package/src/boot/app.ts +58 -2
  135. package/src/boot/dependencies.ts +786 -732
  136. package/src/boot/lifecycle.ts +11 -12
  137. package/src/config/cooldowns.ts +34 -55
  138. package/src/config/network.ts +1 -1
  139. package/src/config/package-paths.ts +1 -1
  140. package/src/config/providers.ts +13 -14
  141. package/src/config/resources.ts +0 -5
  142. package/src/config/runtime.ts +2 -5
  143. package/src/config/spec.ts +26 -6
  144. package/src/console/api-keys/ban-constants.ts +38 -0
  145. package/src/console/api-keys/contracts.ts +71 -62
  146. package/src/console/api-keys/routes.ts +48 -12
  147. package/src/console/auth/access.ts +4 -4
  148. package/src/console/auth/account-reset.ts +1 -1
  149. package/src/console/auth/audit-recorder.ts +1 -1
  150. package/src/console/auth/lockout.ts +7 -3
  151. package/src/console/auth/row-coercion.ts +57 -12
  152. package/src/console/auth/session-resolver.ts +1 -1
  153. package/src/console/auth/session-service.ts +8 -2
  154. package/src/console/auth/session.ts +37 -31
  155. package/src/console/auth/setup-service.ts +4 -3
  156. package/src/console/auth/user-store.ts +1 -1
  157. package/src/console/backup/9router-map.ts +0 -3
  158. package/src/console/backup/contracts.ts +9 -9
  159. package/src/console/backup/export-endpoint.ts +5 -6
  160. package/src/console/backup/nine-router.ts +1 -7
  161. package/src/console/backup/routes.ts +29 -33
  162. package/src/console/backup/service.ts +468 -468
  163. package/src/console/backup/store.ts +47 -29
  164. package/src/console/backup/validate.ts +11 -1
  165. package/src/console/cli-tools/contracts.ts +7 -7
  166. package/src/console/cli-tools/injectors/cline.ts +110 -110
  167. package/src/console/cli-tools/injectors/codex.ts +181 -181
  168. package/src/console/cli-tools/injectors/copilot.ts +108 -108
  169. package/src/console/cli-tools/injectors/driver.ts +247 -247
  170. package/src/console/cli-tools/injectors/jcode.ts +115 -115
  171. package/src/console/cli-tools/injectors/openclaw.ts +161 -161
  172. package/src/console/cli-tools/injectors/opencode.ts +153 -153
  173. package/src/console/cli-tools/routes.ts +1 -1
  174. package/src/console/cli-tools/service.ts +1 -1
  175. package/src/console/cli-tools/store.ts +2 -2
  176. package/src/console/console-router.ts +32 -0
  177. package/src/console/dashboard-assets.ts +9 -9
  178. package/src/console/domain-registration.ts +16 -2
  179. package/src/console/inferhub/client.ts +0 -7
  180. package/src/console/inferhub/key-store.ts +1 -1
  181. package/src/console/inferhub/normalize.ts +2 -2
  182. package/src/console/inferhub/routes.ts +1 -1
  183. package/src/console/inferhub/types.ts +1 -1
  184. package/src/console/observability/contracts.ts +1 -1
  185. package/src/console/observability/live.ts +31 -18
  186. package/src/console/observability/logs.ts +1 -1
  187. package/src/console/observability/sse.ts +62 -8
  188. package/src/console/observability/store.ts +20 -4
  189. package/src/console/providers/catalog/catalog-projections.ts +1 -1
  190. package/src/console/providers/catalog/contracts.ts +39 -0
  191. package/src/console/providers/catalog/model-operations.ts +1 -1
  192. package/src/console/providers/catalog/provider-operations.ts +95 -17
  193. package/src/console/providers/catalog/public-model-store.ts +0 -0
  194. package/src/console/providers/catalog/routes.ts +27 -3
  195. package/src/console/providers/catalog/store.ts +147 -8
  196. package/src/console/providers/detail/routes.ts +1 -1
  197. package/src/console/providers/oauth/callback-listener.ts +100 -18
  198. package/src/console/providers/oauth/routes.ts +92 -13
  199. package/src/console/quota/account-quota-global.ts +41 -3
  200. package/src/console/quota/account-quota-shared.ts +10 -3
  201. package/src/console/quota/account-quota-tenant.ts +259 -66
  202. package/src/console/quota/daily-growth-job.ts +308 -0
  203. package/src/console/quota/native-identity.ts +2 -2
  204. package/src/console/quota/quota-view.ts +1 -1
  205. package/src/console/remote-support/routes.ts +1 -1
  206. package/src/console/remote-support/service.ts +2 -2
  207. package/src/console/routing/model/contracts.ts +1 -1
  208. package/src/console/routing/pools/contracts.ts +2 -2
  209. package/src/console/routing/pools/import-parse.ts +3 -3
  210. package/src/console/routing/pools/relay-deploy.ts +3 -3
  211. package/src/console/settings/contracts.ts +29 -2
  212. package/src/console/settings/store.ts +20 -0
  213. package/src/console/share/share-router.ts +100 -32
  214. package/src/console/share/share-stats.ts +4 -4
  215. package/src/console/share/share-usage.ts +1 -1
  216. package/src/console/shared/errors.ts +2 -2
  217. package/src/console/shared/object.ts +18 -0
  218. package/src/console/shared/read-through-cache.ts +4 -4
  219. package/src/console/shared/transaction.ts +14 -0
  220. package/src/console/system-prompt/contracts.ts +89 -12
  221. package/src/console/system-prompt/routes.ts +98 -45
  222. package/src/console/updates/apply-update.ts +244 -0
  223. package/src/console/updates/routes.ts +252 -97
  224. package/src/main.ts +11 -5
  225. package/src/network/http2-bidi.ts +1 -1
  226. package/src/network/ip-utils.ts +298 -0
  227. package/src/network/outbound-fetch.ts +1 -1
  228. package/src/network/pool/agent.ts +7 -6
  229. package/src/network/pool/byte-accounting.ts +1 -1
  230. package/src/network/pool/resolver.ts +16 -12
  231. package/src/network/pool/selector.ts +150 -136
  232. package/src/network/pool-health-machine.ts +1 -1
  233. package/src/network/rate-limit-verdict.ts +1 -1
  234. package/src/network/retry.ts +1 -1
  235. package/src/network/ssrf.ts +20 -71
  236. package/src/observability/event-log.ts +2 -2
  237. package/src/observability/event-query.ts +59 -291
  238. package/src/observability/log-sanitize.ts +1 -1
  239. package/src/observability/metrics.ts +4 -4
  240. package/src/observability/payload-capture.ts +6 -5
  241. package/src/observability/payload-store.ts +1 -1
  242. package/src/observability/runtime-metrics.ts +1 -1
  243. package/src/observability/telemetry-buffer.ts +12 -3
  244. package/src/observability/telemetry-reconciliation.ts +3 -3
  245. package/src/observability/token-speed.ts +1 -1
  246. package/src/persistence/connection-url.ts +1 -1
  247. package/src/persistence/db-handle.ts +1 -1
  248. package/src/persistence/db-pg.ts +2 -2
  249. package/src/persistence/db-sqlite.ts +3 -3
  250. package/src/persistence/dialect.ts +5 -1
  251. package/src/persistence/readiness.ts +1 -1
  252. package/src/persistence/redis.ts +1 -1
  253. package/src/persistence/schema.ts +113 -40
  254. package/src/persistence/shared-cache.ts +2 -2
  255. package/src/persistence/sort-order.ts +1 -1
  256. package/src/persistence/stores/api-key-store.ts +10 -1
  257. package/src/persistence/stores/share-store.ts +20 -8
  258. package/src/persistence/system-prompt-store.ts +63 -18
  259. package/src/persistence/tenant-preferences.ts +1 -1
  260. package/src/persistence/ttl-cache.ts +3 -3
  261. package/src/persistence/usage-flush.ts +7 -2
  262. package/src/protocol/canonical-model.ts +1 -1
  263. package/src/protocol/codecs.ts +6 -10
  264. package/src/protocol/dsml.ts +3 -49
  265. package/src/protocol/image-clamp.ts +2 -2
  266. package/src/protocol/reasoning-text.ts +1 -1
  267. package/src/protocol/reasoning.ts +7 -52
  268. package/src/protocol/registry.ts +50 -15
  269. package/src/protocol/request/chat.ts +46 -19
  270. package/src/protocol/request/codex.ts +1 -1
  271. package/src/protocol/request/messages.ts +46 -14
  272. package/src/protocol/request/responses.ts +19 -10
  273. package/src/protocol/response/chat.ts +25 -10
  274. package/src/protocol/response/codex.ts +1 -1
  275. package/src/protocol/response/messages.ts +1 -1
  276. package/src/protocol/response/omp-tool-call-markup.ts +1 -1
  277. package/src/protocol/response/responses.ts +1 -1
  278. package/src/protocol/sse-decoder.ts +50 -1
  279. package/src/protocol/stop-reason.ts +2 -2
  280. package/src/protocol/think-split.ts +347 -0
  281. package/src/protocol/translation/attachment-integrity.ts +3 -3
  282. package/src/protocol/translation/cache-controls.ts +8 -20
  283. package/src/protocol/translation/capabilities.ts +6 -6
  284. package/src/protocol/translation/dialect/deepseek.ts +10 -0
  285. package/src/protocol/translation/dialect/inband.ts +39 -0
  286. package/src/protocol/translation/dialect/model-thinking.ts +89 -0
  287. package/src/protocol/translation/dialect/qwen.ts +114 -0
  288. package/src/protocol/translation/dialect/resolver.ts +83 -0
  289. package/src/protocol/translation/dialect/rules.ts +93 -0
  290. package/src/protocol/translation/dialect/thinking-ladder.ts +245 -0
  291. package/src/protocol/translation/dialect/types.ts +58 -0
  292. package/src/protocol/translation/quirks.ts +18 -4
  293. package/src/protocol/translation/thinking.ts +12 -252
  294. package/src/protocol/translation/tool-id.ts +3 -3
  295. package/src/protocol/translation/tool-repair.ts +1 -1
  296. package/src/protocol/upstream/post-json.ts +6 -1
  297. package/src/providers/adapters/compatible-adapter.ts +42 -3
  298. package/src/providers/authentication/jwt-validator.ts +0 -5
  299. package/src/providers/authentication/oauth-client.ts +254 -253
  300. package/src/providers/authentication/oauth-flow-store.ts +42 -7
  301. package/src/providers/bundled-discovery-providers.ts +6 -30
  302. package/src/providers/configured-openai-providers.ts +82 -97
  303. package/src/providers/default-registry.ts +23 -35
  304. package/src/providers/discovery/catalog/catalog-format.ts +13 -2
  305. package/src/providers/discovery/discovery-types.ts +0 -1
  306. package/src/providers/discovery/openai-model-discovery.ts +2 -2
  307. package/src/providers/discovery/probe-phases.ts +48 -13
  308. package/src/providers/discovery/probing-service.ts +6 -8
  309. package/src/providers/integrations/agentrouter/agentrouter.ts +12 -2
  310. package/src/providers/integrations/antigravity/antigravity-oauth.ts +0 -1
  311. package/src/providers/integrations/antigravity/antigravity-protocol.ts +0 -14
  312. package/src/providers/integrations/antigravity/antigravity.ts +2 -2
  313. package/src/providers/integrations/buddy/buddy-catalog-shared.ts +1 -1
  314. package/src/providers/integrations/buddy/buddy-chat-shared.ts +20 -4
  315. package/src/providers/integrations/buddy/buddy-cli-headers.ts +19 -52
  316. package/src/providers/integrations/buddy/buddy-identity.ts +86 -0
  317. package/src/providers/integrations/buddy/buddy-oauth-shared.ts +1 -1
  318. package/src/providers/integrations/buddy/codebuddy/cn-provider.ts +1 -2
  319. package/src/providers/integrations/buddy/codebuddy/provider.ts +4 -15
  320. package/src/providers/integrations/buddy/codebuddy/shared.ts +30 -9
  321. package/src/providers/integrations/buddy/workbuddy/provider.ts +5 -9
  322. package/src/providers/integrations/buddy/workbuddy/shared.ts +21 -3
  323. package/src/providers/integrations/claude/claude-cch.ts +148 -148
  324. package/src/providers/integrations/claude/fallback-credit.ts +3 -7
  325. package/src/providers/integrations/cline/cline.ts +1 -1
  326. package/src/providers/integrations/codex/codex-device-code.ts +101 -101
  327. package/src/providers/integrations/codex/codex-oauth.ts +0 -1
  328. package/src/providers/integrations/commandcode/commandcode.ts +75 -115
  329. package/src/providers/integrations/commandcode/quota.ts +131 -51
  330. package/src/providers/integrations/cursor/cursor-http2.ts +0 -3
  331. package/src/providers/integrations/cursor/cursor-quota.ts +2 -6
  332. package/src/providers/integrations/cursor/cursor-request.ts +0 -87
  333. package/src/providers/integrations/cursor/cursor-shared.ts +0 -4
  334. package/src/providers/integrations/cursor/cursor.ts +38 -5
  335. package/src/providers/integrations/cursor/protocol/framing.ts +0 -56
  336. package/src/providers/integrations/cursor/protocol/messages.ts +0 -96
  337. package/src/providers/integrations/factory/factory.ts +9 -9
  338. package/src/providers/integrations/github/github-discovery.ts +55 -10
  339. package/src/providers/integrations/github/github-oauth.ts +6 -5
  340. package/src/providers/integrations/github/github.ts +41 -14
  341. package/src/providers/integrations/grok/grok-oauth.ts +261 -261
  342. package/src/providers/integrations/grok/grok-quota-frame.ts +1 -1
  343. package/src/providers/integrations/grok/grok-quota.ts +16 -7
  344. package/src/providers/integrations/grok/grok-ratelimit-store.ts +0 -5
  345. package/src/providers/integrations/grok/grok-ratelimit.ts +3 -0
  346. package/src/providers/integrations/grok/grok.ts +86 -36
  347. package/src/providers/integrations/kilo/kilo-oauth.ts +1 -1
  348. package/src/providers/integrations/kiro/kiro-cache.ts +31 -0
  349. package/src/providers/integrations/kiro/kiro-catalog.ts +31 -5
  350. package/src/providers/integrations/kiro/kiro-discovery.ts +47 -43
  351. package/src/providers/integrations/kiro/kiro-machine-id.ts +6 -3
  352. package/src/providers/integrations/kiro/kiro-oauth.ts +523 -255
  353. package/src/providers/integrations/kiro/kiro-quota.ts +35 -47
  354. package/src/providers/integrations/kiro/kiro-request.ts +8 -11
  355. package/src/providers/integrations/kiro/kiro-stream.ts +13 -0
  356. package/src/providers/integrations/kiro/kiro.ts +81 -68
  357. package/src/providers/integrations/muse/muse-oauth.ts +0 -1
  358. package/src/providers/integrations/muse/muse-quota.ts +0 -4
  359. package/src/providers/integrations/opencode/fingerprint.ts +7 -5
  360. package/src/providers/integrations/opencode/provider.ts +17 -24
  361. package/src/providers/integrations/qoder/qoder-catalog.ts +85 -8
  362. package/src/providers/integrations/qoder/qoder-oauth.ts +165 -25
  363. package/src/providers/integrations/qoder/qoder-quota.ts +48 -6
  364. package/src/providers/integrations/qoder/qoder-realm.ts +10 -31
  365. package/src/providers/integrations/qoder/qoder-sse.ts +159 -0
  366. package/src/providers/integrations/qoder/qoder-umid.ts +21 -25
  367. package/src/providers/integrations/qoder/qoder-virtual.ts +12 -0
  368. package/src/providers/integrations/qoder/qoder.ts +354 -62
  369. package/src/providers/integrations/shared/connect.ts +0 -54
  370. package/src/providers/integrations/shared/hash.ts +15 -0
  371. package/src/providers/integrations/shared/session-cache.ts +136 -0
  372. package/src/providers/integrations/trae/trae-cache.ts +7 -87
  373. package/src/providers/integrations/trae/trae-catalog.ts +1 -6
  374. package/src/providers/integrations/trae/trae-protocol.ts +17 -8
  375. package/src/providers/integrations/trae/trae-realm.ts +0 -7
  376. package/src/providers/integrations/trae/trae.ts +53 -10
  377. package/src/providers/integrations/xai/xai-oauth.ts +5 -5
  378. package/src/providers/integrations/zcode-start-plan/gifts.ts +265 -0
  379. package/src/providers/integrations/zcode-start-plan/oauth.ts +154 -0
  380. package/src/providers/integrations/zcode-start-plan/provider.ts +131 -0
  381. package/src/providers/integrations/zcode-start-plan/quota.ts +152 -0
  382. package/src/providers/integrations/zcode-start-plan/zcode_prompt.json +10 -0
  383. package/src/providers/operations/account-error-classification.ts +131 -116
  384. package/src/providers/operations/account-health-service.ts +31 -39
  385. package/src/providers/operations/account-reset-service.ts +58 -1
  386. package/src/providers/operations/cli-platform.ts +31 -5
  387. package/src/providers/operations/client-version-resolver.ts +4 -6
  388. package/src/providers/operations/client-versions.ts +10 -7
  389. package/src/providers/operations/provider-catalog-seeder.ts +2 -0
  390. package/src/providers/operations/provider-catalog-service.ts +18 -2
  391. package/src/providers/operations/provider-credential-service.ts +19 -2
  392. package/src/providers/provider-contracts.ts +18 -7
  393. package/src/providers/provider-metadata.ts +17 -2
  394. package/src/providers/provider-model-definition.ts +22 -1
  395. package/src/providers/provider-probe.ts +4 -2
  396. package/src/providers/provider-usage.ts +81 -16
  397. package/src/providers/quota/cache.ts +29 -0
  398. package/src/providers/quota/quota-contracts.ts +4 -0
  399. package/src/providers/quota/refresh.ts +27 -4
  400. package/src/providers/quota/snapshot.ts +94 -0
  401. package/src/providers/search/search-provider.ts +1 -3
  402. package/src/providers/search/search-providers.ts +2 -1
  403. package/src/security/abuse.ts +4 -4
  404. package/src/security/admission/service.ts +2 -2
  405. package/src/security/admission/ttl.ts +61 -61
  406. package/src/security/api-key-auth.ts +16 -4
  407. package/src/security/client-router-fingerprint.ts +4 -4
  408. package/src/security/credential-codec.ts +3 -3
  409. package/src/security/csrf.ts +2 -2
  410. package/src/security/ip-boundary.ts +16 -189
  411. package/src/security/model-access-rule.ts +1 -1
  412. package/src/security/outbound-headers.ts +18 -0
  413. package/src/shared/invoke-guard.ts +47 -0
  414. package/src/transport/contracts.ts +13 -4
  415. package/src/transport/dispatch/attempt-finalize.ts +1 -1
  416. package/src/transport/dispatch/capture-policy.ts +34 -37
  417. package/src/transport/dispatch/empty-stream.ts +23 -20
  418. package/src/transport/dispatch/generation.ts +25 -45
  419. package/src/transport/dispatch/native-shared.ts +127 -0
  420. package/src/transport/dispatch/proxy-request.ts +3 -1
  421. package/src/transport/dispatch/responses-compact.ts +25 -46
  422. package/src/transport/dispatch/streaming/encoder.ts +18 -72
  423. package/src/transport/dispatch/streaming/finalize.ts +2 -2
  424. package/src/transport/dispatch/streaming/stream.ts +7 -3
  425. package/src/transport/dispatch/streaming/thinking-loop.ts +1 -1
  426. package/src/transport/dispatch/systemone.ts +20 -48
  427. package/src/transport/dispatch/token-count.ts +41 -38
  428. package/src/transport/dispatch/websearch.ts +19 -45
  429. package/src/transport/drain-endpoint.ts +1 -1
  430. package/src/transport/failure-policy.ts +6 -0
  431. package/src/transport/guards/auth-guard.ts +0 -6
  432. package/src/transport/guards/body-policy.ts +3 -3
  433. package/src/transport/guards/headroom-guard.ts +1 -1
  434. package/src/transport/guards/pipeline.ts +1 -1
  435. package/src/transport/guards/request-context.ts +12 -17
  436. package/src/transport/request/preparer.ts +286 -7
  437. package/src/transport/request/rtk/compress-request.ts +3 -3
  438. package/src/transport/request/rtk/rtk-constants.ts +2 -2
  439. package/src/transport/request/rtk/rtk-filters.ts +8 -8
  440. package/src/transport/request/state.ts +1 -13
  441. package/src/transport/request/system-prompt-injection.ts +74 -11
  442. package/src/transport/request/tenant-preferences.ts +22 -0
  443. package/src/transport/routing/candidate-index.ts +2 -2
  444. package/src/transport/routing/round-robin.ts +1 -1
  445. package/src/transport/routing/route-catalog.ts +17 -18
  446. package/src/transport/routing/route-model.ts +126 -33
  447. package/src/transport/routing/router.ts +152 -37
  448. package/src/transport/shutdown-notice.ts +2 -2
  449. package/src/transport/surface/adapters.ts +3 -3
  450. package/src/transport/surface/chat/encode.ts +7 -7
  451. package/src/transport/surface/chat/parse.ts +7 -7
  452. package/src/transport/surface/completion.ts +2 -2
  453. package/src/transport/surface/content-parts.ts +1 -1
  454. package/src/transport/surface/dialects.ts +2 -2
  455. package/src/transport/surface/messages/parse.ts +3 -3
  456. package/src/transport/surface/responses/adapter.ts +1 -1
  457. package/src/transport/surface/responses/errors.ts +0 -9
  458. package/src/transport/vision-handoff-cache.ts +58 -0
  459. package/src/transport/vision-handoff.ts +376 -0
  460. package/src/workers/account-identity-sweep.ts +2 -2
  461. package/src/workers/buddy-growth-tasks.ts +392 -346
  462. package/src/workers/daily-checkin.ts +102 -49
  463. package/src/workers/maintenance-lease.ts +2 -35
  464. package/src/workers/oauth-refresh-sweep.ts +8 -1
  465. package/src/workers/quota-refresh-sweep.ts +120 -82
  466. package/src/workers/scheduler.ts +67 -4
  467. package/src/workers/sweep-runner.ts +24 -5
  468. package/src/workers/zcode-gift-claim.ts +108 -0
  469. package/dist/dashboard/assets/AccountCooldown-Bjo92Qat.js +0 -1
  470. package/dist/dashboard/assets/AccountCooldown-Bjo92Qat.js.gz +0 -0
  471. package/dist/dashboard/assets/BannedPage-ChG5svFb.js.gz +0 -0
  472. package/dist/dashboard/assets/CliToolDetailPage-BIcWQun7.js.gz +0 -0
  473. package/dist/dashboard/assets/CliToolsPage-Bf2VelDe.js.gz +0 -0
  474. package/dist/dashboard/assets/CombosPage-DCgm5g6g.js +0 -1
  475. package/dist/dashboard/assets/CombosPage-DCgm5g6g.js.gz +0 -0
  476. package/dist/dashboard/assets/ConsoleLogPage-a8mD0QF1.js +0 -1
  477. package/dist/dashboard/assets/ConsoleLogPage-a8mD0QF1.js.gz +0 -0
  478. package/dist/dashboard/assets/CustomizationPage-ggeMSjte.js.gz +0 -0
  479. package/dist/dashboard/assets/HealthEventsModal-DzSWzE_j.js +0 -1
  480. package/dist/dashboard/assets/HealthEventsModal-DzSWzE_j.js.gz +0 -0
  481. package/dist/dashboard/assets/LoginPage-U6AKaJcF.js.gz +0 -0
  482. package/dist/dashboard/assets/ModelPicker-BMS2t8BA.js.gz +0 -0
  483. package/dist/dashboard/assets/OverviewPage-D2D4IiHl.js +0 -1
  484. package/dist/dashboard/assets/OverviewPage-D2D4IiHl.js.gz +0 -0
  485. package/dist/dashboard/assets/ProviderDetailPage-CrNf7j_X.js +0 -5
  486. package/dist/dashboard/assets/ProviderDetailPage-CrNf7j_X.js.gz +0 -0
  487. package/dist/dashboard/assets/ProviderIcon-FB6yS4v1.js +0 -1
  488. package/dist/dashboard/assets/ProviderIcon-FB6yS4v1.js.gz +0 -0
  489. package/dist/dashboard/assets/ProvidersPage-BSDbquc1.js +0 -1
  490. package/dist/dashboard/assets/ProvidersPage-BSDbquc1.js.gz +0 -0
  491. package/dist/dashboard/assets/ProxyPage-lsrx7NYg.js.gz +0 -0
  492. package/dist/dashboard/assets/QuotaPage-L0skzML8.js +0 -1
  493. package/dist/dashboard/assets/QuotaPage-L0skzML8.js.gz +0 -0
  494. package/dist/dashboard/assets/SettingsPage-CmAbjRHW.js +0 -1
  495. package/dist/dashboard/assets/SettingsPage-CmAbjRHW.js.gz +0 -0
  496. package/dist/dashboard/assets/SetupPage-f0DE1h0-.js.gz +0 -0
  497. package/dist/dashboard/assets/SortableList-ClzpwyET.js +0 -1
  498. package/dist/dashboard/assets/SortableList-ClzpwyET.js.gz +0 -0
  499. package/dist/dashboard/assets/StudioPage-Cq5tW7hW.js.gz +0 -0
  500. package/dist/dashboard/assets/UsagePage-Dfc9rWQn.js +0 -56
  501. package/dist/dashboard/assets/UsagePage-Dfc9rWQn.js.gz +0 -0
  502. package/dist/dashboard/assets/api-keys-C38iXoO4.js +0 -1
  503. package/dist/dashboard/assets/api-keys-C38iXoO4.js.gz +0 -0
  504. package/dist/dashboard/assets/app-a159k0ub.css +0 -2
  505. package/dist/dashboard/assets/app-a159k0ub.css.gz +0 -0
  506. package/dist/dashboard/assets/assert-DbRA8EG2.js +0 -15
  507. package/dist/dashboard/assets/assert-DbRA8EG2.js.gz +0 -0
  508. package/dist/dashboard/assets/badge-D9CS6dZk.js.gz +0 -0
  509. package/dist/dashboard/assets/banner-DympBNq4.js.gz +0 -0
  510. package/dist/dashboard/assets/card-ibRWU_uT.js.gz +0 -0
  511. package/dist/dashboard/assets/cli-tools-63qBGaRw.js +0 -1
  512. package/dist/dashboard/assets/cli-tools-63qBGaRw.js.gz +0 -0
  513. package/dist/dashboard/assets/clipboard-button-DJm-9pz7.js.gz +0 -0
  514. package/dist/dashboard/assets/dialog-8fiE6tec.js.gz +0 -0
  515. package/dist/dashboard/assets/drawer-CqGYeOrd.js.gz +0 -0
  516. package/dist/dashboard/assets/entry-BSAsYsmV.js.gz +0 -0
  517. package/dist/dashboard/assets/entry-CiIQULZD.js +0 -4
  518. package/dist/dashboard/assets/entry-CiIQULZD.js.gz +0 -0
  519. package/dist/dashboard/assets/entry-Daz0lJ-W.js +0 -1
  520. package/dist/dashboard/assets/entry-Daz0lJ-W.js.gz +0 -0
  521. package/dist/dashboard/assets/formatters-D-MTJxMr.js.gz +0 -0
  522. package/dist/dashboard/assets/github-badge-CPK47xQx.js.gz +0 -0
  523. package/dist/dashboard/assets/index-DBNPOfhV.js.gz +0 -0
  524. package/dist/dashboard/assets/inline-BT0zntEr.js.gz +0 -0
  525. package/dist/dashboard/assets/input-Da2ZViWg.js.gz +0 -0
  526. package/dist/dashboard/assets/layout-BXNeLw6M.js.gz +0 -0
  527. package/dist/dashboard/assets/list-row-BycOrrIV.js.gz +0 -0
  528. package/dist/dashboard/assets/live-DCQNZpF7.js +0 -1
  529. package/dist/dashboard/assets/live-DCQNZpF7.js.gz +0 -0
  530. package/dist/dashboard/assets/network-9Yj2ZyLo.js +0 -1
  531. package/dist/dashboard/assets/network-9Yj2ZyLo.js.gz +0 -0
  532. package/dist/dashboard/assets/numbers-CEagj6ZZ.js +0 -2
  533. package/dist/dashboard/assets/numbers-CEagj6ZZ.js.gz +0 -0
  534. package/dist/dashboard/assets/quota-Caw7wqci.js +0 -1
  535. package/dist/dashboard/assets/quota-Caw7wqci.js.gz +0 -0
  536. package/dist/dashboard/assets/routing-CO9zCUus.js +0 -1
  537. package/dist/dashboard/assets/routing-CO9zCUus.js.gz +0 -0
  538. package/dist/dashboard/assets/select-BIYIBkMU.js.gz +0 -0
  539. package/dist/dashboard/assets/settings-jS3-PNSA.js +0 -1
  540. package/dist/dashboard/assets/settings-jS3-PNSA.js.gz +0 -0
  541. package/dist/dashboard/assets/stack-DfgnFDWY.js.gz +0 -0
  542. package/dist/dashboard/assets/state-CkfdYWel.js.gz +0 -0
  543. package/dist/dashboard/assets/stream-retry-5QnVuSSo.js +0 -1
  544. package/dist/dashboard/assets/stream-retry-5QnVuSSo.js.gz +0 -0
  545. package/dist/dashboard/assets/switch-SYm237HG.js.gz +0 -0
  546. package/dist/dashboard/assets/useMutation-BQqCRNIi.js.gz +0 -0
  547. package/src/network/response-headers.ts +0 -39
  548. package/src/protocol/response/dsml.ts +0 -38
  549. package/src/providers/integrations/xiaomi-mimo/think-stream.ts +0 -229
  550. /package/dist/dashboard/assets/{app-BayTTy01.js → app-Bgd3zANQ.js} +0 -0
  551. /package/dist/dashboard/assets/{app-BayTTy01.js.gz → app-Bgd3zANQ.js.gz} +0 -0
  552. /package/dist/dashboard/assets/brand/{og_bansos.webp → og_bansos_initial.webp} +0 -0
  553. /package/dist/dashboard/assets/brand/{og_image.webp → og_image_initial.webp} +0 -0
@@ -1,253 +1,254 @@
1
- /**
2
- * Generic OAuth 2.0 base class for provider-specific OAuth clients.
3
- *
4
- * Encapsulates common PKCE, device-code, token-exchange and refresh logic
5
- * while exposing protected hooks for provider-specific customizations.
6
- */
7
- import {
8
- buildPkceAuthorizeUrl as buildPkceAuthorizeUrlShared,
9
- nonEmptyString,
10
- postFormTokenRequest,
11
- record,
12
- } from "./oauth-flow-store";
13
- import type {
14
- OAuthAuthorizeRequest,
15
- OAuthCodeExchangeContext,
16
- OAuthExchangeResult,
17
- OAuthLoginClient,
18
- } from "./oauth-flow-store";
19
- import type { OAuthTokenRefreshResult, OAuthTokenRefresher } from "./oauth-refresh-service";
20
-
21
- /** Minimal fetch surface accepted by the generic OAuth client. */
22
- export type FetchLike = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;
23
-
24
- /** Normalized token shape returned by provider token endpoints. */
25
- interface NormalizedTokenResponse {
26
- readonly access: string;
27
- readonly refresh: string;
28
- readonly expiresAt: Date;
29
- readonly accountLabel?: string | undefined;
30
- /**
31
- * Identity the flow learned beside the tokens — an upstream user id the
32
- * token itself does not carry. Threaded through both converters so a
33
- * provider that resolves it during login does not lose it on the way to
34
- * storage, and can refresh it later without a second round trip.
35
- */
36
- readonly auth_state?: Readonly<Record<string, unknown>> | undefined;
37
- }
38
-
39
- /** Options for building a PKCE authorize URL. */
40
- interface PkceAuthorizeOptions {
41
- readonly clientId: string;
42
- readonly authorizeUrl: string;
43
- readonly redirectUri: string;
44
- readonly scope: string;
45
- readonly state: string;
46
- readonly codeChallenge: string;
47
- readonly extra?: Record<string, string> | undefined;
48
- }
49
-
50
- /** Options for a form-encoded token exchange or refresh. */
51
- interface FormTokenOptions {
52
- readonly url: string;
53
- readonly params: Record<string, string>;
54
- readonly headers?: Record<string, string>;
55
- readonly signal?: AbortSignal;
56
- readonly label: string;
57
- }
58
-
59
-
60
- /** Base class for provider OAuth clients. */
61
- export abstract class OAuthClient implements OAuthLoginClient, OAuthTokenRefresher {
62
- /** Provider display label used in error messages. */
63
- protected abstract readonly providerLabel: string;
64
- /** OAuth client id. */
65
- protected abstract readonly clientId: string;
66
- /** Token endpoint URL. */
67
- protected abstract readonly tokenUrl: string;
68
- /** Authorization endpoint URL (omit for device-only providers). */
69
- protected readonly authorizeUrl?: string;
70
- /** Space-separated OAuth scopes. */
71
- protected abstract readonly scopes: string;
72
-
73
- /** Whether the provider supports the device-code flow. */
74
- abstract readonly supportsDeviceCode: boolean;
75
- /** Whether the provider supports browser PKCE authorization. */
76
- abstract readonly supportsBrowserCode: boolean;
77
- /**
78
- * Loopback/native redirect URI this client's authorization server
79
- * allowlists, when it differs from the gateway-wide default. Declared here so
80
- * a client can state it without the console route reaching into provider
81
- * specifics; see `OAuthLoginClient.browserRedirectUri`.
82
- */
83
- readonly browserRedirectUri?: string;
84
-
85
- protected readonly fetchFn: FetchLike;
86
-
87
- constructor(fetchFn: FetchLike = globalThis.fetch) {
88
- this.fetchFn = fetchFn;
89
- }
90
-
91
- // ---------------------------------------------------------------------------
92
- // Public OAuthLoginClient surface
93
- // ---------------------------------------------------------------------------
94
-
95
- buildAuthorizeUrl(request: OAuthAuthorizeRequest): string {
96
- if (!this.authorizeUrl) {
97
- throw new Error(`${this.providerLabel} does not support browser authorization`);
98
- }
99
- return this.buildPkceAuthorizeUrl({
100
- clientId: this.clientId,
101
- authorizeUrl: this.authorizeUrl,
102
- redirectUri: request.redirectUri,
103
- scope: this.scopes,
104
- state: request.state,
105
- codeChallenge: request.codeChallenge,
106
- extra: this.extraAuthorizeParams(),
107
- });
108
- }
109
-
110
- async exchangeCode(
111
- code: string,
112
- codeVerifier: string,
113
- redirectUri: string,
114
- _state?: string,
115
- _context?: OAuthCodeExchangeContext,
116
- ): Promise<OAuthExchangeResult> {
117
- if (!this.supportsBrowserCode) {
118
- throw new Error(`${this.providerLabel} does not support browser code exchange`);
119
- }
120
- return this.exchangeCodeVia(code, codeVerifier, redirectUri);
121
- }
122
-
123
- refresh(_refreshToken: string, _signal?: AbortSignal): Promise<OAuthTokenRefreshResult> {
124
- throw new Error(`${this.providerLabel} does not support token refresh`);
125
- }
126
-
127
- // ---------------------------------------------------------------------------
128
- // Protected hooks
129
- // ---------------------------------------------------------------------------
130
-
131
- /** Extra query parameters appended to the PKCE authorize URL. */
132
- protected extraAuthorizeParams(): Record<string, string> | undefined {
133
- return undefined;
134
- }
135
-
136
- /** Extracts an account label from a token exchange/refresh response. */
137
- protected extractAccountLabel(_data: unknown): string | undefined {
138
- return undefined;
139
- }
140
-
141
- /** Calculates an expiry Date from an `expires_in` value. */
142
- protected calculateExpiry(expiresIn: unknown, fallbackSeconds = 3600): Date {
143
- const seconds =
144
- typeof expiresIn === "number" && Number.isFinite(expiresIn) && expiresIn >= 0
145
- ? expiresIn
146
- : fallbackSeconds;
147
- return new Date(Date.now() + Math.max(0, seconds) * 1000);
148
- }
149
-
150
- /**
151
- * Parses a standard token response object into a normalized result.
152
- *
153
- * Fails when the response carries no `access_token`. Returning an empty
154
- * access value instead let a poll report `complete` with an unusable
155
- * credential: the account was persisted and the browser saw success, while
156
- * the gateway then dispatched with an empty bearer. A token endpoint that
157
- * answers 2xx without a token is a failure, whatever the status code says —
158
- * an `error` field in a 200 body is exactly that case. An empty refresh
159
- * token is still allowed, because several providers legitimately issue an
160
- * access-only credential.
161
- */
162
- protected parseTokenResponse(data: unknown, fallbackRefresh?: string): NormalizedTokenResponse {
163
- const body = record(data) ?? {};
164
- const access = nonEmptyString(body.access_token);
165
- if (access === undefined) {
166
- const detail = nonEmptyString(body.error_description) ?? nonEmptyString(body.error);
167
- throw new Error(
168
- `${this.providerLabel} token response omitted access_token${detail === undefined ? "" : `: ${detail}`}`,
169
- );
170
- }
171
- const refresh = nonEmptyString(body.refresh_token) ?? fallbackRefresh ?? "";
172
- const expiresAt = this.calculateExpiry(body.expires_in);
173
- const accountLabel = this.extractAccountLabel(data);
174
- return { access, refresh, expiresAt, ...(accountLabel ? { accountLabel } : {}) };
175
- }
176
-
177
- /** Builds a PKCE authorization URL using the shared helper. */
178
- protected buildPkceAuthorizeUrl(options: PkceAuthorizeOptions): string {
179
- return buildPkceAuthorizeUrlShared({
180
- clientId: options.clientId,
181
- authorizeUrl: options.authorizeUrl,
182
- redirectUri: options.redirectUri,
183
- scope: options.scope,
184
- state: options.state,
185
- codeChallenge: options.codeChallenge,
186
- ...(options.extra === undefined ? {} : { extra: options.extra }),
187
- });
188
- }
189
-
190
- // ---------------------------------------------------------------------------
191
- // Shared token request helpers
192
- // ---------------------------------------------------------------------------
193
-
194
- protected async postFormToken(options: FormTokenOptions): Promise<unknown> {
195
- return postFormTokenRequest({
196
- url: options.url,
197
- fetchFn: this.fetchFn,
198
- params: options.params,
199
- ...(options.headers === undefined ? {} : { headers: options.headers }),
200
- ...(options.signal === undefined ? {} : { signal: options.signal }),
201
- label: options.label,
202
- });
203
- }
204
-
205
- /** Exchanges a browser authorization code using an explicit callback redirect. */
206
- protected async exchangeCodeVia(
207
- code: string,
208
- codeVerifier: string,
209
- redirectUri: string,
210
- extraParams: Record<string, string> = {},
211
- ): Promise<OAuthExchangeResult> {
212
- const response = await this.postFormToken({
213
- url: this.tokenUrl,
214
- params: {
215
- client_id: this.clientId,
216
- grant_type: "authorization_code",
217
- code,
218
- redirect_uri: redirectUri,
219
- code_verifier: codeVerifier,
220
- ...extraParams,
221
- },
222
- label: `${this.providerLabel} token exchange`,
223
- });
224
- return this.toExchangeResult(this.parseTokenResponse(response));
225
- }
226
-
227
-
228
- // ---------------------------------------------------------------------------
229
- // Converters
230
- // ---------------------------------------------------------------------------
231
-
232
- protected toExchangeResult(normalized: NormalizedTokenResponse): OAuthExchangeResult {
233
- const { access, refresh, expiresAt, accountLabel, auth_state } = normalized;
234
- return {
235
- access,
236
- refresh,
237
- expiresAt,
238
- ...(accountLabel ? { accountLabel } : {}),
239
- ...(auth_state === undefined ? {} : { auth_state }),
240
- };
241
- }
242
-
243
- protected toRefreshResult(normalized: NormalizedTokenResponse): OAuthTokenRefreshResult {
244
- const { access, refresh, expiresAt, accountLabel, auth_state } = normalized;
245
- return {
246
- access,
247
- ...(refresh ? { refresh } : {}),
248
- expiresAt,
249
- ...(accountLabel ? { accountLabel } : {}),
250
- ...(auth_state === undefined ? {} : { auth_state }),
251
- };
252
- }
253
- }
1
+ /**
2
+ * Generic OAuth 2.0 base class for provider-specific OAuth clients.
3
+ *
4
+ * Encapsulates common PKCE, device-code, token-exchange and refresh logic
5
+ * while exposing protected hooks for provider-specific customizations.
6
+ */
7
+ import {
8
+ buildPkceAuthorizeUrl as buildPkceAuthorizeUrlShared,
9
+ expiryFromSeconds,
10
+ nonEmptyString,
11
+ postFormTokenRequest,
12
+ record,
13
+ } from "./oauth-flow-store";
14
+ import type {
15
+ OAuthAuthorizeRequest,
16
+ OAuthCodeExchangeContext,
17
+ OAuthExchangeResult,
18
+ OAuthLoginClient,
19
+ } from "./oauth-flow-store";
20
+ import type { OAuthTokenRefreshResult, OAuthTokenRefresher } from "./oauth-refresh-service";
21
+
22
+ /** Minimal fetch surface accepted by the generic OAuth client. */
23
+ export type FetchLike = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;
24
+
25
+ /** Normalized token shape returned by provider token endpoints. */
26
+ interface NormalizedTokenResponse {
27
+ readonly access: string;
28
+ readonly refresh: string;
29
+ readonly expiresAt: Date;
30
+ readonly accountLabel?: string | undefined;
31
+ /**
32
+ * Identity the flow learned beside the tokens — an upstream user id the
33
+ * token itself does not carry. Threaded through both converters so a
34
+ * provider that resolves it during login does not lose it on the way to
35
+ * storage, and can refresh it later without a second round trip.
36
+ */
37
+ readonly auth_state?: Readonly<Record<string, unknown>> | undefined;
38
+ }
39
+
40
+ /** Options for building a PKCE authorize URL. */
41
+ interface PkceAuthorizeOptions {
42
+ readonly clientId: string;
43
+ readonly authorizeUrl: string;
44
+ readonly redirectUri: string;
45
+ readonly scope: string;
46
+ readonly state: string;
47
+ readonly codeChallenge: string;
48
+ readonly extra?: Record<string, string> | undefined;
49
+ }
50
+
51
+ /** Options for a form-encoded token exchange or refresh. */
52
+ interface FormTokenOptions {
53
+ readonly url: string;
54
+ readonly params: Record<string, string>;
55
+ readonly headers?: Record<string, string>;
56
+ readonly signal?: AbortSignal;
57
+ readonly label: string;
58
+ }
59
+
60
+
61
+ /** Base class for provider OAuth clients. */
62
+ export abstract class OAuthClient implements OAuthLoginClient, OAuthTokenRefresher {
63
+ /** Provider display label used in error messages. */
64
+ protected abstract readonly providerLabel: string;
65
+ /** OAuth client id. */
66
+ protected abstract readonly clientId: string;
67
+ /** Token endpoint URL. */
68
+ protected abstract readonly tokenUrl: string;
69
+ /** Authorization endpoint URL (omit for device-only providers). */
70
+ protected readonly authorizeUrl?: string;
71
+ /** Space-separated OAuth scopes. */
72
+ protected abstract readonly scopes: string;
73
+
74
+ /** Whether the provider supports the device-code flow. */
75
+ abstract readonly supportsDeviceCode: boolean;
76
+ /** Whether the provider supports browser PKCE authorization. */
77
+ abstract readonly supportsBrowserCode: boolean;
78
+ /**
79
+ * Loopback/native redirect URI this client's authorization server
80
+ * allowlists, when it differs from the gateway-wide default. Declared here so
81
+ * a client can state it without the console route reaching into provider
82
+ * specifics; see `OAuthLoginClient.browserRedirectUri`.
83
+ */
84
+ readonly browserRedirectUri?: string;
85
+
86
+ protected readonly fetchFn: FetchLike;
87
+
88
+ constructor(fetchFn: FetchLike = globalThis.fetch) {
89
+ this.fetchFn = fetchFn;
90
+ }
91
+
92
+ // ---------------------------------------------------------------------------
93
+ // Public OAuthLoginClient surface
94
+ // ---------------------------------------------------------------------------
95
+
96
+ buildAuthorizeUrl(request: OAuthAuthorizeRequest): string {
97
+ if (!this.authorizeUrl) {
98
+ throw new Error(`${this.providerLabel} does not support browser authorization`);
99
+ }
100
+ return this.buildPkceAuthorizeUrl({
101
+ clientId: this.clientId,
102
+ authorizeUrl: this.authorizeUrl,
103
+ redirectUri: request.redirectUri,
104
+ scope: this.scopes,
105
+ state: request.state,
106
+ codeChallenge: request.codeChallenge,
107
+ extra: this.extraAuthorizeParams(),
108
+ });
109
+ }
110
+
111
+ async exchangeCode(
112
+ code: string,
113
+ codeVerifier: string,
114
+ redirectUri: string,
115
+ _state?: string,
116
+ _context?: OAuthCodeExchangeContext,
117
+ ): Promise<OAuthExchangeResult> {
118
+ if (!this.supportsBrowserCode) {
119
+ throw new Error(`${this.providerLabel} does not support browser code exchange`);
120
+ }
121
+ return this.exchangeCodeVia(code, codeVerifier, redirectUri);
122
+ }
123
+
124
+ refresh(_refreshToken: string, _signal?: AbortSignal): Promise<OAuthTokenRefreshResult> {
125
+ throw new Error(`${this.providerLabel} does not support token refresh`);
126
+ }
127
+
128
+ // ---------------------------------------------------------------------------
129
+ // Protected hooks
130
+ // ---------------------------------------------------------------------------
131
+
132
+ /** Extra query parameters appended to the PKCE authorize URL. */
133
+ protected extraAuthorizeParams(): Record<string, string> | undefined {
134
+ return undefined;
135
+ }
136
+
137
+ /** Extracts an account label from a token exchange/refresh response. */
138
+ protected extractAccountLabel(_data: unknown): string | undefined {
139
+ return undefined;
140
+ }
141
+
142
+ /** Calculates an expiry Date from an `expires_in` value. */
143
+ protected calculateExpiry(expiresIn: unknown, fallbackSeconds = 3600): Date {
144
+ const seconds =
145
+ typeof expiresIn === "number" && Number.isFinite(expiresIn) && expiresIn >= 0
146
+ ? expiresIn
147
+ : fallbackSeconds;
148
+ return expiryFromSeconds(seconds);
149
+ }
150
+
151
+ /**
152
+ * Parses a standard token response object into a normalized result.
153
+ *
154
+ * Fails when the response carries no `access_token`. Returning an empty
155
+ * access value instead let a poll report `complete` with an unusable
156
+ * credential: the account was persisted and the browser saw success, while
157
+ * the gateway then dispatched with an empty bearer. A token endpoint that
158
+ * answers 2xx without a token is a failure, whatever the status code says —
159
+ * an `error` field in a 200 body is exactly that case. An empty refresh
160
+ * token is still allowed, because several providers legitimately issue an
161
+ * access-only credential.
162
+ */
163
+ protected parseTokenResponse(data: unknown, fallbackRefresh?: string): NormalizedTokenResponse {
164
+ const body = record(data) ?? {};
165
+ const access = nonEmptyString(body.access_token);
166
+ if (access === undefined) {
167
+ const detail = nonEmptyString(body.error_description) ?? nonEmptyString(body.error);
168
+ throw new Error(
169
+ `${this.providerLabel} token response omitted access_token${detail === undefined ? "" : `: ${detail}`}`,
170
+ );
171
+ }
172
+ const refresh = nonEmptyString(body.refresh_token) ?? fallbackRefresh ?? "";
173
+ const expiresAt = this.calculateExpiry(body.expires_in);
174
+ const accountLabel = this.extractAccountLabel(data);
175
+ return { access, refresh, expiresAt, ...(accountLabel ? { accountLabel } : {}) };
176
+ }
177
+
178
+ /** Builds a PKCE authorization URL using the shared helper. */
179
+ protected buildPkceAuthorizeUrl(options: PkceAuthorizeOptions): string {
180
+ return buildPkceAuthorizeUrlShared({
181
+ clientId: options.clientId,
182
+ authorizeUrl: options.authorizeUrl,
183
+ redirectUri: options.redirectUri,
184
+ scope: options.scope,
185
+ state: options.state,
186
+ codeChallenge: options.codeChallenge,
187
+ ...(options.extra === undefined ? {} : { extra: options.extra }),
188
+ });
189
+ }
190
+
191
+ // ---------------------------------------------------------------------------
192
+ // Shared token request helpers
193
+ // ---------------------------------------------------------------------------
194
+
195
+ protected async postFormToken(options: FormTokenOptions): Promise<unknown> {
196
+ return postFormTokenRequest({
197
+ url: options.url,
198
+ fetchFn: this.fetchFn,
199
+ params: options.params,
200
+ ...(options.headers === undefined ? {} : { headers: options.headers }),
201
+ ...(options.signal === undefined ? {} : { signal: options.signal }),
202
+ label: options.label,
203
+ });
204
+ }
205
+
206
+ /** Exchanges a browser authorization code using an explicit callback redirect. */
207
+ protected async exchangeCodeVia(
208
+ code: string,
209
+ codeVerifier: string,
210
+ redirectUri: string,
211
+ extraParams: Record<string, string> = {},
212
+ ): Promise<OAuthExchangeResult> {
213
+ const response = await this.postFormToken({
214
+ url: this.tokenUrl,
215
+ params: {
216
+ client_id: this.clientId,
217
+ grant_type: "authorization_code",
218
+ code,
219
+ redirect_uri: redirectUri,
220
+ code_verifier: codeVerifier,
221
+ ...extraParams,
222
+ },
223
+ label: `${this.providerLabel} token exchange`,
224
+ });
225
+ return this.toExchangeResult(this.parseTokenResponse(response));
226
+ }
227
+
228
+
229
+ // ---------------------------------------------------------------------------
230
+ // Converters
231
+ // ---------------------------------------------------------------------------
232
+
233
+ protected toExchangeResult(normalized: NormalizedTokenResponse): OAuthExchangeResult {
234
+ const { access, refresh, expiresAt, accountLabel, auth_state } = normalized;
235
+ return {
236
+ access,
237
+ refresh,
238
+ expiresAt,
239
+ ...(accountLabel ? { accountLabel } : {}),
240
+ ...(auth_state === undefined ? {} : { auth_state }),
241
+ };
242
+ }
243
+
244
+ protected toRefreshResult(normalized: NormalizedTokenResponse): OAuthTokenRefreshResult {
245
+ const { access, refresh, expiresAt, accountLabel, auth_state } = normalized;
246
+ return {
247
+ access,
248
+ ...(refresh ? { refresh } : {}),
249
+ expiresAt,
250
+ ...(accountLabel ? { accountLabel } : {}),
251
+ ...(auth_state === undefined ? {} : { auth_state }),
252
+ };
253
+ }
254
+ }
@@ -25,6 +25,8 @@ export interface OAuthAuthorizeRequest {
25
25
  export interface OAuthCodeExchangeContext {
26
26
  readonly state?: string;
27
27
  readonly parameters?: Readonly<Record<string, string>>;
28
+ /** Server-side provider continuation state for a multi-step browser login. */
29
+ readonly providerState?: string;
28
30
  }
29
31
 
30
32
  export interface OAuthExchangeResult {
@@ -197,6 +199,8 @@ const DEFAULT_DEVICE_EXPIRY_SECONDS = 900;
197
199
  * so each caller keeps its own error text. Missing or non-positive
198
200
  * `interval`/`expires_in` fall back to the caller's defaults (or the shared
199
201
  * ones); present values are floored at one second.
202
+ * Both wire shapes are accepted: the RFC snake_case (`device_code`) and the
203
+ * AWS SSO OIDC camelCase (`deviceCode`), which Kiro's OIDC device flow speaks.
200
204
  */
201
205
  export function parseDeviceAuthStart(
202
206
  payload: unknown,
@@ -204,10 +208,17 @@ export function parseDeviceAuthStart(
204
208
  ): DeviceAuthStart | undefined {
205
209
  const root = record(payload);
206
210
  if (!root) return undefined;
207
- const deviceCode = nonEmptyTrimmedString(root.device_code);
208
- const userCode = nonEmptyTrimmedString(root.user_code);
209
- const complete = nonEmptyTrimmedString(root.verification_uri_complete);
210
- const verificationUri = nonEmptyTrimmedString(root.verification_uri) ?? complete;
211
+ const deviceCode =
212
+ nonEmptyTrimmedString(root.device_code) ?? nonEmptyTrimmedString(root.deviceCode);
213
+ const userCode =
214
+ nonEmptyTrimmedString(root.user_code) ?? nonEmptyTrimmedString(root.userCode);
215
+ const complete =
216
+ nonEmptyTrimmedString(root.verification_uri_complete) ??
217
+ nonEmptyTrimmedString(root.verificationUriComplete);
218
+ const verificationUri =
219
+ nonEmptyTrimmedString(root.verification_uri) ??
220
+ nonEmptyTrimmedString(root.verificationUri) ??
221
+ complete;
211
222
  if (!deviceCode || !userCode || !verificationUri) return undefined;
212
223
  return {
213
224
  deviceCode,
@@ -219,7 +230,7 @@ export function parseDeviceAuthStart(
219
230
  defaults?.intervalSeconds ?? DEFAULT_DEVICE_INTERVAL_SECONDS,
220
231
  ),
221
232
  expiresInSeconds: positiveSeconds(
222
- root.expires_in,
233
+ root.expires_in ?? root.expiresIn,
223
234
  defaults?.expiresInSeconds ?? DEFAULT_DEVICE_EXPIRY_SECONDS,
224
235
  ),
225
236
  };
@@ -236,12 +247,12 @@ function positiveSeconds(value: unknown, fallbackSeconds: number): number {
236
247
  * True when a device-token poll error means "keep polling": the user has not
237
248
  * approved yet, or the client is polling faster than the server allows.
238
249
  */
239
- export function isDevicePollPending(error: string | undefined): boolean {
250
+ function isDevicePollPending(error: string | undefined): boolean {
240
251
  return error === "authorization_pending";
241
252
  }
242
253
 
243
254
  /** RFC 8628 `slow_down`: the client must widen its polling interval. */
244
- export function isDevicePollSlowDown(error: string | undefined): boolean {
255
+ function isDevicePollSlowDown(error: string | undefined): boolean {
245
256
  return error === "slow_down";
246
257
  }
247
258
 
@@ -498,6 +509,8 @@ export interface OAuthFlowStorage {
498
509
  savePending(state: string, flow: PendingOAuthFlow): Promise<void>;
499
510
  consumePendingByProvider(providerId: string): Promise<PendingOAuthFlow | undefined>;
500
511
  consumePending(state: string): Promise<PendingOAuthFlow | undefined>;
512
+ /** Reads a pending flow without consuming it (for a retry-safe callback path). */
513
+ peekPending(state: string): Promise<PendingOAuthFlow | undefined>;
501
514
  saveDevice(deviceAuthId: string, correlation: DeviceFlowCorrelation): Promise<void>;
502
515
  getDevice(deviceAuthId: string): Promise<DeviceFlowCorrelation | undefined>;
503
516
  deleteDevice(deviceAuthId: string): Promise<void>;
@@ -588,6 +601,17 @@ export class OAuthFlowStore implements OAuthFlowStorage {
588
601
  }
589
602
  }
590
603
 
604
+ /** Reads a pending flow without consuming it — used to replay a callback. */
605
+ async peekPending(state: string): Promise<PendingOAuthFlow | undefined> {
606
+ const raw = await this.#redis.get(PENDING_PREFIX + state);
607
+ if (!raw) return undefined;
608
+ try {
609
+ return JSON.parse(raw) as PendingOAuthFlow;
610
+ } catch {
611
+ return undefined;
612
+ }
613
+ }
614
+
591
615
  // ---------------------------------------------------------- Device correlation
592
616
 
593
617
  async saveDevice(deviceAuthId: string, correlation: DeviceFlowCorrelation): Promise<void> {
@@ -691,6 +715,17 @@ export class InMemoryOAuthFlowStore implements OAuthFlowStorage {
691
715
  }
692
716
  }
693
717
 
718
+ /** Reads a pending flow without consuming it — used to replay a callback. */
719
+ async peekPending(state: string): Promise<PendingOAuthFlow | undefined> {
720
+ const raw = this.pending.get(PENDING_PREFIX + state);
721
+ if (!raw) return undefined;
722
+ try {
723
+ return JSON.parse(raw) as PendingOAuthFlow;
724
+ } catch {
725
+ return undefined;
726
+ }
727
+ }
728
+
694
729
  async saveDevice(deviceAuthId: string, correlation: DeviceFlowCorrelation): Promise<void> {
695
730
  this.devices.set(DEVICE_PREFIX + deviceAuthId, JSON.stringify(correlation));
696
731
  }