cartethyia 2.7.2 → 2.7.3

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 (249) hide show
  1. package/.env.example +2 -0
  2. package/dist/dashboard/assets/{BannedPage-XaUmiBrC.js → BannedPage-2TJD37Hb.js} +1 -1
  3. package/dist/dashboard/assets/BannedPage-2TJD37Hb.js.gz +0 -0
  4. package/dist/dashboard/assets/CliToolDetailPage-xefJNRmJ.js +1 -0
  5. package/dist/dashboard/assets/CliToolDetailPage-xefJNRmJ.js.gz +0 -0
  6. package/dist/dashboard/assets/CliToolsPage-Rj9iHQ3F.js +1 -0
  7. package/dist/dashboard/assets/CliToolsPage-Rj9iHQ3F.js.gz +0 -0
  8. package/dist/dashboard/assets/{CombosPage-CXGS_Ct-.js → CombosPage-JEbYJFxw.js} +1 -1
  9. package/dist/dashboard/assets/CombosPage-JEbYJFxw.js.gz +0 -0
  10. package/dist/dashboard/assets/{ConsoleLogPage-DGnGNYnM.js → ConsoleLogPage-C3xx_inM.js} +1 -1
  11. package/dist/dashboard/assets/ConsoleLogPage-C3xx_inM.js.gz +0 -0
  12. package/dist/dashboard/assets/CustomizationPage-Dw306gJU.js +1 -0
  13. package/dist/dashboard/assets/CustomizationPage-Dw306gJU.js.gz +0 -0
  14. package/dist/dashboard/assets/HealthEventsModal-jaBo1TWV.js +1 -0
  15. package/dist/dashboard/assets/HealthEventsModal-jaBo1TWV.js.gz +0 -0
  16. package/dist/dashboard/assets/{LoginPage-BdmRLnq2.js → LoginPage-C4w7vea-.js} +1 -1
  17. package/dist/dashboard/assets/LoginPage-C4w7vea-.js.gz +0 -0
  18. package/dist/dashboard/assets/{ModelPicker-BH8Tehdi.js → ModelPicker-BtPcAfot.js} +1 -1
  19. package/dist/dashboard/assets/ModelPicker-BtPcAfot.js.gz +0 -0
  20. package/dist/dashboard/assets/OverviewPage-CGC5gNs1.js +1 -0
  21. package/dist/dashboard/assets/OverviewPage-CGC5gNs1.js.gz +0 -0
  22. package/dist/dashboard/assets/ProviderDetailPage-DQcthNGt.js +4 -0
  23. package/dist/dashboard/assets/ProviderDetailPage-DQcthNGt.js.gz +0 -0
  24. package/dist/dashboard/assets/ProvidersPage-0OsXRGXe.js +1 -0
  25. package/dist/dashboard/assets/ProvidersPage-0OsXRGXe.js.gz +0 -0
  26. package/dist/dashboard/assets/ProxyPage-DdPc8slb.js +9 -0
  27. package/dist/dashboard/assets/ProxyPage-DdPc8slb.js.gz +0 -0
  28. package/dist/dashboard/assets/{QuotaPage-7P2n--Fv.js → QuotaPage-Ci5O4BnH.js} +1 -1
  29. package/dist/dashboard/assets/QuotaPage-Ci5O4BnH.js.gz +0 -0
  30. package/dist/dashboard/assets/{SettingsPage-CxZ1fTkN.js → SettingsPage-CDZjTt87.js} +1 -1
  31. package/dist/dashboard/assets/SettingsPage-CDZjTt87.js.gz +0 -0
  32. package/dist/dashboard/assets/SetupPage-BQS0Rx_u.js +1 -0
  33. package/dist/dashboard/assets/SetupPage-BQS0Rx_u.js.gz +0 -0
  34. package/dist/dashboard/assets/{SortableList-Dqf4zpS-.js → SortableList-BAL5npBC.js} +1 -1
  35. package/dist/dashboard/assets/SortableList-BAL5npBC.js.gz +0 -0
  36. package/dist/dashboard/assets/{StudioPage-Byj2lAEm.js → StudioPage-TP7voAQ0.js} +3 -3
  37. package/dist/dashboard/assets/StudioPage-TP7voAQ0.js.gz +0 -0
  38. package/dist/dashboard/assets/{UsagePage-CTkLAuRc.js → UsagePage-Cj_fEzhg.js} +13 -13
  39. package/dist/dashboard/assets/UsagePage-Cj_fEzhg.js.gz +0 -0
  40. package/dist/dashboard/assets/{api-keys-CUi6UXsR.js → api-keys-MbI7e7rt.js} +1 -1
  41. package/dist/dashboard/assets/api-keys-MbI7e7rt.js.gz +0 -0
  42. package/dist/dashboard/assets/app-B2vyPoII.css +2 -0
  43. package/dist/dashboard/assets/app-B2vyPoII.css.gz +0 -0
  44. package/dist/dashboard/assets/arrow-up-59ms1iiT.js +1 -0
  45. package/dist/dashboard/assets/arrow-up-59ms1iiT.js.gz +0 -0
  46. package/dist/dashboard/assets/{assert-67xXH5rf.js → assert-C0YYuZJ4.js} +1 -1
  47. package/dist/dashboard/assets/assert-C0YYuZJ4.js.gz +0 -0
  48. package/dist/dashboard/assets/{badge-DC2L43Mj.js → badge-B_DMpMJN.js} +1 -1
  49. package/dist/dashboard/assets/badge-B_DMpMJN.js.gz +0 -0
  50. package/dist/dashboard/assets/{banner-BBVcb0J3.js → banner-DMrMPmth.js} +1 -1
  51. package/dist/dashboard/assets/banner-DMrMPmth.js.gz +0 -0
  52. package/dist/dashboard/assets/{card-Cca1XC6G.js → card-Be5Uzamx.js} +1 -1
  53. package/dist/dashboard/assets/card-Be5Uzamx.js.gz +0 -0
  54. package/dist/dashboard/assets/{cli-tools-KvsWa1Jl.js → cli-tools-muFRphDu.js} +1 -1
  55. package/dist/dashboard/assets/cli-tools-muFRphDu.js.gz +0 -0
  56. package/dist/dashboard/assets/{clipboard-button-DUzEbynq.js → clipboard-button-DOfrVmsi.js} +1 -1
  57. package/dist/dashboard/assets/clipboard-button-DOfrVmsi.js.gz +0 -0
  58. package/dist/dashboard/assets/{dialog-DFvWhwTa.js → dialog-C9omdjQt.js} +1 -1
  59. package/dist/dashboard/assets/dialog-C9omdjQt.js.gz +0 -0
  60. package/dist/dashboard/assets/drawer-Bm8WKaGY.js +1 -0
  61. package/dist/dashboard/assets/drawer-Bm8WKaGY.js.gz +0 -0
  62. package/dist/dashboard/assets/{entry-_xHo5x6r.js → entry-DS90gUks.js} +1 -1
  63. package/dist/dashboard/assets/entry-DS90gUks.js.gz +0 -0
  64. package/dist/dashboard/assets/{entry-ClCMCWWQ.js → entry-j40LJotO.js} +3 -3
  65. package/dist/dashboard/assets/entry-j40LJotO.js.gz +0 -0
  66. package/dist/dashboard/assets/{entry-Bqy8RFvM.js → entry-q5HwZ8nN.js} +1 -1
  67. package/dist/dashboard/assets/entry-q5HwZ8nN.js.gz +0 -0
  68. package/dist/dashboard/assets/{concurrency-BDF0ok7y.js → fingerprint-pattern-BWuHtbW4.js} +1 -1
  69. package/dist/dashboard/assets/fingerprint-pattern-BWuHtbW4.js.gz +0 -0
  70. package/dist/dashboard/assets/{formatters-CWWZ-uCZ.js → formatters-BTScrQpe.js} +1 -1
  71. package/dist/dashboard/assets/formatters-BTScrQpe.js.gz +0 -0
  72. package/dist/dashboard/assets/{github-badge-C9e8Ts7e.js → github-badge-Orjuzemr.js} +1 -1
  73. package/dist/dashboard/assets/github-badge-Orjuzemr.js.gz +0 -0
  74. package/dist/dashboard/assets/{index-DFVFrnWW.js → index-cPrX5vn6.js} +2 -2
  75. package/dist/dashboard/assets/index-cPrX5vn6.js.gz +0 -0
  76. package/dist/dashboard/assets/{inline-BFUcvllj.js → inline-Dvux8w-0.js} +1 -1
  77. package/dist/dashboard/assets/inline-Dvux8w-0.js.gz +0 -0
  78. package/dist/dashboard/assets/{input-C_ILAvBb.js → input-CU1Rgf3p.js} +1 -1
  79. package/dist/dashboard/assets/input-CU1Rgf3p.js.gz +0 -0
  80. package/dist/dashboard/assets/{layout-CBIyT6Rt.js → layout-C_7A6H55.js} +1 -1
  81. package/dist/dashboard/assets/layout-C_7A6H55.js.gz +0 -0
  82. package/dist/dashboard/assets/{list-row-ebJ_-Nsb.js → list-row-CzFvogbj.js} +1 -1
  83. package/dist/dashboard/assets/list-row-CzFvogbj.js.gz +0 -0
  84. package/dist/dashboard/assets/{live-D0mm--ME.js → live-KaG15HLQ.js} +1 -1
  85. package/dist/dashboard/assets/live-KaG15HLQ.js.gz +0 -0
  86. package/dist/dashboard/assets/{mutation-sMD965oO.js → mutation-JJGQm8TD.js} +1 -1
  87. package/dist/dashboard/assets/mutation-JJGQm8TD.js.gz +0 -0
  88. package/dist/dashboard/assets/{numbers-BO9dKaFr.js → numbers-BNDZnsUE.js} +1 -1
  89. package/dist/dashboard/assets/numbers-BNDZnsUE.js.gz +0 -0
  90. package/dist/dashboard/assets/{query-keys-CfL_Zdoh.js → query-keys-CLaNz8Xz.js} +1 -1
  91. package/dist/dashboard/assets/query-keys-CLaNz8Xz.js.gz +0 -0
  92. package/dist/dashboard/assets/{routing-BnIpi1IJ.js → routing-BEH32QOC.js} +1 -1
  93. package/dist/dashboard/assets/routing-BEH32QOC.js.gz +0 -0
  94. package/dist/dashboard/assets/{select-DBNVLdUu.js → select-B3iTetHN.js} +1 -1
  95. package/dist/dashboard/assets/select-B3iTetHN.js.gz +0 -0
  96. package/dist/dashboard/assets/settings-2-Ds9DQp0t.js +1 -0
  97. package/dist/dashboard/assets/settings-2-Ds9DQp0t.js.gz +0 -0
  98. package/dist/dashboard/assets/{settings-BAFhDgX8.js → settings-Dt3Eqbnq.js} +1 -1
  99. package/dist/dashboard/assets/settings-Dt3Eqbnq.js.gz +0 -0
  100. package/dist/dashboard/assets/{stack-EMrOMt4I.js → stack-KrOrm7JZ.js} +1 -1
  101. package/dist/dashboard/assets/stack-KrOrm7JZ.js.gz +0 -0
  102. package/dist/dashboard/assets/{state-CWoo7ty5.js → state-DLS7IDMy.js} +1 -1
  103. package/dist/dashboard/assets/state-DLS7IDMy.js.gz +0 -0
  104. package/dist/dashboard/assets/{switch-CCjT6IkF.js → switch-42ItvbAs.js} +1 -1
  105. package/dist/dashboard/assets/switch-42ItvbAs.js.gz +0 -0
  106. package/dist/dashboard/assets/{useMutation-DjkLHUcE.js → useMutation-Dmnfh1Ue.js} +1 -1
  107. package/dist/dashboard/assets/useMutation-Dmnfh1Ue.js.gz +0 -0
  108. package/dist/dashboard/index.html +3 -2
  109. package/dist/dashboard/index.html.gz +0 -0
  110. package/dist/dashboard/precompressed-assets.json +117 -115
  111. package/migrations/full-postgres/0026_add_qoder_native_identity.sql +20 -0
  112. package/migrations/full-postgres/0027_qoder_identity_genuine_seed.sql +22 -0
  113. package/migrations/full-postgres/0028_add_family_template_key_telemetry.sql +40 -0
  114. package/migrations/full-postgres/0029_null_share_child_policy_columns.sql +38 -0
  115. package/migrations/full-postgres/0030_add_api_key_max_children.sql +10 -0
  116. package/migrations/full-postgres/0031_tenant_system_prompts.sql +16 -0
  117. package/migrations/lite-sqlite3/0026_add_qoder_native_identity.sql +15 -0
  118. package/migrations/lite-sqlite3/0027_qoder_identity_genuine_seed.sql +22 -0
  119. package/migrations/lite-sqlite3/0028_add_family_template_key_telemetry.sql +40 -0
  120. package/migrations/lite-sqlite3/0029_null_share_child_policy_columns.sql +38 -0
  121. package/migrations/lite-sqlite3/0030_add_api_key_max_children.sql +10 -0
  122. package/migrations/lite-sqlite3/0031_tenant_system_prompts.sql +10 -0
  123. package/package.json +1 -1
  124. package/src/config/network.ts +1 -1
  125. package/src/console/api-keys/bucket-spend.ts +7 -7
  126. package/src/console/api-keys/contracts.ts +423 -410
  127. package/src/console/api-keys/routes.ts +118 -19
  128. package/src/console/backup/export-endpoint.ts +8 -11
  129. package/src/console/backup/routes.ts +40 -8
  130. package/src/console/backup/service.ts +11 -6
  131. package/src/console/backup/store.ts +384 -88
  132. package/src/console/dashboard-assets.ts +16 -1
  133. package/src/console/domain-registration.ts +2 -0
  134. package/src/console/quota/account-quota-tenant.ts +8 -1
  135. package/src/console/quota/account-quota.ts +4 -1
  136. package/src/console/quota/native-identity.ts +189 -0
  137. package/src/console/remote-support/contracts.ts +12 -6
  138. package/src/console/remote-support/service.ts +2 -2
  139. package/src/console/share/share-router.ts +39 -6
  140. package/src/console/share/share-stats.ts +64 -25
  141. package/src/console/share/share-usage.ts +24 -7
  142. package/src/console/system-prompt/contracts.ts +102 -0
  143. package/src/console/system-prompt/routes.ts +165 -0
  144. package/src/main.ts +11 -0
  145. package/src/observability/event-query.ts +118 -7
  146. package/src/persistence/db-pg.ts +42 -0
  147. package/src/persistence/schema.ts +102 -0
  148. package/src/persistence/stores/api-key-store.ts +753 -581
  149. package/src/persistence/stores/share-store.ts +65 -13
  150. package/src/persistence/stores/telemetry-store.ts +57 -1
  151. package/src/persistence/system-prompt-store.ts +104 -0
  152. package/src/protocol/reasoning.ts +65 -1
  153. package/src/protocol/request/chat.ts +1 -0
  154. package/src/providers/integrations/antigravity/antigravity.ts +20 -23
  155. package/src/providers/integrations/buddy/buddy-chat-shared.ts +30 -2
  156. package/src/providers/integrations/buddy/buddy-media.ts +5 -1
  157. package/src/providers/integrations/buddy/codebuddy/provider.ts +5 -1
  158. package/src/providers/integrations/buddy/workbuddy/provider.ts +5 -1
  159. package/src/providers/integrations/cline/cline.ts +7 -0
  160. package/src/providers/integrations/github/github.ts +20 -1
  161. package/src/providers/integrations/hermes.ts +5 -1
  162. package/src/providers/integrations/kilo/kilo.ts +4 -0
  163. package/src/providers/integrations/openrouter/provider.ts +4 -0
  164. package/src/providers/integrations/qoder/qoder-checkin.ts +224 -51
  165. package/src/providers/integrations/qoder/qoder-native-identity-store.ts +156 -0
  166. package/src/providers/integrations/qoder/qoder-oauth.ts +12 -3
  167. package/src/providers/integrations/qoder/qoder-umid.ts +288 -0
  168. package/src/providers/integrations/qoder/qoder.ts +5 -3
  169. package/src/providers/operations/account-error-classification.ts +6 -8
  170. package/src/providers/operations/account-health-service.ts +14 -16
  171. package/src/providers/operations/client-versions.ts +37 -22
  172. package/src/providers/provider-contracts.ts +8 -0
  173. package/src/security/access-control.ts +19 -0
  174. package/src/security/api-key-auth.ts +14 -1
  175. package/src/transport/dispatch/proxy-request.ts +31 -2
  176. package/src/transport/dispatch/streaming/stream.ts +16 -1
  177. package/src/transport/dispatch/upstream.ts +10 -0
  178. package/src/transport/request/preparer.ts +17 -1
  179. package/src/transport/request/system-prompt-injection.ts +89 -0
  180. package/src/transport/request/tenant-preferences.ts +43 -0
  181. package/src/transport/routing/admission.ts +13 -3
  182. package/src/transport/routing/route-catalog.ts +7 -0
  183. package/src/transport/routing/route-model.ts +53 -0
  184. package/src/transport/routing/router.ts +306 -256
  185. package/src/workers/daily-checkin.ts +2 -0
  186. package/dist/dashboard/assets/BannedPage-XaUmiBrC.js.gz +0 -0
  187. package/dist/dashboard/assets/CliToolDetailPage-CqD7QiLM.js +0 -1
  188. package/dist/dashboard/assets/CliToolDetailPage-CqD7QiLM.js.gz +0 -0
  189. package/dist/dashboard/assets/CliToolsPage-0XUo4UMn.js +0 -1
  190. package/dist/dashboard/assets/CliToolsPage-0XUo4UMn.js.gz +0 -0
  191. package/dist/dashboard/assets/CombosPage-CXGS_Ct-.js.gz +0 -0
  192. package/dist/dashboard/assets/ConsoleLogPage-DGnGNYnM.js.gz +0 -0
  193. package/dist/dashboard/assets/CustomizationPage-DAG5J9EY.js +0 -1
  194. package/dist/dashboard/assets/CustomizationPage-DAG5J9EY.js.gz +0 -0
  195. package/dist/dashboard/assets/HealthEventsModal-BKtAPYVF.js +0 -1
  196. package/dist/dashboard/assets/HealthEventsModal-BKtAPYVF.js.gz +0 -0
  197. package/dist/dashboard/assets/LoginPage-BdmRLnq2.js.gz +0 -0
  198. package/dist/dashboard/assets/ModelPicker-BH8Tehdi.js.gz +0 -0
  199. package/dist/dashboard/assets/OverviewPage-CqMxibJB.js +0 -1
  200. package/dist/dashboard/assets/OverviewPage-CqMxibJB.js.gz +0 -0
  201. package/dist/dashboard/assets/ProviderDetailPage-CqMh2NRX.js +0 -4
  202. package/dist/dashboard/assets/ProviderDetailPage-CqMh2NRX.js.gz +0 -0
  203. package/dist/dashboard/assets/ProvidersPage-B9uWu4Nz.js +0 -1
  204. package/dist/dashboard/assets/ProvidersPage-B9uWu4Nz.js.gz +0 -0
  205. package/dist/dashboard/assets/ProxyPage-BoWOhpDO.js +0 -9
  206. package/dist/dashboard/assets/ProxyPage-BoWOhpDO.js.gz +0 -0
  207. package/dist/dashboard/assets/QuotaPage-7P2n--Fv.js.gz +0 -0
  208. package/dist/dashboard/assets/SettingsPage-CxZ1fTkN.js.gz +0 -0
  209. package/dist/dashboard/assets/SetupPage-Co12Zzaw.js +0 -1
  210. package/dist/dashboard/assets/SetupPage-Co12Zzaw.js.gz +0 -0
  211. package/dist/dashboard/assets/SortableList-Dqf4zpS-.js.gz +0 -0
  212. package/dist/dashboard/assets/StudioPage-Byj2lAEm.js.gz +0 -0
  213. package/dist/dashboard/assets/UsagePage-CTkLAuRc.js.gz +0 -0
  214. package/dist/dashboard/assets/api-keys-CUi6UXsR.js.gz +0 -0
  215. package/dist/dashboard/assets/app-KvsUJUMF.css +0 -2
  216. package/dist/dashboard/assets/app-KvsUJUMF.css.gz +0 -0
  217. package/dist/dashboard/assets/assert-67xXH5rf.js.gz +0 -0
  218. package/dist/dashboard/assets/badge-DC2L43Mj.js.gz +0 -0
  219. package/dist/dashboard/assets/banner-BBVcb0J3.js.gz +0 -0
  220. package/dist/dashboard/assets/card-Cca1XC6G.js.gz +0 -0
  221. package/dist/dashboard/assets/cli-tools-KvsWa1Jl.js.gz +0 -0
  222. package/dist/dashboard/assets/clipboard-button-DUzEbynq.js.gz +0 -0
  223. package/dist/dashboard/assets/concurrency-BDF0ok7y.js.gz +0 -0
  224. package/dist/dashboard/assets/dialog-DFvWhwTa.js.gz +0 -0
  225. package/dist/dashboard/assets/drawer-CFM2sMX1.js +0 -1
  226. package/dist/dashboard/assets/drawer-CFM2sMX1.js.gz +0 -0
  227. package/dist/dashboard/assets/entry-Bqy8RFvM.js.gz +0 -0
  228. package/dist/dashboard/assets/entry-ClCMCWWQ.js.gz +0 -0
  229. package/dist/dashboard/assets/entry-_xHo5x6r.js.gz +0 -0
  230. package/dist/dashboard/assets/formatters-CWWZ-uCZ.js.gz +0 -0
  231. package/dist/dashboard/assets/github-badge-C9e8Ts7e.js.gz +0 -0
  232. package/dist/dashboard/assets/index-DFVFrnWW.js.gz +0 -0
  233. package/dist/dashboard/assets/inline-BFUcvllj.js.gz +0 -0
  234. package/dist/dashboard/assets/input-C_ILAvBb.js.gz +0 -0
  235. package/dist/dashboard/assets/layout-CBIyT6Rt.js.gz +0 -0
  236. package/dist/dashboard/assets/list-row-ebJ_-Nsb.js.gz +0 -0
  237. package/dist/dashboard/assets/live-D0mm--ME.js.gz +0 -0
  238. package/dist/dashboard/assets/mutation-sMD965oO.js.gz +0 -0
  239. package/dist/dashboard/assets/numbers-BO9dKaFr.js.gz +0 -0
  240. package/dist/dashboard/assets/query-keys-CfL_Zdoh.js.gz +0 -0
  241. package/dist/dashboard/assets/routing-BnIpi1IJ.js.gz +0 -0
  242. package/dist/dashboard/assets/select-DBNVLdUu.js.gz +0 -0
  243. package/dist/dashboard/assets/settings-BAFhDgX8.js.gz +0 -0
  244. package/dist/dashboard/assets/stack-EMrOMt4I.js.gz +0 -0
  245. package/dist/dashboard/assets/state-CWoo7ty5.js.gz +0 -0
  246. package/dist/dashboard/assets/switch-CCjT6IkF.js.gz +0 -0
  247. package/dist/dashboard/assets/useMutation-DjkLHUcE.js.gz +0 -0
  248. /package/dist/dashboard/assets/{app-BaWd0puM.js → app-wvwCi4Eh.js} +0 -0
  249. /package/dist/dashboard/assets/{app-BaWd0puM.js.gz → app-wvwCi4Eh.js.gz} +0 -0
@@ -1,120 +1,122 @@
1
1
  {
2
- "count": 115,
2
+ "count": 117,
3
3
  "assets": [
4
- "assets\\AccountCooldown-Bjo92Qat.js",
5
- "assets\\BannedPage-XaUmiBrC.js",
6
- "assets\\CliToolDetailPage-CqD7QiLM.js",
7
- "assets\\CliToolsPage-0XUo4UMn.js",
8
- "assets\\CombosPage-CXGS_Ct-.js",
9
- "assets\\ConsoleLogPage-DGnGNYnM.js",
10
- "assets\\CustomizationPage-DAG5J9EY.js",
11
- "assets\\HealthEventsModal-BKtAPYVF.js",
12
- "assets\\LoginPage-BdmRLnq2.js",
13
- "assets\\ModelPicker-BH8Tehdi.js",
14
- "assets\\OverviewPage-CqMxibJB.js",
15
- "assets\\ProviderDetailPage-CqMh2NRX.js",
16
- "assets\\ProviderIcon-FB6yS4v1.js",
17
- "assets\\ProvidersPage-B9uWu4Nz.js",
18
- "assets\\ProxyPage-BoWOhpDO.js",
19
- "assets\\QuotaPage-7P2n--Fv.js",
20
- "assets\\SettingsPage-CxZ1fTkN.js",
21
- "assets\\SetupPage-Co12Zzaw.js",
22
- "assets\\SortableList-Dqf4zpS-.js",
23
- "assets\\StudioPage-Byj2lAEm.js",
24
- "assets\\ToolIcon-K1ckcDKg.js",
25
- "assets\\UsagePage-CTkLAuRc.js",
26
- "assets\\api-keys-CUi6UXsR.js",
27
- "assets\\app-BaWd0puM.js",
28
- "assets\\app-KvsUJUMF.css",
29
- "assets\\arrow-left-CpBxkoxI.js",
30
- "assets\\arrow-right-Dl5yKnp8.js",
31
- "assets\\assert-67xXH5rf.js",
32
- "assets\\backup-file-gdKIlg8U.js",
33
- "assets\\badge-DC2L43Mj.js",
34
- "assets\\banner-BBVcb0J3.js",
35
- "assets\\brain-Cwed_72z.js",
36
- "assets\\card-Cca1XC6G.js",
37
- "assets\\chevron-right-BXIy5l3h.js",
38
- "assets\\circle-alert-CntYHV5v.js",
39
- "assets\\circle-check-BU3v_mFW.js",
40
- "assets\\cli-tools-KvsWa1Jl.js",
41
- "assets\\clipboard-button-DUzEbynq.js",
42
- "assets\\concurrency-BDF0ok7y.js",
43
- "assets\\database-Dz9N3zGd.js",
44
- "assets\\dialog-DFvWhwTa.js",
45
- "assets\\dialog-actions-B1axpEg7.js",
46
- "assets\\download-dRFo5_Wu.js",
47
- "assets\\drawer-CFM2sMX1.js",
48
- "assets\\entry-Bqy8RFvM.js",
49
- "assets\\entry-ClCMCWWQ.js",
50
- "assets\\entry-_xHo5x6r.js",
51
- "assets\\eye-C_hawfH4.js",
52
- "assets\\eye-off-Bk5g2luF.js",
53
- "assets\\formatters-CWWZ-uCZ.js",
54
- "assets\\gauge-BbIMy7MB.js",
55
- "assets\\github-badge-C9e8Ts7e.js",
56
- "assets\\image-BPaouViG.js",
57
- "assets\\index-DFVFrnWW.js",
58
- "assets\\inline-BFUcvllj.js",
59
- "assets\\input-C_ILAvBb.js",
60
- "assets\\jsx-runtime-CXUMngI_.js",
61
- "assets\\key-round-UkavsGxp.js",
62
- "assets\\layers-2-glBbjl.js",
63
- "assets\\layout-CBIyT6Rt.js",
64
- "assets\\list-row-ebJ_-Nsb.js",
65
- "assets\\live-D0mm--ME.js",
66
- "assets\\log-in-BmRjy60c.js",
67
- "assets\\message-circle-CCxGwRvv.js",
68
- "assets\\minimize-2-D-MN8W8a.js",
69
- "assets\\mutation-sMD965oO.js",
70
- "assets\\numbers-BO9dKaFr.js",
71
- "assets\\pencil-768ysRAr.js",
72
- "assets\\plus-DIdX_g-x.js",
73
- "assets\\power-off-Yjw9GMJh.js",
74
- "assets\\privacy-mode-GM8bej85.js",
75
- "assets\\providers\\agentrouter.svg",
76
- "assets\\providers\\aihubmix.svg",
77
- "assets\\providers\\alibaba-coding-plan.svg",
78
- "assets\\providers\\alibaba.svg",
79
- "assets\\providers\\antigravity.svg",
80
- "assets\\providers\\bai.svg",
81
- "assets\\providers\\blackbox.svg",
82
- "assets\\providers\\claude-code.svg",
83
- "assets\\providers\\exa.svg",
84
- "assets\\providers\\gmi-cloud.svg",
85
- "assets\\providers\\inception.svg",
86
- "assets\\providers\\inferhub.svg",
87
- "assets\\providers\\muse.svg",
88
- "assets\\providers\\nous-research.svg",
89
- "assets\\providers\\openai-light.svg",
90
- "assets\\providers\\parallel.svg",
91
- "assets\\providers\\tokenharbor.svg",
92
- "assets\\providers\\zai-coding-plan.svg",
93
- "assets\\query-keys-CfL_Zdoh.js",
94
- "assets\\quota-DZGyp0N5.js",
95
- "assets\\refresh-cw-BqJFk4sU.js",
96
- "assets\\rotate-ccw-CufcqITi.js",
97
- "assets\\route-CNSNj9Zm.js",
98
- "assets\\routing-BnIpi1IJ.js",
99
- "assets\\scaling-nWE4Cx8f.js",
100
- "assets\\search-JOKus9rb.js",
101
- "assets\\select-DBNVLdUu.js",
102
- "assets\\settings-BAFhDgX8.js",
103
- "assets\\shield-check-DVS0Foqh.js",
104
- "assets\\stack-EMrOMt4I.js",
105
- "assets\\state-CWoo7ty5.js",
106
- "assets\\stream-retry-5QnVuSSo.js",
107
- "assets\\switch-CCjT6IkF.js",
108
- "assets\\terminal-0_IjPWTk.js",
109
- "assets\\tokens-COzario9.js",
110
- "assets\\trash-Cppn5c3R.js",
111
- "assets\\use-clipboard-B0Sy03fE.js",
112
- "assets\\use-modal-focus-By7oJoGd.js",
113
- "assets\\use-reduced-motion-C4B0R6Sz.js",
114
- "assets\\use-timeout-BwcBBRrT.js",
115
- "assets\\useMutation-DjkLHUcE.js",
116
- "assets\\wrench-B6E1oEuY.js",
117
- "assets\\zap-C4EeVW4q.js",
4
+ "assets/AccountCooldown-Bjo92Qat.js",
5
+ "assets/BannedPage-2TJD37Hb.js",
6
+ "assets/CliToolDetailPage-xefJNRmJ.js",
7
+ "assets/CliToolsPage-Rj9iHQ3F.js",
8
+ "assets/CombosPage-JEbYJFxw.js",
9
+ "assets/ConsoleLogPage-C3xx_inM.js",
10
+ "assets/CustomizationPage-Dw306gJU.js",
11
+ "assets/HealthEventsModal-jaBo1TWV.js",
12
+ "assets/LoginPage-C4w7vea-.js",
13
+ "assets/ModelPicker-BtPcAfot.js",
14
+ "assets/OverviewPage-CGC5gNs1.js",
15
+ "assets/ProviderDetailPage-DQcthNGt.js",
16
+ "assets/ProviderIcon-FB6yS4v1.js",
17
+ "assets/ProvidersPage-0OsXRGXe.js",
18
+ "assets/ProxyPage-DdPc8slb.js",
19
+ "assets/QuotaPage-Ci5O4BnH.js",
20
+ "assets/SettingsPage-CDZjTt87.js",
21
+ "assets/SetupPage-BQS0Rx_u.js",
22
+ "assets/SortableList-BAL5npBC.js",
23
+ "assets/StudioPage-TP7voAQ0.js",
24
+ "assets/ToolIcon-K1ckcDKg.js",
25
+ "assets/UsagePage-Cj_fEzhg.js",
26
+ "assets/api-keys-MbI7e7rt.js",
27
+ "assets/app-B2vyPoII.css",
28
+ "assets/app-wvwCi4Eh.js",
29
+ "assets/arrow-left-CpBxkoxI.js",
30
+ "assets/arrow-right-Dl5yKnp8.js",
31
+ "assets/arrow-up-59ms1iiT.js",
32
+ "assets/assert-C0YYuZJ4.js",
33
+ "assets/backup-file-gdKIlg8U.js",
34
+ "assets/badge-B_DMpMJN.js",
35
+ "assets/banner-DMrMPmth.js",
36
+ "assets/brain-Cwed_72z.js",
37
+ "assets/card-Be5Uzamx.js",
38
+ "assets/chevron-right-BXIy5l3h.js",
39
+ "assets/circle-alert-CntYHV5v.js",
40
+ "assets/circle-check-BU3v_mFW.js",
41
+ "assets/cli-tools-muFRphDu.js",
42
+ "assets/clipboard-button-DOfrVmsi.js",
43
+ "assets/database-Dz9N3zGd.js",
44
+ "assets/dialog-C9omdjQt.js",
45
+ "assets/dialog-actions-B1axpEg7.js",
46
+ "assets/download-dRFo5_Wu.js",
47
+ "assets/drawer-Bm8WKaGY.js",
48
+ "assets/entry-DS90gUks.js",
49
+ "assets/entry-j40LJotO.js",
50
+ "assets/entry-q5HwZ8nN.js",
51
+ "assets/eye-C_hawfH4.js",
52
+ "assets/eye-off-Bk5g2luF.js",
53
+ "assets/fingerprint-pattern-BWuHtbW4.js",
54
+ "assets/formatters-BTScrQpe.js",
55
+ "assets/gauge-BbIMy7MB.js",
56
+ "assets/github-badge-Orjuzemr.js",
57
+ "assets/image-BPaouViG.js",
58
+ "assets/index-cPrX5vn6.js",
59
+ "assets/inline-Dvux8w-0.js",
60
+ "assets/input-CU1Rgf3p.js",
61
+ "assets/jsx-runtime-CXUMngI_.js",
62
+ "assets/key-round-UkavsGxp.js",
63
+ "assets/layers-2-glBbjl.js",
64
+ "assets/layout-C_7A6H55.js",
65
+ "assets/list-row-CzFvogbj.js",
66
+ "assets/live-KaG15HLQ.js",
67
+ "assets/log-in-BmRjy60c.js",
68
+ "assets/message-circle-CCxGwRvv.js",
69
+ "assets/minimize-2-D-MN8W8a.js",
70
+ "assets/mutation-JJGQm8TD.js",
71
+ "assets/numbers-BNDZnsUE.js",
72
+ "assets/pencil-768ysRAr.js",
73
+ "assets/plus-DIdX_g-x.js",
74
+ "assets/power-off-Yjw9GMJh.js",
75
+ "assets/privacy-mode-GM8bej85.js",
76
+ "assets/providers/agentrouter.svg",
77
+ "assets/providers/aihubmix.svg",
78
+ "assets/providers/alibaba-coding-plan.svg",
79
+ "assets/providers/alibaba.svg",
80
+ "assets/providers/antigravity.svg",
81
+ "assets/providers/bai.svg",
82
+ "assets/providers/blackbox.svg",
83
+ "assets/providers/claude-code.svg",
84
+ "assets/providers/exa.svg",
85
+ "assets/providers/gmi-cloud.svg",
86
+ "assets/providers/inception.svg",
87
+ "assets/providers/inferhub.svg",
88
+ "assets/providers/muse.svg",
89
+ "assets/providers/nous-research.svg",
90
+ "assets/providers/openai-light.svg",
91
+ "assets/providers/parallel.svg",
92
+ "assets/providers/tokenharbor.svg",
93
+ "assets/providers/zai-coding-plan.svg",
94
+ "assets/query-keys-CLaNz8Xz.js",
95
+ "assets/quota-DZGyp0N5.js",
96
+ "assets/refresh-cw-BqJFk4sU.js",
97
+ "assets/rotate-ccw-CufcqITi.js",
98
+ "assets/route-CNSNj9Zm.js",
99
+ "assets/routing-BEH32QOC.js",
100
+ "assets/scaling-nWE4Cx8f.js",
101
+ "assets/search-JOKus9rb.js",
102
+ "assets/select-B3iTetHN.js",
103
+ "assets/settings-2-Ds9DQp0t.js",
104
+ "assets/settings-Dt3Eqbnq.js",
105
+ "assets/shield-check-DVS0Foqh.js",
106
+ "assets/stack-KrOrm7JZ.js",
107
+ "assets/state-DLS7IDMy.js",
108
+ "assets/stream-retry-5QnVuSSo.js",
109
+ "assets/switch-42ItvbAs.js",
110
+ "assets/terminal-0_IjPWTk.js",
111
+ "assets/tokens-COzario9.js",
112
+ "assets/trash-Cppn5c3R.js",
113
+ "assets/use-clipboard-B0Sy03fE.js",
114
+ "assets/use-modal-focus-By7oJoGd.js",
115
+ "assets/use-reduced-motion-C4B0R6Sz.js",
116
+ "assets/use-timeout-BwcBBRrT.js",
117
+ "assets/useMutation-Dmnfh1Ue.js",
118
+ "assets/wrench-B6E1oEuY.js",
119
+ "assets/zap-C4EeVW4q.js",
118
120
  "index.html"
119
121
  ]
120
122
  }
@@ -0,0 +1,20 @@
1
+ -- Qoder native machine identity (UMID) bound to one account.
2
+ --
3
+ -- The daily 100-credit check-in campaign appears only when the request
4
+ -- carries a genuine, non-VM device identity. That identity is a
5
+ -- deterministic function of a seed file (`~/.config/.locale_cfg`): the
6
+ -- `runtime-info` bridge derives machineToken/machineType/machineCode from the
7
+ -- seed. Each account gets its own minted seed, so it looks like its own
8
+ -- device to the server.
9
+ --
10
+ -- The identity is not a credential (it travels in plaintext `cosy-machine*`
11
+ -- headers), so it lives unsealed as a JSON object. The partial unique index
12
+ -- on the extracted `machineToken` enforces "one device per account" at the
13
+ -- database level: two accounts sharing a token would claim as the same
14
+ -- device and the second would lose the grant for the day.
15
+ ALTER TABLE "provider_accounts"
16
+ ADD COLUMN "native_identity" jsonb;
17
+
18
+ CREATE UNIQUE INDEX "provider_accounts_native_identity_token_uidx"
19
+ ON "provider_accounts" ((native_identity ->> 'machineToken'))
20
+ WHERE native_identity IS NOT NULL;
@@ -0,0 +1,22 @@
1
+ -- Qoder native identity: genuine SG identity + per-account seed replay.
2
+ --
3
+ -- Research (2026-10-30, see documentation/research/qoder-identity-gate-
4
+ -- postmortem.md and qoder-umid-reverse.md) established that the daily-credit
5
+ -- campaign gates its CREDITS grant on a *genuine* Alibaba SG-produced
6
+ -- identity: generated/deterministic tokens do not reveal the grant on a
7
+ -- fresh account, while the `runtime-info` bridge (SG-signed) does.
8
+ --
9
+ -- Migration 0026 already added `native_identity` (the token triple + optional
10
+ -- seed) with a partial unique index on the extracted machineToken — the
11
+ -- "one device per account" invariant. This migration does not change that
12
+ -- schema; it only documents the contract change on the same column:
13
+ --
14
+ -- `seed` is now REQUIRED for a claim-capable identity (the seed is the
15
+ -- device material; the token can be re-derived from it, never the reverse).
16
+ -- Rows minted by the retired generated path carry `seed = ""` — they stay
17
+ -- valid records but must be re-minted through the bridge before the next
18
+ -- claim; the store treats a missing/empty seed as "not replay-capable".
19
+ --
20
+ -- No DDL is needed: the JSON shape already carries everything. Kept as an
21
+ -- empty migration so the migration numbering records the policy change.
22
+ SELECT 1;
@@ -0,0 +1,40 @@
1
+ -- Denormalizes the share-template family onto every telemetry event.
2
+ --
3
+ -- The share page's family rollup used to scope by an `EXISTS` against
4
+ -- `api_keys` (the template plus every child it issued). That made history
5
+ -- depend on the key row surviving: revoking/removing a key silently dropped
6
+ -- its events out of the family totals. This column pins the template on the
7
+ -- event at write time, so usage outlives the key.
8
+ --
9
+ -- Backfill is idempotent: it only fills NULL rows (the column is new, so
10
+ -- every existing row is NULL) and never overwrites a value. Events whose key
11
+ -- was already hard-deleted before this migration cannot be attributed and stay
12
+ -- NULL; the soft-delete change shipped alongside this prevents future loss.
13
+
14
+ ALTER TABLE "telemetry_events" ADD COLUMN IF NOT EXISTS "family_template_key_id" uuid;
15
+
16
+ CREATE INDEX IF NOT EXISTS "telemetry_events_tenant_family_created_id_idx"
17
+ ON "telemetry_events" ("tenant_id", "family_template_key_id", "created_at" DESC, "id" DESC);
18
+
19
+ ALTER TABLE "telemetry_usage_totals" ADD COLUMN IF NOT EXISTS "family_template_key_id" uuid;
20
+
21
+ CREATE INDEX IF NOT EXISTS "telemetry_usage_totals_tenant_family_idx"
22
+ ON "telemetry_usage_totals" ("tenant_id", "family_template_key_id");
23
+
24
+ UPDATE "telemetry_events" AS e
25
+ SET "family_template_key_id" = (
26
+ SELECT COALESCE(k."parent_key_id", k."id")
27
+ FROM "api_keys" k
28
+ WHERE k."id" = e."api_key_id"
29
+ )
30
+ WHERE e."family_template_key_id" IS NULL AND e."api_key_id" IS NOT NULL;
31
+
32
+ UPDATE "telemetry_usage_totals" AS t
33
+ SET "family_template_key_id" = (
34
+ SELECT COALESCE(k."parent_key_id", k."id")
35
+ FROM "api_keys" k
36
+ WHERE k."id" = t."entity_id"
37
+ )
38
+ WHERE t."family_template_key_id" IS NULL
39
+ AND t."identity_type" = 'api_key'
40
+ AND t."entity_id" IS NOT NULL;
@@ -0,0 +1,38 @@
1
+ -- One-time row-data optimization for share children.
2
+ --
3
+ -- Every minted share child used to copy the template's policy columns
4
+ -- (notes, limits, model_list, denylist, …). Auth never reads those from the
5
+ -- child — it resolves `policy = parent ?? row` — so the copies were pure
6
+ -- write-amplification. This UPDATE nulls the 11 nullable policy columns on
7
+ -- every child (`parent_key_id IS NOT NULL`). `scopes` stays (NOT NULL, and
8
+ -- required by backup restore); `model_access_mode` stays (NOT NULL default
9
+ -- 'whitelist'). Schema shape is unchanged — no DROP COLUMN — so backup/
10
+ -- restore remains compatible both directions.
11
+ --
12
+ -- Idempotent: the OR-of-IS-NOT-NULL predicate matches nothing on a re-run,
13
+ -- and the migration ledger skips the file after the first apply.
14
+ --
15
+ -- Keep in sync with `normalizeShareChildPolicy` in
16
+ -- `src/console/backup/store.ts` (post-restore re-applies the same null-out
17
+ -- for a tenant, because restore does not re-run numbered migrations).
18
+
19
+ UPDATE "api_keys"
20
+ SET "notes_title" = NULL,
21
+ "notes_subtitle" = NULL,
22
+ "notes_body" = NULL,
23
+ "requests_per_minute" = NULL,
24
+ "daily_token_limit" = NULL,
25
+ "monthly_token_limit" = NULL,
26
+ "lifetime_token_budget" = NULL,
27
+ "max_concurrent_requests" = NULL,
28
+ "model_prefix" = NULL,
29
+ "model_list" = NULL,
30
+ "client_router_denylist" = NULL
31
+ WHERE "parent_key_id" IS NOT NULL
32
+ AND ( "notes_title" IS NOT NULL OR "notes_subtitle" IS NOT NULL
33
+ OR "notes_body" IS NOT NULL OR "requests_per_minute" IS NOT NULL
34
+ OR "daily_token_limit" IS NOT NULL OR "monthly_token_limit" IS NOT NULL
35
+ OR "lifetime_token_budget" IS NOT NULL
36
+ OR "max_concurrent_requests" IS NOT NULL OR "model_prefix" IS NOT NULL
37
+ OR "model_list" IS NOT NULL
38
+ OR "client_router_denylist" IS NOT NULL );
@@ -0,0 +1,10 @@
1
+ -- Add a share-template child slot cap.
2
+ --
3
+ -- Share enrollment links are public, and an attacker minting child rows is
4
+ -- only bounded by the per-IP dedupe, which IP rotation (CDN edges, cloud
5
+ -- egress, residential proxies) defeats. `max_children` lets an operator cap
6
+ -- how many concurrently-active child keys a template may mint; NULL keeps the
7
+ -- legacy unlimited behavior. Enforced at mint time (not a database
8
+ -- constraint) so the error path is a clean 429/409.
9
+
10
+ ALTER TABLE "api_keys" ADD COLUMN "max_children" integer;
@@ -0,0 +1,16 @@
1
+ -- Tenant-scoped system prompt injection (append/override).
2
+ --
3
+ -- Resolution is most-specific-wins: model > provider > global. A provider
4
+ -- either follows the tenant's global prompt (`providers` entry
5
+ -- followGlobal = true, its own setting is ignored) or carries a custom one.
6
+ -- Text is capped at 5 MB per scope in the console route; the dispatch-path
7
+ -- reader is revision-keyed cached, so a mutation converges within the
8
+ -- settings-revision bump. `global` NULL means never configured — distinct
9
+ -- from an explicit `{"enabled": false}` row.
10
+ CREATE TABLE IF NOT EXISTS "tenant_system_prompts" (
11
+ "tenant_id" uuid PRIMARY KEY REFERENCES "tenants" ("id") ON DELETE CASCADE,
12
+ "global" jsonb,
13
+ "providers" jsonb NOT NULL DEFAULT '{}',
14
+ "models" jsonb NOT NULL DEFAULT '{}',
15
+ "updated_at" timestamptz NOT NULL DEFAULT now()
16
+ );
@@ -0,0 +1,15 @@
1
+ -- Qoder native machine identity (UMID) bound to one account.
2
+ --
3
+ -- SQLite mirror of `full-postgres/0026_add_qoder_native_identity.sql`:
4
+ -- the column is `text` (the SQLite representation of jsonb) and the unique
5
+ -- index extracts the `machineToken` the same way the application reads it.
6
+ --
7
+ -- The partial unique index enforces "one device per account" at the database
8
+ -- level. SQLite supports expression indexes (3.38+); a bound identity is a
9
+ -- non-null JSON object whose `$.machineToken` is the device key.
10
+ ALTER TABLE "provider_accounts"
11
+ ADD COLUMN "native_identity" text;
12
+
13
+ CREATE UNIQUE INDEX "provider_accounts_native_identity_token_uidx"
14
+ ON "provider_accounts" (json_extract(native_identity, '$.machineToken'))
15
+ WHERE native_identity IS NOT NULL;
@@ -0,0 +1,22 @@
1
+ -- Qoder native identity: genuine SG identity + per-account seed replay.
2
+ --
3
+ -- Research (2026-10-30, see documentation/research/qoder-identity-gate-
4
+ -- postmortem.md and qoder-umid-reverse.md) established that the daily-credit
5
+ -- campaign gates its CREDITS grant on a *genuine* Alibaba SG-produced
6
+ -- identity: generated/deterministic tokens do not reveal the grant on a
7
+ -- fresh account, while the `runtime-info` bridge (SG-signed) does.
8
+ --
9
+ -- Migration 0026 already added `native_identity` (the token triple + optional
10
+ -- seed) with a partial unique index on the extracted machineToken — the
11
+ -- "one device per account" invariant. This migration does not change that
12
+ -- schema; it only documents the contract change on the same column:
13
+ --
14
+ -- `seed` is now REQUIRED for a claim-capable identity (the seed is the
15
+ -- device material; the token can be re-derived from it, never the reverse).
16
+ -- Rows minted by the retired generated path carry `seed = ""` — they stay
17
+ -- valid records but must be re-minted through the bridge before the next
18
+ -- claim; the store treats a missing/empty seed as "not replay-capable".
19
+ --
20
+ -- No DDL is needed: the JSON shape already carries everything. Kept as an
21
+ -- empty migration so the migration numbering records the policy change.
22
+ SELECT 1;
@@ -0,0 +1,40 @@
1
+ -- Denormalizes the share-template family onto every telemetry event.
2
+ --
3
+ -- The share page's family rollup used to scope by an `EXISTS` against
4
+ -- `api_keys` (the template plus every child it issued). That made history
5
+ -- depend on the key row surviving: revoking/removing a key silently dropped
6
+ -- its events out of the family totals. This column pins the template on the
7
+ -- event at write time, so usage outlives the key.
8
+ --
9
+ -- Backfill is idempotent: it only fills NULL rows (the column is new, so
10
+ -- every existing row is NULL) and never overwrites a value. Events whose key
11
+ -- was already hard-deleted before this migration cannot be attributed and stay
12
+ -- NULL; the soft-delete change shipped alongside this prevents future loss.
13
+
14
+ ALTER TABLE "telemetry_events" ADD COLUMN "family_template_key_id" text;
15
+
16
+ CREATE INDEX IF NOT EXISTS "telemetry_events_tenant_family_created_id_idx"
17
+ ON "telemetry_events" ("tenant_id", "family_template_key_id", "created_at" DESC, "id" DESC);
18
+
19
+ ALTER TABLE "telemetry_usage_totals" ADD COLUMN "family_template_key_id" text;
20
+
21
+ CREATE INDEX IF NOT EXISTS "telemetry_usage_totals_tenant_family_idx"
22
+ ON "telemetry_usage_totals" ("tenant_id", "family_template_key_id");
23
+
24
+ UPDATE "telemetry_events" AS e
25
+ SET "family_template_key_id" = (
26
+ SELECT COALESCE(k."parent_key_id", k."id")
27
+ FROM "api_keys" k
28
+ WHERE k."id" = e."api_key_id"
29
+ )
30
+ WHERE e."family_template_key_id" IS NULL AND e."api_key_id" IS NOT NULL;
31
+
32
+ UPDATE "telemetry_usage_totals" AS t
33
+ SET "family_template_key_id" = (
34
+ SELECT COALESCE(k."parent_key_id", k."id")
35
+ FROM "api_keys" k
36
+ WHERE k."id" = t."entity_id"
37
+ )
38
+ WHERE t."family_template_key_id" IS NULL
39
+ AND t."identity_type" = 'api_key'
40
+ AND t."entity_id" IS NOT NULL;
@@ -0,0 +1,38 @@
1
+ -- One-time row-data optimization for share children.
2
+ --
3
+ -- Every minted share child used to copy the template's policy columns
4
+ -- (notes, limits, model_list, denylist, …). Auth never reads those from the
5
+ -- child — it resolves `policy = parent ?? row` — so the copies were pure
6
+ -- write-amplification. This UPDATE nulls the 11 nullable policy columns on
7
+ -- every child (`parent_key_id IS NOT NULL`). `scopes` stays (NOT NULL, and
8
+ -- required by backup restore); `model_access_mode` stays (NOT NULL default
9
+ -- 'whitelist'). Schema shape is unchanged — no DROP COLUMN — so backup/
10
+ -- restore remains compatible both directions.
11
+ --
12
+ -- Idempotent: the OR-of-IS-NOT-NULL predicate matches nothing on a re-run,
13
+ -- and the migration ledger skips the file after the first apply.
14
+ --
15
+ -- Keep in sync with `normalizeShareChildPolicy` in
16
+ -- `src/console/backup/store.ts` (post-restore re-applies the same null-out
17
+ -- for a tenant, because restore does not re-run numbered migrations).
18
+
19
+ UPDATE "api_keys"
20
+ SET "notes_title" = NULL,
21
+ "notes_subtitle" = NULL,
22
+ "notes_body" = NULL,
23
+ "requests_per_minute" = NULL,
24
+ "daily_token_limit" = NULL,
25
+ "monthly_token_limit" = NULL,
26
+ "lifetime_token_budget" = NULL,
27
+ "max_concurrent_requests" = NULL,
28
+ "model_prefix" = NULL,
29
+ "model_list" = NULL,
30
+ "client_router_denylist" = NULL
31
+ WHERE "parent_key_id" IS NOT NULL
32
+ AND ( "notes_title" IS NOT NULL OR "notes_subtitle" IS NOT NULL
33
+ OR "notes_body" IS NOT NULL OR "requests_per_minute" IS NOT NULL
34
+ OR "daily_token_limit" IS NOT NULL OR "monthly_token_limit" IS NOT NULL
35
+ OR "lifetime_token_budget" IS NOT NULL
36
+ OR "max_concurrent_requests" IS NOT NULL OR "model_prefix" IS NOT NULL
37
+ OR "model_list" IS NOT NULL
38
+ OR "client_router_denylist" IS NOT NULL );
@@ -0,0 +1,10 @@
1
+ -- Add a share-template child slot cap.
2
+ --
3
+ -- Share enrollment links are public, and an attacker minting child rows is
4
+ -- only bounded by the per-IP dedupe, which IP rotation (CDN edges, cloud
5
+ -- egress, residential proxies) defeats. `max_children` lets an operator cap
6
+ -- how many concurrently-active child keys a template may mint; NULL keeps the
7
+ -- legacy unlimited behavior. Enforced at mint time (not a database
8
+ -- constraint) so the error path is a clean 429/409.
9
+
10
+ ALTER TABLE "api_keys" ADD COLUMN "max_children" integer;
@@ -0,0 +1,10 @@
1
+ -- Tenant-scoped system prompt injection (append/override).
2
+ --
3
+ -- Mirror of the Postgres migration; see that file for rationale.
4
+ CREATE TABLE IF NOT EXISTS "tenant_system_prompts" (
5
+ "tenant_id" TEXT PRIMARY KEY REFERENCES "tenants" ("id") ON DELETE CASCADE,
6
+ "global" TEXT,
7
+ "providers" TEXT NOT NULL DEFAULT '{}',
8
+ "models" TEXT NOT NULL DEFAULT '{}',
9
+ "updated_at" TEXT NOT NULL DEFAULT (datetime('now'))
10
+ );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cartethyia",
3
- "version": "2.7.2",
3
+ "version": "2.7.3",
4
4
  "description": "A powerful, self-hosted reverse proxy for OpenAI- and Anthropic-compatible AI clients, powered by native Bun and Elysia. It serves both protocols from a single server, routes every model across any configured provider, and translates requests and responses in real time — streaming and prompt caching included. Underneath it runs a full delivery engine: per-account health tracking, quota and cooldown enforcement, automatic failover across pools and providers, usage accounting, and telemetry. Point OpenCode, Cline, Claude Code, Codex, or any compatible client at Cartethyia and it keeps its native protocol while the gateway absorbs every provider-specific difference behind it. Runs on embedded SQLite or external PostgreSQL with optional Redis coordination, ships as a global CLI with a system-tray console, and needs only Bun 1.4+ alongside Node.js/npm.",
5
5
  "license": "GPL-3.0-only",
6
6
  "type": "module",
@@ -116,5 +116,5 @@ export const DEFAULT_BOUNDS = {
116
116
  * matters because the gateway is designed to run several processes behind
117
117
  * `reusePort` — see `assertPoolFitsServerCapacity`.
118
118
  */
119
- maxPostgresPoolSize: 20,
119
+ maxPostgresPoolSize: 8,
120
120
  } as const;
@@ -20,7 +20,12 @@ import { utcDayStart, utcMonthStart } from "../shared/day";
20
20
  *
21
21
  * A share template's recipients admit under the parent id, and their spend is
22
22
  * attributed to their own child row, so the family is summed — otherwise
23
- * seeding a template would miss everything its recipients already used.
23
+ * seeding a template would miss everything its recipients already used. The
24
+ * family is passed to the reader as the template's id, which the query
25
+ * resolves with an `EXISTS` against `api_keys`: a family that has minted tens
26
+ * of thousands of children must not expand them into bind parameters on the
27
+ * key-creation path, which is where an old id-list version crashed the
28
+ * process.
24
29
  */
25
30
  export async function familyBucketSpend(
26
31
  db: CartethyiaDatabase,
@@ -36,15 +41,10 @@ export async function familyBucketSpend(
36
41
  .limit(1);
37
42
  const tenantId = parent?.tenantId;
38
43
  if (tenantId === undefined) return { daily: 0, monthly: 0 };
39
- const children = await db
40
- .select({ id: apiKeys.id })
41
- .from(apiKeys)
42
- .where(eq(apiKeys.parentKeyId, keyId));
43
- const keyIds = [keyId, ...children.map((child) => child.id)];
44
44
  // Two SQL sums instead of reading every event of the family: the bucket
45
45
  // spend only needs a total, and this runs on the key-creation path.
46
46
  const spentSince = async (start: Date): Promise<number> =>
47
- sumTelemetryTokens(db, tenantId, { apiKeyIds: keyIds, since: start });
47
+ sumTelemetryTokens(db, tenantId, { familyKeyId: keyId, since: start });
48
48
  const [daily, monthly] = await Promise.all([
49
49
  spentSince(utcDayStart(now)),
50
50
  spentSince(utcMonthStart(now)),