cartethyia 2.7.3 → 2.7.4

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 (352) hide show
  1. package/dist/dashboard/assets/{BannedPage-2TJD37Hb.js → BannedPage-ChG5svFb.js} +1 -1
  2. package/dist/dashboard/assets/BannedPage-ChG5svFb.js.gz +0 -0
  3. package/dist/dashboard/assets/{CliToolDetailPage-xefJNRmJ.js → CliToolDetailPage-BIcWQun7.js} +1 -1
  4. package/dist/dashboard/assets/CliToolDetailPage-BIcWQun7.js.gz +0 -0
  5. package/dist/dashboard/assets/{CliToolsPage-Rj9iHQ3F.js → CliToolsPage-Bf2VelDe.js} +1 -1
  6. package/dist/dashboard/assets/CliToolsPage-Bf2VelDe.js.gz +0 -0
  7. package/dist/dashboard/assets/{CombosPage-JEbYJFxw.js → CombosPage-DCgm5g6g.js} +1 -1
  8. package/dist/dashboard/assets/CombosPage-DCgm5g6g.js.gz +0 -0
  9. package/dist/dashboard/assets/ConsoleLogPage-a8mD0QF1.js +1 -0
  10. package/dist/dashboard/assets/ConsoleLogPage-a8mD0QF1.js.gz +0 -0
  11. package/dist/dashboard/assets/CustomizationPage-ggeMSjte.js +1 -0
  12. package/dist/dashboard/assets/CustomizationPage-ggeMSjte.js.gz +0 -0
  13. package/dist/dashboard/assets/HealthEventsModal-DzSWzE_j.js +1 -0
  14. package/dist/dashboard/assets/HealthEventsModal-DzSWzE_j.js.gz +0 -0
  15. package/dist/dashboard/assets/{LoginPage-C4w7vea-.js → LoginPage-U6AKaJcF.js} +1 -1
  16. package/dist/dashboard/assets/LoginPage-U6AKaJcF.js.gz +0 -0
  17. package/dist/dashboard/assets/{ModelPicker-BtPcAfot.js → ModelPicker-BMS2t8BA.js} +1 -1
  18. package/dist/dashboard/assets/ModelPicker-BMS2t8BA.js.gz +0 -0
  19. package/dist/dashboard/assets/OverviewPage-D2D4IiHl.js +1 -0
  20. package/dist/dashboard/assets/OverviewPage-D2D4IiHl.js.gz +0 -0
  21. package/dist/dashboard/assets/ProviderDetailPage-CrNf7j_X.js +5 -0
  22. package/dist/dashboard/assets/ProviderDetailPage-CrNf7j_X.js.gz +0 -0
  23. package/dist/dashboard/assets/ProvidersPage-BSDbquc1.js +1 -0
  24. package/dist/dashboard/assets/ProvidersPage-BSDbquc1.js.gz +0 -0
  25. package/dist/dashboard/assets/ProxyPage-lsrx7NYg.js +9 -0
  26. package/dist/dashboard/assets/ProxyPage-lsrx7NYg.js.gz +0 -0
  27. package/dist/dashboard/assets/QuotaPage-L0skzML8.js +1 -0
  28. package/dist/dashboard/assets/QuotaPage-L0skzML8.js.gz +0 -0
  29. package/dist/dashboard/assets/SettingsPage-CmAbjRHW.js +1 -0
  30. package/dist/dashboard/assets/SettingsPage-CmAbjRHW.js.gz +0 -0
  31. package/dist/dashboard/assets/{SetupPage-BQS0Rx_u.js → SetupPage-f0DE1h0-.js} +1 -1
  32. package/dist/dashboard/assets/SetupPage-f0DE1h0-.js.gz +0 -0
  33. package/dist/dashboard/assets/{SortableList-BAL5npBC.js → SortableList-ClzpwyET.js} +1 -1
  34. package/dist/dashboard/assets/SortableList-ClzpwyET.js.gz +0 -0
  35. package/dist/dashboard/assets/{StudioPage-TP7voAQ0.js → StudioPage-Cq5tW7hW.js} +3 -3
  36. package/dist/dashboard/assets/StudioPage-Cq5tW7hW.js.gz +0 -0
  37. package/dist/dashboard/assets/UsagePage-Dfc9rWQn.js +56 -0
  38. package/dist/dashboard/assets/UsagePage-Dfc9rWQn.js.gz +0 -0
  39. package/dist/dashboard/assets/api-keys-C38iXoO4.js +1 -0
  40. package/dist/dashboard/assets/api-keys-C38iXoO4.js.gz +0 -0
  41. package/dist/dashboard/assets/app-a159k0ub.css +2 -0
  42. package/dist/dashboard/assets/app-a159k0ub.css.gz +0 -0
  43. package/dist/dashboard/assets/assert-DbRA8EG2.js +15 -0
  44. package/dist/dashboard/assets/assert-DbRA8EG2.js.gz +0 -0
  45. package/dist/dashboard/assets/{badge-B_DMpMJN.js → badge-D9CS6dZk.js} +1 -1
  46. package/dist/dashboard/assets/badge-D9CS6dZk.js.gz +0 -0
  47. package/dist/dashboard/assets/{banner-DMrMPmth.js → banner-DympBNq4.js} +1 -1
  48. package/dist/dashboard/assets/banner-DympBNq4.js.gz +0 -0
  49. package/dist/dashboard/assets/{card-Be5Uzamx.js → card-ibRWU_uT.js} +1 -1
  50. package/dist/dashboard/assets/card-ibRWU_uT.js.gz +0 -0
  51. package/dist/dashboard/assets/cli-tools-63qBGaRw.js +1 -0
  52. package/dist/dashboard/assets/cli-tools-63qBGaRw.js.gz +0 -0
  53. package/dist/dashboard/assets/{clipboard-button-DOfrVmsi.js → clipboard-button-DJm-9pz7.js} +1 -1
  54. package/dist/dashboard/assets/clipboard-button-DJm-9pz7.js.gz +0 -0
  55. package/dist/dashboard/assets/{dialog-C9omdjQt.js → dialog-8fiE6tec.js} +1 -1
  56. package/dist/dashboard/assets/dialog-8fiE6tec.js.gz +0 -0
  57. package/dist/dashboard/assets/{drawer-Bm8WKaGY.js → drawer-CqGYeOrd.js} +1 -1
  58. package/dist/dashboard/assets/drawer-CqGYeOrd.js.gz +0 -0
  59. package/dist/dashboard/assets/{entry-q5HwZ8nN.js → entry-BSAsYsmV.js} +1 -1
  60. package/dist/dashboard/assets/entry-BSAsYsmV.js.gz +0 -0
  61. package/dist/dashboard/assets/entry-CiIQULZD.js +4 -0
  62. package/dist/dashboard/assets/entry-CiIQULZD.js.gz +0 -0
  63. package/dist/dashboard/assets/entry-Daz0lJ-W.js +1 -0
  64. package/dist/dashboard/assets/entry-Daz0lJ-W.js.gz +0 -0
  65. package/dist/dashboard/assets/{formatters-BTScrQpe.js → formatters-D-MTJxMr.js} +1 -1
  66. package/dist/dashboard/assets/formatters-D-MTJxMr.js.gz +0 -0
  67. package/dist/dashboard/assets/{github-badge-Orjuzemr.js → github-badge-CPK47xQx.js} +1 -1
  68. package/dist/dashboard/assets/github-badge-CPK47xQx.js.gz +0 -0
  69. package/dist/dashboard/assets/{index-cPrX5vn6.js → index-DBNPOfhV.js} +2 -2
  70. package/dist/dashboard/assets/index-DBNPOfhV.js.gz +0 -0
  71. package/dist/dashboard/assets/{inline-Dvux8w-0.js → inline-BT0zntEr.js} +1 -1
  72. package/dist/dashboard/assets/inline-BT0zntEr.js.gz +0 -0
  73. package/dist/dashboard/assets/{input-CU1Rgf3p.js → input-Da2ZViWg.js} +1 -1
  74. package/dist/dashboard/assets/input-Da2ZViWg.js.gz +0 -0
  75. package/dist/dashboard/assets/{layout-C_7A6H55.js → layout-BXNeLw6M.js} +1 -1
  76. package/dist/dashboard/assets/layout-BXNeLw6M.js.gz +0 -0
  77. package/dist/dashboard/assets/{list-row-CzFvogbj.js → list-row-BycOrrIV.js} +1 -1
  78. package/dist/dashboard/assets/list-row-BycOrrIV.js.gz +0 -0
  79. package/dist/dashboard/assets/live-DCQNZpF7.js +1 -0
  80. package/dist/dashboard/assets/live-DCQNZpF7.js.gz +0 -0
  81. package/dist/dashboard/assets/minimize-2-BTmMTK4o.js +1 -0
  82. package/dist/dashboard/assets/minimize-2-BTmMTK4o.js.gz +0 -0
  83. package/dist/dashboard/assets/{mutation-JJGQm8TD.js → mutation-Rr0TIvcj.js} +1 -1
  84. package/dist/dashboard/assets/mutation-Rr0TIvcj.js.gz +0 -0
  85. package/dist/dashboard/assets/network-9Yj2ZyLo.js +1 -0
  86. package/dist/dashboard/assets/network-9Yj2ZyLo.js.gz +0 -0
  87. package/dist/dashboard/assets/{numbers-BNDZnsUE.js → numbers-CEagj6ZZ.js} +2 -2
  88. package/dist/dashboard/assets/numbers-CEagj6ZZ.js.gz +0 -0
  89. package/dist/dashboard/assets/{query-keys-CLaNz8Xz.js → query-keys-BloKtaXJ.js} +1 -1
  90. package/dist/dashboard/assets/query-keys-BloKtaXJ.js.gz +0 -0
  91. package/dist/dashboard/assets/quota-Caw7wqci.js +1 -0
  92. package/dist/dashboard/assets/quota-Caw7wqci.js.gz +0 -0
  93. package/dist/dashboard/assets/routing-CO9zCUus.js +1 -0
  94. package/dist/dashboard/assets/routing-CO9zCUus.js.gz +0 -0
  95. package/dist/dashboard/assets/{select-B3iTetHN.js → select-BIYIBkMU.js} +2 -2
  96. package/dist/dashboard/assets/select-BIYIBkMU.js.gz +0 -0
  97. package/dist/dashboard/assets/settings-jS3-PNSA.js +1 -0
  98. package/dist/dashboard/assets/settings-jS3-PNSA.js.gz +0 -0
  99. package/dist/dashboard/assets/{stack-KrOrm7JZ.js → stack-DfgnFDWY.js} +1 -1
  100. package/dist/dashboard/assets/stack-DfgnFDWY.js.gz +0 -0
  101. package/dist/dashboard/assets/{state-DLS7IDMy.js → state-CkfdYWel.js} +1 -1
  102. package/dist/dashboard/assets/state-CkfdYWel.js.gz +0 -0
  103. package/dist/dashboard/assets/{switch-42ItvbAs.js → switch-SYm237HG.js} +1 -1
  104. package/dist/dashboard/assets/switch-SYm237HG.js.gz +0 -0
  105. package/dist/dashboard/assets/{useMutation-Dmnfh1Ue.js → useMutation-BQqCRNIi.js} +1 -1
  106. package/dist/dashboard/assets/useMutation-BQqCRNIi.js.gz +0 -0
  107. package/dist/dashboard/index.html +2 -2
  108. package/dist/dashboard/index.html.gz +0 -0
  109. package/dist/dashboard/precompressed-assets.json +55 -54
  110. package/migrations/full-postgres/0027_qoder_identity_genuine_seed.sql +9 -10
  111. package/migrations/full-postgres/0032_add_provider_pool_accounts.sql +53 -0
  112. package/migrations/full-postgres/0033_add_api_key_ban.sql +9 -0
  113. package/migrations/full-postgres/0034_add_api_key_ban_until.sql +7 -0
  114. package/migrations/full-postgres/0035_align_pool_account_status_enum.sql +21 -0
  115. package/migrations/lite-sqlite3/0027_qoder_identity_genuine_seed.sql +9 -10
  116. package/migrations/lite-sqlite3/0032_add_provider_pool_accounts.sql +44 -0
  117. package/migrations/lite-sqlite3/0033_add_api_key_ban.sql +8 -0
  118. package/migrations/lite-sqlite3/0034_add_api_key_ban_until.sql +5 -0
  119. package/migrations/lite-sqlite3/0035_align_pool_account_status_enum.sql +6 -0
  120. package/package.json +2 -1
  121. package/src/boot/app.ts +9 -8
  122. package/src/config/network.ts +7 -3
  123. package/src/console/api-keys/contracts.ts +52 -0
  124. package/src/console/api-keys/routes.ts +93 -4
  125. package/src/console/audit/routes.ts +3 -3
  126. package/src/console/auth/account-reset.ts +4 -4
  127. package/src/console/auth/session.ts +3 -3
  128. package/src/console/backup/contracts.ts +2 -0
  129. package/src/console/backup/export-endpoint.ts +6 -6
  130. package/src/console/backup/routes.ts +3 -3
  131. package/src/console/cli-tools/routes.ts +3 -3
  132. package/src/console/console-router-guards.ts +2 -2
  133. package/src/console/console-router.ts +4 -4
  134. package/src/console/data-management/routes.ts +3 -3
  135. package/src/console/domain-registration.ts +2 -2
  136. package/src/console/observability/contracts.ts +4 -0
  137. package/src/console/observability/live.ts +3 -3
  138. package/src/console/observability/logs.ts +3 -3
  139. package/src/console/observability/performance.ts +3 -3
  140. package/src/console/observability/routes.ts +3 -3
  141. package/src/console/observability/store.ts +16 -16
  142. package/src/console/providers/catalog/contracts.ts +43 -22
  143. package/src/console/providers/catalog/provider-operations.ts +17 -2
  144. package/src/console/providers/catalog/routes.ts +3 -3
  145. package/src/console/providers/catalog/store-helpers.ts +349 -326
  146. package/src/console/providers/catalog/store.ts +1523 -1292
  147. package/src/console/providers/detail/routes.ts +3 -3
  148. package/src/console/providers/oauth/routes.ts +3 -3
  149. package/src/console/quota/account-quota-tenant.ts +26 -1
  150. package/src/console/quota/account-test-egress.ts +4 -4
  151. package/src/console/routing/model/routes.ts +3 -3
  152. package/src/console/routing/pools/contracts.ts +11 -8
  153. package/src/console/routing/pools/operations.ts +14 -7
  154. package/src/console/routing/pools/probe-verdict.ts +8 -3
  155. package/src/console/routing/pools/relay-deploy.ts +9 -9
  156. package/src/console/routing/pools/routes.ts +3 -3
  157. package/src/console/routing/pools/store.ts +21 -1
  158. package/src/console/settings/routes.ts +3 -3
  159. package/src/console/share/share-router.ts +12 -12
  160. package/src/console/share/share-stats.ts +105 -35
  161. package/src/console/shared/read-through-cache.ts +38 -2
  162. package/src/console/updates/routes.ts +7 -4
  163. package/src/network/outbound-fetch.ts +75 -4
  164. package/src/network/pool/resolver.ts +39 -39
  165. package/src/network/pool-cooldown-store.ts +71 -16
  166. package/src/network/pool-health-machine.ts +21 -1
  167. package/src/network/rate-limit-verdict.ts +68 -0
  168. package/src/network/ssrf.ts +4 -4
  169. package/src/observability/event-query.ts +320 -16
  170. package/src/observability/telemetry-status.ts +1 -1
  171. package/src/persistence/db-sqlite.ts +7 -2
  172. package/src/persistence/readiness.ts +18 -6
  173. package/src/persistence/schema.ts +66 -7
  174. package/src/persistence/stores/api-key-store.ts +99 -3
  175. package/src/persistence/stores/telemetry-store.ts +1 -1
  176. package/src/protocol/codecs.ts +6 -6
  177. package/src/protocol/gateway-error.ts +6 -3
  178. package/src/protocol/image-generation.ts +2 -2
  179. package/src/protocol/response/chat.ts +2 -2
  180. package/src/protocol/response/codex.ts +1 -1
  181. package/src/protocol/response/gemini.ts +1 -1
  182. package/src/protocol/response/messages.ts +5 -5
  183. package/src/protocol/response/responses.ts +2 -2
  184. package/src/protocol/sse-decoder.ts +14 -3
  185. package/src/protocol/translation/capabilities.ts +2 -2
  186. package/src/protocol/upstream/send-claude-messages.ts +3 -3
  187. package/src/providers/adapters/base-adapter.ts +1 -1
  188. package/src/providers/adapters/compatible-adapter.ts +2 -2
  189. package/src/providers/authentication/oauth-refresh-service.ts +2 -2
  190. package/src/providers/configured-provider.ts +1 -1
  191. package/src/providers/discovery/probe-phases.ts +2 -2
  192. package/src/providers/discovery/probing-service.ts +12 -12
  193. package/src/providers/integrations/agentrouter/agentrouter.ts +2 -3
  194. package/src/providers/integrations/alibabacp/alibabacp.ts +2 -2
  195. package/src/providers/integrations/anthropic.ts +4 -11
  196. package/src/providers/integrations/antigravity/antigravity.ts +13 -24
  197. package/src/providers/integrations/buddy/buddy-catalog-shared.ts +1 -1
  198. package/src/providers/integrations/buddy/buddy-discovery-shared.ts +37 -6
  199. package/src/providers/integrations/buddy/buddy-identity.ts +22 -1
  200. package/src/providers/integrations/buddy/buddy-media.ts +16 -16
  201. package/src/providers/integrations/buddy/codebuddy/provider.ts +1 -1
  202. package/src/providers/integrations/buddy/workbuddy/provider.ts +1 -1
  203. package/src/providers/integrations/claude/claude-betas.ts +1 -1
  204. package/src/providers/integrations/claude/claude-credentials.ts +1 -1
  205. package/src/providers/integrations/claude/claude-slow-lane-retry.ts +1 -1
  206. package/src/providers/integrations/claude/claude.ts +3 -10
  207. package/src/providers/integrations/cline/cline.ts +1 -1
  208. package/src/providers/integrations/cloudflareai/cloudflareai.ts +4 -7
  209. package/src/providers/integrations/codex/codex-errors.ts +1 -1
  210. package/src/providers/integrations/codex/codex.ts +14 -15
  211. package/src/providers/integrations/commandcode/commandcode.ts +4 -4
  212. package/src/providers/integrations/commandcode/quota.ts +5 -1
  213. package/src/providers/integrations/cursor/cursor-http2.ts +11 -11
  214. package/src/providers/integrations/cursor/cursor.ts +15 -15
  215. package/src/providers/integrations/factory/factory.ts +4 -4
  216. package/src/providers/integrations/gemini.ts +11 -11
  217. package/src/providers/integrations/github/github.ts +6 -6
  218. package/src/providers/integrations/grok/grok.ts +2 -6
  219. package/src/providers/integrations/inferhub.ts +4 -11
  220. package/src/providers/integrations/kimi/kimi.ts +4 -11
  221. package/src/providers/integrations/kiro/kiro.ts +10 -10
  222. package/src/providers/integrations/muse/muse.ts +6 -9
  223. package/src/providers/integrations/perplexity.ts +2 -2
  224. package/src/providers/integrations/qoder/qoder-catalog.ts +47 -9
  225. package/src/providers/integrations/qoder/qoder-checkin.ts +26 -8
  226. package/src/providers/integrations/qoder/qoder-native-identity-store.ts +9 -8
  227. package/src/providers/integrations/qoder/qoder-realm.ts +15 -0
  228. package/src/providers/integrations/qoder/qoder-umid.ts +12 -13
  229. package/src/providers/integrations/qoder/qoder-virtual.ts +2 -2
  230. package/src/providers/integrations/qoder/qoder.ts +188 -22
  231. package/src/providers/integrations/tokenharbor.ts +2 -2
  232. package/src/providers/integrations/trae/trae.ts +6 -9
  233. package/src/providers/integrations/zcode/oauth.ts +1 -1
  234. package/src/providers/operations/provider-catalog-service.ts +4 -4
  235. package/src/providers/operations/provider-credential-service.ts +16 -4
  236. package/src/providers/operations/upstream-deadline.ts +3 -3
  237. package/src/providers/provider-contracts.ts +47 -3
  238. package/src/providers/provider-credential-resolver.ts +1 -1
  239. package/src/providers/provider-registry.ts +4 -4
  240. package/src/providers/quota/quota-contracts.ts +24 -10
  241. package/src/providers/quota/refresh.ts +2 -2
  242. package/src/providers/search/search-provider.ts +5 -5
  243. package/src/security/abuse.ts +4 -4
  244. package/src/security/admission/reasons.ts +17 -17
  245. package/src/security/api-key-auth.ts +4 -4
  246. package/src/shared/coerce.ts +19 -0
  247. package/src/transport/dispatch/attempt-finalize.ts +4 -3
  248. package/src/transport/dispatch/attempt-loop.ts +10 -7
  249. package/src/transport/dispatch/empty-stream.ts +6 -6
  250. package/src/transport/dispatch/generation.ts +9 -9
  251. package/src/transport/dispatch/leases.ts +8 -8
  252. package/src/transport/dispatch/proxy-request.ts +7 -7
  253. package/src/transport/dispatch/responses-compact.ts +11 -11
  254. package/src/transport/dispatch/retry-policy.ts +4 -67
  255. package/src/transport/dispatch/stream-bridge.ts +1 -1
  256. package/src/transport/dispatch/streaming/finalize.ts +9 -8
  257. package/src/transport/dispatch/systemone.ts +8 -8
  258. package/src/transport/dispatch/token-count.ts +9 -9
  259. package/src/transport/dispatch/websearch.ts +6 -6
  260. package/src/transport/drain-endpoint.ts +2 -2
  261. package/src/transport/failure-policy.ts +13 -6
  262. package/src/transport/guards/auth-guard.ts +6 -5
  263. package/src/transport/guards/body-policy.ts +4 -4
  264. package/src/transport/guards/error-lifecycle.ts +18 -3
  265. package/src/transport/guards/guard-errors.ts +7 -3
  266. package/src/transport/guards/headroom-guard.ts +1 -1
  267. package/src/transport/guards/pipeline.ts +6 -6
  268. package/src/transport/guards/readiness-guard.ts +16 -2
  269. package/src/transport/guards/request-context.ts +3 -3
  270. package/src/transport/request/preparer.ts +20 -20
  271. package/src/transport/request/state.ts +4 -7
  272. package/src/transport/routing/route-catalog.ts +97 -2
  273. package/src/transport/routing/route-model.ts +7 -7
  274. package/src/transport/routing/router.ts +2 -2
  275. package/src/transport/shutdown-notice.ts +19 -7
  276. package/src/transport/surface/completion.ts +1 -1
  277. package/src/transport/surface/messages/encode.ts +1 -1
  278. package/dist/dashboard/assets/BannedPage-2TJD37Hb.js.gz +0 -0
  279. package/dist/dashboard/assets/CliToolDetailPage-xefJNRmJ.js.gz +0 -0
  280. package/dist/dashboard/assets/CliToolsPage-Rj9iHQ3F.js.gz +0 -0
  281. package/dist/dashboard/assets/CombosPage-JEbYJFxw.js.gz +0 -0
  282. package/dist/dashboard/assets/ConsoleLogPage-C3xx_inM.js +0 -1
  283. package/dist/dashboard/assets/ConsoleLogPage-C3xx_inM.js.gz +0 -0
  284. package/dist/dashboard/assets/CustomizationPage-Dw306gJU.js +0 -1
  285. package/dist/dashboard/assets/CustomizationPage-Dw306gJU.js.gz +0 -0
  286. package/dist/dashboard/assets/HealthEventsModal-jaBo1TWV.js +0 -1
  287. package/dist/dashboard/assets/HealthEventsModal-jaBo1TWV.js.gz +0 -0
  288. package/dist/dashboard/assets/LoginPage-C4w7vea-.js.gz +0 -0
  289. package/dist/dashboard/assets/ModelPicker-BtPcAfot.js.gz +0 -0
  290. package/dist/dashboard/assets/OverviewPage-CGC5gNs1.js +0 -1
  291. package/dist/dashboard/assets/OverviewPage-CGC5gNs1.js.gz +0 -0
  292. package/dist/dashboard/assets/ProviderDetailPage-DQcthNGt.js +0 -4
  293. package/dist/dashboard/assets/ProviderDetailPage-DQcthNGt.js.gz +0 -0
  294. package/dist/dashboard/assets/ProvidersPage-0OsXRGXe.js +0 -1
  295. package/dist/dashboard/assets/ProvidersPage-0OsXRGXe.js.gz +0 -0
  296. package/dist/dashboard/assets/ProxyPage-DdPc8slb.js +0 -9
  297. package/dist/dashboard/assets/ProxyPage-DdPc8slb.js.gz +0 -0
  298. package/dist/dashboard/assets/QuotaPage-Ci5O4BnH.js +0 -1
  299. package/dist/dashboard/assets/QuotaPage-Ci5O4BnH.js.gz +0 -0
  300. package/dist/dashboard/assets/SettingsPage-CDZjTt87.js +0 -1
  301. package/dist/dashboard/assets/SettingsPage-CDZjTt87.js.gz +0 -0
  302. package/dist/dashboard/assets/SetupPage-BQS0Rx_u.js.gz +0 -0
  303. package/dist/dashboard/assets/SortableList-BAL5npBC.js.gz +0 -0
  304. package/dist/dashboard/assets/StudioPage-TP7voAQ0.js.gz +0 -0
  305. package/dist/dashboard/assets/UsagePage-Cj_fEzhg.js +0 -56
  306. package/dist/dashboard/assets/UsagePage-Cj_fEzhg.js.gz +0 -0
  307. package/dist/dashboard/assets/api-keys-MbI7e7rt.js +0 -1
  308. package/dist/dashboard/assets/api-keys-MbI7e7rt.js.gz +0 -0
  309. package/dist/dashboard/assets/app-B2vyPoII.css +0 -2
  310. package/dist/dashboard/assets/app-B2vyPoII.css.gz +0 -0
  311. package/dist/dashboard/assets/assert-C0YYuZJ4.js +0 -1
  312. package/dist/dashboard/assets/assert-C0YYuZJ4.js.gz +0 -0
  313. package/dist/dashboard/assets/badge-B_DMpMJN.js.gz +0 -0
  314. package/dist/dashboard/assets/banner-DMrMPmth.js.gz +0 -0
  315. package/dist/dashboard/assets/card-Be5Uzamx.js.gz +0 -0
  316. package/dist/dashboard/assets/cli-tools-muFRphDu.js +0 -1
  317. package/dist/dashboard/assets/cli-tools-muFRphDu.js.gz +0 -0
  318. package/dist/dashboard/assets/clipboard-button-DOfrVmsi.js.gz +0 -0
  319. package/dist/dashboard/assets/dialog-C9omdjQt.js.gz +0 -0
  320. package/dist/dashboard/assets/drawer-Bm8WKaGY.js.gz +0 -0
  321. package/dist/dashboard/assets/entry-DS90gUks.js +0 -1
  322. package/dist/dashboard/assets/entry-DS90gUks.js.gz +0 -0
  323. package/dist/dashboard/assets/entry-j40LJotO.js +0 -4
  324. package/dist/dashboard/assets/entry-j40LJotO.js.gz +0 -0
  325. package/dist/dashboard/assets/entry-q5HwZ8nN.js.gz +0 -0
  326. package/dist/dashboard/assets/formatters-BTScrQpe.js.gz +0 -0
  327. package/dist/dashboard/assets/github-badge-Orjuzemr.js.gz +0 -0
  328. package/dist/dashboard/assets/index-cPrX5vn6.js.gz +0 -0
  329. package/dist/dashboard/assets/inline-Dvux8w-0.js.gz +0 -0
  330. package/dist/dashboard/assets/input-CU1Rgf3p.js.gz +0 -0
  331. package/dist/dashboard/assets/layout-C_7A6H55.js.gz +0 -0
  332. package/dist/dashboard/assets/list-row-CzFvogbj.js.gz +0 -0
  333. package/dist/dashboard/assets/live-KaG15HLQ.js +0 -1
  334. package/dist/dashboard/assets/live-KaG15HLQ.js.gz +0 -0
  335. package/dist/dashboard/assets/minimize-2-D-MN8W8a.js +0 -1
  336. package/dist/dashboard/assets/minimize-2-D-MN8W8a.js.gz +0 -0
  337. package/dist/dashboard/assets/mutation-JJGQm8TD.js.gz +0 -0
  338. package/dist/dashboard/assets/numbers-BNDZnsUE.js.gz +0 -0
  339. package/dist/dashboard/assets/query-keys-CLaNz8Xz.js.gz +0 -0
  340. package/dist/dashboard/assets/quota-DZGyp0N5.js +0 -1
  341. package/dist/dashboard/assets/quota-DZGyp0N5.js.gz +0 -0
  342. package/dist/dashboard/assets/routing-BEH32QOC.js +0 -1
  343. package/dist/dashboard/assets/routing-BEH32QOC.js.gz +0 -0
  344. package/dist/dashboard/assets/select-B3iTetHN.js.gz +0 -0
  345. package/dist/dashboard/assets/settings-Dt3Eqbnq.js +0 -1
  346. package/dist/dashboard/assets/settings-Dt3Eqbnq.js.gz +0 -0
  347. package/dist/dashboard/assets/stack-KrOrm7JZ.js.gz +0 -0
  348. package/dist/dashboard/assets/state-DLS7IDMy.js.gz +0 -0
  349. package/dist/dashboard/assets/switch-42ItvbAs.js.gz +0 -0
  350. package/dist/dashboard/assets/useMutation-Dmnfh1Ue.js.gz +0 -0
  351. /package/dist/dashboard/assets/{app-wvwCi4Eh.js → app-BayTTy01.js} +0 -0
  352. /package/dist/dashboard/assets/{app-wvwCi4Eh.js.gz → app-BayTTy01.js.gz} +0 -0
@@ -2,7 +2,7 @@
2
2
  //
3
3
  // Owns validation, CRUD operations, and route wiring through the ApiKeyStore.
4
4
 
5
- import { Elysia, t } from "elysia";
5
+ import { Elysia, t, type AnyElysia } from "elysia";
6
6
  import { randomBytes, randomUUID } from "node:crypto";
7
7
  import { decryptCredentialToString, encryptCredential } from "../../security/crypto";
8
8
  import { invalidateApiKeyCache } from "../../security/api-key-auth";
@@ -12,7 +12,7 @@ import type { AccessDecision } from "../../security/access-control";
12
12
  import { ConsoleDomainError, errorResponse, requireTenantScope } from "../shared/errors";
13
13
  import { literalUnion } from "../shared/elysia-schema";
14
14
  import { API_KEY_MODES, API_KEY_MODEL_ACCESS_MODES, type ShareLinkKind } from "../../persistence/schema";
15
- import type { ApiKeyConfig, ApiKeyResponse, UpdateApiKeyResponse } from "./contracts";
15
+ import type { ApiKeyConfig, ApiKeyResponse, BanApiKeyRequest, UpdateApiKeyResponse } from "./contracts";
16
16
  import type {
17
17
  ApiKeyPatch,
18
18
  ApiKeyRecord,
@@ -20,6 +20,8 @@ import type {
20
20
  SharedChildrenPageOptions,
21
21
  } from "../../persistence/stores/api-key-store";
22
22
  import {
23
+ BAN_DURATION_CHOICES,
24
+ DEFAULT_BAN_MINUTES,
23
25
  generateApiKeySecret,
24
26
  isDefaultGatewayApiKey,
25
27
  parseSharePopupImage,
@@ -775,6 +777,69 @@ export function createApiKeyOperations(config: ApiKeyConfig) {
775
777
  });
776
778
  return { success: true };
777
779
  },
780
+ async banKey(
781
+ access: AccessDecision | undefined,
782
+ keyId: string,
783
+ request: BanApiKeyRequest,
784
+ ): Promise<ApiKeyResponse> {
785
+ const authorized = requireTenantScope(access, "dashboard:write");
786
+ const reason = request.reason.trim();
787
+ if (reason.length === 0)
788
+ throw new ConsoleDomainError("invalid_request", 400, "reason is required");
789
+ // Parse the duration choice. `null` is permanent; absent defaults to one
790
+ // hour. Anything not on the offered list is rejected rather than clamped —
791
+ // clamping would answer a request for 90 days with a week and report
792
+ // success.
793
+ const chosenMinutes = request.minutes === undefined ? DEFAULT_BAN_MINUTES : request.minutes;
794
+ const allowed = new Set(BAN_DURATION_CHOICES.map((choice) => choice.minutes));
795
+ if (!allowed.has(chosenMinutes)) {
796
+ throw new ConsoleDomainError(
797
+ "invalid_request",
798
+ 400,
799
+ "Unsupported ban duration. Choose one of the offered durations.",
800
+ );
801
+ }
802
+ const bannedUntil = chosenMinutes === null ? null : new Date(Date.now() + chosenMinutes * 60_000);
803
+ const current = await config.store.get(authorized.tenantId, keyId);
804
+ if (!current || current.revokedAt !== undefined)
805
+ throw new ConsoleDomainError("key_not_found", 404, "Key not found");
806
+ const banned = await config.store.ban(authorized.tenantId, keyId, reason, bannedUntil);
807
+ if (!banned) throw new ConsoleDomainError("key_not_found", 404, "Key not found");
808
+ // A banned child key does not affect its share template or sibling keys:
809
+ // `store.ban` only turns off the one row named by `keyId`, and the auth
810
+ // path rejects per key hash. The template keeps issuing working children.
811
+ // A banned key must leave the auth cache for every process at once.
812
+ invalidateApiKeyCache();
813
+ await config.auditSink?.record({
814
+ access: authorized,
815
+ action: "api_key.banned",
816
+ target: keyId,
817
+ detail: { reason, ...(bannedUntil === null ? { permanent: true } : { bannedUntil: bannedUntil.toISOString() }) },
818
+ });
819
+ const record = await config.store.get(authorized.tenantId, keyId);
820
+ if (!record) throw new ConsoleDomainError("key_not_found", 404, "Key not found");
821
+ return sanitizeApiKeyResponse(record);
822
+ },
823
+ async unbanKey(
824
+ access: AccessDecision | undefined,
825
+ keyId: string,
826
+ ): Promise<ApiKeyResponse> {
827
+ const authorized = requireTenantScope(access, "dashboard:write");
828
+ const current = await config.store.get(authorized.tenantId, keyId);
829
+ if (!current || current.revokedAt !== undefined)
830
+ throw new ConsoleDomainError("key_not_found", 404, "Key not found");
831
+ const unbanned = await config.store.unban(authorized.tenantId, keyId);
832
+ if (!unbanned) throw new ConsoleDomainError("key_not_found", 404, "Key not found");
833
+ invalidateApiKeyCache();
834
+ await config.auditSink?.record({
835
+ access: authorized,
836
+ action: "api_key.unbanned",
837
+ target: keyId,
838
+ });
839
+ const record = await config.store.get(authorized.tenantId, keyId);
840
+ if (!record) throw new ConsoleDomainError("key_not_found", 404, "Key not found");
841
+ return sanitizeApiKeyResponse(record);
842
+ },
778
843
  };
779
844
  return operations;
780
845
  }
@@ -830,7 +895,7 @@ function jsonNull(): Response {
830
895
  });
831
896
  }
832
897
  /** Creates tenant-bound API-key routes with request-local authorization. */
833
- export function createApiKeyRoutes(config: ApiKeyConfig): Elysia {
898
+ export function createApiKeyRoutes(config: ApiKeyConfig): AnyElysia {
834
899
  const factory = createApiKeyOperations(config);
835
900
  return new Elysia({ prefix: "/api-keys" })
836
901
  .get("/", async ({ request, set }) => {
@@ -950,6 +1015,30 @@ export function createApiKeyRoutes(config: ApiKeyConfig): Elysia {
950
1015
  return errorResponse(error, set, "API-key operation failed");
951
1016
  }
952
1017
  })
1018
+ .post(
1019
+ "/:keyId/ban",
1020
+ {
1021
+ body: t.Object({
1022
+ reason: t.String(),
1023
+ reasonLabel: t.Optional(t.String()),
1024
+ minutes: t.Optional(t.Union([t.Number({ minimum: 1 }), t.Null()])),
1025
+ }),
1026
+ },
1027
+ async ({ request, params, body, set }) => {
1028
+ try {
1029
+ return await factory.banKey(config.accessResolver(request), params.keyId, body);
1030
+ } catch (error) {
1031
+ return errorResponse(error, set, "API-key operation failed");
1032
+ }
1033
+ },
1034
+ )
1035
+ .post("/:keyId/unban", async ({ request, params, set }) => {
1036
+ try {
1037
+ return await factory.unbanKey(config.accessResolver(request), params.keyId);
1038
+ } catch (error) {
1039
+ return errorResponse(error, set, "API-key operation failed");
1040
+ }
1041
+ })
953
1042
  .get("/:keyId/share", async ({ request, params, set }) => {
954
1043
  try {
955
1044
  const share = await factory.getShare(config.accessResolver(request), params.keyId, {
@@ -988,5 +1077,5 @@ export function createApiKeyRoutes(config: ApiKeyConfig): Elysia {
988
1077
  } catch (error) {
989
1078
  return errorResponse(error, set, "API-key operation failed");
990
1079
  }
991
- }) as unknown as Elysia;
1080
+ });
992
1081
  }
@@ -1,4 +1,4 @@
1
- import { Elysia, t } from "elysia";
1
+ import { Elysia, t, type AnyElysia } from "elysia";
2
2
  import { errorResponse, requireGlobalAdmin, requireTenantScope } from "../shared/errors";
3
3
  import { parseQueryLimit } from "../shared/query";
4
4
  import type { AuditRoutesConfig } from "./contracts";
@@ -10,7 +10,7 @@ const listQuery = t.Object({
10
10
  actor: t.Optional(t.String()),
11
11
  });
12
12
 
13
- export function createAuditRoutes(config: AuditRoutesConfig): Elysia {
13
+ export function createAuditRoutes(config: AuditRoutesConfig): AnyElysia {
14
14
  return new Elysia().get("/audit", { query: listQuery }, async ({ request, query, set }) => {
15
15
  try {
16
16
  const resolved = config.accessResolver(request);
@@ -28,5 +28,5 @@ export function createAuditRoutes(config: AuditRoutesConfig): Elysia {
28
28
  } catch (e) {
29
29
  return errorResponse(e, set, "Audit read failed");
30
30
  }
31
- }) as unknown as Elysia;
31
+ });
32
32
  }
@@ -42,12 +42,12 @@ export function createConsoleAccountResetHandler(
42
42
  return async ({ request, body }) => {
43
43
  if (!isLoopbackPeer(deps.resolvePeerAddress(request)))
44
44
  throw new GatewayError(
45
- "invalid_request",
45
+ "policy_rejected",
46
46
  403,
47
- "console account reset is only available from loopback",
47
+ "console account reset is only available from loopback (request {requestId}). This operation is only allowed from a trusted loopback connection — no hard feelings 🫂",
48
48
  );
49
49
  if (!tokenMatches(request.headers.get("x-drain-token"), deps.token))
50
- throw new GatewayError("invalid_request", 401, "invalid reset token");
50
+ throw new GatewayError("authentication_failed", 401, "invalid reset token (request {requestId}). Wrong key, right door — check the token 🔑");
51
51
  const confirm =
52
52
  body !== null && typeof body === "object" && "confirm" in body
53
53
  ? body.confirm
@@ -56,7 +56,7 @@ export function createConsoleAccountResetHandler(
56
56
  throw new GatewayError(
57
57
  "invalid_request",
58
58
  400,
59
- `send {"confirm":"${CONFIRMATION}"} to confirm; this deletes every console account`,
59
+ `send {"confirm":"${CONFIRMATION}"} to confirm (request {requestId}); this deletes every console account. Make sure you mean it — there's no undo 🫂`,
60
60
  );
61
61
 
62
62
  const removed = await deps.resetConsoleAccount();
@@ -1,5 +1,5 @@
1
1
  import { asCookie, clearCsrfCookie, newCsrfToken, setCsrfCookie } from "../../security/csrf";
2
- import { Elysia, t } from "elysia";
2
+ import { Elysia, t, type AnyElysia } from "elysia";
3
3
  import { eq } from "drizzle-orm";
4
4
  import { isRecord } from "../../protocol/codecs";
5
5
  import { userRecord, returningRows, assertMutationApplied } from "./row-coercion";
@@ -217,7 +217,7 @@ export function createConsoleAuthRoutes(
217
217
  cookiePolicy: SessionCookiePolicy = defaultSessionCookiePolicy,
218
218
  trustedProxyBoundary: TrustedProxyBoundary = { mode: "disabled" },
219
219
  resolvePeerAddress: (request: Request) => string | undefined = () => undefined,
220
- ): Elysia {
220
+ ): AnyElysia {
221
221
  const app = new Elysia({ prefix: "/auth" });
222
222
  const policy = cookiePolicy;
223
223
  const database = db;
@@ -532,5 +532,5 @@ export function createConsoleAuthRoutes(
532
532
  },
533
533
  );
534
534
 
535
- return app as unknown as Elysia;
535
+ return app;
536
536
  }
@@ -33,6 +33,7 @@ import {
33
33
  poolRoutingSettings,
34
34
  providerAccounts,
35
35
  providerOauthStates,
36
+ providerPoolAccounts,
36
37
  providerRoutingSettings,
37
38
  providers,
38
39
  shareLinks,
@@ -96,6 +97,7 @@ export const CONFIG_TABLES = [
96
97
  models,
97
98
  providerRoutingSettings,
98
99
  providerAccounts,
100
+ providerPoolAccounts,
99
101
  poolRoutingSettings,
100
102
  networkPools,
101
103
  providers,
@@ -52,20 +52,20 @@ export function createBackupExportHandler(
52
52
  // came from, the second is the credential it carried — and `invalid_request`
53
53
  // told an operator to fix a body that was never the problem.
54
54
  if (!isLoopbackPeer(deps.resolvePeerAddress(request)))
55
- throw new GatewayError("policy_rejected", 403, "backup export is only available from loopback");
55
+ throw new GatewayError("policy_rejected", 403, "backup export is only available from loopback (request {requestId}). This operation is only allowed from a trusted loopback connection — no hard feelings 🫂");
56
56
  if (!tokenMatches(request.headers.get("x-drain-token"), deps.token))
57
- throw new GatewayError("authentication_failed", 401, "invalid export token");
57
+ throw new GatewayError("authentication_failed", 401, "invalid export token (request {requestId}). Wrong key, right door — check the token 🔑");
58
58
 
59
59
  const directory =
60
60
  body !== null && typeof body === "object" && "directory" in body
61
61
  ? body.directory
62
62
  : undefined;
63
63
  if (directory !== undefined && typeof directory !== "string")
64
- throw new GatewayError("invalid_request", 400, "directory must be a string");
64
+ throw new GatewayError("invalid_request", 400, "directory must be a string (request {requestId}). Check the shape of what you sent — then resend 🪞");
65
65
 
66
66
  const tenantId = await deps.resolveTenantId();
67
67
  if (tenantId === null)
68
- throw new GatewayError("invalid_request", 409, "no tenant exists; run setup first");
68
+ throw new GatewayError("invalid_request", 409, "no tenant exists; run setup first (request {requestId}). Nothing here but dust — run setup first 🌙");
69
69
 
70
70
  // One gzip pass over the streamed document: a tenant with hundreds of
71
71
  // thousands of rows is read page by page and only the compressed bytes
@@ -83,9 +83,9 @@ export function createBackupExportHandler(
83
83
  writeFileSync(path, gzipped);
84
84
  } catch (error) {
85
85
  throw new GatewayError(
86
- "invalid_request",
86
+ "internal_error",
87
87
  500,
88
- `could not write ${path}: ${error instanceof Error ? error.message : "unknown error"}`,
88
+ `could not write ${path}: ${error instanceof Error ? error.message : "unknown error"} (request {requestId}). Even we have bad days — retry, and quote the request id if it persists 🐻`,
89
89
  );
90
90
  }
91
91
 
@@ -14,7 +14,7 @@
14
14
  * The body bound is enforced here, before the JSON parse, because the whole
15
15
  * point of the limit is to not buffer an unbounded file.
16
16
  */
17
- import { Elysia, t } from "elysia";
17
+ import { Elysia, t, type AnyElysia } from "elysia";
18
18
  import type { ConsoleAccessResolver } from "../auth/access";
19
19
  import { invalidateApiKeyCache } from "../../security/api-key-auth";
20
20
  import { invalidatePublicModels } from "../providers/catalog/public-model-store";
@@ -139,7 +139,7 @@ function payloadDocument(chunks: AsyncGenerator<string, void, void>): ReadableSt
139
139
  });
140
140
  }
141
141
 
142
- export function createBackupRoutes(config: BackupRoutesConfig): Elysia {
142
+ export function createBackupRoutes(config: BackupRoutesConfig): AnyElysia {
143
143
  return new Elysia({ prefix: "/backup" })
144
144
  .get("/export", { query: exportQuery }, async ({ request, query, set }) => {
145
145
  try {
@@ -304,5 +304,5 @@ export function createBackupRoutes(config: BackupRoutesConfig): Elysia {
304
304
  } catch (error) {
305
305
  return errorResponse(error, set, "Backup inspection failed");
306
306
  }
307
- }) as unknown as Elysia;
307
+ });
308
308
  }
@@ -1,6 +1,6 @@
1
1
  import type { ConsoleAccessResolver } from "../auth/access";
2
2
  import type { AuditSink } from "../audit/contracts";
3
- import { Elysia, t } from "elysia";
3
+ import { Elysia, t, type AnyElysia } from "elysia";
4
4
  import { errorResponse, requireTenantScope } from "../shared/errors";
5
5
  import type { CliToolService } from "./service";
6
6
  import type { ApplyInput, CliMappingInput, CliModelMapping } from "./contracts";
@@ -143,7 +143,7 @@ const mappingBody = t.Object({
143
143
  ),
144
144
  });
145
145
 
146
- export function createCliToolsRoutes(config: CliToolsRoutesConfig): Elysia {
146
+ export function createCliToolsRoutes(config: CliToolsRoutesConfig): AnyElysia {
147
147
  const { service, accessResolver, auditSink, snapshotInvalidator } = config;
148
148
 
149
149
  return new Elysia({ prefix: "/cli-tools" })
@@ -335,5 +335,5 @@ export function createCliToolsRoutes(config: CliToolsRoutesConfig): Elysia {
335
335
  } catch (e) {
336
336
  return errorResponse(e, set, "CLI tool operation failed");
337
337
  }
338
- }) as unknown as Elysia;
338
+ });
339
339
  }
@@ -35,7 +35,7 @@ export function createConsoleCsrfMiddleware(): Elysia {
35
35
  // CSRF enforcement applies exactly when a session cookie is present.
36
36
  if (!token) return;
37
37
  if (!isCsrfValid(request))
38
- throw new GatewayError("invalid_request", 403, "CSRF validation failed");
38
+ throw new GatewayError("policy_rejected", 403, "CSRF validation failed (request {requestId}). Not allowed by policy — no hard feelings 🫂");
39
39
  })
40
40
  .as("plugin");
41
41
  }
@@ -102,7 +102,7 @@ export function createConsoleMutationLimiterMiddleware(): Elysia {
102
102
  ? Math.ceil(CONSOLE_MUTATION_WINDOW_MS / 1000)
103
103
  : Math.max(1, Math.ceil((oldest + CONSOLE_MUTATION_WINDOW_MS - now) / 1000));
104
104
  set.headers["retry-after"] = String(retryAfterSeconds);
105
- throw new GatewayError("quota_exceeded", 429, "Console mutation rate limit exceeded");
105
+ throw new GatewayError("rate_limited", 429, "Console mutation rate limit exceeded (request {requestId}). Retry shortly. You've maxed this window — pace yourself ⏳");
106
106
  }
107
107
  hits.push(now);
108
108
  consoleMutationHits.set(key, hits);
@@ -4,7 +4,7 @@
4
4
  * composition time; concrete Drizzle stores are the defaults, so this file
5
5
  * is the single place that knows them.
6
6
  */
7
- import { Elysia } from "elysia";
7
+ import { Elysia, type AnyElysia } from "elysia";
8
8
  import { log } from "../observability/logger";
9
9
  import { resolveConsoleAccess, resolveConsoleUser } from "./auth/session-resolver";
10
10
  import { ConsoleCredentialService } from "./auth/credentials";
@@ -100,7 +100,7 @@ function readApiKeyBearer(request: Request): string | undefined {
100
100
  return match?.[1];
101
101
  }
102
102
 
103
- export function createConsoleRouter(deps: ConsoleApiCompositionDeps): Elysia {
103
+ export function createConsoleRouter(deps: ConsoleApiCompositionDeps): AnyElysia {
104
104
  const { db, routeSnapshotService, poolSelector, telemetryBuffer, redis } = deps;
105
105
  /**
106
106
  * Per-request cache: `beforeHandle` resolves the session asynchronously, and
@@ -207,7 +207,7 @@ export function createConsoleRouter(deps: ConsoleApiCompositionDeps): Elysia {
207
207
  return user === null ? null : { passwordHash: user.passwordHash };
208
208
  },
209
209
  };
210
- registerConsoleDomains(console as unknown as Elysia, ctx);
210
+ registerConsoleDomains(console, ctx);
211
211
  // Compress the JSON control plane on the way out.
212
212
  //
213
213
  // `wrap` is used rather than a lifecycle hook because this Elysia beta does
@@ -229,5 +229,5 @@ export function createConsoleRouter(deps: ConsoleApiCompositionDeps): Elysia {
229
229
  gzipResponse(request, response),
230
230
  ),
231
231
  );
232
- return console as unknown as Elysia;
232
+ return console;
233
233
  }
@@ -1,4 +1,4 @@
1
- import { Elysia } from "elysia";
1
+ import { Elysia, type AnyElysia } from "elysia";
2
2
  import { t } from "elysia";
3
3
  import { errorResponse, requireAnyScope } from "../shared/errors";
4
4
  import type { AccessDecision } from "../../security/access-control";
@@ -39,7 +39,7 @@ export function createDataManagementRoutes(
39
39
  } | undefined;
40
40
  readonly flusher?: { flush(): Promise<void> } | undefined;
41
41
  },
42
- ): Elysia {
42
+ ): AnyElysia {
43
43
  const operations = createDataManagementOperations(config);
44
44
 
45
45
  return new Elysia({ prefix: "/data-management" })
@@ -101,5 +101,5 @@ export function createDataManagementRoutes(
101
101
  } catch (error) {
102
102
  return errorResponse(error, set, "Purge failed");
103
103
  }
104
- }) as unknown as Elysia;
104
+ });
105
105
  }
@@ -1,4 +1,4 @@
1
- import { Elysia } from "elysia";
1
+ import { type AnyElysia } from "elysia";
2
2
  import { ConsoleDomainError } from "./shared/errors";
3
3
  import { createCliToolsRoutes } from "./cli-tools/routes";
4
4
  import { createAccountQuotaRoutes } from "./quota/account-quota";
@@ -133,7 +133,7 @@ import type { ProbeOutboundBinding } from "../providers/discovery/probing-servic
133
133
 
134
134
 
135
135
  export function registerConsoleDomains(
136
- console: Elysia<any, any, any, any, any, any, any, any>,
136
+ console: AnyElysia,
137
137
  ctx: ConsoleDomainContext,
138
138
  ): void {
139
139
  const observabilityStore = new DrizzleObservabilityStore(ctx.db, ctx.redis);
@@ -191,6 +191,10 @@ export interface UsageRequestItem {
191
191
  apiKeyId?: string;
192
192
  userAgent?: string;
193
193
  clientName?: string;
194
+ /** The proxy pool that carried this request, when one was used. */
195
+ networkPoolId?: string;
196
+ /** Operator-facing label of the pool; absent when the pool is gone. */
197
+ networkPoolLabel?: string;
194
198
  estimatedCost?: number;
195
199
  /** Provider-billed credits; absent when the upstream reported no credit field. */
196
200
  creditUsed?: number;
@@ -7,7 +7,7 @@
7
7
  // Every endpoint requires `dashboard:read`. The global request count is
8
8
  // process-level; pool usage and health are filtered to the caller's tenant.
9
9
 
10
- import { Elysia } from "elysia";
10
+ import { Elysia, type AnyElysia } from "elysia";
11
11
  import { errorResponse, requireScope } from "../shared/errors";
12
12
  import type { ConsoleAccessResolver } from "../auth/access";
13
13
  /**
@@ -86,7 +86,7 @@ function withPoolBytes<T extends { poolId: string; currentInflight?: number }>(
86
86
  });
87
87
  }
88
88
 
89
- export function createLiveRoutes(config: LiveConfig): Elysia {
89
+ export function createLiveRoutes(config: LiveConfig): AnyElysia {
90
90
  return new Elysia()
91
91
  .get("/live/requests/stream", ({ request, set }) => {
92
92
  try {
@@ -176,5 +176,5 @@ export function createLiveRoutes(config: LiveConfig): Elysia {
176
176
  };
177
177
  }),
178
178
  );
179
- }) as unknown as Elysia;
179
+ });
180
180
  }
@@ -8,7 +8,7 @@
8
8
  // metadata and their args are redacted at the source, the same audience
9
9
  // that already reads request/response bodies on Usage.
10
10
 
11
- import { Elysia, t } from "elysia";
11
+ import { Elysia, t, type AnyElysia } from "elysia";
12
12
  import { ConsoleDomainError, errorResponse, requireScope } from "../shared/errors";
13
13
  import { parseQueryLimit } from "../shared/query";
14
14
  import type { ConsoleAccessResolver } from "../auth/access";
@@ -37,7 +37,7 @@ const logsQuery = t.Object({
37
37
  limit: t.Optional(t.String()),
38
38
  });
39
39
 
40
- export function createLogRoutes(config: LogsConfig): Elysia {
40
+ export function createLogRoutes(config: LogsConfig): AnyElysia {
41
41
  const readLogs = (access: AccessDecision | undefined, level?: string, limitRaw?: string) => {
42
42
  requireScope(access, "dashboard:read");
43
43
  if (level !== undefined && !isLogLevel(level)) {
@@ -83,5 +83,5 @@ export function createLogRoutes(config: LogsConfig): Elysia {
83
83
  });
84
84
  }),
85
85
  );
86
- }) as unknown as Elysia;
86
+ });
87
87
  }
@@ -5,12 +5,12 @@
5
5
  // this instance's own module graph and egress), so the route is guarded by
6
6
  // `platform:admin` like the other instance-level operations.
7
7
 
8
- import { Elysia } from "elysia";
8
+ import { Elysia, type AnyElysia } from "elysia";
9
9
  import { errorResponse, requireGlobalAdmin } from "../shared/errors";
10
10
  import { performanceMetricsSnapshot } from "../../observability/performance-metrics";
11
11
  import type { PerformanceConfig } from "./performance-contracts";
12
12
 
13
- export function createPerformanceRoutes(config: PerformanceConfig): Elysia {
13
+ export function createPerformanceRoutes(config: PerformanceConfig): AnyElysia {
14
14
  return new Elysia()
15
15
  .get("/system/performance", ({ request, set }) => {
16
16
  try {
@@ -19,5 +19,5 @@ export function createPerformanceRoutes(config: PerformanceConfig): Elysia {
19
19
  } catch (e) {
20
20
  return errorResponse(e, set, "Performance operation failed");
21
21
  }
22
- }) as unknown as Elysia;
22
+ });
23
23
  }
@@ -1,4 +1,4 @@
1
- import { Elysia, t } from "elysia";
1
+ import { Elysia, t, type AnyElysia } from "elysia";
2
2
  import { ConsoleDomainError, consoleErrorHandler } from "../shared/errors";
3
3
  import { USAGE_DIMENSIONS, type UsageDimension } from "./usage-dimensions";
4
4
  import { createObservabilityOperations, type ObservabilityConfig } from "./contracts";
@@ -18,7 +18,7 @@ const telemetryDetailQuery = t.Object({
18
18
  includePayload: t.Optional(t.String()),
19
19
  createdAt: t.Optional(t.String()),
20
20
  });
21
- export function createObservabilityRoutes(config: ObservabilityConfig): Elysia {
21
+ export function createObservabilityRoutes(config: ObservabilityConfig): AnyElysia {
22
22
  const factory = createObservabilityOperations(config);
23
23
  return new Elysia()
24
24
  .error(consoleErrorHandler("Observability operation failed"))
@@ -114,5 +114,5 @@ export function createObservabilityRoutes(config: ObservabilityConfig): Elysia {
114
114
  query.createdAt,
115
115
  );
116
116
  },
117
- ) as unknown as Elysia;
117
+ );
118
118
  }
@@ -7,11 +7,8 @@ import { type TelemetryEventRecord } from "../../observability/event-log";
7
7
  import {
8
8
  breakdownTelemetry,
9
9
  chartTelemetry,
10
- healthTelemetry,
11
10
  queryTelemetryEvents as queryTelemetryEventPage,
12
- summarizeHealthPerformance,
13
- summarizeUsagePerformanceSql,
14
- summarizeTelemetry,
11
+ summarizeUsageWithPerformance,
15
12
  } from "../../observability/event-query";
16
13
  import { clientNameFromUserAgent } from "../../observability/client-name";
17
14
 
@@ -145,6 +142,7 @@ function mapUsageRequestItem(
145
142
  : {}),
146
143
  ...(event.endpoint ? { endpoint: event.endpoint } : {}),
147
144
  ...(event.apiKeyId ? { apiKeyId: event.apiKeyId } : {}),
145
+ ...(event.networkPoolId ? { networkPoolId: event.networkPoolId } : {}),
148
146
  ...(event.userAgent ? { userAgent: event.userAgent } : {}),
149
147
  ...(event.userAgent ? { clientName: clientNameFromUserAgent(event.userAgent) } : {}),
150
148
  ...(event.clientIp
@@ -326,11 +324,10 @@ export class DrizzleObservabilityStore implements ObservabilityStore {
326
324
  // cost on the dashboard. `healthTelemetry` returns the totals and the
327
325
  // database computes the percentiles.
328
326
  const since = new Date(Date.now() - HEALTH_WINDOW_MS);
329
- const totals = await healthTelemetry(this.db, tenantId, since);
330
- const performance = await summarizeHealthPerformance(this.db, tenantId, since);
327
+ const { summary: totals, performance } = await summarizeUsageWithPerformance(this.db, tenantId, since);
331
328
  total = totals.requests;
332
329
  errors = totals.errors;
333
- avg = performance.latencyAvgMs === null ? 0 : Math.round(performance.latencyAvgMs);
330
+ avg = Math.round(performance.avgDurationMs ?? 0);
334
331
  p95 = performance.latencyP95Ms ?? 0;
335
332
  p99 = performance.latencyP99Ms ?? 0;
336
333
  const inputTokens = totals.inputTokens;
@@ -417,8 +414,8 @@ export class DrizzleObservabilityStore implements ObservabilityStore {
417
414
  // Totals AND the top-model/top-provider counts come from SQL: the old
418
415
  // shape parsed the whole retained window into an array to count two
419
416
  // dimensions in JavaScript.
420
- const [summary, models, providers] = await Promise.all([
421
- summarizeTelemetry(this.db, tenantId, since),
417
+ const [{ summary }, models, providers] = await Promise.all([
418
+ summarizeUsageWithPerformance(this.db, tenantId, since),
422
419
  breakdownTelemetry(this.db, tenantId, "model", since),
423
420
  breakdownTelemetry(this.db, tenantId, "provider", since),
424
421
  ]);
@@ -468,12 +465,11 @@ export class DrizzleObservabilityStore implements ObservabilityStore {
468
465
  private async computeSummary(tenantId: string, period: string): Promise<UsageSummaryResponse> {
469
466
  const since = this.periodSince(period);
470
467
  // Totals, status breakdown, and latency percentiles all computed in SQL.
471
- // This used to parse the whole retained window into JavaScript to sum six
472
- // counters and sort a latency array.
473
- const [summary, statuses, performance] = await Promise.all([
474
- summarizeTelemetry(this.db, tenantId, since),
468
+ // The summary totals and performance figures come from ONE combined window
469
+ // scan (one percentile pass), not two independent scans.
470
+ const [{ summary, performance }, statuses] = await Promise.all([
471
+ summarizeUsageWithPerformance(this.db, tenantId, since),
475
472
  breakdownTelemetry(this.db, tenantId, "status", since),
476
- summarizeUsagePerformanceSql(this.db, tenantId, since),
477
473
  ]);
478
474
  const inputTokens = summary.inputTokens;
479
475
  const cachedTokens = summary.cachedInputTokens;
@@ -655,7 +651,7 @@ export class DrizzleObservabilityStore implements ObservabilityStore {
655
651
  }
656
652
 
657
653
  private async computeCache(tenantId: string, period: string): Promise<UsageCacheResponse> {
658
- const summary = await summarizeTelemetry(this.db, tenantId, this.periodSince(period));
654
+ const { summary } = await summarizeUsageWithPerformance(this.db, tenantId, this.periodSince(period));
659
655
  const inputTokens = summary.inputTokens;
660
656
  const outputTokens = summary.outputTokens;
661
657
  const cachedTokens = summary.cachedInputTokens;
@@ -766,7 +762,11 @@ export class DrizzleObservabilityStore implements ObservabilityStore {
766
762
  const item = mapUsageRequestItem(event, hideClientIp);
767
763
  const keyLabel = event.apiKeyId ? keyLabels?.get(event.apiKeyId) : undefined;
768
764
  const labeled = keyLabel === undefined ? item : { ...item, apiKeyLabel: keyLabel };
769
- const presented = { ...labeled, proxy };
765
+ const presented = {
766
+ ...labeled,
767
+ proxy,
768
+ ...(event.networkPoolId ? { networkPoolLabel: proxy } : {}),
769
+ };
770
770
  // Filter the payload table directly instead of joining `telemetry_events`
771
771
  // only to re-apply the tenant predicate: `telemetry_payloads` carries
772
772
  // `tenant_id` itself, so the join added a second table's rows to filter for