@amir83nasr/10router 0.1.8 → 0.1.9

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 (299) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-path-routes-manifest.json +6 -6
  3. package/.next/build-manifest.json +3 -3
  4. package/.next/prerender-manifest.json +23 -23
  5. package/.next/react-loadable-manifest.json +9 -0
  6. package/.next/server/app/(dashboard)/dashboard/basic-chat/page.js +1 -1
  7. package/.next/server/app/(dashboard)/dashboard/basic-chat/page.js.nft.json +1 -1
  8. package/.next/server/app/(dashboard)/dashboard/basic-chat/page_client-reference-manifest.js +1 -1
  9. package/.next/server/app/(dashboard)/dashboard/cli-tools/[toolId]/page.js +2 -2
  10. package/.next/server/app/(dashboard)/dashboard/cli-tools/[toolId]/page.js.nft.json +1 -1
  11. package/.next/server/app/(dashboard)/dashboard/cli-tools/[toolId]/page_client-reference-manifest.js +1 -1
  12. package/.next/server/app/(dashboard)/dashboard/cli-tools/page.js +1 -1
  13. package/.next/server/app/(dashboard)/dashboard/cli-tools/page.js.nft.json +1 -1
  14. package/.next/server/app/(dashboard)/dashboard/cli-tools/page_client-reference-manifest.js +1 -1
  15. package/.next/server/app/(dashboard)/dashboard/combos/page.js +1 -1
  16. package/.next/server/app/(dashboard)/dashboard/combos/page.js.nft.json +1 -1
  17. package/.next/server/app/(dashboard)/dashboard/combos/page_client-reference-manifest.js +1 -1
  18. package/.next/server/app/(dashboard)/dashboard/console-log/page.js +1 -1
  19. package/.next/server/app/(dashboard)/dashboard/console-log/page.js.nft.json +1 -1
  20. package/.next/server/app/(dashboard)/dashboard/console-log/page_client-reference-manifest.js +1 -1
  21. package/.next/server/app/(dashboard)/dashboard/endpoint/page.js +1 -1
  22. package/.next/server/app/(dashboard)/dashboard/endpoint/page.js.nft.json +1 -1
  23. package/.next/server/app/(dashboard)/dashboard/endpoint/page_client-reference-manifest.js +1 -1
  24. package/.next/server/app/(dashboard)/dashboard/media-providers/systemone/[id]/page.js +1 -1
  25. package/.next/server/app/(dashboard)/dashboard/media-providers/systemone/[id]/page.js.nft.json +1 -1
  26. package/.next/server/app/(dashboard)/dashboard/media-providers/systemone/[id]/page_client-reference-manifest.js +1 -1
  27. package/.next/server/app/(dashboard)/dashboard/media-providers/systemone/page.js +1 -1
  28. package/.next/server/app/(dashboard)/dashboard/media-providers/systemone/page.js.nft.json +1 -1
  29. package/.next/server/app/(dashboard)/dashboard/media-providers/systemone/page_client-reference-manifest.js +1 -1
  30. package/.next/server/app/(dashboard)/dashboard/page.js +1 -1
  31. package/.next/server/app/(dashboard)/dashboard/page.js.nft.json +1 -1
  32. package/.next/server/app/(dashboard)/dashboard/page_client-reference-manifest.js +1 -1
  33. package/.next/server/app/(dashboard)/dashboard/profile/page.js +1 -1
  34. package/.next/server/app/(dashboard)/dashboard/profile/page.js.nft.json +1 -1
  35. package/.next/server/app/(dashboard)/dashboard/profile/page_client-reference-manifest.js +1 -1
  36. package/.next/server/app/(dashboard)/dashboard/providers/[id]/page.js +1 -1
  37. package/.next/server/app/(dashboard)/dashboard/providers/[id]/page.js.nft.json +1 -1
  38. package/.next/server/app/(dashboard)/dashboard/providers/[id]/page_client-reference-manifest.js +1 -1
  39. package/.next/server/app/(dashboard)/dashboard/providers/new/page.js +1 -1
  40. package/.next/server/app/(dashboard)/dashboard/providers/new/page.js.nft.json +1 -1
  41. package/.next/server/app/(dashboard)/dashboard/providers/new/page_client-reference-manifest.js +1 -1
  42. package/.next/server/app/(dashboard)/dashboard/providers/page.js +1 -1
  43. package/.next/server/app/(dashboard)/dashboard/providers/page.js.nft.json +1 -1
  44. package/.next/server/app/(dashboard)/dashboard/providers/page_client-reference-manifest.js +1 -1
  45. package/.next/server/app/(dashboard)/dashboard/proxy-pools/page.js +2 -2
  46. package/.next/server/app/(dashboard)/dashboard/proxy-pools/page.js.nft.json +1 -1
  47. package/.next/server/app/(dashboard)/dashboard/proxy-pools/page_client-reference-manifest.js +1 -1
  48. package/.next/server/app/(dashboard)/dashboard/pxpipe/page.js +1 -1
  49. package/.next/server/app/(dashboard)/dashboard/pxpipe/page.js.nft.json +1 -1
  50. package/.next/server/app/(dashboard)/dashboard/pxpipe/page_client-reference-manifest.js +1 -1
  51. package/.next/server/app/(dashboard)/dashboard/quota/page.js +1 -1
  52. package/.next/server/app/(dashboard)/dashboard/quota/page.js.nft.json +1 -1
  53. package/.next/server/app/(dashboard)/dashboard/quota/page_client-reference-manifest.js +1 -1
  54. package/.next/server/app/(dashboard)/dashboard/token-saver/page.js +1 -1
  55. package/.next/server/app/(dashboard)/dashboard/token-saver/page.js.nft.json +1 -1
  56. package/.next/server/app/(dashboard)/dashboard/token-saver/page_client-reference-manifest.js +1 -1
  57. package/.next/server/app/(dashboard)/dashboard/usage/page.js +1 -1
  58. package/.next/server/app/(dashboard)/dashboard/usage/page.js.nft.json +1 -1
  59. package/.next/server/app/(dashboard)/dashboard/usage/page_client-reference-manifest.js +1 -1
  60. package/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  61. package/.next/server/app/_global-error.html +1 -1
  62. package/.next/server/app/_global-error.rsc +1 -1
  63. package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  64. package/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  65. package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  66. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  67. package/.next/server/app/_not-found.html +1 -1
  68. package/.next/server/app/_not-found.rsc +5 -5
  69. package/.next/server/app/_not-found.segments/_full.segment.rsc +5 -5
  70. package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +5 -5
  71. package/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  72. package/.next/server/app/api/cli-tools/all-statuses/route.js +1 -1
  73. package/.next/server/app/api/cli-tools/claude-settings/route.js +1 -1
  74. package/.next/server/app/api/cli-tools/codex-settings/route.js +1 -1
  75. package/.next/server/app/api/cli-tools/cowork-mcp-registry/route.js +1 -1
  76. package/.next/server/app/api/cli-tools/cowork-mcp-tools/route.js +1 -1
  77. package/.next/server/app/api/cli-tools/cowork-settings/route.js +1 -1
  78. package/.next/server/app/api/cli-tools/dsh-settings/route.js +1 -1
  79. package/.next/server/app/api/cli-tools/opencode-settings/route.js +1 -1
  80. package/.next/server/app/api/combos/[id]/route.js +1 -1
  81. package/.next/server/app/api/combos/route.js +1 -1
  82. package/.next/server/app/api/oauth/[provider]/[action]/route.js +1 -1
  83. package/.next/server/app/api/oauth/codex/bulk-import/route.js +1 -1
  84. package/.next/server/app/api/oauth/codex/import-token/route.js +1 -1
  85. package/.next/server/app/api/providers/[id]/models/route.js +1 -1
  86. package/.next/server/app/api/providers/client/route.js +1 -1
  87. package/.next/server/app/api/providers/route.js +1 -1
  88. package/.next/server/app/api/translator/send/route.js +1 -1
  89. package/.next/server/app/api/translator/translate/route.js +1 -1
  90. package/.next/server/app/api/tunnel/tailscale-install/route.js +2 -2
  91. package/.next/server/app/api/usage/[connectionId]/codex-reset-credits/route.js +1 -1
  92. package/.next/server/app/api/usage/[connectionId]/route.js +1 -1
  93. package/.next/server/app/api/usage/stream/route.js +2 -6
  94. package/.next/server/app/api/v1/audio/speech/route.js +1 -1
  95. package/.next/server/app/api/v1/audio/transcriptions/route.js +1 -1
  96. package/.next/server/app/api/v1/embeddings/route.js +1 -1
  97. package/.next/server/app/api/v1/images/generations/route.js +1 -1
  98. package/.next/server/app/api/v1/systemone/route.js +1 -1
  99. package/.next/server/app/api/version/route.js +1 -1
  100. package/.next/server/app/callback/page_client-reference-manifest.js +1 -1
  101. package/.next/server/app/callback.html +1 -1
  102. package/.next/server/app/callback.rsc +6 -6
  103. package/.next/server/app/callback.segments/_full.segment.rsc +6 -6
  104. package/.next/server/app/callback.segments/_tree.segment.rsc +1 -1
  105. package/.next/server/app/callback.segments/callback/__PAGE__.segment.rsc +6 -6
  106. package/.next/server/app/dashboard/basic-chat.html +1 -1
  107. package/.next/server/app/dashboard/basic-chat.rsc +7 -7
  108. package/.next/server/app/dashboard/basic-chat.segments/!KGRhc2hib2FyZCk/dashboard/basic-chat/__PAGE__.segment.rsc +7 -7
  109. package/.next/server/app/dashboard/basic-chat.segments/_full.segment.rsc +7 -7
  110. package/.next/server/app/dashboard/basic-chat.segments/_tree.segment.rsc +1 -1
  111. package/.next/server/app/dashboard/cli-tools.html +1 -1
  112. package/.next/server/app/dashboard/cli-tools.rsc +7 -7
  113. package/.next/server/app/dashboard/cli-tools.segments/!KGRhc2hib2FyZCk/dashboard/cli-tools/__PAGE__.segment.rsc +7 -7
  114. package/.next/server/app/dashboard/cli-tools.segments/_full.segment.rsc +7 -7
  115. package/.next/server/app/dashboard/cli-tools.segments/_tree.segment.rsc +1 -1
  116. package/.next/server/app/dashboard/combos.html +1 -1
  117. package/.next/server/app/dashboard/combos.rsc +7 -7
  118. package/.next/server/app/dashboard/combos.segments/!KGRhc2hib2FyZCk/dashboard/combos/__PAGE__.segment.rsc +7 -7
  119. package/.next/server/app/dashboard/combos.segments/_full.segment.rsc +7 -7
  120. package/.next/server/app/dashboard/combos.segments/_tree.segment.rsc +1 -1
  121. package/.next/server/app/dashboard/endpoint.html +1 -1
  122. package/.next/server/app/dashboard/endpoint.rsc +7 -7
  123. package/.next/server/app/dashboard/endpoint.segments/!KGRhc2hib2FyZCk/dashboard/endpoint/__PAGE__.segment.rsc +7 -7
  124. package/.next/server/app/dashboard/endpoint.segments/_full.segment.rsc +7 -7
  125. package/.next/server/app/dashboard/endpoint.segments/_tree.segment.rsc +1 -1
  126. package/.next/server/app/dashboard/media-providers/systemone.html +1 -1
  127. package/.next/server/app/dashboard/media-providers/systemone.rsc +7 -7
  128. package/.next/server/app/dashboard/media-providers/systemone.segments/!KGRhc2hib2FyZCk/dashboard/media-providers/systemone/__PAGE__.segment.rsc +7 -7
  129. package/.next/server/app/dashboard/media-providers/systemone.segments/_full.segment.rsc +7 -7
  130. package/.next/server/app/dashboard/media-providers/systemone.segments/_tree.segment.rsc +1 -1
  131. package/.next/server/app/dashboard/profile.html +1 -1
  132. package/.next/server/app/dashboard/profile.rsc +7 -7
  133. package/.next/server/app/dashboard/profile.segments/!KGRhc2hib2FyZCk/dashboard/profile/__PAGE__.segment.rsc +7 -7
  134. package/.next/server/app/dashboard/profile.segments/_full.segment.rsc +7 -7
  135. package/.next/server/app/dashboard/profile.segments/_tree.segment.rsc +1 -1
  136. package/.next/server/app/dashboard/providers/new.html +1 -1
  137. package/.next/server/app/dashboard/providers/new.rsc +7 -7
  138. package/.next/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk/dashboard/providers/new/__PAGE__.segment.rsc +7 -7
  139. package/.next/server/app/dashboard/providers/new.segments/_full.segment.rsc +7 -7
  140. package/.next/server/app/dashboard/providers/new.segments/_tree.segment.rsc +1 -1
  141. package/.next/server/app/dashboard/providers.html +1 -1
  142. package/.next/server/app/dashboard/providers.rsc +7 -7
  143. package/.next/server/app/dashboard/providers.segments/!KGRhc2hib2FyZCk/dashboard/providers/__PAGE__.segment.rsc +7 -7
  144. package/.next/server/app/dashboard/providers.segments/_full.segment.rsc +7 -7
  145. package/.next/server/app/dashboard/providers.segments/_tree.segment.rsc +1 -1
  146. package/.next/server/app/dashboard/proxy-pools.html +1 -1
  147. package/.next/server/app/dashboard/proxy-pools.rsc +7 -7
  148. package/.next/server/app/dashboard/proxy-pools.segments/!KGRhc2hib2FyZCk/dashboard/proxy-pools/__PAGE__.segment.rsc +7 -7
  149. package/.next/server/app/dashboard/proxy-pools.segments/_full.segment.rsc +7 -7
  150. package/.next/server/app/dashboard/proxy-pools.segments/_tree.segment.rsc +1 -1
  151. package/.next/server/app/dashboard/pxpipe.html +1 -1
  152. package/.next/server/app/dashboard/pxpipe.rsc +7 -7
  153. package/.next/server/app/dashboard/pxpipe.segments/!KGRhc2hib2FyZCk/dashboard/pxpipe/__PAGE__.segment.rsc +7 -7
  154. package/.next/server/app/dashboard/pxpipe.segments/_full.segment.rsc +7 -7
  155. package/.next/server/app/dashboard/pxpipe.segments/_tree.segment.rsc +1 -1
  156. package/.next/server/app/dashboard/quota.html +2 -2
  157. package/.next/server/app/dashboard/quota.rsc +8 -8
  158. package/.next/server/app/dashboard/quota.segments/!KGRhc2hib2FyZCk/dashboard/quota/__PAGE__.segment.rsc +8 -8
  159. package/.next/server/app/dashboard/quota.segments/_full.segment.rsc +8 -8
  160. package/.next/server/app/dashboard/quota.segments/_tree.segment.rsc +1 -1
  161. package/.next/server/app/dashboard/settings/pricing/page_client-reference-manifest.js +1 -1
  162. package/.next/server/app/dashboard/settings/pricing.html +1 -1
  163. package/.next/server/app/dashboard/settings/pricing.rsc +6 -6
  164. package/.next/server/app/dashboard/settings/pricing.segments/_full.segment.rsc +6 -6
  165. package/.next/server/app/dashboard/settings/pricing.segments/_tree.segment.rsc +1 -1
  166. package/.next/server/app/dashboard/settings/pricing.segments/dashboard/settings/pricing/__PAGE__.segment.rsc +6 -6
  167. package/.next/server/app/dashboard/token-saver.html +1 -1
  168. package/.next/server/app/dashboard/token-saver.rsc +6 -6
  169. package/.next/server/app/dashboard/token-saver.segments/!KGRhc2hib2FyZCk/dashboard/token-saver/__PAGE__.segment.rsc +6 -6
  170. package/.next/server/app/dashboard/token-saver.segments/_full.segment.rsc +6 -6
  171. package/.next/server/app/dashboard/token-saver.segments/_tree.segment.rsc +1 -1
  172. package/.next/server/app/dashboard/usage.html +2 -2
  173. package/.next/server/app/dashboard/usage.rsc +7 -7
  174. package/.next/server/app/dashboard/usage.segments/!KGRhc2hib2FyZCk/dashboard/usage/__PAGE__.segment.rsc +7 -7
  175. package/.next/server/app/dashboard/usage.segments/_full.segment.rsc +7 -7
  176. package/.next/server/app/dashboard/usage.segments/_tree.segment.rsc +1 -1
  177. package/.next/server/app/dashboard.html +1 -1
  178. package/.next/server/app/dashboard.rsc +7 -7
  179. package/.next/server/app/dashboard.segments/!KGRhc2hib2FyZCk/dashboard/__PAGE__.segment.rsc +7 -7
  180. package/.next/server/app/dashboard.segments/_full.segment.rsc +7 -7
  181. package/.next/server/app/dashboard.segments/_tree.segment.rsc +1 -1
  182. package/.next/server/app/index.html +1 -1
  183. package/.next/server/app/index.rsc +5 -5
  184. package/.next/server/app/index.segments/__PAGE__.segment.rsc +5 -5
  185. package/.next/server/app/index.segments/_full.segment.rsc +5 -5
  186. package/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  187. package/.next/server/app/landing/page_client-reference-manifest.js +1 -1
  188. package/.next/server/app/landing.html +1 -1
  189. package/.next/server/app/landing.rsc +6 -6
  190. package/.next/server/app/landing.segments/_full.segment.rsc +6 -6
  191. package/.next/server/app/landing.segments/_tree.segment.rsc +1 -1
  192. package/.next/server/app/landing.segments/landing/__PAGE__.segment.rsc +6 -6
  193. package/.next/server/app/login/page_client-reference-manifest.js +1 -1
  194. package/.next/server/app/login.html +1 -1
  195. package/.next/server/app/login.rsc +5 -5
  196. package/.next/server/app/login.segments/_full.segment.rsc +5 -5
  197. package/.next/server/app/login.segments/_tree.segment.rsc +1 -1
  198. package/.next/server/app/login.segments/login/__PAGE__.segment.rsc +5 -5
  199. package/.next/server/app/page_client-reference-manifest.js +1 -1
  200. package/.next/server/app-paths-manifest.json +6 -6
  201. package/.next/server/chunks/1003.js +1 -1
  202. package/.next/server/chunks/1011.js +1 -1
  203. package/.next/server/chunks/1194.js +1 -1
  204. package/.next/server/chunks/1289.js +1 -1
  205. package/.next/server/chunks/1412.js +1 -1
  206. package/.next/server/chunks/1633.js +1 -1
  207. package/.next/server/chunks/1985.js +1 -1
  208. package/.next/server/chunks/2282.js +8 -4
  209. package/.next/server/chunks/2339.js +1 -1
  210. package/.next/server/chunks/2801.js +1 -1
  211. package/.next/server/chunks/3425.js +1 -1
  212. package/.next/server/chunks/4364.js +1 -1
  213. package/.next/server/chunks/460.js +1 -1
  214. package/.next/server/chunks/5761.js +1 -1
  215. package/.next/server/chunks/6056.js +1 -1
  216. package/.next/server/chunks/6343.js +3 -3
  217. package/.next/server/chunks/6823.js +1 -1
  218. package/.next/server/chunks/7019.js +2 -2
  219. package/.next/server/chunks/7348.js +1 -1
  220. package/.next/server/chunks/7504.js +1 -1
  221. package/.next/server/chunks/7535.js +2 -2
  222. package/.next/server/chunks/8923.js +1 -1
  223. package/.next/server/chunks/9018.js +1 -1
  224. package/.next/server/chunks/9250.js +1 -1
  225. package/.next/server/chunks/9429.js +1 -1
  226. package/.next/server/chunks/9646.js +1 -1
  227. package/.next/server/chunks/9817.js +67 -0
  228. package/.next/server/middleware-build-manifest.js +1 -1
  229. package/.next/server/middleware-react-loadable-manifest.js +1 -1
  230. package/.next/server/middleware.js +1 -1
  231. package/.next/server/pages/404.html +1 -1
  232. package/.next/server/pages/500.html +1 -1
  233. package/.next/server/server-reference-manifest.js +1 -1
  234. package/.next/server/server-reference-manifest.json +1 -1
  235. package/.next/static/chunks/{1278-605cc36f762c2ea7.js → 1278-efb46cc82262aa4e.js} +1 -1
  236. package/.next/static/chunks/{1471-69a7c30abf98c656.js → 1471-10f225f62f7469cc.js} +1 -1
  237. package/.next/static/chunks/{1699-49be310981e2759e.js → 1699-13ee6864a8a31a96.js} +2 -2
  238. package/.next/static/chunks/{1830-901fe48c3c62604f.js → 1830-d26d77c95932d7ce.js} +1 -1
  239. package/.next/static/chunks/1940.1f30124180f22498.js +1 -0
  240. package/.next/static/chunks/{2836-8e7f4c382297ac97.js → 2836-d97f0aa2718945d5.js} +1 -1
  241. package/.next/static/chunks/3445-99e12528f235cedb.js +1 -0
  242. package/.next/static/chunks/{3577-1f02993330d7fba7.js → 3577-cd98d40e3099e1b0.js} +1 -1
  243. package/.next/static/chunks/{5862-6f3a3a6d4c00100d.js → 5862-f98c2f3d480b80d2.js} +1 -1
  244. package/.next/static/chunks/6770-e2921b2ce695ed57.js +1 -0
  245. package/.next/static/chunks/7276-a15e4d56ec28aba8.js +1 -0
  246. package/.next/static/chunks/{9369-7ef21480b9132957.js → 9369-0d43b295968c2168.js} +1 -1
  247. package/.next/static/chunks/{9ce8c186-6cd204e9c27ecee1.js → 9ce8c186-3c7d7dbc5d428052.js} +1 -1
  248. package/.next/static/chunks/app/(dashboard)/dashboard/cli-tools/[toolId]/{page-9efe55fed2f7c81f.js → page-e8bceccb95695755.js} +2 -2
  249. package/.next/static/chunks/app/(dashboard)/dashboard/cli-tools/{page-9dcb29085167b384.js → page-adee408d9de02423.js} +1 -1
  250. package/.next/static/chunks/app/(dashboard)/dashboard/combos/{page-f5db9f681c6bface.js → page-d4c1e29e8d038f09.js} +1 -1
  251. package/.next/static/chunks/app/(dashboard)/dashboard/console-log/{page-d134cc313c9fa0b8.js → page-139200833f7a4ecc.js} +1 -1
  252. package/.next/static/chunks/app/(dashboard)/dashboard/endpoint/{page-f2d1a733e7f841cb.js → page-67516b120adbc4d7.js} +1 -1
  253. package/.next/static/chunks/app/(dashboard)/dashboard/media-providers/systemone/[id]/{page-0d6e623de6134598.js → page-b751d9603cb82e62.js} +1 -1
  254. package/.next/static/chunks/app/(dashboard)/dashboard/{page-e8f1d8be5e294fb0.js → page-315c9f52c472a700.js} +1 -1
  255. package/.next/static/chunks/app/(dashboard)/dashboard/providers/[id]/{page-c96cbcc4f5736e36.js → page-d5d480e209fdc55a.js} +1 -1
  256. package/.next/static/chunks/app/(dashboard)/dashboard/providers/new/{page-cc51346e464158b1.js → page-61b87a31ba21a055.js} +1 -1
  257. package/.next/static/chunks/app/(dashboard)/dashboard/providers/{page-1ee147fbe0693dc1.js → page-2396571281d02804.js} +1 -1
  258. package/.next/static/chunks/app/(dashboard)/dashboard/proxy-pools/{page-2287b1915fa887fc.js → page-cfd6bcb7e55d7d18.js} +2 -2
  259. package/.next/static/chunks/app/(dashboard)/dashboard/pxpipe/{page-696cb5c2703ca1ec.js → page-4d758f53c8cfc308.js} +1 -1
  260. package/.next/static/chunks/app/(dashboard)/dashboard/quota/{page-54a329d725734a1f.js → page-fef6edb7aafd8bd0.js} +1 -1
  261. package/.next/static/chunks/app/(dashboard)/dashboard/usage/{page-a81f78bb43042c30.js → page-697f46461825d7fc.js} +1 -1
  262. package/.next/static/chunks/app/(dashboard)/{layout-c199eb2ad56ae96a.js → layout-5039502fc12707c9.js} +1 -1
  263. package/.next/static/chunks/app/{layout-9bd5877ae6198856.js → layout-8810d4df3081b5df.js} +1 -1
  264. package/.next/static/chunks/webpack-cb89101193742e2b.js +1 -0
  265. package/CHANGELOG.md +19 -0
  266. package/open-sse/executors/zed.js +98 -5
  267. package/open-sse/handlers/chatCore/sseToJsonHandler.js +11 -4
  268. package/open-sse/providers/pricing.js +24 -10
  269. package/open-sse/services/usage/antigravity-weekly.js +10 -0
  270. package/open-sse/services/usage/claude.js +15 -0
  271. package/open-sse/shared/zedAuth.js +43 -2
  272. package/open-sse/translator/concerns/prefetch.js +12 -4
  273. package/open-sse/translator/response/claude-to-openai.js +2 -2
  274. package/open-sse/utils/streamHandler.js +1 -5
  275. package/package.json +1 -1
  276. package/src/app/(dashboard)/dashboard/providers/[id]/BulkImportGrokCliModal.tsx +1 -1
  277. package/src/app/(dashboard)/dashboard/providers/[id]/page.tsx +1 -1
  278. package/src/app/(dashboard)/dashboard/usage/components/ProviderTopology.tsx +5 -2
  279. package/src/app/api/combos/[id]/route.js +38 -1
  280. package/src/app/api/combos/route.js +27 -2
  281. package/src/app/api/providers/[id]/models/route.js +12 -1
  282. package/src/app/api/providers/route.js +4 -1
  283. package/src/app/api/usage/stream/route.js +74 -68
  284. package/src/app/api/v1/models/route.js +20 -6
  285. package/src/lib/db/index.js +3 -0
  286. package/src/lib/db/repos/settingsRepo.js +22 -1
  287. package/src/lib/oauth/services/xai.js +4 -4
  288. package/src/lib/validateComboModels.ts +48 -0
  289. package/src/shared/components/UsageStats.tsx +7 -1
  290. package/src/shared/hooks/useShutdown.ts +2 -4
  291. package/src/sse/handlers/chat.js +5 -1
  292. package/src/sse/services/antigravityQuota.ts +7 -3
  293. package/src/sse/services/model.ts +9 -20
  294. package/.next/server/chunks/5351.js +0 -67
  295. package/.next/static/chunks/3973-424848b943e2ecab.js +0 -1
  296. package/.next/static/chunks/7276-16ef14f7b2cd478d.js +0 -1
  297. package/.next/static/chunks/webpack-452a2f4aec1a53ee.js +0 -1
  298. /package/.next/static/{iz7psrsEuHZGPvj7rbSWc → awjDWqWCZbU3VVSuN7-oA}/_buildManifest.js +0 -0
  299. /package/.next/static/{iz7psrsEuHZGPvj7rbSWc → awjDWqWCZbU3VVSuN7-oA}/_ssgManifest.js +0 -0
@@ -1 +1 @@
1
- (self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[7177],{1352:(e,t,n)=>{"use strict";n.d(t,{Bc:()=>i,ZI:()=>l,k$:()=>s,m_:()=>d});var o=n(29798);n(15814);var r=n(5471),a=n(44484);function i({delayDuration:e=0,...t}){return(0,o.jsx)(a.Kq,{"data-slot":"tooltip-provider",delayDuration:e,...t})}function d({...e}){return(0,o.jsx)(a.bL,{"data-slot":"tooltip",...e})}function s({...e}){return(0,o.jsx)(a.l9,{"data-slot":"tooltip-trigger",...e})}function l({className:e,sideOffset:t=0,children:n,...i}){return(0,o.jsx)(a.ZL,{children:(0,o.jsxs)(a.UC,{"data-slot":"tooltip-content",sideOffset:t,className:(0,r.cn)("z-50 inline-flex w-fit max-w-xs origin-(--radix-tooltip-content-transform-origin) items-center gap-1.5 rounded-md bg-foreground px-3 py-1.5 text-xs text-background has-data-[slot=kbd]:pr-1.5 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 **:data-[slot=kbd]:relative **:data-[slot=kbd]:isolate **:data-[slot=kbd]:z-50 **:data-[slot=kbd]:rounded-sm data-[state=delayed-open]:animate-in data-[state=delayed-open]:fade-in-0 data-[state=delayed-open]:zoom-in-95 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",e),...i,children:[n,(0,o.jsx)(a.i3,{className:"z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px] bg-foreground fill-foreground"})]})})}},8872:(e,t,n)=>{Promise.resolve().then(n.bind(n,48565)),Promise.resolve().then(n.bind(n,1693)),Promise.resolve().then(n.bind(n,4780)),Promise.resolve().then(n.t.bind(n,52760,23)),Promise.resolve().then(n.t.bind(n,10414,23)),Promise.resolve().then(n.t.bind(n,65262,23)),Promise.resolve().then(n.t.bind(n,63185,23)),Promise.resolve().then(n.bind(n,84885)),Promise.resolve().then(n.bind(n,33526))},33526:(e,t,n)=>{"use strict";n.d(t,{ThemeProvider:()=>d});var o=n(29798),r=n(15814),a=n(88739),i=n(1352);function d({children:e}){let{initTheme:t}=(0,a.A)();return(0,r.useEffect)(()=>{t()},[t]),(0,o.jsx)(i.Bc,{children:e})}},51660:(e,t,n)=>{"use strict";n.d(t,{Q2:()=>o.Q2,fg:()=>o.fg,vQ:()=>r,_$:()=>i,MA:()=>o.MA,UY:()=>s,Nu:()=>a,zN:()=>o.zN,B2:()=>d});var o=n(13794);n(80159);let r={name:"10Router Proxy",description:"AI Infrastructure Management",version:"0.1.8"},a={changelogUrl:"/api/changelog"},i=20128,d={storageKey:"theme",defaultTheme:"light"},s={maxLines:500,pollIntervalMs:1e3}},51780:(e,t,n)=>{"use strict";n.d(t,{FE:()=>p,Tl:()=>u,kk:()=>c,oQ:()=>m,wn:()=>g});var o=n(66454);let r={},a=o.Xn,i=[];function d(){if("u"<typeof document)return o.Xn;let e=document.cookie.split(";").map(e=>e.trim()).find(e=>e.startsWith(`${o.CL}=`)),t=e?decodeURIComponent(e.split("=").slice(1).join("=")):o.Xn;return(0,o.QC)(t)}function s(e){"u">typeof document&&(document.documentElement.lang=e,document.documentElement.dir="fa"===e?"rtl":"ltr")}async function l(e){if("en"===e){r={};return}try{let t=await fetch(`/i18n/literals/${e}.json`);r=await t.json()}catch(e){console.error("Failed to load translations:",e),r={}}}function u(e){if(!e||"string"!=typeof e)return e;let t=e.trim();return t&&"en"!==a&&r[t]||e}function c(){return a}function m(e){return i.push(e),()=>{i=i.filter(t=>t!==e)}}function f(e){if(!e.nodeValue||!e.nodeValue.trim())return;let t=e.parentElement;if(!t)return;let n=t;for(;n;){if(n.hasAttribute&&n.hasAttribute("data-i18n-skip"))return;n=n.parentElement}if(["script","style","code","pre","colgroup","table","thead","tbody","tfoot","tr","select","datalist","optgroup"].includes(t.tagName?.toLowerCase()))return;e._originalText||(e._originalText=e.nodeValue);let o=u(e._originalText);o!==e.nodeValue&&(e.nodeValue=o)}function h(e){let t;if(!e)return;let n=document.createTreeWalker(e,NodeFilter.SHOW_TEXT,null),o=[];for(;t=n.nextNode();)o.push(t);o.forEach(f)}async function p(){s(a=d()),await l(a),h(document.body),new MutationObserver(e=>{e.forEach(e=>{e.addedNodes.forEach(e=>{e.nodeType===Node.ELEMENT_NODE?h(e):e.nodeType===Node.TEXT_NODE&&f(e)})})}).observe(document.body,{childList:!0,subtree:!0})}async function g(){s(a=d()),await l(a),i.forEach(e=>e()),h(document.body)}},63185:()=>{},66454:(e,t,n)=>{"use strict";n.d(t,{CL:()=>a,QC:()=>i,Xn:()=>r,YZ:()=>o});let o=["en","fa"],r="en",a="locale";function i(e){return"fa"===e?"fa":r}},84885:(e,t,n)=>{"use strict";n.d(t,{RuntimeI18nProvider:()=>d});var o=n(29798),r=n(15814),a=n(70782),i=n(51780);function d({children:e}){let t=(0,a.usePathname)();return(0,r.useEffect)(()=>{(0,i.FE)()},[]),(0,r.useEffect)(()=>{t&&requestAnimationFrame(()=>{requestAnimationFrame(()=>{(0,i.wn)()})})},[t]),(0,o.jsx)(o.Fragment,{children:e})}},88739:(e,t,n)=>{"use strict";n.d(t,{A:()=>d});var o=n(58013),r=n(47353),a=n(51660);function i(){document.documentElement.classList.remove("dark")}let d=(0,o.v)()((0,r.Zr)(e=>({theme:"light",setTheme:()=>{e({theme:"light"}),i()},toggleTheme:()=>{e({theme:"light"}),i()},initTheme:()=>{e({theme:"light"}),i()}}),{name:a.B2.storageKey}))}},e=>{e.O(0,[165,2262,5166,7552,9980,4484,7287,159,427,9966,7358],()=>e(e.s=8872)),_N_E=e.O()}]);
1
+ (self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[7177],{1352:(e,t,n)=>{"use strict";n.d(t,{Bc:()=>i,ZI:()=>l,k$:()=>s,m_:()=>d});var o=n(29798);n(15814);var r=n(5471),a=n(44484);function i({delayDuration:e=0,...t}){return(0,o.jsx)(a.Kq,{"data-slot":"tooltip-provider",delayDuration:e,...t})}function d({...e}){return(0,o.jsx)(a.bL,{"data-slot":"tooltip",...e})}function s({...e}){return(0,o.jsx)(a.l9,{"data-slot":"tooltip-trigger",...e})}function l({className:e,sideOffset:t=0,children:n,...i}){return(0,o.jsx)(a.ZL,{children:(0,o.jsxs)(a.UC,{"data-slot":"tooltip-content",sideOffset:t,className:(0,r.cn)("z-50 inline-flex w-fit max-w-xs origin-(--radix-tooltip-content-transform-origin) items-center gap-1.5 rounded-md bg-foreground px-3 py-1.5 text-xs text-background has-data-[slot=kbd]:pr-1.5 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 **:data-[slot=kbd]:relative **:data-[slot=kbd]:isolate **:data-[slot=kbd]:z-50 **:data-[slot=kbd]:rounded-sm data-[state=delayed-open]:animate-in data-[state=delayed-open]:fade-in-0 data-[state=delayed-open]:zoom-in-95 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",e),...i,children:[n,(0,o.jsx)(a.i3,{className:"z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px] bg-foreground fill-foreground"})]})})}},8872:(e,t,n)=>{Promise.resolve().then(n.bind(n,48565)),Promise.resolve().then(n.bind(n,1693)),Promise.resolve().then(n.bind(n,4780)),Promise.resolve().then(n.t.bind(n,52760,23)),Promise.resolve().then(n.t.bind(n,10414,23)),Promise.resolve().then(n.t.bind(n,65262,23)),Promise.resolve().then(n.t.bind(n,63185,23)),Promise.resolve().then(n.bind(n,84885)),Promise.resolve().then(n.bind(n,33526))},33526:(e,t,n)=>{"use strict";n.d(t,{ThemeProvider:()=>d});var o=n(29798),r=n(15814),a=n(88739),i=n(1352);function d({children:e}){let{initTheme:t}=(0,a.A)();return(0,r.useEffect)(()=>{t()},[t]),(0,o.jsx)(i.Bc,{children:e})}},51660:(e,t,n)=>{"use strict";n.d(t,{Q2:()=>o.Q2,fg:()=>o.fg,vQ:()=>r,_$:()=>i,MA:()=>o.MA,UY:()=>s,Nu:()=>a,zN:()=>o.zN,B2:()=>d});var o=n(13794);n(80159);let r={name:"10Router Proxy",description:"AI Infrastructure Management",version:"0.1.9"},a={changelogUrl:"/api/changelog"},i=20128,d={storageKey:"theme",defaultTheme:"light"},s={maxLines:500,pollIntervalMs:1e3}},51780:(e,t,n)=>{"use strict";n.d(t,{FE:()=>p,Tl:()=>u,kk:()=>c,oQ:()=>m,wn:()=>g});var o=n(66454);let r={},a=o.Xn,i=[];function d(){if("u"<typeof document)return o.Xn;let e=document.cookie.split(";").map(e=>e.trim()).find(e=>e.startsWith(`${o.CL}=`)),t=e?decodeURIComponent(e.split("=").slice(1).join("=")):o.Xn;return(0,o.QC)(t)}function s(e){"u">typeof document&&(document.documentElement.lang=e,document.documentElement.dir="fa"===e?"rtl":"ltr")}async function l(e){if("en"===e){r={};return}try{let t=await fetch(`/i18n/literals/${e}.json`);r=await t.json()}catch(e){console.error("Failed to load translations:",e),r={}}}function u(e){if(!e||"string"!=typeof e)return e;let t=e.trim();return t&&"en"!==a&&r[t]||e}function c(){return a}function m(e){return i.push(e),()=>{i=i.filter(t=>t!==e)}}function f(e){if(!e.nodeValue||!e.nodeValue.trim())return;let t=e.parentElement;if(!t)return;let n=t;for(;n;){if(n.hasAttribute&&n.hasAttribute("data-i18n-skip"))return;n=n.parentElement}if(["script","style","code","pre","colgroup","table","thead","tbody","tfoot","tr","select","datalist","optgroup"].includes(t.tagName?.toLowerCase()))return;e._originalText||(e._originalText=e.nodeValue);let o=u(e._originalText);o!==e.nodeValue&&(e.nodeValue=o)}function h(e){let t;if(!e)return;let n=document.createTreeWalker(e,NodeFilter.SHOW_TEXT,null),o=[];for(;t=n.nextNode();)o.push(t);o.forEach(f)}async function p(){s(a=d()),await l(a),h(document.body),new MutationObserver(e=>{e.forEach(e=>{e.addedNodes.forEach(e=>{e.nodeType===Node.ELEMENT_NODE?h(e):e.nodeType===Node.TEXT_NODE&&f(e)})})}).observe(document.body,{childList:!0,subtree:!0})}async function g(){s(a=d()),await l(a),i.forEach(e=>e()),h(document.body)}},63185:()=>{},66454:(e,t,n)=>{"use strict";n.d(t,{CL:()=>a,QC:()=>i,Xn:()=>r,YZ:()=>o});let o=["en","fa"],r="en",a="locale";function i(e){return"fa"===e?"fa":r}},84885:(e,t,n)=>{"use strict";n.d(t,{RuntimeI18nProvider:()=>d});var o=n(29798),r=n(15814),a=n(70782),i=n(51780);function d({children:e}){let t=(0,a.usePathname)();return(0,r.useEffect)(()=>{(0,i.FE)()},[]),(0,r.useEffect)(()=>{t&&requestAnimationFrame(()=>{requestAnimationFrame(()=>{(0,i.wn)()})})},[t]),(0,o.jsx)(o.Fragment,{children:e})}},88739:(e,t,n)=>{"use strict";n.d(t,{A:()=>d});var o=n(58013),r=n(47353),a=n(51660);function i(){document.documentElement.classList.remove("dark")}let d=(0,o.v)()((0,r.Zr)(e=>({theme:"light",setTheme:()=>{e({theme:"light"}),i()},toggleTheme:()=>{e({theme:"light"}),i()},initTheme:()=>{e({theme:"light"}),i()}}),{name:a.B2.storageKey}))}},e=>{e.O(0,[165,2262,5166,7552,9980,4484,7287,159,427,9966,7358],()=>e(e.s=8872)),_N_E=e.O()}]);
@@ -0,0 +1 @@
1
+ (()=>{"use strict";var e,t,r,o,n,a,i,l,s,u={},c={};function d(e){var t=c[e];if(void 0!==t)return t.exports;var r=c[e]={exports:{}},o=!0;try{u[e].call(r.exports,r,r.exports,d),o=!1}finally{o&&delete c[e]}return r.exports}d.m=u,e=[],d.O=(t,r,o,n)=>{if(r){n=n||0;for(var a=e.length;a>0&&e[a-1][2]>n;a--)e[a]=e[a-1];e[a]=[r,o,n];return}for(var i=1/0,a=0;a<e.length;a++){for(var[r,o,n]=e[a],l=!0,s=0;s<r.length;s++)(!1&n||i>=n)&&Object.keys(d.O).every(e=>d.O[e](r[s]))?r.splice(s--,1):(l=!1,n<i&&(i=n));if(l){e.splice(a--,1);var u=o();void 0!==u&&(t=u)}}return t},d.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return d.d(t,{a:t}),t},r=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,d.t=function(e,o){if(1&o&&(e=this(e)),8&o||"object"==typeof e&&e&&(4&o&&e.__esModule||16&o&&"function"==typeof e.then))return e;var n=Object.create(null);d.r(n);var a={};t=t||[null,r({}),r([]),r(r)];for(var i=2&o&&e;"object"==typeof i&&!~t.indexOf(i);i=r(i))Object.getOwnPropertyNames(i).forEach(t=>a[t]=()=>e[t]);return a.default=()=>e,d.d(n,a),n},d.d=(e,t)=>{for(var r in t)d.o(t,r)&&!d.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},d.f={},d.e=e=>Promise.all(Object.keys(d.f).reduce((t,r)=>(d.f[r](e,t),t),[])),d.u=e=>3445===e?"static/chunks/3445-99e12528f235cedb.js":7276===e?"static/chunks/7276-a15e4d56ec28aba8.js":"static/chunks/"+(6381===e?"80d4b624":e)+"."+({1940:"1f30124180f22498",4899:"0d4260af2a463837",6381:"42a8767f1c8767a3",7822:"01a4d5bdd39fa0b7"})[e]+".js",d.miniCssF=e=>"static/css/e07f2bf4fa519943.css",d.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||Function("return this")()}catch(e){if("object"==typeof window)return window}}(),d.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),o={},d.l=(e,t,r,n)=>{if(o[e])return void o[e].push(t);if(void 0!==r)for(var a,i,l=document.getElementsByTagName("script"),s=0;s<l.length;s++){var u=l[s];if(u.getAttribute("src")==e||u.getAttribute("data-webpack")=="_N_E:"+r){a=u;break}}a||(i=!0,(a=document.createElement("script")).charset="utf-8",a.timeout=120,d.nc&&a.setAttribute("nonce",d.nc),a.setAttribute("data-webpack","_N_E:"+r),a.src=d.tu(e)),o[e]=[t];var c=(t,r)=>{a.onerror=a.onload=null,clearTimeout(f);var n=o[e];if(delete o[e],a.parentNode&&a.parentNode.removeChild(a),n&&n.forEach(e=>e(r)),t)return t(r)},f=setTimeout(c.bind(null,void 0,{type:"timeout",target:a}),12e4);a.onerror=c.bind(null,a.onerror),a.onload=c.bind(null,a.onload),i&&document.head.appendChild(a)},d.r=e=>{"u">typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},d.tt=()=>(void 0===n&&(n={createScriptURL:e=>e},"u">typeof trustedTypes&&trustedTypes.createPolicy&&(n=trustedTypes.createPolicy("nextjs#bundler",n))),n),d.tu=e=>d.tt().createScriptURL(e),d.p="/_next/",a={8068:0},d.f.miniCss=(e,t)=>{if(a[e])t.push(a[e]);else 0!==a[e]&&({670:1})[e]&&t.push(a[e]=new Promise((t,r)=>{var o=d.miniCssF(e),n=d.p+o;if(((e,t)=>{for(var r=document.getElementsByTagName("link"),o=0;o<r.length;o++){var n=r[o],a=n.getAttribute("data-href")||n.getAttribute("href");if("stylesheet"===n.rel&&(a===e||a===t))return n}for(var i=document.getElementsByTagName("style"),o=0;o<i.length;o++){var n=i[o],a=n.getAttribute("data-href");if(a===e||a===t)return n}})(o,n))return t();((e,t,r,o)=>{var n=document.createElement("link");n.rel="stylesheet",n.type="text/css",n.onerror=n.onload=a=>{if(n.onerror=n.onload=null,"load"===a.type)r();else{var i=a&&("load"===a.type?"missing":a.type),l=a&&a.target&&a.target.href||t,s=Error("Loading CSS chunk "+e+" failed.\n("+l+")");s.code="CSS_CHUNK_LOAD_FAILED",s.type=i,s.request=l,n.parentNode.removeChild(n),o(s)}},n.href=t;if("function"==typeof _N_E_STYLE_LOAD){var a=n.href,i=n.onload,l=n.onerror;_N_E_STYLE_LOAD(0===a.indexOf(window.location.origin)?new URL(a).pathname:a).then(function(){i&&i.call(n,{type:"load"})},function(){l&&l.call(n,{})})}else document.head.appendChild(n)})(e,n,t,r)}).then(()=>{a[e]=0},t=>{throw delete a[e],t}))},i={8068:0,165:0,2262:0},d.f.j=(e,t)=>{var r=d.o(i,e)?i[e]:void 0;if(0!==r)if(r)t.push(r[2]);else if(/^(165|2262|670|8068)$/.test(e))i[e]=0;else{var o=new Promise((t,o)=>r=i[e]=[t,o]);t.push(r[2]=o);var n=d.p+d.u(e),a=Error();d.l(n,t=>{if(d.o(i,e)&&(0!==(r=i[e])&&(i[e]=void 0),r)){var o=t&&("load"===t.type?"missing":t.type),n=t&&t.target&&t.target.src;a.message="Loading chunk "+e+" failed.\n("+o+": "+n+")",a.name="ChunkLoadError",a.type=o,a.request=n,r[1](a)}},"chunk-"+e,e)}},d.O.j=e=>0===i[e],l=(e,t)=>{var r,o,[n,a,l]=t,s=0;if(n.some(e=>0!==i[e])){for(r in a)d.o(a,r)&&(d.m[r]=a[r]);if(l)var u=l(d)}for(e&&e(t);s<n.length;s++)o=n[s],d.o(i,o)&&i[o]&&i[o][0](),i[o]=0;return d.O(u)},(s=self.webpackChunk_N_E=self.webpackChunk_N_E||[]).forEach(l.bind(null,0)),s.push=l.bind(null,s.push.bind(s)),d.nc=void 0})();
package/CHANGELOG.md CHANGED
@@ -2,6 +2,25 @@
2
2
 
3
3
  All notable changes to 10Router will be documented in this file.
4
4
 
5
+ ## [0.1.9] — 2026-10-17
6
+
7
+ - Zed: detect context-window overflow reported as an in-stream `status:failed` frame and return it as a request-scoped `400 context_length_exceeded` instead of assistant text — the account is no longer cooled down by the fallback layer. History is trimmed to the model's catalog limit before sending, and a pre-send guard fails fast when even the trimmed body does not fit.
8
+ - Zed: retry transient network failures (`ECONNRESET`/`ETIMEDOUT`) on auth and completion fetches using the shared 502 retry config; caller aborts are never retried.
9
+ - Combos: validate members on create/update (`POST`/`PUT /api/combos`) — bare words from a bad paste, duplicates, self-references, and unknown names are rejected at save time with a message naming the offending entries, instead of failing every run at request time.
10
+ - Zed: model-list and usage resolvers now honour the connection's proxy pool instead of falling back to a direct call.
11
+ - Claude → OpenAI: stop emitting literal `<think>`/`</think>` markers into `delta.content` — thinking text streams as `reasoning_content` only.
12
+ - Fix: opencode model-list URL for Anthropic-compatible providers built `.../v1/messag` (`slice(0, -9)` ate a character); now sliced by `"/messages".length`.
13
+ - Fix: xAI OAuth poll interval was never cleared on the 5-minute auth timeout, leaking a 100 ms timer.
14
+ - Fix: `useShutdown` called `setState` inside an effect (cascading render); the transition now happens where the poll completes.
15
+ - Perf: `/api/usage/stream` ran the full usage-stats recompute once per open tab per event; all subscribers now share one cache and one in-flight recompute, so N tabs cost the same as one.
16
+ - Perf: `matchPattern` recompiled a `RegExp` on every call inside ~100-entry pricing/capability loops; patterns are now memoized.
17
+ - Perf: settings were read from the DB and re-merged against ~40 defaults three times per chat request; added a short-TTL cache with write invalidation.
18
+ - Perf: remote-image prefetch for base64-only targets now fetches in parallel instead of serially in the pre-first-byte path.
19
+ - Perf: custom provider-node prefix resolution did three identical type-filtered table scans per request; now one scan.
20
+ - Fix: token-keyed Claude/Antigravity usage caches never evicted retired tokens; added unref'd sweepers.
21
+ - Fix: silently swallowed failures now log — background projectId persistence and provider-node name lookup.
22
+ - Types: resolved 11 pre-existing `tsc --noEmit` errors under `src/` (stale generated `.next/types` route-tag warnings remain, covered by `ignoreBuildErrors`).
23
+
5
24
  ## [0.1.8] — 2026-10-15
6
25
 
7
26
  - Deps: drop `better-sqlite3` — fixes `npm i -g` install-script warning (`allowScripts`) and the deprecated `prebuild-install` warning. DB chain is now built-in `node:sqlite` (≥22.5) → `sql.js` (WASM fallback); the adapter loads `better-sqlite3` lazily as a manual opt-in only, so the Next.js build no longer resolves it.
@@ -24,6 +24,8 @@ import { claudeToOpenAIResponse } from "../translator/response/claude-to-openai.
24
24
  import { geminiToOpenAIResponse } from "../translator/response/gemini-to-openai.js";
25
25
  import { openaiResponsesToOpenAIResponse } from "../translator/response/openai-responses.js";
26
26
  import { ZED_HEADERS, resolveZedModels, zedLlmFetch } from "../shared/zedAuth.js";
27
+ import { estimateInputTokens } from "../utils/usageTracking.js";
28
+ import { stripHistoryForContext } from "../services/capacityAdapter.js";
27
29
 
28
30
  // Wire values for the `provider` field of POST /completions. These are NOT
29
31
  // display names: cloud.zed.dev matches them exactly, and an unrecognized value
@@ -139,6 +141,29 @@ function normalizeStatus(status) {
139
141
  return null;
140
142
  }
141
143
 
144
+ // Zed reports context overflow inside a `status:failed` frame on an HTTP-200
145
+ // stream (and occasionally as a non-200 body) — never as a typed API error.
146
+ // Detect it by wording so both paths below can treat it as request-scoped.
147
+ const OVERFLOW_RE =
148
+ /context_length_exceeded|\bcontext\b.*\b(window|length|limit)\b|exceeds.*token|too many tokens|prompt (is )?too long|maximum.*token/i;
149
+
150
+ function isContextOverflowText(value) {
151
+ return OVERFLOW_RE.test(String(value || ""));
152
+ }
153
+
154
+ // SSE error frame in the shared buildErrorBody shape ({error:{message,type,
155
+ // code}}) so stream aggregation and clients treat it as a failure, not as
156
+ // assistant text. Never a fabricated finish_reason.
157
+ function createOverflowErrorFrame(message) {
158
+ return `data: ${JSON.stringify({
159
+ error: {
160
+ message,
161
+ type: "invalid_request_error",
162
+ code: "context_length_exceeded",
163
+ },
164
+ })}\n\n`;
165
+ }
166
+
142
167
  function wrapZedCompletionStream(response, provider, model) {
143
168
  if (!response.ok || !response.body) return response;
144
169
 
@@ -169,8 +194,24 @@ function wrapZedCompletionStream(response, provider, model) {
169
194
  if (status?.type === "failed" || status?.failed) {
170
195
  const failed = status.failed || status;
171
196
  const message = String(failed.message || failed.error || failed.code || "request failed");
172
- enqueueSseObject(controller, encoder, createErrorChunk(model, message));
173
- finish(controller);
197
+ // Context overflow must be a clean error, not assistant text:
198
+ // clients aggregate delta.content into the answer, and the fallback
199
+ // layer keys off status — so emit the error frame + [DONE] with no
200
+ // fabricated finish_reason, and skip the trailing translate flush.
201
+ if (isContextOverflowText(message)) {
202
+ controller.enqueue(
203
+ encoder.encode(
204
+ createOverflowErrorFrame(
205
+ `Context window exceeded for ${model}: ${message}. ` +
206
+ `Shorten the conversation or use a larger model.`,
207
+ ) + "data: [DONE]\n\n",
208
+ ),
209
+ );
210
+ done = true;
211
+ } else {
212
+ enqueueSseObject(controller, encoder, createErrorChunk(model, message));
213
+ finish(controller);
214
+ }
174
215
  } else if (status?.type === "stream_ended" || status === "stream_ended") {
175
216
  finish(controller);
176
217
  }
@@ -243,9 +284,52 @@ class ZedExecutor extends BaseExecutor {
243
284
  }
244
285
 
245
286
  async execute({ model, body, stream, credentials, signal, log, proxyOptions = null }) {
246
- const { provider } = await this.resolveModel(model, credentials, signal, log, proxyOptions);
247
- const providerRequest = buildProviderRequest(provider, model, body, stream, credentials);
248
- const bodyRecord = body || {};
287
+ const { raw, provider } = await this.resolveModel(
288
+ model,
289
+ credentials,
290
+ signal,
291
+ log,
292
+ proxyOptions,
293
+ );
294
+ let requestBody = body || {};
295
+ // Pre-send context guard: Zed reports overflow as an in-stream
296
+ // `status:failed` frame (HTTP 200 already sent), which can only surface
297
+ // as assistant text — never as a clean error. Trim history to the
298
+ // catalog window first; fail fast with 400 (request-scoped, no account
299
+ // lock) when even the trimmed body doesn't fit.
300
+ const contextLimit = Number(raw?.max_token_count ?? raw?.maxTokenCount) || null;
301
+ if (contextLimit) {
302
+ if (estimateInputTokens(requestBody) > contextLimit) {
303
+ const trimmed = stripHistoryForContext(requestBody, contextLimit);
304
+ if (trimmed !== requestBody) {
305
+ log?.info?.("ZED", `trimmed history for ${model} to fit ${contextLimit} tokens`);
306
+ requestBody = trimmed;
307
+ }
308
+ }
309
+ const estimated = estimateInputTokens(requestBody);
310
+ if (estimated > contextLimit) {
311
+ const message =
312
+ `Context window exceeded: ~${estimated} tokens exceeds the limit of ` +
313
+ `${contextLimit} tokens for ${model}. Shorten the conversation or use a larger model.`;
314
+ return {
315
+ response: new Response(
316
+ JSON.stringify({
317
+ error: {
318
+ message,
319
+ type: "invalid_request_error",
320
+ code: "context_length_exceeded",
321
+ },
322
+ }),
323
+ { status: 400, headers: { "Content-Type": "application/json" } },
324
+ ),
325
+ url: `${this.config?.llmBaseUrl || "https://cloud.zed.dev"}/completions`,
326
+ headers: { "Content-Type": "application/json", Authorization: "Bearer <zed-llm-token>" },
327
+ transformedBody: { model, estimatedInputTokens: estimated, contextLimit },
328
+ };
329
+ }
330
+ }
331
+ const providerRequest = buildProviderRequest(provider, model, requestBody, stream, credentials);
332
+ const bodyRecord = requestBody;
249
333
  const payload = {
250
334
  thread_id: bodyRecord.thread_id || credentials?._clientSessionId,
251
335
  prompt_id: bodyRecord.prompt_id,
@@ -292,6 +376,15 @@ class ZedExecutor extends BaseExecutor {
292
376
  const errorObj = parsed?.error || undefined;
293
377
  const code = parsed?.code || errorObj?.code || "";
294
378
  const rawMessage = parsed?.message || errorObj?.message || bodyText || response.statusText;
379
+ // Overflow is request-scoped: return it as-is (no proxy/lock guidance, no
380
+ // retry wording) so the fallback layer hands it back without cooling the
381
+ // account. checkFallbackError already treats non-quota 400s this way.
382
+ if (code === "context_length_exceeded" || isContextOverflowText(rawMessage)) {
383
+ return {
384
+ status: 400,
385
+ message: `Context window exceeded for this request: ${rawMessage}. Shorten the conversation or use a larger model.`,
386
+ };
387
+ }
295
388
  if (code === "trial_blocked") {
296
389
  return {
297
390
  status: response.status,
@@ -413,10 +413,17 @@ export async function handleForcedSSEToJson({
413
413
  "Invalid SSE response for non-streaming request",
414
414
  );
415
415
  if (parsed.error) {
416
- return createErrorResult(
417
- HTTP_STATUS.BAD_GATEWAY,
418
- parsed.error.message || "Upstream SSE stream failed",
419
- );
416
+ // Request-scoped errors (e.g. Zed context_length_exceeded, surfaced as an
417
+ // in-stream error frame) keep their own status: 400 must not cool the
418
+ // account via the fallback layer, and must reach the client as 400.
419
+ const upstreamCode = String(parsed.error.code || "");
420
+ const status =
421
+ parsed.error.type === "invalid_request_error" ||
422
+ upstreamCode === "context_length_exceeded" ||
423
+ upstreamCode === "bad_request"
424
+ ? HTTP_STATUS.BAD_REQUEST
425
+ : HTTP_STATUS.BAD_GATEWAY;
426
+ return createErrorResult(status, parsed.error.message || "Upstream SSE stream failed");
420
427
  }
421
428
 
422
429
  if (onRequestSuccess) await onRequestSuccess();
@@ -1099,18 +1099,32 @@ export const PATTERN_PRICING = [
1099
1099
  /**
1100
1100
  * Match a model ID against a glob pattern (* = wildcard). Case-insensitive:
1101
1101
  * registry ids mix casing (e.g. "MiniMax-M2.5" vs "minimax-m2.5").
1102
+ *
1103
+ * Patterns are a fixed config table, so the compiled RegExp is memoized:
1104
+ * callers loop over ~100 patterns, and this used to recompile every one of
1105
+ * them on each call (several times per request).
1102
1106
  */
1107
+ const PATTERN_REGEX_CACHE = new Map();
1108
+
1109
+ function patternRegex(pattern) {
1110
+ let regex = PATTERN_REGEX_CACHE.get(pattern);
1111
+ if (!regex) {
1112
+ regex = new RegExp(
1113
+ "^" +
1114
+ pattern
1115
+ .split("*")
1116
+ .map((s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"))
1117
+ .join(".*") +
1118
+ "$",
1119
+ "i",
1120
+ );
1121
+ PATTERN_REGEX_CACHE.set(pattern, regex);
1122
+ }
1123
+ return regex;
1124
+ }
1125
+
1103
1126
  export function matchPattern(pattern, model) {
1104
- const regex = new RegExp(
1105
- "^" +
1106
- pattern
1107
- .split("*")
1108
- .map((s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"))
1109
- .join(".*") +
1110
- "$",
1111
- "i",
1112
- );
1113
- return regex.test(model);
1127
+ return patternRegex(pattern).test(model);
1114
1128
  }
1115
1129
 
1116
1130
  /**
@@ -16,6 +16,16 @@ const WEEKLY_CONFIG = {
16
16
  const WEEKLY_CACHE_TTL_MS = 180_000; // 3 minutes
17
17
  const weeklyCache = new Map(); // cacheKey -> { result, expiresAt } | { promise }
18
18
 
19
+ // Keys embed the access token, which rotates. Expiry is only read-checked, so
20
+ // retired tokens would accumulate — sweep on a slow unref'd timer.
21
+ setInterval(() => {
22
+ const now = Date.now();
23
+ for (const [key, hit] of weeklyCache) {
24
+ if (hit?.promise) continue; // in-flight
25
+ if (!hit || hit.expiresAt <= now) weeklyCache.delete(key);
26
+ }
27
+ }, WEEKLY_CACHE_TTL_MS).unref?.();
28
+
19
29
  function cacheKey(accessToken, projectId) {
20
30
  return `${accessToken}::${projectId || ""}`;
21
31
  }
@@ -24,6 +24,21 @@ const oauthCooldown = new Map();
24
24
  const USAGE_CACHE_TTL_MS = 300000;
25
25
  const usageCache = new Map(); // token -> { promise } | { result, expiresAt }
26
26
 
27
+ // Both maps are keyed by access token, which rotates. Expiry is only checked on
28
+ // read, so entries for retired tokens would live forever — sweep them on a slow
29
+ // timer (unref'd so it never holds the process open).
30
+ function sweepExpired() {
31
+ const now = Date.now();
32
+ for (const [token, hit] of usageCache) {
33
+ if (hit?.promise) continue; // in-flight
34
+ if (!hit || hit.expiresAt <= now) usageCache.delete(token);
35
+ }
36
+ for (const [token, until] of oauthCooldown) {
37
+ if (until <= now) oauthCooldown.delete(token);
38
+ }
39
+ }
40
+ setInterval(sweepExpired, USAGE_CACHE_TTL_MS).unref?.();
41
+
27
42
  export async function getClaudeUsage(accessToken, proxyOptions = null, options = {}) {
28
43
  const force = options?.force === true;
29
44
 
@@ -11,6 +11,7 @@
11
11
 
12
12
  import crypto from "node:crypto";
13
13
  import { proxyAwareFetch } from "../utils/proxyFetch.js";
14
+ import { DEFAULT_RETRY_CONFIG, resolveRetryEntry } from "../config/runtimeConfig.js";
14
15
 
15
16
  export const ZED_WEB_BASE_URL = "https://zed.dev";
16
17
  export const ZED_CLOUD_BASE_URL = "https://cloud.zed.dev";
@@ -179,8 +180,48 @@ function getSystemId(credentials) {
179
180
  return String(credentials?.providerSpecificData?.systemId || credentials?.systemId || "");
180
181
  }
181
182
 
183
+ function sleep(ms) {
184
+ return new Promise((resolve) => setTimeout(resolve, ms));
185
+ }
186
+
187
+ // Transient socket failures (ECONNRESET/ETIMEDOUT/socket hang up via relay or
188
+ // direct) surface as thrown TypeErrors from fetch. Retry those with the same
189
+ // 502-config the BaseExecutor pipeline uses. Anything else — including caller
190
+ // aborts and permanent failures (ENOTFOUND, bad TLS, 5xx bodies that resolve
191
+ // normally) — is rethrown immediately: retrying it only adds delay to an
192
+ // outcome that cannot change.
193
+ const TRANSIENT_NET_CODES = new Set([
194
+ "ECONNRESET",
195
+ "ECONNREFUSED",
196
+ "ETIMEDOUT",
197
+ "EPIPE",
198
+ "EAI_AGAIN",
199
+ "UND_ERR_SOCKET",
200
+ ]);
201
+
202
+ function isTransientNetError(error) {
203
+ if (!error || error.name === "AbortError") return false;
204
+ const code = error.code || error.cause?.code;
205
+ if (code && TRANSIENT_NET_CODES.has(code)) return true;
206
+ // Node's undici raises a bare TypeError("fetch failed") / "socket hang up"
207
+ // for relay-side resets, so the message is the only signal available.
208
+ return /socket hang up|ECONNRESET|other side closed/i.test(String(error.message || ""));
209
+ }
210
+
211
+ async function zedFetchWithRetry(url, options, proxyOptions = null, statusKey = 502) {
212
+ const { attempts, delayMs } = resolveRetryEntry(DEFAULT_RETRY_CONFIG[statusKey]);
213
+ for (let attempt = 0; ; attempt++) {
214
+ try {
215
+ return await proxyAwareFetch(url, options, proxyOptions);
216
+ } catch (error) {
217
+ if (!isTransientNetError(error) || attempt >= attempts) throw error;
218
+ await sleep(delayMs);
219
+ }
220
+ }
221
+ }
222
+
182
223
  async function fetchJson(url, options, proxyOptions = null) {
183
- const res = await proxyAwareFetch(url, options, proxyOptions);
224
+ const res = await zedFetchWithRetry(url, options, proxyOptions);
184
225
  const text = await res.text();
185
226
  let data = null;
186
227
  if (text) {
@@ -309,7 +350,7 @@ export async function zedLlmFetch(credentials, path, options = {}) {
309
350
  const url = zedUrl(config, "llmBaseUrl", path, ZED_LLM_BASE_URL);
310
351
  const buildRequest = async (forceRefresh) => {
311
352
  const token = await fetchZedLlmToken(credentials, { ...options, forceRefresh });
312
- return proxyAwareFetch(
353
+ return zedFetchWithRetry(
313
354
  url,
314
355
  {
315
356
  ...options.fetchOptions,
@@ -89,11 +89,19 @@ export async function prefetchRemoteImages(body, sourceFormat, targetFormat, opt
89
89
  const refs = collectImageRefs(body, sourceFormat);
90
90
  if (!refs.length) return 0;
91
91
 
92
+ // Fetch in parallel: this runs in the pre-first-byte path, and serial
93
+ // round trips made N images cost N × latency. Per-ref failure is already
94
+ // fail-open, so allSettled preserves existing behaviour.
95
+ const fetchedList = await Promise.all(
96
+ refs.map(async (ref) => {
97
+ const url = ref.get();
98
+ if (parseDataUri(url)) return { ref, fetched: null };
99
+ return { ref, fetched: await fetchImageAsBase64(url, options) };
100
+ }),
101
+ );
102
+
92
103
  let converted = 0;
93
- for (const ref of refs) {
94
- const url = ref.get();
95
- if (parseDataUri(url)) continue; // already inline
96
- const fetched = await fetchImageAsBase64(url, options);
104
+ for (const { ref, fetched } of fetchedList) {
97
105
  if (!fetched) continue;
98
106
  if (ref.set) ref.set(fetched.url);
99
107
  else if (ref.part) {
@@ -71,9 +71,10 @@ export function claudeToOpenAIResponse(chunk, state) {
71
71
  if (block?.type === CLAUDE_BLOCK.TEXT) {
72
72
  state.textBlockStarted = true;
73
73
  } else if (block?.type === CLAUDE_BLOCK.THINKING) {
74
+ // Thinking text streams as `reasoning_content` below; no literal tag is
75
+ // emitted into `content` — clients render that as part of the answer.
74
76
  state.inThinkingBlock = true;
75
77
  state.currentBlockIndex = chunk.index;
76
- results.push(createChunk(state, { content: "<think>" }));
77
78
  } else if (block?.type === CLAUDE_BLOCK.TOOL_USE) {
78
79
  const toolCallIndex = state.toolCallIndex++;
79
80
  // Restore original tool name from mapping (Claude OAuth)
@@ -128,7 +129,6 @@ export function claudeToOpenAIResponse(chunk, state) {
128
129
  break;
129
130
  }
130
131
  if (state.inThinkingBlock && chunk.index === state.currentBlockIndex) {
131
- results.push(createChunk(state, { content: "</think>" }));
132
132
  state.inThinkingBlock = false;
133
133
  }
134
134
  state.textBlockStarted = false;
@@ -94,11 +94,7 @@ export function createStreamController({
94
94
  return;
95
95
  }
96
96
 
97
- logStream(
98
- "ERROR",
99
- `ERROR: ${error.message}${error.stack ? `\n ${error.stack}` : ""}`,
100
- true,
101
- );
97
+ logStream("ERROR", `${error.message}${error.stack ? `\n ${error.stack}` : ""}`, true);
102
98
  onError?.(error);
103
99
  },
104
100
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@amir83nasr/10router",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/Amir83Nasr/10Router.git"
@@ -76,7 +76,7 @@ export default function BulkImportGrokCliModal({ isOpen, onClose, onSuccess }: a
76
76
  const processFiles = async (files: any) => {
77
77
  if (!files || files.length === 0) return;
78
78
  setParseError("");
79
- const jsonFiles: any[] = Array.from(files).filter(
79
+ const jsonFiles: File[] = Array.from(files as FileList).filter(
80
80
  (file) => file.name.endsWith(".json") || file.type === "application/json" || file.type === "",
81
81
  );
82
82
 
@@ -556,7 +556,7 @@ export default function ProviderDetailPage() {
556
556
  modelId,
557
557
  type = "llm",
558
558
  providerAliasOverride = providerStorageAlias,
559
- caps,
559
+ caps?: unknown,
560
560
  ) => {
561
561
  try {
562
562
  const res = await fetch("/api/models/custom", {
@@ -423,12 +423,15 @@ export default function ProviderTopology({
423
423
  const lastKey = lastProvider?.toLowerCase() || "";
424
424
  const errorKey = errorProvider?.toLowerCase() || "";
425
425
 
426
- const rawActiveSet = useMemo(() => new Set(activeKey ? activeKey.split(",") : []), [activeKey]);
426
+ const rawActiveSet = useMemo(
427
+ () => new Set<string>(activeKey ? activeKey.split(",") : []),
428
+ [activeKey],
429
+ );
427
430
  const lastSet = useMemo(() => new Set(lastKey ? [lastKey] : []), [lastKey]);
428
431
  const errorSet = useMemo(() => new Set(errorKey ? [errorKey] : []), [errorKey]);
429
432
 
430
433
  // Track firstSeen per active provider; drop provider if running too long (BE stuck)
431
- const firstSeenRef = useRef({});
434
+ const firstSeenRef = useRef<Record<string, number>>({});
432
435
  const [tick, setTick] = useState<number>(0);
433
436
 
434
437
  useEffect(() => {
@@ -1,6 +1,14 @@
1
1
  import { NextResponse } from "next/server";
2
- import { getComboById, updateCombo, deleteCombo, getComboByName } from "@/lib/localDb";
2
+ import {
3
+ getComboById,
4
+ updateCombo,
5
+ deleteCombo,
6
+ getComboByName,
7
+ getCombos,
8
+ getModelAliases,
9
+ } from "@/lib/localDb";
3
10
  import { resetComboRotation } from "open-sse/services/combo.js";
11
+ import { findComboMemberProblems } from "@/lib/validateComboModels";
4
12
 
5
13
  // Validate combo name: only a-z, A-Z, 0-9, -, _
6
14
  const VALID_NAME_REGEX = /^[a-zA-Z0-9_.\-]+$/;
@@ -46,6 +54,35 @@ export async function PUT(request, { params }) {
46
54
 
47
55
  // Capture previous name to invalidate rotation state on rename
48
56
  const prev = await getComboById(id);
57
+ if (!prev) {
58
+ return NextResponse.json({ error: "Combo not found" }, { status: 404 });
59
+ }
60
+
61
+ // Same member validation as POST (see validateComboModels.ts).
62
+ if (body.models !== undefined) {
63
+ const [aliases, combos] = await Promise.all([getModelAliases(), getCombos()]);
64
+ const cleanedModels = Array.isArray(body.models)
65
+ ? [
66
+ ...new Set(
67
+ body.models.map((m) => (typeof m === "string" ? m.trim() : "")).filter(Boolean),
68
+ ),
69
+ ]
70
+ : [];
71
+ const problems = findComboMemberProblems(cleanedModels, {
72
+ aliases,
73
+ comboNames: combos.filter((c) => c.id !== id).map((c) => c.name),
74
+ selfName: body.name || prev.name,
75
+ });
76
+ if (!Array.isArray(body.models) || problems.length > 0) {
77
+ return NextResponse.json(
78
+ {
79
+ error: `Invalid combo models: ${!Array.isArray(body.models) ? "models must be an array" : problems.join("; ")}`,
80
+ },
81
+ { status: 400 },
82
+ );
83
+ }
84
+ body = { ...body, models: cleanedModels };
85
+ }
49
86
  const combo = await updateCombo(id, body);
50
87
 
51
88
  if (!combo) {
@@ -1,5 +1,6 @@
1
1
  import { NextResponse } from "next/server";
2
- import { getCombos, createCombo, getComboByName } from "@/lib/localDb";
2
+ import { getCombos, createCombo, getComboByName, getModelAliases } from "@/lib/localDb";
3
+ import { findComboMemberProblems } from "@/lib/validateComboModels";
3
4
 
4
5
  export const dynamic = "force-dynamic";
5
6
 
@@ -41,7 +42,31 @@ export async function POST(request) {
41
42
  return NextResponse.json({ error: "Combo name already exists" }, { status: 400 });
42
43
  }
43
44
 
44
- const combo = await createCombo({ name, models: models || [], kind: kind || null });
45
+ // Validate members: bare words ("Support", "Last") die at request time
46
+ // with "Invalid model format", so reject them at save time instead.
47
+ const [aliases, combos] = await Promise.all([getModelAliases(), getCombos()]);
48
+ if (models !== undefined && !Array.isArray(models)) {
49
+ return NextResponse.json(
50
+ { error: "Invalid combo models: models must be an array" },
51
+ { status: 400 },
52
+ );
53
+ }
54
+ const cleanedModels = Array.isArray(models)
55
+ ? [...new Set(models.map((m) => (typeof m === "string" ? m.trim() : "")).filter(Boolean))]
56
+ : [];
57
+ const problems = findComboMemberProblems(cleanedModels, {
58
+ aliases,
59
+ comboNames: combos.map((c) => c.name),
60
+ selfName: name,
61
+ });
62
+ if (problems.length > 0) {
63
+ return NextResponse.json(
64
+ { error: `Invalid combo models: ${problems.join("; ")}` },
65
+ { status: 400 },
66
+ );
67
+ }
68
+
69
+ const combo = await createCombo({ name, models: cleanedModels, kind: kind || null });
45
70
 
46
71
  return NextResponse.json(combo, { status: 201 });
47
72
  } catch (error) {
@@ -285,12 +285,23 @@ const PROVIDER_MODELS_CONFIG = {
285
285
  zed: {
286
286
  customResolver: async (connection) => {
287
287
  try {
288
+ const proxy = await resolveConnectionProxyConfig(connection.providerSpecificData || {});
288
289
  const result = await resolveZedModels(
289
290
  {
290
291
  accessToken: connection.accessToken,
291
292
  providerSpecificData: connection.providerSpecificData || {},
292
293
  },
293
- { config: ZED_HOSTED_CONFIG, forceRefresh: true },
294
+ {
295
+ config: ZED_HOSTED_CONFIG,
296
+ forceRefresh: true,
297
+ proxyOptions: {
298
+ connectionProxyEnabled: proxy.connectionProxyEnabled === true,
299
+ connectionProxyUrl: proxy.connectionProxyUrl || "",
300
+ connectionNoProxy: proxy.connectionNoProxy || "",
301
+ vercelRelayUrl: proxy.vercelRelayUrl || "",
302
+ strictProxy: proxy.strictProxy === true,
303
+ },
304
+ },
294
305
  );
295
306
  const models = (result?.models || [])
296
307
  .filter((m) => m && !m.isDisabled)
@@ -70,7 +70,10 @@ export async function GET() {
70
70
  for (const node of nodes) {
71
71
  if (node.id && node.name) nodeNameMap[node.id] = node.name;
72
72
  }
73
- } catch {}
73
+ } catch (err) {
74
+ // Non-fatal: names degrade to raw provider ids, but stay visible.
75
+ console.warn("Failed to load provider nodes for name map:", err);
76
+ }
74
77
 
75
78
  // Hide sensitive fields, enrich name for compatible providers
76
79
  const safeConnections = connections.map((c) => {