cartethyia 2.7.3 → 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 (625) hide show
  1. package/.env.example +2 -0
  2. package/README.md +17 -5
  3. package/dist/dashboard/assets/{BannedPage-2TJD37Hb.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-xefJNRmJ.js → CliToolDetailPage-DZKmVuJN.js} +1 -1
  8. package/dist/dashboard/assets/CliToolDetailPage-DZKmVuJN.js.gz +0 -0
  9. package/dist/dashboard/assets/{CliToolsPage-Rj9iHQ3F.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-BKj_r0rp.js +1 -0
  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-C4w7vea-.js → LoginPage-DkXb6dx-.js} +1 -1
  20. package/dist/dashboard/assets/LoginPage-DkXb6dx-.js.gz +0 -0
  21. package/dist/dashboard/assets/{ModelPicker-BtPcAfot.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-5SnUSy3j.js +9 -0
  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-BQS0Rx_u.js → SetupPage-WTa0sktC.js} +1 -1
  38. package/dist/dashboard/assets/SetupPage-WTa0sktC.js.gz +0 -0
  39. package/dist/dashboard/assets/{StudioPage-TP7voAQ0.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-C0YYuZJ4.js → assert-C0K-c4eo.js} +1 -1
  48. package/dist/dashboard/assets/assert-C0K-c4eo.js.gz +0 -0
  49. package/dist/dashboard/assets/{badge-B_DMpMJN.js → badge-DfbhQU4k.js} +1 -1
  50. package/dist/dashboard/assets/badge-DfbhQU4k.js.gz +0 -0
  51. package/dist/dashboard/assets/{banner-DMrMPmth.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-Be5Uzamx.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-muFRphDu.js → cli-tools-CQXVMn4P.js} +1 -1
  62. package/dist/dashboard/assets/cli-tools-CQXVMn4P.js.gz +0 -0
  63. package/dist/dashboard/assets/{clipboard-button-DOfrVmsi.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-C9omdjQt.js → dialog-BEK7KP0H.js} +1 -1
  66. package/dist/dashboard/assets/dialog-BEK7KP0H.js.gz +0 -0
  67. package/dist/dashboard/assets/{drawer-Bm8WKaGY.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-q5HwZ8nN.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-BTScrQpe.js → formatters-BAACA727.js} +1 -1
  76. package/dist/dashboard/assets/formatters-BAACA727.js.gz +0 -0
  77. package/dist/dashboard/assets/{github-badge-Orjuzemr.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-cPrX5vn6.js → index-FQlj0HUT.js} +2 -2
  80. package/dist/dashboard/assets/index-FQlj0HUT.js.gz +0 -0
  81. package/dist/dashboard/assets/{inline-Dvux8w-0.js → inline-C4gU5iOL.js} +1 -1
  82. package/dist/dashboard/assets/inline-C4gU5iOL.js.gz +0 -0
  83. package/dist/dashboard/assets/{input-CU1Rgf3p.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-C_7A6H55.js → layout-CajrYUnD.js} +1 -1
  86. package/dist/dashboard/assets/{layout-C_7A6H55.js.gz → layout-CajrYUnD.js.gz} +0 -0
  87. package/dist/dashboard/assets/{list-row-CzFvogbj.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/minimize-2-BTmMTK4o.js +1 -0
  92. package/dist/dashboard/assets/minimize-2-BTmMTK4o.js.gz +0 -0
  93. package/dist/dashboard/assets/{mutation-JJGQm8TD.js → mutation-Rr0TIvcj.js} +1 -1
  94. package/dist/dashboard/assets/mutation-Rr0TIvcj.js.gz +0 -0
  95. package/dist/dashboard/assets/network-C5UBACrJ.js +1 -0
  96. package/dist/dashboard/assets/network-C5UBACrJ.js.gz +0 -0
  97. package/dist/dashboard/assets/numbers-CUWAZK4J.js +2 -0
  98. package/dist/dashboard/assets/numbers-CUWAZK4J.js.gz +0 -0
  99. package/dist/dashboard/assets/pagination-Xsi9Qx04.js +1 -0
  100. package/dist/dashboard/assets/pagination-Xsi9Qx04.js.gz +0 -0
  101. package/dist/dashboard/assets/{query-keys-CLaNz8Xz.js → query-keys-BloKtaXJ.js} +1 -1
  102. package/dist/dashboard/assets/query-keys-BloKtaXJ.js.gz +0 -0
  103. package/dist/dashboard/assets/quota-DvQbD_sr.js +1 -0
  104. package/dist/dashboard/assets/quota-DvQbD_sr.js.gz +0 -0
  105. package/dist/dashboard/assets/{routing-BEH32QOC.js → routing-in0f_IfK.js} +1 -1
  106. package/dist/dashboard/assets/routing-in0f_IfK.js.gz +0 -0
  107. package/dist/dashboard/assets/{select-B3iTetHN.js → select-BLULNqTp.js} +2 -2
  108. package/dist/dashboard/assets/select-BLULNqTp.js.gz +0 -0
  109. package/dist/dashboard/assets/settings-CcGczj6I.js +1 -0
  110. package/dist/dashboard/assets/settings-CcGczj6I.js.gz +0 -0
  111. package/dist/dashboard/assets/shield-BMQNxORh.js +1 -0
  112. package/dist/dashboard/assets/shield-BMQNxORh.js.gz +0 -0
  113. package/dist/dashboard/assets/{stack-KrOrm7JZ.js → stack-D2lIR0tg.js} +1 -1
  114. package/dist/dashboard/assets/stack-D2lIR0tg.js.gz +0 -0
  115. package/dist/dashboard/assets/{state-DLS7IDMy.js → state-DTARjfiW.js} +1 -1
  116. package/dist/dashboard/assets/state-DTARjfiW.js.gz +0 -0
  117. package/dist/dashboard/assets/{switch-42ItvbAs.js → switch-c0oPSnqW.js} +1 -1
  118. package/dist/dashboard/assets/switch-c0oPSnqW.js.gz +0 -0
  119. package/dist/dashboard/assets/{useMutation-Dmnfh1Ue.js → useMutation-m8WGNPrz.js} +1 -1
  120. package/dist/dashboard/assets/useMutation-m8WGNPrz.js.gz +0 -0
  121. package/dist/dashboard/console-backgrounds.jpg +0 -0
  122. package/dist/dashboard/console-backgrounds_initial.jpg +0 -0
  123. package/dist/dashboard/index.html +2 -2
  124. package/dist/dashboard/index.html.gz +0 -0
  125. package/dist/dashboard/precompressed-assets.json +59 -57
  126. package/migrations/full-postgres/0027_qoder_identity_genuine_seed.sql +9 -10
  127. package/migrations/full-postgres/0032_add_provider_pool_accounts.sql +53 -0
  128. package/migrations/full-postgres/0033_add_api_key_ban.sql +9 -0
  129. package/migrations/full-postgres/0034_add_api_key_ban_until.sql +7 -0
  130. package/migrations/full-postgres/0035_align_pool_account_status_enum.sql +21 -0
  131. package/migrations/full-postgres/0036_system_prompt_presets_refs.sql +10 -0
  132. package/migrations/full-postgres/0037_share_concurrency_scope.sql +3 -0
  133. package/migrations/full-postgres/0038_add_accounts_quota_snapshot.sql +7 -0
  134. package/migrations/full-postgres/0039_add_telemetry_provider_model_indexes.sql +13 -0
  135. package/migrations/full-postgres/0040_add_models_dialect.sql +3 -0
  136. package/migrations/full-postgres/0041_add_daily_checkin_ledger_account_fk.sql +7 -0
  137. package/migrations/lite-sqlite3/0027_qoder_identity_genuine_seed.sql +9 -10
  138. package/migrations/lite-sqlite3/0032_add_provider_pool_accounts.sql +44 -0
  139. package/migrations/lite-sqlite3/0033_add_api_key_ban.sql +8 -0
  140. package/migrations/lite-sqlite3/0034_add_api_key_ban_until.sql +5 -0
  141. package/migrations/lite-sqlite3/0035_align_pool_account_status_enum.sql +6 -0
  142. package/migrations/lite-sqlite3/0036_system_prompt_presets_refs.sql +14 -0
  143. package/migrations/lite-sqlite3/0037_share_concurrency_scope.sql +3 -0
  144. package/migrations/lite-sqlite3/0038_add_accounts_quota_snapshot.sql +4 -0
  145. package/migrations/lite-sqlite3/0039_add_telemetry_provider_model_indexes.sql +6 -0
  146. package/migrations/lite-sqlite3/0040_add_models_dialect.sql +3 -0
  147. package/migrations/lite-sqlite3/0041_add_daily_checkin_ledger_account_fk.sql +26 -0
  148. package/package.json +4 -5
  149. package/scripts/cli/update.ts +15 -41
  150. package/src/boot/app.ts +67 -10
  151. package/src/boot/dependencies.ts +786 -732
  152. package/src/boot/lifecycle.ts +11 -12
  153. package/src/config/cooldowns.ts +34 -55
  154. package/src/config/network.ts +8 -4
  155. package/src/config/package-paths.ts +1 -1
  156. package/src/config/providers.ts +13 -14
  157. package/src/config/resources.ts +0 -5
  158. package/src/config/runtime.ts +2 -5
  159. package/src/config/spec.ts +26 -6
  160. package/src/console/api-keys/ban-constants.ts +38 -0
  161. package/src/console/api-keys/contracts.ts +92 -31
  162. package/src/console/api-keys/routes.ts +131 -6
  163. package/src/console/audit/routes.ts +3 -3
  164. package/src/console/auth/access.ts +4 -4
  165. package/src/console/auth/account-reset.ts +5 -5
  166. package/src/console/auth/audit-recorder.ts +1 -1
  167. package/src/console/auth/lockout.ts +7 -3
  168. package/src/console/auth/row-coercion.ts +57 -12
  169. package/src/console/auth/session-resolver.ts +1 -1
  170. package/src/console/auth/session-service.ts +8 -2
  171. package/src/console/auth/session.ts +40 -34
  172. package/src/console/auth/setup-service.ts +4 -3
  173. package/src/console/auth/user-store.ts +1 -1
  174. package/src/console/backup/9router-map.ts +0 -3
  175. package/src/console/backup/contracts.ts +11 -9
  176. package/src/console/backup/export-endpoint.ts +11 -12
  177. package/src/console/backup/nine-router.ts +1 -7
  178. package/src/console/backup/routes.ts +32 -36
  179. package/src/console/backup/service.ts +468 -468
  180. package/src/console/backup/store.ts +47 -29
  181. package/src/console/backup/validate.ts +11 -1
  182. package/src/console/cli-tools/contracts.ts +7 -7
  183. package/src/console/cli-tools/injectors/cline.ts +110 -110
  184. package/src/console/cli-tools/injectors/codex.ts +181 -181
  185. package/src/console/cli-tools/injectors/copilot.ts +108 -108
  186. package/src/console/cli-tools/injectors/driver.ts +247 -247
  187. package/src/console/cli-tools/injectors/jcode.ts +115 -115
  188. package/src/console/cli-tools/injectors/openclaw.ts +161 -161
  189. package/src/console/cli-tools/injectors/opencode.ts +153 -153
  190. package/src/console/cli-tools/routes.ts +4 -4
  191. package/src/console/cli-tools/service.ts +1 -1
  192. package/src/console/cli-tools/store.ts +2 -2
  193. package/src/console/console-router-guards.ts +2 -2
  194. package/src/console/console-router.ts +36 -4
  195. package/src/console/dashboard-assets.ts +9 -9
  196. package/src/console/data-management/routes.ts +3 -3
  197. package/src/console/domain-registration.ts +18 -4
  198. package/src/console/inferhub/client.ts +0 -7
  199. package/src/console/inferhub/key-store.ts +1 -1
  200. package/src/console/inferhub/normalize.ts +2 -2
  201. package/src/console/inferhub/routes.ts +1 -1
  202. package/src/console/inferhub/types.ts +1 -1
  203. package/src/console/observability/contracts.ts +5 -1
  204. package/src/console/observability/live.ts +34 -21
  205. package/src/console/observability/logs.ts +4 -4
  206. package/src/console/observability/performance.ts +3 -3
  207. package/src/console/observability/routes.ts +3 -3
  208. package/src/console/observability/sse.ts +62 -8
  209. package/src/console/observability/store.ts +36 -20
  210. package/src/console/providers/catalog/catalog-projections.ts +1 -1
  211. package/src/console/providers/catalog/contracts.ts +82 -22
  212. package/src/console/providers/catalog/model-operations.ts +1 -1
  213. package/src/console/providers/catalog/provider-operations.ts +110 -17
  214. package/src/console/providers/catalog/public-model-store.ts +0 -0
  215. package/src/console/providers/catalog/routes.ts +30 -6
  216. package/src/console/providers/catalog/store-helpers.ts +349 -326
  217. package/src/console/providers/catalog/store.ts +1662 -1292
  218. package/src/console/providers/detail/routes.ts +4 -4
  219. package/src/console/providers/oauth/callback-listener.ts +100 -18
  220. package/src/console/providers/oauth/routes.ts +95 -16
  221. package/src/console/quota/account-quota-global.ts +41 -3
  222. package/src/console/quota/account-quota-shared.ts +10 -3
  223. package/src/console/quota/account-quota-tenant.ts +285 -67
  224. package/src/console/quota/account-test-egress.ts +4 -4
  225. package/src/console/quota/daily-growth-job.ts +308 -0
  226. package/src/console/quota/native-identity.ts +2 -2
  227. package/src/console/quota/quota-view.ts +1 -1
  228. package/src/console/remote-support/routes.ts +1 -1
  229. package/src/console/remote-support/service.ts +2 -2
  230. package/src/console/routing/model/contracts.ts +1 -1
  231. package/src/console/routing/model/routes.ts +3 -3
  232. package/src/console/routing/pools/contracts.ts +13 -10
  233. package/src/console/routing/pools/import-parse.ts +3 -3
  234. package/src/console/routing/pools/operations.ts +14 -7
  235. package/src/console/routing/pools/probe-verdict.ts +8 -3
  236. package/src/console/routing/pools/relay-deploy.ts +12 -12
  237. package/src/console/routing/pools/routes.ts +3 -3
  238. package/src/console/routing/pools/store.ts +21 -1
  239. package/src/console/settings/contracts.ts +29 -2
  240. package/src/console/settings/routes.ts +3 -3
  241. package/src/console/settings/store.ts +20 -0
  242. package/src/console/share/share-router.ts +112 -44
  243. package/src/console/share/share-stats.ts +109 -39
  244. package/src/console/share/share-usage.ts +1 -1
  245. package/src/console/shared/errors.ts +2 -2
  246. package/src/console/shared/object.ts +18 -0
  247. package/src/console/shared/read-through-cache.ts +42 -6
  248. package/src/console/shared/transaction.ts +14 -0
  249. package/src/console/system-prompt/contracts.ts +89 -12
  250. package/src/console/system-prompt/routes.ts +98 -45
  251. package/src/console/updates/apply-update.ts +244 -0
  252. package/src/console/updates/routes.ts +256 -98
  253. package/src/main.ts +11 -5
  254. package/src/network/http2-bidi.ts +1 -1
  255. package/src/network/ip-utils.ts +298 -0
  256. package/src/network/outbound-fetch.ts +76 -5
  257. package/src/network/pool/agent.ts +7 -6
  258. package/src/network/pool/byte-accounting.ts +1 -1
  259. package/src/network/pool/resolver.ts +55 -51
  260. package/src/network/pool/selector.ts +150 -136
  261. package/src/network/pool-cooldown-store.ts +71 -16
  262. package/src/network/pool-health-machine.ts +22 -2
  263. package/src/network/rate-limit-verdict.ts +68 -0
  264. package/src/network/retry.ts +1 -1
  265. package/src/network/ssrf.ts +24 -75
  266. package/src/observability/event-log.ts +2 -2
  267. package/src/observability/event-query.ts +286 -214
  268. package/src/observability/log-sanitize.ts +1 -1
  269. package/src/observability/metrics.ts +4 -4
  270. package/src/observability/payload-capture.ts +6 -5
  271. package/src/observability/payload-store.ts +1 -1
  272. package/src/observability/runtime-metrics.ts +1 -1
  273. package/src/observability/telemetry-buffer.ts +12 -3
  274. package/src/observability/telemetry-reconciliation.ts +3 -3
  275. package/src/observability/telemetry-status.ts +1 -1
  276. package/src/observability/token-speed.ts +1 -1
  277. package/src/persistence/connection-url.ts +1 -1
  278. package/src/persistence/db-handle.ts +1 -1
  279. package/src/persistence/db-pg.ts +2 -2
  280. package/src/persistence/db-sqlite.ts +10 -5
  281. package/src/persistence/dialect.ts +5 -1
  282. package/src/persistence/readiness.ts +19 -7
  283. package/src/persistence/redis.ts +1 -1
  284. package/src/persistence/schema.ts +177 -45
  285. package/src/persistence/shared-cache.ts +2 -2
  286. package/src/persistence/sort-order.ts +1 -1
  287. package/src/persistence/stores/api-key-store.ts +109 -4
  288. package/src/persistence/stores/share-store.ts +20 -8
  289. package/src/persistence/stores/telemetry-store.ts +1 -1
  290. package/src/persistence/system-prompt-store.ts +63 -18
  291. package/src/persistence/tenant-preferences.ts +1 -1
  292. package/src/persistence/ttl-cache.ts +3 -3
  293. package/src/persistence/usage-flush.ts +7 -2
  294. package/src/protocol/canonical-model.ts +1 -1
  295. package/src/protocol/codecs.ts +12 -16
  296. package/src/protocol/dsml.ts +3 -49
  297. package/src/protocol/gateway-error.ts +6 -3
  298. package/src/protocol/image-clamp.ts +2 -2
  299. package/src/protocol/image-generation.ts +2 -2
  300. package/src/protocol/reasoning-text.ts +1 -1
  301. package/src/protocol/reasoning.ts +7 -52
  302. package/src/protocol/registry.ts +50 -15
  303. package/src/protocol/request/chat.ts +46 -19
  304. package/src/protocol/request/codex.ts +1 -1
  305. package/src/protocol/request/messages.ts +46 -14
  306. package/src/protocol/request/responses.ts +19 -10
  307. package/src/protocol/response/chat.ts +27 -12
  308. package/src/protocol/response/codex.ts +2 -2
  309. package/src/protocol/response/gemini.ts +1 -1
  310. package/src/protocol/response/messages.ts +6 -6
  311. package/src/protocol/response/omp-tool-call-markup.ts +1 -1
  312. package/src/protocol/response/responses.ts +3 -3
  313. package/src/protocol/sse-decoder.ts +64 -4
  314. package/src/protocol/stop-reason.ts +2 -2
  315. package/src/protocol/think-split.ts +347 -0
  316. package/src/protocol/translation/attachment-integrity.ts +3 -3
  317. package/src/protocol/translation/cache-controls.ts +8 -20
  318. package/src/protocol/translation/capabilities.ts +8 -8
  319. package/src/protocol/translation/dialect/deepseek.ts +10 -0
  320. package/src/protocol/translation/dialect/inband.ts +39 -0
  321. package/src/protocol/translation/dialect/model-thinking.ts +89 -0
  322. package/src/protocol/translation/dialect/qwen.ts +114 -0
  323. package/src/protocol/translation/dialect/resolver.ts +83 -0
  324. package/src/protocol/translation/dialect/rules.ts +93 -0
  325. package/src/protocol/translation/dialect/thinking-ladder.ts +245 -0
  326. package/src/protocol/translation/dialect/types.ts +58 -0
  327. package/src/protocol/translation/quirks.ts +18 -4
  328. package/src/protocol/translation/thinking.ts +12 -252
  329. package/src/protocol/translation/tool-id.ts +3 -3
  330. package/src/protocol/translation/tool-repair.ts +1 -1
  331. package/src/protocol/upstream/post-json.ts +6 -1
  332. package/src/protocol/upstream/send-claude-messages.ts +3 -3
  333. package/src/providers/adapters/base-adapter.ts +1 -1
  334. package/src/providers/adapters/compatible-adapter.ts +44 -5
  335. package/src/providers/authentication/jwt-validator.ts +0 -5
  336. package/src/providers/authentication/oauth-client.ts +254 -253
  337. package/src/providers/authentication/oauth-flow-store.ts +42 -7
  338. package/src/providers/authentication/oauth-refresh-service.ts +2 -2
  339. package/src/providers/bundled-discovery-providers.ts +6 -30
  340. package/src/providers/configured-openai-providers.ts +82 -97
  341. package/src/providers/configured-provider.ts +1 -1
  342. package/src/providers/default-registry.ts +23 -35
  343. package/src/providers/discovery/catalog/catalog-format.ts +13 -2
  344. package/src/providers/discovery/discovery-types.ts +0 -1
  345. package/src/providers/discovery/openai-model-discovery.ts +2 -2
  346. package/src/providers/discovery/probe-phases.ts +50 -15
  347. package/src/providers/discovery/probing-service.ts +18 -20
  348. package/src/providers/integrations/agentrouter/agentrouter.ts +14 -5
  349. package/src/providers/integrations/alibabacp/alibabacp.ts +2 -2
  350. package/src/providers/integrations/anthropic.ts +4 -11
  351. package/src/providers/integrations/antigravity/antigravity-oauth.ts +0 -1
  352. package/src/providers/integrations/antigravity/antigravity-protocol.ts +0 -14
  353. package/src/providers/integrations/antigravity/antigravity.ts +15 -26
  354. package/src/providers/integrations/buddy/buddy-catalog-shared.ts +2 -2
  355. package/src/providers/integrations/buddy/buddy-chat-shared.ts +20 -4
  356. package/src/providers/integrations/buddy/buddy-cli-headers.ts +19 -52
  357. package/src/providers/integrations/buddy/buddy-discovery-shared.ts +37 -6
  358. package/src/providers/integrations/buddy/buddy-identity.ts +108 -1
  359. package/src/providers/integrations/buddy/buddy-media.ts +16 -16
  360. package/src/providers/integrations/buddy/buddy-oauth-shared.ts +1 -1
  361. package/src/providers/integrations/buddy/codebuddy/cn-provider.ts +1 -2
  362. package/src/providers/integrations/buddy/codebuddy/provider.ts +5 -16
  363. package/src/providers/integrations/buddy/codebuddy/shared.ts +30 -9
  364. package/src/providers/integrations/buddy/workbuddy/provider.ts +6 -10
  365. package/src/providers/integrations/buddy/workbuddy/shared.ts +21 -3
  366. package/src/providers/integrations/claude/claude-betas.ts +1 -1
  367. package/src/providers/integrations/claude/claude-cch.ts +148 -148
  368. package/src/providers/integrations/claude/claude-credentials.ts +1 -1
  369. package/src/providers/integrations/claude/claude-slow-lane-retry.ts +1 -1
  370. package/src/providers/integrations/claude/claude.ts +3 -10
  371. package/src/providers/integrations/claude/fallback-credit.ts +3 -7
  372. package/src/providers/integrations/cline/cline.ts +2 -2
  373. package/src/providers/integrations/cloudflareai/cloudflareai.ts +4 -7
  374. package/src/providers/integrations/codex/codex-device-code.ts +101 -101
  375. package/src/providers/integrations/codex/codex-errors.ts +1 -1
  376. package/src/providers/integrations/codex/codex-oauth.ts +0 -1
  377. package/src/providers/integrations/codex/codex.ts +14 -15
  378. package/src/providers/integrations/commandcode/commandcode.ts +76 -116
  379. package/src/providers/integrations/commandcode/quota.ts +132 -48
  380. package/src/providers/integrations/cursor/cursor-http2.ts +11 -14
  381. package/src/providers/integrations/cursor/cursor-quota.ts +2 -6
  382. package/src/providers/integrations/cursor/cursor-request.ts +0 -87
  383. package/src/providers/integrations/cursor/cursor-shared.ts +0 -4
  384. package/src/providers/integrations/cursor/cursor.ts +53 -20
  385. package/src/providers/integrations/cursor/protocol/framing.ts +0 -56
  386. package/src/providers/integrations/cursor/protocol/messages.ts +0 -96
  387. package/src/providers/integrations/factory/factory.ts +13 -13
  388. package/src/providers/integrations/gemini.ts +11 -11
  389. package/src/providers/integrations/github/github-discovery.ts +55 -10
  390. package/src/providers/integrations/github/github-oauth.ts +6 -5
  391. package/src/providers/integrations/github/github.ts +47 -20
  392. package/src/providers/integrations/grok/grok-oauth.ts +261 -261
  393. package/src/providers/integrations/grok/grok-quota-frame.ts +1 -1
  394. package/src/providers/integrations/grok/grok-quota.ts +16 -7
  395. package/src/providers/integrations/grok/grok-ratelimit-store.ts +0 -5
  396. package/src/providers/integrations/grok/grok-ratelimit.ts +3 -0
  397. package/src/providers/integrations/grok/grok.ts +88 -42
  398. package/src/providers/integrations/inferhub.ts +4 -11
  399. package/src/providers/integrations/kilo/kilo-oauth.ts +1 -1
  400. package/src/providers/integrations/kimi/kimi.ts +4 -11
  401. package/src/providers/integrations/kiro/kiro-cache.ts +31 -0
  402. package/src/providers/integrations/kiro/kiro-catalog.ts +31 -5
  403. package/src/providers/integrations/kiro/kiro-discovery.ts +47 -43
  404. package/src/providers/integrations/kiro/kiro-machine-id.ts +6 -3
  405. package/src/providers/integrations/kiro/kiro-oauth.ts +523 -255
  406. package/src/providers/integrations/kiro/kiro-quota.ts +35 -47
  407. package/src/providers/integrations/kiro/kiro-request.ts +8 -11
  408. package/src/providers/integrations/kiro/kiro-stream.ts +13 -0
  409. package/src/providers/integrations/kiro/kiro.ts +91 -78
  410. package/src/providers/integrations/muse/muse-oauth.ts +0 -1
  411. package/src/providers/integrations/muse/muse-quota.ts +0 -4
  412. package/src/providers/integrations/muse/muse.ts +6 -9
  413. package/src/providers/integrations/opencode/fingerprint.ts +7 -5
  414. package/src/providers/integrations/opencode/provider.ts +17 -24
  415. package/src/providers/integrations/perplexity.ts +2 -2
  416. package/src/providers/integrations/qoder/qoder-catalog.ts +132 -17
  417. package/src/providers/integrations/qoder/qoder-checkin.ts +26 -8
  418. package/src/providers/integrations/qoder/qoder-native-identity-store.ts +9 -8
  419. package/src/providers/integrations/qoder/qoder-oauth.ts +165 -25
  420. package/src/providers/integrations/qoder/qoder-quota.ts +48 -6
  421. package/src/providers/integrations/qoder/qoder-realm.ts +22 -28
  422. package/src/providers/integrations/qoder/qoder-sse.ts +159 -0
  423. package/src/providers/integrations/qoder/qoder-umid.ts +33 -38
  424. package/src/providers/integrations/qoder/qoder-virtual.ts +14 -2
  425. package/src/providers/integrations/qoder/qoder.ts +521 -63
  426. package/src/providers/integrations/shared/connect.ts +0 -54
  427. package/src/providers/integrations/shared/hash.ts +15 -0
  428. package/src/providers/integrations/shared/session-cache.ts +136 -0
  429. package/src/providers/integrations/tokenharbor.ts +2 -2
  430. package/src/providers/integrations/trae/trae-cache.ts +7 -87
  431. package/src/providers/integrations/trae/trae-catalog.ts +1 -6
  432. package/src/providers/integrations/trae/trae-protocol.ts +17 -8
  433. package/src/providers/integrations/trae/trae-realm.ts +0 -7
  434. package/src/providers/integrations/trae/trae.ts +59 -19
  435. package/src/providers/integrations/xai/xai-oauth.ts +5 -5
  436. package/src/providers/integrations/zcode/oauth.ts +1 -1
  437. package/src/providers/integrations/zcode-start-plan/gifts.ts +265 -0
  438. package/src/providers/integrations/zcode-start-plan/oauth.ts +154 -0
  439. package/src/providers/integrations/zcode-start-plan/provider.ts +131 -0
  440. package/src/providers/integrations/zcode-start-plan/quota.ts +152 -0
  441. package/src/providers/integrations/zcode-start-plan/zcode_prompt.json +10 -0
  442. package/src/providers/operations/account-error-classification.ts +131 -116
  443. package/src/providers/operations/account-health-service.ts +31 -39
  444. package/src/providers/operations/account-reset-service.ts +58 -1
  445. package/src/providers/operations/cli-platform.ts +31 -5
  446. package/src/providers/operations/client-version-resolver.ts +4 -6
  447. package/src/providers/operations/client-versions.ts +10 -7
  448. package/src/providers/operations/provider-catalog-seeder.ts +2 -0
  449. package/src/providers/operations/provider-catalog-service.ts +22 -6
  450. package/src/providers/operations/provider-credential-service.ts +35 -6
  451. package/src/providers/operations/upstream-deadline.ts +3 -3
  452. package/src/providers/provider-contracts.ts +65 -10
  453. package/src/providers/provider-credential-resolver.ts +1 -1
  454. package/src/providers/provider-metadata.ts +17 -2
  455. package/src/providers/provider-model-definition.ts +22 -1
  456. package/src/providers/provider-probe.ts +4 -2
  457. package/src/providers/provider-registry.ts +4 -4
  458. package/src/providers/provider-usage.ts +81 -16
  459. package/src/providers/quota/cache.ts +29 -0
  460. package/src/providers/quota/quota-contracts.ts +28 -10
  461. package/src/providers/quota/refresh.ts +29 -6
  462. package/src/providers/quota/snapshot.ts +94 -0
  463. package/src/providers/search/search-provider.ts +6 -8
  464. package/src/providers/search/search-providers.ts +2 -1
  465. package/src/security/abuse.ts +8 -8
  466. package/src/security/admission/reasons.ts +17 -17
  467. package/src/security/admission/service.ts +2 -2
  468. package/src/security/admission/ttl.ts +61 -61
  469. package/src/security/api-key-auth.ts +20 -8
  470. package/src/security/client-router-fingerprint.ts +4 -4
  471. package/src/security/credential-codec.ts +3 -3
  472. package/src/security/csrf.ts +2 -2
  473. package/src/security/ip-boundary.ts +16 -189
  474. package/src/security/model-access-rule.ts +1 -1
  475. package/src/security/outbound-headers.ts +18 -0
  476. package/src/shared/coerce.ts +19 -0
  477. package/src/shared/invoke-guard.ts +47 -0
  478. package/src/transport/contracts.ts +13 -4
  479. package/src/transport/dispatch/attempt-finalize.ts +5 -4
  480. package/src/transport/dispatch/attempt-loop.ts +10 -7
  481. package/src/transport/dispatch/capture-policy.ts +34 -37
  482. package/src/transport/dispatch/empty-stream.ts +28 -25
  483. package/src/transport/dispatch/generation.ts +33 -53
  484. package/src/transport/dispatch/leases.ts +8 -8
  485. package/src/transport/dispatch/native-shared.ts +127 -0
  486. package/src/transport/dispatch/proxy-request.ts +10 -8
  487. package/src/transport/dispatch/responses-compact.ts +35 -56
  488. package/src/transport/dispatch/retry-policy.ts +4 -67
  489. package/src/transport/dispatch/stream-bridge.ts +1 -1
  490. package/src/transport/dispatch/streaming/encoder.ts +18 -72
  491. package/src/transport/dispatch/streaming/finalize.ts +11 -10
  492. package/src/transport/dispatch/streaming/stream.ts +7 -3
  493. package/src/transport/dispatch/streaming/thinking-loop.ts +1 -1
  494. package/src/transport/dispatch/systemone.ts +27 -55
  495. package/src/transport/dispatch/token-count.ts +49 -46
  496. package/src/transport/dispatch/websearch.ts +24 -50
  497. package/src/transport/drain-endpoint.ts +3 -3
  498. package/src/transport/failure-policy.ts +19 -6
  499. package/src/transport/guards/auth-guard.ts +6 -11
  500. package/src/transport/guards/body-policy.ts +7 -7
  501. package/src/transport/guards/error-lifecycle.ts +18 -3
  502. package/src/transport/guards/guard-errors.ts +7 -3
  503. package/src/transport/guards/headroom-guard.ts +2 -2
  504. package/src/transport/guards/pipeline.ts +7 -7
  505. package/src/transport/guards/readiness-guard.ts +16 -2
  506. package/src/transport/guards/request-context.ts +15 -20
  507. package/src/transport/request/preparer.ts +306 -27
  508. package/src/transport/request/rtk/compress-request.ts +3 -3
  509. package/src/transport/request/rtk/rtk-constants.ts +2 -2
  510. package/src/transport/request/rtk/rtk-filters.ts +8 -8
  511. package/src/transport/request/state.ts +5 -20
  512. package/src/transport/request/system-prompt-injection.ts +74 -11
  513. package/src/transport/request/tenant-preferences.ts +22 -0
  514. package/src/transport/routing/candidate-index.ts +2 -2
  515. package/src/transport/routing/round-robin.ts +1 -1
  516. package/src/transport/routing/route-catalog.ts +113 -19
  517. package/src/transport/routing/route-model.ts +131 -38
  518. package/src/transport/routing/router.ts +154 -39
  519. package/src/transport/shutdown-notice.ts +21 -9
  520. package/src/transport/surface/adapters.ts +3 -3
  521. package/src/transport/surface/chat/encode.ts +7 -7
  522. package/src/transport/surface/chat/parse.ts +7 -7
  523. package/src/transport/surface/completion.ts +3 -3
  524. package/src/transport/surface/content-parts.ts +1 -1
  525. package/src/transport/surface/dialects.ts +2 -2
  526. package/src/transport/surface/messages/encode.ts +1 -1
  527. package/src/transport/surface/messages/parse.ts +3 -3
  528. package/src/transport/surface/responses/adapter.ts +1 -1
  529. package/src/transport/surface/responses/errors.ts +0 -9
  530. package/src/transport/vision-handoff-cache.ts +58 -0
  531. package/src/transport/vision-handoff.ts +376 -0
  532. package/src/workers/account-identity-sweep.ts +2 -2
  533. package/src/workers/buddy-growth-tasks.ts +392 -346
  534. package/src/workers/daily-checkin.ts +102 -49
  535. package/src/workers/maintenance-lease.ts +2 -35
  536. package/src/workers/oauth-refresh-sweep.ts +8 -1
  537. package/src/workers/quota-refresh-sweep.ts +120 -82
  538. package/src/workers/scheduler.ts +67 -4
  539. package/src/workers/sweep-runner.ts +24 -5
  540. package/src/workers/zcode-gift-claim.ts +108 -0
  541. package/dist/dashboard/assets/AccountCooldown-Bjo92Qat.js +0 -1
  542. package/dist/dashboard/assets/AccountCooldown-Bjo92Qat.js.gz +0 -0
  543. package/dist/dashboard/assets/BannedPage-2TJD37Hb.js.gz +0 -0
  544. package/dist/dashboard/assets/CliToolDetailPage-xefJNRmJ.js.gz +0 -0
  545. package/dist/dashboard/assets/CliToolsPage-Rj9iHQ3F.js.gz +0 -0
  546. package/dist/dashboard/assets/CombosPage-JEbYJFxw.js +0 -1
  547. package/dist/dashboard/assets/CombosPage-JEbYJFxw.js.gz +0 -0
  548. package/dist/dashboard/assets/ConsoleLogPage-C3xx_inM.js +0 -1
  549. package/dist/dashboard/assets/ConsoleLogPage-C3xx_inM.js.gz +0 -0
  550. package/dist/dashboard/assets/CustomizationPage-Dw306gJU.js +0 -1
  551. package/dist/dashboard/assets/CustomizationPage-Dw306gJU.js.gz +0 -0
  552. package/dist/dashboard/assets/HealthEventsModal-jaBo1TWV.js +0 -1
  553. package/dist/dashboard/assets/HealthEventsModal-jaBo1TWV.js.gz +0 -0
  554. package/dist/dashboard/assets/LoginPage-C4w7vea-.js.gz +0 -0
  555. package/dist/dashboard/assets/ModelPicker-BtPcAfot.js.gz +0 -0
  556. package/dist/dashboard/assets/OverviewPage-CGC5gNs1.js +0 -1
  557. package/dist/dashboard/assets/OverviewPage-CGC5gNs1.js.gz +0 -0
  558. package/dist/dashboard/assets/ProviderDetailPage-DQcthNGt.js +0 -4
  559. package/dist/dashboard/assets/ProviderDetailPage-DQcthNGt.js.gz +0 -0
  560. package/dist/dashboard/assets/ProviderIcon-FB6yS4v1.js +0 -1
  561. package/dist/dashboard/assets/ProviderIcon-FB6yS4v1.js.gz +0 -0
  562. package/dist/dashboard/assets/ProvidersPage-0OsXRGXe.js +0 -1
  563. package/dist/dashboard/assets/ProvidersPage-0OsXRGXe.js.gz +0 -0
  564. package/dist/dashboard/assets/ProxyPage-DdPc8slb.js +0 -9
  565. package/dist/dashboard/assets/ProxyPage-DdPc8slb.js.gz +0 -0
  566. package/dist/dashboard/assets/QuotaPage-Ci5O4BnH.js +0 -1
  567. package/dist/dashboard/assets/QuotaPage-Ci5O4BnH.js.gz +0 -0
  568. package/dist/dashboard/assets/SettingsPage-CDZjTt87.js +0 -1
  569. package/dist/dashboard/assets/SettingsPage-CDZjTt87.js.gz +0 -0
  570. package/dist/dashboard/assets/SetupPage-BQS0Rx_u.js.gz +0 -0
  571. package/dist/dashboard/assets/SortableList-BAL5npBC.js +0 -1
  572. package/dist/dashboard/assets/SortableList-BAL5npBC.js.gz +0 -0
  573. package/dist/dashboard/assets/StudioPage-TP7voAQ0.js.gz +0 -0
  574. package/dist/dashboard/assets/UsagePage-Cj_fEzhg.js +0 -56
  575. package/dist/dashboard/assets/UsagePage-Cj_fEzhg.js.gz +0 -0
  576. package/dist/dashboard/assets/api-keys-MbI7e7rt.js +0 -1
  577. package/dist/dashboard/assets/api-keys-MbI7e7rt.js.gz +0 -0
  578. package/dist/dashboard/assets/app-B2vyPoII.css +0 -2
  579. package/dist/dashboard/assets/app-B2vyPoII.css.gz +0 -0
  580. package/dist/dashboard/assets/assert-C0YYuZJ4.js.gz +0 -0
  581. package/dist/dashboard/assets/badge-B_DMpMJN.js.gz +0 -0
  582. package/dist/dashboard/assets/banner-DMrMPmth.js.gz +0 -0
  583. package/dist/dashboard/assets/card-Be5Uzamx.js.gz +0 -0
  584. package/dist/dashboard/assets/cli-tools-muFRphDu.js.gz +0 -0
  585. package/dist/dashboard/assets/clipboard-button-DOfrVmsi.js.gz +0 -0
  586. package/dist/dashboard/assets/dialog-C9omdjQt.js.gz +0 -0
  587. package/dist/dashboard/assets/drawer-Bm8WKaGY.js.gz +0 -0
  588. package/dist/dashboard/assets/entry-DS90gUks.js +0 -1
  589. package/dist/dashboard/assets/entry-DS90gUks.js.gz +0 -0
  590. package/dist/dashboard/assets/entry-j40LJotO.js +0 -4
  591. package/dist/dashboard/assets/entry-j40LJotO.js.gz +0 -0
  592. package/dist/dashboard/assets/entry-q5HwZ8nN.js.gz +0 -0
  593. package/dist/dashboard/assets/formatters-BTScrQpe.js.gz +0 -0
  594. package/dist/dashboard/assets/github-badge-Orjuzemr.js.gz +0 -0
  595. package/dist/dashboard/assets/index-cPrX5vn6.js.gz +0 -0
  596. package/dist/dashboard/assets/inline-Dvux8w-0.js.gz +0 -0
  597. package/dist/dashboard/assets/input-CU1Rgf3p.js.gz +0 -0
  598. package/dist/dashboard/assets/list-row-CzFvogbj.js.gz +0 -0
  599. package/dist/dashboard/assets/live-KaG15HLQ.js +0 -1
  600. package/dist/dashboard/assets/live-KaG15HLQ.js.gz +0 -0
  601. package/dist/dashboard/assets/minimize-2-D-MN8W8a.js +0 -1
  602. package/dist/dashboard/assets/minimize-2-D-MN8W8a.js.gz +0 -0
  603. package/dist/dashboard/assets/mutation-JJGQm8TD.js.gz +0 -0
  604. package/dist/dashboard/assets/numbers-BNDZnsUE.js +0 -2
  605. package/dist/dashboard/assets/numbers-BNDZnsUE.js.gz +0 -0
  606. package/dist/dashboard/assets/query-keys-CLaNz8Xz.js.gz +0 -0
  607. package/dist/dashboard/assets/quota-DZGyp0N5.js +0 -1
  608. package/dist/dashboard/assets/quota-DZGyp0N5.js.gz +0 -0
  609. package/dist/dashboard/assets/routing-BEH32QOC.js.gz +0 -0
  610. package/dist/dashboard/assets/select-B3iTetHN.js.gz +0 -0
  611. package/dist/dashboard/assets/settings-Dt3Eqbnq.js +0 -1
  612. package/dist/dashboard/assets/settings-Dt3Eqbnq.js.gz +0 -0
  613. package/dist/dashboard/assets/stack-KrOrm7JZ.js.gz +0 -0
  614. package/dist/dashboard/assets/state-DLS7IDMy.js.gz +0 -0
  615. package/dist/dashboard/assets/stream-retry-5QnVuSSo.js +0 -1
  616. package/dist/dashboard/assets/stream-retry-5QnVuSSo.js.gz +0 -0
  617. package/dist/dashboard/assets/switch-42ItvbAs.js.gz +0 -0
  618. package/dist/dashboard/assets/useMutation-Dmnfh1Ue.js.gz +0 -0
  619. package/src/network/response-headers.ts +0 -39
  620. package/src/protocol/response/dsml.ts +0 -38
  621. package/src/providers/integrations/xiaomi-mimo/think-stream.ts +0 -229
  622. /package/dist/dashboard/assets/{app-wvwCi4Eh.js → app-Bgd3zANQ.js} +0 -0
  623. /package/dist/dashboard/assets/{app-wvwCi4Eh.js.gz → app-Bgd3zANQ.js.gz} +0 -0
  624. /package/dist/dashboard/assets/brand/{og_bansos.webp → og_bansos_initial.webp} +0 -0
  625. /package/dist/dashboard/assets/brand/{og_image.webp → og_image_initial.webp} +0 -0
@@ -4,17 +4,22 @@ import type { Elysia } from "elysia";
4
4
  import { and, eq, inArray } from "drizzle-orm";
5
5
  import { providerAccounts, providers } from "../../persistence/schema";
6
6
  import { providerDisplayName } from "../../providers/provider-metadata";
7
- import { invalidateCredentialCache } from "../../providers/operations/provider-credential-service";
7
+ import {
8
+ invalidateCredentialCache,
9
+ invalidateCredentialCaches,
10
+ } from "../../providers/operations/provider-credential-service";
8
11
  import { requireTenantScope } from "../shared/errors";
9
12
  import { BUDDY_PROVIDER_IDS } from "../../providers/provider-metadata";
10
- import { readBuddyUsageSnapshots } from "../../providers/integrations/buddy/buddy-usage-store";
11
13
  import { GatewayError } from "../../protocol/gateway-error";
12
14
  import {
13
15
  GLOBAL_QUOTA_LENS,
14
16
  getCachedQuotaEntries,
15
17
  getCachedQuotaEntry,
16
18
  invalidateQuotaCache,
19
+ invalidateQuotaCaches,
20
+ invalidateQuotaCacheForAccount,
17
21
  } from "../../providers/quota/cache";
22
+ import { readQuotaSnapshot, readQuotaSnapshots } from "../../providers/quota/snapshot";
18
23
  import {
19
24
  QUOTA_REFRESH_TIMEOUT_MS,
20
25
  refreshAccountQuota,
@@ -47,13 +52,16 @@ import {
47
52
  DrizzleQoderNativeIdentityStore,
48
53
  type QoderNativeIdentityStore,
49
54
  } from "../../providers/integrations/qoder/qoder-native-identity-store";
50
- import { buddyAccountUid } from "../../providers/integrations/buddy/buddy-oauth-shared";
55
+ import { claimZcodeGifts, type ZcodeGiftResult } from "../../providers/integrations/zcode-start-plan/gifts";
56
+ import { ZCODE_START_PLAN_PROVIDER_ID } from "../../providers/integrations/zcode-start-plan/provider";
51
57
  import {
52
58
  supportsAccountReset,
53
59
  consumeAccountResetCredit,
60
+ getCachedResetCredits,
54
61
  listAccountResetCredits,
55
62
  } from "../../providers/operations/account-reset-service";
56
63
  import {
64
+ enqueueBackgroundQuotaRefresh,
57
65
  pendingQuotaRefreshes,
58
66
  toQuotaAccountHealth,
59
67
  toQuotaView,
@@ -63,6 +71,14 @@ import {
63
71
  type AccountQuotaRoutesDeps,
64
72
  type AccountStatus,
65
73
  } from "./account-quota-shared";
74
+ import {
75
+ DAILY_GROWTH_LEG_TIMEOUT_MS,
76
+ enqueueDailyGrowthJob,
77
+ getDailyGrowthJob,
78
+ withLegBudget,
79
+ type DailyGrowthJobAccount,
80
+ type DailyGrowthJobDeps,
81
+ } from "./daily-growth-job";
66
82
 
67
83
  /** Daily check-in only exists on the buddy billing facade; everything else 400s with intent. */
68
84
  function supportsAccountCheckin(providerId: string): boolean {
@@ -132,10 +148,6 @@ async function runAccountCheckin(
132
148
  });
133
149
  }
134
150
 
135
- /** Bound on accounts one manual daily-growth batch may cover. */
136
- /** Concurrent accounts inside one manual daily-growth batch. */
137
- const DAILY_GROWTH_CONCURRENCY = 3;
138
-
139
151
  /**
140
152
  * One account's daily growth pass, report first then claim.
141
153
  *
@@ -174,6 +186,12 @@ async function runDailyGrowthForAccount(
174
186
  // fails closed instead of reporting under another account's identity. Qoder
175
187
  // has no activity-report leg — its daily grant is purely the check-in.
176
188
  const qoderAccount = isQoderCheckinProvider(String(providerId));
189
+ // dynamic-import: B-02 lazy graph — buddy uid decoder, only for buddy report legs.
190
+ // The buddy-oauth-shared graph is lazy-loaded: the uid decoder is only
191
+ // needed for buddy accounts' report leg (B-02).
192
+ const { buddyAccountUid } = await import(
193
+ "../../providers/integrations/buddy/buddy-oauth-shared"
194
+ );
177
195
  const userId = buddyAccountUid(credential);
178
196
  let report: { ok: boolean; message: string };
179
197
  if (qoderAccount) {
@@ -352,6 +370,13 @@ export function registerAccountQuotaTenantRoutes(
352
370
  getCachedQuotaEntries(access.tenantId, ownedIds, redis),
353
371
  getCachedQuotaEntries(GLOBAL_QUOTA_LENS, globalIds, redis),
354
372
  ]);
373
+ // A page open right after a restart finds the in-process cache empty.
374
+ // Fall back to the persisted snapshots (which survive a restart) so the
375
+ // page still renders the last known balance; the sweep refreshes it.
376
+ const snapshots = await readQuotaSnapshots(
377
+ db,
378
+ rows.filter((row) => !globalCache.has(row.id) && !ownedCache.has(row.id)).map((row) => row.id),
379
+ );
355
380
 
356
381
  const pending = pendingQuotaRefreshes();
357
382
  const providerIds = [...new Set(rows.map((row) => row.providerId))];
@@ -369,6 +394,15 @@ export function registerAccountQuotaTenantRoutes(
369
394
  icon: providerId,
370
395
  }));
371
396
  let refreshing = 0;
397
+ // Cold-cache backfill: the overview renders whatever is cached, and the
398
+ // periodic sweep owns freshness — but with many accounts (e.g. a large
399
+ // Qoder roster) the sweep's per-pass cap cannot keep every cache warm,
400
+ // so a page open would show accounts with no badge for minutes. Enqueue
401
+ // a bounded background refresh for accounts whose cache entry is missing
402
+ // (not merely stale), so the badge fills in without waiting for the next
403
+ // sweep pass and without fanning out to the whole roster at once.
404
+ const coldCacheCap = 20;
405
+ let coldCacheEnqueued = 0;
372
406
  // The sweep's day markers answer "attempted today" without an upstream
373
407
  // request; only check-in-capable accounts can carry one, so only they
374
408
  // are read.
@@ -385,6 +419,12 @@ export function registerAccountQuotaTenantRoutes(
385
419
  // the upstream: the page renders every account at once, and re-hitting the
386
420
  // billing endpoint per account would make opening it scale with the
387
421
  // account count. One batch read for every buddy row.
422
+ // dynamic-import: B-02 lazy graph — buddy usage snapshots, only when the page renders buddy accounts.
423
+ // The buddy-usage-store graph is lazy-loaded: it is only needed when the
424
+ // page actually renders buddy accounts (B-02).
425
+ const { readBuddyUsageSnapshots } = await import(
426
+ "../../providers/integrations/buddy/buddy-usage-store"
427
+ );
388
428
  const usageByAccount = await readBuddyUsageSnapshots(
389
429
  db,
390
430
  rows.filter((row) => isBuddyProvider(row.providerId)).map((row) => row.id),
@@ -392,6 +432,9 @@ export function registerAccountQuotaTenantRoutes(
392
432
  const accounts = rows.map((row) => {
393
433
  const entry =
394
434
  row.tenantId === null ? globalCache.get(row.id) : ownedCache.get(row.id);
435
+ const snapshot = entry ?? snapshots.get(row.id);
436
+ const entryQuota = snapshot ? snapshot.quota : null;
437
+ const entryFetchedAt = snapshot ? snapshot.fetchedAt : null;
395
438
  // No background refresh is enqueued here: enqueuing one for every
396
439
  // account whose cached value had aged out means a single page open hits
397
440
  // every provider's quota endpoint at once — and because the page also
@@ -404,19 +447,34 @@ export function registerAccountQuotaTenantRoutes(
404
447
  const canRefresh = providerRegistry.hasQuotaCollector(row.providerId);
405
448
  const isRefreshing = canRefresh && (pending.has(row.id) || entry === undefined);
406
449
  if (isRefreshing) refreshing += 1;
450
+ // Backfill a missing cache entry on page open (bounded, see above).
451
+ if (
452
+ canRefresh &&
453
+ entry === undefined &&
454
+ !pending.has(row.id) &&
455
+ coldCacheEnqueued < coldCacheCap
456
+ ) {
457
+ coldCacheEnqueued += 1;
458
+ enqueueBackgroundQuotaRefresh(refreshDeps, {
459
+ accountId: row.id,
460
+ providerId: row.providerId,
461
+ tenantId: row.tenantId,
462
+ credentialKind: row.credentialKind,
463
+ });
464
+ }
407
465
  return {
408
466
  id: row.id,
409
467
  provider: row.providerId,
410
468
  name: row.label || row.id,
411
469
  credentialHint: row.credentialKind,
412
470
  active: row.status === "active",
413
- quota: entry
414
- ? toQuotaView(entry.quota, row, {
415
- fetchedAt: entry.fetchedAt,
416
- lastAttemptAt: entry.lastAttemptAt,
417
- refreshError: entry.refreshError,
418
- ...(isRefreshing ? { status: "refreshing" as const } : {}),
419
- })
471
+ quota: entryQuota
472
+ ? toQuotaView(entryQuota, row, {
473
+ fetchedAt: entryFetchedAt,
474
+ lastAttemptAt: entry?.lastAttemptAt ?? null,
475
+ refreshError: entry?.refreshError ?? null,
476
+ ...(isRefreshing ? { status: "refreshing" as const } : {}),
477
+ })
420
478
  : null,
421
479
  pending: isRefreshing,
422
480
  health: toQuotaAccountHealth(row),
@@ -478,13 +536,33 @@ export function registerAccountQuotaTenantRoutes(
478
536
  health: toQuotaAccountHealth(account),
479
537
  };
480
538
  }
539
+ // Cache is cold (e.g. right after a restart): render the last persisted
540
+ // snapshot instead of hitting upstream on every page open. The sweep
541
+ // refreshes it; a page open does not need to pay the upstream cost.
542
+ const snapshot = await readQuotaSnapshot(db, accountId);
543
+ if (snapshot) {
544
+ return {
545
+ accountId,
546
+ quota: toQuotaView(snapshot.quota, account, {
547
+ fetchedAt: snapshot.fetchedAt,
548
+ lastAttemptAt: snapshot.fetchedAt,
549
+ }),
550
+ health: toQuotaAccountHealth(account),
551
+ };
552
+ }
481
553
 
482
554
  // Cold read: this is the one path that legitimately waits on upstream, and
483
555
  // it shares the in-flight fetch with any queued background fill so a cold
484
556
  // page open never issues two requests for the same account.
485
557
  const outcome = await refreshAccountQuota(
486
558
  refreshDeps,
487
- { accountId, providerId: account.providerId, tenantId: account.tenantId, credentialKind: account.credentialKind },
559
+ {
560
+ accountId,
561
+ providerId: account.providerId,
562
+ tenantId: account.tenantId,
563
+ credentialKind: account.credentialKind,
564
+ authState: account.authState,
565
+ },
488
566
  signalFetch(timeoutSignal(request.signal, QUOTA_REFRESH_TIMEOUT_MS)),
489
567
  );
490
568
  const fresh = await getCachedQuotaEntry(access.tenantId, accountId, redis);
@@ -525,7 +603,7 @@ export function registerAccountQuotaTenantRoutes(
525
603
  throw new GatewayError(
526
604
  "proxy_pool_unavailable",
527
605
  503,
528
- "Account test cannot select a proxy because proxy routing is not configured.",
606
+ "Account test cannot select a proxy because proxy routing is not configured (request {requestId}). No bridge to cross — configure a pool first 🏗️",
529
607
  { reason: "proxy_routing_unconfigured" },
530
608
  "network",
531
609
  );
@@ -546,7 +624,16 @@ export function registerAccountQuotaTenantRoutes(
546
624
  try {
547
625
  outcome = await refreshAccountQuota(
548
626
  refreshDeps,
549
- { accountId, providerId: account.providerId, tenantId: account.tenantId, credentialKind: account.credentialKind },
627
+ {
628
+ accountId,
629
+ providerId: account.providerId,
630
+ tenantId: account.tenantId,
631
+ credentialKind: account.credentialKind,
632
+ // Kiro's usage surface is profile-scoped: without the account's auth
633
+ // state the collector cannot resolve a `profileArn`, and the GET is
634
+ // refused with `400 Invalid profileArn.`.
635
+ authState: account.authState,
636
+ },
550
637
  egress.fetch,
551
638
  );
552
639
  } finally {
@@ -591,6 +678,7 @@ export function registerAccountQuotaTenantRoutes(
591
678
  providerId: providerAccounts.providerId,
592
679
  tenantId: providerAccounts.tenantId,
593
680
  credentialKind: providerAccounts.credentialKind,
681
+ authState: providerAccounts.authState,
594
682
  })
595
683
  .from(providerAccounts)
596
684
  .where(
@@ -751,17 +839,60 @@ export function registerAccountQuotaTenantRoutes(
751
839
  });
752
840
  return { success: true };
753
841
  })
842
+ .post(
843
+ "/accounts/batch-delete",
844
+ {
845
+ body: t.Object({
846
+ accountIds: t.Array(t.String()),
847
+ }),
848
+ },
849
+ async ({ request, body }) => {
850
+ const access = requireTenantScope(accessResolver(request), "dashboard:write");
851
+ const accountIds = [...new Set(body.accountIds)];
852
+ if (accountIds.length === 0) {
853
+ return { ok: true, deleted: [], missing: [] };
854
+ }
855
+ // One DELETE statement for the whole batch, scoped to the tenant: a
856
+ // global/shared account (`tenant_id IS NULL`) is never matchable, so
857
+ // it lands in `missing` rather than being deleted by a tenant.
858
+ const deleted = await db
859
+ .delete(providerAccounts)
860
+ .where(
861
+ and(
862
+ inArray(providerAccounts.id, accountIds),
863
+ eq(providerAccounts.tenantId, access.tenantId),
864
+ ),
865
+ )
866
+ .returning({ id: providerAccounts.id });
867
+ const deletedIds = deleted.map((row) => row.id);
868
+ const deletedSet = new Set(deletedIds);
869
+ const missing = accountIds.filter((id) => !deletedSet.has(id));
870
+ // One credential-cache pass, one quota-cache pass, one snapshot
871
+ // invalidation, one audit row — never one per deleted account.
872
+ invalidateCredentialCaches(deletedIds);
873
+ await invalidateQuotaCaches(access.tenantId, deletedIds, redis);
874
+ await snapshotInvalidator?.invalidate();
875
+ await auditRecorder?.record({
876
+ access,
877
+ action: "provider_account.batch_deleted",
878
+ target: access.tenantId,
879
+ detail: { deleted: deletedIds, missing },
880
+ });
881
+ return { ok: true, deleted: deletedIds, missing };
882
+ },
883
+ )
754
884
  /**
755
- * Runs the daily growth pass over a provider's accounts in one request:
756
- * the growth-activity report first, then the check-in claim — the order the
885
+ * Enqueues a background daily-growth job over a provider's accounts: the
886
+ * growth-activity report first, then the check-in claim — the order the
757
887
  * sweep uses — with egress rotated per account the same way the worker
758
888
  * does, so a batch leaves from more than one address.
759
889
  *
760
- * A manual trigger is the operator asserting "try now", so it bypasses the
761
- * sweep's once-per-day ledger; the upstream stays idempotent either way.
762
- * Per-account outcomes are reported individually: a batch is not
763
- * all-or-nothing, and one account's closed check-in must not hide the
764
- * others' streaks.
890
+ * Running the whole batch in the request held it open for every account's
891
+ * upstream calls; the route now returns `{ jobId }` immediately and the
892
+ * work drains through a bounded background worker (see the job status
893
+ * route below). A manual trigger is the operator asserting "try now", so
894
+ * it bypasses the sweep's once-per-day ledger; the upstream stays
895
+ * idempotent either way.
765
896
  */
766
897
  .post(
767
898
  "/quota/daily-growth",
@@ -807,59 +938,66 @@ export function registerAccountQuotaTenantRoutes(
807
938
  };
808
939
  }
809
940
  // No size cap, for the same reason as the quota refresh: the work is
810
- // already drained through a bounded worker pool, so refusing the request
811
- // protected nothing and just forced the operator to batch by hand.
812
- // One egress rotator for the whole request, exactly as the sweep builds
813
- // it, so consecutive accounts leave from consecutive pools.
941
+ // already drained through a bounded worker pool behind the job, so
942
+ // refusing the request protected nothing and just forced the operator
943
+ // to batch by hand.
944
+ //
945
+ // One egress rotator for the whole job, exactly as the sweep builds it,
946
+ // so consecutive accounts leave from consecutive pools. The job carries
947
+ // the per-account run (report then claim) through the injected runner.
814
948
  const rotator =
815
949
  networkBindingFactory !== undefined
816
950
  ? dailyCheckinEgressForPass({ db, networkBindingFactory })
817
951
  : undefined;
952
+ // One leg budget for the whole job: every upstream fetch the per-account
953
+ // run issues carries it on top of the helpers' own per-request timeouts.
954
+ const legSignal = AbortSignal.timeout(DAILY_GROWTH_LEG_TIMEOUT_MS);
955
+ const rotatorWithBudget =
956
+ rotator === undefined
957
+ ? undefined
958
+ : async (accountId: string, tenantId?: string | null) => {
959
+ const base = await rotator(accountId, tenantId);
960
+ return withLegBudget(base, legSignal) as unknown as ValidatedFetch;
961
+ };
818
962
 
819
- const results: {
820
- readonly accountId: string;
821
- readonly label: string;
822
- readonly report: { readonly ok: boolean; readonly message: string };
823
- readonly checkin: { readonly ok: boolean; readonly message: string };
824
- }[] = [];
825
-
826
- for (let offset = 0; offset < accounts.length; offset += DAILY_GROWTH_CONCURRENCY) {
827
- const batch = accounts.slice(offset, offset + DAILY_GROWTH_CONCURRENCY);
828
- const settled = await Promise.all(
829
- batch.map(async (account) => {
830
- const outcome = await runDailyGrowthForAccount(
831
- providerId as ProviderId,
832
- account,
833
- refreshDeps,
834
- rotator,
835
- );
836
- return { account, outcome };
837
- }),
963
+ const runAccount = async (account: DailyGrowthJobAccount) => {
964
+ const outcome = await runDailyGrowthForAccount(
965
+ providerId as ProviderId,
966
+ account,
967
+ refreshDeps,
968
+ rotatorWithBudget,
838
969
  );
839
- for (const { account, outcome } of settled) {
840
- results.push({
841
- accountId: account.id,
842
- label: account.label || account.id,
843
- report: outcome.report,
844
- checkin: outcome.checkin,
845
- });
970
+ if (!outcome.checkin.ok) {
971
+ return { ok: false, error: outcome.checkin.message };
846
972
  }
847
- }
973
+ return { ok: true };
974
+ };
848
975
 
849
- // The ledger is shared with the sweep, so invalidate once at the end
850
- // rather than per account — the page re-reads "attempted today" from it.
851
- await snapshotInvalidator?.invalidate();
852
- const reportsOk = results.filter((entry) => entry.report.ok).length;
853
- const claimed = results.filter((entry) => entry.checkin.ok).length;
854
- return {
855
- ok: true,
856
- status: 200,
857
- providerId,
858
- data: results,
859
- message: `${results.length} account${results.length === 1 ? "" : "s"} · report ${reportsOk}/${results.length} · check-in ${claimed}/${results.length}`,
976
+ const jobDeps: DailyGrowthJobDeps = {
977
+ db,
978
+ redis,
979
+ runAccount,
980
+ ...(snapshotInvalidator ? { snapshotInvalidator } : {}),
860
981
  };
982
+ const jobId = enqueueDailyGrowthJob({
983
+ deps: jobDeps,
984
+ tenantId: access.tenantId,
985
+ providerId,
986
+ accounts,
987
+ });
988
+ set.status = 202;
989
+ return { jobId, status: 202 };
861
990
  },
862
991
  )
992
+ .get("/quota/daily-growth/status/:jobId", async ({ request, params, set }) => {
993
+ const access = requireTenantScope(accessResolver(request), "dashboard:read");
994
+ const job = getDailyGrowthJob(params.jobId, access.tenantId);
995
+ if (job === null) {
996
+ set.status = 404;
997
+ return { error: `Job ${params.jobId} not found`, code: "not_found" };
998
+ }
999
+ return job;
1000
+ })
863
1001
  .post("/accounts/:id/checkin", async ({ request, params, set }) => {
864
1002
  const access = requireTenantScope(accessResolver(request), "dashboard:write");
865
1003
  const rows = await db
@@ -929,6 +1067,75 @@ export function registerAccountQuotaTenantRoutes(
929
1067
  message: checkinStateMessage(result),
930
1068
  };
931
1069
  })
1070
+ // Gift grants are an explicit action, not a side effect of a quota read.
1071
+ .post("/accounts/:id/claim-gifts", async ({ request, params, set }) => {
1072
+ const access = requireTenantScope(accessResolver(request), "dashboard:write");
1073
+ const rows = await db
1074
+ .select()
1075
+ .from(providerAccounts)
1076
+ .where(
1077
+ and(eq(providerAccounts.id, params.id), eq(providerAccounts.tenantId, access.tenantId)),
1078
+ )
1079
+ .limit(1);
1080
+ const account = rows[0];
1081
+ if (!account) {
1082
+ set.status = 404;
1083
+ return { error: `Account ${params.id} not found`, code: "not_found" };
1084
+ }
1085
+ if (account.providerId !== ZCODE_START_PLAN_PROVIDER_ID) {
1086
+ set.status = 400;
1087
+ return {
1088
+ error: `Gift plans are only claimable for ${ZCODE_START_PLAN_PROVIDER_ID}`,
1089
+ code: "gifts_unsupported",
1090
+ };
1091
+ }
1092
+ let result: ZcodeGiftResult;
1093
+ try {
1094
+ const credential = await refreshDeps.resolveCredential(account.providerId as ProviderId, account.id);
1095
+ const fetcher = networkBindingFactory
1096
+ ? await dailyCheckinEgressForPass({ db, networkBindingFactory })(account.id, access.tenantId)
1097
+ : globalThis.fetch;
1098
+ result = await claimZcodeGifts({ accountId: account.id, credential, fetcher });
1099
+ } catch {
1100
+ set.status = 502;
1101
+ return {
1102
+ ok: false, status: 502,
1103
+ data: { id: account.id, state: "error", claimed: [], detail: "Gift claim request failed" },
1104
+ message: "Gift claim request failed", code: "gift_claim_failed",
1105
+ };
1106
+ }
1107
+ if (result.claimed.length > 0) {
1108
+ // Cold readers must not resurrect the balance from before the grant.
1109
+ await db.update(providerAccounts).set({ quotaSnapshot: null }).where(
1110
+ and(eq(providerAccounts.id, account.id), eq(providerAccounts.tenantId, access.tenantId)),
1111
+ );
1112
+ await invalidateQuotaCacheForAccount(account.id, redis);
1113
+ await snapshotInvalidator?.invalidate();
1114
+ }
1115
+ if (result.state === "error") {
1116
+ set.status = 502;
1117
+ return {
1118
+ ok: false,
1119
+ status: 502,
1120
+ data: { id: account.id, ...result },
1121
+ message: result.detail ?? "Gift claim failed",
1122
+ code: "gift_claim_failed",
1123
+ };
1124
+ }
1125
+ return {
1126
+ ok: true,
1127
+ status: 200,
1128
+ data: { id: account.id, ...result },
1129
+ message:
1130
+ result.state === "nothing"
1131
+ ? "No gift plan to claim"
1132
+ : result.state === "claimed"
1133
+ ? `Claimed ${result.claimed.join(", ")}`
1134
+ : result.state === "already_claimed"
1135
+ ? "Every gift plan was claimed before"
1136
+ : (result.detail ?? "Claim it in the ZCode app"),
1137
+ };
1138
+ })
932
1139
  .post("/accounts/:id/activity-report", async ({ request, params, set }) => {
933
1140
  const access = requireTenantScope(accessResolver(request), "dashboard:write");
934
1141
  const rows = await db
@@ -977,6 +1184,12 @@ export function registerAccountQuotaTenantRoutes(
977
1184
  // The growth event scores by uid, and only a JWT carries one. An
978
1185
  // opaque API key must fail closed here — reporting it under another
979
1186
  // account's uid would poison someone else's streak.
1187
+ // dynamic-import: B-02 lazy graph — buddy uid decoder on this buddy-only surface.
1188
+ // The buddy-oauth-shared graph is lazy-loaded: the uid decoder is only
1189
+ // needed on this buddy-only surface (B-02).
1190
+ const { buddyAccountUid } = await import(
1191
+ "../../providers/integrations/buddy/buddy-oauth-shared"
1192
+ );
980
1193
  const userId = buddyAccountUid(credential);
981
1194
  if (!userId) {
982
1195
  set.status = 400;
@@ -1043,7 +1256,12 @@ export function registerAccountQuotaTenantRoutes(
1043
1256
  account.providerId as ProviderId,
1044
1257
  account.id,
1045
1258
  );
1046
- const list = await listAccountResetCredits(account.providerId, credential);
1259
+ // Cached per account for a short TTL: every dialog open was hitting the
1260
+ // upstream live. The cache is cleared on a successful redemption, so a
1261
+ // consumed credit is not shown again for the rest of the TTL.
1262
+ const list = await getCachedResetCredits(account.providerId, account.id, () =>
1263
+ listAccountResetCredits(account.providerId, credential),
1264
+ );
1047
1265
  return list ?? { availableCount: 0, credits: [] };
1048
1266
  } catch (err) {
1049
1267
  return { availableCount: 0, credits: [] };
@@ -138,7 +138,7 @@ export async function selectAccountTestEgress(
138
138
  throw new GatewayError(
139
139
  "proxy_pool_unavailable",
140
140
  503,
141
- "No active proxy pool is available because coordination is unavailable.",
141
+ "No active proxy pool is available because coordination is unavailable (request {requestId}). The bouncer stepped out — come back shortly 🚪",
142
142
  { reason: "coordination_unavailable" },
143
143
  "network",
144
144
  );
@@ -159,10 +159,10 @@ export async function selectAccountTestEgress(
159
159
  const status = failure.reason === "at_capacity" ? 429 : 503;
160
160
  const message =
161
161
  failure.reason === "at_capacity"
162
- ? "Every proxy pool for this provider is at its concurrency limit. Retry shortly, or add a pool or raise its capacity."
162
+ ? "Every proxy pool for this provider is at its concurrency limit (request {requestId}). Retry shortly, or add a pool or raise its capacity. The pools are full right now — chill 🌊"
163
163
  : failure.reason === "cooldown"
164
- ? "Every proxy pool for this provider is cooling down after upstream failures. Retry once the cooldown resets."
165
- : "No active proxy pool is configured for this tenant and provider. Add one, or route this provider through direct egress.";
164
+ ? "Every proxy pool for this provider is cooling down after upstream failures (request {requestId}). Retry once the cooldown resets. The proxies are catching their breath — zzz 💤"
165
+ : "No active proxy pool is configured for this tenant and provider (request {requestId}). Add one, or route this provider through direct egress. No bridge to cross — configure a pool first 🏗️";
166
166
  throw new GatewayError(
167
167
  code,
168
168
  status,