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,81 @@
1
+ import { NextResponse } from "next/server";
2
+ import { getComboById, updateCombo, deleteCombo, getComboByName } from "@/lib/localDb";
3
+ import { resetComboRotation } from "open-sse/services/combo.js";
4
+
5
+ // Validate combo name: only a-z, A-Z, 0-9, -, _
6
+ const VALID_NAME_REGEX = /^[a-zA-Z0-9_.\-]+$/;
7
+
8
+ // GET /api/combos/[id] - Get combo by ID
9
+ export async function GET(request, { params }) {
10
+ try {
11
+ const { id } = await params;
12
+ const combo = await getComboById(id);
13
+
14
+ if (!combo) {
15
+ return NextResponse.json({ error: "Combo not found" }, { status: 404 });
16
+ }
17
+
18
+ return NextResponse.json(combo);
19
+ } catch (error) {
20
+ console.log("Error fetching combo:", error);
21
+ return NextResponse.json({ error: "Failed to fetch combo" }, { status: 500 });
22
+ }
23
+ }
24
+
25
+ // PUT /api/combos/[id] - Update combo
26
+ export async function PUT(request, { params }) {
27
+ try {
28
+ const { id } = await params;
29
+ const body = await request.json();
30
+
31
+ // Validate name format if provided
32
+ if (body.name) {
33
+ if (!VALID_NAME_REGEX.test(body.name)) {
34
+ return NextResponse.json({ error: "Name can only contain letters, numbers, -, _ and ." }, { status: 400 });
35
+ }
36
+
37
+ // Check if name already exists (exclude current combo)
38
+ const existing = await getComboByName(body.name);
39
+ if (existing && existing.id !== id) {
40
+ return NextResponse.json({ error: "Combo name already exists" }, { status: 400 });
41
+ }
42
+ }
43
+
44
+ // Capture previous name to invalidate rotation state on rename
45
+ const prev = await getComboById(id);
46
+ const combo = await updateCombo(id, body);
47
+
48
+ if (!combo) {
49
+ return NextResponse.json({ error: "Combo not found" }, { status: 404 });
50
+ }
51
+
52
+ // Invalidate rotation state (models/strategy/name may have changed)
53
+ if (prev?.name) resetComboRotation(prev.name);
54
+ if (combo.name && combo.name !== prev?.name) resetComboRotation(combo.name);
55
+
56
+ return NextResponse.json(combo);
57
+ } catch (error) {
58
+ console.log("Error updating combo:", error);
59
+ return NextResponse.json({ error: "Failed to update combo" }, { status: 500 });
60
+ }
61
+ }
62
+
63
+ // DELETE /api/combos/[id] - Delete combo
64
+ export async function DELETE(request, { params }) {
65
+ try {
66
+ const { id } = await params;
67
+ const prev = await getComboById(id);
68
+ const success = await deleteCombo(id);
69
+
70
+ if (!success) {
71
+ return NextResponse.json({ error: "Combo not found" }, { status: 404 });
72
+ }
73
+
74
+ if (prev?.name) resetComboRotation(prev.name);
75
+
76
+ return NextResponse.json({ success: true });
77
+ } catch (error) {
78
+ console.log("Error deleting combo:", error);
79
+ return NextResponse.json({ error: "Failed to delete combo" }, { status: 500 });
80
+ }
81
+ }
@@ -0,0 +1,48 @@
1
+ import { NextResponse } from "next/server";
2
+ import { getCombos, createCombo, getComboByName } from "@/lib/localDb";
3
+
4
+ export const dynamic = "force-dynamic";
5
+
6
+ // Validate combo name: only a-z, A-Z, 0-9, -, _
7
+ const VALID_NAME_REGEX = /^[a-zA-Z0-9_.\-]+$/;
8
+
9
+ // GET /api/combos - Get all combos
10
+ export async function GET() {
11
+ try {
12
+ const combos = await getCombos();
13
+ return NextResponse.json({ combos });
14
+ } catch (error) {
15
+ console.log("Error fetching combos:", error);
16
+ return NextResponse.json({ error: "Failed to fetch combos" }, { status: 500 });
17
+ }
18
+ }
19
+
20
+ // POST /api/combos - Create new combo
21
+ export async function POST(request) {
22
+ try {
23
+ const body = await request.json();
24
+ const { name, models, kind } = body;
25
+
26
+ if (!name) {
27
+ return NextResponse.json({ error: "Name is required" }, { status: 400 });
28
+ }
29
+
30
+ // Validate name format
31
+ if (!VALID_NAME_REGEX.test(name)) {
32
+ return NextResponse.json({ error: "Name can only contain letters, numbers, -, _ and ." }, { status: 400 });
33
+ }
34
+
35
+ // Check if name already exists
36
+ const existing = await getComboByName(name);
37
+ if (existing) {
38
+ return NextResponse.json({ error: "Combo name already exists" }, { status: 400 });
39
+ }
40
+
41
+ const combo = await createCombo({ name, models: models || [], kind: kind || null });
42
+
43
+ return NextResponse.json(combo, { status: 201 });
44
+ } catch (error) {
45
+ console.log("Error creating combo:", error);
46
+ return NextResponse.json({ error: "Failed to create combo" }, { status: 500 });
47
+ }
48
+ }
@@ -0,0 +1,15 @@
1
+ import { NextResponse } from "next/server";
2
+
3
+ const CORS_HEADERS = {
4
+ "Access-Control-Allow-Origin": "*",
5
+ "Access-Control-Allow-Methods": "GET, OPTIONS",
6
+ "Access-Control-Allow-Headers": "*",
7
+ };
8
+
9
+ export async function GET() {
10
+ return NextResponse.json({ ok: true }, { headers: CORS_HEADERS });
11
+ }
12
+
13
+ export async function OPTIONS() {
14
+ return new NextResponse(null, { status: 204, headers: CORS_HEADERS });
15
+ }
@@ -0,0 +1,4 @@
1
+ // This API route is called automatically to initialize app
2
+ export async function GET() {
3
+ return new Response("Initialized", { status: 200 });
4
+ }
@@ -0,0 +1,58 @@
1
+ import { NextResponse } from "next/server";
2
+ import { deleteApiKey, getApiKeyById, updateApiKey } from "@/lib/localDb";
3
+
4
+ // GET /api/keys/[id] - Get single key
5
+ export async function GET(request, { params }) {
6
+ try {
7
+ const { id } = await params;
8
+ const key = await getApiKeyById(id);
9
+ if (!key) {
10
+ return NextResponse.json({ error: "Key not found" }, { status: 404 });
11
+ }
12
+ return NextResponse.json({ key });
13
+ } catch (error) {
14
+ console.log("Error fetching key:", error);
15
+ return NextResponse.json({ error: "Failed to fetch key" }, { status: 500 });
16
+ }
17
+ }
18
+
19
+ // PUT /api/keys/[id] - Update key
20
+ export async function PUT(request, { params }) {
21
+ try {
22
+ const { id } = await params;
23
+ const body = await request.json();
24
+ const { isActive } = body;
25
+
26
+ const existing = await getApiKeyById(id);
27
+ if (!existing) {
28
+ return NextResponse.json({ error: "Key not found" }, { status: 404 });
29
+ }
30
+
31
+ const updateData = {};
32
+ if (isActive !== undefined) updateData.isActive = isActive;
33
+
34
+ const updated = await updateApiKey(id, updateData);
35
+
36
+ return NextResponse.json({ key: updated });
37
+ } catch (error) {
38
+ console.log("Error updating key:", error);
39
+ return NextResponse.json({ error: "Failed to update key" }, { status: 500 });
40
+ }
41
+ }
42
+
43
+ // DELETE /api/keys/[id] - Delete API key
44
+ export async function DELETE(request, { params }) {
45
+ try {
46
+ const { id } = await params;
47
+
48
+ const deleted = await deleteApiKey(id);
49
+ if (!deleted) {
50
+ return NextResponse.json({ error: "Key not found" }, { status: 404 });
51
+ }
52
+
53
+ return NextResponse.json({ message: "Key deleted successfully" });
54
+ } catch (error) {
55
+ console.log("Error deleting key:", error);
56
+ return NextResponse.json({ error: "Failed to delete key" }, { status: 500 });
57
+ }
58
+ }
@@ -0,0 +1,42 @@
1
+ import { NextResponse } from "next/server";
2
+ import { getApiKeys, createApiKey } from "@/lib/localDb";
3
+ import { getConsistentMachineId } from "@/shared/utils/machineId";
4
+
5
+ export const dynamic = "force-dynamic";
6
+
7
+ // GET /api/keys - List API keys
8
+ export async function GET() {
9
+ try {
10
+ const keys = await getApiKeys();
11
+ return NextResponse.json({ keys });
12
+ } catch (error) {
13
+ console.log("Error fetching keys:", error);
14
+ return NextResponse.json({ error: "Failed to fetch keys" }, { status: 500 });
15
+ }
16
+ }
17
+
18
+ // POST /api/keys - Create new API key
19
+ export async function POST(request) {
20
+ try {
21
+ const body = await request.json();
22
+ const { name } = body;
23
+
24
+ if (!name) {
25
+ return NextResponse.json({ error: "Name is required" }, { status: 400 });
26
+ }
27
+
28
+ // Always get machineId from server
29
+ const machineId = await getConsistentMachineId();
30
+ const apiKey = await createApiKey(name, machineId);
31
+
32
+ return NextResponse.json({
33
+ key: apiKey.key,
34
+ name: apiKey.name,
35
+ id: apiKey.id,
36
+ machineId: apiKey.machineId,
37
+ }, { status: 201 });
38
+ } catch (error) {
39
+ console.log("Error creating key:", error);
40
+ return NextResponse.json({ error: "Failed to create key" }, { status: 500 });
41
+ }
42
+ }
@@ -0,0 +1,30 @@
1
+ import { cookies } from "next/headers";
2
+ import { NextResponse } from "next/server";
3
+ import { LOCALE_COOKIE, normalizeLocale, isSupportedLocale } from "@/i18n/config";
4
+
5
+ export async function POST(request) {
6
+ try {
7
+ const { locale } = await request.json();
8
+
9
+ if (!locale || !isSupportedLocale(locale)) {
10
+ return NextResponse.json(
11
+ { error: "Invalid locale" },
12
+ { status: 400 }
13
+ );
14
+ }
15
+
16
+ const normalized = normalizeLocale(locale);
17
+ const cookieStore = await cookies();
18
+ cookieStore.set(LOCALE_COOKIE, normalized, {
19
+ path: "/",
20
+ maxAge: 60 * 60 * 24 * 365, // 1 year
21
+ });
22
+
23
+ return NextResponse.json({ success: true, locale: normalized });
24
+ } catch (error) {
25
+ return NextResponse.json(
26
+ { error: "Failed to set locale" },
27
+ { status: 500 }
28
+ );
29
+ }
30
+ }
@@ -0,0 +1,21 @@
1
+ import { NextResponse } from "next/server";
2
+ import { sendToChild, findPlugin } from "@/lib/mcp/stdioSseBridge";
3
+
4
+ export const runtime = "nodejs";
5
+ export const dynamic = "force-dynamic";
6
+
7
+ export async function POST(request, { params }) {
8
+ // Cowork disabled: MCP stdio bridge spawns arbitrary processes (RCE risk).
9
+ return NextResponse.json({ error: "Cowork is disabled" }, { status: 403 });
10
+ const { plugin } = await params;
11
+ if (!findPlugin(plugin)) {
12
+ return NextResponse.json({ error: `Unknown plugin: ${plugin}` }, { status: 404 });
13
+ }
14
+ try {
15
+ const body = await request.json();
16
+ sendToChild(plugin, body);
17
+ return new Response(null, { status: 202 });
18
+ } catch (e) {
19
+ return NextResponse.json({ error: e.message }, { status: 500 });
20
+ }
21
+ }
@@ -0,0 +1,37 @@
1
+ import { registerSession, unregisterSession, findPlugin } from "@/lib/mcp/stdioSseBridge";
2
+
3
+ export const runtime = "nodejs";
4
+ export const dynamic = "force-dynamic";
5
+
6
+ export async function GET(request, { params }) {
7
+ // Cowork disabled: MCP stdio bridge spawns arbitrary processes (RCE risk).
8
+ return new Response("Cowork is disabled", { status: 403 });
9
+ const { plugin } = await params;
10
+ if (!findPlugin(plugin)) {
11
+ return new Response(`Unknown plugin: ${plugin}`, { status: 404 });
12
+ }
13
+
14
+ const encoder = new TextEncoder();
15
+ let sid;
16
+
17
+ const stream = new ReadableStream({
18
+ start(controller) {
19
+ const send = (chunk) => controller.enqueue(encoder.encode(chunk));
20
+ sid = registerSession(plugin, send);
21
+ // MCP SSE handshake: tell client where to POST messages.
22
+ send(`event: endpoint\ndata: /api/mcp/${plugin}/message?sessionId=${sid}\n\n`);
23
+ },
24
+ cancel() {
25
+ if (sid) unregisterSession(plugin, sid);
26
+ },
27
+ });
28
+
29
+ return new Response(stream, {
30
+ headers: {
31
+ "Content-Type": "text/event-stream",
32
+ "Cache-Control": "no-cache, no-transform",
33
+ Connection: "keep-alive",
34
+ "X-Accel-Buffering": "no",
35
+ },
36
+ });
37
+ }
@@ -0,0 +1,65 @@
1
+ import { NextResponse } from "next/server";
2
+ import { getProviderConnections } from "@/lib/localDb";
3
+
4
+ const langNames = new Intl.DisplayNames(["en"], { type: "language" });
5
+
6
+ /**
7
+ * GET /api/media-providers/tts/deepgram/voices[?lang=en]
8
+ * Returns { languages, byLang } grouped by language code (same shape as edge-tts/elevenlabs/inworld)
9
+ * Each Deepgram voice = one model (canonical_name like "aura-2-thalia-en")
10
+ */
11
+ export async function GET(request) {
12
+ try {
13
+ const { searchParams } = new URL(request.url);
14
+ const langFilter = searchParams.get("lang");
15
+
16
+ const connections = await getProviderConnections({ provider: "deepgram", isActive: true });
17
+ const apiKey = connections[0]?.apiKey;
18
+ if (!apiKey) return NextResponse.json({ error: "No Deepgram connection found" }, { status: 400 });
19
+
20
+ const res = await fetch("https://api.deepgram.com/v1/models", {
21
+ headers: { "Authorization": `Token ${apiKey}` },
22
+ });
23
+ if (!res.ok) {
24
+ const text = await res.text().catch(() => "");
25
+ return NextResponse.json({ error: `Deepgram API ${res.status}: ${text || "Failed"}` }, { status: 502 });
26
+ }
27
+ const data = await res.json();
28
+ const ttsModels = data.tts || [];
29
+
30
+ const byLang = {};
31
+ for (const m of ttsModels) {
32
+ // Deepgram returns `languages: ["en"]` or sometimes language inferred from canonical_name suffix
33
+ const langs = Array.isArray(m.languages) && m.languages.length
34
+ ? m.languages
35
+ : [m.canonical_name?.split("-").pop() || "en"];
36
+ for (const code of langs) {
37
+ if (!byLang[code]) {
38
+ byLang[code] = {
39
+ code,
40
+ name: (() => { try { return langNames.of(code); } catch { return code; } })(),
41
+ voices: [],
42
+ };
43
+ }
44
+ const voiceId = m.canonical_name || m.name;
45
+ if (!byLang[code].voices.find((x) => x.id === voiceId)) {
46
+ byLang[code].voices.push({
47
+ id: voiceId,
48
+ name: m.name || voiceId,
49
+ gender: m.metadata?.tags?.find((t) => t === "masculine" || t === "feminine") || "",
50
+ lang: code,
51
+ });
52
+ }
53
+ }
54
+ }
55
+
56
+ const languages = Object.values(byLang).sort((a, b) => a.name.localeCompare(b.name));
57
+
58
+ if (langFilter) {
59
+ return NextResponse.json({ voices: byLang[langFilter]?.voices || [] });
60
+ }
61
+ return NextResponse.json({ languages, byLang });
62
+ } catch (err) {
63
+ return NextResponse.json({ error: err.message || "Failed to fetch voices" }, { status: 502 });
64
+ }
65
+ }
@@ -0,0 +1,71 @@
1
+ import { NextResponse } from "next/server";
2
+ import { getProviderConnections } from "@/lib/localDb";
3
+ import { fetchElevenLabsVoices } from "open-sse/handlers/ttsCore.js";
4
+
5
+ const langNames = new Intl.DisplayNames(["en"], { type: "language" });
6
+
7
+ /**
8
+ * GET /api/media-providers/tts/elevenlabs/voices[?lang=en]
9
+ * Returns { languages, byLang } grouped by language - same format as edge-tts
10
+ * Uses direct DB read (no mutex) to avoid blocking on concurrent TTS requests
11
+ */
12
+ export async function GET(request) {
13
+ try {
14
+ const { searchParams } = new URL(request.url);
15
+ const langFilter = searchParams.get("lang");
16
+
17
+ // Direct DB read - bypass auth mutex used for TTS inference
18
+ const connections = await getProviderConnections({ provider: "elevenlabs", isActive: true });
19
+ const apiKey = connections[0]?.apiKey;
20
+ if (!apiKey) {
21
+ return NextResponse.json({ error: "No ElevenLabs connection found" }, { status: 400 });
22
+ }
23
+
24
+ const voices = await fetchElevenLabsVoices(apiKey);
25
+
26
+ // Group by all supported languages (verified_languages + labels.language)
27
+ const byLang = {};
28
+ const addToLang = (code, voice) => {
29
+ if (!byLang[code]) {
30
+ byLang[code] = {
31
+ code,
32
+ name: (() => { try { return langNames.of(code); } catch { return code; } })(),
33
+ voices: [],
34
+ };
35
+ }
36
+ // Avoid duplicate voice in same lang
37
+ if (!byLang[code].voices.find((v) => v.id === voice.voice_id)) {
38
+ byLang[code].voices.push({
39
+ id: voice.voice_id,
40
+ name: voice.name,
41
+ gender: voice.labels?.gender || "",
42
+ lang: code,
43
+ // premade voices are free; professional library voices added to account may require paid plan
44
+ free_users_allowed: voice.category === "premade" || voice.is_owner === true
45
+ });
46
+ }
47
+ };
48
+ for (const v of voices) {
49
+ // Add to primary language
50
+ const primaryLang = v.labels?.language || "en";
51
+ addToLang(primaryLang, v);
52
+ // Add to all verified languages
53
+ for (const vl of v.verified_languages || []) {
54
+ if (vl.language && vl.language !== primaryLang) {
55
+ addToLang(vl.language, v);
56
+ }
57
+ }
58
+ }
59
+
60
+ const languages = Object.values(byLang).sort((a, b) => a.name.localeCompare(b.name));
61
+
62
+ // If lang filter requested, return only that group's voices
63
+ if (langFilter) {
64
+ return NextResponse.json({ voices: byLang[langFilter]?.voices || [] });
65
+ }
66
+
67
+ return NextResponse.json({ languages, byLang });
68
+ } catch (err) {
69
+ return NextResponse.json({ error: err.message || "Failed to fetch voices" }, { status: 502 });
70
+ }
71
+ }
@@ -0,0 +1,61 @@
1
+ import { NextResponse } from "next/server";
2
+ import { getProviderConnections } from "@/lib/localDb";
3
+
4
+ const langNames = new Intl.DisplayNames(["en"], { type: "language" });
5
+
6
+ /**
7
+ * GET /api/media-providers/tts/inworld/voices[?lang=en]
8
+ * Returns { languages, byLang } grouped by language code (same shape as edge-tts/elevenlabs)
9
+ */
10
+ export async function GET(request) {
11
+ try {
12
+ const { searchParams } = new URL(request.url);
13
+ const langFilter = searchParams.get("lang");
14
+
15
+ const connections = await getProviderConnections({ provider: "inworld", isActive: true });
16
+ const apiKey = connections[0]?.apiKey;
17
+ if (!apiKey) return NextResponse.json({ error: "No Inworld connection found" }, { status: 400 });
18
+
19
+ const res = await fetch("https://api.inworld.ai/tts/v1/voices", {
20
+ headers: { "Authorization": `Basic ${apiKey}` },
21
+ });
22
+ if (!res.ok) {
23
+ const text = await res.text().catch(() => "");
24
+ return NextResponse.json({ error: `Inworld API ${res.status}: ${text || "Failed"}` }, { status: 502 });
25
+ }
26
+ const data = await res.json();
27
+ const voices = data.voices || [];
28
+
29
+ const byLang = {};
30
+ for (const v of voices) {
31
+ // Each voice has `languages: ["en", "es", ...]`
32
+ const langs = Array.isArray(v.languages) && v.languages.length ? v.languages : ["en"];
33
+ for (const code of langs) {
34
+ if (!byLang[code]) {
35
+ byLang[code] = {
36
+ code,
37
+ name: (() => { try { return langNames.of(code); } catch { return code; } })(),
38
+ voices: [],
39
+ };
40
+ }
41
+ if (!byLang[code].voices.find((x) => x.id === v.voiceId)) {
42
+ byLang[code].voices.push({
43
+ id: v.voiceId,
44
+ name: v.displayName || v.voiceId,
45
+ gender: v.gender || "",
46
+ lang: code,
47
+ });
48
+ }
49
+ }
50
+ }
51
+
52
+ const languages = Object.values(byLang).sort((a, b) => a.name.localeCompare(b.name));
53
+
54
+ if (langFilter) {
55
+ return NextResponse.json({ voices: byLang[langFilter]?.voices || [] });
56
+ }
57
+ return NextResponse.json({ languages, byLang });
58
+ } catch (err) {
59
+ return NextResponse.json({ error: err.message || "Failed to fetch voices" }, { status: 502 });
60
+ }
61
+ }
@@ -0,0 +1,113 @@
1
+ import { NextResponse } from "next/server";
2
+ import { getProviderConnections } from "@/lib/localDb";
3
+
4
+ const MINIMAX_VOICE_ENDPOINTS = {
5
+ minimax: "https://api.minimax.io/v1/get_voice",
6
+ "minimax-cn": "https://api.minimaxi.com/v1/get_voice",
7
+ };
8
+
9
+ const VOICE_GROUPS = [
10
+ { key: "system_voice", label: "System" },
11
+ { key: "voice_cloning", label: "Cloned" },
12
+ { key: "voice_generation", label: "Generated" },
13
+ { key: "music_generation", label: "Music" },
14
+ ];
15
+
16
+ function inferLanguage(voiceId) {
17
+ const value = typeof voiceId === "string" ? voiceId.trim() : "";
18
+ if (!value.includes("_")) return "Custom";
19
+ return value.split("_")[0] || "Custom";
20
+ }
21
+
22
+ function addVoice(byLang, code, voice) {
23
+ if (!byLang[code]) byLang[code] = { code, name: code, voices: [] };
24
+ if (byLang[code].voices.some((v) => v.id === voice.id)) return;
25
+ byLang[code].voices.push(voice);
26
+ }
27
+
28
+ function normalizeMiniMaxVoices(data) {
29
+ const byLang = {};
30
+
31
+ for (const group of VOICE_GROUPS) {
32
+ const voices = Array.isArray(data?.[group.key]) ? data[group.key] : [];
33
+ for (const item of voices) {
34
+ const voiceId = item?.voice_id || item?.voiceId;
35
+ if (!voiceId) continue;
36
+
37
+ const voiceName = item?.voice_name || item?.voiceName || voiceId;
38
+ const lang = group.key === "system_voice" ? inferLanguage(voiceId) : "Custom";
39
+ addVoice(byLang, lang, {
40
+ id: voiceId,
41
+ name: group.key === "system_voice" ? voiceName : `${voiceName} · ${group.label}`,
42
+ lang,
43
+ category: group.key,
44
+ });
45
+ }
46
+ }
47
+
48
+ const languages = Object.values(byLang).sort((a, b) => {
49
+ if (a.code === "Custom") return 1;
50
+ if (b.code === "Custom") return -1;
51
+ return a.name.localeCompare(b.name);
52
+ });
53
+
54
+ for (const lang of languages) {
55
+ lang.voices.sort((a, b) => a.name.localeCompare(b.name));
56
+ }
57
+
58
+ return { languages, byLang };
59
+ }
60
+
61
+ /**
62
+ * GET /api/media-providers/tts/minimax/voices[?provider=minimax|minimax-cn&voice_type=all]
63
+ * Returns { languages, byLang } grouped for the shared TTS voice picker.
64
+ */
65
+ export async function GET(request) {
66
+ try {
67
+ const { searchParams } = new URL(request.url);
68
+ const provider = searchParams.get("provider") === "minimax-cn" ? "minimax-cn" : "minimax";
69
+ const voiceType = searchParams.get("voice_type") || "all";
70
+ const langFilter = searchParams.get("lang");
71
+
72
+ const connections = await getProviderConnections({ provider, isActive: true });
73
+ const apiKey = connections[0]?.apiKey;
74
+ if (!apiKey) {
75
+ return NextResponse.json({ error: `No ${provider} connection found` }, { status: 400 });
76
+ }
77
+
78
+ const res = await fetch(MINIMAX_VOICE_ENDPOINTS[provider], {
79
+ method: "POST",
80
+ headers: {
81
+ Authorization: `Bearer ${apiKey}`,
82
+ "Content-Type": "application/json",
83
+ },
84
+ body: JSON.stringify({ voice_type: voiceType }),
85
+ });
86
+
87
+ const rawText = await res.text();
88
+ let data = {};
89
+ if (rawText) {
90
+ try { data = JSON.parse(rawText); } catch { data = {}; }
91
+ }
92
+
93
+ const baseResp = data.base_resp || data.baseResp || {};
94
+ const statusCode = Number(baseResp.status_code ?? baseResp.statusCode ?? 0);
95
+ const statusMessage = baseResp.status_msg || baseResp.statusMsg || data.message || "";
96
+
97
+ if (!res.ok) {
98
+ return NextResponse.json({ error: `MiniMax API ${res.status}: ${statusMessage || rawText || "Failed"}` }, { status: 502 });
99
+ }
100
+ if (statusCode !== 0) {
101
+ return NextResponse.json({ error: statusMessage || "MiniMax voice API error" }, { status: 502 });
102
+ }
103
+
104
+ const normalized = normalizeMiniMaxVoices(data);
105
+ if (langFilter) {
106
+ return NextResponse.json({ voices: normalized.byLang[langFilter]?.voices || [] });
107
+ }
108
+
109
+ return NextResponse.json(normalized);
110
+ } catch (err) {
111
+ return NextResponse.json({ error: err.message || "Failed to fetch MiniMax voices" }, { status: 502 });
112
+ }
113
+ }