wyxrouter 0.4.71

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 (763) hide show
  1. package/CHANGELOG.md +222 -0
  2. package/LICENSE +21 -0
  3. package/README.md +96 -0
  4. package/README.zh-CN.md +1311 -0
  5. package/assets/pixel-router-2d.png +0 -0
  6. package/cli/LICENSE +42 -0
  7. package/cli/README.md +125 -0
  8. package/cli/app/package.json +58 -0
  9. package/cli/cli.js +806 -0
  10. package/cli/package.json +48 -0
  11. package/i18n/README.ja-JP.md +1209 -0
  12. package/i18n/README.ru.md +1311 -0
  13. package/i18n/README.vi.md +1310 -0
  14. package/i18n/README.zh-CN.md +1306 -0
  15. package/images/9router.png +0 -0
  16. package/jsconfig.json +12 -0
  17. package/next.config.mjs +71 -0
  18. package/open-sse/config/appConstants.js +203 -0
  19. package/open-sse/config/codexInstructions.js +119 -0
  20. package/open-sse/config/constants.js +4 -0
  21. package/open-sse/config/defaultThinkingSignature.js +12 -0
  22. package/open-sse/config/errorConfig.js +85 -0
  23. package/open-sse/config/googleTtsLanguages.js +62 -0
  24. package/open-sse/config/kiroConstants.js +322 -0
  25. package/open-sse/config/models.js +13 -0
  26. package/open-sse/config/ollamaModels.js +19 -0
  27. package/open-sse/config/providerModels.js +944 -0
  28. package/open-sse/config/providers.js +458 -0
  29. package/open-sse/config/runtimeConfig.js +72 -0
  30. package/open-sse/config/ttsModels.js +129 -0
  31. package/open-sse/executors/antigravity.js +504 -0
  32. package/open-sse/executors/azure.js +57 -0
  33. package/open-sse/executors/base.js +185 -0
  34. package/open-sse/executors/codex.js +469 -0
  35. package/open-sse/executors/commandcode.js +88 -0
  36. package/open-sse/executors/cursor.js +795 -0
  37. package/open-sse/executors/default.js +497 -0
  38. package/open-sse/executors/gemini-cli.js +89 -0
  39. package/open-sse/executors/github.js +379 -0
  40. package/open-sse/executors/grok-web.js +345 -0
  41. package/open-sse/executors/iflow.js +108 -0
  42. package/open-sse/executors/index.js +75 -0
  43. package/open-sse/executors/kiro.js +508 -0
  44. package/open-sse/executors/ollama-local.js +14 -0
  45. package/open-sse/executors/opencode-go.js +41 -0
  46. package/open-sse/executors/opencode.js +32 -0
  47. package/open-sse/executors/perplexity-web.js +507 -0
  48. package/open-sse/executors/qoder.js +450 -0
  49. package/open-sse/executors/qwen.js +129 -0
  50. package/open-sse/executors/vertex.js +131 -0
  51. package/open-sse/executors/xiaomi-tokenplan.js +19 -0
  52. package/open-sse/handlers/chatCore/nonStreamingHandler.js +230 -0
  53. package/open-sse/handlers/chatCore/requestDetail.js +102 -0
  54. package/open-sse/handlers/chatCore/sseToJsonHandler.js +231 -0
  55. package/open-sse/handlers/chatCore/streamingHandler.js +103 -0
  56. package/open-sse/handlers/chatCore.js +287 -0
  57. package/open-sse/handlers/embeddingProviders/_base.js +4 -0
  58. package/open-sse/handlers/embeddingProviders/gemini.js +54 -0
  59. package/open-sse/handlers/embeddingProviders/index.js +23 -0
  60. package/open-sse/handlers/embeddingProviders/openai.js +39 -0
  61. package/open-sse/handlers/embeddingProviders/openaiCompatNode.js +13 -0
  62. package/open-sse/handlers/embeddingsCore.js +126 -0
  63. package/open-sse/handlers/fetch/index.js +237 -0
  64. package/open-sse/handlers/imageGenerationCore.js +189 -0
  65. package/open-sse/handlers/imageProviders/_base.js +31 -0
  66. package/open-sse/handlers/imageProviders/blackForestLabs.js +43 -0
  67. package/open-sse/handlers/imageProviders/cloudflareAi.js +178 -0
  68. package/open-sse/handlers/imageProviders/codex.js +198 -0
  69. package/open-sse/handlers/imageProviders/comfyui.js +8 -0
  70. package/open-sse/handlers/imageProviders/falAi.js +41 -0
  71. package/open-sse/handlers/imageProviders/gemini.js +25 -0
  72. package/open-sse/handlers/imageProviders/huggingface.js +22 -0
  73. package/open-sse/handlers/imageProviders/index.js +40 -0
  74. package/open-sse/handlers/imageProviders/nanobanana.js +58 -0
  75. package/open-sse/handlers/imageProviders/openai.js +40 -0
  76. package/open-sse/handlers/imageProviders/runwayml.js +47 -0
  77. package/open-sse/handlers/imageProviders/sdwebui.js +17 -0
  78. package/open-sse/handlers/imageProviders/stabilityAi.js +34 -0
  79. package/open-sse/handlers/responsesHandler.js +103 -0
  80. package/open-sse/handlers/search/callers.js +371 -0
  81. package/open-sse/handlers/search/chatSearch.js +409 -0
  82. package/open-sse/handlers/search/index.js +201 -0
  83. package/open-sse/handlers/search/normalizers.js +223 -0
  84. package/open-sse/handlers/sttCore.js +194 -0
  85. package/open-sse/handlers/ttsCore.js +74 -0
  86. package/open-sse/handlers/ttsProviders/_base.js +39 -0
  87. package/open-sse/handlers/ttsProviders/edgeTts.js +89 -0
  88. package/open-sse/handlers/ttsProviders/elevenlabs.js +48 -0
  89. package/open-sse/handlers/ttsProviders/gemini.js +117 -0
  90. package/open-sse/handlers/ttsProviders/genericFormats.js +169 -0
  91. package/open-sse/handlers/ttsProviders/googleTts.js +54 -0
  92. package/open-sse/handlers/ttsProviders/index.js +50 -0
  93. package/open-sse/handlers/ttsProviders/localDevice.js +87 -0
  94. package/open-sse/handlers/ttsProviders/minimax.js +59 -0
  95. package/open-sse/handlers/ttsProviders/openai.js +30 -0
  96. package/open-sse/handlers/ttsProviders/openrouter.js +70 -0
  97. package/open-sse/index.js +82 -0
  98. package/open-sse/rtk/applyFilter.js +15 -0
  99. package/open-sse/rtk/autodetect.js +111 -0
  100. package/open-sse/rtk/caveman.js +100 -0
  101. package/open-sse/rtk/cavemanPrompts.js +78 -0
  102. package/open-sse/rtk/constants.js +55 -0
  103. package/open-sse/rtk/filters/buildOutput.js +127 -0
  104. package/open-sse/rtk/filters/dedupLog.js +44 -0
  105. package/open-sse/rtk/filters/find.js +49 -0
  106. package/open-sse/rtk/filters/gitDiff.js +92 -0
  107. package/open-sse/rtk/filters/gitStatus.js +117 -0
  108. package/open-sse/rtk/filters/grep.js +48 -0
  109. package/open-sse/rtk/filters/ls.js +79 -0
  110. package/open-sse/rtk/filters/readNumbered.js +27 -0
  111. package/open-sse/rtk/filters/searchList.js +52 -0
  112. package/open-sse/rtk/filters/smartTruncate.js +15 -0
  113. package/open-sse/rtk/filters/tree.js +32 -0
  114. package/open-sse/rtk/index.js +155 -0
  115. package/open-sse/rtk/registry.js +38 -0
  116. package/open-sse/services/accountFallback.js +238 -0
  117. package/open-sse/services/combo.js +198 -0
  118. package/open-sse/services/compact.js +71 -0
  119. package/open-sse/services/kiroModels.js +332 -0
  120. package/open-sse/services/model.js +261 -0
  121. package/open-sse/services/oauthCredentialManager.js +151 -0
  122. package/open-sse/services/projectId.js +306 -0
  123. package/open-sse/services/provider.js +356 -0
  124. package/open-sse/services/qoderModels.js +214 -0
  125. package/open-sse/services/tokenRefresh.js +939 -0
  126. package/open-sse/services/usage.js +1496 -0
  127. package/open-sse/transformer/responsesTransformer.js +439 -0
  128. package/open-sse/transformer/streamToJsonConverter.js +103 -0
  129. package/open-sse/translator/formats.js +36 -0
  130. package/open-sse/translator/helpers/claudeHelper.js +216 -0
  131. package/open-sse/translator/helpers/geminiHelper.js +372 -0
  132. package/open-sse/translator/helpers/imageHelper.js +34 -0
  133. package/open-sse/translator/helpers/maxTokensHelper.js +27 -0
  134. package/open-sse/translator/helpers/openaiHelper.js +130 -0
  135. package/open-sse/translator/helpers/responsesApiHelper.js +139 -0
  136. package/open-sse/translator/helpers/toolCallHelper.js +148 -0
  137. package/open-sse/translator/index.js +251 -0
  138. package/open-sse/translator/request/antigravity-to-openai.js +229 -0
  139. package/open-sse/translator/request/claude-to-openai.js +232 -0
  140. package/open-sse/translator/request/gemini-to-openai.js +147 -0
  141. package/open-sse/translator/request/openai-responses.js +318 -0
  142. package/open-sse/translator/request/openai-to-claude.js +401 -0
  143. package/open-sse/translator/request/openai-to-commandcode.js +170 -0
  144. package/open-sse/translator/request/openai-to-cursor.js +183 -0
  145. package/open-sse/translator/request/openai-to-gemini.js +470 -0
  146. package/open-sse/translator/request/openai-to-kiro.js +629 -0
  147. package/open-sse/translator/request/openai-to-kiro.old.js +278 -0
  148. package/open-sse/translator/request/openai-to-ollama.js +192 -0
  149. package/open-sse/translator/request/openai-to-vertex.js +42 -0
  150. package/open-sse/translator/response/claude-to-openai.js +206 -0
  151. package/open-sse/translator/response/commandcode-to-openai.js +197 -0
  152. package/open-sse/translator/response/cursor-to-openai.js +30 -0
  153. package/open-sse/translator/response/gemini-to-openai.js +245 -0
  154. package/open-sse/translator/response/kiro-to-openai.js +195 -0
  155. package/open-sse/translator/response/ollama-to-openai.js +152 -0
  156. package/open-sse/translator/response/openai-responses.js +590 -0
  157. package/open-sse/translator/response/openai-to-antigravity.js +122 -0
  158. package/open-sse/translator/response/openai-to-claude.js +266 -0
  159. package/open-sse/utils/bypassHandler.js +298 -0
  160. package/open-sse/utils/claudeCloaking.js +155 -0
  161. package/open-sse/utils/claudeHeaderCache.js +70 -0
  162. package/open-sse/utils/clientDetector.js +63 -0
  163. package/open-sse/utils/cursorChecksum.js +149 -0
  164. package/open-sse/utils/cursorProtobuf.js +904 -0
  165. package/open-sse/utils/debugLog.js +14 -0
  166. package/open-sse/utils/error.js +147 -0
  167. package/open-sse/utils/ollamaTransform.js +85 -0
  168. package/open-sse/utils/proxyFetch.js +368 -0
  169. package/open-sse/utils/reasoningContentInjector.js +79 -0
  170. package/open-sse/utils/requestLogger.js +260 -0
  171. package/open-sse/utils/responsesStreamHelpers.js +49 -0
  172. package/open-sse/utils/sessionManager.js +82 -0
  173. package/open-sse/utils/stream.js +462 -0
  174. package/open-sse/utils/streamHandler.js +250 -0
  175. package/open-sse/utils/streamHelpers.js +122 -0
  176. package/open-sse/utils/toolDeduper.js +49 -0
  177. package/open-sse/utils/usageTracking.js +347 -0
  178. package/package.json +100 -0
  179. package/postcss.config.mjs +12 -0
  180. package/public/favicon.svg +11 -0
  181. package/public/file.svg +1 -0
  182. package/public/globe.svg +1 -0
  183. package/public/i18n/literals/ar.json +195 -0
  184. package/public/i18n/literals/bn.json +195 -0
  185. package/public/i18n/literals/cs.json +195 -0
  186. package/public/i18n/literals/da.json +195 -0
  187. package/public/i18n/literals/de.json +195 -0
  188. package/public/i18n/literals/el.json +195 -0
  189. package/public/i18n/literals/es.json +195 -0
  190. package/public/i18n/literals/fi.json +195 -0
  191. package/public/i18n/literals/fr.json +195 -0
  192. package/public/i18n/literals/he.json +195 -0
  193. package/public/i18n/literals/hi.json +195 -0
  194. package/public/i18n/literals/hu.json +195 -0
  195. package/public/i18n/literals/id.json +195 -0
  196. package/public/i18n/literals/it.json +195 -0
  197. package/public/i18n/literals/ja.json +195 -0
  198. package/public/i18n/literals/ko.json +195 -0
  199. package/public/i18n/literals/nl.json +195 -0
  200. package/public/i18n/literals/no.json +195 -0
  201. package/public/i18n/literals/pl.json +195 -0
  202. package/public/i18n/literals/pt-BR.json +195 -0
  203. package/public/i18n/literals/pt-PT.json +195 -0
  204. package/public/i18n/literals/ro.json +195 -0
  205. package/public/i18n/literals/ru.json +195 -0
  206. package/public/i18n/literals/sv.json +195 -0
  207. package/public/i18n/literals/th.json +195 -0
  208. package/public/i18n/literals/tl.json +195 -0
  209. package/public/i18n/literals/tr.json +195 -0
  210. package/public/i18n/literals/uk.json +195 -0
  211. package/public/i18n/literals/ur.json +195 -0
  212. package/public/i18n/literals/vi.json +195 -0
  213. package/public/i18n/literals/zh-CN.json +772 -0
  214. package/public/i18n/literals/zh-TW.json +195 -0
  215. package/public/icons/discord.svg +4 -0
  216. package/public/icons/icon-192.svg +4 -0
  217. package/public/icons/icon-512.svg +4 -0
  218. package/public/next.svg +1 -0
  219. package/public/providers/alicode-intl.png +0 -0
  220. package/public/providers/alicode.png +0 -0
  221. package/public/providers/amp.png +0 -0
  222. package/public/providers/anthropic-m.png +0 -0
  223. package/public/providers/anthropic.png +0 -0
  224. package/public/providers/antigravity.png +0 -0
  225. package/public/providers/assemblyai.png +0 -0
  226. package/public/providers/aws-polly.png +0 -0
  227. package/public/providers/azure.png +0 -0
  228. package/public/providers/black-forest-labs.png +0 -0
  229. package/public/providers/blackbox.png +0 -0
  230. package/public/providers/brave-search.png +0 -0
  231. package/public/providers/byteplus.png +0 -0
  232. package/public/providers/cartesia.png +0 -0
  233. package/public/providers/cerebras.png +0 -0
  234. package/public/providers/chutes.png +0 -0
  235. package/public/providers/claude.png +0 -0
  236. package/public/providers/cline.png +0 -0
  237. package/public/providers/cloudflare-ai.png +0 -0
  238. package/public/providers/codebuddy.svg +37 -0
  239. package/public/providers/codex.png +0 -0
  240. package/public/providers/cohere.png +0 -0
  241. package/public/providers/comfyui.png +0 -0
  242. package/public/providers/commandcode.png +0 -0
  243. package/public/providers/continue.png +0 -0
  244. package/public/providers/copilot.png +0 -0
  245. package/public/providers/coqui.png +0 -0
  246. package/public/providers/cursor.png +0 -0
  247. package/public/providers/deepgram.png +0 -0
  248. package/public/providers/deepseek-tui.png +0 -0
  249. package/public/providers/deepseek.png +0 -0
  250. package/public/providers/droid.png +0 -0
  251. package/public/providers/edge-tts.png +0 -0
  252. package/public/providers/elevenlabs.png +0 -0
  253. package/public/providers/exa.png +0 -0
  254. package/public/providers/fal-ai.png +0 -0
  255. package/public/providers/firecrawl.png +0 -0
  256. package/public/providers/fireworks.png +0 -0
  257. package/public/providers/gemini-cli.png +0 -0
  258. package/public/providers/gemini.png +0 -0
  259. package/public/providers/github.png +0 -0
  260. package/public/providers/glm-cn.png +0 -0
  261. package/public/providers/glm.png +0 -0
  262. package/public/providers/google-pse.png +0 -0
  263. package/public/providers/google-tts.png +0 -0
  264. package/public/providers/grok-web.png +0 -0
  265. package/public/providers/groq.png +0 -0
  266. package/public/providers/hermes.png +0 -0
  267. package/public/providers/huggingface.png +0 -0
  268. package/public/providers/hyperbolic.png +0 -0
  269. package/public/providers/iflow.png +0 -0
  270. package/public/providers/inworld.png +0 -0
  271. package/public/providers/jcode.png +0 -0
  272. package/public/providers/jina-ai.png +0 -0
  273. package/public/providers/jina-reader.png +0 -0
  274. package/public/providers/kilocode.png +0 -0
  275. package/public/providers/kimi-coding.png +0 -0
  276. package/public/providers/kimi.png +0 -0
  277. package/public/providers/kiro.png +0 -0
  278. package/public/providers/linkup.png +0 -0
  279. package/public/providers/local-device.png +0 -0
  280. package/public/providers/minimax-cn.png +0 -0
  281. package/public/providers/minimax.png +0 -0
  282. package/public/providers/mistral.png +0 -0
  283. package/public/providers/nanobanana.png +0 -0
  284. package/public/providers/nebius.png +0 -0
  285. package/public/providers/nvidia.png +0 -0
  286. package/public/providers/oai-cc.png +0 -0
  287. package/public/providers/oai-r.png +0 -0
  288. package/public/providers/ollama-local.png +0 -0
  289. package/public/providers/ollama.png +0 -0
  290. package/public/providers/openai.png +0 -0
  291. package/public/providers/openclaw.png +0 -0
  292. package/public/providers/opencode-go.png +0 -0
  293. package/public/providers/opencode.png +0 -0
  294. package/public/providers/openrouter.png +0 -0
  295. package/public/providers/perplexity-web.png +0 -0
  296. package/public/providers/perplexity.png +0 -0
  297. package/public/providers/playht.png +0 -0
  298. package/public/providers/qoder.png +0 -0
  299. package/public/providers/qwen.png +0 -0
  300. package/public/providers/recraft.png +0 -0
  301. package/public/providers/roo.png +0 -0
  302. package/public/providers/runwayml.png +0 -0
  303. package/public/providers/sdwebui.png +0 -0
  304. package/public/providers/searchapi.png +0 -0
  305. package/public/providers/searxng.png +0 -0
  306. package/public/providers/serper.png +0 -0
  307. package/public/providers/siliconflow.png +0 -0
  308. package/public/providers/stability-ai.png +0 -0
  309. package/public/providers/tavily.png +0 -0
  310. package/public/providers/together.png +0 -0
  311. package/public/providers/topaz.png +0 -0
  312. package/public/providers/tortoise.png +0 -0
  313. package/public/providers/vertex-partner.png +0 -0
  314. package/public/providers/vertex.png +0 -0
  315. package/public/providers/volcengine-ark.png +0 -0
  316. package/public/providers/voyage-ai.png +0 -0
  317. package/public/providers/xai.png +0 -0
  318. package/public/providers/xiaomi-mimo.png +0 -0
  319. package/public/providers/xiaomi-tokenplan.png +0 -0
  320. package/public/providers/youcom.png +0 -0
  321. package/public/sw.js +22 -0
  322. package/public/vercel.svg +1 -0
  323. package/public/window.svg +1 -0
  324. package/scripts/compact-request-details.mjs +71 -0
  325. package/scripts/import-codex-gptjson.mjs +342 -0
  326. package/scripts/start-standalone.mjs +25 -0
  327. package/scripts/translate-readme.js +201 -0
  328. package/src/app/(dashboard)/dashboard/automation/page.js +294 -0
  329. package/src/app/(dashboard)/dashboard/basic-chat/BasicChatPageClient.js +967 -0
  330. package/src/app/(dashboard)/dashboard/basic-chat/page.js +5 -0
  331. package/src/app/(dashboard)/dashboard/cli-tools/CLIToolsPageClient.js +66 -0
  332. package/src/app/(dashboard)/dashboard/cli-tools/[toolId]/ToolDetailClient.js +173 -0
  333. package/src/app/(dashboard)/dashboard/cli-tools/[toolId]/page.js +11 -0
  334. package/src/app/(dashboard)/dashboard/cli-tools/components/AntigravityToolCard.js +481 -0
  335. package/src/app/(dashboard)/dashboard/cli-tools/components/ApiKeySelect.js +66 -0
  336. package/src/app/(dashboard)/dashboard/cli-tools/components/BaseUrlSelect.js +174 -0
  337. package/src/app/(dashboard)/dashboard/cli-tools/components/ClaudeToolCard.js +390 -0
  338. package/src/app/(dashboard)/dashboard/cli-tools/components/ClineToolCard.js +301 -0
  339. package/src/app/(dashboard)/dashboard/cli-tools/components/CodexToolCard.js +458 -0
  340. package/src/app/(dashboard)/dashboard/cli-tools/components/CopilotToolCard.js +323 -0
  341. package/src/app/(dashboard)/dashboard/cli-tools/components/CoworkToolCard.js +640 -0
  342. package/src/app/(dashboard)/dashboard/cli-tools/components/DeepSeekTuiToolCard.js +338 -0
  343. package/src/app/(dashboard)/dashboard/cli-tools/components/DefaultToolCard.js +271 -0
  344. package/src/app/(dashboard)/dashboard/cli-tools/components/DroidToolCard.js +410 -0
  345. package/src/app/(dashboard)/dashboard/cli-tools/components/EndpointPresetControl.js +128 -0
  346. package/src/app/(dashboard)/dashboard/cli-tools/components/HermesToolCard.js +317 -0
  347. package/src/app/(dashboard)/dashboard/cli-tools/components/JcodeToolCard.js +380 -0
  348. package/src/app/(dashboard)/dashboard/cli-tools/components/KiloToolCard.js +275 -0
  349. package/src/app/(dashboard)/dashboard/cli-tools/components/MitmLinkCard.js +40 -0
  350. package/src/app/(dashboard)/dashboard/cli-tools/components/MitmServerCard.js +329 -0
  351. package/src/app/(dashboard)/dashboard/cli-tools/components/MitmToolCard.js +318 -0
  352. package/src/app/(dashboard)/dashboard/cli-tools/components/OpenClawToolCard.js +388 -0
  353. package/src/app/(dashboard)/dashboard/cli-tools/components/OpenCodeToolCard.js +500 -0
  354. package/src/app/(dashboard)/dashboard/cli-tools/components/ToolSummaryCard.js +39 -0
  355. package/src/app/(dashboard)/dashboard/cli-tools/components/cliEndpointMatch.js +13 -0
  356. package/src/app/(dashboard)/dashboard/cli-tools/components/index.js +19 -0
  357. package/src/app/(dashboard)/dashboard/cli-tools/page.js +7 -0
  358. package/src/app/(dashboard)/dashboard/combos/page.js +612 -0
  359. package/src/app/(dashboard)/dashboard/console-log/ConsoleLogClient.js +91 -0
  360. package/src/app/(dashboard)/dashboard/console-log/page.js +8 -0
  361. package/src/app/(dashboard)/dashboard/endpoint/EndpointPageClient.js +1555 -0
  362. package/src/app/(dashboard)/dashboard/endpoint/page.js +7 -0
  363. package/src/app/(dashboard)/dashboard/media-providers/[kind]/[id]/page.js +1903 -0
  364. package/src/app/(dashboard)/dashboard/media-providers/[kind]/page.js +289 -0
  365. package/src/app/(dashboard)/dashboard/media-providers/combo/[id]/page.js +410 -0
  366. package/src/app/(dashboard)/dashboard/media-providers/web/page.js +209 -0
  367. package/src/app/(dashboard)/dashboard/mitm/MitmPageClient.js +117 -0
  368. package/src/app/(dashboard)/dashboard/mitm/page.js +5 -0
  369. package/src/app/(dashboard)/dashboard/page.js +7 -0
  370. package/src/app/(dashboard)/dashboard/profile/page.js +1140 -0
  371. package/src/app/(dashboard)/dashboard/providers/[id]/AddApiKeyModal.js +389 -0
  372. package/src/app/(dashboard)/dashboard/providers/[id]/AddCustomModelModal.js +125 -0
  373. package/src/app/(dashboard)/dashboard/providers/[id]/CompatibleModelsSection.js +250 -0
  374. package/src/app/(dashboard)/dashboard/providers/[id]/ConnectionRow.js +299 -0
  375. package/src/app/(dashboard)/dashboard/providers/[id]/CooldownTimer.js +42 -0
  376. package/src/app/(dashboard)/dashboard/providers/[id]/EditCompatibleNodeModal.js +161 -0
  377. package/src/app/(dashboard)/dashboard/providers/[id]/ModelRow.js +95 -0
  378. package/src/app/(dashboard)/dashboard/providers/[id]/PassthroughModelsSection.js +183 -0
  379. package/src/app/(dashboard)/dashboard/providers/[id]/page.js +2053 -0
  380. package/src/app/(dashboard)/dashboard/providers/[id]/page.new.js +1724 -0
  381. package/src/app/(dashboard)/dashboard/providers/components/ConnectionsCard.js +497 -0
  382. package/src/app/(dashboard)/dashboard/providers/components/ModelAvailabilityBadge.js +185 -0
  383. package/src/app/(dashboard)/dashboard/providers/components/ModelsCard.js +294 -0
  384. package/src/app/(dashboard)/dashboard/providers/new/page.js +220 -0
  385. package/src/app/(dashboard)/dashboard/providers/page.js +1365 -0
  386. package/src/app/(dashboard)/dashboard/proxy-pools/page.js +1092 -0
  387. package/src/app/(dashboard)/dashboard/quota/page.js +11 -0
  388. package/src/app/(dashboard)/dashboard/skills/page.js +112 -0
  389. package/src/app/(dashboard)/dashboard/translator/page.js +303 -0
  390. package/src/app/(dashboard)/dashboard/usage/components/OverviewCards.js +35 -0
  391. package/src/app/(dashboard)/dashboard/usage/components/ProviderLimits/ProviderLimitCard.js +185 -0
  392. package/src/app/(dashboard)/dashboard/usage/components/ProviderLimits/QuotaProgressBar.js +127 -0
  393. package/src/app/(dashboard)/dashboard/usage/components/ProviderLimits/QuotaTable.js +259 -0
  394. package/src/app/(dashboard)/dashboard/usage/components/ProviderLimits/index.js +1394 -0
  395. package/src/app/(dashboard)/dashboard/usage/components/ProviderLimits/utils.js +244 -0
  396. package/src/app/(dashboard)/dashboard/usage/components/ProviderTopology.js +327 -0
  397. package/src/app/(dashboard)/dashboard/usage/components/RequestDetailsTab.js +433 -0
  398. package/src/app/(dashboard)/dashboard/usage/components/UsageChart.js +141 -0
  399. package/src/app/(dashboard)/dashboard/usage/components/UsageTable.js +247 -0
  400. package/src/app/(dashboard)/dashboard/usage/page.js +75 -0
  401. package/src/app/(dashboard)/layout.js +6 -0
  402. package/src/app/api/auth/login/route.js +76 -0
  403. package/src/app/api/auth/logout/route.js +12 -0
  404. package/src/app/api/auth/oidc/callback/route.js +87 -0
  405. package/src/app/api/auth/oidc/start/route.js +52 -0
  406. package/src/app/api/auth/oidc/test/route.js +84 -0
  407. package/src/app/api/auth/status/route.js +45 -0
  408. package/src/app/api/cli-tools/all-statuses/route.js +46 -0
  409. package/src/app/api/cli-tools/antigravity-mitm/alias/route.js +53 -0
  410. package/src/app/api/cli-tools/antigravity-mitm/route.js +202 -0
  411. package/src/app/api/cli-tools/claude-settings/route.js +203 -0
  412. package/src/app/api/cli-tools/cline-settings/route.js +133 -0
  413. package/src/app/api/cli-tools/codex-gateway/accounts/route.js +16 -0
  414. package/src/app/api/cli-tools/codex-settings/route.js +239 -0
  415. package/src/app/api/cli-tools/copilot-settings/route.js +148 -0
  416. package/src/app/api/cli-tools/cowork-mcp-registry/route.js +77 -0
  417. package/src/app/api/cli-tools/cowork-mcp-tools/route.js +95 -0
  418. package/src/app/api/cli-tools/cowork-settings/route.js +412 -0
  419. package/src/app/api/cli-tools/deepseek-tui-settings/route.js +164 -0
  420. package/src/app/api/cli-tools/droid-settings/route.js +213 -0
  421. package/src/app/api/cli-tools/hermes-settings/route.js +175 -0
  422. package/src/app/api/cli-tools/jcode-settings/route.js +216 -0
  423. package/src/app/api/cli-tools/kilo-settings/route.js +131 -0
  424. package/src/app/api/cli-tools/openclaw-settings/route.js +292 -0
  425. package/src/app/api/cli-tools/opencode-settings/route.js +259 -0
  426. package/src/app/api/combos/[id]/route.js +81 -0
  427. package/src/app/api/combos/route.js +48 -0
  428. package/src/app/api/health/route.js +15 -0
  429. package/src/app/api/init/route.js +4 -0
  430. package/src/app/api/keys/[id]/route.js +58 -0
  431. package/src/app/api/keys/route.js +42 -0
  432. package/src/app/api/locale/route.js +30 -0
  433. package/src/app/api/mcp/[plugin]/message/route.js +21 -0
  434. package/src/app/api/mcp/[plugin]/sse/route.js +37 -0
  435. package/src/app/api/media-providers/tts/deepgram/voices/route.js +65 -0
  436. package/src/app/api/media-providers/tts/elevenlabs/voices/route.js +71 -0
  437. package/src/app/api/media-providers/tts/inworld/voices/route.js +61 -0
  438. package/src/app/api/media-providers/tts/minimax/voices/route.js +113 -0
  439. package/src/app/api/media-providers/tts/voices/route.js +99 -0
  440. package/src/app/api/models/alias/route.js +53 -0
  441. package/src/app/api/models/availability/route.js +103 -0
  442. package/src/app/api/models/custom/route.js +48 -0
  443. package/src/app/api/models/disabled/route.js +50 -0
  444. package/src/app/api/models/route.js +64 -0
  445. package/src/app/api/models/test/ping.js +191 -0
  446. package/src/app/api/models/test/route.js +14 -0
  447. package/src/app/api/oauth/[provider]/[action]/route.js +343 -0
  448. package/src/app/api/oauth/codebuddy/bulk-import/[jobId]/cancel/route.js +19 -0
  449. package/src/app/api/oauth/codebuddy/bulk-import/[jobId]/manual/[workerId]/route.js +30 -0
  450. package/src/app/api/oauth/codebuddy/bulk-import/[jobId]/route.js +23 -0
  451. package/src/app/api/oauth/codebuddy/bulk-import/latest/route.js +25 -0
  452. package/src/app/api/oauth/codebuddy/bulk-import/route.js +49 -0
  453. package/src/app/api/oauth/codebuddy/quota-cookie/route.js +133 -0
  454. package/src/app/api/oauth/codex/import-token/route.js +96 -0
  455. package/src/app/api/oauth/cursor/auto-import/route.js +258 -0
  456. package/src/app/api/oauth/cursor/import/route.js +100 -0
  457. package/src/app/api/oauth/gitlab/pat/route.js +62 -0
  458. package/src/app/api/oauth/iflow/cookie/route.js +137 -0
  459. package/src/app/api/oauth/kiro/auto-import/route.js +85 -0
  460. package/src/app/api/oauth/kiro/bulk-import/[jobId]/cancel/route.js +18 -0
  461. package/src/app/api/oauth/kiro/bulk-import/[jobId]/manual/[workerId]/route.js +29 -0
  462. package/src/app/api/oauth/kiro/bulk-import/[jobId]/route.js +22 -0
  463. package/src/app/api/oauth/kiro/bulk-import/latest/route.js +25 -0
  464. package/src/app/api/oauth/kiro/bulk-import/route.js +49 -0
  465. package/src/app/api/oauth/kiro/import/route.js +110 -0
  466. package/src/app/api/oauth/kiro/social-authorize/route.js +27 -0
  467. package/src/app/api/oauth/kiro/social-exchange/route.js +41 -0
  468. package/src/app/api/pricing/route.js +134 -0
  469. package/src/app/api/provider-nodes/[id]/route.js +101 -0
  470. package/src/app/api/provider-nodes/route.js +104 -0
  471. package/src/app/api/provider-nodes/validate/route.js +201 -0
  472. package/src/app/api/providers/[id]/models/route.js +526 -0
  473. package/src/app/api/providers/[id]/route.js +189 -0
  474. package/src/app/api/providers/[id]/test/route.js +23 -0
  475. package/src/app/api/providers/[id]/test/testUtils.js +714 -0
  476. package/src/app/api/providers/[id]/test-models/route.js +66 -0
  477. package/src/app/api/providers/client/route.js +126 -0
  478. package/src/app/api/providers/kilo/free-models/route.js +55 -0
  479. package/src/app/api/providers/route.js +206 -0
  480. package/src/app/api/providers/suggested-models/filters.js +20 -0
  481. package/src/app/api/providers/suggested-models/route.js +32 -0
  482. package/src/app/api/providers/test-batch/route.js +131 -0
  483. package/src/app/api/providers/validate/route.js +637 -0
  484. package/src/app/api/proxy-pools/[id]/route.js +123 -0
  485. package/src/app/api/proxy-pools/[id]/test/route.js +70 -0
  486. package/src/app/api/proxy-pools/cloudflare-deploy/route.js +145 -0
  487. package/src/app/api/proxy-pools/deno-deploy/route.js +175 -0
  488. package/src/app/api/proxy-pools/route.js +93 -0
  489. package/src/app/api/proxy-pools/vercel-deploy/route.js +142 -0
  490. package/src/app/api/settings/database/route.js +36 -0
  491. package/src/app/api/settings/proxy-test/route.js +23 -0
  492. package/src/app/api/settings/require-login/route.js +15 -0
  493. package/src/app/api/settings/route.js +100 -0
  494. package/src/app/api/shutdown/route.js +24 -0
  495. package/src/app/api/tags/route.js +18 -0
  496. package/src/app/api/translator/console-logs/route.js +24 -0
  497. package/src/app/api/translator/console-logs/stream/route.js +79 -0
  498. package/src/app/api/translator/load/route.js +45 -0
  499. package/src/app/api/translator/save/route.js +44 -0
  500. package/src/app/api/translator/send/route.js +94 -0
  501. package/src/app/api/translator/translate/route.js +90 -0
  502. package/src/app/api/tunnel/disable/route.js +12 -0
  503. package/src/app/api/tunnel/enable/route.js +16 -0
  504. package/src/app/api/tunnel/status/route.js +13 -0
  505. package/src/app/api/tunnel/tailscale-check/route.js +50 -0
  506. package/src/app/api/tunnel/tailscale-disable/route.js +12 -0
  507. package/src/app/api/tunnel/tailscale-enable/route.js +12 -0
  508. package/src/app/api/tunnel/tailscale-install/route.js +72 -0
  509. package/src/app/api/usage/[connectionId]/route.js +188 -0
  510. package/src/app/api/usage/chart/route.js +21 -0
  511. package/src/app/api/usage/history/route.js +12 -0
  512. package/src/app/api/usage/logs/route.js +12 -0
  513. package/src/app/api/usage/providers/route.js +42 -0
  514. package/src/app/api/usage/request-details/route.js +57 -0
  515. package/src/app/api/usage/request-logs/route.js +13 -0
  516. package/src/app/api/usage/stats/route.js +23 -0
  517. package/src/app/api/usage/stream/route.js +79 -0
  518. package/src/app/api/v1/api/chat/route.js +37 -0
  519. package/src/app/api/v1/audio/speech/route.js +16 -0
  520. package/src/app/api/v1/audio/transcriptions/route.js +19 -0
  521. package/src/app/api/v1/audio/voices/route.js +68 -0
  522. package/src/app/api/v1/chat/completions/route.js +35 -0
  523. package/src/app/api/v1/embeddings/route.js +21 -0
  524. package/src/app/api/v1/images/generations/route.js +16 -0
  525. package/src/app/api/v1/messages/count_tokens/route.js +52 -0
  526. package/src/app/api/v1/messages/route.js +36 -0
  527. package/src/app/api/v1/models/[kind]/route.js +55 -0
  528. package/src/app/api/v1/models/info/route.js +110 -0
  529. package/src/app/api/v1/models/route.js +451 -0
  530. package/src/app/api/v1/responses/compact/route.js +37 -0
  531. package/src/app/api/v1/responses/route.js +30 -0
  532. package/src/app/api/v1/route.js +1 -0
  533. package/src/app/api/v1/search/route.js +21 -0
  534. package/src/app/api/v1/web/fetch/route.js +21 -0
  535. package/src/app/api/v1beta/models/[...path]/route.js +328 -0
  536. package/src/app/api/v1beta/models/route.js +44 -0
  537. package/src/app/api/version/route.js +45 -0
  538. package/src/app/api/version/shutdown/route.js +15 -0
  539. package/src/app/api/version/update/route.js +21 -0
  540. package/src/app/callback/page.js +148 -0
  541. package/src/app/dashboard/settings/pricing/page.js +173 -0
  542. package/src/app/favicon.ico +0 -0
  543. package/src/app/globals.css +496 -0
  544. package/src/app/landing/components/AnimatedBackground.js +57 -0
  545. package/src/app/landing/components/Features.js +133 -0
  546. package/src/app/landing/components/FlowAnimation.js +175 -0
  547. package/src/app/landing/components/Footer.js +61 -0
  548. package/src/app/landing/components/GetStarted.js +97 -0
  549. package/src/app/landing/components/HeroSection.js +47 -0
  550. package/src/app/landing/components/HowItWorks.js +66 -0
  551. package/src/app/landing/components/Navigation.js +72 -0
  552. package/src/app/landing/page.js +106 -0
  553. package/src/app/layout.js +49 -0
  554. package/src/app/login/page.js +197 -0
  555. package/src/app/manifest.js +30 -0
  556. package/src/app/page.js +5 -0
  557. package/src/dashboardGuard.js +242 -0
  558. package/src/i18n/RuntimeI18nProvider.js +27 -0
  559. package/src/i18n/config.js +146 -0
  560. package/src/i18n/runtime.js +162 -0
  561. package/src/lib/appUpdater.js +200 -0
  562. package/src/lib/auth/dashboardSession.js +68 -0
  563. package/src/lib/auth/loginLimiter.js +52 -0
  564. package/src/lib/auth/oidc.js +234 -0
  565. package/src/lib/consoleLogBuffer.js +79 -0
  566. package/src/lib/dataDir.js +29 -0
  567. package/src/lib/db/adapters/betterSqliteAdapter.js +55 -0
  568. package/src/lib/db/adapters/bunSqliteAdapter.js +63 -0
  569. package/src/lib/db/adapters/nodeSqliteAdapter.js +84 -0
  570. package/src/lib/db/adapters/sqljsAdapter.js +115 -0
  571. package/src/lib/db/backup.js +35 -0
  572. package/src/lib/db/driver.js +85 -0
  573. package/src/lib/db/helpers/jsonCol.js +9 -0
  574. package/src/lib/db/helpers/kvStore.js +39 -0
  575. package/src/lib/db/helpers/metaStore.js +22 -0
  576. package/src/lib/db/index.js +171 -0
  577. package/src/lib/db/migrate.js +286 -0
  578. package/src/lib/db/migrations/001-initial.js +14 -0
  579. package/src/lib/db/migrations/index.js +10 -0
  580. package/src/lib/db/paths.js +18 -0
  581. package/src/lib/db/repos/aliasRepo.js +62 -0
  582. package/src/lib/db/repos/apiKeysRepo.js +75 -0
  583. package/src/lib/db/repos/combosRepo.js +73 -0
  584. package/src/lib/db/repos/connectionsRepo.js +226 -0
  585. package/src/lib/db/repos/disabledModelsRepo.js +56 -0
  586. package/src/lib/db/repos/nodesRepo.js +95 -0
  587. package/src/lib/db/repos/pricingRepo.js +108 -0
  588. package/src/lib/db/repos/proxyPoolsRepo.js +103 -0
  589. package/src/lib/db/repos/requestDetailsRepo.js +259 -0
  590. package/src/lib/db/repos/settingsRepo.js +104 -0
  591. package/src/lib/db/repos/usageRepo.js +731 -0
  592. package/src/lib/db/schema.js +157 -0
  593. package/src/lib/db/version.js +21 -0
  594. package/src/lib/disabledModelsDb.js +4 -0
  595. package/src/lib/localDb.js +21 -0
  596. package/src/lib/mcp/stdioSseBridge.js +198 -0
  597. package/src/lib/mitmAliasCache.js +46 -0
  598. package/src/lib/network/connectionProxy.js +160 -0
  599. package/src/lib/network/initOutboundProxy.js +25 -0
  600. package/src/lib/network/outboundProxy.js +68 -0
  601. package/src/lib/network/proxyTest.js +91 -0
  602. package/src/lib/oauth/constants/oauth.js +284 -0
  603. package/src/lib/oauth/constants/xai.js +61 -0
  604. package/src/lib/oauth/providers.js +1506 -0
  605. package/src/lib/oauth/services/antigravity.js +321 -0
  606. package/src/lib/oauth/services/claude.js +136 -0
  607. package/src/lib/oauth/services/codebuddyBulkImportManager.js +454 -0
  608. package/src/lib/oauth/services/codex.js +144 -0
  609. package/src/lib/oauth/services/cursor.js +179 -0
  610. package/src/lib/oauth/services/gemini.js +240 -0
  611. package/src/lib/oauth/services/github.js +225 -0
  612. package/src/lib/oauth/services/iflow.js +202 -0
  613. package/src/lib/oauth/services/index.js +17 -0
  614. package/src/lib/oauth/services/kiro.js +334 -0
  615. package/src/lib/oauth/services/kiroBulkImportManager.js +778 -0
  616. package/src/lib/oauth/services/kiroConnections.js +93 -0
  617. package/src/lib/oauth/services/kiroGoogleAutomation.js +1136 -0
  618. package/src/lib/oauth/services/oauth.js +157 -0
  619. package/src/lib/oauth/services/openai.js +123 -0
  620. package/src/lib/oauth/services/qoder.js +216 -0
  621. package/src/lib/oauth/services/qwen.js +170 -0
  622. package/src/lib/oauth/services/xai.js +238 -0
  623. package/src/lib/oauth/utils/banner.js +63 -0
  624. package/src/lib/oauth/utils/pkce.js +39 -0
  625. package/src/lib/oauth/utils/server.js +415 -0
  626. package/src/lib/oauth/utils/ui.js +48 -0
  627. package/src/lib/providerNormalization.js +45 -0
  628. package/src/lib/qoder/constants.js +64 -0
  629. package/src/lib/qoder/cosy.js +175 -0
  630. package/src/lib/qoder/encoding.js +55 -0
  631. package/src/lib/requestDetailsDb.js +4 -0
  632. package/src/lib/tunnel/cloudflare/cloudflared.js +449 -0
  633. package/src/lib/tunnel/cloudflare/config.js +9 -0
  634. package/src/lib/tunnel/cloudflare/healthCheck.js +29 -0
  635. package/src/lib/tunnel/cloudflare/manager.js +151 -0
  636. package/src/lib/tunnel/cloudflare/pid.js +23 -0
  637. package/src/lib/tunnel/index.js +48 -0
  638. package/src/lib/tunnel/shared/dnsResolver.js +17 -0
  639. package/src/lib/tunnel/shared/internetCheck.js +26 -0
  640. package/src/lib/tunnel/shared/state.js +41 -0
  641. package/src/lib/tunnel/shared/watchdogConfig.js +8 -0
  642. package/src/lib/tunnel/tailscale/config.js +7 -0
  643. package/src/lib/tunnel/tailscale/healthCheck.js +29 -0
  644. package/src/lib/tunnel/tailscale/manager.js +129 -0
  645. package/src/lib/tunnel/tailscale/tailscale.js +790 -0
  646. package/src/lib/updater/updater.js +235 -0
  647. package/src/lib/usage/fetcher.js +208 -0
  648. package/src/lib/usageDb.js +7 -0
  649. package/src/mitm/antigravityIdeVersion.js +50 -0
  650. package/src/mitm/cert/generate.js +32 -0
  651. package/src/mitm/cert/install.js +269 -0
  652. package/src/mitm/cert/rootCA.js +173 -0
  653. package/src/mitm/config.js +87 -0
  654. package/src/mitm/dbReader.js +22 -0
  655. package/src/mitm/dns/dnsConfig.js +266 -0
  656. package/src/mitm/handlers/antigravity.js +33 -0
  657. package/src/mitm/handlers/base.js +226 -0
  658. package/src/mitm/handlers/copilot.js +35 -0
  659. package/src/mitm/handlers/cursor.js +15 -0
  660. package/src/mitm/handlers/kiro.js +526 -0
  661. package/src/mitm/logger.js +106 -0
  662. package/src/mitm/manager.js +851 -0
  663. package/src/mitm/paths.js +32 -0
  664. package/src/mitm/server.js +435 -0
  665. package/src/mitm/winElevated.js +81 -0
  666. package/src/models/index.js +38 -0
  667. package/src/proxy.js +5 -0
  668. package/src/shared/components/AddCustomEmbeddingModal.js +183 -0
  669. package/src/shared/components/Avatar.js +88 -0
  670. package/src/shared/components/Badge.js +54 -0
  671. package/src/shared/components/BulkAccountAutomationModal.js +508 -0
  672. package/src/shared/components/Button.js +56 -0
  673. package/src/shared/components/Card.js +116 -0
  674. package/src/shared/components/ChangelogModal.js +97 -0
  675. package/src/shared/components/CodeBuddyQuotaCookieModal.js +109 -0
  676. package/src/shared/components/ComboFormModal.js +176 -0
  677. package/src/shared/components/CursorAuthModal.js +212 -0
  678. package/src/shared/components/DonateModal.js +136 -0
  679. package/src/shared/components/Drawer.js +82 -0
  680. package/src/shared/components/EditConnectionModal.js +286 -0
  681. package/src/shared/components/Footer.js +132 -0
  682. package/src/shared/components/GitLabAuthModal.js +194 -0
  683. package/src/shared/components/Header.js +380 -0
  684. package/src/shared/components/HeaderLanguage.js +46 -0
  685. package/src/shared/components/HeaderMenu.js +126 -0
  686. package/src/shared/components/IFlowCookieModal.js +132 -0
  687. package/src/shared/components/Input.js +65 -0
  688. package/src/shared/components/KiroAuthModal.js +1171 -0
  689. package/src/shared/components/KiroOAuthWrapper.js +149 -0
  690. package/src/shared/components/KiroSocialOAuthModal.js +205 -0
  691. package/src/shared/components/LanguageSwitcher.js +190 -0
  692. package/src/shared/components/Loading.js +75 -0
  693. package/src/shared/components/ManualConfigModal.js +44 -0
  694. package/src/shared/components/McpMarketplaceModal.js +255 -0
  695. package/src/shared/components/Modal.js +146 -0
  696. package/src/shared/components/ModelSelectModal.js +537 -0
  697. package/src/shared/components/NineRemoteButton.js +23 -0
  698. package/src/shared/components/NineRemotePromoModal.js +99 -0
  699. package/src/shared/components/NoAuthProxyCard.js +86 -0
  700. package/src/shared/components/OAuthModal.js +682 -0
  701. package/src/shared/components/Pagination.js +150 -0
  702. package/src/shared/components/PricingModal.js +208 -0
  703. package/src/shared/components/ProviderIcon.js +63 -0
  704. package/src/shared/components/ProviderInfoCard.js +82 -0
  705. package/src/shared/components/RequestLogger.js +121 -0
  706. package/src/shared/components/SegmentedControl.js +48 -0
  707. package/src/shared/components/Select.js +67 -0
  708. package/src/shared/components/Sidebar.js +441 -0
  709. package/src/shared/components/ThemeProvider.js +15 -0
  710. package/src/shared/components/ThemeToggle.js +42 -0
  711. package/src/shared/components/Toggle.js +69 -0
  712. package/src/shared/components/Tooltip.js +25 -0
  713. package/src/shared/components/UsageStats.js +505 -0
  714. package/src/shared/components/index.js +46 -0
  715. package/src/shared/components/layouts/AuthLayout.js +29 -0
  716. package/src/shared/components/layouts/DashboardLayout.js +104 -0
  717. package/src/shared/components/layouts/index.js +4 -0
  718. package/src/shared/constants/cliTools.js +397 -0
  719. package/src/shared/constants/colors.js +77 -0
  720. package/src/shared/constants/config.js +99 -0
  721. package/src/shared/constants/coworkPlugins.js +75 -0
  722. package/src/shared/constants/index.js +4 -0
  723. package/src/shared/constants/locales.js +36 -0
  724. package/src/shared/constants/mitmToolHosts.js +12 -0
  725. package/src/shared/constants/models.js +38 -0
  726. package/src/shared/constants/pricing.js +303 -0
  727. package/src/shared/constants/providers.js +289 -0
  728. package/src/shared/constants/skills.js +78 -0
  729. package/src/shared/constants/ttsProviders.js +138 -0
  730. package/src/shared/hooks/index.js +2 -0
  731. package/src/shared/hooks/useCopyToClipboard.js +43 -0
  732. package/src/shared/hooks/useTheme.js +60 -0
  733. package/src/shared/services/bootstrap.js +12 -0
  734. package/src/shared/services/initializeApp.js +268 -0
  735. package/src/shared/utils/api.js +93 -0
  736. package/src/shared/utils/apiKey.js +98 -0
  737. package/src/shared/utils/clineAuth.js +37 -0
  738. package/src/shared/utils/cn.js +11 -0
  739. package/src/shared/utils/connectionStatus.js +162 -0
  740. package/src/shared/utils/index.js +40 -0
  741. package/src/shared/utils/machine.js +6 -0
  742. package/src/shared/utils/machineId.js +66 -0
  743. package/src/shared/utils/providerModelsFetcher.js +30 -0
  744. package/src/sse/handlers/chat.js +261 -0
  745. package/src/sse/handlers/embeddings.js +141 -0
  746. package/src/sse/handlers/fetch.js +213 -0
  747. package/src/sse/handlers/imageGeneration.js +142 -0
  748. package/src/sse/handlers/search.js +206 -0
  749. package/src/sse/handlers/stt.js +88 -0
  750. package/src/sse/handlers/tts.js +114 -0
  751. package/src/sse/services/auth.js +346 -0
  752. package/src/sse/services/codexGateway.js +215 -0
  753. package/src/sse/services/model.js +99 -0
  754. package/src/sse/services/tokenRefresh.js +319 -0
  755. package/src/sse/utils/logger.js +75 -0
  756. package/src/store/headerSearchStore.js +19 -0
  757. package/src/store/index.js +6 -0
  758. package/src/store/notificationStore.js +45 -0
  759. package/src/store/providerStore.js +55 -0
  760. package/src/store/settingsStore.js +51 -0
  761. package/src/store/themeStore.js +54 -0
  762. package/src/store/userStore.js +20 -0
  763. package/start.sh +4 -0
@@ -0,0 +1,346 @@
1
+ import { getProviderConnections, validateApiKey, updateProviderConnection, getSettings } from "@/lib/localDb";
2
+ import { resolveConnectionProxyConfig } from "@/lib/network/connectionProxy";
3
+ import { formatRetryAfter, checkFallbackError, isModelLockActive, buildModelLockUpdate, getEarliestModelLockUntil, isNonAccountError } from "open-sse/services/accountFallback.js";
4
+ import { MAX_RATE_LIMIT_COOLDOWN_MS } from "open-sse/config/errorConfig.js";
5
+ import { resolveProviderId, FREE_PROVIDERS } from "@/shared/constants/providers.js";
6
+ import * as log from "../utils/logger.js";
7
+
8
+ // Mutex to prevent race conditions during account selection
9
+ let selectionMutex = Promise.resolve();
10
+
11
+ /**
12
+ * Get provider credentials from localDb
13
+ * Filters out unavailable accounts and returns the selected account based on strategy
14
+ * @param {string} provider - Provider name
15
+ * @param {Set<string>|string|null} excludeConnectionIds - Connection ID(s) to exclude (for retry with next account)
16
+ * @param {string|null} model - Model name for per-model rate limit filtering
17
+ */
18
+ export async function getProviderCredentials(provider, excludeConnectionIds = null, model = null, options = {}) {
19
+ // Normalize to Set for consistent handling
20
+ const excludeSet = excludeConnectionIds instanceof Set
21
+ ? excludeConnectionIds
22
+ : (excludeConnectionIds ? new Set([excludeConnectionIds]) : new Set());
23
+ const preferredConnectionId = options?.preferredConnectionId || null;
24
+ const strictPreferred = !!options?.strictPreferred;
25
+ // Acquire mutex to prevent race conditions
26
+ const currentMutex = selectionMutex;
27
+ let resolveMutex;
28
+ selectionMutex = new Promise(resolve => { resolveMutex = resolve; });
29
+
30
+ try {
31
+ await currentMutex;
32
+
33
+ // Resolve alias to provider ID (e.g., "kc" -> "kilocode")
34
+ const providerId = resolveProviderId(provider);
35
+
36
+ // Inject a virtual connection for no-auth free providers (with optional proxy pool from settings)
37
+ if (FREE_PROVIDERS[providerId]?.noAuth) {
38
+ const settings = await getSettings();
39
+ const override = (settings.providerStrategies || {})[providerId] || {};
40
+ const resolvedProxy = await resolveConnectionProxyConfig({ proxyPoolId: override.proxyPoolId || "" });
41
+ return {
42
+ id: "noauth",
43
+ connectionName: "Public",
44
+ isActive: true,
45
+ accessToken: "public",
46
+ providerSpecificData: {
47
+ connectionProxyEnabled: resolvedProxy.connectionProxyEnabled,
48
+ connectionProxyUrl: resolvedProxy.connectionProxyUrl,
49
+ connectionNoProxy: resolvedProxy.connectionNoProxy,
50
+ connectionProxyPoolId: resolvedProxy.proxyPoolId || null,
51
+ vercelRelayUrl: resolvedProxy.vercelRelayUrl || "",
52
+ },
53
+ };
54
+ }
55
+
56
+ const connections = await getProviderConnections({ provider: providerId, isActive: true });
57
+ log.debug("AUTH", `${provider} | total connections: ${connections.length}, excludeIds: ${excludeSet.size > 0 ? [...excludeSet].join(",") : "none"}, model: ${model || "any"}`);
58
+
59
+ if (connections.length === 0) {
60
+ log.warn("AUTH", `No credentials for ${provider}`);
61
+ return null;
62
+ }
63
+
64
+ const baseAvailableConnections = connections.filter(c => {
65
+ if (excludeSet.has(c.id)) return false;
66
+ if (isModelLockActive(c, model)) return false;
67
+ return true;
68
+ });
69
+
70
+ // Filter out model-locked and excluded connections. Strict pinning is used
71
+ // by Codex gateway account aliases, where silently switching identity would
72
+ // break the user's mental model of "this session/account".
73
+ let availableConnections = baseAvailableConnections;
74
+ if (strictPreferred && preferredConnectionId) {
75
+ const preferred = connections.find((c) => c.id === preferredConnectionId);
76
+ if (!preferred) {
77
+ log.warn("AUTH", `${provider} | pinned account not found: ${preferredConnectionId}`);
78
+ return null;
79
+ }
80
+ if (excludeSet.has(preferred.id)) {
81
+ log.warn("AUTH", `${provider} | pinned account excluded after failure: ${preferred.id?.slice(0, 8)}`);
82
+ return null;
83
+ }
84
+ if (isModelLockActive(preferred, model)) {
85
+ const retryAfter = getEarliestModelLockUntil(preferred);
86
+ return {
87
+ allRateLimited: true,
88
+ retryAfter,
89
+ retryAfterHuman: formatRetryAfter(retryAfter),
90
+ lastError: preferred.lastError || "Pinned account unavailable",
91
+ lastErrorCode: preferred.errorCode || null,
92
+ };
93
+ }
94
+ availableConnections = [preferred];
95
+ }
96
+
97
+ log.debug("AUTH", `${provider} | available: ${availableConnections.length}/${connections.length}`);
98
+ connections.forEach(c => {
99
+ const excluded = excludeSet.has(c.id);
100
+ const locked = isModelLockActive(c, model);
101
+ if (excluded || locked) {
102
+ const lockUntil = getEarliestModelLockUntil(c);
103
+ log.debug("AUTH", ` → ${c.id?.slice(0, 8)} | ${excluded ? "excluded" : ""} ${locked ? `modelLocked(${model}) until ${lockUntil}` : ""}`);
104
+ }
105
+ });
106
+
107
+ if (availableConnections.length === 0) {
108
+ // Find earliest lock expiry across all connections for retry timing
109
+ const lockedConns = connections.filter(c => isModelLockActive(c, model));
110
+ const expiries = lockedConns.map(c => getEarliestModelLockUntil(c)).filter(Boolean);
111
+ const earliest = expiries.sort()[0] || null;
112
+ if (earliest) {
113
+ const earliestConn = lockedConns[0];
114
+ log.warn("AUTH", `${provider} | all ${connections.length} accounts locked for ${model || "all"} (${formatRetryAfter(earliest)}) | lastError=${earliestConn?.lastError?.slice(0, 50)}`);
115
+ return {
116
+ allRateLimited: true,
117
+ retryAfter: earliest,
118
+ retryAfterHuman: formatRetryAfter(earliest),
119
+ lastError: earliestConn?.lastError || null,
120
+ lastErrorCode: earliestConn?.errorCode || null
121
+ };
122
+ }
123
+ log.warn("AUTH", `${provider} | all ${connections.length} accounts unavailable`);
124
+ return null;
125
+ }
126
+
127
+ const settings = await getSettings();
128
+ // Per-provider strategy overrides global setting
129
+ const providerOverride = (settings.providerStrategies || {})[providerId] || {};
130
+ const strategy = providerOverride.fallbackStrategy || settings.fallbackStrategy || "fill-first";
131
+
132
+ let connection;
133
+ // Pin to preferred connection if specified and available
134
+ if (preferredConnectionId) {
135
+ connection = availableConnections.find((c) => c.id === preferredConnectionId);
136
+ if (connection) {
137
+ log.info("AUTH", `${provider} | pinned to ${connection.id?.slice(0, 8)} (${connection.name || connection.email || "unnamed"})`);
138
+ }
139
+ }
140
+ if (connection) {
141
+ // skip strategy
142
+ } else if (strictPreferred && preferredConnectionId) {
143
+ log.warn("AUTH", `${provider} | pinned account unavailable: ${preferredConnectionId}`);
144
+ return null;
145
+ } else if (strategy === "round-robin") {
146
+ const stickyLimit = providerOverride.stickyRoundRobinLimit || settings.stickyRoundRobinLimit || 3;
147
+
148
+ // Sort by lastUsed (most recent first) to find current candidate
149
+ const byRecency = [...availableConnections].sort((a, b) => {
150
+ if (!a.lastUsedAt && !b.lastUsedAt) return (a.priority || 999) - (b.priority || 999);
151
+ if (!a.lastUsedAt) return 1;
152
+ if (!b.lastUsedAt) return -1;
153
+ return new Date(b.lastUsedAt) - new Date(a.lastUsedAt);
154
+ });
155
+
156
+ const current = byRecency[0];
157
+ const currentCount = current?.consecutiveUseCount || 0;
158
+
159
+ if (current && current.lastUsedAt && currentCount < stickyLimit) {
160
+ // Stay with current account
161
+ connection = current;
162
+ // Update lastUsedAt and increment count (await to ensure persistence)
163
+ await updateProviderConnection(connection.id, {
164
+ lastUsedAt: new Date().toISOString(),
165
+ consecutiveUseCount: (connection.consecutiveUseCount || 0) + 1
166
+ });
167
+ } else {
168
+ // Pick the least recently used (excluding current if possible)
169
+ const sortedByOldest = [...availableConnections].sort((a, b) => {
170
+ if (!a.lastUsedAt && !b.lastUsedAt) return (a.priority || 999) - (b.priority || 999);
171
+ if (!a.lastUsedAt) return -1;
172
+ if (!b.lastUsedAt) return 1;
173
+ return new Date(a.lastUsedAt) - new Date(b.lastUsedAt);
174
+ });
175
+
176
+ connection = sortedByOldest[0];
177
+
178
+ // Update lastUsedAt and reset count to 1 (await to ensure persistence)
179
+ await updateProviderConnection(connection.id, {
180
+ lastUsedAt: new Date().toISOString(),
181
+ consecutiveUseCount: 1
182
+ });
183
+ }
184
+ } else {
185
+ // Default: fill-first (already sorted by priority in getProviderConnections)
186
+ connection = availableConnections[0];
187
+ }
188
+
189
+ const resolvedProxy = await resolveConnectionProxyConfig(connection.providerSpecificData || {});
190
+
191
+ return {
192
+ authType: connection.authType,
193
+ apiKey: connection.apiKey,
194
+ accessToken: connection.accessToken,
195
+ refreshToken: connection.refreshToken,
196
+ idToken: connection.idToken,
197
+ expiresAt: connection.expiresAt,
198
+ expiresIn: connection.expiresIn,
199
+ lastRefreshAt: connection.lastRefreshAt,
200
+ projectId: connection.projectId,
201
+ connectionName: connection.displayName || connection.name || connection.email || connection.id,
202
+ copilotToken: connection.providerSpecificData?.copilotToken,
203
+ providerSpecificData: {
204
+ ...(connection.providerSpecificData || {}),
205
+ connectionProxyEnabled: resolvedProxy.connectionProxyEnabled,
206
+ connectionProxyUrl: resolvedProxy.connectionProxyUrl,
207
+ connectionNoProxy: resolvedProxy.connectionNoProxy,
208
+ connectionProxyPoolId: resolvedProxy.proxyPoolId || null,
209
+ vercelRelayUrl: resolvedProxy.vercelRelayUrl || "",
210
+ },
211
+ connectionId: connection.id,
212
+ // Include current status for optimization check
213
+ testStatus: connection.testStatus,
214
+ lastError: connection.lastError,
215
+ // Pass full connection for clearAccountError to read modelLock_* keys
216
+ _connection: connection
217
+ };
218
+ } finally {
219
+ if (resolveMutex) resolveMutex();
220
+ }
221
+ }
222
+
223
+ /**
224
+ * Mark account+model as unavailable — locks modelLock_${model} in DB.
225
+ * All errors (429, 401, 5xx, etc.) lock per model, not per account.
226
+ * @param {string} connectionId
227
+ * @param {number} status - HTTP status code from upstream
228
+ * @param {string} errorText
229
+ * @param {string|null} provider
230
+ * @param {string|null} model - The specific model that triggered the error
231
+ * @returns {{ shouldFallback: boolean, cooldownMs: number }}
232
+ */
233
+ export async function markAccountUnavailable(connectionId, status, errorText, provider = null, model = null, resetsAtMs = null) {
234
+ if (!connectionId || connectionId === "noauth") return { shouldFallback: false, cooldownMs: 0 };
235
+ if (isNonAccountError(status, errorText)) {
236
+ log.warn("AUTH", `non-account error; no fallback [${status}] ${typeof errorText === "string" ? errorText.slice(0, 100) : "Provider error"}`);
237
+ return { shouldFallback: false, cooldownMs: 0 };
238
+ }
239
+ const connections = await getProviderConnections({ provider });
240
+ const conn = connections.find(c => c.id === connectionId);
241
+ const backoffLevel = conn?.backoffLevel || 0;
242
+
243
+ // Provider-specific precise cooldown (e.g. codex usage_limit_reached resets_at) overrides backoff
244
+ let shouldFallback, cooldownMs, newBackoffLevel;
245
+ if (resetsAtMs && resetsAtMs > Date.now()) {
246
+ shouldFallback = true;
247
+ cooldownMs = Math.min(resetsAtMs - Date.now(), MAX_RATE_LIMIT_COOLDOWN_MS);
248
+ newBackoffLevel = 0;
249
+ } else {
250
+ ({ shouldFallback, cooldownMs, newBackoffLevel } = checkFallbackError(status, errorText, backoffLevel));
251
+ }
252
+ if (!shouldFallback) return { shouldFallback: false, cooldownMs: 0 };
253
+
254
+ const reason = typeof errorText === "string" ? errorText.slice(0, 100) : "Provider error";
255
+ const lockUpdate = buildModelLockUpdate(model, cooldownMs);
256
+
257
+ await updateProviderConnection(connectionId, {
258
+ ...lockUpdate,
259
+ testStatus: "unavailable",
260
+ lastError: reason,
261
+ errorCode: status,
262
+ lastErrorAt: new Date().toISOString(),
263
+ backoffLevel: newBackoffLevel ?? backoffLevel
264
+ });
265
+
266
+ const lockKey = Object.keys(lockUpdate)[0];
267
+ const connName = conn?.displayName || conn?.name || conn?.email || connectionId.slice(0, 8);
268
+ log.warn("AUTH", `${connName} locked ${lockKey} for ${Math.round(cooldownMs / 1000)}s [${status}]`);
269
+
270
+ if (provider && status && reason) {
271
+ console.error(`❌ ${provider} [${status}]: ${reason}`);
272
+ }
273
+
274
+ return { shouldFallback: true, cooldownMs };
275
+ }
276
+
277
+ /**
278
+ * Clear account error status on successful request.
279
+ * - Clears modelLock_${model} (the model that just succeeded)
280
+ * - Lazy-cleans any other expired modelLock_* keys
281
+ * - Resets error state only if no active locks remain
282
+ * @param {string} connectionId
283
+ * @param {object} currentConnection - credentials object (has _connection) or raw connection
284
+ * @param {string|null} model - model that succeeded
285
+ */
286
+ export async function clearAccountError(connectionId, currentConnection, model = null) {
287
+ if (!connectionId || connectionId === "noauth") return;
288
+ const conn = currentConnection._connection || currentConnection;
289
+ const now = Date.now();
290
+ const allLockKeys = Object.keys(conn).filter(k => k.startsWith("modelLock_"));
291
+
292
+ if (!conn.testStatus && !conn.lastError && allLockKeys.length === 0) return;
293
+
294
+ // Keys to clear: current model's lock + all expired locks
295
+ const keysToClear = allLockKeys.filter(k => {
296
+ if (model && k === `modelLock_${model}`) return true; // succeeded model
297
+ if (model && k === "modelLock___all") return true; // account-level lock
298
+ const expiry = conn[k];
299
+ return expiry && new Date(expiry).getTime() <= now; // expired
300
+ });
301
+
302
+ if (keysToClear.length === 0 && conn.testStatus !== "unavailable" && !conn.lastError) return;
303
+
304
+ // Check if any active locks remain after clearing
305
+ const remainingActiveLocks = allLockKeys.filter(k => {
306
+ if (keysToClear.includes(k)) return false;
307
+ const expiry = conn[k];
308
+ return expiry && new Date(expiry).getTime() > now;
309
+ });
310
+
311
+ const clearObj = Object.fromEntries(keysToClear.map(k => [k, null]));
312
+
313
+ // Only reset error state if no active locks remain
314
+ if (remainingActiveLocks.length === 0) {
315
+ Object.assign(clearObj, { testStatus: "active", lastError: null, lastErrorAt: null, backoffLevel: 0 });
316
+ }
317
+
318
+ await updateProviderConnection(connectionId, clearObj);
319
+ }
320
+
321
+ /**
322
+ * Extract API key from request headers
323
+ */
324
+ export function extractApiKey(request) {
325
+ // Check Authorization header first
326
+ const authHeader = request.headers.get("Authorization");
327
+ if (authHeader?.startsWith("Bearer ")) {
328
+ return authHeader.slice(7);
329
+ }
330
+
331
+ // Check Anthropic x-api-key header
332
+ const xApiKey = request.headers.get("x-api-key");
333
+ if (xApiKey) {
334
+ return xApiKey;
335
+ }
336
+
337
+ return null;
338
+ }
339
+
340
+ /**
341
+ * Validate API key (optional - for local use can skip)
342
+ */
343
+ export async function isValidApiKey(apiKey) {
344
+ if (!apiKey) return false;
345
+ return await validateApiKey(apiKey);
346
+ }
@@ -0,0 +1,215 @@
1
+ import { getProviderConnections, getSettings } from "@/lib/localDb";
2
+ import { PROVIDER_MODELS } from "open-sse/config/providerModels.js";
3
+
4
+ export const CODEX_GATEWAY_DEFAULT_MODEL = "gpt-5.5";
5
+ export const CODEX_GATEWAY_ACCOUNT_LIMIT = 5000;
6
+
7
+ function cleanSegment(value) {
8
+ return String(value || "").trim().replace(/^\/+|\/+$/g, "");
9
+ }
10
+
11
+ function stripCodexPrefix(model) {
12
+ const value = cleanSegment(model);
13
+ if (value.startsWith("cx/")) return value.slice(3);
14
+ if (value.startsWith("codex/")) return value.slice(6);
15
+ return value || CODEX_GATEWAY_DEFAULT_MODEL;
16
+ }
17
+
18
+ function normalizeRouterTarget(value) {
19
+ const target = cleanSegment(value) || CODEX_GATEWAY_DEFAULT_MODEL;
20
+ if (!target.includes("/")) return `cx/${target}`;
21
+ return target;
22
+ }
23
+
24
+ function normalizeCodexTarget(value) {
25
+ return `cx/${stripCodexPrefix(value)}`;
26
+ }
27
+
28
+ export function parseCodexGatewayModel(modelStr) {
29
+ const value = cleanSegment(modelStr);
30
+ if (!value) return null;
31
+
32
+ if (value === "auto-codex") {
33
+ return {
34
+ mode: "router",
35
+ modelString: `cx/${CODEX_GATEWAY_DEFAULT_MODEL}`,
36
+ strictAccount: false,
37
+ label: "Auto Codex",
38
+ };
39
+ }
40
+
41
+ if (value.startsWith("router/")) {
42
+ return {
43
+ mode: "router",
44
+ modelString: normalizeRouterTarget(value.slice("router/".length)),
45
+ strictAccount: false,
46
+ label: "Router Pool",
47
+ };
48
+ }
49
+
50
+ if (value.startsWith("original/")) {
51
+ return {
52
+ mode: "original",
53
+ modelString: normalizeCodexTarget(value.slice("original/".length)),
54
+ strictAccount: true,
55
+ label: "Original Codex",
56
+ };
57
+ }
58
+
59
+ if (value === "original") {
60
+ return {
61
+ mode: "original",
62
+ modelString: `cx/${CODEX_GATEWAY_DEFAULT_MODEL}`,
63
+ strictAccount: true,
64
+ label: "Original Codex",
65
+ };
66
+ }
67
+
68
+ const accountPrefix = value.startsWith("account/")
69
+ ? "account/"
70
+ : (value.startsWith("codex-account/") ? "codex-account/" : null);
71
+ if (accountPrefix) {
72
+ const rest = value.slice(accountPrefix.length);
73
+ const slash = rest.indexOf("/");
74
+ const accountRef = slash === -1 ? rest : rest.slice(0, slash);
75
+ const model = slash === -1 ? CODEX_GATEWAY_DEFAULT_MODEL : rest.slice(slash + 1);
76
+ if (!accountRef) return null;
77
+ return {
78
+ mode: "account",
79
+ accountRef,
80
+ modelString: normalizeCodexTarget(model),
81
+ strictAccount: true,
82
+ label: "Pinned Codex Account",
83
+ };
84
+ }
85
+
86
+ return null;
87
+ }
88
+
89
+ export function getCodexConnectionLabel(connection) {
90
+ return (
91
+ connection?.displayName ||
92
+ connection?.name ||
93
+ connection?.email ||
94
+ connection?.id ||
95
+ "Codex account"
96
+ );
97
+ }
98
+
99
+ export function slugifyCodexAccount(connection) {
100
+ const raw = getCodexConnectionLabel(connection);
101
+ const base = String(raw)
102
+ .toLowerCase()
103
+ .replace(/@/g, "-")
104
+ .replace(/[^a-z0-9]+/g, "-")
105
+ .replace(/^-+|-+$/g, "")
106
+ .slice(0, 48) || "account";
107
+ return `${base}-${String(connection?.id || "").slice(0, 8)}`;
108
+ }
109
+
110
+ function normalizeRef(value) {
111
+ return String(value || "").trim().toLowerCase();
112
+ }
113
+
114
+ function isImportedGptJson(connection) {
115
+ const data = connection?.providerSpecificData || {};
116
+ return data.importedFrom === "GPTJson" || String(data.tokenSource || "").startsWith("ChatGPT_team");
117
+ }
118
+
119
+ export async function listCodexGatewayAccounts(limit = CODEX_GATEWAY_ACCOUNT_LIMIT) {
120
+ const connections = await getProviderConnections({ provider: "codex", isActive: true });
121
+ const accounts = connections.slice(0, limit).map((connection) => ({
122
+ id: connection.id,
123
+ slug: slugifyCodexAccount(connection),
124
+ label: getCodexConnectionLabel(connection),
125
+ email: connection.email || null,
126
+ imported: isImportedGptJson(connection),
127
+ priority: connection.priority || null,
128
+ }));
129
+
130
+ const original = findOriginalCodexConnection(connections);
131
+ return {
132
+ accounts,
133
+ original: original ? {
134
+ id: original.id,
135
+ slug: slugifyCodexAccount(original),
136
+ label: getCodexConnectionLabel(original),
137
+ email: original.email || null,
138
+ imported: isImportedGptJson(original),
139
+ priority: original.priority || null,
140
+ } : null,
141
+ };
142
+ }
143
+
144
+ export function findOriginalCodexConnection(connections) {
145
+ if (!Array.isArray(connections) || connections.length === 0) return null;
146
+ return connections.find((connection) => !isImportedGptJson(connection)) || connections[0];
147
+ }
148
+
149
+ export async function resolveCodexConnectionRef(ref) {
150
+ const target = normalizeRef(ref);
151
+ if (!target) return null;
152
+ const connections = await getProviderConnections({ provider: "codex", isActive: true });
153
+
154
+ const exact = connections.find((connection) => (
155
+ normalizeRef(connection.id) === target ||
156
+ slugifyCodexAccount(connection) === target ||
157
+ normalizeRef(connection.email) === target ||
158
+ normalizeRef(connection.name) === target ||
159
+ normalizeRef(connection.displayName) === target
160
+ ));
161
+ if (exact) return exact;
162
+
163
+ const prefixMatches = connections.filter((connection) => (
164
+ normalizeRef(connection.id).startsWith(target) ||
165
+ slugifyCodexAccount(connection).startsWith(target)
166
+ ));
167
+ if (prefixMatches.length === 1) return prefixMatches[0];
168
+
169
+ return null;
170
+ }
171
+
172
+ export async function resolveCodexGatewayConnection(gateway) {
173
+ if (!gateway || (gateway.mode !== "original" && gateway.mode !== "account")) return null;
174
+
175
+ if (gateway.mode === "account") {
176
+ return resolveCodexConnectionRef(gateway.accountRef);
177
+ }
178
+
179
+ const settings = await getSettings();
180
+ const configuredId = settings.codexGatewayOriginalConnectionId || settings.codexOriginalConnectionId || "";
181
+ if (configuredId) {
182
+ const configured = await resolveCodexConnectionRef(configuredId);
183
+ if (configured) return configured;
184
+ }
185
+
186
+ const connections = await getProviderConnections({ provider: "codex", isActive: true });
187
+ return findOriginalCodexConnection(connections);
188
+ }
189
+
190
+ export function buildCodexGatewayModelEntries(connections = []) {
191
+ const hasCodex = connections.some((connection) => connection.provider === "codex" && connection.isActive !== false);
192
+ if (!hasCodex) return [];
193
+
194
+ const codexModels = (PROVIDER_MODELS.cx || [])
195
+ .filter((model) => !model.type || model.type === "llm")
196
+ .map((model) => model.id);
197
+
198
+ const entries = [
199
+ { id: "auto-codex", object: "model", owned_by: "9router-codex-gateway" },
200
+ ...codexModels.flatMap((model) => [
201
+ { id: `router/${model}`, object: "model", owned_by: "9router-codex-gateway" },
202
+ { id: `original/${model}`, object: "model", owned_by: "9router-codex-gateway" },
203
+ ]),
204
+ ];
205
+
206
+ for (const connection of connections.filter((conn) => conn.provider === "codex" && conn.isActive !== false)) {
207
+ entries.push({
208
+ id: `account/${slugifyCodexAccount(connection)}`,
209
+ object: "model",
210
+ owned_by: "9router-codex-account",
211
+ });
212
+ }
213
+
214
+ return entries;
215
+ }
@@ -0,0 +1,99 @@
1
+ // Re-export from open-sse with localDb integration
2
+ import { getModelAliases, getComboByName, getProviderNodes } from "@/lib/localDb";
3
+ import { parseModel as parseModelCore, resolveModelAliasFromMap, getModelInfoCore } from "open-sse/services/model.js";
4
+ import { parseCodexGatewayModel } from "./codexGateway.js";
5
+
6
+ // Local provider alias overrides (HMR-friendly, applied on top of open-sse map)
7
+ const LOCAL_PROVIDER_ALIASES = {
8
+ xmtp: "xiaomi-tokenplan",
9
+ "xiaomi-tokenplan": "xiaomi-tokenplan",
10
+ };
11
+
12
+ export function parseModel(modelStr) {
13
+ const parsed = parseModelCore(modelStr);
14
+ if (parsed?.providerAlias && LOCAL_PROVIDER_ALIASES[parsed.providerAlias]) {
15
+ return { ...parsed, provider: LOCAL_PROVIDER_ALIASES[parsed.providerAlias] };
16
+ }
17
+ return parsed;
18
+ }
19
+
20
+ /**
21
+ * Resolve model alias from localDb
22
+ */
23
+ export async function resolveModelAlias(alias) {
24
+ const aliases = await getModelAliases();
25
+ return resolveModelAliasFromMap(alias, aliases);
26
+ }
27
+
28
+ /**
29
+ * Get full model info (parse or resolve)
30
+ */
31
+ export async function getModelInfo(modelStr) {
32
+ const gateway = parseCodexGatewayModel(modelStr);
33
+ if (gateway) {
34
+ const resolved = await getModelInfo(gateway.modelString);
35
+ return {
36
+ ...resolved,
37
+ gateway: {
38
+ mode: gateway.mode,
39
+ accountRef: gateway.accountRef || null,
40
+ strictAccount: !!gateway.strictAccount,
41
+ requestedModel: modelStr,
42
+ modelString: gateway.modelString,
43
+ },
44
+ };
45
+ }
46
+
47
+ const parsed = parseModel(modelStr);
48
+
49
+ if (!parsed.isAlias) {
50
+ // Always check provider-node prefix matching using original input first
51
+ const openaiNodes = await getProviderNodes({ type: "openai-compatible" });
52
+ const matchedOpenAI = openaiNodes.find((node) => node.prefix === parsed.providerAlias);
53
+ if (matchedOpenAI) {
54
+ return { provider: matchedOpenAI.id, model: parsed.model };
55
+ }
56
+
57
+ const anthropicNodes = await getProviderNodes({ type: "anthropic-compatible" });
58
+ const matchedAnthropic = anthropicNodes.find((node) => node.prefix === parsed.providerAlias);
59
+ if (matchedAnthropic) {
60
+ return { provider: matchedAnthropic.id, model: parsed.model };
61
+ }
62
+
63
+ const embeddingNodes = await getProviderNodes({ type: "custom-embedding" });
64
+ const matchedEmbedding = embeddingNodes.find((node) => node.prefix === parsed.providerAlias);
65
+ if (matchedEmbedding) {
66
+ return { provider: matchedEmbedding.id, model: parsed.model };
67
+ }
68
+ return {
69
+ provider: parsed.provider,
70
+ model: parsed.model
71
+ };
72
+ }
73
+
74
+ // Check if this is a combo name before resolving as alias
75
+ // This prevents combo names from being incorrectly routed to providers
76
+ const combo = await getComboByName(parsed.model);
77
+ if (combo) {
78
+ // Return null provider to signal this should be handled as combo
79
+ // The caller (handleChat) will detect this and handle it as combo
80
+ return { provider: null, model: parsed.model };
81
+ }
82
+
83
+ return getModelInfoCore(modelStr, getModelAliases);
84
+ }
85
+
86
+ /**
87
+ * Check if model is a combo and get models list
88
+ * @returns {Promise<string[]|null>} Array of models or null if not a combo
89
+ */
90
+ export async function getComboModels(modelStr) {
91
+ // Only check if it's not in provider/model format
92
+ if (modelStr.includes("/")) return null;
93
+
94
+ const combo = await getComboByName(modelStr);
95
+ if (combo && combo.models && combo.models.length > 0) {
96
+ return combo.models;
97
+ }
98
+ return null;
99
+ }