@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,1002 @@
1
+ import http from 'http';
2
+ import https from 'https';
3
+ import { execFileSync } from 'node:child_process';
4
+ import { AsyncLocalStorage } from 'node:async_hooks';
5
+ import { getSetting } from '../db/index.js';
6
+ import { decrypt, encrypt } from './crypto.js';
7
+ import { assertProviderUrlAllowed, isLoopbackOrPrivateHostname } from './url-guard.js';
8
+ // #590 (per-key proxy): the SAME provider may be reached through different
9
+ // exit IPs per key (geo-ban / risk-control avoidance). Providers are process
10
+ // singletons, so the per-key override cannot live on the provider instance —
11
+ // it rides request-scoped AsyncLocalStorage instead, set by the dispatcher
12
+ // around a provider call and read here in proxyFetch.
13
+ const perKeyProxyStore = new AsyncLocalStorage();
14
+ /** Run `fn` with a per-key proxy override in effect; empty URL = global proxy. */
15
+ export function withKeyProxy(proxyUrl, fn) {
16
+ return perKeyProxyStore.run(proxyUrl ?? '', fn);
17
+ }
18
+ let _proxyAgentCtor = null;
19
+ let _socksAgentCtor = null;
20
+ async function loadHttpProxyAgent() {
21
+ if (!_proxyAgentCtor)
22
+ _proxyAgentCtor = (await import('undici')).ProxyAgent;
23
+ return _proxyAgentCtor;
24
+ }
25
+ async function loadSocksAgent() {
26
+ if (!_socksAgentCtor)
27
+ _socksAgentCtor = (await import('socks-proxy-agent')).SocksProxyAgent;
28
+ return _socksAgentCtor;
29
+ }
30
+ // SOCKS schemes socks-proxy-agent understands. `socks5h`/`socks4a` are the
31
+ // "resolve DNS at the proxy" variants (#630) — the ones that matter on
32
+ // DNS-poisoned networks, where resolving the upstream hostname locally is
33
+ // exactly what fails. They are ordinary SOCKS URLs to the agent; only our
34
+ // scheme detection ever needed teaching.
35
+ const SOCKS_SCHEMES = ['socks5:', 'socks5h:', 'socks4:', 'socks4a:'];
36
+ /** Every proxy scheme the app accepts. Shared with the settings validator. */
37
+ export const PROXY_SCHEMES = ['http:', 'https:', ...SOCKS_SCHEMES];
38
+ export const PROXY_MODES = ['forward', 'fetch-relay'];
39
+ export const FETCH_RELAY_TARGET_HEADER = 'fetch-relay-target';
40
+ export const FETCH_RELAY_AUTH_HEADER = 'fetch-relay-authorization';
41
+ // A Fetch Relay carries the provider API key AND the relay token inside the
42
+ // request it forwards, so the hop to the relay must be encrypted. Plain http
43
+ // is only tolerable when the relay never leaves the machine.
44
+ const LOOPBACK_RELAY_HOSTNAMES = new Set(['localhost', '127.0.0.1', '::1', '[::1]']);
45
+ /** True for a hostname that cannot leave the local machine. `new URL()` keeps
46
+ * the brackets on an IPv6 literal, hence both spellings of ::1. */
47
+ export function isLoopbackRelayHostname(hostname) {
48
+ const host = hostname.toLowerCase();
49
+ return LOOPBACK_RELAY_HOSTNAMES.has(host) || /^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(host);
50
+ }
51
+ /** Why a URL cannot serve as a Fetch Relay endpoint, or undefined when it can.
52
+ * Shared by the settings validator and the boot-time env guard so the
53
+ * dashboard and a headless install agree on what a usable relay looks like. */
54
+ export function fetchRelayUrlError(url) {
55
+ let parsed;
56
+ try {
57
+ parsed = new URL(url);
58
+ }
59
+ catch {
60
+ return 'Invalid Fetch Relay URL. Use a full URL like https://relay.example.workers.dev';
61
+ }
62
+ if (parsed.protocol === 'https:')
63
+ return undefined;
64
+ if (parsed.protocol === 'http:' && isLoopbackRelayHostname(parsed.hostname))
65
+ return undefined;
66
+ return 'Fetch Relay URL must use https, or http only for a loopback relay. The provider API key and the relay token travel inside the relayed request.';
67
+ }
68
+ /** True when the URL names a SOCKS scheme (so it needs SocksProxyAgent, not undici). */
69
+ export function isSocksProxyUrl(url) {
70
+ const colon = url.indexOf(':');
71
+ if (colon < 0)
72
+ return false;
73
+ return SOCKS_SCHEMES.includes(url.slice(0, colon + 1).toLowerCase());
74
+ }
75
+ /** Reduce a proxy/relay URL to a safe connection hint. Relay paths commonly
76
+ * act as bearer secrets, while query strings may contain target templates or
77
+ * credentials, so neither is safe to print. */
78
+ function redactProxyUrl(url) {
79
+ try {
80
+ const parsed = new URL(url);
81
+ const credentials = parsed.username || parsed.password ? '***@' : '';
82
+ const path = parsed.pathname && parsed.pathname !== '/' ? '/[redacted]' : '';
83
+ return `${parsed.protocol}//${credentials}${parsed.host}${path}`;
84
+ }
85
+ catch {
86
+ return '[invalid proxy URL]';
87
+ }
88
+ }
89
+ // Standard proxy env vars, in the order they are consulted. PROXY_URL is the
90
+ // app's own knob and outranks the dashboard; the rest are ambient system
91
+ // settings (#353) that only apply when nothing is configured in the dashboard.
92
+ const ENV_PROXY_FALLBACKS = ['ALL_PROXY', 'HTTPS_PROXY', 'HTTP_PROXY'];
93
+ /** Read an env var in either the upper- or lower-case spelling. */
94
+ function readEnv(name) {
95
+ return (process.env[name] ?? process.env[name.toLowerCase()] ?? '').trim();
96
+ }
97
+ /**
98
+ * Decide which proxy URL wins, and say where it came from.
99
+ *
100
+ * PROXY_URL → dashboard setting → ALL_PROXY → HTTPS_PROXY → HTTP_PROXY.
101
+ *
102
+ * PROXY_URL stays on top because it has always documented itself as taking
103
+ * precedence (the dashboard hint says so). The standard vars sit *below* the
104
+ * dashboard: they're usually exported machine-wide for curl/git, so a proxy a
105
+ * user deliberately typed into the UI must not be silently overridden by them.
106
+ */
107
+ function resolveProxySource(dbValue) {
108
+ const { url, source } = pickProxySource(dbValue);
109
+ return { url: normalizeProxyUrl(url), source };
110
+ }
111
+ /**
112
+ * Give a scheme-less `host:port` proxy an `http://` scheme. Windows Internet
113
+ * Options and macOS `scutil --proxy` both store the proxy that way, and so do
114
+ * plenty of hand-written HTTPS_PROXY values; `new URL('127.0.0.1:7890')`
115
+ * throws, so without this the proxy was logged as invalid and every request
116
+ * silently went direct (#1373).
117
+ */
118
+ export function normalizeProxyUrl(url) {
119
+ const trimmed = url.trim();
120
+ if (!trimmed || /^[a-z][a-z0-9+.-]*:\/\//i.test(trimmed))
121
+ return trimmed;
122
+ return `http://${trimmed}`;
123
+ }
124
+ function pickProxySource(dbValue) {
125
+ const explicit = readEnv('PROXY_URL');
126
+ if (explicit)
127
+ return { url: explicit, source: 'PROXY_URL' };
128
+ const db = dbValue.trim();
129
+ if (db)
130
+ return { url: db, source: 'dashboard' };
131
+ for (const name of ENV_PROXY_FALLBACKS) {
132
+ const value = readEnv(name);
133
+ if (value)
134
+ return { url: value, source: name };
135
+ }
136
+ // #353: last resort — read the system-wide proxy settings (macOS System
137
+ // Settings / Windows Internet Options / GNOME desktop) so the app works
138
+ // without duplicating the OS config. Best-effort: every failure here just
139
+ // falls through to the direct (no-proxy) path.
140
+ const system = detectSystemProxy();
141
+ if (system.url)
142
+ return system;
143
+ return { url: '', source: 'none' };
144
+ }
145
+ /**
146
+ * Read the OS-wide proxy configuration. Synchronous and best-effort: never
147
+ * throws, returns '' when the platform is unsupported or the command fails.
148
+ *
149
+ * - macOS: `scutil --proxy` (System Settings → Network → Proxies)
150
+ * - Windows: Internet Options registry (ProxyEnable + ProxyServer)
151
+ * - Linux: GNOME gsettings (the most common desktop), manual mode only
152
+ */
153
+ export function detectSystemProxy() {
154
+ try {
155
+ if (process.platform === 'darwin') {
156
+ const out = execFileSync('scutil', ['--proxy'], { encoding: 'utf8', timeout: 2000 });
157
+ return parseScutilProxy(out);
158
+ }
159
+ if (process.platform === 'win32') {
160
+ const enable = execFileSync('reg', ['query', 'HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings', '/v', 'ProxyEnable'], { encoding: 'utf8', timeout: 2000 });
161
+ const server = execFileSync('reg', ['query', 'HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings', '/v', 'ProxyServer'], { encoding: 'utf8', timeout: 2000 });
162
+ return parseRegProxy(enable, server);
163
+ }
164
+ if (process.platform === 'linux') {
165
+ return parseGsettingsProxy();
166
+ }
167
+ }
168
+ catch {
169
+ // fall through to no-proxy
170
+ }
171
+ return { url: '', source: 'none' };
172
+ }
173
+ /** Parse `scutil --proxy` output: HTTPEnable/HTTPProxy/HTTPPort first, then SOCKS. */
174
+ export function parseScutilProxy(out) {
175
+ const kv = (key) => out.match(new RegExp(`^\\s*${key}\\s*:\\s*(.+)$`, 'm'))?.[1]?.trim();
176
+ const httpEnabled = kv('HTTPEnable') === '1';
177
+ const httpHost = kv('HTTPProxy');
178
+ const httpPort = kv('HTTPPort') || '80';
179
+ if (httpEnabled && httpHost) {
180
+ return { url: `${httpHost}:${httpPort}`, source: 'system(macOS)' };
181
+ }
182
+ const socksEnabled = kv('SOCKSEnable') === '1';
183
+ const socksHost = kv('SOCKSProxy');
184
+ const socksPort = kv('SOCKSPort') || '1080';
185
+ if (socksEnabled && socksHost) {
186
+ return { url: `socks5://${socksHost}:${socksPort}`, source: 'system(macOS)' };
187
+ }
188
+ return { url: '', source: 'none' };
189
+ }
190
+ /** Parse Windows registry output; ProxyServer may be "host:port" or "http=…;https=…". */
191
+ export function parseRegProxy(enableOut, serverOut) {
192
+ // reg query prints: ` ProxyEnable REG_DWORD 0x1`
193
+ if (!/ProxyEnable\s+REG_DWORD\s+0x1/.test(enableOut))
194
+ return { url: '', source: 'none' };
195
+ const m = serverOut.match(/ProxyServer\s+REG_SZ\s+(.+)$/m);
196
+ if (!m)
197
+ return { url: '', source: 'none' };
198
+ const raw = m[1].trim();
199
+ if (!raw.includes('='))
200
+ return { url: raw, source: 'system(Windows)' };
201
+ // Per-scheme form: prefer the http entry, then https, then socks (which
202
+ // Internet Options means as SOCKS, so it must not become an HTTP proxy).
203
+ const entries = new Map(raw.split(';').map(p => p.trim()).filter(Boolean).map(p => {
204
+ const eq = p.indexOf('=');
205
+ return [p.slice(0, eq).trim().toLowerCase(), p.slice(eq + 1).trim()];
206
+ }));
207
+ const http = entries.get('http') || entries.get('https');
208
+ if (http)
209
+ return { url: http, source: 'system(Windows)' };
210
+ const socks = entries.get('socks');
211
+ if (socks)
212
+ return { url: `socks5://${socks}`, source: 'system(Windows)' };
213
+ return { url: '', source: 'none' };
214
+ }
215
+ /** GNOME desktop proxy in manual mode (gsettings). */
216
+ function parseGsettingsProxy() {
217
+ const mode = execFileSync('gsettings', ['get', 'org.gnome.system.proxy', 'mode'], { encoding: 'utf8', timeout: 2000 }).trim();
218
+ if (mode !== "'manual'")
219
+ return { url: '', source: 'none' };
220
+ const host = execFileSync('gsettings', ['get', 'org.gnome.system.proxy.http', 'host'], { encoding: 'utf8', timeout: 2000 }).trim().replace(/^'|'$/g, '');
221
+ const port = execFileSync('gsettings', ['get', 'org.gnome.system.proxy.http', 'port'], { encoding: 'utf8', timeout: 2000 }).trim();
222
+ if (!host || !port)
223
+ return { url: '', source: 'none' };
224
+ return { url: `${host}:${port}`, source: 'system(GNOME)' };
225
+ }
226
+ /**
227
+ * Parse a NO_PROXY list into match rules. Entries are hosts or suffixes,
228
+ * comma-separated: `localhost,.internal.corp,example.com,*`. A bare domain
229
+ * also covers its subdomains, matching curl/git behaviour.
230
+ */
231
+ function parseNoProxy(value) {
232
+ return value
233
+ .split(',')
234
+ .map(s => s.trim().toLowerCase())
235
+ .filter(Boolean)
236
+ .map(s => (s.startsWith('*.') ? s.slice(1) : s));
237
+ }
238
+ /** True when NO_PROXY says this hostname must be reached directly. */
239
+ function noProxyMatches(hostname) {
240
+ if (_noProxyRules.length === 0)
241
+ return false;
242
+ // Trailing dot (FQDN form) and IPv6 brackets are noise for matching.
243
+ const host = hostname.toLowerCase().replace(/\.$/, '').replace(/^\[|\]$/g, '');
244
+ for (const rule of _noProxyRules) {
245
+ if (rule === '*')
246
+ return true;
247
+ // A `host:port` qualifier narrows the rule to one port; we match on host,
248
+ // so compare the host half. Guarded so bare IPv6 rules aren't mangled.
249
+ const bare = /^[^:]+:\d+$/.test(rule) ? rule.slice(0, rule.lastIndexOf(':')) : rule;
250
+ if (!bare)
251
+ continue;
252
+ if (bare.startsWith('.')) {
253
+ if (host === bare.slice(1) || host.endsWith(bare))
254
+ return true;
255
+ }
256
+ else if (host === bare || host.endsWith(`.${bare}`)) {
257
+ return true;
258
+ }
259
+ }
260
+ return false;
261
+ }
262
+ // Module-level proxy URL.
263
+ let _proxyUrl = '';
264
+ let _proxyUrlSource = 'none';
265
+ let _proxyMode = 'forward';
266
+ let _fetchRelayToken = '';
267
+ let _proxyEnabled = true;
268
+ let _bypassPlatforms = new Set();
269
+ let _noProxyRules = [];
270
+ // Escape hatch for the `ssh -D` tunnel case — see shouldBypassProxy.
271
+ let _proxyLocalDestinations = false;
272
+ let _initialized = false;
273
+ // Cache.
274
+ let cached = null;
275
+ const CACHE_TTL_MS = 30_000;
276
+ // #590: per-key proxy dispatchers, keyed by the key's proxy URL. Independent
277
+ // of the global cache so a per-key override never poisons the global one.
278
+ //
279
+ // A working dispatcher is cached for as long as it stays in the map: the cache
280
+ // key IS the whole proxy URL, so unlike the global entry (whose URL can change
281
+ // under it) it can never go stale — re-building it on a timer would only churn
282
+ // connection pools. A FAILED build is cached briefly instead, so a proxy that
283
+ // was down doesn't stay written off forever.
284
+ //
285
+ // The map is bounded: entries are per distinct proxy URL, so at human scale
286
+ // this holds a handful, but nothing stops an operator from pointing a hundred
287
+ // keys at a hundred rotating exits. Oldest-first eviction keeps a bad day from
288
+ // turning into an unbounded pile of agents. An evicted (or expired) dispatcher
289
+ // is dropped, not closed — closing it would tear down requests still streaming
290
+ // through it; the GC collects it once they finish. Same as the global cache.
291
+ const perKeyCached = new Map();
292
+ const PER_KEY_FAILURE_TTL_MS = 30_000;
293
+ const PER_KEY_CACHE_MAX = 32;
294
+ function rememberPerKeyDispatcher(proxyUrl, entry) {
295
+ // Delete-then-set so re-use moves an entry to the young end of the map and
296
+ // eviction takes the genuinely least-recently-used URL.
297
+ perKeyCached.delete(proxyUrl);
298
+ perKeyCached.set(proxyUrl, entry);
299
+ while (perKeyCached.size > PER_KEY_CACHE_MAX) {
300
+ const oldest = perKeyCached.keys().next().value;
301
+ if (oldest === undefined)
302
+ break;
303
+ perKeyCached.delete(oldest);
304
+ }
305
+ }
306
+ /** Called once at startup (after initDb) and on PUT /api/settings/proxy. */
307
+ export function applyProxyUrl(dbValue) {
308
+ const { url, source } = resolveProxySource(dbValue);
309
+ _proxyUrl = url;
310
+ _proxyUrlSource = source;
311
+ // A saved relay mode must never reinterpret legacy/ambient proxy variables.
312
+ // PROXY_MODE is the only way an environment-sourced URL becomes a relay.
313
+ if (source !== 'dashboard' && !readEnv('PROXY_MODE'))
314
+ _proxyMode = 'forward';
315
+ _noProxyRules = parseNoProxy(readEnv('NO_PROXY'));
316
+ _proxyLocalDestinations = /^(1|true|yes)$/i.test(readEnv('SROUTER_PROXY_LOCAL_DESTINATIONS'));
317
+ cached = null;
318
+ if (_proxyUrl) {
319
+ console.log(`[proxy] Configured → ${redactProxyUrl(_proxyUrl)} (source: ${source})`);
320
+ if (_noProxyRules.length > 0) {
321
+ console.log(`[proxy] NO_PROXY direct for: ${_noProxyRules.join(', ')}`);
322
+ }
323
+ if (_proxyLocalDestinations) {
324
+ console.log('[proxy] SROUTER_PROXY_LOCAL_DESTINATIONS is set — localhost/LAN destinations go through the proxy too.');
325
+ }
326
+ }
327
+ else {
328
+ console.log('[proxy] Not configured — outbound requests go direct.');
329
+ }
330
+ enforceRelayUrlPolicy();
331
+ _initialized = true;
332
+ }
333
+ /**
334
+ * Refuse to run a relay over a URL it cannot speak. A relay hop is an ordinary
335
+ * HTTP request, so a socks5:// (or otherwise non-HTTP) endpoint would fail
336
+ * every provider call at runtime with an opaque error. Say so once at boot and
337
+ * degrade to a forward proxy, which is what such a URL was always good for. A
338
+ * plaintext relay to a remote host does work, but leaks the provider key and
339
+ * the relay token it carries, so that one only earns a warning.
340
+ */
341
+ function enforceRelayUrlPolicy() {
342
+ if (_proxyMode !== 'fetch-relay' || !_proxyUrl)
343
+ return;
344
+ let protocol = '';
345
+ try {
346
+ protocol = new URL(_proxyUrl).protocol;
347
+ }
348
+ catch { /* handled below */ }
349
+ if (protocol !== 'http:' && protocol !== 'https:') {
350
+ console.warn(`[proxy] fetch-relay mode needs an http(s) relay URL; ${redactProxyUrl(_proxyUrl)} is not one. Falling back to a forward proxy.`);
351
+ _proxyMode = 'forward';
352
+ return;
353
+ }
354
+ const error = fetchRelayUrlError(_proxyUrl);
355
+ if (error)
356
+ console.warn(`[proxy] ${error}`);
357
+ }
358
+ /**
359
+ * Hydrate the process-wide proxy state from the settings table.
360
+ *
361
+ * The standalone server does this in index.ts after initDb; the desktop
362
+ * embedder (desktop/src/server-host.ts) builds the app without index.ts and
363
+ * must call this itself — otherwise the URL saved by PUT /api/settings/proxy
364
+ * sits in the DB but the process starts with an empty proxy and every
365
+ * outbound request goes direct until the user re-saves the setting (#949).
366
+ * Safe to call more than once; it is idempotent.
367
+ */
368
+ export function restoreProxySettings() {
369
+ applyProxyUrl(getSetting('proxy_url') ?? '');
370
+ applyProxyMode(getSetting('proxy_mode') ?? 'forward');
371
+ applyFetchRelayToken(decodeFetchRelayToken(getSetting('fetch_relay_token') ?? ''));
372
+ applyProxyEnabled(getSetting('proxy_enabled') !== '0'); // default: enabled
373
+ applyProxyBypass(getSetting('proxy_bypass') ?? '');
374
+ }
375
+ export function getProxyUrl() {
376
+ return _proxyUrl;
377
+ }
378
+ /** Set how the global proxy URL is used. An explicit PROXY_MODE wins. A legacy
379
+ * PROXY_URL (or an ambient standard proxy variable) without PROXY_MODE always
380
+ * stays a forward proxy, regardless of a saved dashboard mode. */
381
+ export function applyProxyMode(dbValue) {
382
+ const envMode = readEnv('PROXY_MODE');
383
+ const candidate = envMode || (_proxyUrlSource === 'dashboard' ? dbValue.trim() : 'forward');
384
+ _proxyMode = candidate === 'fetch-relay' ? 'fetch-relay' : 'forward';
385
+ enforceRelayUrlPolicy();
386
+ }
387
+ export function getProxyMode() {
388
+ return _proxyMode;
389
+ }
390
+ /** Set the bearer token used only to authenticate srouter to a Fetch Relay.
391
+ * The environment wins so headless deployments never expose or overwrite it
392
+ * through the dashboard. This token is separate from the provider's
393
+ * Authorization header, which is preserved for the upstream request. */
394
+ export function applyFetchRelayToken(dbValue) {
395
+ _fetchRelayToken = readEnv('FETCH_RELAY_TOKEN') || dbValue.trim();
396
+ }
397
+ export function getFetchRelayToken() {
398
+ return _fetchRelayToken;
399
+ }
400
+ /** Encrypt the dashboard-saved Relay credential at rest. The environment form
401
+ * never enters the database. */
402
+ export function encodeFetchRelayToken(value) {
403
+ const trimmed = value.trim();
404
+ return trimmed ? JSON.stringify(encrypt(trimmed)) : '';
405
+ }
406
+ function decodeFetchRelayToken(value) {
407
+ if (!value)
408
+ return '';
409
+ try {
410
+ const parsed = JSON.parse(value);
411
+ if (!parsed.encrypted || !parsed.iv || !parsed.authTag)
412
+ return '';
413
+ return decrypt(parsed.encrypted, parsed.iv, parsed.authTag);
414
+ }
415
+ catch {
416
+ console.warn('[proxy] Saved Fetch Relay token could not be decrypted; configure it again.');
417
+ return '';
418
+ }
419
+ }
420
+ /** Toggle the proxy on/off without losing the URL. */
421
+ export function applyProxyEnabled(enabled) {
422
+ _proxyEnabled = enabled;
423
+ if (!enabled)
424
+ console.log('[proxy] Disabled — requests go direct.');
425
+ }
426
+ export function isProxyEnabled() {
427
+ return _proxyEnabled;
428
+ }
429
+ /** Set which platforms bypass the proxy. Comma-separated string from DB. */
430
+ export function applyProxyBypass(platformsCsv) {
431
+ _bypassPlatforms = new Set(platformsCsv
432
+ .split(',')
433
+ .map(s => s.trim().toLowerCase())
434
+ .filter(Boolean));
435
+ if (_bypassPlatforms.size > 0) {
436
+ console.log(`[proxy] Bypass for: ${[..._bypassPlatforms].join(', ')}`);
437
+ }
438
+ }
439
+ export function getProxyBypassPlatforms() {
440
+ return [..._bypassPlatforms];
441
+ }
442
+ /** The NO_PROXY rules currently in effect (parsed from the env at apply time). */
443
+ export function getNoProxyRules() {
444
+ return [..._noProxyRules];
445
+ }
446
+ /**
447
+ * Returns true when a request should NOT use the proxy.
448
+ * True when: proxy is disabled globally, the platform is in the bypass list,
449
+ * the upstream host is covered by NO_PROXY, or the upstream is a local/LAN
450
+ * destination (#951 — see below).
451
+ *
452
+ * A loopback (127.0.0.0/8, ::1, 0.0.0.0, `localhost`) or private/LAN
453
+ * (RFC1918, ULA, CGNAT) destination is unreachable through a remote proxy:
454
+ * that proxy has no route to your own 127.0.0.1 and, on any network but
455
+ * yours, none to 192.168.1.20 either. Routing it there is never useful and,
456
+ * for SOCKS, actively harmful: an IP literal must go on the wire as ATYP 0x01
457
+ * (an IP) no matter what the `socks5h` suffix promises, so Tor logs "giving
458
+ * Tor only an IP address" and may refuse the connection. The
459
+ * Ollama/llama.cpp/LM Studio case — the app's primary documented local use,
460
+ * "on localhost or the LAN" — is exactly this.
461
+ *
462
+ * SROUTER_PROXY_LOCAL_DESTINATIONS=true opts out, for the one setup where
463
+ * proxying a local address IS the point: an `ssh -D` dynamic tunnel, where
464
+ * http://127.0.0.1:11434 sent through the SOCKS proxy resolves at the far end
465
+ * and reaches the REMOTE host's Ollama.
466
+ */
467
+ function shouldBypassProxy(url, platform) {
468
+ if (!_proxyEnabled)
469
+ return true;
470
+ if (platform && _bypassPlatforms.has(platform.toLowerCase()))
471
+ return true;
472
+ let hostname;
473
+ try {
474
+ hostname = new URL(url).hostname;
475
+ }
476
+ catch {
477
+ // Unparseable URL — leave the routing decision to the caller/fetch.
478
+ return false;
479
+ }
480
+ if (_noProxyRules.length > 0 && noProxyMatches(hostname))
481
+ return true;
482
+ if (!_proxyLocalDestinations && isLoopbackOrPrivateHostname(hostname))
483
+ return true;
484
+ return false;
485
+ }
486
+ /**
487
+ * Resolve the proxy dispatcher. For SOCKS schemes this returns a
488
+ * SocksProxyAgent; for HTTP/HTTPS it returns an undici ProxyAgent.
489
+ */
490
+ async function resolveDispatcher() {
491
+ const now = Date.now();
492
+ if (cached && (now - cached.ts) < CACHE_TTL_MS) {
493
+ return cached.dispatcher ? { dispatcher: cached.dispatcher, isSocks: cached.isSocks } : undefined;
494
+ }
495
+ if (!_initialized)
496
+ applyProxyUrl('');
497
+ if (!_proxyUrl) {
498
+ cached = { dispatcher: undefined, proxyUrl: '', isSocks: false, ts: now };
499
+ return undefined;
500
+ }
501
+ try {
502
+ const isSocks = isSocksProxyUrl(_proxyUrl);
503
+ if (isSocks) {
504
+ const SocksAgent = await loadSocksAgent();
505
+ const dispatcher = new SocksAgent(_proxyUrl);
506
+ cached = { dispatcher, proxyUrl: _proxyUrl, isSocks: true, ts: now };
507
+ return { dispatcher, isSocks: true };
508
+ }
509
+ const ProxyAgentCtor = await loadHttpProxyAgent();
510
+ const dispatcher = new ProxyAgentCtor({ uri: _proxyUrl });
511
+ cached = { dispatcher, proxyUrl: _proxyUrl, isSocks: false, ts: now };
512
+ return { dispatcher, isSocks: false };
513
+ }
514
+ catch (err) {
515
+ console.error(`[proxy] Failed to create dispatcher for "${redactProxyUrl(_proxyUrl)}": ${err.message}`);
516
+ cached = { dispatcher: undefined, proxyUrl: _proxyUrl, isSocks: false, ts: now };
517
+ return undefined;
518
+ }
519
+ }
520
+ /**
521
+ * Build an AbortError DOMException whose `message` carries a compact triage
522
+ * tag in the form `<platform>, <type>, <timeout>s`. No upstream URL, no
523
+ * credentials — the platform column in `requests` already identifies the
524
+ * upstream and the type column identifies the request kind, so the abort
525
+ * message just needs to round-trip what's already on the row.
526
+ *
527
+ * `isRetryableError()` still triggers on the literal substring "aborted".
528
+ *
529
+ * `elapsedMs` (when known) is appended so timeout vs. client-cancel is
530
+ * distinguishable in logs.
531
+ */
532
+ function abortError(platform, type, timeoutMs, elapsedMs) {
533
+ const tag = describeAbort(platform, type, timeoutMs);
534
+ const timing = typeof elapsedMs === 'number' ? ` after ${elapsedMs}ms` : '';
535
+ return new DOMException(`The operation was aborted (${tag})${timing}`, 'AbortError');
536
+ }
537
+ /**
538
+ * Format the `<platform>, <type>, <timeout>s` tag. Exposed for testing and
539
+ * for callers that want to log the tag without re-throwing. Falls back
540
+ * gracefully when fields are missing: unknown platform → 'unknown',
541
+ * unknown type → 'unknown', no timeout → omit the trailing ', <N>s'.
542
+ */
543
+ export function describeAbort(platform, type, timeoutMs) {
544
+ const p = (platform && platform.trim()) || 'unknown';
545
+ const t = type || 'unknown';
546
+ if (typeof timeoutMs !== 'number' || !Number.isFinite(timeoutMs) || timeoutMs <= 0) {
547
+ return `${p}, ${t}`;
548
+ }
549
+ const seconds = Math.max(1, Math.round(timeoutMs / 1000));
550
+ return `${p}, ${t}, ${seconds}s`;
551
+ }
552
+ /**
553
+ * undici reports every connection that never opened as a bare "fetch failed"
554
+ * and keeps the reason (ENOTFOUND, ECONNREFUSED, a certificate error) in
555
+ * `err.cause`, which never reached the attempt trail, the logs or the client.
556
+ * A DNS failure, a dead proxy and TLS-intercepting antivirus all looked the
557
+ * same (#1373). Append the cause code and the upstream host so the message
558
+ * says which it was. "fetch failed" stays as the prefix, which the
559
+ * retry classifier matches on.
560
+ */
561
+ export function describeFetchFailure(err, url, platform) {
562
+ if (!(err instanceof TypeError) || err.message !== 'fetch failed')
563
+ return;
564
+ let code = '';
565
+ const seen = new Set();
566
+ let cur = err.cause;
567
+ for (let depth = 0; cur && typeof cur === 'object' && !seen.has(cur) && depth < 5; depth++) {
568
+ seen.add(cur);
569
+ if (typeof cur.code === 'string' && cur.code) {
570
+ code = cur.code;
571
+ break;
572
+ }
573
+ cur = cur.cause;
574
+ }
575
+ if (!code)
576
+ return;
577
+ let host = '';
578
+ try {
579
+ host = new URL(url).hostname;
580
+ }
581
+ catch { /* leave it out */ }
582
+ const proxied = _proxyEnabled && !!(perKeyProxyStore.getStore() || _proxyUrl) && !shouldBypassProxy(url, platform);
583
+ const parts = [code, host, proxied ? 'via proxy' : ''].filter(Boolean);
584
+ err.message = `fetch failed (${parts.join(' ')})`;
585
+ }
586
+ /**
587
+ * Rewrite an AbortError rejection so its `.message` carries the compact
588
+ * triage tag `<platform>, <type>, <timeout>s`. Preserves `name: 'AbortError'`
589
+ * so `isRetryableError()` (which matches on the substring "aborted") keeps
590
+ * classifying it as retryable. If the original error is not an AbortError,
591
+ * it's returned unchanged.
592
+ */
593
+ function enrichAbort(err, platform, type, timeoutMs) {
594
+ if (!err || typeof err !== 'object')
595
+ return err;
596
+ const e = err;
597
+ const isAbort = e.name === 'AbortError' || /aborted/i.test(e.message ?? '');
598
+ if (!isAbort)
599
+ return e;
600
+ const enriched = new DOMException(`The operation was aborted (${describeAbort(platform, type, timeoutMs)})`, 'AbortError');
601
+ // Preserve upstream error chain so debug logs still see the original cause.
602
+ if (e.cause !== undefined)
603
+ enriched.cause = e.cause;
604
+ return enriched;
605
+ }
606
+ /**
607
+ * DNS `lookup` override for the SOCKS fallback path: hand back the hostname it
608
+ * was asked to resolve, unchanged.
609
+ *
610
+ * socks-proxy-agent resolves the DESTINATION locally for the `socks5://` and
611
+ * `socks4://` schemes (`shouldLookup`) and sends the proxy a bare IP; only
612
+ * `socks5h://`/`socks4a://` pass the name through. That local resolution is
613
+ * what breaks rule-based proxy clients (Clash and friends), which match routing
614
+ * rules on the domain and have nothing to match once the name is gone — and on
615
+ * a DNS-poisoned network it resolves to the poisoned address as well.
616
+ *
617
+ * `http.request` forwards this to the agent as `opts.lookup`, so echoing the
618
+ * hostname makes every SOCKS scheme reach the proxy with the domain intact,
619
+ * i.e. behave like its `h`/`a` variant. The agent only forwards the "address"
620
+ * as the SOCKS destination host — it never inspects the address family, so the
621
+ * `4` is a placeholder the callback signature requires.
622
+ */
623
+ export function socksHostnameLookup(hostname, _options, callback) {
624
+ callback(null, hostname, 4);
625
+ }
626
+ function socksFetch(urlStr, init, agent, platform, type, timeoutMs) {
627
+ const url = new URL(urlStr);
628
+ const isTls = url.protocol === 'https:';
629
+ const transport = isTls ? https : http;
630
+ const port = url.port || (isTls ? 443 : 80);
631
+ const method = init?.method ?? 'GET';
632
+ const headers = {};
633
+ if (init?.headers) {
634
+ for (const [k, v] of Object.entries(init.headers)) {
635
+ headers[k.toLowerCase()] = v;
636
+ }
637
+ }
638
+ const signal = init?.signal;
639
+ const startedAt = Date.now();
640
+ // Socket guard for the SOCKS fallback path — deliberately NOT `timeoutMs`.
641
+ // The two clocks measure different things: http.request's `timeout` is a
642
+ // socket INACTIVITY timer that stays armed across the whole streaming body,
643
+ // while `timeoutMs` is a header/request deadline the caller disarms the
644
+ // moment response headers arrive (providers/base.ts fetchWithTimeout). Mid-
645
+ // stream time is owned by the stall watchdog and the first-byte grace
646
+ // (#553/#584, default 90s), so pinning the socket timer to a platform's
647
+ // 15-60s chat timeout would kill healthy streams during prefill.
648
+ //
649
+ // So this only ever RAISES the historical 120s floor (#666): a user with
650
+ // PROVIDER_TIMEOUT_CUSTOM=600000 no longer dies at 120s, and the +30s grace
651
+ // keeps the caller's abort firing first so the tagged AbortError (see
652
+ // enrichAbort) survives instead of the bare socket 'timeout'. 0 means "no
653
+ // timeout" (provider semantics); undefined or malformed input falls back to
654
+ // the 120s guard rather than disabling it.
655
+ const socketTimeoutMs = timeoutMs === 0
656
+ ? 0
657
+ : typeof timeoutMs === 'number' && Number.isFinite(timeoutMs) && timeoutMs > 0
658
+ ? Math.max(timeoutMs + 30_000, 120_000)
659
+ : 120_000;
660
+ // What to reject with when the signal fires. A client-caused abort carries
661
+ // its own marked reason (newClientAbortError in lib/error-classify.ts) —
662
+ // preserve it so the failure isn't misclassified downstream as a provider
663
+ // timeout; a plain timer abort keeps the tagged AbortError.
664
+ const abortRejection = () => {
665
+ const reason = signal?.reason;
666
+ return reason instanceof Error && reason.name !== 'AbortError' && reason.name !== 'TimeoutError'
667
+ ? reason
668
+ : abortError(platform, type, timeoutMs, Date.now() - startedAt);
669
+ };
670
+ return new Promise((resolve, reject) => {
671
+ const req = transport.request({
672
+ hostname: url.hostname,
673
+ port,
674
+ path: url.pathname + url.search,
675
+ method,
676
+ headers: { ...headers, host: url.hostname },
677
+ agent,
678
+ servername: isTls ? url.hostname : undefined,
679
+ rejectUnauthorized: true,
680
+ timeout: socketTimeoutMs,
681
+ // Keep the destination hostname unresolved so the SOCKS proxy does the
682
+ // DNS. `agent` here is always a SocksProxyAgent (every socksFetch caller
683
+ // is behind an `isSocks` branch), and the agent is the only consumer of
684
+ // this hook — the connection to the proxy itself still resolves normally.
685
+ lookup: socksHostnameLookup,
686
+ }, (res) => {
687
+ if (signal?.aborted) {
688
+ res.destroy();
689
+ reject(abortRejection());
690
+ return;
691
+ }
692
+ const status = res.statusCode ?? 0;
693
+ const statusText = res.statusMessage ?? '';
694
+ const body = new ReadableStream({
695
+ start(controller) {
696
+ res.on('data', (chunk) => controller.enqueue(new Uint8Array(chunk)));
697
+ res.on('end', () => controller.close());
698
+ res.on('error', (err) => controller.error(err));
699
+ },
700
+ cancel() {
701
+ res.destroy();
702
+ },
703
+ });
704
+ const hdrs = {};
705
+ for (const [k, v] of Object.entries(res.headers)) {
706
+ hdrs[k] = v;
707
+ }
708
+ resolve(new Response(body, { status, statusText, headers: hdrs }));
709
+ });
710
+ req.on('error', (err) => reject(err));
711
+ req.on('timeout', () => {
712
+ req.destroy();
713
+ reject(new Error('timeout'));
714
+ });
715
+ if (signal) {
716
+ if (signal.aborted) {
717
+ req.destroy();
718
+ reject(abortRejection());
719
+ return;
720
+ }
721
+ signal.addEventListener('abort', () => {
722
+ req.destroy();
723
+ reject(abortRejection());
724
+ }, { once: true });
725
+ }
726
+ if (init?.body) {
727
+ req.write(init.body);
728
+ }
729
+ req.end();
730
+ });
731
+ }
732
+ /**
733
+ * Drop-in replacement for `fetch(url, init)` that routes through the
734
+ * configured proxy. Pass an optional `platform` string to respect the
735
+ * per-platform bypass list.
736
+ *
737
+ * When no proxy is configured, or proxy is disabled, or the platform is
738
+ * in the bypass list, this is a direct pass-through to `fetch()`.
739
+ *
740
+ * `requestType` and `timeoutMs` are propagated into the AbortError
741
+ * message so triage reads `<platform>, <type>, <timeout>s`. Both default
742
+ * to `undefined` / `'unknown'` when callers haven't been updated yet —
743
+ * the abort still fires, it just omits the unknown fields.
744
+ */
745
+ const REDIRECT_STATUSES = new Set([301, 302, 303, 307, 308]);
746
+ export async function proxyFetch(url, init, platform, requestType = 'unknown', timeoutMs) {
747
+ try {
748
+ // SSRF guard (#440): 'custom' is the only platform whose target URL is
749
+ // user-supplied (base_url on the api_keys row), so it is re-assessed on
750
+ // every request — a URL saved before the guard existed, edited in the DB,
751
+ // or whose DNS now points somewhere blocked still can't reach cloud
752
+ // metadata / link-local addresses.
753
+ if (platform === 'custom') {
754
+ await assertProviderUrlAllowed(url);
755
+ // Redirects are never followed for custom providers: fetch()'s default
756
+ // 'follow' would re-request the Location target WITHOUT re-running the
757
+ // guard above, so a public base_url answering 302 → an internal or
758
+ // metadata address would defeat the check. socksFetch (http.request)
759
+ // never followed redirects; forcing redirect: 'manual' here makes every
760
+ // path behave the same, and the 3xx is converted to an explicit error
761
+ // below so the operator sees why instead of a confusing empty body.
762
+ init = { ...init, redirect: 'manual' };
763
+ }
764
+ const response = await dispatchFetch(url, init, platform, requestType, timeoutMs);
765
+ if (platform === 'custom' && REDIRECT_STATUSES.has(response.status)) {
766
+ const location = response.headers.get('location') ?? 'an unspecified location';
767
+ throw new Error(`Custom provider URL blocked: upstream redirected (${response.status}) to ${location}; ` +
768
+ 'redirects are not followed for custom providers, point base_url directly at the API');
769
+ }
770
+ return response;
771
+ }
772
+ catch (err) {
773
+ describeFetchFailure(err, url, platform);
774
+ // Rewrite bare "The operation was aborted" rejections so they carry the
775
+ // compact triage tag. Preserves the AbortError name so
776
+ // `isRetryableError()` still classifies the failure as retryable.
777
+ throw enrichAbort(err, platform, requestType, timeoutMs);
778
+ }
779
+ }
780
+ /** Route the request through the configured proxy (or straight to fetch). */
781
+ async function dispatchFetch(url, init, platform, requestType, timeoutMs) {
782
+ // #590: a per-key proxy override (set via withKeyProxy around the provider
783
+ // call) takes precedence over the global proxy for THIS request. Empty
784
+ // string (the store default) means "fall back to global".
785
+ const perKeyUrl = perKeyProxyStore.getStore() ?? '';
786
+ if (perKeyUrl) {
787
+ // Every bypass still applies, unchanged: the global on/off switch, the
788
+ // per-platform bypass list, NO_PROXY, and local/LAN destinations. A
789
+ // per-key override says WHICH proxy to use, not that this request must be
790
+ // proxied — an operator who turned proxying off, listed the upstream in
791
+ // NO_PROXY, or points at a local box still gets a direct connection.
792
+ if (!shouldBypassProxy(url, platform)) {
793
+ const resolved = await resolvePerKeyDispatcher(perKeyUrl);
794
+ if (resolved) {
795
+ if (resolved.isSocks) {
796
+ return socksFetch(url, init, resolved.dispatcher, platform, requestType, timeoutMs);
797
+ }
798
+ return fetch(url, { ...init, dispatcher: resolved.dispatcher });
799
+ }
800
+ }
801
+ // Per-key proxy failed to build → fall through to the global/direct path.
802
+ }
803
+ // Bypass check: disabled globally, this platform is exempt, the upstream
804
+ // host is listed in NO_PROXY, or it is a local/LAN destination no proxy can
805
+ // reach (#951).
806
+ if (shouldBypassProxy(url, platform)) {
807
+ return fetch(url, init);
808
+ }
809
+ if (_proxyMode === 'fetch-relay' && _proxyUrl) {
810
+ return fetchRelayFetch(_proxyUrl, url, init, _fetchRelayToken);
811
+ }
812
+ const resolved = await resolveDispatcher();
813
+ // No dispatcher (no proxy URL configured, or it failed to build) → direct
814
+ if (!resolved) {
815
+ return fetch(url, init);
816
+ }
817
+ // SOCKS proxy → http/https fallback
818
+ if (resolved.isSocks) {
819
+ return socksFetch(url, init, resolved.dispatcher, platform, requestType, timeoutMs);
820
+ }
821
+ // HTTP/HTTPS proxy → undici (dispatcher is an undici extension not in TS types)
822
+ return fetch(url, { ...init, dispatcher: resolved.dispatcher });
823
+ }
824
+ /** Send an application-layer HTTP request through a user-controlled fetch
825
+ * relay. The original body remains a stream/body object and the returned
826
+ * Response is passed through untouched, so neither direction is buffered.
827
+ * Redirects from the relay are deliberately exposed to the caller: following
828
+ * one here could silently turn a relayed request into a direct request. */
829
+ async function fetchRelayFetch(relayUrl, targetUrl, init, relayToken) {
830
+ const headers = new Headers(init?.headers);
831
+ // These describe the provider connection and must be recalculated for the
832
+ // relay connection. The relay reference implementation removes the target
833
+ // header before calling the provider.
834
+ headers.delete('host');
835
+ headers.delete('content-length');
836
+ headers.set(FETCH_RELAY_TARGET_HEADER, targetUrl);
837
+ // Always overwrite caller-supplied Relay control headers. They belong to
838
+ // this hop and must not let an upstream request choose another target or
839
+ // credential. An empty token supports deliberately unauthenticated relays.
840
+ if (relayToken)
841
+ headers.set(FETCH_RELAY_AUTH_HEADER, `Bearer ${relayToken}`);
842
+ else
843
+ headers.delete(FETCH_RELAY_AUTH_HEADER);
844
+ return fetch(relayUrl, {
845
+ ...init,
846
+ headers,
847
+ redirect: 'manual',
848
+ });
849
+ }
850
+ /** Build (and TTL-cache) a dispatcher for a per-key proxy URL. Returns
851
+ * undefined when the URL is empty or the agent fails to build. */
852
+ async function resolvePerKeyDispatcher(proxyUrl) {
853
+ const now = Date.now();
854
+ const hit = perKeyCached.get(proxyUrl);
855
+ if (hit?.dispatcher) {
856
+ rememberPerKeyDispatcher(proxyUrl, hit);
857
+ return { dispatcher: hit.dispatcher, isSocks: hit.isSocks };
858
+ }
859
+ // Negative entry, still inside its cool-off: don't retry the build yet.
860
+ if (hit && now - hit.ts < PER_KEY_FAILURE_TTL_MS)
861
+ return undefined;
862
+ try {
863
+ const isSocks = isSocksProxyUrl(proxyUrl);
864
+ if (isSocks) {
865
+ const SocksAgent = await loadSocksAgent();
866
+ const dispatcher = new SocksAgent(proxyUrl);
867
+ rememberPerKeyDispatcher(proxyUrl, { dispatcher, isSocks: true, ts: now });
868
+ return { dispatcher, isSocks: true };
869
+ }
870
+ const ProxyAgentCtor = await loadHttpProxyAgent();
871
+ const dispatcher = new ProxyAgentCtor({ uri: proxyUrl });
872
+ rememberPerKeyDispatcher(proxyUrl, { dispatcher, isSocks: false, ts: now });
873
+ return { dispatcher, isSocks: false };
874
+ }
875
+ catch (err) {
876
+ console.error(`[proxy] Failed to create per-key dispatcher for "${redactProxyUrl(proxyUrl)}": ${err.message}`);
877
+ rememberPerKeyDispatcher(proxyUrl, { dispatcher: undefined, isSocks: false, ts: now });
878
+ return undefined;
879
+ }
880
+ }
881
+ /**
882
+ * Returns true when the proxy is configured AND enabled. Used by the dashboard
883
+ * to show the "Active" badge. Intentionally does NOT construct a dispatcher (so
884
+ * it never triggers the lazy undici import) — "configured + enabled" is exactly
885
+ * what the badge means.
886
+ */
887
+ export function isProxyActive() {
888
+ if (!_initialized)
889
+ applyProxyUrl('');
890
+ return _proxyEnabled && !!_proxyUrl;
891
+ }
892
+ /** Force-rebuild the outbound connection pools on the next request. Called on
893
+ * sleep/wake recovery to drop pooled TCP connections that died while the
894
+ * host was suspended (undici keeps them warm and would hand a dead socket
895
+ * to the first post-wake request). */
896
+ export function flushProxyCache() {
897
+ // Outbound-proxy dispatcher (only in play when a proxy URL is configured).
898
+ cached = null;
899
+ // The default no-proxy path is bare fetch() on Node's GLOBAL undici
900
+ // dispatcher — exactly the pool the headline laptop-lid scenario rides — so
901
+ // nulling the proxy cache alone left the flush a no-op for most
902
+ // deployments. Node keeps that dispatcher in the global symbol registry
903
+ // (getGlobalDispatcher/setGlobalDispatcher read and write the same key), so
904
+ // swap in a fresh instance of its own constructor: new requests get new
905
+ // sockets, in-flight requests keep a reference to the old dispatcher and
906
+ // complete undisturbed. Deliberately NOT `import('undici')`: the built-in
907
+ // fetch uses Node's bundled copy, and the npm package isn't installed in
908
+ // the production image (verified live — the import throws there).
909
+ try {
910
+ const sym = Symbol.for('undici.globalDispatcher.1');
911
+ const current = globalThis[sym];
912
+ // Symbol unset = no fetch has run yet, so there are no pooled sockets to drop.
913
+ if (current?.constructor) {
914
+ globalThis[sym] = new current.constructor();
915
+ }
916
+ }
917
+ catch (err) {
918
+ console.warn(`[proxy] could not replace the global fetch dispatcher on wake: ${err?.message ?? err}`);
919
+ }
920
+ }
921
+ /**
922
+ * Where the probe goes when the caller names no target and no provider key
923
+ * can supply one.
924
+ *
925
+ * Deliberately NOT an AI vendor. The probe answers "can this proxy reach the
926
+ * internet", and pointing it at a third party the install may never use makes
927
+ * the test lie in both directions: a gateway that never calls that vendor now
928
+ * calls it on every Test, and a network that blocks it reports a working proxy
929
+ * as broken. `/cdn-cgi/trace` is a plain-text reachability endpoint with no
930
+ * account, no rate limit and no regional AI-vendor blocking.
931
+ */
932
+ export const DEFAULT_PROXY_PROBE_TARGET = 'https://www.cloudflare.com/cdn-cgi/trace';
933
+ /**
934
+ * Test whether a proxy URL can actually route traffic (#863). Backs the
935
+ * Settings → Outbound proxy "Test" button so an operator can verify a draft
936
+ * value BEFORE saving it.
937
+ *
938
+ * `proxyUrl` empty → falls back to the saved global proxy URL (getProxyUrl);
939
+ * when neither is set the probe runs direct, so the button is still useful
940
+ * before any proxy has been configured.
941
+ *
942
+ * The probe target is supplied by the caller and should be an endpoint this
943
+ * install genuinely uses — the /models route of a provider the operator holds
944
+ * an enabled key for. Any HTTP response, even a 401/403 without a key, proves
945
+ * the proxy route works; only a network-level failure (DNS, connect, timeout)
946
+ * counts as a proxy failure.
947
+ */
948
+ export async function probeProxyUrl(proxyUrl, options = {}) {
949
+ const timeoutMs = options.timeoutMs ?? 10_000;
950
+ const started = Date.now();
951
+ const url = (proxyUrl ?? '').trim() || getProxyUrl();
952
+ // The caller passes the endpoint this install actually talks to (see
953
+ // routes/settings.ts); the constant is only the no-providers fallback.
954
+ const target = (options.targetUrl ?? '').trim() || DEFAULT_PROXY_PROBE_TARGET;
955
+ const relayMode = Boolean(url) && (options.mode ?? getProxyMode()) === 'fetch-relay';
956
+ try {
957
+ let response;
958
+ if (!url) {
959
+ response = await fetch(target, { signal: AbortSignal.timeout(timeoutMs) });
960
+ }
961
+ else if (relayMode) {
962
+ response = await fetchRelayFetch(url, target, {
963
+ method: 'GET',
964
+ signal: AbortSignal.timeout(timeoutMs),
965
+ }, options.relayToken ?? getFetchRelayToken());
966
+ }
967
+ else {
968
+ const resolved = await resolvePerKeyDispatcher(url);
969
+ if (!resolved) {
970
+ return { ok: false, latencyMs: Date.now() - started, target, error: 'Failed to build a proxy agent for the given URL' };
971
+ }
972
+ if (resolved.isSocks) {
973
+ response = await socksFetch(target, { signal: AbortSignal.timeout(timeoutMs) }, resolved.dispatcher, undefined, 'unknown', timeoutMs);
974
+ }
975
+ else {
976
+ response = await fetch(target, { ...{ signal: AbortSignal.timeout(timeoutMs) }, dispatcher: resolved.dispatcher });
977
+ }
978
+ }
979
+ // A relay answers on the same connection it forwards over, so a 401/403
980
+ // here is far more likely to be the relay refusing our token than the
981
+ // provider refusing a key we never sent. Reporting that as a pass is what
982
+ // makes a misconfigured token look like a working relay, so fail it and
983
+ // name the hop. A provider that genuinely answers 401 through a good relay
984
+ // is the rare false negative, and the reason still points at the token.
985
+ if (relayMode && (response.status === 401 || response.status === 403)) {
986
+ return {
987
+ ok: false,
988
+ latencyMs: Date.now() - started,
989
+ status: response.status,
990
+ target,
991
+ error: `relay rejected the token (${response.status})`,
992
+ };
993
+ }
994
+ // Any other HTTP response proves the proxy route works; the upstream may
995
+ // still answer 4xx without a key, which is connectivity, not proxy failure.
996
+ return { ok: true, latencyMs: Date.now() - started, status: response.status, target };
997
+ }
998
+ catch (err) {
999
+ return { ok: false, latencyMs: Date.now() - started, target, error: err?.message ?? String(err) };
1000
+ }
1001
+ }
1002
+ //# sourceMappingURL=proxy.js.map