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,526 @@
1
+ const { err } = require("../logger");
2
+ const { IS_DEV } = require("../config");
3
+ const { fetchRouter, pipeTransformedEventStream } = require("./base");
4
+ const fs = require("fs");
5
+ const path = require("path");
6
+
7
+ // Debug trace log — written to data/logs/mitm/kiro-debug.log (dev only)
8
+ const DEBUG_LOG = path.join(__dirname, "../../../data/logs/mitm/kiro-debug.log");
9
+ function dbg(msg) {
10
+ if (!IS_DEV) return;
11
+ try {
12
+ fs.appendFileSync(DEBUG_LOG, `${new Date().toISOString()} ${msg}\n`);
13
+ } catch {}
14
+ }
15
+
16
+ // ─── CRC32 (standard, polynomial 0xEDB88320 — same as AWS EventStream) ───────
17
+ const CRC32_TABLE = (() => {
18
+ const t = new Uint32Array(256);
19
+ for (let n = 0; n < 256; n++) {
20
+ let c = n;
21
+ for (let k = 0; k < 8; k++) c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1;
22
+ t[n] = c;
23
+ }
24
+ return t;
25
+ })();
26
+
27
+ function crc32(buf) {
28
+ let crc = 0xffffffff;
29
+ for (let i = 0; i < buf.length; i++) {
30
+ crc = (crc >>> 8) ^ CRC32_TABLE[(crc ^ buf[i]) & 0xff];
31
+ }
32
+ return (crc ^ 0xffffffff) >>> 0;
33
+ }
34
+
35
+ /**
36
+ * Initialize state for the Kiro response translator
37
+ */
38
+ function initKiroState(modelId) {
39
+ return {
40
+ modelId: modelId || null, // Model name from first chunk
41
+ toolCallInit: {}, // { [index]: { id, name } } — tracks seen tools
42
+ hasToolCalls: false, // Whether this response uses tool calls
43
+ finishSent: false, // Whether termination has been emitted
44
+ usage: null, // Accumulated usage from usage-only chunks
45
+ inThink: false, // Whether inside a <thinking> block
46
+ thinkBuf: "" // Buffer for partial thinking content
47
+ };
48
+ }
49
+
50
+ /**
51
+ * Extract thinking blocks from text content.
52
+ * Handles both <thinking>...</thinking> and <think>...</think> tags,
53
+ * including partial tags split across SSE chunks.
54
+ */
55
+ function extractThinking(text, state) {
56
+ if (!text) return { thinking: null, text: null };
57
+
58
+ let working = text;
59
+
60
+ // Prepend buffered partial thinking from previous chunk
61
+ if (state.inThink && state.thinkBuf) {
62
+ working = state.thinkBuf + working;
63
+ state.thinkBuf = "";
64
+ state.inThink = false;
65
+ }
66
+
67
+ // Match <thinking> or <think> opening tags
68
+ const startRe = /<thinking>|<think>/i;
69
+ const startMatch = working.match(startRe);
70
+
71
+ if (!startMatch) {
72
+ return { thinking: null, text: working };
73
+ }
74
+
75
+ const tag = startMatch[0].toLowerCase();
76
+ const closeTag = tag === "<think>" ? "</think>" : "</thinking>";
77
+ const startIdx = startMatch.index;
78
+ const endIdx = working.indexOf(closeTag, startIdx + tag.length);
79
+
80
+ if (endIdx === -1) {
81
+ // Opening tag without closing — buffer for next chunk
82
+ state.inThink = true;
83
+ state.thinkBuf = working.slice(startIdx);
84
+ const before = working.slice(0, startIdx).trim();
85
+ return { thinking: null, text: before || null };
86
+ }
87
+
88
+ // Complete block found
89
+ const thinking = working.slice(startIdx + tag.length, endIdx);
90
+ const before = working.slice(0, startIdx).trim();
91
+ const after = working.slice(endIdx + closeTag.length).trim();
92
+ const rest = [before, after].filter(Boolean).join("");
93
+
94
+ // Recursively process for more blocks
95
+ const recurse = rest
96
+ ? extractThinking(rest, { inThink: false, thinkBuf: "" })
97
+ : { thinking: null, text: null };
98
+
99
+ return {
100
+ thinking: thinking || null,
101
+ text: recurse.text || null
102
+ };
103
+ }
104
+
105
+ // ─── AWS EventStream frame builder ────────────────────────────────────────────
106
+ /**
107
+ * Encode a single string header into the AWS EventStream binary format.
108
+ * Header wire format: [nameLen 1B][name][type=7 1B][valueLen 2B][value]
109
+ */
110
+ function encodeHeader(name, value) {
111
+ const nameBuf = Buffer.from(name, "utf8");
112
+ const valueBuf = Buffer.from(value, "utf8");
113
+ const buf = Buffer.alloc(1 + nameBuf.length + 1 + 2 + valueBuf.length);
114
+ let o = 0;
115
+ buf[o++] = nameBuf.length;
116
+ nameBuf.copy(buf, o); o += nameBuf.length;
117
+ buf[o++] = 7; // string type
118
+ buf.writeUInt16BE(valueBuf.length, o); o += 2;
119
+ valueBuf.copy(buf, o);
120
+ return buf;
121
+ }
122
+
123
+ /**
124
+ * Build a single AWS EventStream binary frame with all Smithy-required headers.
125
+ *
126
+ * Frame layout (big-endian):
127
+ * [totalLen 4B][headersLen 4B][preludeCRC 4B]
128
+ * [headers ...][payload JSON ...][messageCRC 4B]
129
+ *
130
+ * The SmithyMessageDecoderStream layer requires three system headers on every frame:
131
+ * :message-type = "event" (or "exception" / "error")
132
+ * :event-type = e.g. "assistantResponseEvent"
133
+ * :content-type = "application/json"
134
+ */
135
+ function buildEventStreamFrame(eventType, payload) {
136
+ const payloadBuf = Buffer.from(
137
+ typeof payload === "string" ? payload : JSON.stringify(payload),
138
+ "utf8"
139
+ );
140
+
141
+ // All three Smithy system headers are required
142
+ const headersBuf = Buffer.concat([
143
+ encodeHeader(":message-type", "event"),
144
+ encodeHeader(":event-type", eventType),
145
+ encodeHeader(":content-type", "application/json"),
146
+ ]);
147
+ const headersLen = headersBuf.length;
148
+
149
+ const totalLen = 4 + 4 + 4 + headersLen + payloadBuf.length + 4;
150
+ const frame = Buffer.alloc(totalLen);
151
+
152
+ frame.writeUInt32BE(totalLen, 0);
153
+ frame.writeUInt32BE(headersLen, 4);
154
+ frame.writeUInt32BE(crc32(frame.slice(0, 8)), 8); // prelude CRC
155
+ headersBuf.copy(frame, 12);
156
+ payloadBuf.copy(frame, 12 + headersLen);
157
+ frame.writeUInt32BE(crc32(frame.slice(0, totalLen - 4)), totalLen - 4); // message CRC
158
+
159
+ return frame;
160
+ }
161
+
162
+ // ─── CodeWhisperer → OpenAI conversion ───────────────────────────────────────
163
+
164
+ /**
165
+ * Safely stringify a tool-call input value.
166
+ * OpenAI expects `function.arguments` to be a JSON string, never an object.
167
+ * If 9router's Anthropic→OpenAI conversion passes the input as a pre-parsed object,
168
+ * this prevents the "" + object → "[object Object]" corruption.
169
+ */
170
+ function safeArgsString(value) {
171
+ if (typeof value === "string") return value;
172
+ if (value == null) return "{}";
173
+ try { return JSON.stringify(value); } catch { return "{}"; }
174
+ }
175
+
176
+ /**
177
+ * Convert a CodeWhisperer userInputMessage to one or more OpenAI messages.
178
+ *
179
+ * A user turn can contain:
180
+ * - plain text content → { role:"user", content }
181
+ * - toolResults only → one { role:"tool", tool_call_id, content } per result
182
+ * - both → tool messages first, then the user text message
183
+ */
184
+ function convertUserInputMessage(uim) {
185
+ const out = [];
186
+ const toolResults = uim.userInputMessageContext?.toolResults || [];
187
+
188
+ // Emit one "tool" message per tool result (OpenAI multi-tool format)
189
+ for (const tr of toolResults) {
190
+ const text = (tr.content || []).map(c => c.text || "").join("\n");
191
+ out.push({
192
+ role: "tool",
193
+ tool_call_id: tr.toolUseId || "",
194
+ content: text,
195
+ });
196
+ }
197
+
198
+ // Emit user text only if it exists alongside OR when there are no tool results
199
+ const text = (uim.content || "").trim();
200
+ if (text || toolResults.length === 0) {
201
+ out.push({ role: "user", content: text });
202
+ }
203
+
204
+ return out;
205
+ }
206
+
207
+ /**
208
+ * Convert a CodeWhisperer assistantResponseMessage to an OpenAI assistant message.
209
+ *
210
+ * The assistant turn can contain:
211
+ * - plain text content
212
+ * - toolUses (tool calls) → tool_calls[] on the assistant message
213
+ */
214
+ function convertAssistantResponseMessage(arm) {
215
+ const toolUses = arm.toolUses || [];
216
+
217
+ if (toolUses.length > 0) {
218
+ return {
219
+ role: "assistant",
220
+ content: arm.content || null,
221
+ tool_calls: toolUses.map(tu => ({
222
+ id: tu.toolUseId || `call_${Date.now()}`,
223
+ type: "function",
224
+ function: {
225
+ name: tu.name || "",
226
+ arguments: safeArgsString(tu.input),
227
+ },
228
+ })),
229
+ };
230
+ }
231
+
232
+ return { role: "assistant", content: arm.content || "" };
233
+ }
234
+
235
+ /**
236
+ * Convert AWS CodeWhisperer conversationState to an OpenAI messages array.
237
+ *
238
+ * Full multi-turn shape:
239
+ * history: [
240
+ * { userInputMessage: { content, userInputMessageContext?: { toolResults?, tools? } } },
241
+ * { assistantResponseMessage: { content, toolUses?: [...] } },
242
+ * ...
243
+ * ]
244
+ * currentMessage: { userInputMessage: { content, userInputMessageContext?: { toolResults? } } }
245
+ */
246
+ function codeWhispererToMessages(body) {
247
+ const cs = body.conversationState || {};
248
+ const history = cs.history || [];
249
+ const currentMsg = cs.currentMessage;
250
+ const messages = [];
251
+
252
+ for (const item of history) {
253
+ if (item.userInputMessage) {
254
+ messages.push(...convertUserInputMessage(item.userInputMessage));
255
+ } else if (item.assistantResponseMessage) {
256
+ messages.push(convertAssistantResponseMessage(item.assistantResponseMessage));
257
+ }
258
+ }
259
+
260
+ // Append the current (latest) turn
261
+ if (currentMsg?.userInputMessage) {
262
+ messages.push(...convertUserInputMessage(currentMsg.userInputMessage));
263
+ }
264
+
265
+ return messages;
266
+ }
267
+
268
+ /**
269
+ * Extract tool definitions from a CodeWhisperer request and convert to OpenAI format.
270
+ *
271
+ * CodeWhisperer tools live in:
272
+ * conversationState.currentMessage.userInputMessage.userInputMessageContext.tools
273
+ * OR (in multi-turn) the first history item's userInputMessageContext.tools
274
+ *
275
+ * CodeWhisperer tool shape:
276
+ * { toolSpecification: { name, description, inputSchema: { json: <schema> } } }
277
+ *
278
+ * OpenAI tool shape:
279
+ * { type: "function", function: { name, description, parameters: <schema> } }
280
+ */
281
+ function extractTools(body) {
282
+ const cs = body.conversationState || {};
283
+
284
+ // Tools are typically on the currentMessage; may also appear on the first history item
285
+ const fromCurrent = cs.currentMessage?.userInputMessage?.userInputMessageContext?.tools || [];
286
+ const fromHistory = cs.history?.find(h => h.userInputMessage?.userInputMessageContext?.tools)
287
+ ?.userInputMessage?.userInputMessageContext?.tools || [];
288
+ const cwTools = fromCurrent.length > 0 ? fromCurrent : fromHistory;
289
+
290
+ if (!cwTools.length) return [];
291
+
292
+ return cwTools.map(item => {
293
+ const spec = item.toolSpecification || item;
294
+ return {
295
+ type: "function",
296
+ function: {
297
+ name: spec.name || "",
298
+ description: spec.description || `Tool: ${spec.name || "unknown"}`,
299
+ parameters: spec.inputSchema?.json || { type: "object", properties: {}, required: [] },
300
+ },
301
+ };
302
+ });
303
+ }
304
+
305
+ // ─── OpenAI SSE → EventStream binary conversion ───────────────────────────────
306
+
307
+ /**
308
+ * Convert an OpenAI SSE chunk to AWS EventStream binary frame(s)
309
+ * This replaces pipeOpenAIasEventStream and works with pipeTransformedEventStream
310
+ *
311
+ * @param {object|null} chunk - Parsed OpenAI chat.completion.chunk, or null for flush
312
+ * @param {object} state - Mutable state object
313
+ * @returns {Uint8Array|Uint8Array[]|null} Binary EventStream frame(s) or null to skip
314
+ */
315
+ function convertOpenAIToKiro(chunk, state) {
316
+ // Flush: ensure clean stream termination
317
+ if (!chunk) {
318
+ if (state.finishSent) return null;
319
+ // Flush any remaining buffered thinking
320
+ if (state.inThink && state.thinkBuf) {
321
+ state.inThink = false;
322
+ const thinking = state.thinkBuf;
323
+ state.thinkBuf = "";
324
+ return buildEventStreamFrame("reasoningContentEvent", {
325
+ content: thinking,
326
+ modelId: state.modelId || "kiro-unknown"
327
+ });
328
+ }
329
+ return buildEventStreamFrame("messageStopEvent", {});
330
+ }
331
+
332
+ const frames = [];
333
+ const choice = chunk.choices?.[0];
334
+ const delta = choice?.delta || {};
335
+
336
+ // Capture modelId from first chunk (real API includes it in every content frame)
337
+ if (!state.modelId && chunk.model) {
338
+ state.modelId = chunk.model;
339
+ }
340
+ const modelId = state.modelId || "unknown";
341
+
342
+ // Handle usage (may arrive standalone or with other chunks)
343
+ if (chunk.usage) {
344
+ state.usage = chunk.usage;
345
+ }
346
+
347
+ // Handle tool calls — stream incrementally, matching real API format
348
+ if (delta.tool_calls) {
349
+ state.hasToolCalls = true;
350
+ for (const tc of delta.tool_calls) {
351
+ const idx = tc.index ?? 0;
352
+
353
+ if (tc.id && tc.function?.name && !state.toolCallInit[idx]) {
354
+ // First appearance: emit frame with name + id, no input
355
+ state.toolCallInit[idx] = { id: tc.id, name: tc.function.name };
356
+ dbg(`toolUseEvent init: ${tc.function.name} (${tc.id})`);
357
+ frames.push(buildEventStreamFrame("toolUseEvent", {
358
+ name: tc.function.name,
359
+ toolUseId: tc.id
360
+ }));
361
+ }
362
+
363
+ // Emit incremental input fragment
364
+ if (tc.function?.arguments) {
365
+ const init = state.toolCallInit[idx];
366
+ dbg(`toolUseEvent fragment: ${tc.function.arguments.slice(0, 100)}`);
367
+ frames.push(buildEventStreamFrame("toolUseEvent", {
368
+ input: tc.function.arguments,
369
+ name: init?.name || tc.function?.name || "",
370
+ toolUseId: init?.id || tc.id || ""
371
+ }));
372
+ }
373
+ }
374
+ }
375
+
376
+ // Handle explicit reasoning_content (type-specific thinking channel)
377
+ if (delta.reasoning_content) {
378
+ frames.push(buildEventStreamFrame("reasoningContentEvent", {
379
+ content: delta.reasoning_content,
380
+ modelId
381
+ }));
382
+ }
383
+
384
+ // Handle text content — extract thinking blocks, emit rest as assistantResponseEvent
385
+ if (delta.content) {
386
+ const { thinking, text } = extractThinking(delta.content, state);
387
+
388
+ if (thinking) {
389
+ frames.push(buildEventStreamFrame("reasoningContentEvent", {
390
+ content: thinking,
391
+ modelId
392
+ }));
393
+ }
394
+
395
+ if (text) {
396
+ frames.push(buildEventStreamFrame("assistantResponseEvent", {
397
+ content: text,
398
+ modelId
399
+ }));
400
+ }
401
+ }
402
+
403
+ // Handle finish_reason
404
+ if (choice?.finish_reason) {
405
+ const finishFrames = emitFinish(state);
406
+ if (finishFrames) {
407
+ frames.push(...(Array.isArray(finishFrames) ? finishFrames : [finishFrames]));
408
+ }
409
+ }
410
+
411
+ if (frames.length === 0) return null;
412
+ return frames.length === 1 ? frames[0] : frames;
413
+ }
414
+
415
+ /**
416
+ * Emit termination frames. For tool-call responses, emits stop:true per tool.
417
+ * For text-only responses, emits messageStopEvent.
418
+ */
419
+ function emitFinish(state) {
420
+ const frames = [];
421
+
422
+ if (state.hasToolCalls) {
423
+ // Tool-call response: emit stop:true for each tool
424
+ for (const idx of Object.keys(state.toolCallInit).sort()) {
425
+ const tc = state.toolCallInit[idx];
426
+ frames.push(buildEventStreamFrame("toolUseEvent", {
427
+ name: tc.name,
428
+ stop: true,
429
+ toolUseId: tc.id
430
+ }));
431
+ }
432
+ } else {
433
+ // Text-only response: emit messageStopEvent
434
+ frames.push(buildEventStreamFrame("messageStopEvent", {}));
435
+ }
436
+ state.finishSent = true;
437
+
438
+ // Emit usage if available
439
+ if (state.usage) {
440
+ frames.push(buildEventStreamFrame("usageEvent", {
441
+ inputTokens: state.usage.prompt_tokens || 0,
442
+ outputTokens: state.usage.completion_tokens || 0
443
+ }));
444
+ }
445
+
446
+ state.toolCallInit = {};
447
+ return frames.length > 0 ? frames : null;
448
+ }
449
+
450
+ // ─── MITM intercept entry point ───────────────────────────────────────────────
451
+ /**
452
+ * Intercept Kiro IDE CodeWhisperer request and convert to EventStream response:
453
+ * 1. Parse CodeWhisperer JSON body (reject binary EventStream formats)
454
+ * 2. Convert CodeWhisperer format to OpenAI messages[] format
455
+ * 3. Forward to 9router /v1/chat/completions (OpenAI SSE)
456
+ * 4. Convert OpenAI SSE response → AWS EventStream binary frames
457
+ * 5. Stream EventStream frames back to Kiro IDE
458
+ *
459
+ * @param {http.IncomingMessage} req - HTTP request from Kiro IDE
460
+ * @param {http.ServerResponse} res - HTTP response to Kiro IDE
461
+ * @param {Buffer} bodyBuffer - Request body buffer
462
+ * @param {string} mappedModel - Model name after MITM alias mapping
463
+ */
464
+ async function intercept(req, res, bodyBuffer, mappedModel) {
465
+ try {
466
+ // Detect and handle binary data (e.g., continuation requests with EventStream frames)
467
+ if (isBinaryEventStream(bodyBuffer)) {
468
+ // Binary EventStream requests are typically continuation/streaming frames
469
+ // that don't contain model info - pass them through directly to avoid JSON.parse crash
470
+ throw new Error(`Binary EventStream format detected (${bodyBuffer.length}B) - request should use passthrough instead of intercept`);
471
+ }
472
+
473
+ const body = JSON.parse(bodyBuffer.toString());
474
+
475
+ // 1 + 2: CodeWhisperer → OpenAI messages + tools
476
+ const messages = codeWhispererToMessages(body);
477
+ if (messages.length === 0) {
478
+ throw new Error("codeWhispererToMessages produced 0 messages — check request body");
479
+ }
480
+
481
+ const tools = extractTools(body);
482
+
483
+ const openaiBody = {
484
+ model: mappedModel,
485
+ messages,
486
+ stream: true,
487
+ // Forward tools so Claude uses structured tool_calls instead of XML text fallback
488
+ ...(tools.length > 0 && { tools, tool_choice: "auto" }),
489
+ };
490
+
491
+ // 3: Forward to 9router
492
+ const routerRes = await fetchRouter(openaiBody, "/v1/chat/completions", req.headers);
493
+
494
+ // 4 + 5: Re-encode response as AWS EventStream binary using standard pipeline
495
+ const state = initKiroState(mappedModel);
496
+
497
+ await pipeTransformedEventStream(routerRes, res, convertOpenAIToKiro, state);
498
+ } catch (error) {
499
+ err(`[Kiro MITM] Request processing failed: ${error.message}`);
500
+ if (!res.headersSent) {
501
+ res.writeHead(500, { "Content-Type": "application/json" });
502
+ }
503
+ res.end(JSON.stringify({
504
+ error: {
505
+ message: error.message,
506
+ type: "mitm_error",
507
+ handler: "kiro"
508
+ }
509
+ }));
510
+ }
511
+ }
512
+
513
+ // Detect AWS EventStream binary format
514
+ function isBinaryEventStream(buffer) {
515
+ if (!buffer || buffer.length < 12) return false;
516
+ // AWS EventStream signature:
517
+ // - First 4 bytes: total frame length (big-endian)
518
+ // - Bytes 4-8: headers length (big-endian)
519
+ // - Typical frame length: 100-10000 bytes
520
+ const totalLen = buffer.readUInt32BE(0);
521
+ const headersLen = buffer.readUInt32BE(4);
522
+ // Sanity checks: frame length should be reasonable and headers should fit
523
+ return totalLen > 12 && totalLen < 1000000 && headersLen < totalLen - 12;
524
+ }
525
+
526
+ module.exports = { intercept };
@@ -0,0 +1,106 @@
1
+ const fs = require("fs");
2
+ const path = require("path");
3
+ const zlib = require("zlib");
4
+ const { DATA_DIR } = require("./paths");
5
+ const { LOG_BLACKLIST_URL_PARTS } = require("./config");
6
+
7
+ function time() {
8
+ return new Date().toLocaleTimeString("en-US", { hour12: false });
9
+ }
10
+
11
+ const log = (msg) => console.log(`[${time()}] [MITM] ${msg}`);
12
+ const err = (msg) => console.error(`[${time()}] ❌ [MITM] ${msg}`);
13
+
14
+ const DUMP_DIR = path.join(DATA_DIR, "logs", "mitm");
15
+ if (!fs.existsSync(DUMP_DIR)) fs.mkdirSync(DUMP_DIR, { recursive: true });
16
+
17
+ // Clear all files inside DUMP_DIR (called on MITM server start to avoid unbounded growth)
18
+ function clearDumpDir() {
19
+ try {
20
+ if (!fs.existsSync(DUMP_DIR)) return;
21
+ for (const f of fs.readdirSync(DUMP_DIR)) {
22
+ try { fs.rmSync(path.join(DUMP_DIR, f), { recursive: true, force: true }); } catch { /* ignore */ }
23
+ }
24
+ } catch { /* ignore */ }
25
+ }
26
+
27
+ const EMPTY_BODY_RE = /^\s*(\{\s*\}|\[\s*\]|null)?\s*$/;
28
+
29
+ function slugify(s, max = 80) {
30
+ return String(s).replace(/[^a-zA-Z0-9]/g, "_").substring(0, max);
31
+ }
32
+
33
+ function isBlacklisted(url) {
34
+ if (!url) return false;
35
+ return LOG_BLACKLIST_URL_PARTS.some(part => url.includes(part));
36
+ }
37
+
38
+ // Decode body buffer based on content-encoding header
39
+ function decodeBody(buf, encoding) {
40
+ if (!buf || buf.length === 0) return buf;
41
+ try {
42
+ const enc = (encoding || "").toLowerCase();
43
+ if (enc.includes("gzip")) return zlib.gunzipSync(buf);
44
+ if (enc.includes("br")) return zlib.brotliDecompressSync(buf);
45
+ if (enc.includes("deflate")) return zlib.inflateSync(buf);
46
+ } catch { /* return raw on failure */ }
47
+ return buf;
48
+ }
49
+
50
+ // Save raw request: method + url + headers + body
51
+ function dumpRequest(req, bodyBuffer, tag = "raw") {
52
+ if (isBlacklisted(req.url)) return null;
53
+ try {
54
+ const ts = new Date().toISOString().replace(/[:.]/g, "-");
55
+ const slug = slugify((req.headers.host || "") + req.url);
56
+ const file = path.join(DUMP_DIR, `${ts}_${tag}_${slug}.req.json`);
57
+ let parsed = null;
58
+ try { parsed = JSON.parse(bodyBuffer.toString()); } catch { /* not JSON */ }
59
+ fs.writeFileSync(file, JSON.stringify({
60
+ method: req.method,
61
+ url: req.url,
62
+ host: req.headers.host,
63
+ headers: req.headers,
64
+ body: parsed ?? bodyBuffer.toString("utf8")
65
+ }, null, 2));
66
+ return file;
67
+ } catch { return null; }
68
+ }
69
+
70
+ // Buffer-based response dumper — collects chunks then decodes + writes once on end()
71
+ // Trade-off: holds response in RAM, but enables gzip/br decoding for readable output.
72
+ function createResponseDumper(req, tag = "raw") {
73
+ if (isBlacklisted(req.url)) return null;
74
+ const ts = new Date().toISOString().replace(/[:.]/g, "-");
75
+ const slug = slugify((req.headers.host || "") + req.url);
76
+ const file = path.join(DUMP_DIR, `${ts}_${tag}_${slug}.res.txt`);
77
+ let status = 0;
78
+ let headers = {};
79
+ const chunks = [];
80
+ return {
81
+ writeHeader: (s, h) => { status = s; headers = h || {}; },
82
+ writeChunk: (chunk) => {
83
+ if (chunk == null) return;
84
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
85
+ },
86
+ end: () => {
87
+ try {
88
+ const raw = Buffer.concat(chunks);
89
+ const enc = headers["content-encoding"] || headers["Content-Encoding"];
90
+ const decoded = decodeBody(raw, enc);
91
+ const text = decoded.toString("utf8");
92
+ // Skip empty / trivially-empty bodies
93
+ if (EMPTY_BODY_RE.test(text)) return;
94
+ // Strip content-encoding since body is now decoded
95
+ const cleanHeaders = { ...headers };
96
+ delete cleanHeaders["content-encoding"];
97
+ delete cleanHeaders["Content-Encoding"];
98
+ const out = `STATUS: ${status}\nHEADERS: ${JSON.stringify(cleanHeaders, null, 2)}\n---BODY---\n${text}`;
99
+ fs.writeFileSync(file, out);
100
+ } catch { /* ignore */ }
101
+ },
102
+ file
103
+ };
104
+ }
105
+
106
+ module.exports = { log, err, dumpRequest, createResponseDumper, clearDumpDir };