@srouterhq/server 0.0.0-stage → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1027) hide show
  1. package/LICENSE +21 -0
  2. package/client/dist/assets/am-TQ7Jmdqe.js +1 -0
  3. package/client/dist/assets/ar-Bf5a7yfC.js +1 -0
  4. package/client/dist/assets/az-CrosE1xH.js +1 -0
  5. package/client/dist/assets/bg-BvWnmcUz.js +1 -0
  6. package/client/dist/assets/bn-ams5TsJp.js +1 -0
  7. package/client/dist/assets/cs-Dh67CaJ_.js +1 -0
  8. package/client/dist/assets/da-9WlT8Iq7.js +1 -0
  9. package/client/dist/assets/de-lWhJJzz7.js +1 -0
  10. package/client/dist/assets/el-Cu7_GhNq.js +1 -0
  11. package/client/dist/assets/es-BZuzsBcP.js +1 -0
  12. package/client/dist/assets/fa-Dwdn-jKS.js +1 -0
  13. package/client/dist/assets/fi-BFrFyOTy.js +1 -0
  14. package/client/dist/assets/fr-XhbtmPpj.js +1 -0
  15. package/client/dist/assets/geist-cyrillic-ext-wght-normal-DjL33-gN.woff2 +0 -0
  16. package/client/dist/assets/geist-cyrillic-wght-normal-BEAKL7Jp.woff2 +0 -0
  17. package/client/dist/assets/geist-latin-ext-wght-normal-DC-KSUi6.woff2 +0 -0
  18. package/client/dist/assets/geist-latin-wght-normal-BgDaEnEv.woff2 +0 -0
  19. package/client/dist/assets/geist-mono-cyrillic-ext-wght-normal-I4S5GZfc.woff2 +0 -0
  20. package/client/dist/assets/geist-mono-cyrillic-wght-normal-BmXc_FBt.woff2 +0 -0
  21. package/client/dist/assets/geist-mono-latin-ext-wght-normal-DrnZ1wKl.woff2 +0 -0
  22. package/client/dist/assets/geist-mono-latin-wght-normal-B_7UjwxQ.woff2 +0 -0
  23. package/client/dist/assets/geist-mono-symbols2-wght-normal-GZpp1pK2.woff2 +0 -0
  24. package/client/dist/assets/geist-mono-vietnamese-wght-normal-D8KDMBhC.woff2 +0 -0
  25. package/client/dist/assets/geist-vietnamese-wght-normal-6IgcOCM7.woff2 +0 -0
  26. package/client/dist/assets/gu-D0uhLUB8.js +1 -0
  27. package/client/dist/assets/ha-CVlm9pqp.js +1 -0
  28. package/client/dist/assets/he-CMIFeoWr.js +1 -0
  29. package/client/dist/assets/hi-ENTwhBpn.js +1 -0
  30. package/client/dist/assets/hr-fc03vMy_.js +1 -0
  31. package/client/dist/assets/hu-YBo2BIYt.js +1 -0
  32. package/client/dist/assets/id-BEWXYX69.js +1 -0
  33. package/client/dist/assets/ig-BKLZFKka.js +1 -0
  34. package/client/dist/assets/index-D9I4KtvR.js +145 -0
  35. package/client/dist/assets/index-txhEmCdb.css +2 -0
  36. package/client/dist/assets/it-Bzmei1Y2.js +1 -0
  37. package/client/dist/assets/ja-BfcpuqEl.js +1 -0
  38. package/client/dist/assets/ka-CnWjRgLo.js +1 -0
  39. package/client/dist/assets/km-BAjPR3Qj.js +1 -0
  40. package/client/dist/assets/kn-B15WKU5m.js +1 -0
  41. package/client/dist/assets/ko-C61fAB-w.js +1 -0
  42. package/client/dist/assets/lt-CYTr4_YW.js +1 -0
  43. package/client/dist/assets/ml-CtqxgyH3.js +1 -0
  44. package/client/dist/assets/mr-X5TMY7aR.js +1 -0
  45. package/client/dist/assets/ms-DSg8RqPS.js +1 -0
  46. package/client/dist/assets/my-D7RqR8uE.js +1 -0
  47. package/client/dist/assets/ne-DaflxkDj.js +1 -0
  48. package/client/dist/assets/nl-BOqqtsC8.js +1 -0
  49. package/client/dist/assets/no-BSHp_StB.js +1 -0
  50. package/client/dist/assets/or-BkLR9Vub.js +1 -0
  51. package/client/dist/assets/pa-CarJ2XgI.js +1 -0
  52. package/client/dist/assets/pl-C2n0V-0k.js +1 -0
  53. package/client/dist/assets/pt-BR-CqJdNhg2.js +1 -0
  54. package/client/dist/assets/pt-PT-C_HpMyKz.js +1 -0
  55. package/client/dist/assets/ro-DVRZqSAS.js +1 -0
  56. package/client/dist/assets/ru-DwAJG7VC.js +1 -0
  57. package/client/dist/assets/si-BxUezXm0.js +1 -0
  58. package/client/dist/assets/sk-eI1VcIfY.js +1 -0
  59. package/client/dist/assets/sr-CJF3auCr.js +1 -0
  60. package/client/dist/assets/srouter-logo-C6ZfjGIi.svg +14 -0
  61. package/client/dist/assets/sv-nqvwHAq_.js +1 -0
  62. package/client/dist/assets/sw-DWynE2pW.js +1 -0
  63. package/client/dist/assets/ta-BVM12knC.js +1 -0
  64. package/client/dist/assets/te-oyzEkF7_.js +1 -0
  65. package/client/dist/assets/th-COVeE0ZQ.js +1 -0
  66. package/client/dist/assets/tl-DsJANnQz.js +1 -0
  67. package/client/dist/assets/tr-B-Fl-urO.js +1 -0
  68. package/client/dist/assets/uk-C5qketAO.js +1 -0
  69. package/client/dist/assets/ur-QU9KugfV.js +1 -0
  70. package/client/dist/assets/uz-DL9cG_mY.js +1 -0
  71. package/client/dist/assets/vi-CQiVy3Pu.js +1 -0
  72. package/client/dist/assets/yo-DqazMdrZ.js +1 -0
  73. package/client/dist/assets/zh-CN-DnYL_Kio.js +1 -0
  74. package/client/dist/assets/zh-TW-5bdbosKj.js +1 -0
  75. package/client/dist/favicon.svg +14 -0
  76. package/client/dist/icons.svg +24 -0
  77. package/client/dist/index.html +37 -0
  78. package/dist/app.d.ts +4 -0
  79. package/dist/app.d.ts.map +1 -0
  80. package/dist/app.js +372 -0
  81. package/dist/app.js.map +1 -0
  82. package/dist/db/index.d.ts +49 -0
  83. package/dist/db/index.d.ts.map +1 -0
  84. package/dist/db/index.js +203 -0
  85. package/dist/db/index.js.map +1 -0
  86. package/dist/db/migrate/TEMPLATE.d.ts +4 -0
  87. package/dist/db/migrate/TEMPLATE.d.ts.map +1 -0
  88. package/dist/db/migrate/TEMPLATE.js +18 -0
  89. package/dist/db/migrate/TEMPLATE.js.map +1 -0
  90. package/dist/db/migrate/cli.d.ts +2 -0
  91. package/dist/db/migrate/cli.d.ts.map +1 -0
  92. package/dist/db/migrate/cli.js +177 -0
  93. package/dist/db/migrate/cli.js.map +1 -0
  94. package/dist/db/migrate/defaults.d.ts +52 -0
  95. package/dist/db/migrate/defaults.d.ts.map +1 -0
  96. package/dist/db/migrate/defaults.js +126 -0
  97. package/dist/db/migrate/defaults.js.map +1 -0
  98. package/dist/db/migrate/runner.d.ts +16 -0
  99. package/dist/db/migrate/runner.d.ts.map +1 -0
  100. package/dist/db/migrate/runner.js +178 -0
  101. package/dist/db/migrate/runner.js.map +1 -0
  102. package/dist/db/migrations/20260101_000000_legacy_baseline.d.ts +4 -0
  103. package/dist/db/migrations/20260101_000000_legacy_baseline.d.ts.map +1 -0
  104. package/dist/db/migrations/20260101_000000_legacy_baseline.js +2240 -0
  105. package/dist/db/migrations/20260101_000000_legacy_baseline.js.map +1 -0
  106. package/dist/db/migrations/20260627_000001_custom_provider_modalities.d.ts +4 -0
  107. package/dist/db/migrations/20260627_000001_custom_provider_modalities.d.ts.map +1 -0
  108. package/dist/db/migrations/20260627_000001_custom_provider_modalities.js +27 -0
  109. package/dist/db/migrations/20260627_000001_custom_provider_modalities.js.map +1 -0
  110. package/dist/db/migrations/20260627_000002_catalog_model_state.d.ts +4 -0
  111. package/dist/db/migrations/20260627_000002_catalog_model_state.d.ts.map +1 -0
  112. package/dist/db/migrations/20260627_000002_catalog_model_state.js +30 -0
  113. package/dist/db/migrations/20260627_000002_catalog_model_state.js.map +1 -0
  114. package/dist/db/migrations/20260628_120000_request_aggregates.d.ts +6 -0
  115. package/dist/db/migrations/20260628_120000_request_aggregates.d.ts.map +1 -0
  116. package/dist/db/migrations/20260628_120000_request_aggregates.js +104 -0
  117. package/dist/db/migrations/20260628_120000_request_aggregates.js.map +1 -0
  118. package/dist/db/migrations/20260630_000001_github_gpt41_context.d.ts +9 -0
  119. package/dist/db/migrations/20260630_000001_github_gpt41_context.d.ts.map +1 -0
  120. package/dist/db/migrations/20260630_000001_github_gpt41_context.js +22 -0
  121. package/dist/db/migrations/20260630_000001_github_gpt41_context.js.map +1 -0
  122. package/dist/db/migrations/20260706_000001_request_client_info.d.ts +4 -0
  123. package/dist/db/migrations/20260706_000001_request_client_info.d.ts.map +1 -0
  124. package/dist/db/migrations/20260706_000001_request_client_info.js +30 -0
  125. package/dist/db/migrations/20260706_000001_request_client_info.js.map +1 -0
  126. package/dist/db/migrations/20260706_000002_custom_model_tool_support.d.ts +17 -0
  127. package/dist/db/migrations/20260706_000002_custom_model_tool_support.d.ts.map +1 -0
  128. package/dist/db/migrations/20260706_000002_custom_model_tool_support.js +20 -0
  129. package/dist/db/migrations/20260706_000002_custom_model_tool_support.js.map +1 -0
  130. package/dist/db/migrations/20260714_000001_profile_chain_backfill.d.ts +12 -0
  131. package/dist/db/migrations/20260714_000001_profile_chain_backfill.d.ts.map +1 -0
  132. package/dist/db/migrations/20260714_000001_profile_chain_backfill.js +45 -0
  133. package/dist/db/migrations/20260714_000001_profile_chain_backfill.js.map +1 -0
  134. package/dist/db/migrations/20260720_000001_key_health_error.d.ts +5 -0
  135. package/dist/db/migrations/20260720_000001_key_health_error.d.ts.map +1 -0
  136. package/dist/db/migrations/20260720_000001_key_health_error.js +16 -0
  137. package/dist/db/migrations/20260720_000001_key_health_error.js.map +1 -0
  138. package/dist/db/migrations/20260726_000001_cooldown_probe_provenance.d.ts +4 -0
  139. package/dist/db/migrations/20260726_000001_cooldown_probe_provenance.d.ts.map +1 -0
  140. package/dist/db/migrations/20260726_000001_cooldown_probe_provenance.js +38 -0
  141. package/dist/db/migrations/20260726_000001_cooldown_probe_provenance.js.map +1 -0
  142. package/dist/db/migrations/20260726_000002_request_attempts.d.ts +4 -0
  143. package/dist/db/migrations/20260726_000002_request_attempts.d.ts.map +1 -0
  144. package/dist/db/migrations/20260726_000002_request_attempts.js +43 -0
  145. package/dist/db/migrations/20260726_000002_request_attempts.js.map +1 -0
  146. package/dist/db/migrations/20260726_000003_model_source_provenance.d.ts +4 -0
  147. package/dist/db/migrations/20260726_000003_model_source_provenance.d.ts.map +1 -0
  148. package/dist/db/migrations/20260726_000003_model_source_provenance.js +80 -0
  149. package/dist/db/migrations/20260726_000003_model_source_provenance.js.map +1 -0
  150. package/dist/db/migrations/20260726_000004_media_model_meta.d.ts +4 -0
  151. package/dist/db/migrations/20260726_000004_media_model_meta.d.ts.map +1 -0
  152. package/dist/db/migrations/20260726_000004_media_model_meta.js +34 -0
  153. package/dist/db/migrations/20260726_000004_media_model_meta.js.map +1 -0
  154. package/dist/db/migrations/20260726_000005_request_served_model.d.ts +4 -0
  155. package/dist/db/migrations/20260726_000005_request_served_model.d.ts.map +1 -0
  156. package/dist/db/migrations/20260726_000005_request_served_model.js +31 -0
  157. package/dist/db/migrations/20260726_000005_request_served_model.js.map +1 -0
  158. package/dist/db/migrations/20260726_000006_attempt_error_summary.d.ts +4 -0
  159. package/dist/db/migrations/20260726_000006_attempt_error_summary.d.ts.map +1 -0
  160. package/dist/db/migrations/20260726_000006_attempt_error_summary.js +29 -0
  161. package/dist/db/migrations/20260726_000006_attempt_error_summary.js.map +1 -0
  162. package/dist/db/migrations/20260727_000001_agent_compatibility.d.ts +4 -0
  163. package/dist/db/migrations/20260727_000001_agent_compatibility.d.ts.map +1 -0
  164. package/dist/db/migrations/20260727_000001_agent_compatibility.js +41 -0
  165. package/dist/db/migrations/20260727_000001_agent_compatibility.js.map +1 -0
  166. package/dist/db/migrations/20260728_000001_tombstone_provenance.d.ts +12 -0
  167. package/dist/db/migrations/20260728_000001_tombstone_provenance.d.ts.map +1 -0
  168. package/dist/db/migrations/20260728_000001_tombstone_provenance.js +37 -0
  169. package/dist/db/migrations/20260728_000001_tombstone_provenance.js.map +1 -0
  170. package/dist/db/migrations/20260729_000001_custom_model_endpoint_identity.d.ts +4 -0
  171. package/dist/db/migrations/20260729_000001_custom_model_endpoint_identity.d.ts.map +1 -0
  172. package/dist/db/migrations/20260729_000001_custom_model_endpoint_identity.js +145 -0
  173. package/dist/db/migrations/20260729_000001_custom_model_endpoint_identity.js.map +1 -0
  174. package/dist/db/migrations/20260802_000001_custom_endpoint_host_labels.d.ts +6 -0
  175. package/dist/db/migrations/20260802_000001_custom_endpoint_host_labels.d.ts.map +1 -0
  176. package/dist/db/migrations/20260802_000001_custom_endpoint_host_labels.js +52 -0
  177. package/dist/db/migrations/20260802_000001_custom_endpoint_host_labels.js.map +1 -0
  178. package/dist/db/migrations/20260805_000001_key_model_scope.d.ts +6 -0
  179. package/dist/db/migrations/20260805_000001_key_model_scope.d.ts.map +1 -0
  180. package/dist/db/migrations/20260805_000001_key_model_scope.js +17 -0
  181. package/dist/db/migrations/20260805_000001_key_model_scope.js.map +1 -0
  182. package/dist/db/migrations/20260805_000002_client_profiles.d.ts +4 -0
  183. package/dist/db/migrations/20260805_000002_client_profiles.d.ts.map +1 -0
  184. package/dist/db/migrations/20260805_000002_client_profiles.js +33 -0
  185. package/dist/db/migrations/20260805_000002_client_profiles.js.map +1 -0
  186. package/dist/db/migrations/20260810_000001_api_key_proxy.d.ts +4 -0
  187. package/dist/db/migrations/20260810_000001_api_key_proxy.d.ts.map +1 -0
  188. package/dist/db/migrations/20260810_000001_api_key_proxy.js +33 -0
  189. package/dist/db/migrations/20260810_000001_api_key_proxy.js.map +1 -0
  190. package/dist/db/migrations/20260819_000001_custom_model_tombstones.d.ts +4 -0
  191. package/dist/db/migrations/20260819_000001_custom_model_tombstones.d.ts.map +1 -0
  192. package/dist/db/migrations/20260819_000001_custom_model_tombstones.js +19 -0
  193. package/dist/db/migrations/20260819_000001_custom_model_tombstones.js.map +1 -0
  194. package/dist/db/migrations/20260820_000001_playground_conversations.d.ts +4 -0
  195. package/dist/db/migrations/20260820_000001_playground_conversations.d.ts.map +1 -0
  196. package/dist/db/migrations/20260820_000001_playground_conversations.js +47 -0
  197. package/dist/db/migrations/20260820_000001_playground_conversations.js.map +1 -0
  198. package/dist/db/migrations/20260823_000001_server_logs.d.ts +4 -0
  199. package/dist/db/migrations/20260823_000001_server_logs.d.ts.map +1 -0
  200. package/dist/db/migrations/20260823_000001_server_logs.js +53 -0
  201. package/dist/db/migrations/20260823_000001_server_logs.js.map +1 -0
  202. package/dist/db/migrations/20260823_000002_backups_table.d.ts +8 -0
  203. package/dist/db/migrations/20260823_000002_backups_table.d.ts.map +1 -0
  204. package/dist/db/migrations/20260823_000002_backups_table.js +22 -0
  205. package/dist/db/migrations/20260823_000002_backups_table.js.map +1 -0
  206. package/dist/db/migrations/20260823_000003_attempt_key_label.d.ts +19 -0
  207. package/dist/db/migrations/20260823_000003_attempt_key_label.d.ts.map +1 -0
  208. package/dist/db/migrations/20260823_000003_attempt_key_label.js +28 -0
  209. package/dist/db/migrations/20260823_000003_attempt_key_label.js.map +1 -0
  210. package/dist/db/migrations/20260823_000004_profile_auto_include.d.ts +14 -0
  211. package/dist/db/migrations/20260823_000004_profile_auto_include.d.ts.map +1 -0
  212. package/dist/db/migrations/20260823_000004_profile_auto_include.js +25 -0
  213. package/dist/db/migrations/20260823_000004_profile_auto_include.js.map +1 -0
  214. package/dist/db/migrations/20260901_000001_idempotency_claims.d.ts +4 -0
  215. package/dist/db/migrations/20260901_000001_idempotency_claims.d.ts.map +1 -0
  216. package/dist/db/migrations/20260901_000001_idempotency_claims.js +46 -0
  217. package/dist/db/migrations/20260901_000001_idempotency_claims.js.map +1 -0
  218. package/dist/db/migrations/20260901_000002_quota_observation_lookup.d.ts +4 -0
  219. package/dist/db/migrations/20260901_000002_quota_observation_lookup.d.ts.map +1 -0
  220. package/dist/db/migrations/20260901_000002_quota_observation_lookup.js +37 -0
  221. package/dist/db/migrations/20260901_000002_quota_observation_lookup.js.map +1 -0
  222. package/dist/db/migrations/20260901_000003_request_caller.d.ts +4 -0
  223. package/dist/db/migrations/20260901_000003_request_caller.d.ts.map +1 -0
  224. package/dist/db/migrations/20260901_000003_request_caller.js +27 -0
  225. package/dist/db/migrations/20260901_000003_request_caller.js.map +1 -0
  226. package/dist/db/migrations/20260902_000001_analytics_latency_percentile_index.d.ts +4 -0
  227. package/dist/db/migrations/20260902_000001_analytics_latency_percentile_index.d.ts.map +1 -0
  228. package/dist/db/migrations/20260902_000001_analytics_latency_percentile_index.js +35 -0
  229. package/dist/db/migrations/20260902_000001_analytics_latency_percentile_index.js.map +1 -0
  230. package/dist/db/migrations/20260903_000001_mcp_enabled_default.d.ts +4 -0
  231. package/dist/db/migrations/20260903_000001_mcp_enabled_default.d.ts.map +1 -0
  232. package/dist/db/migrations/20260903_000001_mcp_enabled_default.js +37 -0
  233. package/dist/db/migrations/20260903_000001_mcp_enabled_default.js.map +1 -0
  234. package/dist/db/migrations/20260903_000002_response_cache.d.ts +4 -0
  235. package/dist/db/migrations/20260903_000002_response_cache.d.ts.map +1 -0
  236. package/dist/db/migrations/20260903_000002_response_cache.js +53 -0
  237. package/dist/db/migrations/20260903_000002_response_cache.js.map +1 -0
  238. package/dist/db/migrations/20260904_000001_key_monthly_budget.d.ts +13 -0
  239. package/dist/db/migrations/20260904_000001_key_monthly_budget.d.ts.map +1 -0
  240. package/dist/db/migrations/20260904_000001_key_monthly_budget.js +35 -0
  241. package/dist/db/migrations/20260904_000001_key_monthly_budget.js.map +1 -0
  242. package/dist/db/migrations/20260913_000001_request_model_attribution.d.ts +4 -0
  243. package/dist/db/migrations/20260913_000001_request_model_attribution.d.ts.map +1 -0
  244. package/dist/db/migrations/20260913_000001_request_model_attribution.js +68 -0
  245. package/dist/db/migrations/20260913_000001_request_model_attribution.js.map +1 -0
  246. package/dist/db/migrations/20260914_000001_key_monthly_usage.d.ts +5 -0
  247. package/dist/db/migrations/20260914_000001_key_monthly_usage.d.ts.map +1 -0
  248. package/dist/db/migrations/20260914_000001_key_monthly_usage.js +37 -0
  249. package/dist/db/migrations/20260914_000001_key_monthly_usage.js.map +1 -0
  250. package/dist/db/migrations/20260915_000001_quota_snapshot_freshness.d.ts +4 -0
  251. package/dist/db/migrations/20260915_000001_quota_snapshot_freshness.d.ts.map +1 -0
  252. package/dist/db/migrations/20260915_000001_quota_snapshot_freshness.js +28 -0
  253. package/dist/db/migrations/20260915_000001_quota_snapshot_freshness.js.map +1 -0
  254. package/dist/db/migrations/20261004_000001_unified_key_sr_prefix.d.ts +4 -0
  255. package/dist/db/migrations/20261004_000001_unified_key_sr_prefix.d.ts.map +1 -0
  256. package/dist/db/migrations/20261004_000001_unified_key_sr_prefix.js +25 -0
  257. package/dist/db/migrations/20261004_000001_unified_key_sr_prefix.js.map +1 -0
  258. package/dist/db/migrations/20261005_000001_key_budget_period.d.ts +10 -0
  259. package/dist/db/migrations/20261005_000001_key_budget_period.d.ts.map +1 -0
  260. package/dist/db/migrations/20261005_000001_key_budget_period.js +78 -0
  261. package/dist/db/migrations/20261005_000001_key_budget_period.js.map +1 -0
  262. package/dist/db/migrations/20261005_000002_key_budget_period_auto.d.ts +21 -0
  263. package/dist/db/migrations/20261005_000002_key_budget_period_auto.d.ts.map +1 -0
  264. package/dist/db/migrations/20261005_000002_key_budget_period_auto.js +41 -0
  265. package/dist/db/migrations/20261005_000002_key_budget_period_auto.js.map +1 -0
  266. package/dist/db/model-pricing.d.ts +39 -0
  267. package/dist/db/model-pricing.d.ts.map +1 -0
  268. package/dist/db/model-pricing.js +274 -0
  269. package/dist/db/model-pricing.js.map +1 -0
  270. package/dist/db/node-sqlite.d.ts +9 -0
  271. package/dist/db/node-sqlite.d.ts.map +1 -0
  272. package/dist/db/node-sqlite.js +87 -0
  273. package/dist/db/node-sqlite.js.map +1 -0
  274. package/dist/db/types.d.ts +22 -0
  275. package/dist/db/types.d.ts.map +1 -0
  276. package/dist/db/types.js +2 -0
  277. package/dist/db/types.js.map +1 -0
  278. package/dist/docs/docs-page.d.ts +2 -0
  279. package/dist/docs/docs-page.d.ts.map +1 -0
  280. package/dist/docs/docs-page.js +319 -0
  281. package/dist/docs/docs-page.js.map +1 -0
  282. package/dist/docs/openapi.d.ts +1896 -0
  283. package/dist/docs/openapi.d.ts.map +1 -0
  284. package/dist/docs/openapi.js +1096 -0
  285. package/dist/docs/openapi.js.map +1 -0
  286. package/dist/env.d.ts +2 -0
  287. package/dist/env.d.ts.map +1 -0
  288. package/dist/env.js +9 -0
  289. package/dist/env.js.map +1 -0
  290. package/dist/index.d.ts +2 -0
  291. package/dist/index.d.ts.map +1 -0
  292. package/dist/index.js +144 -0
  293. package/dist/index.js.map +1 -0
  294. package/dist/lib/anthropic-documents.d.ts +41 -0
  295. package/dist/lib/anthropic-documents.d.ts.map +1 -0
  296. package/dist/lib/anthropic-documents.js +132 -0
  297. package/dist/lib/anthropic-documents.js.map +1 -0
  298. package/dist/lib/app-version.d.ts +5 -0
  299. package/dist/lib/app-version.d.ts.map +1 -0
  300. package/dist/lib/app-version.js +61 -0
  301. package/dist/lib/app-version.js.map +1 -0
  302. package/dist/lib/attempt-trace.d.ts +23 -0
  303. package/dist/lib/attempt-trace.d.ts.map +1 -0
  304. package/dist/lib/attempt-trace.js +32 -0
  305. package/dist/lib/attempt-trace.js.map +1 -0
  306. package/dist/lib/budget.d.ts +6 -0
  307. package/dist/lib/budget.d.ts.map +1 -0
  308. package/dist/lib/budget.js +40 -0
  309. package/dist/lib/budget.js.map +1 -0
  310. package/dist/lib/client-classifier.d.ts +10 -0
  311. package/dist/lib/client-classifier.d.ts.map +1 -0
  312. package/dist/lib/client-classifier.js +126 -0
  313. package/dist/lib/client-classifier.js.map +1 -0
  314. package/dist/lib/client-context.d.ts +10 -0
  315. package/dist/lib/client-context.d.ts.map +1 -0
  316. package/dist/lib/client-context.js +39 -0
  317. package/dist/lib/client-context.js.map +1 -0
  318. package/dist/lib/config.d.ts +33 -0
  319. package/dist/lib/config.d.ts.map +1 -0
  320. package/dist/lib/config.js +94 -0
  321. package/dist/lib/config.js.map +1 -0
  322. package/dist/lib/content.d.ts +33 -0
  323. package/dist/lib/content.d.ts.map +1 -0
  324. package/dist/lib/content.js +201 -0
  325. package/dist/lib/content.js.map +1 -0
  326. package/dist/lib/credential.d.ts +11 -0
  327. package/dist/lib/credential.d.ts.map +1 -0
  328. package/dist/lib/credential.js +18 -0
  329. package/dist/lib/credential.js.map +1 -0
  330. package/dist/lib/crypto.d.ts +31 -0
  331. package/dist/lib/crypto.d.ts.map +1 -0
  332. package/dist/lib/crypto.js +206 -0
  333. package/dist/lib/crypto.js.map +1 -0
  334. package/dist/lib/custom-provider-cleanup.d.ts +13 -0
  335. package/dist/lib/custom-provider-cleanup.d.ts.map +1 -0
  336. package/dist/lib/custom-provider-cleanup.js +43 -0
  337. package/dist/lib/custom-provider-cleanup.js.map +1 -0
  338. package/dist/lib/db-backup.d.ts +31 -0
  339. package/dist/lib/db-backup.d.ts.map +1 -0
  340. package/dist/lib/db-backup.js +255 -0
  341. package/dist/lib/db-backup.js.map +1 -0
  342. package/dist/lib/endpoint-scope.d.ts +42 -0
  343. package/dist/lib/endpoint-scope.d.ts.map +1 -0
  344. package/dist/lib/endpoint-scope.js +95 -0
  345. package/dist/lib/endpoint-scope.js.map +1 -0
  346. package/dist/lib/env-drift.d.ts +17 -0
  347. package/dist/lib/env-drift.d.ts.map +1 -0
  348. package/dist/lib/env-drift.js +108 -0
  349. package/dist/lib/env-drift.js.map +1 -0
  350. package/dist/lib/error-classify.d.ts +40 -0
  351. package/dist/lib/error-classify.d.ts.map +1 -0
  352. package/dist/lib/error-classify.js +687 -0
  353. package/dist/lib/error-classify.js.map +1 -0
  354. package/dist/lib/error-redaction.d.ts +8 -0
  355. package/dist/lib/error-redaction.d.ts.map +1 -0
  356. package/dist/lib/error-redaction.js +45 -0
  357. package/dist/lib/error-redaction.js.map +1 -0
  358. package/dist/lib/fallback-loop.d.ts +306 -0
  359. package/dist/lib/fallback-loop.d.ts.map +1 -0
  360. package/dist/lib/fallback-loop.js +1336 -0
  361. package/dist/lib/fallback-loop.js.map +1 -0
  362. package/dist/lib/file-permissions.d.ts +98 -0
  363. package/dist/lib/file-permissions.d.ts.map +1 -0
  364. package/dist/lib/file-permissions.js +159 -0
  365. package/dist/lib/file-permissions.js.map +1 -0
  366. package/dist/lib/gemini-wire.d.ts +76 -0
  367. package/dist/lib/gemini-wire.d.ts.map +1 -0
  368. package/dist/lib/gemini-wire.js +392 -0
  369. package/dist/lib/gemini-wire.js.map +1 -0
  370. package/dist/lib/guardrails.d.ts +37 -0
  371. package/dist/lib/guardrails.d.ts.map +1 -0
  372. package/dist/lib/guardrails.js +106 -0
  373. package/dist/lib/guardrails.js.map +1 -0
  374. package/dist/lib/header-value.d.ts +8 -0
  375. package/dist/lib/header-value.d.ts.map +1 -0
  376. package/dist/lib/header-value.js +55 -0
  377. package/dist/lib/header-value.js.map +1 -0
  378. package/dist/lib/image-normalize.d.ts +21 -0
  379. package/dist/lib/image-normalize.d.ts.map +1 -0
  380. package/dist/lib/image-normalize.js +218 -0
  381. package/dist/lib/image-normalize.js.map +1 -0
  382. package/dist/lib/inbound-chat.d.ts +48 -0
  383. package/dist/lib/inbound-chat.d.ts.map +1 -0
  384. package/dist/lib/inbound-chat.js +406 -0
  385. package/dist/lib/inbound-chat.js.map +1 -0
  386. package/dist/lib/key-parser.d.ts +79 -0
  387. package/dist/lib/key-parser.d.ts.map +1 -0
  388. package/dist/lib/key-parser.js +701 -0
  389. package/dist/lib/key-parser.js.map +1 -0
  390. package/dist/lib/key-proxy.d.ts +49 -0
  391. package/dist/lib/key-proxy.d.ts.map +1 -0
  392. package/dist/lib/key-proxy.js +92 -0
  393. package/dist/lib/key-proxy.js.map +1 -0
  394. package/dist/lib/log-redaction.d.ts +28 -0
  395. package/dist/lib/log-redaction.d.ts.map +1 -0
  396. package/dist/lib/log-redaction.js +166 -0
  397. package/dist/lib/log-redaction.js.map +1 -0
  398. package/dist/lib/model-scope.d.ts +9 -0
  399. package/dist/lib/model-scope.d.ts.map +1 -0
  400. package/dist/lib/model-scope.js +29 -0
  401. package/dist/lib/model-scope.js.map +1 -0
  402. package/dist/lib/one-time-code.d.ts +15 -0
  403. package/dist/lib/one-time-code.d.ts.map +1 -0
  404. package/dist/lib/one-time-code.js +41 -0
  405. package/dist/lib/one-time-code.js.map +1 -0
  406. package/dist/lib/output-cap.d.ts +24 -0
  407. package/dist/lib/output-cap.d.ts.map +1 -0
  408. package/dist/lib/output-cap.js +80 -0
  409. package/dist/lib/output-cap.js.map +1 -0
  410. package/dist/lib/password.d.ts +3 -0
  411. package/dist/lib/password.d.ts.map +1 -0
  412. package/dist/lib/password.js +27 -0
  413. package/dist/lib/password.js.map +1 -0
  414. package/dist/lib/process-safety-net.d.ts +32 -0
  415. package/dist/lib/process-safety-net.d.ts.map +1 -0
  416. package/dist/lib/process-safety-net.js +123 -0
  417. package/dist/lib/process-safety-net.js.map +1 -0
  418. package/dist/lib/provider-identity.d.ts +37 -0
  419. package/dist/lib/provider-identity.d.ts.map +1 -0
  420. package/dist/lib/provider-identity.js +110 -0
  421. package/dist/lib/provider-identity.js.map +1 -0
  422. package/dist/lib/provider-size-parser.d.ts +6 -0
  423. package/dist/lib/provider-size-parser.d.ts.map +1 -0
  424. package/dist/lib/provider-size-parser.js +72 -0
  425. package/dist/lib/provider-size-parser.js.map +1 -0
  426. package/dist/lib/provider-timeout.d.ts +17 -0
  427. package/dist/lib/provider-timeout.d.ts.map +1 -0
  428. package/dist/lib/provider-timeout.js +70 -0
  429. package/dist/lib/provider-timeout.js.map +1 -0
  430. package/dist/lib/proxy.d.ts +180 -0
  431. package/dist/lib/proxy.d.ts.map +1 -0
  432. package/dist/lib/proxy.js +1002 -0
  433. package/dist/lib/proxy.js.map +1 -0
  434. package/dist/lib/request-log.d.ts +4 -0
  435. package/dist/lib/request-log.d.ts.map +1 -0
  436. package/dist/lib/request-log.js +161 -0
  437. package/dist/lib/request-log.js.map +1 -0
  438. package/dist/lib/reset-code.d.ts +5 -0
  439. package/dist/lib/reset-code.d.ts.map +1 -0
  440. package/dist/lib/reset-code.js +39 -0
  441. package/dist/lib/reset-code.js.map +1 -0
  442. package/dist/lib/retry-hint.d.ts +14 -0
  443. package/dist/lib/retry-hint.d.ts.map +1 -0
  444. package/dist/lib/retry-hint.js +36 -0
  445. package/dist/lib/retry-hint.js.map +1 -0
  446. package/dist/lib/route-live.d.ts +29 -0
  447. package/dist/lib/route-live.d.ts.map +1 -0
  448. package/dist/lib/route-live.js +97 -0
  449. package/dist/lib/route-live.js.map +1 -0
  450. package/dist/lib/sampling-params.d.ts +183 -0
  451. package/dist/lib/sampling-params.d.ts.map +1 -0
  452. package/dist/lib/sampling-params.js +386 -0
  453. package/dist/lib/sampling-params.js.map +1 -0
  454. package/dist/lib/scheduler.d.ts +13 -0
  455. package/dist/lib/scheduler.d.ts.map +1 -0
  456. package/dist/lib/scheduler.js +11 -0
  457. package/dist/lib/scheduler.js.map +1 -0
  458. package/dist/lib/served-model.d.ts +16 -0
  459. package/dist/lib/served-model.d.ts.map +1 -0
  460. package/dist/lib/served-model.js +0 -0
  461. package/dist/lib/served-model.js.map +1 -0
  462. package/dist/lib/server-logs.d.ts +132 -0
  463. package/dist/lib/server-logs.d.ts.map +1 -0
  464. package/dist/lib/server-logs.js +473 -0
  465. package/dist/lib/server-logs.js.map +1 -0
  466. package/dist/lib/setup-code.d.ts +5 -0
  467. package/dist/lib/setup-code.d.ts.map +1 -0
  468. package/dist/lib/setup-code.js +35 -0
  469. package/dist/lib/setup-code.js.map +1 -0
  470. package/dist/lib/structured-output.d.ts +9 -0
  471. package/dist/lib/structured-output.d.ts.map +1 -0
  472. package/dist/lib/structured-output.js +72 -0
  473. package/dist/lib/structured-output.js.map +1 -0
  474. package/dist/lib/system-prompt.d.ts +30 -0
  475. package/dist/lib/system-prompt.d.ts.map +1 -0
  476. package/dist/lib/system-prompt.js +66 -0
  477. package/dist/lib/system-prompt.js.map +1 -0
  478. package/dist/lib/task-type.d.ts +18 -0
  479. package/dist/lib/task-type.d.ts.map +1 -0
  480. package/dist/lib/task-type.js +92 -0
  481. package/dist/lib/task-type.js.map +1 -0
  482. package/dist/lib/think-tags.d.ts +37 -0
  483. package/dist/lib/think-tags.d.ts.map +1 -0
  484. package/dist/lib/think-tags.js +203 -0
  485. package/dist/lib/think-tags.js.map +1 -0
  486. package/dist/lib/tool-args.d.ts +36 -0
  487. package/dist/lib/tool-args.d.ts.map +1 -0
  488. package/dist/lib/tool-args.js +190 -0
  489. package/dist/lib/tool-args.js.map +1 -0
  490. package/dist/lib/tool-call-rescue.d.ts +62 -0
  491. package/dist/lib/tool-call-rescue.d.ts.map +1 -0
  492. package/dist/lib/tool-call-rescue.js +258 -0
  493. package/dist/lib/tool-call-rescue.js.map +1 -0
  494. package/dist/lib/tool-capability.d.ts +13 -0
  495. package/dist/lib/tool-capability.d.ts.map +1 -0
  496. package/dist/lib/tool-capability.js +70 -0
  497. package/dist/lib/tool-capability.js.map +1 -0
  498. package/dist/lib/tool-validate.d.ts +44 -0
  499. package/dist/lib/tool-validate.d.ts.map +1 -0
  500. package/dist/lib/tool-validate.js +165 -0
  501. package/dist/lib/tool-validate.js.map +1 -0
  502. package/dist/lib/ttfb-budget.d.ts +13 -0
  503. package/dist/lib/ttfb-budget.d.ts.map +1 -0
  504. package/dist/lib/ttfb-budget.js +153 -0
  505. package/dist/lib/ttfb-budget.js.map +1 -0
  506. package/dist/lib/url-guard.d.ts +47 -0
  507. package/dist/lib/url-guard.d.ts.map +1 -0
  508. package/dist/lib/url-guard.js +229 -0
  509. package/dist/lib/url-guard.js.map +1 -0
  510. package/dist/lib/wake-detect.d.ts +12 -0
  511. package/dist/lib/wake-detect.d.ts.map +1 -0
  512. package/dist/lib/wake-detect.js +99 -0
  513. package/dist/lib/wake-detect.js.map +1 -0
  514. package/dist/middleware/errorHandler.d.ts +3 -0
  515. package/dist/middleware/errorHandler.d.ts.map +1 -0
  516. package/dist/middleware/errorHandler.js +45 -0
  517. package/dist/middleware/errorHandler.js.map +1 -0
  518. package/dist/middleware/rateLimit.d.ts +4 -0
  519. package/dist/middleware/rateLimit.d.ts.map +1 -0
  520. package/dist/middleware/rateLimit.js +125 -0
  521. package/dist/middleware/rateLimit.js.map +1 -0
  522. package/dist/middleware/requireAuth.d.ts +3 -0
  523. package/dist/middleware/requireAuth.d.ts.map +1 -0
  524. package/dist/middleware/requireAuth.js +17 -0
  525. package/dist/middleware/requireAuth.js.map +1 -0
  526. package/dist/providers/aclide.d.ts +18 -0
  527. package/dist/providers/aclide.d.ts.map +1 -0
  528. package/dist/providers/aclide.js +174 -0
  529. package/dist/providers/aclide.js.map +1 -0
  530. package/dist/providers/aihorde.d.ts +42 -0
  531. package/dist/providers/aihorde.d.ts.map +1 -0
  532. package/dist/providers/aihorde.js +192 -0
  533. package/dist/providers/aihorde.js.map +1 -0
  534. package/dist/providers/airforce.d.ts +11 -0
  535. package/dist/providers/airforce.d.ts.map +1 -0
  536. package/dist/providers/airforce.js +32 -0
  537. package/dist/providers/airforce.js.map +1 -0
  538. package/dist/providers/base.d.ts +177 -0
  539. package/dist/providers/base.d.ts.map +1 -0
  540. package/dist/providers/base.js +354 -0
  541. package/dist/providers/base.js.map +1 -0
  542. package/dist/providers/blaze.d.ts +11 -0
  543. package/dist/providers/blaze.d.ts.map +1 -0
  544. package/dist/providers/blaze.js +33 -0
  545. package/dist/providers/blaze.js.map +1 -0
  546. package/dist/providers/blockrun.d.ts +14 -0
  547. package/dist/providers/blockrun.d.ts.map +1 -0
  548. package/dist/providers/blockrun.js +36 -0
  549. package/dist/providers/blockrun.js.map +1 -0
  550. package/dist/providers/clod.d.ts +11 -0
  551. package/dist/providers/clod.d.ts.map +1 -0
  552. package/dist/providers/clod.js +39 -0
  553. package/dist/providers/clod.js.map +1 -0
  554. package/dist/providers/cloudflare.d.ts +15 -0
  555. package/dist/providers/cloudflare.d.ts.map +1 -0
  556. package/dist/providers/cloudflare.js +175 -0
  557. package/dist/providers/cloudflare.js.map +1 -0
  558. package/dist/providers/cohere.d.ts +11 -0
  559. package/dist/providers/cohere.d.ts.map +1 -0
  560. package/dist/providers/cohere.js +117 -0
  561. package/dist/providers/cohere.js.map +1 -0
  562. package/dist/providers/dreamprompting.d.ts +11 -0
  563. package/dist/providers/dreamprompting.d.ts.map +1 -0
  564. package/dist/providers/dreamprompting.js +41 -0
  565. package/dist/providers/dreamprompting.js.map +1 -0
  566. package/dist/providers/electronhub.d.ts +10 -0
  567. package/dist/providers/electronhub.d.ts.map +1 -0
  568. package/dist/providers/electronhub.js +56 -0
  569. package/dist/providers/electronhub.js.map +1 -0
  570. package/dist/providers/experiential.d.ts +10 -0
  571. package/dist/providers/experiential.d.ts.map +1 -0
  572. package/dist/providers/experiential.js +33 -0
  573. package/dist/providers/experiential.js.map +1 -0
  574. package/dist/providers/gizmo.d.ts +15 -0
  575. package/dist/providers/gizmo.d.ts.map +1 -0
  576. package/dist/providers/gizmo.js +54 -0
  577. package/dist/providers/gizmo.js.map +1 -0
  578. package/dist/providers/google.d.ts +30 -0
  579. package/dist/providers/google.d.ts.map +1 -0
  580. package/dist/providers/google.js +766 -0
  581. package/dist/providers/google.js.map +1 -0
  582. package/dist/providers/index.d.ts +13 -0
  583. package/dist/providers/index.d.ts.map +1 -0
  584. package/dist/providers/index.js +561 -0
  585. package/dist/providers/index.js.map +1 -0
  586. package/dist/providers/llmtr.d.ts +15 -0
  587. package/dist/providers/llmtr.d.ts.map +1 -0
  588. package/dist/providers/llmtr.js +51 -0
  589. package/dist/providers/llmtr.js.map +1 -0
  590. package/dist/providers/logfare.d.ts +11 -0
  591. package/dist/providers/logfare.d.ts.map +1 -0
  592. package/dist/providers/logfare.js +33 -0
  593. package/dist/providers/logfare.js.map +1 -0
  594. package/dist/providers/lucidity.d.ts +11 -0
  595. package/dist/providers/lucidity.d.ts.map +1 -0
  596. package/dist/providers/lucidity.js +37 -0
  597. package/dist/providers/lucidity.js.map +1 -0
  598. package/dist/providers/modelscope.d.ts +50 -0
  599. package/dist/providers/modelscope.d.ts.map +1 -0
  600. package/dist/providers/modelscope.js +143 -0
  601. package/dist/providers/modelscope.js.map +1 -0
  602. package/dist/providers/moondream.d.ts +17 -0
  603. package/dist/providers/moondream.d.ts.map +1 -0
  604. package/dist/providers/moondream.js +140 -0
  605. package/dist/providers/moondream.js.map +1 -0
  606. package/dist/providers/openai-compat.d.ts +140 -0
  607. package/dist/providers/openai-compat.d.ts.map +1 -0
  608. package/dist/providers/openai-compat.js +537 -0
  609. package/dist/providers/openai-compat.js.map +1 -0
  610. package/dist/providers/opencode-free.d.ts +24 -0
  611. package/dist/providers/opencode-free.d.ts.map +1 -0
  612. package/dist/providers/opencode-free.js +262 -0
  613. package/dist/providers/opencode-free.js.map +1 -0
  614. package/dist/providers/pollinations.d.ts +32 -0
  615. package/dist/providers/pollinations.d.ts.map +1 -0
  616. package/dist/providers/pollinations.js +65 -0
  617. package/dist/providers/pollinations.js.map +1 -0
  618. package/dist/providers/router9.d.ts +16 -0
  619. package/dist/providers/router9.d.ts.map +1 -0
  620. package/dist/providers/router9.js +42 -0
  621. package/dist/providers/router9.js.map +1 -0
  622. package/dist/providers/sail.d.ts +44 -0
  623. package/dist/providers/sail.d.ts.map +1 -0
  624. package/dist/providers/sail.js +302 -0
  625. package/dist/providers/sail.js.map +1 -0
  626. package/dist/providers/septor.d.ts +10 -0
  627. package/dist/providers/septor.d.ts.map +1 -0
  628. package/dist/providers/septor.js +36 -0
  629. package/dist/providers/septor.js.map +1 -0
  630. package/dist/providers/speechify.d.ts +14 -0
  631. package/dist/providers/speechify.d.ts.map +1 -0
  632. package/dist/providers/speechify.js +28 -0
  633. package/dist/providers/speechify.js.map +1 -0
  634. package/dist/providers/speka.d.ts +12 -0
  635. package/dist/providers/speka.d.ts.map +1 -0
  636. package/dist/providers/speka.js +37 -0
  637. package/dist/providers/speka.js.map +1 -0
  638. package/dist/providers/waterfall.d.ts +11 -0
  639. package/dist/providers/waterfall.d.ts.map +1 -0
  640. package/dist/providers/waterfall.js +33 -0
  641. package/dist/providers/waterfall.js.map +1 -0
  642. package/dist/providers/xkiro.d.ts +71 -0
  643. package/dist/providers/xkiro.d.ts.map +1 -0
  644. package/dist/providers/xkiro.js +119 -0
  645. package/dist/providers/xkiro.js.map +1 -0
  646. package/dist/providers/zhipu.d.ts +43 -0
  647. package/dist/providers/zhipu.d.ts.map +1 -0
  648. package/dist/providers/zhipu.js +95 -0
  649. package/dist/providers/zhipu.js.map +1 -0
  650. package/dist/routes/analytics.d.ts +2 -0
  651. package/dist/routes/analytics.d.ts.map +1 -0
  652. package/dist/routes/analytics.js +738 -0
  653. package/dist/routes/analytics.js.map +1 -0
  654. package/dist/routes/anthropic.d.ts +7 -0
  655. package/dist/routes/anthropic.d.ts.map +1 -0
  656. package/dist/routes/anthropic.js +1076 -0
  657. package/dist/routes/anthropic.js.map +1 -0
  658. package/dist/routes/auth.d.ts +2 -0
  659. package/dist/routes/auth.d.ts.map +1 -0
  660. package/dist/routes/auth.js +310 -0
  661. package/dist/routes/auth.js.map +1 -0
  662. package/dist/routes/backups.d.ts +2 -0
  663. package/dist/routes/backups.d.ts.map +1 -0
  664. package/dist/routes/backups.js +127 -0
  665. package/dist/routes/backups.js.map +1 -0
  666. package/dist/routes/cache.d.ts +2 -0
  667. package/dist/routes/cache.d.ts.map +1 -0
  668. package/dist/routes/cache.js +40 -0
  669. package/dist/routes/cache.js.map +1 -0
  670. package/dist/routes/client-profiles.d.ts +2 -0
  671. package/dist/routes/client-profiles.d.ts.map +1 -0
  672. package/dist/routes/client-profiles.js +128 -0
  673. package/dist/routes/client-profiles.js.map +1 -0
  674. package/dist/routes/compression.d.ts +2 -0
  675. package/dist/routes/compression.d.ts.map +1 -0
  676. package/dist/routes/compression.js +82 -0
  677. package/dist/routes/compression.js.map +1 -0
  678. package/dist/routes/conversations.d.ts +3 -0
  679. package/dist/routes/conversations.d.ts.map +1 -0
  680. package/dist/routes/conversations.js +215 -0
  681. package/dist/routes/conversations.js.map +1 -0
  682. package/dist/routes/docs.d.ts +2 -0
  683. package/dist/routes/docs.d.ts.map +1 -0
  684. package/dist/routes/docs.js +21 -0
  685. package/dist/routes/docs.js.map +1 -0
  686. package/dist/routes/embeddings.d.ts +2 -0
  687. package/dist/routes/embeddings.d.ts.map +1 -0
  688. package/dist/routes/embeddings.js +255 -0
  689. package/dist/routes/embeddings.js.map +1 -0
  690. package/dist/routes/fallback.d.ts +2 -0
  691. package/dist/routes/fallback.d.ts.map +1 -0
  692. package/dist/routes/fallback.js +631 -0
  693. package/dist/routes/fallback.js.map +1 -0
  694. package/dist/routes/free-tier.d.ts +22 -0
  695. package/dist/routes/free-tier.d.ts.map +1 -0
  696. package/dist/routes/free-tier.js +175 -0
  697. package/dist/routes/free-tier.js.map +1 -0
  698. package/dist/routes/gemini.d.ts +2 -0
  699. package/dist/routes/gemini.d.ts.map +1 -0
  700. package/dist/routes/gemini.js +218 -0
  701. package/dist/routes/gemini.js.map +1 -0
  702. package/dist/routes/health.d.ts +2 -0
  703. package/dist/routes/health.d.ts.map +1 -0
  704. package/dist/routes/health.js +72 -0
  705. package/dist/routes/health.js.map +1 -0
  706. package/dist/routes/keys.d.ts +17 -0
  707. package/dist/routes/keys.d.ts.map +1 -0
  708. package/dist/routes/keys.js +1787 -0
  709. package/dist/routes/keys.js.map +1 -0
  710. package/dist/routes/logs.d.ts +2 -0
  711. package/dist/routes/logs.d.ts.map +1 -0
  712. package/dist/routes/logs.js +88 -0
  713. package/dist/routes/logs.js.map +1 -0
  714. package/dist/routes/mcp.d.ts +4 -0
  715. package/dist/routes/mcp.d.ts.map +1 -0
  716. package/dist/routes/mcp.js +563 -0
  717. package/dist/routes/mcp.js.map +1 -0
  718. package/dist/routes/media.d.ts +2 -0
  719. package/dist/routes/media.d.ts.map +1 -0
  720. package/dist/routes/media.js +180 -0
  721. package/dist/routes/media.js.map +1 -0
  722. package/dist/routes/models.d.ts +2 -0
  723. package/dist/routes/models.d.ts.map +1 -0
  724. package/dist/routes/models.js +439 -0
  725. package/dist/routes/models.js.map +1 -0
  726. package/dist/routes/ollama.d.ts +7 -0
  727. package/dist/routes/ollama.d.ts.map +1 -0
  728. package/dist/routes/ollama.js +595 -0
  729. package/dist/routes/ollama.js.map +1 -0
  730. package/dist/routes/profiles.d.ts +3 -0
  731. package/dist/routes/profiles.d.ts.map +1 -0
  732. package/dist/routes/profiles.js +431 -0
  733. package/dist/routes/profiles.js.map +1 -0
  734. package/dist/routes/proxy.d.ts +32 -0
  735. package/dist/routes/proxy.d.ts.map +1 -0
  736. package/dist/routes/proxy.js +2793 -0
  737. package/dist/routes/proxy.js.map +1 -0
  738. package/dist/routes/responses.d.ts +1161 -0
  739. package/dist/routes/responses.d.ts.map +1 -0
  740. package/dist/routes/responses.js +1521 -0
  741. package/dist/routes/responses.js.map +1 -0
  742. package/dist/routes/settings.d.ts +2 -0
  743. package/dist/routes/settings.d.ts.map +1 -0
  744. package/dist/routes/settings.js +549 -0
  745. package/dist/routes/settings.js.map +1 -0
  746. package/dist/routes/status.d.ts +3 -0
  747. package/dist/routes/status.d.ts.map +1 -0
  748. package/dist/routes/status.js +214 -0
  749. package/dist/routes/status.js.map +1 -0
  750. package/dist/routes/update.d.ts +31 -0
  751. package/dist/routes/update.d.ts.map +1 -0
  752. package/dist/routes/update.js +536 -0
  753. package/dist/routes/update.js.map +1 -0
  754. package/dist/routes/url-tokens.d.ts +2 -0
  755. package/dist/routes/url-tokens.d.ts.map +1 -0
  756. package/dist/routes/url-tokens.js +31 -0
  757. package/dist/routes/url-tokens.js.map +1 -0
  758. package/dist/scripts/export-catalog.d.ts +2 -0
  759. package/dist/scripts/export-catalog.d.ts.map +1 -0
  760. package/dist/scripts/export-catalog.js +114 -0
  761. package/dist/scripts/export-catalog.js.map +1 -0
  762. package/dist/scripts/rotate-encryption-key.d.ts +81 -0
  763. package/dist/scripts/rotate-encryption-key.d.ts.map +1 -0
  764. package/dist/scripts/rotate-encryption-key.js +232 -0
  765. package/dist/scripts/rotate-encryption-key.js.map +1 -0
  766. package/dist/scripts/routing-sim.d.ts +2 -0
  767. package/dist/scripts/routing-sim.d.ts.map +1 -0
  768. package/dist/scripts/routing-sim.js +130 -0
  769. package/dist/scripts/routing-sim.js.map +1 -0
  770. package/dist/scripts/test-all-models.d.ts +2 -0
  771. package/dist/scripts/test-all-models.d.ts.map +1 -0
  772. package/dist/scripts/test-all-models.js +56 -0
  773. package/dist/scripts/test-all-models.js.map +1 -0
  774. package/dist/services/anthropic-map.d.ts +39 -0
  775. package/dist/services/anthropic-map.d.ts.map +1 -0
  776. package/dist/services/anthropic-map.js +138 -0
  777. package/dist/services/anthropic-map.js.map +1 -0
  778. package/dist/services/auth.d.ts +30 -0
  779. package/dist/services/auth.d.ts.map +1 -0
  780. package/dist/services/auth.js +124 -0
  781. package/dist/services/auth.js.map +1 -0
  782. package/dist/services/auto-discover.d.ts +77 -0
  783. package/dist/services/auto-discover.d.ts.map +1 -0
  784. package/dist/services/auto-discover.js +1047 -0
  785. package/dist/services/auto-discover.js.map +1 -0
  786. package/dist/services/backups.d.ts +67 -0
  787. package/dist/services/backups.d.ts.map +1 -0
  788. package/dist/services/backups.js +444 -0
  789. package/dist/services/backups.js.map +1 -0
  790. package/dist/services/builtin-model-discovery.d.ts +107 -0
  791. package/dist/services/builtin-model-discovery.d.ts.map +1 -0
  792. package/dist/services/builtin-model-discovery.js +296 -0
  793. package/dist/services/builtin-model-discovery.js.map +1 -0
  794. package/dist/services/cache.d.ts +190 -0
  795. package/dist/services/cache.d.ts.map +1 -0
  796. package/dist/services/cache.js +617 -0
  797. package/dist/services/cache.js.map +1 -0
  798. package/dist/services/catalog-sync.d.ts +257 -0
  799. package/dist/services/catalog-sync.d.ts.map +1 -0
  800. package/dist/services/catalog-sync.js +1041 -0
  801. package/dist/services/catalog-sync.js.map +1 -0
  802. package/dist/services/compression/config.d.ts +33 -0
  803. package/dist/services/compression/config.d.ts.map +1 -0
  804. package/dist/services/compression/config.js +158 -0
  805. package/dist/services/compression/config.js.map +1 -0
  806. package/dist/services/compression/engines/aging.d.ts +2 -0
  807. package/dist/services/compression/engines/aging.d.ts.map +1 -0
  808. package/dist/services/compression/engines/aging.js +53 -0
  809. package/dist/services/compression/engines/aging.js.map +1 -0
  810. package/dist/services/compression/engines/custom-filters.d.ts +4 -0
  811. package/dist/services/compression/engines/custom-filters.d.ts.map +1 -0
  812. package/dist/services/compression/engines/custom-filters.js +49 -0
  813. package/dist/services/compression/engines/custom-filters.js.map +1 -0
  814. package/dist/services/compression/engines/dedup.d.ts +2 -0
  815. package/dist/services/compression/engines/dedup.d.ts.map +1 -0
  816. package/dist/services/compression/engines/dedup.js +61 -0
  817. package/dist/services/compression/engines/dedup.js.map +1 -0
  818. package/dist/services/compression/engines/filter-definitions.d.ts +75 -0
  819. package/dist/services/compression/engines/filter-definitions.d.ts.map +1 -0
  820. package/dist/services/compression/engines/filter-definitions.js +45 -0
  821. package/dist/services/compression/engines/filter-definitions.js.map +1 -0
  822. package/dist/services/compression/engines/hard-budget.d.ts +2 -0
  823. package/dist/services/compression/engines/hard-budget.d.ts.map +1 -0
  824. package/dist/services/compression/engines/hard-budget.js +52 -0
  825. package/dist/services/compression/engines/hard-budget.js.map +1 -0
  826. package/dist/services/compression/engines/index.d.ts +9 -0
  827. package/dist/services/compression/engines/index.d.ts.map +1 -0
  828. package/dist/services/compression/engines/index.js +9 -0
  829. package/dist/services/compression/engines/index.js.map +1 -0
  830. package/dist/services/compression/engines/jsoncompact.d.ts +3 -0
  831. package/dist/services/compression/engines/jsoncompact.d.ts.map +1 -0
  832. package/dist/services/compression/engines/jsoncompact.js +145 -0
  833. package/dist/services/compression/engines/jsoncompact.js.map +1 -0
  834. package/dist/services/compression/engines/lite.d.ts +2 -0
  835. package/dist/services/compression/engines/lite.d.ts.map +1 -0
  836. package/dist/services/compression/engines/lite.js +34 -0
  837. package/dist/services/compression/engines/lite.js.map +1 -0
  838. package/dist/services/compression/engines/read-lifecycle.d.ts +2 -0
  839. package/dist/services/compression/engines/read-lifecycle.d.ts.map +1 -0
  840. package/dist/services/compression/engines/read-lifecycle.js +70 -0
  841. package/dist/services/compression/engines/read-lifecycle.js.map +1 -0
  842. package/dist/services/compression/engines/relevance.d.ts +2 -0
  843. package/dist/services/compression/engines/relevance.d.ts.map +1 -0
  844. package/dist/services/compression/engines/relevance.js +74 -0
  845. package/dist/services/compression/engines/relevance.js.map +1 -0
  846. package/dist/services/compression/engines/toolfilter.d.ts +2 -0
  847. package/dist/services/compression/engines/toolfilter.d.ts.map +1 -0
  848. package/dist/services/compression/engines/toolfilter.js +195 -0
  849. package/dist/services/compression/engines/toolfilter.js.map +1 -0
  850. package/dist/services/compression/fidelity-gate.d.ts +12 -0
  851. package/dist/services/compression/fidelity-gate.d.ts.map +1 -0
  852. package/dist/services/compression/fidelity-gate.js +90 -0
  853. package/dist/services/compression/fidelity-gate.js.map +1 -0
  854. package/dist/services/compression/helpers.d.ts +9 -0
  855. package/dist/services/compression/helpers.d.ts.map +1 -0
  856. package/dist/services/compression/helpers.js +52 -0
  857. package/dist/services/compression/helpers.js.map +1 -0
  858. package/dist/services/compression/pipeline.d.ts +7 -0
  859. package/dist/services/compression/pipeline.d.ts.map +1 -0
  860. package/dist/services/compression/pipeline.js +245 -0
  861. package/dist/services/compression/pipeline.js.map +1 -0
  862. package/dist/services/compression/preservation.d.ts +27 -0
  863. package/dist/services/compression/preservation.d.ts.map +1 -0
  864. package/dist/services/compression/preservation.js +109 -0
  865. package/dist/services/compression/preservation.js.map +1 -0
  866. package/dist/services/compression/registry.d.ts +6 -0
  867. package/dist/services/compression/registry.d.ts.map +1 -0
  868. package/dist/services/compression/registry.js +16 -0
  869. package/dist/services/compression/registry.js.map +1 -0
  870. package/dist/services/compression/stats.d.ts +29 -0
  871. package/dist/services/compression/stats.d.ts.map +1 -0
  872. package/dist/services/compression/stats.js +55 -0
  873. package/dist/services/compression/stats.js.map +1 -0
  874. package/dist/services/compression/types.d.ts +90 -0
  875. package/dist/services/compression/types.d.ts.map +1 -0
  876. package/dist/services/compression/types.js +2 -0
  877. package/dist/services/compression/types.js.map +1 -0
  878. package/dist/services/context-handoff.d.ts +22 -0
  879. package/dist/services/context-handoff.d.ts.map +1 -0
  880. package/dist/services/context-handoff.js +164 -0
  881. package/dist/services/context-handoff.js.map +1 -0
  882. package/dist/services/cooldown-probe.d.ts +24 -0
  883. package/dist/services/cooldown-probe.d.ts.map +1 -0
  884. package/dist/services/cooldown-probe.js +181 -0
  885. package/dist/services/cooldown-probe.js.map +1 -0
  886. package/dist/services/custom-endpoint.d.ts +58 -0
  887. package/dist/services/custom-endpoint.d.ts.map +1 -0
  888. package/dist/services/custom-endpoint.js +167 -0
  889. package/dist/services/custom-endpoint.js.map +1 -0
  890. package/dist/services/custom-media-register.d.ts +22 -0
  891. package/dist/services/custom-media-register.d.ts.map +1 -0
  892. package/dist/services/custom-media-register.js +45 -0
  893. package/dist/services/custom-media-register.js.map +1 -0
  894. package/dist/services/custom-model-register.d.ts +50 -0
  895. package/dist/services/custom-model-register.d.ts.map +1 -0
  896. package/dist/services/custom-model-register.js +103 -0
  897. package/dist/services/custom-model-register.js.map +1 -0
  898. package/dist/services/custom-model-seed.d.ts +18 -0
  899. package/dist/services/custom-model-seed.d.ts.map +1 -0
  900. package/dist/services/custom-model-seed.js +42 -0
  901. package/dist/services/custom-model-seed.js.map +1 -0
  902. package/dist/services/custom-model-sync.d.ts +37 -0
  903. package/dist/services/custom-model-sync.d.ts.map +1 -0
  904. package/dist/services/custom-model-sync.js +118 -0
  905. package/dist/services/custom-model-sync.js.map +1 -0
  906. package/dist/services/custom-model-tombstone.d.ts +5 -0
  907. package/dist/services/custom-model-tombstone.d.ts.map +1 -0
  908. package/dist/services/custom-model-tombstone.js +30 -0
  909. package/dist/services/custom-model-tombstone.js.map +1 -0
  910. package/dist/services/declarative-config.d.ts +356 -0
  911. package/dist/services/declarative-config.d.ts.map +1 -0
  912. package/dist/services/declarative-config.js +427 -0
  913. package/dist/services/declarative-config.js.map +1 -0
  914. package/dist/services/degradation.d.ts +40 -0
  915. package/dist/services/degradation.d.ts.map +1 -0
  916. package/dist/services/degradation.js +119 -0
  917. package/dist/services/degradation.js.map +1 -0
  918. package/dist/services/embeddings.d.ts +76 -0
  919. package/dist/services/embeddings.d.ts.map +1 -0
  920. package/dist/services/embeddings.js +319 -0
  921. package/dist/services/embeddings.js.map +1 -0
  922. package/dist/services/fusion.d.ts +162 -0
  923. package/dist/services/fusion.d.ts.map +1 -0
  924. package/dist/services/fusion.js +789 -0
  925. package/dist/services/fusion.js.map +1 -0
  926. package/dist/services/gemini-map.d.ts +14 -0
  927. package/dist/services/gemini-map.d.ts.map +1 -0
  928. package/dist/services/gemini-map.js +78 -0
  929. package/dist/services/gemini-map.js.map +1 -0
  930. package/dist/services/health.d.ts +52 -0
  931. package/dist/services/health.d.ts.map +1 -0
  932. package/dist/services/health.js +352 -0
  933. package/dist/services/health.js.map +1 -0
  934. package/dist/services/idempotency.d.ts +49 -0
  935. package/dist/services/idempotency.d.ts.map +1 -0
  936. package/dist/services/idempotency.js +140 -0
  937. package/dist/services/idempotency.js.map +1 -0
  938. package/dist/services/key-budget.d.ts +74 -0
  939. package/dist/services/key-budget.d.ts.map +1 -0
  940. package/dist/services/key-budget.js +200 -0
  941. package/dist/services/key-budget.js.map +1 -0
  942. package/dist/services/media.d.ts +123 -0
  943. package/dist/services/media.d.ts.map +1 -0
  944. package/dist/services/media.js +954 -0
  945. package/dist/services/media.js.map +1 -0
  946. package/dist/services/model-discovery.d.ts +126 -0
  947. package/dist/services/model-discovery.d.ts.map +1 -0
  948. package/dist/services/model-discovery.js +662 -0
  949. package/dist/services/model-discovery.js.map +1 -0
  950. package/dist/services/model-groups.d.ts +149 -0
  951. package/dist/services/model-groups.d.ts.map +1 -0
  952. package/dist/services/model-groups.js +314 -0
  953. package/dist/services/model-groups.js.map +1 -0
  954. package/dist/services/model-listing.d.ts +18 -0
  955. package/dist/services/model-listing.d.ts.map +1 -0
  956. package/dist/services/model-listing.js +94 -0
  957. package/dist/services/model-listing.js.map +1 -0
  958. package/dist/services/model-retirement.d.ts +29 -0
  959. package/dist/services/model-retirement.d.ts.map +1 -0
  960. package/dist/services/model-retirement.js +86 -0
  961. package/dist/services/model-retirement.js.map +1 -0
  962. package/dist/services/model-state.d.ts +90 -0
  963. package/dist/services/model-state.d.ts.map +1 -0
  964. package/dist/services/model-state.js +342 -0
  965. package/dist/services/model-state.js.map +1 -0
  966. package/dist/services/model-weight-overrides.d.ts +48 -0
  967. package/dist/services/model-weight-overrides.d.ts.map +1 -0
  968. package/dist/services/model-weight-overrides.js +127 -0
  969. package/dist/services/model-weight-overrides.js.map +1 -0
  970. package/dist/services/notification-emitter.d.ts +50 -0
  971. package/dist/services/notification-emitter.d.ts.map +1 -0
  972. package/dist/services/notification-emitter.js +177 -0
  973. package/dist/services/notification-emitter.js.map +1 -0
  974. package/dist/services/opencode-free-sync.d.ts +29 -0
  975. package/dist/services/opencode-free-sync.d.ts.map +1 -0
  976. package/dist/services/opencode-free-sync.js +206 -0
  977. package/dist/services/opencode-free-sync.js.map +1 -0
  978. package/dist/services/penalty-inspector.d.ts +56 -0
  979. package/dist/services/penalty-inspector.d.ts.map +1 -0
  980. package/dist/services/penalty-inspector.js +167 -0
  981. package/dist/services/penalty-inspector.js.map +1 -0
  982. package/dist/services/profile-models.d.ts +5 -0
  983. package/dist/services/profile-models.d.ts.map +1 -0
  984. package/dist/services/profile-models.js +62 -0
  985. package/dist/services/profile-models.js.map +1 -0
  986. package/dist/services/provider-credential.d.ts +19 -0
  987. package/dist/services/provider-credential.d.ts.map +1 -0
  988. package/dist/services/provider-credential.js +51 -0
  989. package/dist/services/provider-credential.js.map +1 -0
  990. package/dist/services/provider-quota.d.ts +64 -0
  991. package/dist/services/provider-quota.d.ts.map +1 -0
  992. package/dist/services/provider-quota.js +563 -0
  993. package/dist/services/provider-quota.js.map +1 -0
  994. package/dist/services/quirks.d.ts +0 -0
  995. package/dist/services/quirks.d.ts.map +1 -0
  996. package/dist/services/quirks.js +0 -0
  997. package/dist/services/quirks.js.map +1 -0
  998. package/dist/services/quota-forecast.d.ts +50 -0
  999. package/dist/services/quota-forecast.d.ts.map +1 -0
  1000. package/dist/services/quota-forecast.js +150 -0
  1001. package/dist/services/quota-forecast.js.map +1 -0
  1002. package/dist/services/quota-outlook.d.ts +4 -0
  1003. package/dist/services/quota-outlook.d.ts.map +1 -0
  1004. package/dist/services/quota-outlook.js +92 -0
  1005. package/dist/services/quota-outlook.js.map +1 -0
  1006. package/dist/services/ratelimit.d.ts +249 -0
  1007. package/dist/services/ratelimit.d.ts.map +1 -0
  1008. package/dist/services/ratelimit.js +1182 -0
  1009. package/dist/services/ratelimit.js.map +1 -0
  1010. package/dist/services/request-retention.d.ts +60 -0
  1011. package/dist/services/request-retention.d.ts.map +1 -0
  1012. package/dist/services/request-retention.js +229 -0
  1013. package/dist/services/request-retention.js.map +1 -0
  1014. package/dist/services/router.d.ts +384 -0
  1015. package/dist/services/router.d.ts.map +1 -0
  1016. package/dist/services/router.js +1986 -0
  1017. package/dist/services/router.js.map +1 -0
  1018. package/dist/services/scoring.d.ts +156 -0
  1019. package/dist/services/scoring.d.ts.map +1 -0
  1020. package/dist/services/scoring.js +435 -0
  1021. package/dist/services/scoring.js.map +1 -0
  1022. package/dist/services/url-tokens.d.ts +15 -0
  1023. package/dist/services/url-tokens.d.ts.map +1 -0
  1024. package/dist/services/url-tokens.js +55 -0
  1025. package/dist/services/url-tokens.js.map +1 -0
  1026. package/package.json +77 -4
  1027. package/README.md +0 -3
@@ -0,0 +1,1041 @@
1
+ import crypto from 'crypto';
2
+ import { getDb, getSetting, setSetting } from '../db/index.js';
3
+ import { hasProvider } from '../providers/index.js';
4
+ import { MEDIA_PLATFORMS, TRANSCRIPTION_PLATFORMS, VIDEO_PLATFORMS } from './media.js';
5
+ import { EMBEDDING_PLATFORMS } from './embeddings.js';
6
+ import { applyAllModelOverrides, refreshModelOverrideBaselines, routableContextWindow, applyModelOverrides, deleteTombstonedCatalogModels, isCatalogModelTombstoned, reinstateUpstreamRetiredCatalogModel, } from './model-state.js';
7
+ import { ensureAllModelsInProfiles } from './profile-models.js';
8
+ // Generative-media modalities are routed into the separate media_models table
9
+ // (see services/media.ts), never into the chat `models` table.
10
+ const MEDIA_MODALITIES = new Set(['image', 'audio']);
11
+ /**
12
+ * catalog-sync — keeps the local model catalog in step with the published one.
13
+ *
14
+ * Twice a day (and on on boot) the server pulls the signed catalog from the
15
+ * catalog service. Everyone gets the monthly snapshot, which self-heals on a
16
+ * regular cadence. The response is verified against a pinned Ed25519 public
17
+ * key over the exact bytes received; anything unsigned or tampered with is
18
+ * discarded, which means a compromised CDN or MITM cannot inject models or
19
+ * quirks into the router.
20
+ *
21
+ * The bundled migrations remain the baseline: a fetched catalog is applied
22
+ * only when it is NEWER than what the binary shipped with (MIN_CATALOG_VERSION
23
+ * below), so a stale monthly snapshot can never roll back models that a newer
24
+ * app version added via migrations.
25
+ */
26
+ const DEFAULT_BASE_URL = 'https://api.freellmapi.co';
27
+ // The Ed25519 public key the production catalog is signed with. The private
28
+ // half was generated on the catalog host and has never left it. Self-hosters
29
+ // running their own catalog server can override both via env.
30
+ const PINNED_CATALOG_PUBKEY = `-----BEGIN PUBLIC KEY-----
31
+ MCowBQYDK2VwAyEAq9yv4+3EeyMHKsfVYBhkcz1lYgIXSUeHNnN6tNgYX3k=
32
+ -----END PUBLIC KEY-----
33
+ `;
34
+ // Catalogs older than this are ignored. Bump to today's date whenever a model
35
+ // migration lands, so the bundled DB is always the floor.
36
+ export const MIN_CATALOG_VERSION = '2026.06.07';
37
+ const DEFAULT_SYNC_INTERVAL_MS = 12 * 60 * 60 * 1000; // default: 12h
38
+ const BOOT_DELAY_MS = 10 * 1000; // let the server settle before first sync
39
+ const FETCH_TIMEOUT_MS = 20 * 1000;
40
+ // settings table keys
41
+ const SETTING_APPLIED_VERSION = 'catalog_applied_version';
42
+ const SETTING_APPLIED_TIER = 'catalog_applied_tier';
43
+ const SETTING_APPLIED_JSON = 'catalog_applied_json';
44
+ const SETTING_LAST_SYNC_MS = 'catalog_last_sync_ms';
45
+ const SETTING_LAST_ERROR = 'catalog_last_error';
46
+ const SETTING_SYNC_INTERVAL_HOURS = 'sync_interval_hours';
47
+ const SETTING_NOTIFICATIONS = 'sync_notifications';
48
+ const VALID_INTERVALS = ['off', 6, 12, 24];
49
+ export function getSyncIntervalHours() {
50
+ const raw = getSetting(SETTING_SYNC_INTERVAL_HOURS);
51
+ // Unset (fresh install) keeps the upstream default of twice daily; only an
52
+ // explicit 'off' disables the timer.
53
+ if (!raw)
54
+ return DEFAULT_SYNC_INTERVAL_MS / (60 * 60 * 1000);
55
+ if (raw === 'off')
56
+ return 'off';
57
+ const n = Number(raw);
58
+ return VALID_INTERVALS.includes(n) ? n : 'off';
59
+ }
60
+ export function setSyncIntervalHours(interval) {
61
+ setSetting(SETTING_SYNC_INTERVAL_HOURS, interval === 'off' ? 'off' : String(interval));
62
+ }
63
+ function syncIntervalMs() {
64
+ const hours = getSyncIntervalHours();
65
+ return hours === 'off' ? 0 : hours * 60 * 60 * 1000;
66
+ }
67
+ export function getNotifications() {
68
+ const raw = getSetting(SETTING_NOTIFICATIONS);
69
+ if (!raw)
70
+ return [];
71
+ try {
72
+ const parsed = JSON.parse(raw);
73
+ if (!Array.isArray(parsed))
74
+ return [];
75
+ const rows = parsed;
76
+ // A *pending* update notification is pinned above everything else no
77
+ // matter how old it is: the operator must keep seeing it (and the bell
78
+ // badge) until the update lands. Everything else — including a settled
79
+ // update row — is plain newest-first chronological order. Storage stays
80
+ // chronological; the pin is presentation, applied on read.
81
+ const pinned = (n) => n.type === 'update_available' && !n.read ? 1 : 0;
82
+ return [...rows].sort((a, b) => pinned(b) - pinned(a) || b.timestamp - a.timestamp);
83
+ }
84
+ catch {
85
+ return [];
86
+ }
87
+ }
88
+ export function addNotifications(notifs) {
89
+ if (notifs.length === 0)
90
+ return;
91
+ const existing = getNotifications();
92
+ // Prepend new ones, cap at 50.
93
+ const merged = [...notifs, ...existing].slice(0, 50);
94
+ merged.sort((a, b) => b.timestamp - a.timestamp);
95
+ setSetting(SETTING_NOTIFICATIONS, JSON.stringify(merged));
96
+ }
97
+ export function markNotificationsRead() {
98
+ // A pending update_available row deliberately survives the mark-all: the
99
+ // bell keeps its badge until the update actually lands (the periodic check
100
+ // settles it via settleUpdateNotifications). Everything else reads on cue.
101
+ const all = getNotifications().map(n => n.type === 'update_available' && !n.read ? n : { ...n, read: true });
102
+ setSetting(SETTING_NOTIFICATIONS, JSON.stringify(all));
103
+ }
104
+ /**
105
+ * Settle the update-available reminder once the installed version caught up:
106
+ * collapse historical duplicates down to the newest row, mark it read (which
107
+ * un-pins it — it sinks into normal chronological order), and keep it in the
108
+ * list so the history still shows what happened.
109
+ */
110
+ export function settleUpdateNotifications() {
111
+ const all = getNotifications();
112
+ const updates = all.filter(n => n.type === 'update_available');
113
+ if (updates.length === 0)
114
+ return;
115
+ if (updates.length === 1 && updates[0].read)
116
+ return;
117
+ updates.sort((a, b) => b.timestamp - a.timestamp);
118
+ const rest = all.filter(n => n.type !== 'update_available');
119
+ const merged = [{ ...updates[0], read: true }, ...rest]
120
+ .sort((a, b) => b.timestamp - a.timestamp)
121
+ .slice(0, 50);
122
+ setSetting(SETTING_NOTIFICATIONS, JSON.stringify(merged));
123
+ }
124
+ export function unreadNotificationCount() {
125
+ return getNotifications().filter(n => !n.read).length;
126
+ }
127
+ /** Remove all notifications of a given type (e.g. 'update_available' after user updates). */
128
+ export function removeNotificationsByType(type) {
129
+ const all = getNotifications();
130
+ const filtered = all.filter(n => n.type !== type);
131
+ if (filtered.length === all.length)
132
+ return; // nothing matched — skip the write
133
+ setSetting(SETTING_NOTIFICATIONS, JSON.stringify(filtered));
134
+ }
135
+ export function catalogBaseUrl() {
136
+ return (process.env.CATALOG_BASE_URL ?? DEFAULT_BASE_URL).replace(/\/$/, '');
137
+ }
138
+ function catalogPublicKey() {
139
+ const pem = process.env.CATALOG_PUBKEY ? process.env.CATALOG_PUBKEY.replace(/\\n/g, '\n') : PINNED_CATALOG_PUBKEY;
140
+ return crypto.createPublicKey({ key: pem, format: 'pem' });
141
+ }
142
+ /** Minimal structural check — enough to fail loudly on a wrong/garbled body. */
143
+ function isCatalog(value) {
144
+ const c = value;
145
+ return (!!c &&
146
+ typeof c.version === 'string' &&
147
+ (c.tier === 'live' || c.tier === 'monthly') &&
148
+ Array.isArray(c.models) &&
149
+ Array.isArray(c.quirks) &&
150
+ (c.embeddings === undefined ||
151
+ (Array.isArray(c.embeddings) &&
152
+ c.embeddings.every((m) => typeof m?.family === 'string' &&
153
+ typeof m?.platform === 'string' &&
154
+ typeof m?.modelId === 'string' &&
155
+ typeof m?.displayName === 'string' &&
156
+ typeof m?.dimensions === 'number' &&
157
+ typeof m?.priority === 'number' &&
158
+ typeof m?.enabled === 'boolean'))) &&
159
+ (c.transcriptionModels === undefined ||
160
+ (Array.isArray(c.transcriptionModels) &&
161
+ c.transcriptionModels.every((m) => typeof m?.platform === 'string' &&
162
+ typeof m?.modelId === 'string' &&
163
+ typeof m?.displayName === 'string' &&
164
+ typeof m?.priority === 'number' &&
165
+ typeof m?.enabled === 'boolean' &&
166
+ (m.subtitleFormats === undefined ||
167
+ (Array.isArray(m.subtitleFormats) && m.subtitleFormats.every((f) => typeof f === 'string'))) &&
168
+ (m.maxBytes === undefined || m.maxBytes === null || typeof m.maxBytes === 'number') &&
169
+ (m.requestStyle === undefined || m.requestStyle === null || typeof m.requestStyle === 'string')))) &&
170
+ (c.videoModels === undefined ||
171
+ (Array.isArray(c.videoModels) &&
172
+ c.videoModels.every((m) => typeof m?.platform === 'string' &&
173
+ typeof m?.modelId === 'string' &&
174
+ typeof m?.displayName === 'string' &&
175
+ typeof m?.priority === 'number' &&
176
+ typeof m?.enabled === 'boolean' &&
177
+ (m.quotaLabel === undefined || typeof m.quotaLabel === 'string') &&
178
+ (m.providerModelId === undefined || typeof m.providerModelId === 'string')))) &&
179
+ c.models.every((m) => typeof m?.platform === 'string' &&
180
+ typeof m?.modelId === 'string' &&
181
+ typeof m?.displayName === 'string' &&
182
+ typeof m?.enabled === 'boolean' &&
183
+ (m.requestStyle === undefined || m.requestStyle === null || typeof m.requestStyle === 'string') &&
184
+ !!m?.limits &&
185
+ typeof m.limits === 'object') &&
186
+ (c.managedPlatforms === undefined ||
187
+ (Array.isArray(c.managedPlatforms) && c.managedPlatforms.every((p) => typeof p === 'string'))) &&
188
+ c.quirks.every((q) => typeof q?.slug === 'string' && Array.isArray(q?.targets)));
189
+ }
190
+ /**
191
+ * Apply a verified catalog to the local DB inside one transaction.
192
+ *
193
+ * Rules of engagement with user data:
194
+ * - metadata (name, ranks, limits, context, capabilities) tracks the catalog
195
+ * unless the user has an explicit local override;
196
+ * - catalog enabled=false force-disables (the model is dead upstream), but
197
+ * enabled=true never re-enables a model the user turned off themselves;
198
+ * - rows the user created (models.source = 'user': custom providers,
199
+ * declarative config, admin adds) are never updated, never deleted, and
200
+ * never adopted — on a platform:model_id collision the user row wins and
201
+ * the catalog entry is skipped outright;
202
+ * - catalog models the user deleted stay deleted via tombstones, while models
203
+ * auto-retired from an upstream 410/end-of-life response (#634) are only
204
+ * disabled — a catalog that still lists them lifts the retirement;
205
+ * - models that vanished from the catalog are deleted, exactly like the
206
+ * dead-model migrations do (fallback_config row first, FK order);
207
+ * - rows found by built-in model discovery (models.source = 'discovered',
208
+ * #1348) are a stopgap for platforms the catalog does not manage. The
209
+ * catalog outranks them: a listed platform:model_id adopts the discovered
210
+ * row as a catalog row, and once the catalog manages a platform at all,
211
+ * every other discovered row on it is retired.
212
+ */
213
+ /** models.source for rows written by built-in model discovery (#1348). */
214
+ export const DISCOVERED_MODEL_SOURCE = 'discovered';
215
+ /** Every platform a catalog document manages: any row in any registry, plus
216
+ * the names-only managedPlatforms list. */
217
+ function catalogPlatforms(catalog) {
218
+ const platforms = new Set();
219
+ for (const m of catalog.models)
220
+ platforms.add(m.platform);
221
+ for (const m of catalog.embeddings ?? [])
222
+ platforms.add(m.platform);
223
+ for (const m of catalog.transcriptionModels ?? [])
224
+ platforms.add(m.platform);
225
+ for (const m of catalog.videoModels ?? [])
226
+ platforms.add(m.platform);
227
+ for (const p of catalog.managedPlatforms ?? [])
228
+ platforms.add(p);
229
+ return platforms;
230
+ }
231
+ let appliedPlatformsCache = null;
232
+ /**
233
+ * Platforms the catalog applied on this install manages (see catalogPlatforms),
234
+ * read from the cached verified document. Empty when no catalog has been
235
+ * applied yet. Built-in model discovery treats every platform in here as off
236
+ * limits, so the audited catalog, not an upstream /models list, decides what
237
+ * those providers serve.
238
+ */
239
+ export function appliedCatalogPlatforms(db) {
240
+ const row = db.prepare('SELECT value FROM settings WHERE key = ?').get(SETTING_APPLIED_JSON);
241
+ const raw = row?.value ?? '';
242
+ if (appliedPlatformsCache && appliedPlatformsCache.raw === raw)
243
+ return appliedPlatformsCache.platforms;
244
+ let platforms = new Set();
245
+ if (raw) {
246
+ try {
247
+ const parsed = JSON.parse(raw);
248
+ if (isCatalog(parsed))
249
+ platforms = catalogPlatforms(parsed);
250
+ }
251
+ catch { /* an unreadable cache manages nothing; the DB checks still apply */ }
252
+ }
253
+ appliedPlatformsCache = { raw, platforms };
254
+ return platforms;
255
+ }
256
+ export function applyCatalog(db, catalog) {
257
+ return applyCatalogDetailed(db, catalog).counts;
258
+ }
259
+ /** Same apply, but also returns the per-platform ledger of which models
260
+ * changed — what feeds the "3 models added on Groq" bell notifications.
261
+ * Counts alone cannot name a provider or a model. */
262
+ export function applyCatalogDetailed(db, catalog) {
263
+ // One transaction for the whole apply (#1047): the body runs hundreds of
264
+ // individual statements, and under WAL each one outside a transaction is its
265
+ // own commit + fsync executed on the event loop. On slow storage that made
266
+ // the 12-hourly sync freeze every in-flight request — including the 3-query
267
+ // profile-activate POST — for minutes.
268
+ return db.transaction(() => applyCatalogInner(db, catalog))();
269
+ }
270
+ function applyCatalogInner(db, catalog) {
271
+ const counts = { updated: 0, inserted: 0, removed: 0, skippedUnknownPlatform: 0, quirks: 0 };
272
+ const details = { added: new Map(), removed: new Map(), updated: new Map() };
273
+ /** Note one model change against its provider. Names use the catalog
274
+ * display_name where we have it (that is what the user recognises) and fall
275
+ * back to the raw model_id for pruned rows, whose catalog entry is gone. */
276
+ const record = (ledger, platform, name) => {
277
+ const bucket = ledger.get(platform);
278
+ if (bucket)
279
+ bucket.push(name);
280
+ else
281
+ ledger.set(platform, [name]);
282
+ };
283
+ // The previous display_name/enabled are read alongside so an "updated" entry
284
+ // records what actually changed. Without them every catalog row looks
285
+ // updated on every sync, which drowns the real news.
286
+ const selectModel = db.prepare('SELECT id, enabled, source, display_name AS displayName FROM models WHERE platform = ? AND model_id = ?');
287
+ const updateModel = db.prepare(`
288
+ UPDATE models SET
289
+ display_name = @displayName, intelligence_rank = @intelligenceRank, speed_rank = @speedRank,
290
+ size_label = @sizeLabel, rpm_limit = @rpm, rpd_limit = @rpd, tpm_limit = @tpm, tpd_limit = @tpd,
291
+ monthly_token_budget = @monthlyTokenBudget, context_window = @contextWindow,
292
+ supports_vision = @supportsVision, supports_tools = @supportsTools,
293
+ enabled = @enabled
294
+ WHERE id = @id
295
+ `);
296
+ const adoptModel = db.prepare("UPDATE models SET source = 'catalog' WHERE id = ?");
297
+ const insertModel = db.prepare(`
298
+ INSERT INTO models (platform, model_id, display_name, intelligence_rank, speed_rank, size_label,
299
+ rpm_limit, rpd_limit, tpm_limit, tpd_limit, monthly_token_budget, context_window,
300
+ enabled, supports_vision, supports_tools, source)
301
+ VALUES (@platform, @modelId, @displayName, @intelligenceRank, @speedRank, @sizeLabel,
302
+ @rpm, @rpd, @tpm, @tpd, @monthlyTokenBudget, @contextWindow,
303
+ @enabled, @supportsVision, @supportsTools, 'catalog')
304
+ `);
305
+ // Generative-media models go to their own table (never the chat router's pool).
306
+ const selectMedia = db.prepare('SELECT id, enabled, display_name AS displayName FROM media_models WHERE platform = ? AND model_id = ?');
307
+ const updateMedia = db.prepare(`
308
+ UPDATE media_models SET
309
+ display_name = @displayName, modality = @modality, priority = @priority,
310
+ quota_label = @quotaLabel, enabled = @enabled, meta_json = @metaJson
311
+ WHERE id = @id
312
+ `);
313
+ const insertMedia = db.prepare(`
314
+ INSERT INTO media_models (platform, model_id, display_name, modality, priority, enabled, quota_label, meta_json)
315
+ VALUES (@platform, @modelId, @displayName, @modality, @priority, @enabled, @quotaLabel, @metaJson)
316
+ `);
317
+ // Transcription rows share media_models but carry adapter metadata in
318
+ // meta_json (subtitle capability, upload ceiling, request flavor).
319
+ const updateTranscription = db.prepare(`
320
+ UPDATE media_models SET
321
+ display_name = @displayName, modality = 'transcription', priority = @priority,
322
+ quota_label = @quotaLabel, enabled = @enabled, meta_json = @metaJson
323
+ WHERE id = @id
324
+ `);
325
+ const insertTranscription = db.prepare(`
326
+ INSERT INTO media_models (platform, model_id, display_name, modality, priority, enabled, quota_label, meta_json)
327
+ VALUES (@platform, @modelId, @displayName, 'transcription', @priority, @enabled, @quotaLabel, @metaJson)
328
+ `);
329
+ const selectEmbedding = db.prepare('SELECT id, enabled, display_name AS displayName FROM embedding_models WHERE platform = ? AND model_id = ?');
330
+ const updateEmbedding = db.prepare(`
331
+ UPDATE embedding_models SET
332
+ family = @family, display_name = @displayName, dimensions = @dimensions,
333
+ max_input_tokens = @maxInputTokens, priority = @priority,
334
+ quota_label = @quotaLabel, enabled = @enabled
335
+ WHERE id = @id
336
+ `);
337
+ const insertEmbedding = db.prepare(`
338
+ INSERT INTO embedding_models
339
+ (family, platform, model_id, display_name, dimensions, max_input_tokens,
340
+ priority, enabled, quota_label)
341
+ VALUES
342
+ (@family, @platform, @modelId, @displayName, @dimensions, @maxInputTokens,
343
+ @priority, @enabled, @quotaLabel)
344
+ `);
345
+ const apply = db.transaction(() => {
346
+ const inCatalog = new Set();
347
+ const inMediaCatalog = new Set();
348
+ const inEmbeddingCatalog = new Set();
349
+ const inTranscriptionCatalog = new Set();
350
+ const inVideoCatalog = new Set();
351
+ for (const m of catalog.models) {
352
+ // Media modalities are gated on MEDIA_PLATFORMS (decoupled from the chat
353
+ // provider registry) and routed to media_models, then skip the chat path.
354
+ const modality = m.modality ?? 'text';
355
+ if (MEDIA_MODALITIES.has(modality)) {
356
+ if (!MEDIA_PLATFORMS.has(m.platform)) {
357
+ counts.skippedUnknownPlatform++;
358
+ continue;
359
+ }
360
+ if (isCatalogModelTombstoned(db, 'media', m.platform, m.modelId))
361
+ continue;
362
+ inMediaCatalog.add(`${m.platform}:${m.modelId}`);
363
+ const mrow = selectMedia.get(m.platform, m.modelId);
364
+ // Generative-media meta carries only the adapter request flavor today;
365
+ // a row without one stores NULL so the adapter keeps its default.
366
+ const mmeta = {};
367
+ if (typeof m.requestStyle === 'string')
368
+ mmeta.requestStyle = m.requestStyle;
369
+ const mfields = {
370
+ displayName: m.displayName,
371
+ modality,
372
+ priority: m.intelligenceRank ?? 0,
373
+ quotaLabel: m.mediaNote ?? '',
374
+ metaJson: Object.keys(mmeta).length > 0 ? JSON.stringify(mmeta) : null,
375
+ };
376
+ if (mrow) {
377
+ const enabled = m.enabled ? mrow.enabled : 0; // catalog disable wins; local disable wins
378
+ updateMedia.run({ ...mfields, id: mrow.id, enabled });
379
+ counts.updated++;
380
+ if (mrow.displayName !== m.displayName)
381
+ record(details.updated, m.platform, m.displayName);
382
+ }
383
+ else {
384
+ insertMedia.run({ ...mfields, platform: m.platform, modelId: m.modelId, enabled: m.enabled ? 1 : 0 });
385
+ counts.inserted++;
386
+ record(details.added, m.platform, m.displayName);
387
+ }
388
+ continue;
389
+ }
390
+ if (m.platform === 'custom' || !hasProvider(m.platform)) {
391
+ // An older binary may receive models for providers it cannot route yet;
392
+ // skip them — they will appear after the user updates the app.
393
+ counts.skippedUnknownPlatform++;
394
+ continue;
395
+ }
396
+ if (isCatalogModelTombstoned(db, 'chat', m.platform, m.modelId))
397
+ continue;
398
+ // A model auto-retired from a 410/end-of-life response (#634) is disabled,
399
+ // not deleted. A catalog that STILL lists it — and lists it enabled — is
400
+ // newer evidence than that one provider response, so lift the retirement.
401
+ if (m.enabled)
402
+ reinstateUpstreamRetiredCatalogModel(db, m.platform, m.modelId);
403
+ inCatalog.add(`${m.platform}:${m.modelId}`);
404
+ const row = selectModel.get(m.platform, m.modelId);
405
+ // Collision rule: if the user hand-added a model and the catalog later
406
+ // ships the same platform:model_id, the user row wins — the catalog
407
+ // neither clobbers its metadata nor adopts it (same spirit as the
408
+ // never-touch rule for custom-provider models). The row also survives
409
+ // the prune below because the delete pass only considers source='catalog'.
410
+ if (row && row.source === 'user')
411
+ continue;
412
+ // #1348: a DISCOVERED row is the opposite case. Discovery only fills a
413
+ // gap the catalog left, so once the catalog lists the model it takes the
414
+ // row over: the metadata below replaces discovery's guesses and the row
415
+ // becomes catalog-owned (pruned with the catalog from then on). Local
416
+ // disables survive, like on any catalog row.
417
+ if (row && row.source === DISCOVERED_MODEL_SOURCE)
418
+ adoptModel.run(row.id);
419
+ const fields = {
420
+ displayName: m.displayName,
421
+ intelligenceRank: m.intelligenceRank,
422
+ speedRank: m.speedRank,
423
+ sizeLabel: m.sizeLabel,
424
+ rpm: m.limits.rpm,
425
+ rpd: m.limits.rpd,
426
+ tpm: m.limits.tpm,
427
+ tpd: m.limits.tpd,
428
+ monthlyTokenBudget: m.monthlyTokenBudget,
429
+ contextWindow: routableContextWindow(m.platform, m.modelId, m.contextWindow),
430
+ supportsVision: m.supportsVision ? 1 : 0,
431
+ supportsTools: m.supportsTools ? 1 : 0,
432
+ };
433
+ if (row) {
434
+ // Catalog disable wins (dead upstream); local disable also wins.
435
+ const enabled = m.enabled ? row.enabled : 0;
436
+ updateModel.run({ ...fields, id: row.id, enabled });
437
+ refreshModelOverrideBaselines(db, m.platform, m.modelId);
438
+ applyModelOverrides(db, m.platform, m.modelId);
439
+ counts.updated++;
440
+ if (row.displayName !== m.displayName)
441
+ record(details.updated, m.platform, m.displayName);
442
+ }
443
+ else {
444
+ insertModel.run({ ...fields, platform: m.platform, modelId: m.modelId, enabled: m.enabled ? 1 : 0 });
445
+ refreshModelOverrideBaselines(db, m.platform, m.modelId);
446
+ applyModelOverrides(db, m.platform, m.modelId);
447
+ counts.inserted++;
448
+ record(details.added, m.platform, m.displayName);
449
+ }
450
+ }
451
+ // Video models use their own optional full snapshot. Older catalogs omit
452
+ // the key and leave existing video rows untouched; older binaries ignore
453
+ // the key entirely, which is why these rows must not live in models[].
454
+ if (catalog.videoModels) {
455
+ for (const m of catalog.videoModels) {
456
+ if (!VIDEO_PLATFORMS.has(m.platform)) {
457
+ counts.skippedUnknownPlatform++;
458
+ continue;
459
+ }
460
+ if (isCatalogModelTombstoned(db, 'media', m.platform, m.modelId))
461
+ continue;
462
+ inVideoCatalog.add(`${m.platform}:${m.modelId}`);
463
+ const meta = typeof m.providerModelId === 'string'
464
+ ? JSON.stringify({ providerModelId: m.providerModelId })
465
+ : null;
466
+ const fields = {
467
+ displayName: m.displayName,
468
+ modality: 'video',
469
+ priority: m.priority,
470
+ quotaLabel: m.quotaLabel ?? '',
471
+ metaJson: meta,
472
+ };
473
+ const row = selectMedia.get(m.platform, m.modelId);
474
+ if (row) {
475
+ const enabled = m.enabled ? row.enabled : 0;
476
+ updateMedia.run({ ...fields, id: row.id, enabled });
477
+ counts.updated++;
478
+ if (row.displayName !== m.displayName)
479
+ record(details.updated, m.platform, m.displayName);
480
+ }
481
+ else {
482
+ insertMedia.run({ ...fields, platform: m.platform, modelId: m.modelId, enabled: m.enabled ? 1 : 0 });
483
+ counts.inserted++;
484
+ record(details.added, m.platform, m.displayName);
485
+ }
486
+ }
487
+ }
488
+ // Embeddings are their own full snapshot. Older catalogs omit this field;
489
+ // in that case retain the app's bundled embedding baseline untouched.
490
+ if (catalog.embeddings) {
491
+ for (const m of catalog.embeddings) {
492
+ if (!EMBEDDING_PLATFORMS.has(m.platform)) {
493
+ counts.skippedUnknownPlatform++;
494
+ continue;
495
+ }
496
+ inEmbeddingCatalog.add(`${m.platform}:${m.modelId}`);
497
+ const row = selectEmbedding.get(m.platform, m.modelId);
498
+ const fields = {
499
+ family: m.family,
500
+ displayName: m.displayName,
501
+ dimensions: m.dimensions,
502
+ maxInputTokens: m.maxInputTokens,
503
+ priority: m.priority,
504
+ quotaLabel: m.quotaLabel,
505
+ };
506
+ if (row) {
507
+ const enabled = m.enabled ? row.enabled : 0; // catalog and local disables both win
508
+ updateEmbedding.run({ ...fields, id: row.id, enabled });
509
+ counts.updated++;
510
+ if (row.displayName !== m.displayName)
511
+ record(details.updated, m.platform, m.displayName);
512
+ }
513
+ else {
514
+ insertEmbedding.run({
515
+ ...fields,
516
+ platform: m.platform,
517
+ modelId: m.modelId,
518
+ enabled: m.enabled ? 1 : 0,
519
+ });
520
+ counts.inserted++;
521
+ record(details.added, m.platform, m.displayName);
522
+ }
523
+ }
524
+ }
525
+ // Transcription models are their own full snapshot, routed into
526
+ // media_models with modality='transcription' and gated on
527
+ // TRANSCRIPTION_PLATFORMS the way MEDIA_PLATFORMS gates the generative
528
+ // rows. Older catalogs omit this key; keep existing rows untouched then.
529
+ if (catalog.transcriptionModels) {
530
+ for (const m of catalog.transcriptionModels) {
531
+ if (!TRANSCRIPTION_PLATFORMS.has(m.platform)) {
532
+ counts.skippedUnknownPlatform++;
533
+ continue;
534
+ }
535
+ if (isCatalogModelTombstoned(db, 'media', m.platform, m.modelId))
536
+ continue;
537
+ inTranscriptionCatalog.add(`${m.platform}:${m.modelId}`);
538
+ const meta = {};
539
+ if (m.subtitleFormats?.length)
540
+ meta.subtitleFormats = m.subtitleFormats;
541
+ if (typeof m.maxBytes === 'number')
542
+ meta.maxBytes = m.maxBytes;
543
+ if (typeof m.requestStyle === 'string')
544
+ meta.requestStyle = m.requestStyle;
545
+ const fields = {
546
+ displayName: m.displayName,
547
+ priority: m.priority,
548
+ quotaLabel: m.quotaLabel ?? '',
549
+ metaJson: Object.keys(meta).length > 0 ? JSON.stringify(meta) : null,
550
+ };
551
+ const row = selectMedia.get(m.platform, m.modelId);
552
+ if (row) {
553
+ const enabled = m.enabled ? row.enabled : 0; // catalog and local disables both win
554
+ updateTranscription.run({ ...fields, id: row.id, enabled });
555
+ counts.updated++;
556
+ if (row.displayName !== m.displayName)
557
+ record(details.updated, m.platform, m.displayName);
558
+ }
559
+ else {
560
+ insertTranscription.run({ ...fields, platform: m.platform, modelId: m.modelId, enabled: m.enabled ? 1 : 0 });
561
+ counts.inserted++;
562
+ record(details.added, m.platform, m.displayName);
563
+ }
564
+ }
565
+ }
566
+ counts.removed += deleteTombstonedCatalogModels(db);
567
+ applyAllModelOverrides(db);
568
+ // Ensure every model has a fallback_config row (same invariant migrations keep).
569
+ const missingFb = db
570
+ .prepare(`SELECT m.id FROM models m LEFT JOIN fallback_config f ON m.id = f.model_db_id WHERE f.id IS NULL`)
571
+ .all();
572
+ if (missingFb.length > 0) {
573
+ const maxPriority = db.prepare('SELECT COALESCE(MAX(priority), 0) AS mx FROM fallback_config').get().mx;
574
+ const addFb = db.prepare('INSERT INTO fallback_config (model_db_id, priority, enabled) VALUES (?, ?, 1)');
575
+ missingFb.forEach((r, i) => addFb.run(r.id, maxPriority + 1 + i));
576
+ }
577
+ ensureAllModelsInProfiles(db);
578
+ // Remove catalog-managed models that the catalog no longer lists.
579
+ // Ownership is decided by the `source` provenance column: only rows the
580
+ // catalog itself created are prune candidates. Rows with source='user'
581
+ // (declarative config, admin adds, custom endpoints) are never deleted
582
+ // here, no matter what their size_label or platform says — that replaces
583
+ // the old size_label NOT IN ('User','Custom') heuristic, which lost user
584
+ // rows whose label didn't follow the convention. The platform/key_id
585
+ // predicates stay as belt and braces.
586
+ const candidates = db
587
+ .prepare(`
588
+ SELECT id, platform, model_id, display_name AS displayName
589
+ FROM models
590
+ WHERE platform != 'custom'
591
+ AND key_id IS NULL
592
+ AND source = 'catalog'
593
+ `)
594
+ .all();
595
+ const deleteFb = db.prepare('DELETE FROM fallback_config WHERE model_db_id = ?');
596
+ const deleteModel = db.prepare('DELETE FROM models WHERE id = ?');
597
+ for (const c of candidates) {
598
+ if (!hasProvider(c.platform))
599
+ continue; // not catalog-managed by this binary
600
+ if (!inCatalog.has(`${c.platform}:${c.model_id}`)) {
601
+ deleteFb.run(c.id);
602
+ deleteModel.run(c.id);
603
+ counts.removed++;
604
+ record(details.removed, c.platform, c.displayName ?? c.model_id);
605
+ }
606
+ }
607
+ // #1348: retire discovered rows on every platform the catalog now
608
+ // manages. A platform counts as managed when this catalog carries ANY row
609
+ // for it (chat, media, embedding, STT or video; enabled or disabled, since
610
+ // a disabled row is still an audit verdict) or names it in
611
+ // managedPlatforms. Rows the catalog listed were adopted above and are
612
+ // source='catalog' by now, so what is left is exactly the discovered
613
+ // stopgap the catalog has superseded.
614
+ const managed = catalogPlatforms(catalog);
615
+ const discoveredRows = db
616
+ .prepare('SELECT id, platform, model_id, display_name AS displayName FROM models WHERE source = ?')
617
+ .all(DISCOVERED_MODEL_SOURCE);
618
+ for (const d of discoveredRows) {
619
+ if (!managed.has(d.platform))
620
+ continue;
621
+ deleteFb.run(d.id);
622
+ deleteModel.run(d.id);
623
+ counts.removed++;
624
+ record(details.removed, d.platform, d.displayName ?? d.model_id);
625
+ }
626
+ // Remove media models the catalog no longer lists (own table, no
627
+ // fallback_config). Deliberately an ALLOWLIST of the two modalities that
628
+ // `models[]` maintains, not "everything except transcription": video and
629
+ // transcription rows come from their own optional snapshots below, so a
630
+ // catalog that omits those keys must leave them alone. Widening this back
631
+ // to a `!=` filter would silently delete every video row on the first sync
632
+ // from an older catalog.
633
+ const mediaCandidates = db
634
+ .prepare("SELECT id, platform, model_id, display_name AS displayName FROM media_models WHERE modality IN ('image', 'audio')")
635
+ .all();
636
+ const deleteMedia = db.prepare('DELETE FROM media_models WHERE id = ?');
637
+ for (const c of mediaCandidates) {
638
+ if (!MEDIA_PLATFORMS.has(c.platform))
639
+ continue; // not media-managed by this binary
640
+ if (!inMediaCatalog.has(`${c.platform}:${c.model_id}`)) {
641
+ deleteMedia.run(c.id);
642
+ counts.removed++;
643
+ record(details.removed, c.platform, c.displayName ?? c.model_id);
644
+ }
645
+ }
646
+ // Prune video rows only when this catalog actually carries the dedicated
647
+ // snapshot. An older catalog cannot know whether a video row was retired.
648
+ if (catalog.videoModels) {
649
+ const videoCandidates = db
650
+ .prepare("SELECT id, platform, model_id, display_name AS displayName FROM media_models WHERE modality = 'video'")
651
+ .all();
652
+ for (const c of videoCandidates) {
653
+ if (!VIDEO_PLATFORMS.has(c.platform))
654
+ continue;
655
+ if (!inVideoCatalog.has(`${c.platform}:${c.model_id}`)) {
656
+ deleteMedia.run(c.id);
657
+ counts.removed++;
658
+ record(details.removed, c.platform, c.displayName ?? c.model_id);
659
+ }
660
+ }
661
+ }
662
+ // Prune transcription rows only when the catalog actually carries the
663
+ // snapshot (mirrors the embeddings rule), scoped to the modality so
664
+ // image/audio rows are never touched by it.
665
+ if (catalog.transcriptionModels) {
666
+ const sttCandidates = db
667
+ .prepare("SELECT id, platform, model_id, display_name AS displayName FROM media_models WHERE modality = 'transcription'")
668
+ .all();
669
+ for (const c of sttCandidates) {
670
+ if (!TRANSCRIPTION_PLATFORMS.has(c.platform))
671
+ continue;
672
+ if (!inTranscriptionCatalog.has(`${c.platform}:${c.model_id}`)) {
673
+ deleteMedia.run(c.id);
674
+ counts.removed++;
675
+ record(details.removed, c.platform, c.displayName ?? c.model_id);
676
+ }
677
+ }
678
+ }
679
+ // Embeddings are their own full snapshot. Older catalogs omit this field,
680
+ // AND catalogs may publish `embeddings: []` while still shipping model
681
+ // rows — both cases mean "retain the app's bundled embedding baseline
682
+ // untouched". The JS truthy check on a non-empty array object would
683
+ // misfire on `[]`, wiping the seeded rows; gate on length instead.
684
+ if (catalog.embeddings && catalog.embeddings.length > 0) {
685
+ const embeddingCandidates = db
686
+ .prepare(`
687
+ SELECT id, platform, model_id, display_name AS displayName
688
+ FROM embedding_models
689
+ WHERE platform != 'custom' AND key_id IS NULL
690
+ `)
691
+ .all();
692
+ const deleteEmbedding = db.prepare('DELETE FROM embedding_models WHERE id = ?');
693
+ for (const c of embeddingCandidates) {
694
+ if (!EMBEDDING_PLATFORMS.has(c.platform))
695
+ continue;
696
+ if (!inEmbeddingCatalog.has(`${c.platform}:${c.model_id}`)) {
697
+ deleteEmbedding.run(c.id);
698
+ counts.removed++;
699
+ record(details.removed, c.platform, c.displayName ?? c.model_id);
700
+ }
701
+ }
702
+ }
703
+ // Quirks are pure content: replace wholesale.
704
+ db.prepare('DELETE FROM quirk_targets').run();
705
+ db.prepare('DELETE FROM quirks').run();
706
+ const insertQuirk = db.prepare(`INSERT INTO quirks (slug, title, body, severity, created_at_ms, updated_at_ms) VALUES (?, ?, ?, ?, ?, ?)`);
707
+ const insertTarget = db.prepare(`INSERT INTO quirk_targets (quirk_id, platform, model_glob) VALUES (?, ?, ?)`);
708
+ const now = Date.now();
709
+ for (const q of catalog.quirks) {
710
+ const info = insertQuirk.run(q.slug, q.title, q.body, q.severity, now, now);
711
+ for (const t of q.targets)
712
+ insertTarget.run(info.lastInsertRowid, t.platform ?? null, t.modelGlob ?? null);
713
+ counts.quirks++;
714
+ }
715
+ });
716
+ apply();
717
+ return { counts, details };
718
+ }
719
+ /**
720
+ * Fetch the catalog, verify its signature, and apply it if it moves us forward.
721
+ * `force` skips the `since` short-circuit — forces a full catalog fetch
722
+ * regardless of version changes.
723
+ */
724
+ /** In-flight run for syncCatalog — concurrent callers share the same run. */
725
+ let inFlightSync = null;
726
+ export async function syncCatalog(force = false) {
727
+ // In-flight guard: if a run is already active, hand back the same promise
728
+ // instead of starting a duplicate fetch+apply.
729
+ if (inFlightSync) {
730
+ console.log('[catalog-sync] sync already in flight — reusing run');
731
+ return inFlightSync;
732
+ }
733
+ inFlightSync = runSyncCatalog(force);
734
+ try {
735
+ return await inFlightSync;
736
+ }
737
+ finally {
738
+ inFlightSync = null;
739
+ }
740
+ }
741
+ async function runSyncCatalog(force) {
742
+ const db = getDb();
743
+ const applied = getSetting(SETTING_APPLIED_VERSION);
744
+ try {
745
+ const url = new URL(`${catalogBaseUrl()}/v1/latest`);
746
+ if (applied && !force)
747
+ url.searchParams.set('since', applied);
748
+ const res = await fetch(url, { signal: AbortSignal.timeout(FETCH_TIMEOUT_MS) });
749
+ if (res.status === 304) {
750
+ setSetting(SETTING_LAST_SYNC_MS, String(Date.now()));
751
+ setSetting(SETTING_LAST_ERROR, '');
752
+ return { ok: true, action: 'up_to_date', version: applied };
753
+ }
754
+ if (!res.ok)
755
+ throw new Error(`catalog fetch failed: HTTP ${res.status}`);
756
+ const signature = res.headers.get('x-catalog-signature');
757
+ if (!signature)
758
+ throw new Error('catalog response missing signature');
759
+ const bytes = Buffer.from(await res.arrayBuffer());
760
+ const verified = crypto.verify(null, bytes, catalogPublicKey(), Buffer.from(signature, 'base64'));
761
+ if (!verified)
762
+ throw new Error('catalog signature verification FAILED — discarding response');
763
+ const parsed = JSON.parse(bytes.toString('utf8'));
764
+ if (!isCatalog(parsed))
765
+ throw new Error('catalog payload has unexpected shape');
766
+ const catalog = parsed;
767
+ if (catalog.version < MIN_CATALOG_VERSION) {
768
+ // Older than the bundled baseline (e.g. monthly snapshot lagging a fresh
769
+ // app release) — applying it would roll back migrations. Wait it out.
770
+ setSetting(SETTING_LAST_SYNC_MS, String(Date.now()));
771
+ setSetting(SETTING_LAST_ERROR, '');
772
+ return { ok: true, action: 'skipped_older', version: catalog.version, tier: catalog.tier };
773
+ }
774
+ const sameAsApplied = applied === catalog.version && getSetting(SETTING_APPLIED_TIER) === catalog.tier;
775
+ if (!sameAsApplied) {
776
+ const { counts, details } = applyCatalogDetailed(db, catalog);
777
+ setSetting(SETTING_APPLIED_VERSION, catalog.version);
778
+ setSetting(SETTING_APPLIED_TIER, catalog.tier);
779
+ // Cache the verified document so boots can re-apply it offline (see
780
+ // reapplyCachedCatalog). Stored post-verification: anything that could
781
+ // tamper this row could tamper the models table directly, so the cache
782
+ // adds no new trust surface.
783
+ setSetting(SETTING_APPLIED_JSON, bytes.toString('utf8'));
784
+ console.log(`[catalog-sync] applied ${catalog.tier} v${catalog.version}: ` +
785
+ `${counts.updated} updated, ${counts.inserted} new, ${counts.removed} removed, ` +
786
+ `${counts.quirks} quirks` +
787
+ (counts.skippedUnknownPlatform ? `, ${counts.skippedUnknownPlatform} skipped (unknown platform)` : ''));
788
+ setSetting(SETTING_LAST_SYNC_MS, String(Date.now()));
789
+ setSetting(SETTING_LAST_ERROR, '');
790
+ const syncResult = {
791
+ ok: true,
792
+ action: 'applied',
793
+ version: catalog.version,
794
+ tier: catalog.tier,
795
+ counts,
796
+ details,
797
+ };
798
+ emitSyncNotifications(syncResult);
799
+ return syncResult;
800
+ }
801
+ setSetting(SETTING_LAST_SYNC_MS, String(Date.now()));
802
+ setSetting(SETTING_LAST_ERROR, '');
803
+ return { ok: true, action: 'up_to_date', version: catalog.version, tier: catalog.tier };
804
+ }
805
+ catch (err) {
806
+ const message = err instanceof Error ? err.message : String(err);
807
+ console.warn(`[catalog-sync] ${message}`);
808
+ setSetting(SETTING_LAST_ERROR, message);
809
+ return { ok: false, action: 'error', detail: message };
810
+ }
811
+ }
812
+ export function getSyncState() {
813
+ return {
814
+ baseUrl: catalogBaseUrl(),
815
+ appliedVersion: getSetting(SETTING_APPLIED_VERSION) ?? null,
816
+ appliedTier: getSetting(SETTING_APPLIED_TIER) ?? null,
817
+ lastSyncMs: Number(getSetting(SETTING_LAST_SYNC_MS)) || null,
818
+ lastError: getSetting(SETTING_LAST_ERROR) || null,
819
+ };
820
+ }
821
+ /**
822
+ * Re-apply the cached (already signature-verified) catalog after boot.
823
+ *
824
+ * Migrations run on every boot and re-assert the bundled baseline — they
825
+ * INSERT OR IGNORE baseline models the catalog may have deleted and re-run
826
+ * the family-rule resets — while the boot-time network sync 304s on an
827
+ * unchanged version and so would NOT re-apply. Without this step every
828
+ * restart drifts the DB back toward the baseline until the next catalog
829
+ * version bump. Re-applying from the local cache is synchronous, needs no
830
+ * network, and keeps the catalog authoritative even offline.
831
+ *
832
+ * Legacy upgrade path: installs that applied a catalog before the cache
833
+ * existed have an applied-version setting but no cached document. Clearing
834
+ * the applied version makes the next poll fetch the full catalog (no `since`
835
+ * short-circuit), which re-applies it and populates the cache.
836
+ */
837
+ export function reapplyCachedCatalog() {
838
+ try {
839
+ const raw = getSetting(SETTING_APPLIED_JSON);
840
+ if (!raw) {
841
+ if (getSetting(SETTING_APPLIED_VERSION)) {
842
+ getDb().prepare('DELETE FROM settings WHERE key = ?').run(SETTING_APPLIED_VERSION);
843
+ }
844
+ return { reapplied: false };
845
+ }
846
+ const parsed = JSON.parse(raw);
847
+ if (!isCatalog(parsed) || parsed.version < MIN_CATALOG_VERSION)
848
+ return { reapplied: false };
849
+ applyCatalog(getDb(), parsed);
850
+ console.log(`[catalog-sync] re-applied cached ${parsed.tier} v${parsed.version} after boot`);
851
+ return { reapplied: true, version: parsed.version };
852
+ }
853
+ catch (err) {
854
+ console.warn(`[catalog-sync] cached catalog re-apply failed: ${err instanceof Error ? err.message : err}`);
855
+ return { reapplied: false };
856
+ }
857
+ }
858
+ let cancelBootTimer = null;
859
+ let cancelInterval = null;
860
+ let currentScheduler = null;
861
+ function restartInterval() {
862
+ if (!currentScheduler)
863
+ return;
864
+ if (cancelInterval) {
865
+ cancelInterval();
866
+ cancelInterval = null;
867
+ }
868
+ const ms = syncIntervalMs();
869
+ if (ms > 0) {
870
+ cancelInterval = currentScheduler.every(ms, () => { void syncCatalog(); });
871
+ console.log(`[catalog-sync] polling ${catalogBaseUrl()} every ${ms / 3600000}h`);
872
+ }
873
+ else {
874
+ console.log('[catalog-sync] auto-sync disabled (manual mode)');
875
+ }
876
+ }
877
+ export function startCatalogSync(scheduler) {
878
+ if (cancelInterval)
879
+ return;
880
+ if (process.env.CATALOG_SYNC_DISABLED === '1') {
881
+ console.log('[catalog-sync] disabled via CATALOG_SYNC_DISABLED=1');
882
+ stopCatalogSync();
883
+ return;
884
+ }
885
+ currentScheduler = scheduler;
886
+ reapplyCachedCatalog();
887
+ const run = () => {
888
+ void syncCatalog();
889
+ };
890
+ cancelBootTimer = scheduler.after(BOOT_DELAY_MS, async () => {
891
+ run();
892
+ // Auto-discover models for providers that have keys but zero models in
893
+ // the catalog. Bypasses the monthly catalog: instead of waiting for
894
+ // the next snapshot to include a new provider, we query their APIs.
895
+ try {
896
+ const { autoDiscoverAll } = await import('./auto-discover.js');
897
+ await autoDiscoverAll();
898
+ }
899
+ catch (err) {
900
+ console.warn(`[catalog-sync] auto-discover failed: ${err instanceof Error ? err.message : err}`);
901
+ }
902
+ // Check for server updates on boot (if enabled in settings)
903
+ try {
904
+ const { checkUpdateAvailable } = await import('./notification-emitter.js');
905
+ await checkUpdateAvailable();
906
+ }
907
+ catch {
908
+ // Silent — update check is best-effort
909
+ }
910
+ });
911
+ restartInterval();
912
+ }
913
+ export function stopCatalogSync() {
914
+ if (cancelBootTimer) {
915
+ cancelBootTimer();
916
+ cancelBootTimer = null;
917
+ }
918
+ if (cancelInterval) {
919
+ cancelInterval();
920
+ cancelInterval = null;
921
+ }
922
+ }
923
+ /** Call after changing the schedule setting to restart the polling timer. */
924
+ export function updateSyncSchedule() {
925
+ restartInterval();
926
+ // Also restart auto-discover on the same schedule
927
+ import('./auto-discover.js').then(m => m.restartRefreshInterval()).catch(() => { });
928
+ }
929
+ /** How many model names one notification line may name before it elides. */
930
+ const MAX_NOTIFICATION_MODELS = 5;
931
+ /**
932
+ * One notification per provider that actually changed, naming the models.
933
+ *
934
+ * A bare "12 models added" line tells the user nothing actionable, so the
935
+ * per-platform ledger from applyCatalogInner drives this: each entry is a
936
+ * provider plus the models that changed on it. Names are elided past
937
+ * MAX_NOTIFICATION_MODELS — one sync can land a whole new provider's roster —
938
+ * while the count stays the true total, so nothing is hidden.
939
+ *
940
+ * `updated` collapses to one line per provider with a count rather than
941
+ * naming models: the ledger there is every catalog row whose display name
942
+ * moved, which on a routine monthly snapshot is essentially the entire
943
+ * catalog (370 rows on the install this was built for), and a bell listing
944
+ * all of them is noise, not news.
945
+ */
946
+ function emitSyncNotifications(result) {
947
+ if (!result.counts)
948
+ return;
949
+ const { inserted, removed, updated } = result.counts;
950
+ if (inserted === 0 && removed === 0 && updated === 0)
951
+ return;
952
+ const now = Date.now();
953
+ const notifs = [];
954
+ const ledger = result.details;
955
+ const names = (list) => list.slice(0, MAX_NOTIFICATION_MODELS).join(', ') + (list.length > MAX_NOTIFICATION_MODELS ? '…' : '');
956
+ /** Per-platform lines for added/removed, one line per changed provider. */
957
+ const perPlatform = (changes, type, dataKey) => {
958
+ for (const [platform, list] of changes) {
959
+ const count = list.length;
960
+ notifs.push({
961
+ id: `sync-${now}-${type}-${platform}`,
962
+ type,
963
+ modelId: '*',
964
+ platform,
965
+ displayName: `${count} model ${type === 'added' ? 'baru' : 'dihapus'}`,
966
+ message: names(list),
967
+ data: { key: dataKey, vars: { count, platform } },
968
+ timestamp: now,
969
+ read: false,
970
+ });
971
+ }
972
+ };
973
+ if (inserted > 0) {
974
+ if (ledger && ledger.added.size > 0) {
975
+ perPlatform(ledger.added, 'added', 'notifications.catalogAddedFrom');
976
+ }
977
+ else {
978
+ notifs.push({
979
+ id: `sync-${now}-added`,
980
+ type: 'added',
981
+ modelId: '*',
982
+ platform: '',
983
+ displayName: `${inserted} model baru`,
984
+ message: `${inserted} model baru ditambahkan dari katalog`,
985
+ data: { key: 'notifications.catalogAdded', vars: { count: inserted } },
986
+ timestamp: now,
987
+ read: false,
988
+ });
989
+ }
990
+ }
991
+ if (removed > 0) {
992
+ if (ledger && ledger.removed.size > 0) {
993
+ perPlatform(ledger.removed, 'removed', 'notifications.catalogRemovedFrom');
994
+ }
995
+ else {
996
+ notifs.push({
997
+ id: `sync-${now}-removed`,
998
+ type: 'removed',
999
+ modelId: '*',
1000
+ platform: '',
1001
+ displayName: `${removed} model dihapus`,
1002
+ message: `${removed} model dihapus karena sudah tidak ada di katalog`,
1003
+ data: { key: 'notifications.catalogRemoved', vars: { count: removed } },
1004
+ timestamp: now,
1005
+ read: false,
1006
+ });
1007
+ }
1008
+ }
1009
+ if (updated > 0) {
1010
+ if (ledger && ledger.updated.size > 0) {
1011
+ for (const [platform, list] of ledger.updated) {
1012
+ notifs.push({
1013
+ id: `sync-${now}-updated-${platform}`,
1014
+ type: 'updated',
1015
+ modelId: '*',
1016
+ platform,
1017
+ displayName: `${list.length} model diperbarui`,
1018
+ message: '',
1019
+ data: { key: 'notifications.catalogUpdatedFrom', vars: { count: list.length, platform } },
1020
+ timestamp: now,
1021
+ read: false,
1022
+ });
1023
+ }
1024
+ }
1025
+ else {
1026
+ notifs.push({
1027
+ id: `sync-${now}-updated`,
1028
+ type: 'updated',
1029
+ modelId: '*',
1030
+ platform: '',
1031
+ displayName: `${updated} model diperbarui`,
1032
+ message: `${updated} model diperbarui dari katalog terbaru`,
1033
+ data: { key: 'notifications.catalogUpdated', vars: { count: updated } },
1034
+ timestamp: now,
1035
+ read: false,
1036
+ });
1037
+ }
1038
+ }
1039
+ addNotifications(notifs);
1040
+ }
1041
+ //# sourceMappingURL=catalog-sync.js.map