9router 0.3.54 → 0.3.55

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 (321) hide show
  1. package/app/.next/BUILD_ID +1 -1
  2. package/app/.next/app-path-routes-manifest.json +49 -49
  3. package/app/.next/build-manifest.json +2 -2
  4. package/app/.next/server/app/(dashboard)/dashboard/cli-tools/page_client-reference-manifest.js +1 -1
  5. package/app/.next/server/app/(dashboard)/dashboard/combos/page_client-reference-manifest.js +1 -1
  6. package/app/.next/server/app/(dashboard)/dashboard/console-log/page_client-reference-manifest.js +1 -1
  7. package/app/.next/server/app/(dashboard)/dashboard/endpoint/page_client-reference-manifest.js +1 -1
  8. package/app/.next/server/app/(dashboard)/dashboard/mitm/page_client-reference-manifest.js +1 -1
  9. package/app/.next/server/app/(dashboard)/dashboard/page_client-reference-manifest.js +1 -1
  10. package/app/.next/server/app/(dashboard)/dashboard/profile/page_client-reference-manifest.js +1 -1
  11. package/app/.next/server/app/(dashboard)/dashboard/providers/[id]/page.js +1 -1
  12. package/app/.next/server/app/(dashboard)/dashboard/providers/[id]/page_client-reference-manifest.js +1 -1
  13. package/app/.next/server/app/(dashboard)/dashboard/providers/new/page_client-reference-manifest.js +1 -1
  14. package/app/.next/server/app/(dashboard)/dashboard/providers/page.js +1 -1
  15. package/app/.next/server/app/(dashboard)/dashboard/providers/page_client-reference-manifest.js +1 -1
  16. package/app/.next/server/app/(dashboard)/dashboard/proxy-pools/page_client-reference-manifest.js +1 -1
  17. package/app/.next/server/app/(dashboard)/dashboard/quota/page_client-reference-manifest.js +1 -1
  18. package/app/.next/server/app/(dashboard)/dashboard/translator/page_client-reference-manifest.js +1 -1
  19. package/app/.next/server/app/(dashboard)/dashboard/usage/page_client-reference-manifest.js +1 -1
  20. package/app/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  21. package/app/.next/server/app/_global-error.html +2 -2
  22. package/app/.next/server/app/_global-error.rsc +1 -1
  23. package/app/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  24. package/app/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  25. package/app/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  26. package/app/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  27. package/app/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  28. package/app/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  29. package/app/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  30. package/app/.next/server/app/_not-found.html +1 -1
  31. package/app/.next/server/app/_not-found.rsc +3 -3
  32. package/app/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
  33. package/app/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  34. package/app/.next/server/app/_not-found.segments/_index.segment.rsc +3 -3
  35. package/app/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  36. package/app/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  37. package/app/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  38. package/app/.next/server/app/api/auth/login/route_client-reference-manifest.js +1 -1
  39. package/app/.next/server/app/api/auth/logout/route_client-reference-manifest.js +1 -1
  40. package/app/.next/server/app/api/cli-tools/antigravity-mitm/alias/route_client-reference-manifest.js +1 -1
  41. package/app/.next/server/app/api/cli-tools/antigravity-mitm/route.js +1 -1
  42. package/app/.next/server/app/api/cli-tools/antigravity-mitm/route_client-reference-manifest.js +1 -1
  43. package/app/.next/server/app/api/cli-tools/claude-settings/route_client-reference-manifest.js +1 -1
  44. package/app/.next/server/app/api/cli-tools/codex-settings/route_client-reference-manifest.js +1 -1
  45. package/app/.next/server/app/api/cli-tools/copilot-settings/route_client-reference-manifest.js +1 -1
  46. package/app/.next/server/app/api/cli-tools/droid-settings/route_client-reference-manifest.js +1 -1
  47. package/app/.next/server/app/api/cli-tools/openclaw-settings/route_client-reference-manifest.js +1 -1
  48. package/app/.next/server/app/api/cli-tools/opencode-settings/route_client-reference-manifest.js +1 -1
  49. package/app/.next/server/app/api/cloud/auth/route_client-reference-manifest.js +1 -1
  50. package/app/.next/server/app/api/cloud/credentials/update/route_client-reference-manifest.js +1 -1
  51. package/app/.next/server/app/api/cloud/model/resolve/route_client-reference-manifest.js +1 -1
  52. package/app/.next/server/app/api/cloud/models/alias/route_client-reference-manifest.js +1 -1
  53. package/app/.next/server/app/api/combos/[id]/route_client-reference-manifest.js +1 -1
  54. package/app/.next/server/app/api/combos/route_client-reference-manifest.js +1 -1
  55. package/app/.next/server/app/api/init/route_client-reference-manifest.js +1 -1
  56. package/app/.next/server/app/api/keys/[id]/route_client-reference-manifest.js +1 -1
  57. package/app/.next/server/app/api/keys/route_client-reference-manifest.js +1 -1
  58. package/app/.next/server/app/api/locale/route_client-reference-manifest.js +1 -1
  59. package/app/.next/server/app/api/models/alias/route_client-reference-manifest.js +1 -1
  60. package/app/.next/server/app/api/models/route.js +1 -1
  61. package/app/.next/server/app/api/models/route_client-reference-manifest.js +1 -1
  62. package/app/.next/server/app/api/models/test/route_client-reference-manifest.js +1 -1
  63. package/app/.next/server/app/api/oauth/[provider]/[action]/route_client-reference-manifest.js +1 -1
  64. package/app/.next/server/app/api/oauth/cursor/auto-import/route.js +1 -1
  65. package/app/.next/server/app/api/oauth/cursor/auto-import/route_client-reference-manifest.js +1 -1
  66. package/app/.next/server/app/api/oauth/cursor/import/route_client-reference-manifest.js +1 -1
  67. package/app/.next/server/app/api/oauth/iflow/cookie/route_client-reference-manifest.js +1 -1
  68. package/app/.next/server/app/api/oauth/kiro/auto-import/route_client-reference-manifest.js +1 -1
  69. package/app/.next/server/app/api/oauth/kiro/import/route_client-reference-manifest.js +1 -1
  70. package/app/.next/server/app/api/oauth/kiro/social-authorize/route_client-reference-manifest.js +1 -1
  71. package/app/.next/server/app/api/oauth/kiro/social-exchange/route_client-reference-manifest.js +1 -1
  72. package/app/.next/server/app/api/pricing/route_client-reference-manifest.js +1 -1
  73. package/app/.next/server/app/api/provider-nodes/[id]/route_client-reference-manifest.js +1 -1
  74. package/app/.next/server/app/api/provider-nodes/route_client-reference-manifest.js +1 -1
  75. package/app/.next/server/app/api/provider-nodes/validate/route.js +1 -1
  76. package/app/.next/server/app/api/provider-nodes/validate/route_client-reference-manifest.js +1 -1
  77. package/app/.next/server/app/api/providers/[id]/models/route_client-reference-manifest.js +1 -1
  78. package/app/.next/server/app/api/providers/[id]/route_client-reference-manifest.js +1 -1
  79. package/app/.next/server/app/api/providers/[id]/test/route_client-reference-manifest.js +1 -1
  80. package/app/.next/server/app/api/providers/[id]/test-models/route_client-reference-manifest.js +1 -1
  81. package/app/.next/server/app/api/providers/client/route_client-reference-manifest.js +1 -1
  82. package/app/.next/server/app/api/providers/route.js +1 -1
  83. package/app/.next/server/app/api/providers/route_client-reference-manifest.js +1 -1
  84. package/app/.next/server/app/api/providers/test-batch/route_client-reference-manifest.js +1 -1
  85. package/app/.next/server/app/api/providers/validate/route_client-reference-manifest.js +1 -1
  86. package/app/.next/server/app/api/proxy-pools/[id]/route_client-reference-manifest.js +1 -1
  87. package/app/.next/server/app/api/proxy-pools/[id]/test/route_client-reference-manifest.js +1 -1
  88. package/app/.next/server/app/api/proxy-pools/route_client-reference-manifest.js +1 -1
  89. package/app/.next/server/app/api/settings/database/route_client-reference-manifest.js +1 -1
  90. package/app/.next/server/app/api/settings/proxy-test/route_client-reference-manifest.js +1 -1
  91. package/app/.next/server/app/api/settings/require-login/route_client-reference-manifest.js +1 -1
  92. package/app/.next/server/app/api/settings/route_client-reference-manifest.js +1 -1
  93. package/app/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
  94. package/app/.next/server/app/api/tags/route_client-reference-manifest.js +1 -1
  95. package/app/.next/server/app/api/translator/console-logs/route.js +1 -1
  96. package/app/.next/server/app/api/translator/console-logs/route_client-reference-manifest.js +1 -1
  97. package/app/.next/server/app/api/translator/console-logs/stream/route.js +1 -1
  98. package/app/.next/server/app/api/translator/console-logs/stream/route_client-reference-manifest.js +1 -1
  99. package/app/.next/server/app/api/translator/load/route_client-reference-manifest.js +1 -1
  100. package/app/.next/server/app/api/translator/save/route_client-reference-manifest.js +1 -1
  101. package/app/.next/server/app/api/translator/send/route_client-reference-manifest.js +1 -1
  102. package/app/.next/server/app/api/translator/translate/route_client-reference-manifest.js +1 -1
  103. package/app/.next/server/app/api/tunnel/disable/route.js +1 -1
  104. package/app/.next/server/app/api/tunnel/disable/route_client-reference-manifest.js +1 -1
  105. package/app/.next/server/app/api/tunnel/enable/route.js +1 -1
  106. package/app/.next/server/app/api/tunnel/enable/route_client-reference-manifest.js +1 -1
  107. package/app/.next/server/app/api/tunnel/status/route.js +1 -1
  108. package/app/.next/server/app/api/tunnel/status/route_client-reference-manifest.js +1 -1
  109. package/app/.next/server/app/api/usage/[connectionId]/route_client-reference-manifest.js +1 -1
  110. package/app/.next/server/app/api/usage/chart/route_client-reference-manifest.js +1 -1
  111. package/app/.next/server/app/api/usage/history/route_client-reference-manifest.js +1 -1
  112. package/app/.next/server/app/api/usage/providers/route_client-reference-manifest.js +1 -1
  113. package/app/.next/server/app/api/usage/request-details/route_client-reference-manifest.js +1 -1
  114. package/app/.next/server/app/api/usage/request-logs/route_client-reference-manifest.js +1 -1
  115. package/app/.next/server/app/api/usage/stats/route_client-reference-manifest.js +1 -1
  116. package/app/.next/server/app/api/usage/stream/route_client-reference-manifest.js +1 -1
  117. package/app/.next/server/app/api/v1/api/chat/route_client-reference-manifest.js +1 -1
  118. package/app/.next/server/app/api/v1/chat/completions/route_client-reference-manifest.js +1 -1
  119. package/app/.next/server/app/api/v1/embeddings/route_client-reference-manifest.js +1 -1
  120. package/app/.next/server/app/api/v1/messages/count_tokens/route_client-reference-manifest.js +1 -1
  121. package/app/.next/server/app/api/v1/messages/route_client-reference-manifest.js +1 -1
  122. package/app/.next/server/app/api/v1/models/route_client-reference-manifest.js +1 -1
  123. package/app/.next/server/app/api/v1/responses/route_client-reference-manifest.js +1 -1
  124. package/app/.next/server/app/api/v1/route_client-reference-manifest.js +1 -1
  125. package/app/.next/server/app/api/v1beta/models/[...path]/route_client-reference-manifest.js +1 -1
  126. package/app/.next/server/app/api/v1beta/models/route_client-reference-manifest.js +1 -1
  127. package/app/.next/server/app/api/version/route.js +1 -1
  128. package/app/.next/server/app/api/version/route_client-reference-manifest.js +1 -1
  129. package/app/.next/server/app/callback/page_client-reference-manifest.js +1 -1
  130. package/app/.next/server/app/callback.html +1 -1
  131. package/app/.next/server/app/callback.rsc +3 -3
  132. package/app/.next/server/app/callback.segments/_full.segment.rsc +3 -3
  133. package/app/.next/server/app/callback.segments/_head.segment.rsc +1 -1
  134. package/app/.next/server/app/callback.segments/_index.segment.rsc +3 -3
  135. package/app/.next/server/app/callback.segments/_tree.segment.rsc +1 -1
  136. package/app/.next/server/app/callback.segments/callback/__PAGE__.segment.rsc +1 -1
  137. package/app/.next/server/app/callback.segments/callback.segment.rsc +1 -1
  138. package/app/.next/server/app/dashboard/cli-tools.html +1 -1
  139. package/app/.next/server/app/dashboard/cli-tools.rsc +5 -5
  140. package/app/.next/server/app/dashboard/cli-tools.segments/!KGRhc2hib2FyZCk/dashboard/cli-tools/__PAGE__.segment.rsc +2 -2
  141. package/app/.next/server/app/dashboard/cli-tools.segments/!KGRhc2hib2FyZCk/dashboard/cli-tools.segment.rsc +1 -1
  142. package/app/.next/server/app/dashboard/cli-tools.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  143. package/app/.next/server/app/dashboard/cli-tools.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  144. package/app/.next/server/app/dashboard/cli-tools.segments/_full.segment.rsc +5 -5
  145. package/app/.next/server/app/dashboard/cli-tools.segments/_head.segment.rsc +1 -1
  146. package/app/.next/server/app/dashboard/cli-tools.segments/_index.segment.rsc +3 -3
  147. package/app/.next/server/app/dashboard/cli-tools.segments/_tree.segment.rsc +1 -1
  148. package/app/.next/server/app/dashboard/combos.html +1 -1
  149. package/app/.next/server/app/dashboard/combos.rsc +5 -5
  150. package/app/.next/server/app/dashboard/combos.segments/!KGRhc2hib2FyZCk/dashboard/combos/__PAGE__.segment.rsc +2 -2
  151. package/app/.next/server/app/dashboard/combos.segments/!KGRhc2hib2FyZCk/dashboard/combos.segment.rsc +1 -1
  152. package/app/.next/server/app/dashboard/combos.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  153. package/app/.next/server/app/dashboard/combos.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  154. package/app/.next/server/app/dashboard/combos.segments/_full.segment.rsc +5 -5
  155. package/app/.next/server/app/dashboard/combos.segments/_head.segment.rsc +1 -1
  156. package/app/.next/server/app/dashboard/combos.segments/_index.segment.rsc +3 -3
  157. package/app/.next/server/app/dashboard/combos.segments/_tree.segment.rsc +1 -1
  158. package/app/.next/server/app/dashboard/endpoint.html +1 -1
  159. package/app/.next/server/app/dashboard/endpoint.rsc +5 -5
  160. package/app/.next/server/app/dashboard/endpoint.segments/!KGRhc2hib2FyZCk/dashboard/endpoint/__PAGE__.segment.rsc +2 -2
  161. package/app/.next/server/app/dashboard/endpoint.segments/!KGRhc2hib2FyZCk/dashboard/endpoint.segment.rsc +1 -1
  162. package/app/.next/server/app/dashboard/endpoint.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  163. package/app/.next/server/app/dashboard/endpoint.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  164. package/app/.next/server/app/dashboard/endpoint.segments/_full.segment.rsc +5 -5
  165. package/app/.next/server/app/dashboard/endpoint.segments/_head.segment.rsc +1 -1
  166. package/app/.next/server/app/dashboard/endpoint.segments/_index.segment.rsc +3 -3
  167. package/app/.next/server/app/dashboard/endpoint.segments/_tree.segment.rsc +1 -1
  168. package/app/.next/server/app/dashboard/mitm.html +1 -1
  169. package/app/.next/server/app/dashboard/mitm.rsc +5 -5
  170. package/app/.next/server/app/dashboard/mitm.segments/!KGRhc2hib2FyZCk/dashboard/mitm/__PAGE__.segment.rsc +2 -2
  171. package/app/.next/server/app/dashboard/mitm.segments/!KGRhc2hib2FyZCk/dashboard/mitm.segment.rsc +1 -1
  172. package/app/.next/server/app/dashboard/mitm.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  173. package/app/.next/server/app/dashboard/mitm.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  174. package/app/.next/server/app/dashboard/mitm.segments/_full.segment.rsc +5 -5
  175. package/app/.next/server/app/dashboard/mitm.segments/_head.segment.rsc +1 -1
  176. package/app/.next/server/app/dashboard/mitm.segments/_index.segment.rsc +3 -3
  177. package/app/.next/server/app/dashboard/mitm.segments/_tree.segment.rsc +1 -1
  178. package/app/.next/server/app/dashboard/profile.html +1 -1
  179. package/app/.next/server/app/dashboard/profile.rsc +5 -5
  180. package/app/.next/server/app/dashboard/profile.segments/!KGRhc2hib2FyZCk/dashboard/profile/__PAGE__.segment.rsc +2 -2
  181. package/app/.next/server/app/dashboard/profile.segments/!KGRhc2hib2FyZCk/dashboard/profile.segment.rsc +1 -1
  182. package/app/.next/server/app/dashboard/profile.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  183. package/app/.next/server/app/dashboard/profile.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  184. package/app/.next/server/app/dashboard/profile.segments/_full.segment.rsc +5 -5
  185. package/app/.next/server/app/dashboard/profile.segments/_head.segment.rsc +1 -1
  186. package/app/.next/server/app/dashboard/profile.segments/_index.segment.rsc +3 -3
  187. package/app/.next/server/app/dashboard/profile.segments/_tree.segment.rsc +1 -1
  188. package/app/.next/server/app/dashboard/providers/new.html +1 -1
  189. package/app/.next/server/app/dashboard/providers/new.rsc +5 -5
  190. package/app/.next/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk/dashboard/providers/new/__PAGE__.segment.rsc +2 -2
  191. package/app/.next/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk/dashboard/providers/new.segment.rsc +1 -1
  192. package/app/.next/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk/dashboard/providers.segment.rsc +1 -1
  193. package/app/.next/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  194. package/app/.next/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  195. package/app/.next/server/app/dashboard/providers/new.segments/_full.segment.rsc +5 -5
  196. package/app/.next/server/app/dashboard/providers/new.segments/_head.segment.rsc +1 -1
  197. package/app/.next/server/app/dashboard/providers/new.segments/_index.segment.rsc +3 -3
  198. package/app/.next/server/app/dashboard/providers/new.segments/_tree.segment.rsc +1 -1
  199. package/app/.next/server/app/dashboard/providers.html +1 -1
  200. package/app/.next/server/app/dashboard/providers.rsc +5 -5
  201. package/app/.next/server/app/dashboard/providers.segments/!KGRhc2hib2FyZCk/dashboard/providers/__PAGE__.segment.rsc +2 -2
  202. package/app/.next/server/app/dashboard/providers.segments/!KGRhc2hib2FyZCk/dashboard/providers.segment.rsc +1 -1
  203. package/app/.next/server/app/dashboard/providers.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  204. package/app/.next/server/app/dashboard/providers.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  205. package/app/.next/server/app/dashboard/providers.segments/_full.segment.rsc +5 -5
  206. package/app/.next/server/app/dashboard/providers.segments/_head.segment.rsc +1 -1
  207. package/app/.next/server/app/dashboard/providers.segments/_index.segment.rsc +3 -3
  208. package/app/.next/server/app/dashboard/providers.segments/_tree.segment.rsc +1 -1
  209. package/app/.next/server/app/dashboard/proxy-pools.html +1 -1
  210. package/app/.next/server/app/dashboard/proxy-pools.rsc +5 -5
  211. package/app/.next/server/app/dashboard/proxy-pools.segments/!KGRhc2hib2FyZCk/dashboard/proxy-pools/__PAGE__.segment.rsc +2 -2
  212. package/app/.next/server/app/dashboard/proxy-pools.segments/!KGRhc2hib2FyZCk/dashboard/proxy-pools.segment.rsc +1 -1
  213. package/app/.next/server/app/dashboard/proxy-pools.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  214. package/app/.next/server/app/dashboard/proxy-pools.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  215. package/app/.next/server/app/dashboard/proxy-pools.segments/_full.segment.rsc +5 -5
  216. package/app/.next/server/app/dashboard/proxy-pools.segments/_head.segment.rsc +1 -1
  217. package/app/.next/server/app/dashboard/proxy-pools.segments/_index.segment.rsc +3 -3
  218. package/app/.next/server/app/dashboard/proxy-pools.segments/_tree.segment.rsc +1 -1
  219. package/app/.next/server/app/dashboard/quota.html +2 -2
  220. package/app/.next/server/app/dashboard/quota.rsc +4 -4
  221. package/app/.next/server/app/dashboard/quota.segments/!KGRhc2hib2FyZCk/dashboard/quota/__PAGE__.segment.rsc +1 -1
  222. package/app/.next/server/app/dashboard/quota.segments/!KGRhc2hib2FyZCk/dashboard/quota.segment.rsc +1 -1
  223. package/app/.next/server/app/dashboard/quota.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  224. package/app/.next/server/app/dashboard/quota.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  225. package/app/.next/server/app/dashboard/quota.segments/_full.segment.rsc +4 -4
  226. package/app/.next/server/app/dashboard/quota.segments/_head.segment.rsc +1 -1
  227. package/app/.next/server/app/dashboard/quota.segments/_index.segment.rsc +3 -3
  228. package/app/.next/server/app/dashboard/quota.segments/_tree.segment.rsc +1 -1
  229. package/app/.next/server/app/dashboard/settings/pricing/page_client-reference-manifest.js +1 -1
  230. package/app/.next/server/app/dashboard/settings/pricing.html +1 -1
  231. package/app/.next/server/app/dashboard/settings/pricing.rsc +3 -3
  232. package/app/.next/server/app/dashboard/settings/pricing.segments/_full.segment.rsc +3 -3
  233. package/app/.next/server/app/dashboard/settings/pricing.segments/_head.segment.rsc +1 -1
  234. package/app/.next/server/app/dashboard/settings/pricing.segments/_index.segment.rsc +3 -3
  235. package/app/.next/server/app/dashboard/settings/pricing.segments/_tree.segment.rsc +1 -1
  236. package/app/.next/server/app/dashboard/settings/pricing.segments/dashboard/settings/pricing/__PAGE__.segment.rsc +1 -1
  237. package/app/.next/server/app/dashboard/settings/pricing.segments/dashboard/settings/pricing.segment.rsc +1 -1
  238. package/app/.next/server/app/dashboard/settings/pricing.segments/dashboard/settings.segment.rsc +1 -1
  239. package/app/.next/server/app/dashboard/settings/pricing.segments/dashboard.segment.rsc +1 -1
  240. package/app/.next/server/app/dashboard/translator.html +1 -1
  241. package/app/.next/server/app/dashboard/translator.rsc +5 -5
  242. package/app/.next/server/app/dashboard/translator.segments/!KGRhc2hib2FyZCk/dashboard/translator/__PAGE__.segment.rsc +2 -2
  243. package/app/.next/server/app/dashboard/translator.segments/!KGRhc2hib2FyZCk/dashboard/translator.segment.rsc +1 -1
  244. package/app/.next/server/app/dashboard/translator.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  245. package/app/.next/server/app/dashboard/translator.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  246. package/app/.next/server/app/dashboard/translator.segments/_full.segment.rsc +5 -5
  247. package/app/.next/server/app/dashboard/translator.segments/_head.segment.rsc +1 -1
  248. package/app/.next/server/app/dashboard/translator.segments/_index.segment.rsc +3 -3
  249. package/app/.next/server/app/dashboard/translator.segments/_tree.segment.rsc +1 -1
  250. package/app/.next/server/app/dashboard/usage.html +1 -1
  251. package/app/.next/server/app/dashboard/usage.rsc +5 -5
  252. package/app/.next/server/app/dashboard/usage.segments/!KGRhc2hib2FyZCk/dashboard/usage/__PAGE__.segment.rsc +2 -2
  253. package/app/.next/server/app/dashboard/usage.segments/!KGRhc2hib2FyZCk/dashboard/usage.segment.rsc +1 -1
  254. package/app/.next/server/app/dashboard/usage.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  255. package/app/.next/server/app/dashboard/usage.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  256. package/app/.next/server/app/dashboard/usage.segments/_full.segment.rsc +5 -5
  257. package/app/.next/server/app/dashboard/usage.segments/_head.segment.rsc +1 -1
  258. package/app/.next/server/app/dashboard/usage.segments/_index.segment.rsc +3 -3
  259. package/app/.next/server/app/dashboard/usage.segments/_tree.segment.rsc +1 -1
  260. package/app/.next/server/app/dashboard.html +1 -1
  261. package/app/.next/server/app/dashboard.rsc +5 -5
  262. package/app/.next/server/app/dashboard.segments/!KGRhc2hib2FyZCk/dashboard/__PAGE__.segment.rsc +2 -2
  263. package/app/.next/server/app/dashboard.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  264. package/app/.next/server/app/dashboard.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  265. package/app/.next/server/app/dashboard.segments/_full.segment.rsc +5 -5
  266. package/app/.next/server/app/dashboard.segments/_head.segment.rsc +1 -1
  267. package/app/.next/server/app/dashboard.segments/_index.segment.rsc +3 -3
  268. package/app/.next/server/app/dashboard.segments/_tree.segment.rsc +1 -1
  269. package/app/.next/server/app/index.html +1 -1
  270. package/app/.next/server/app/index.rsc +3 -3
  271. package/app/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  272. package/app/.next/server/app/index.segments/_full.segment.rsc +3 -3
  273. package/app/.next/server/app/index.segments/_head.segment.rsc +1 -1
  274. package/app/.next/server/app/index.segments/_index.segment.rsc +3 -3
  275. package/app/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  276. package/app/.next/server/app/landing/page_client-reference-manifest.js +1 -1
  277. package/app/.next/server/app/landing.html +1 -1
  278. package/app/.next/server/app/landing.rsc +3 -3
  279. package/app/.next/server/app/landing.segments/_full.segment.rsc +3 -3
  280. package/app/.next/server/app/landing.segments/_head.segment.rsc +1 -1
  281. package/app/.next/server/app/landing.segments/_index.segment.rsc +3 -3
  282. package/app/.next/server/app/landing.segments/_tree.segment.rsc +1 -1
  283. package/app/.next/server/app/landing.segments/landing/__PAGE__.segment.rsc +1 -1
  284. package/app/.next/server/app/landing.segments/landing.segment.rsc +1 -1
  285. package/app/.next/server/app/login/page_client-reference-manifest.js +1 -1
  286. package/app/.next/server/app/login.html +1 -1
  287. package/app/.next/server/app/login.rsc +4 -4
  288. package/app/.next/server/app/login.segments/_full.segment.rsc +4 -4
  289. package/app/.next/server/app/login.segments/_head.segment.rsc +1 -1
  290. package/app/.next/server/app/login.segments/_index.segment.rsc +3 -3
  291. package/app/.next/server/app/login.segments/_tree.segment.rsc +1 -1
  292. package/app/.next/server/app/login.segments/login/__PAGE__.segment.rsc +2 -2
  293. package/app/.next/server/app/login.segments/login.segment.rsc +1 -1
  294. package/app/.next/server/app/manifest.webmanifest/route_client-reference-manifest.js +1 -1
  295. package/app/.next/server/app/page_client-reference-manifest.js +1 -1
  296. package/app/.next/server/app-paths-manifest.json +49 -49
  297. package/app/.next/server/chunks/1114.js +1 -1
  298. package/app/.next/server/chunks/1424.js +1 -1
  299. package/app/.next/server/chunks/318.js +1 -1
  300. package/app/.next/server/chunks/6182.js +4 -17
  301. package/app/.next/server/chunks/649.js +1 -1
  302. package/app/.next/server/chunks/9201.js +1 -1
  303. package/app/.next/server/pages/404.html +1 -1
  304. package/app/.next/server/pages/500.html +2 -2
  305. package/app/.next/server/server-reference-manifest.js +1 -1
  306. package/app/.next/server/server-reference-manifest.json +1 -1
  307. package/app/.next/static/chunks/{5497-4115bafa029568f2.js → 5497-9933573cfe960e0c.js} +1 -1
  308. package/app/.next/static/chunks/{9242-c9d752975b449b44.js → 9242-3e0fdad972d9b35d.js} +1 -1
  309. package/app/.next/static/chunks/app/(dashboard)/dashboard/providers/[id]/{page-4ebc425afc0a221a.js → page-5e7e72628fe63cec.js} +1 -1
  310. package/app/.next/static/chunks/app/(dashboard)/dashboard/providers/page-bf901cec2b7f0ea0.js +1 -0
  311. package/app/.next/static/chunks/app/{layout-2cf69a29bcc7722e.js → layout-08e56eacc7acf9e1.js} +1 -1
  312. package/app/package.json +1 -1
  313. package/app/src/mitm/cert/install.js +5 -6
  314. package/app/src/mitm/cert/rootCA.js +22 -2
  315. package/app/src/mitm/dns/dnsConfig.js +7 -61
  316. package/app/src/mitm/manager.js +53 -62
  317. package/cli.js +6 -8
  318. package/package.json +1 -1
  319. package/app/.next/static/chunks/app/(dashboard)/dashboard/providers/page-3143d3dbb2dc3422.js +0 -1
  320. /package/app/.next/static/{lQALtClEnCtM3rGs1b9Jb → lSUZX6G8rzoxhxgvfuJ7I}/_buildManifest.js +0 -0
  321. /package/app/.next/static/{lQALtClEnCtM3rGs1b9Jb → lSUZX6G8rzoxhxgvfuJ7I}/_ssgManifest.js +0 -0
@@ -0,0 +1 @@
1
+ (self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[8460],{52154:(e,t,s)=>{"use strict";s.r(t),s.d(t,{default:()=>b});var r=s(95155),a=s(12115),l=s(5772),i=s(14051),n=s.n(i),o=s(35497),d=s(90620),c=s(52679),p=s(98500),m=s.n(p),x=s(65921);let u={available:{icon:"check_circle",color:"#22c55e",label:"Available"},cooldown:{icon:"schedule",color:"#f59e0b",label:"Cooldown"},unavailable:{icon:"error",color:"#ef4444",label:"Unavailable"},unknown:{icon:"help",color:"#6b7280",label:"Unknown"}};function h(){let[e,t]=(0,a.useState)(null),[s,l]=(0,a.useState)(!0),[i,n]=(0,a.useState)(!1),[d,c]=(0,a.useState)(null),p=(0,a.useRef)(null),m=(0,x.i)(),h=(0,a.useCallback)(async()=>{try{let e=await fetch("/api/models/availability");if(e.ok){let s=await e.json();t(s)}}catch{}finally{l(!1)}},[]);(0,a.useEffect)(()=>{h();let e=setInterval(h,3e4);return()=>clearInterval(e)},[h]),(0,a.useEffect)(()=>{let e=e=>{p.current&&!p.current.contains(e.target)&&n(!1)};return i&&document.addEventListener("mousedown",e),()=>document.removeEventListener("mousedown",e)},[i]);let f=async(e,t)=>{c(`${e}:${t}`);try{(await fetch("/api/models/availability",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({action:"clearCooldown",provider:e,model:t})})).ok?(m.success(`Cooldown cleared for ${t}`),await h()):m.error("Failed to clear cooldown")}catch{m.error("Failed to clear cooldown")}finally{c(null)}};if(s)return null;let b=e?.models||[],g=0===(e?.unavailableCount||b.filter(e=>"available"!==e.status).length),v={};return b.forEach(e=>{if("available"===e.status)return;let t=e.provider||"unknown";v[t]||(v[t]=[]),v[t].push(e)}),(0,r.jsx)("div",{className:"relative",ref:p,children:i&&(0,r.jsxs)("div",{className:"absolute top-full right-0 mt-2 w-80 bg-surface border border-border rounded-xl shadow-2xl z-50 overflow-hidden",children:[(0,r.jsxs)("div",{className:"flex items-center justify-between px-4 py-3 border-b border-border bg-bg",children:[(0,r.jsxs)("div",{className:"flex items-center gap-2",children:[(0,r.jsx)("span",{className:"material-symbols-outlined text-[16px]",style:{color:g?"#22c55e":"#f59e0b"},children:g?"verified":"warning"}),(0,r.jsx)("span",{className:"text-sm font-semibold text-text-main",children:"Model Status"})]}),(0,r.jsx)("button",{onClick:h,className:"p-1 rounded-lg hover:bg-surface text-text-muted hover:text-text-main transition-colors",title:"Refresh",children:(0,r.jsx)("span",{className:"material-symbols-outlined text-[14px]",children:"refresh"})})]}),(0,r.jsx)("div",{className:"px-4 py-3 max-h-60 overflow-y-auto",children:g?(0,r.jsx)("p",{className:"text-sm text-text-muted text-center py-2",children:"All models are responding normally."}):(0,r.jsx)("div",{className:"flex flex-col gap-2.5",children:Object.entries(v).map(([e,t])=>(0,r.jsxs)("div",{children:[(0,r.jsx)("p",{className:"text-xs font-semibold text-text-main mb-1.5 capitalize",children:e}),(0,r.jsx)("div",{className:"flex flex-col gap-1",children:t.map(e=>{let t=u[e.status]||u.unknown,s=d===`${e.provider}:${e.model}`;return(0,r.jsxs)("div",{className:"flex items-center justify-between px-2.5 py-1.5 rounded-lg bg-surface/30",children:[(0,r.jsxs)("div",{className:"flex items-center gap-1.5 min-w-0",children:[(0,r.jsx)("span",{className:"material-symbols-outlined text-[14px] shrink-0",style:{color:t.color},children:t.icon}),(0,r.jsx)("span",{className:"font-mono text-xs text-text-main truncate",children:e.model})]}),"cooldown"===e.status&&(0,r.jsx)(o.$n,{size:"sm",variant:"ghost",onClick:()=>f(e.provider,e.model),disabled:s,className:"text-[10px] px-1.5! py-0.5! ml-2",children:s?"...":"Clear"})]},`${e.provider}-${e.model}`)})})]},e))})})]})})}function f(e,t,s){let a=[];if(e>0&&a.push((0,r.jsxs)(o.Ex,{variant:"success",size:"sm",dot:!0,children:[e," Connected"]},"connected")),t>0){let e=s?`${t} Error (${s})`:`${t} Error`;a.push((0,r.jsx)(o.Ex,{variant:"error",size:"sm",dot:!0,children:e},"error"))}return 0===a.length?(0,r.jsx)("span",{className:"text-text-muted",children:"No connections"}):a}function b(){let[e,t]=(0,a.useState)([]),[s,l]=(0,a.useState)([]),[i,n]=(0,a.useState)(!0),[p,m]=(0,a.useState)(!1),[u,f]=(0,a.useState)(!1),[b,C]=(0,a.useState)(null),[w,k]=(0,a.useState)(null),T=(0,x.i)();(0,a.useEffect)(()=>{(async()=>{try{let[e,s]=await Promise.all([fetch("/api/providers"),fetch("/api/provider-nodes")]),r=await e.json(),a=await s.json();e.ok&&t(r.connections||[]),s.ok&&l(a.nodes||[])}catch(e){console.log("Error fetching data:",e)}finally{n(!1)}})()},[]);let A=(t,s)=>{let r=e.filter(e=>e.provider===t&&e.authType===s),a=e=>{let t=Object.entries(e).some(([e,t])=>e.startsWith("modelLock_")&&t&&new Date(t).getTime()>Date.now());return"unavailable"!==e.testStatus||t?e.testStatus:"active"},l=r.filter(e=>{let t=a(e);return"active"===t||"success"===t}).length,i=r.filter(e=>{let t=a(e);return"error"===t||"expired"===t||"unavailable"===t}),n=i.length,o=r.length,d=o>0&&r.every(e=>!1===e.isActive),c=i.sort((e,t)=>new Date(t.lastErrorAt||0)-new Date(e.lastErrorAt||0))[0];return{connected:l,error:n,total:o,errorCode:c?function(e){if(!e)return null;let t=e.lastErrorType;if("runtime_error"===t)return"RUNTIME";if("upstream_auth_error"===t||"auth_missing"===t||"token_refresh_failed"===t||"token_expired"===t)return"AUTH";if("upstream_rate_limited"===t)return"429";if("upstream_unavailable"===t)return"5XX";if("network_error"===t)return"NET";let s=Number(e.errorCode);if(Number.isFinite(s)&&s>=400)return String(s);let r=function(e){if(!e)return null;let t=e.match(/\b([45]\d{2})\b/);return t?t[1]:"ERR"}(e.lastError);if("401"===r||"403"===r)return"AUTH";if(r&&"ERR"!==r)return r;let a=(e.lastError||"").toLowerCase();return a.includes("runtime")||a.includes("not runnable")||a.includes("not installed")?"RUNTIME":a.includes("invalid api key")||a.includes("token invalid")||a.includes("revoked")||a.includes("unauthorized")?"AUTH":"ERR"}(c):null,errorTime:c?.lastErrorAt?function(e){if(!e)return"";let t=Math.floor((Date.now()-new Date(e).getTime())/6e4);if(t<1)return"just now";if(t<60)return`${t}m ago`;let s=Math.floor(t/60);if(s<24)return`${s}h ago`;let r=Math.floor(s/24);return`${r}d ago`}(c.lastErrorAt):null,allDisabled:d}},I=async(s,r,a)=>{let l=e.filter(e=>e.provider===s&&e.authType===r);t(e=>e.map(e=>e.provider===s&&e.authType===r?{...e,isActive:a}:e)),await Promise.allSettled(l.map(e=>fetch(`/api/providers/${e.id}`,{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({isActive:a})})))},E=async(e,t=null)=>{if(!b){C("provider"===e?t:e),k(null);try{let s=await fetch("/api/providers/test-batch",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({mode:e,providerId:t})}),r=await s.json();if(k(r),r.summary){let{passed:e,failed:t,total:s}=r.summary;0===t?T.success(`All ${s} tests passed`):T.warning(`${e}/${s} passed, ${t} failed`)}}catch(e){k({error:"Test request failed"}),T.error("Provider test failed")}finally{C(null)}}},S=s.filter(e=>"openai-compatible"===e.type).map(e=>({id:e.id,name:e.name||"OpenAI Compatible",color:"#10A37F",textIcon:"OC",apiType:e.apiType})),$=s.filter(e=>"anthropic-compatible"===e.type).map(e=>({id:e.id,name:e.name||"Anthropic Compatible",color:"#D97757",textIcon:"AC"}));return i?(0,r.jsxs)("div",{className:"flex flex-col gap-8",children:[(0,r.jsx)(o.Qv,{}),(0,r.jsx)(o.Qv,{})]}):(0,r.jsxs)("div",{className:"flex flex-col gap-6",children:[(0,r.jsxs)("div",{className:"flex flex-col gap-4",children:[(0,r.jsxs)("div",{className:"flex items-center justify-between",children:[(0,r.jsx)("h2",{className:"text-xl font-semibold flex items-center gap-2",children:"OAuth Providers"}),(0,r.jsxs)("div",{className:"flex items-center gap-2",children:[(0,r.jsx)(h,{}),(0,r.jsxs)("button",{onClick:()=>E("oauth"),disabled:!!b,className:`flex items-center gap-1.5 px-3 py-1.5 rounded-lg text-xs font-medium border transition-colors ${"oauth"===b?"bg-primary/20 border-primary/40 text-primary animate-pulse":"bg-bg border-border text-text-muted hover:text-text-main hover:border-primary/40"}`,title:"Test all OAuth connections","aria-label":"Test all OAuth connections",children:[(0,r.jsx)("span",{className:`material-symbols-outlined text-[14px]${"oauth"===b?" animate-spin":""}`,children:"oauth"===b?"sync":"play_arrow"}),"oauth"===b?"Testing...":"Test All"]})]})]}),(0,r.jsx)("div",{className:"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4",children:Object.entries(d.zN).map(([e,t])=>(0,r.jsx)(g,{providerId:e,provider:t,stats:A(e,"oauth"),authType:"oauth",onToggle:t=>I(e,"oauth",t)},e))})]}),(0,r.jsxs)("div",{className:"flex flex-col gap-4",children:[(0,r.jsxs)("div",{className:"flex items-center justify-between",children:[(0,r.jsx)("h2",{className:"text-xl font-semibold flex items-center gap-2",children:"Free Providers"}),(0,r.jsxs)("button",{onClick:()=>E("free"),disabled:!!b,className:`flex items-center gap-1.5 px-3 py-1.5 rounded-lg text-xs font-medium border transition-colors ${"free"===b?"bg-primary/20 border-primary/40 text-primary animate-pulse":"bg-bg border-border text-text-muted hover:text-text-main hover:border-primary/40"}`,title:"Test all Free connections","aria-label":"Test all Free provider connections",children:[(0,r.jsx)("span",{className:`material-symbols-outlined text-[14px]${"free"===b?" animate-spin":""}`,children:"free"===b?"sync":"play_arrow"}),"free"===b?"Testing...":"Test All"]})]}),(0,r.jsx)("div",{className:"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4",children:Object.entries(c.IS).map(([e,t])=>(0,r.jsx)(g,{providerId:e,provider:t,stats:A(e,"oauth"),authType:"free",onToggle:t=>I(e,"oauth",t)},e))})]}),(0,r.jsxs)("div",{className:"flex flex-col gap-4",children:[(0,r.jsxs)("div",{className:"flex items-center justify-between",children:[(0,r.jsxs)("h2",{className:"text-xl font-semibold flex items-center gap-2",children:["API Key Providers"," "]}),(0,r.jsxs)("button",{onClick:()=>E("apikey"),disabled:!!b,className:`flex items-center gap-1.5 px-3 py-1.5 rounded-lg text-xs font-medium border transition-colors ${"apikey"===b?"bg-primary/20 border-primary/40 text-primary animate-pulse":"bg-bg border-border text-text-muted hover:text-text-main hover:border-primary/40"}`,title:"Test all API Key connections","aria-label":"Test all API Key connections",children:[(0,r.jsx)("span",{className:`material-symbols-outlined text-[14px]${"apikey"===b?" animate-spin":""}`,children:"apikey"===b?"sync":"play_arrow"}),"apikey"===b?"Testing...":"Test All"]})]}),(0,r.jsx)("div",{className:"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4",children:Object.entries(d.fg).map(([e,t])=>(0,r.jsx)(v,{providerId:e,provider:t,stats:A(e,"apikey"),authType:"apikey",onToggle:t=>I(e,"apikey",t)},e))})]}),(0,r.jsxs)("div",{className:"flex flex-col gap-4",children:[(0,r.jsxs)("div",{className:"flex items-center justify-between",children:[(0,r.jsxs)("h2",{className:"text-xl font-semibold flex items-center gap-2",children:["API Key Compatible Providers"," "]}),(0,r.jsxs)("div",{className:"flex gap-2",children:[(0,r.jsx)(o.$n,{size:"sm",icon:"add",onClick:()=>f(!0),children:"Add Anthropic Compatible"}),(0,r.jsx)(o.$n,{size:"sm",variant:"secondary",icon:"add",onClick:()=>m(!0),className:"!bg-white !text-black hover:!bg-gray-100",children:"Add OpenAI Compatible"})]})]}),0===S.length&&0===$.length?(0,r.jsxs)("div",{className:"text-center py-8 border border-dashed border-border rounded-xl",children:[(0,r.jsx)("span",{className:"material-symbols-outlined text-[32px] text-text-muted mb-2",children:"extension"}),(0,r.jsx)("p",{className:"text-text-muted text-sm",children:"No compatible providers added yet"}),(0,r.jsx)("p",{className:"text-text-muted text-xs mt-1",children:"Use the buttons above to add OpenAI or Anthropic compatible endpoints"})]}):(0,r.jsx)("div",{className:"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4",children:[...S,...$].map(e=>(0,r.jsx)(v,{providerId:e.id,provider:e,stats:A(e.id,"apikey"),authType:"compatible",onToggle:t=>I(e.id,"apikey",t)},e.id))})]}),(0,r.jsx)(j,{isOpen:p,onClose:()=>m(!1),onCreated:e=>{l(t=>[...t,e]),m(!1)}}),(0,r.jsx)(y,{isOpen:u,onClose:()=>f(!1),onCreated:e=>{l(t=>[...t,e]),f(!1)}}),w&&(0,r.jsxs)("div",{className:"fixed inset-0 z-50 flex items-start justify-center pt-[10vh]",onClick:()=>k(null),children:[(0,r.jsx)("div",{className:"absolute inset-0 bg-black/60 backdrop-blur-sm"}),(0,r.jsxs)("div",{className:"relative bg-surface border border-border rounded-xl w-full max-w-[600px] max-h-[80vh] overflow-y-auto shadow-2xl",onClick:e=>e.stopPropagation(),children:[(0,r.jsxs)("div",{className:"sticky top-0 z-10 flex items-center justify-between px-5 py-3 border-b border-border bg-surface/95 backdrop-blur-sm rounded-t-xl",children:[(0,r.jsx)("h3",{className:"font-semibold",children:"Test Results"}),(0,r.jsx)("button",{onClick:()=>k(null),className:"p-1 rounded-lg hover:bg-bg text-text-muted hover:text-text-main transition-colors","aria-label":"Close test results",children:(0,r.jsx)("span",{className:"material-symbols-outlined text-lg",children:"close"})})]}),(0,r.jsx)("div",{className:"p-5",children:(0,r.jsx)(N,{results:w})})]})]})]})}function g({providerId:e,provider:t,stats:s,authType:i,onToggle:n}){let{connected:d,error:c,errorCode:p,errorTime:x,allDisabled:u}=s,[h,b]=(0,a.useState)(!1);return(0,r.jsx)(m(),{href:`/dashboard/providers/${e}`,className:"group",children:(0,r.jsx)(o.Zp,{padding:"xs",className:`h-full hover:bg-black/[0.01] dark:hover:bg-white/[0.01] transition-colors cursor-pointer ${u?"opacity-50":""}`,children:(0,r.jsxs)("div",{className:"flex items-center justify-between",children:[(0,r.jsxs)("div",{className:"flex items-center gap-3",children:[(0,r.jsx)("div",{className:"size-8 rounded-lg flex items-center justify-center",style:{backgroundColor:`${t.color?.length>7?t.color:t.color+"15"}`},children:h?(0,r.jsx)("span",{className:"text-xs font-bold",style:{color:t.color},children:t.textIcon||t.id.slice(0,2).toUpperCase()}):(0,r.jsx)(l.default,{src:`/providers/${t.id}.png`,alt:t.name,width:30,height:30,className:"object-contain rounded-lg max-w-[32px] max-h-[32px]",sizes:"32px",onError:()=>b(!0)})}),(0,r.jsxs)("div",{children:[(0,r.jsx)("h3",{className:"font-semibold",children:t.name}),(0,r.jsx)("div",{className:"flex items-center gap-2 text-xs flex-wrap",children:u?(0,r.jsx)(o.Ex,{variant:"default",size:"sm",children:(0,r.jsxs)("span",{className:"flex items-center gap-1",children:[(0,r.jsx)("span",{className:"material-symbols-outlined text-[12px]",children:"pause_circle"}),"Disabled"]})}):(0,r.jsxs)(r.Fragment,{children:[f(d,c,p),x&&(0,r.jsx)("span",{className:"text-text-muted",children:x})]})})]})]}),(0,r.jsx)("div",{className:"flex items-center gap-2",children:s.total>0&&(0,r.jsx)("div",{className:"opacity-0 group-hover:opacity-100 transition-opacity",onClick:e=>{e.preventDefault(),e.stopPropagation(),n(!!u)},children:(0,r.jsx)(o.lM,{size:"sm",checked:!u,onChange:()=>{},title:u?"Enable provider":"Disable provider"})})})]})})})}function v({providerId:e,provider:t,stats:s,authType:i,onToggle:n}){let{connected:d,error:p,errorCode:x,errorTime:u,allDisabled:h}=s,b=e.startsWith(c.JH),g=e.startsWith(c.DI),[v,j]=(0,a.useState)(!1);return(0,r.jsx)(m(),{href:`/dashboard/providers/${e}`,className:"group",children:(0,r.jsx)(o.Zp,{padding:"xs",className:`h-full hover:bg-black/[0.01] dark:hover:bg-white/[0.01] transition-colors cursor-pointer ${h?"opacity-50":""}`,children:(0,r.jsxs)("div",{className:"flex items-center justify-between",children:[(0,r.jsxs)("div",{className:"flex items-center gap-3",children:[(0,r.jsx)("div",{className:"size-8 rounded-lg flex items-center justify-center",style:{backgroundColor:`${t.color?.length>7?t.color:t.color+"15"}`},children:v?(0,r.jsx)("span",{className:"text-xs font-bold",style:{color:t.color},children:t.textIcon||t.id.slice(0,2).toUpperCase()}):(0,r.jsx)(l.default,{src:b?"responses"===t.apiType?"/providers/oai-r.png":"/providers/oai-cc.png":g?"/providers/anthropic-m.png":`/providers/${t.id}.png`,alt:t.name,width:30,height:30,className:"object-contain rounded-lg max-w-[30px] max-h-[30px]",sizes:"30px",onError:()=>j(!0)})}),(0,r.jsxs)("div",{children:[(0,r.jsx)("h3",{className:"font-semibold",children:t.name}),(0,r.jsx)("div",{className:"flex items-center gap-2 text-xs flex-wrap",children:h?(0,r.jsx)(o.Ex,{variant:"default",size:"sm",children:(0,r.jsxs)("span",{className:"flex items-center gap-1",children:[(0,r.jsx)("span",{className:"material-symbols-outlined text-[12px]",children:"pause_circle"}),"Disabled"]})}):(0,r.jsxs)(r.Fragment,{children:[f(d,p,x),b&&(0,r.jsx)(o.Ex,{variant:"default",size:"sm",children:"responses"===t.apiType?"Responses":"Chat"}),g&&(0,r.jsx)(o.Ex,{variant:"default",size:"sm",children:"Messages"}),u&&(0,r.jsx)("span",{className:"text-text-muted",children:u})]})})]})]}),(0,r.jsx)("div",{className:"flex items-center gap-2",children:s.total>0&&(0,r.jsx)("div",{className:"opacity-0 group-hover:opacity-100 transition-opacity",onClick:e=>{e.preventDefault(),e.stopPropagation(),n(!!h)},children:(0,r.jsx)(o.lM,{size:"sm",checked:!h,onChange:()=>{},title:h?"Enable provider":"Disable provider"})})})]})})})}function j({isOpen:e,onClose:t,onCreated:s}){let[l,i]=(0,a.useState)({name:"",prefix:"",apiType:"chat",baseUrl:"https://api.openai.com/v1"}),[n,d]=(0,a.useState)(!1),[c,p]=(0,a.useState)(""),[m,x]=(0,a.useState)(""),[u,h]=(0,a.useState)(!1),[f,b]=(0,a.useState)(null);(0,a.useEffect)(()=>{i(e=>({...e,baseUrl:"https://api.openai.com/v1"}))},[l.apiType]);let g=async()=>{if(l.name.trim()&&l.prefix.trim()&&l.baseUrl.trim()){d(!0);try{let e=await fetch("/api/provider-nodes",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:l.name,prefix:l.prefix,apiType:l.apiType,baseUrl:l.baseUrl,type:"openai-compatible"})}),t=await e.json();e.ok&&(s(t.node),i({name:"",prefix:"",apiType:"chat",baseUrl:"https://api.openai.com/v1"}),p(""),b(null))}catch(e){console.log("Error creating OpenAI Compatible node:",e)}finally{d(!1)}}},v=async()=>{h(!0);try{let e=await fetch("/api/provider-nodes/validate",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({baseUrl:l.baseUrl,apiKey:c,type:"openai-compatible",modelId:m.trim()||void 0})}),t=await e.json();b(t)}catch{b({valid:!1,error:"Network error"})}finally{h(!1)}};return(0,r.jsx)(o.aF,{isOpen:e,title:"Add OpenAI Compatible",onClose:t,children:(0,r.jsxs)("div",{className:"flex flex-col gap-4",children:[(0,r.jsx)(o.pd,{label:"Name",value:l.name,onChange:e=>i({...l,name:e.target.value}),placeholder:"OpenAI Compatible (Prod)",hint:"Required. A friendly label for this node."}),(0,r.jsx)(o.pd,{label:"Prefix",value:l.prefix,onChange:e=>i({...l,prefix:e.target.value}),placeholder:"oc-prod",hint:"Required. Used as the provider prefix for model IDs."}),(0,r.jsx)(o.l6,{label:"API Type",options:[{value:"chat",label:"Chat Completions"},{value:"responses",label:"Responses API"}],value:l.apiType,onChange:e=>i({...l,apiType:e.target.value})}),(0,r.jsx)(o.pd,{label:"Base URL",value:l.baseUrl,onChange:e=>i({...l,baseUrl:e.target.value}),placeholder:"https://api.openai.com/v1",hint:"Use the base URL (ending in /v1) for your OpenAI-compatible API."}),(0,r.jsx)(o.pd,{label:"API Key (for Check)",type:"password",value:c,onChange:e=>p(e.target.value)}),(0,r.jsx)(o.pd,{label:"Model ID (optional)",value:m,onChange:e=>x(e.target.value),placeholder:"e.g. gpt-4, claude-3-opus",hint:"If provider lacks /models endpoint, enter a model ID to validate via chat/completions instead."}),(0,r.jsxs)("div",{className:"flex items-center gap-3",children:[(0,r.jsx)(o.$n,{onClick:v,disabled:!c||u||!l.baseUrl.trim(),variant:"secondary",children:u?"Checking...":"Check"}),(()=>{if(!f)return null;let{valid:e,error:t,method:s}=f;return e?(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(o.Ex,{variant:"success",children:"Valid"}),"chat"===s&&(0,r.jsx)("span",{className:"text-sm text-text-muted",children:"(via inference test)"})]}):(0,r.jsxs)("div",{className:"flex flex-col gap-1",children:[(0,r.jsx)(o.Ex,{variant:"error",children:"Invalid"}),t&&(0,r.jsx)("span",{className:"text-sm text-red-500",children:t})]})})()]}),(0,r.jsxs)("div",{className:"flex gap-2",children:[(0,r.jsx)(o.$n,{onClick:g,fullWidth:!0,disabled:!l.name.trim()||!l.prefix.trim()||!l.baseUrl.trim()||n,children:n?"Creating...":"Create"}),(0,r.jsx)(o.$n,{onClick:t,variant:"ghost",fullWidth:!0,children:"Cancel"})]})]})})}function y({isOpen:e,onClose:t,onCreated:s}){let[l,i]=(0,a.useState)({name:"",prefix:"",baseUrl:"https://api.anthropic.com/v1"}),[n,d]=(0,a.useState)(!1),[c,p]=(0,a.useState)(""),[m,x]=(0,a.useState)(""),[u,h]=(0,a.useState)(!1),[f,b]=(0,a.useState)(null);(0,a.useEffect)(()=>{e&&(b(null),p(""),x(""))},[e]);let g=async()=>{if(l.name.trim()&&l.prefix.trim()&&l.baseUrl.trim()){d(!0);try{let e=await fetch("/api/provider-nodes",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:l.name,prefix:l.prefix,baseUrl:l.baseUrl,type:"anthropic-compatible"})}),t=await e.json();e.ok&&(s(t.node),i({name:"",prefix:"",baseUrl:"https://api.anthropic.com/v1"}),p(""),b(null))}catch(e){console.log("Error creating Anthropic Compatible node:",e)}finally{d(!1)}}},v=async()=>{h(!0);try{let e=await fetch("/api/provider-nodes/validate",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({baseUrl:l.baseUrl,apiKey:c,type:"anthropic-compatible",modelId:m.trim()||void 0})}),t=await e.json();b(t)}catch{b({valid:!1,error:"Network error"})}finally{h(!1)}};return(0,r.jsx)(o.aF,{isOpen:e,title:"Add Anthropic Compatible",onClose:t,children:(0,r.jsxs)("div",{className:"flex flex-col gap-4",children:[(0,r.jsx)(o.pd,{label:"Name",value:l.name,onChange:e=>i({...l,name:e.target.value}),placeholder:"Anthropic Compatible (Prod)",hint:"Required. A friendly label for this node."}),(0,r.jsx)(o.pd,{label:"Prefix",value:l.prefix,onChange:e=>i({...l,prefix:e.target.value}),placeholder:"ac-prod",hint:"Required. Used as the provider prefix for model IDs."}),(0,r.jsx)(o.pd,{label:"Base URL",value:l.baseUrl,onChange:e=>i({...l,baseUrl:e.target.value}),placeholder:"https://api.anthropic.com/v1",hint:"Use the base URL (ending in /v1) for your Anthropic-compatible API. The system will append /messages."}),(0,r.jsx)(o.pd,{label:"API Key (for Check)",type:"password",value:c,onChange:e=>p(e.target.value)}),(0,r.jsx)(o.pd,{label:"Model ID (optional)",value:m,onChange:e=>x(e.target.value),placeholder:"e.g. claude-3-opus",hint:"If provider lacks /models endpoint, enter a model ID to validate via chat/completions instead."}),(0,r.jsxs)("div",{className:"flex items-center gap-3",children:[(0,r.jsx)(o.$n,{onClick:v,disabled:!c||u||!l.baseUrl.trim(),variant:"secondary",children:u?"Checking...":"Check"}),(()=>{if(!f)return null;let{valid:e,error:t,method:s}=f;return e?(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(o.Ex,{variant:"success",children:"Valid"}),"chat"===s&&(0,r.jsx)("span",{className:"text-sm text-text-muted",children:"(via inference test)"})]}):(0,r.jsxs)("div",{className:"flex flex-col gap-1",children:[(0,r.jsx)(o.Ex,{variant:"error",children:"Invalid"}),t&&(0,r.jsx)("span",{className:"text-sm text-red-500",children:t})]})})()]}),(0,r.jsxs)("div",{className:"flex gap-2",children:[(0,r.jsx)(o.$n,{onClick:g,fullWidth:!0,disabled:!l.name.trim()||!l.prefix.trim()||!l.baseUrl.trim()||n,children:n?"Creating...":"Create"}),(0,r.jsx)(o.$n,{onClick:t,variant:"ghost",fullWidth:!0,children:"Cancel"})]})]})})}function N({results:e}){if(e.error&&!e.results)return(0,r.jsxs)("div",{className:"text-center py-6",children:[(0,r.jsx)("span",{className:"material-symbols-outlined text-red-500 text-[32px] mb-2 block",children:"error"}),(0,r.jsx)("p",{className:"text-sm text-red-400",children:e.error})]});let{summary:t,mode:s}=e,a=e.results||[];return(0,r.jsxs)("div",{className:"flex flex-col gap-3",children:[t&&(0,r.jsxs)("div",{className:"flex items-center gap-3 text-xs mb-1",children:[(0,r.jsxs)("span",{className:"text-text-muted",children:[{oauth:"OAuth",free:"Free",apikey:"API Key",provider:"Provider",all:"All"}[s]||s," Test"]}),(0,r.jsxs)("span",{className:"px-2 py-0.5 rounded bg-emerald-500/15 text-emerald-400 font-medium",children:[t.passed," passed"]}),t.failed>0&&(0,r.jsxs)("span",{className:"px-2 py-0.5 rounded bg-red-500/15 text-red-400 font-medium",children:[t.failed," failed"]}),(0,r.jsxs)("span",{className:"text-text-muted ml-auto",children:[t.total," tested"]})]}),a.map((e,t)=>(0,r.jsxs)("div",{className:"flex items-center gap-2 text-xs px-3 py-2 rounded-lg bg-black/[0.03] dark:bg-white/[0.03]",children:[(0,r.jsx)("span",{className:`material-symbols-outlined text-[16px] ${e.valid?"text-emerald-500":"text-red-500"}`,children:e.valid?"check_circle":"error"}),(0,r.jsxs)("div",{className:"flex-1 min-w-0",children:[(0,r.jsx)("span",{className:"font-medium",children:e.connectionName}),(0,r.jsxs)("span",{className:"text-text-muted ml-1.5",children:["(",e.provider,")"]})]}),void 0!==e.latencyMs&&(0,r.jsxs)("span",{className:"text-text-muted font-mono tabular-nums",children:[e.latencyMs,"ms"]}),(0,r.jsx)("span",{className:`text-[10px] uppercase font-bold px-1.5 py-0.5 rounded ${e.valid?"bg-emerald-500/15 text-emerald-400":"bg-red-500/15 text-red-400"}`,children:e.valid?"OK":e.diagnosis?.type||"ERROR"})]},e.connectionId||t)),0===a.length&&(0,r.jsx)("div",{className:"text-center py-4 text-text-muted text-sm",children:"No active connections found for this group."})]})}g.propTypes={providerId:n().string.isRequired,provider:n().shape({id:n().string.isRequired,name:n().string.isRequired,color:n().string,textIcon:n().string}).isRequired,stats:n().shape({connected:n().number,error:n().number,errorCode:n().string,errorTime:n().string}).isRequired,authType:n().string,onToggle:n().func},v.propTypes={providerId:n().string.isRequired,provider:n().shape({id:n().string.isRequired,name:n().string.isRequired,color:n().string,textIcon:n().string,apiType:n().string}).isRequired,stats:n().shape({connected:n().number,error:n().number,errorCode:n().string,errorTime:n().string}).isRequired,authType:n().string,onToggle:n().func},j.propTypes={isOpen:n().bool.isRequired,onClose:n().func.isRequired,onCreated:n().func.isRequired},y.propTypes={isOpen:n().bool.isRequired,onClose:n().func.isRequired,onCreated:n().func.isRequired},N.propTypes={results:n().shape({mode:n().string,results:n().array,summary:n().shape({total:n().number,passed:n().number,failed:n().number}),error:n().string}).isRequired}},63117:(e,t,s)=>{Promise.resolve().then(s.bind(s,52154))}},e=>{e.O(0,[5370,4335,5772,619,2652,5497,8441,3794,7358],()=>e(e.s=63117)),_N_E=e.O()}]);
@@ -1 +1 @@
1
- (self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[7177],{1934:(e,t,r)=>{"use strict";r.d(t,{v:()=>i});var n=r(12115);let a=e=>{let t,r=new Set,n=(e,n)=>{let a="function"==typeof e?e(t):e;if(!Object.is(a,t)){let e=t;t=(null!=n?n:"object"!=typeof a||null===a)?a:Object.assign({},t,a),r.forEach(r=>r(t,e))}},a=()=>t,o={setState:n,getState:a,getInitialState:()=>i,subscribe:e=>(r.add(e),()=>r.delete(e))},i=t=e(n,a,o);return o},o=e=>{let t=e?a(e):a,r=e=>(function(e,t=e=>e){let r=n.useSyncExternalStore(e.subscribe,n.useCallback(()=>t(e.getState()),[e,t]),n.useCallback(()=>t(e.getInitialState()),[e,t]));return n.useDebugValue(r),r})(t,e);return Object.assign(r,t),r},i=e=>e?o(e):o},21110:(e,t,r)=>{"use strict";r.d(t,{ThemeProvider:()=>i});var n=r(95155),a=r(12115),o=r(90085);function i({children:e}){let{initTheme:t}=(0,o.A)();return(0,a.useEffect)(()=>{t()},[t]),(0,n.jsx)(n.Fragment,{children:e})}},28777:(e,t,r)=>{"use strict";r.d(t,{KC:()=>n.KC,Xg:()=>n.Xg});var n=r(45564);Object.entries(r(52679).Q2).filter(([,e])=>e.passthroughModels).map(([e])=>e),Object.entries(n.vq).flatMap(([e,t])=>t.map(t=>({provider:e,model:t.id,name:t.name})))},31692:(e,t,r)=>{"use strict";r.d(t,{Zr:()=>a});let n=e=>t=>{try{let r=e(t);if(r instanceof Promise)return r;return{then:e=>n(e)(r),catch(e){return this}}}catch(e){return{then(e){return this},catch:t=>n(t)(e)}}},a=(e,t)=>(r,a,o)=>{let i,s={storage:function(e,t){let r;try{r=e()}catch(e){return}return{getItem:e=>{var t;let n=e=>null===e?null:JSON.parse(e,void 0),a=null!=(t=r.getItem(e))?t:null;return a instanceof Promise?a.then(n):n(a)},setItem:(e,t)=>r.setItem(e,JSON.stringify(t,void 0)),removeItem:e=>r.removeItem(e)}}(()=>window.localStorage),partialize:e=>e,version:0,merge:(e,t)=>({...t,...e}),...t},u=!1,l=0,c=new Set,d=new Set,m=s.storage;if(!m)return e((...e)=>{console.warn(`[zustand persist middleware] Unable to update item '${s.name}', the given storage is currently unavailable.`),r(...e)},a,o);let f=()=>{let e=s.partialize({...a()});return m.setItem(s.name,{state:e,version:s.version})},h=o.setState;o.setState=(e,t)=>(h(e,t),f());let p=e((...e)=>(r(...e),f()),a,o);o.getInitialState=()=>p;let v=()=>{var e,t;if(!m)return;let o=++l;u=!1,c.forEach(e=>{var t;return e(null!=(t=a())?t:p)});let h=(null==(t=s.onRehydrateStorage)?void 0:t.call(s,null!=(e=a())?e:p))||void 0;return n(m.getItem.bind(m))(s.name).then(e=>{if(e)if("number"!=typeof e.version||e.version===s.version)return[!1,e.state];else{if(s.migrate){let t=s.migrate(e.state,e.version);return t instanceof Promise?t.then(e=>[!0,e]):[!0,t]}console.error("State loaded from storage couldn't be migrated since no migrate function was provided")}return[!1,void 0]}).then(e=>{var t;if(o!==l)return;let[n,u]=e;if(r(i=s.merge(u,null!=(t=a())?t:p),!0),n)return f()}).then(()=>{o===l&&(null==h||h(i,void 0),i=a(),u=!0,d.forEach(e=>e(i)))}).catch(e=>{o===l&&(null==h||h(void 0,e))})};return o.persist={setOptions:e=>{s={...s,...e},e.storage&&(m=e.storage)},clearStorage:()=>{null==m||m.removeItem(s.name)},getOptions:()=>s,rehydrate:()=>v(),hasHydrated:()=>u,onHydrate:e=>(c.add(e),()=>{c.delete(e)}),onFinishHydration:e=>(d.add(e),()=>{d.delete(e)})},s.skipHydration||v(),i||p}},35154:e=>{e.exports={style:{fontFamily:"'Inter', 'Inter Fallback'",fontStyle:"normal"},className:"__className_f367f3",variable:"__variable_f367f3"}},51743:()=>{},54642:e=>{var t;"u">typeof __nccwpck_require__&&(__nccwpck_require__.ab="//"),(t={}).endianness=function(){return"LE"},t.hostname=function(){return"u">typeof location?location.hostname:""},t.loadavg=function(){return[]},t.uptime=function(){return 0},t.freemem=function(){return Number.MAX_VALUE},t.totalmem=function(){return Number.MAX_VALUE},t.cpus=function(){return[]},t.type=function(){return"Browser"},t.release=function(){return"u">typeof navigator?navigator.appVersion:""},t.networkInterfaces=t.getNetworkInterfaces=function(){return{}},t.arch=function(){return"javascript"},t.platform=function(){return"browser"},t.tmpdir=t.tmpDir=function(){return"/tmp"},t.EOL="\n",t.homedir=function(){return"/"},e.exports=t},64206:(e,t,r)=>{Promise.resolve().then(r.t.bind(r,35154,23)),Promise.resolve().then(r.t.bind(r,51743,23)),Promise.resolve().then(r.bind(r,94635)),Promise.resolve().then(r.bind(r,21110))},73006:(e,t,r)=>{"use strict";r.d(t,{FE:()=>m,Tl:()=>l,wn:()=>f});var n=r(93308);let a={},o=n.Xn,i=[];function s(){if("u"<typeof document)return n.Xn;let e=document.cookie.split(";").find(e=>e.trim().startsWith(`${n.CL}=`)),t=e?decodeURIComponent(e.split("=")[1]):n.Xn;return(0,n.QC)(t)}async function u(e){if("en"===e){a={};return}try{let t=await fetch(`/i18n/literals/${e}.json`);a=await t.json()}catch(e){console.error("Failed to load translations:",e),a={}}}function l(e){if(!e||"string"!=typeof e)return e;let t=e.trim();return t&&"en"!==o&&a[t]||e}function c(e){if(!e.nodeValue||!e.nodeValue.trim())return;let t=e.parentElement;if(!t)return;let r=t;for(;r;){if(r.hasAttribute&&r.hasAttribute("data-i18n-skip"))return;r=r.parentElement}if(["script","style","code","pre","colgroup","table","thead","tbody","tfoot","tr","select","datalist","optgroup"].includes(t.tagName?.toLowerCase()))return;e._originalText||(e._originalText=e.nodeValue);let n=l(e._originalText);n!==e.nodeValue&&(e.nodeValue=n)}function d(e){let t;if(!e)return;let r=document.createTreeWalker(e,NodeFilter.SHOW_TEXT,null,!1),n=[];for(;t=r.nextNode();)n.push(t);n.forEach(c)}async function m(){o=s(),await u(o),d(document.body),new MutationObserver(e=>{e.forEach(e=>{e.addedNodes.forEach(e=>{e.nodeType===Node.ELEMENT_NODE?d(e):e.nodeType===Node.TEXT_NODE&&c(e)})})}).observe(document.body,{childList:!0,subtree:!0})}async function f(){o=s(),await u(o),i.forEach(e=>e()),d(document.body)}},73321:(e,t,r)=>{"use strict";var n=r(74645);r.o(n,"useParams")&&r.d(t,{useParams:function(){return n.useParams}}),r.o(n,"usePathname")&&r.d(t,{usePathname:function(){return n.usePathname}}),r.o(n,"useRouter")&&r.d(t,{useRouter:function(){return n.useRouter}}),r.o(n,"useSearchParams")&&r.d(t,{useSearchParams:function(){return n.useSearchParams}})},90085:(e,t,r)=>{"use strict";r.d(t,{A:()=>s});var n=r(1934),a=r(31692),o=r(90620);function i(e){let t=document.documentElement,r=window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light";"dark"===("system"===e?r:e)?t.classList.add("dark"):t.classList.remove("dark")}let s=(0,n.v)((0,a.Zr)((e,t)=>({theme:o.B2.defaultTheme,setTheme:t=>{e({theme:t}),i(t)},toggleTheme:()=>{let r="dark"===t().theme?"light":"dark";e({theme:r}),i(r)},initTheme:()=>{i(t().theme)}}),{name:o.B2.storageKey}))},90620:(e,t,r)=>{"use strict";r.d(t,{Q2:()=>n.Q2,fg:()=>n.fg,vQ:()=>a,MA:()=>n.MA,UY:()=>i,zN:()=>n.zN,B2:()=>o});var n=r(52679);r(28777);let a={name:"Endpoint Proxy",description:"AI Infrastructure Management",version:"0.3.54"},o={storageKey:"theme",defaultTheme:"system"},i={maxLines:200,pollIntervalMs:1e3}},93308:(e,t,r)=>{"use strict";r.d(t,{CL:()=>o,QC:()=>i,Xn:()=>a,YZ:()=>n});let n=["en","vi","zh-CN"],a="en",o="locale";function i(e){return"zh"===e||"zh-CN"===e?"zh-CN":"en"===e?"en":"vi"===e?"vi":a}},94635:(e,t,r)=>{"use strict";r.d(t,{RuntimeI18nProvider:()=>s});var n=r(95155),a=r(12115),o=r(73321),i=r(73006);function s({children:e}){let t=(0,o.usePathname)();return(0,a.useEffect)(()=>{(0,i.FE)()},[]),(0,a.useEffect)(()=>{t&&requestAnimationFrame(()=>{requestAnimationFrame(()=>{(0,i.wn)()})})},[t]),(0,n.jsx)(n.Fragment,{children:e})}}},e=>{e.O(0,[6930,2652,8441,3794,7358],()=>e(e.s=64206)),_N_E=e.O()}]);
1
+ (self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[7177],{1934:(e,t,r)=>{"use strict";r.d(t,{v:()=>i});var n=r(12115);let a=e=>{let t,r=new Set,n=(e,n)=>{let a="function"==typeof e?e(t):e;if(!Object.is(a,t)){let e=t;t=(null!=n?n:"object"!=typeof a||null===a)?a:Object.assign({},t,a),r.forEach(r=>r(t,e))}},a=()=>t,o={setState:n,getState:a,getInitialState:()=>i,subscribe:e=>(r.add(e),()=>r.delete(e))},i=t=e(n,a,o);return o},o=e=>{let t=e?a(e):a,r=e=>(function(e,t=e=>e){let r=n.useSyncExternalStore(e.subscribe,n.useCallback(()=>t(e.getState()),[e,t]),n.useCallback(()=>t(e.getInitialState()),[e,t]));return n.useDebugValue(r),r})(t,e);return Object.assign(r,t),r},i=e=>e?o(e):o},21110:(e,t,r)=>{"use strict";r.d(t,{ThemeProvider:()=>i});var n=r(95155),a=r(12115),o=r(90085);function i({children:e}){let{initTheme:t}=(0,o.A)();return(0,a.useEffect)(()=>{t()},[t]),(0,n.jsx)(n.Fragment,{children:e})}},28777:(e,t,r)=>{"use strict";r.d(t,{KC:()=>n.KC,Xg:()=>n.Xg});var n=r(45564);Object.entries(r(52679).Q2).filter(([,e])=>e.passthroughModels).map(([e])=>e),Object.entries(n.vq).flatMap(([e,t])=>t.map(t=>({provider:e,model:t.id,name:t.name})))},31692:(e,t,r)=>{"use strict";r.d(t,{Zr:()=>a});let n=e=>t=>{try{let r=e(t);if(r instanceof Promise)return r;return{then:e=>n(e)(r),catch(e){return this}}}catch(e){return{then(e){return this},catch:t=>n(t)(e)}}},a=(e,t)=>(r,a,o)=>{let i,s={storage:function(e,t){let r;try{r=e()}catch(e){return}return{getItem:e=>{var t;let n=e=>null===e?null:JSON.parse(e,void 0),a=null!=(t=r.getItem(e))?t:null;return a instanceof Promise?a.then(n):n(a)},setItem:(e,t)=>r.setItem(e,JSON.stringify(t,void 0)),removeItem:e=>r.removeItem(e)}}(()=>window.localStorage),partialize:e=>e,version:0,merge:(e,t)=>({...t,...e}),...t},u=!1,l=0,c=new Set,d=new Set,m=s.storage;if(!m)return e((...e)=>{console.warn(`[zustand persist middleware] Unable to update item '${s.name}', the given storage is currently unavailable.`),r(...e)},a,o);let f=()=>{let e=s.partialize({...a()});return m.setItem(s.name,{state:e,version:s.version})},h=o.setState;o.setState=(e,t)=>(h(e,t),f());let p=e((...e)=>(r(...e),f()),a,o);o.getInitialState=()=>p;let v=()=>{var e,t;if(!m)return;let o=++l;u=!1,c.forEach(e=>{var t;return e(null!=(t=a())?t:p)});let h=(null==(t=s.onRehydrateStorage)?void 0:t.call(s,null!=(e=a())?e:p))||void 0;return n(m.getItem.bind(m))(s.name).then(e=>{if(e)if("number"!=typeof e.version||e.version===s.version)return[!1,e.state];else{if(s.migrate){let t=s.migrate(e.state,e.version);return t instanceof Promise?t.then(e=>[!0,e]):[!0,t]}console.error("State loaded from storage couldn't be migrated since no migrate function was provided")}return[!1,void 0]}).then(e=>{var t;if(o!==l)return;let[n,u]=e;if(r(i=s.merge(u,null!=(t=a())?t:p),!0),n)return f()}).then(()=>{o===l&&(null==h||h(i,void 0),i=a(),u=!0,d.forEach(e=>e(i)))}).catch(e=>{o===l&&(null==h||h(void 0,e))})};return o.persist={setOptions:e=>{s={...s,...e},e.storage&&(m=e.storage)},clearStorage:()=>{null==m||m.removeItem(s.name)},getOptions:()=>s,rehydrate:()=>v(),hasHydrated:()=>u,onHydrate:e=>(c.add(e),()=>{c.delete(e)}),onFinishHydration:e=>(d.add(e),()=>{d.delete(e)})},s.skipHydration||v(),i||p}},35154:e=>{e.exports={style:{fontFamily:"'Inter', 'Inter Fallback'",fontStyle:"normal"},className:"__className_f367f3",variable:"__variable_f367f3"}},51743:()=>{},54642:e=>{var t;"u">typeof __nccwpck_require__&&(__nccwpck_require__.ab="//"),(t={}).endianness=function(){return"LE"},t.hostname=function(){return"u">typeof location?location.hostname:""},t.loadavg=function(){return[]},t.uptime=function(){return 0},t.freemem=function(){return Number.MAX_VALUE},t.totalmem=function(){return Number.MAX_VALUE},t.cpus=function(){return[]},t.type=function(){return"Browser"},t.release=function(){return"u">typeof navigator?navigator.appVersion:""},t.networkInterfaces=t.getNetworkInterfaces=function(){return{}},t.arch=function(){return"javascript"},t.platform=function(){return"browser"},t.tmpdir=t.tmpDir=function(){return"/tmp"},t.EOL="\n",t.homedir=function(){return"/"},e.exports=t},64206:(e,t,r)=>{Promise.resolve().then(r.t.bind(r,35154,23)),Promise.resolve().then(r.t.bind(r,51743,23)),Promise.resolve().then(r.bind(r,94635)),Promise.resolve().then(r.bind(r,21110))},73006:(e,t,r)=>{"use strict";r.d(t,{FE:()=>m,Tl:()=>l,wn:()=>f});var n=r(93308);let a={},o=n.Xn,i=[];function s(){if("u"<typeof document)return n.Xn;let e=document.cookie.split(";").find(e=>e.trim().startsWith(`${n.CL}=`)),t=e?decodeURIComponent(e.split("=")[1]):n.Xn;return(0,n.QC)(t)}async function u(e){if("en"===e){a={};return}try{let t=await fetch(`/i18n/literals/${e}.json`);a=await t.json()}catch(e){console.error("Failed to load translations:",e),a={}}}function l(e){if(!e||"string"!=typeof e)return e;let t=e.trim();return t&&"en"!==o&&a[t]||e}function c(e){if(!e.nodeValue||!e.nodeValue.trim())return;let t=e.parentElement;if(!t)return;let r=t;for(;r;){if(r.hasAttribute&&r.hasAttribute("data-i18n-skip"))return;r=r.parentElement}if(["script","style","code","pre","colgroup","table","thead","tbody","tfoot","tr","select","datalist","optgroup"].includes(t.tagName?.toLowerCase()))return;e._originalText||(e._originalText=e.nodeValue);let n=l(e._originalText);n!==e.nodeValue&&(e.nodeValue=n)}function d(e){let t;if(!e)return;let r=document.createTreeWalker(e,NodeFilter.SHOW_TEXT,null,!1),n=[];for(;t=r.nextNode();)n.push(t);n.forEach(c)}async function m(){o=s(),await u(o),d(document.body),new MutationObserver(e=>{e.forEach(e=>{e.addedNodes.forEach(e=>{e.nodeType===Node.ELEMENT_NODE?d(e):e.nodeType===Node.TEXT_NODE&&c(e)})})}).observe(document.body,{childList:!0,subtree:!0})}async function f(){o=s(),await u(o),i.forEach(e=>e()),d(document.body)}},73321:(e,t,r)=>{"use strict";var n=r(74645);r.o(n,"useParams")&&r.d(t,{useParams:function(){return n.useParams}}),r.o(n,"usePathname")&&r.d(t,{usePathname:function(){return n.usePathname}}),r.o(n,"useRouter")&&r.d(t,{useRouter:function(){return n.useRouter}}),r.o(n,"useSearchParams")&&r.d(t,{useSearchParams:function(){return n.useSearchParams}})},90085:(e,t,r)=>{"use strict";r.d(t,{A:()=>s});var n=r(1934),a=r(31692),o=r(90620);function i(e){let t=document.documentElement,r=window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light";"dark"===("system"===e?r:e)?t.classList.add("dark"):t.classList.remove("dark")}let s=(0,n.v)((0,a.Zr)((e,t)=>({theme:o.B2.defaultTheme,setTheme:t=>{e({theme:t}),i(t)},toggleTheme:()=>{let r="dark"===t().theme?"light":"dark";e({theme:r}),i(r)},initTheme:()=>{i(t().theme)}}),{name:o.B2.storageKey}))},90620:(e,t,r)=>{"use strict";r.d(t,{Q2:()=>n.Q2,fg:()=>n.fg,vQ:()=>a,MA:()=>n.MA,UY:()=>i,zN:()=>n.zN,B2:()=>o});var n=r(52679);r(28777);let a={name:"Endpoint Proxy",description:"AI Infrastructure Management",version:"0.3.55"},o={storageKey:"theme",defaultTheme:"system"},i={maxLines:200,pollIntervalMs:1e3}},93308:(e,t,r)=>{"use strict";r.d(t,{CL:()=>o,QC:()=>i,Xn:()=>a,YZ:()=>n});let n=["en","vi","zh-CN"],a="en",o="locale";function i(e){return"zh"===e||"zh-CN"===e?"zh-CN":"en"===e?"en":"vi"===e?"vi":a}},94635:(e,t,r)=>{"use strict";r.d(t,{RuntimeI18nProvider:()=>s});var n=r(95155),a=r(12115),o=r(73321),i=r(73006);function s({children:e}){let t=(0,o.usePathname)();return(0,a.useEffect)(()=>{(0,i.FE)()},[]),(0,a.useEffect)(()=>{t&&requestAnimationFrame(()=>{requestAnimationFrame(()=>{(0,i.wn)()})})},[t]),(0,n.jsx)(n.Fragment,{children:e})}}},e=>{e.O(0,[6930,2652,8441,3794,7358],()=>e(e.s=64206)),_N_E=e.O()}]);
package/app/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "9router-app",
3
- "version": "0.3.54",
3
+ "version": "0.3.55",
4
4
  "description": "9Router web dashboard",
5
5
  "private": true,
6
6
  "scripts": {
@@ -45,7 +45,7 @@ function checkCertInstalledMac(certPath) {
45
45
  function checkCertInstalledWindows(certPath) {
46
46
  return new Promise((resolve) => {
47
47
  // Check Root store for our Root CA by common name
48
- exec("certutil -store Root \"9Router MITM Root CA\"", (error) => {
48
+ exec("certutil -store Root \"9Router MITM Root CA\"", { windowsHide: true }, (error) => {
49
49
  resolve(!error);
50
50
  });
51
51
  });
@@ -88,11 +88,10 @@ async function installCertMac(sudoPassword, certPath) {
88
88
  }
89
89
 
90
90
  async function installCertWindows(certPath) {
91
- const escaped = certPath.replace(/'/g, "''");
92
- const psCommand = `Start-Process certutil -ArgumentList '-addstore','Root','${escaped}' -Verb RunAs -Wait -WindowStyle Hidden`;
91
+ // Process already has admin rights — run certutil directly, no UAC needed
93
92
  return new Promise((resolve, reject) => {
94
93
  exec(
95
- `powershell -NonInteractive -WindowStyle Hidden -Command "${psCommand}"`,
94
+ `certutil -addstore Root "${certPath}"`,
96
95
  { windowsHide: true },
97
96
  (error) => {
98
97
  if (error) reject(new Error(`Failed to install certificate: ${error.message}`));
@@ -133,10 +132,10 @@ async function uninstallCertMac(sudoPassword, certPath) {
133
132
  }
134
133
 
135
134
  async function uninstallCertWindows() {
136
- const psCommand = `Start-Process certutil -ArgumentList '-delstore','Root','9Router MITM Root CA' -Verb RunAs -Wait -WindowStyle Hidden`;
135
+ // Process already has admin rights run certutil directly, no UAC needed
137
136
  return new Promise((resolve, reject) => {
138
137
  exec(
139
- `powershell -NonInteractive -WindowStyle Hidden -Command "${psCommand}"`,
138
+ `certutil -delstore Root "9Router MITM Root CA"`,
140
139
  { windowsHide: true },
141
140
  (error) => {
142
141
  if (error) reject(new Error(`Failed to uninstall certificate: ${error.message}`));
@@ -7,14 +7,33 @@ const ROOT_CA_KEY_PATH = path.join(MITM_DIR, "rootCA.key");
7
7
  const ROOT_CA_CERT_PATH = path.join(MITM_DIR, "rootCA.crt");
8
8
 
9
9
  /**
10
- * Generate Root CA certificate (only once)
10
+ * Check if cert file is expired or expiring within 30 days
11
+ */
12
+ function isCertExpired(certPath) {
13
+ try {
14
+ const cert = forge.pki.certificateFromPem(fs.readFileSync(certPath, "utf8"));
15
+ const expiryThreshold = new Date(Date.now() + 30 * 24 * 60 * 60 * 1000);
16
+ return cert.validity.notAfter < expiryThreshold;
17
+ } catch {
18
+ return true; // treat unreadable cert as expired
19
+ }
20
+ }
21
+
22
+ /**
23
+ * Generate Root CA certificate (only once, auto-regenerate if expired)
11
24
  * This Root CA will sign all dynamic leaf certificates
12
25
  */
13
26
  async function generateRootCA() {
14
- if (fs.existsSync(ROOT_CA_KEY_PATH) && fs.existsSync(ROOT_CA_CERT_PATH)) {
27
+ const exists = fs.existsSync(ROOT_CA_KEY_PATH) && fs.existsSync(ROOT_CA_CERT_PATH);
28
+ if (exists && !isCertExpired(ROOT_CA_CERT_PATH)) {
15
29
  console.log("✅ Root CA already exists");
16
30
  return { key: ROOT_CA_KEY_PATH, cert: ROOT_CA_CERT_PATH };
17
31
  }
32
+ if (exists) {
33
+ console.log("🔐 Root CA expired or expiring soon — regenerating...");
34
+ try { fs.unlinkSync(ROOT_CA_KEY_PATH); } catch { /* ignore */ }
35
+ try { fs.unlinkSync(ROOT_CA_CERT_PATH); } catch { /* ignore */ }
36
+ }
18
37
 
19
38
  if (!fs.existsSync(MITM_DIR)) {
20
39
  fs.mkdirSync(MITM_DIR, { recursive: true });
@@ -148,6 +167,7 @@ module.exports = {
148
167
  generateRootCA,
149
168
  loadRootCA,
150
169
  generateLeafCert,
170
+ isCertExpired,
151
171
  ROOT_CA_CERT_PATH,
152
172
  ROOT_CA_KEY_PATH
153
173
  };
@@ -140,38 +140,10 @@ async function addDNSEntry(tool, sudoPassword) {
140
140
 
141
141
  try {
142
142
  if (IS_WIN) {
143
- const hostsPath = HOSTS_FILE.replace(/'/g, "''");
144
-
145
- // Build PowerShell script with proper error handling
146
- const scriptLines = [];
147
- scriptLines.push(`$ErrorActionPreference = 'Stop'`);
148
- scriptLines.push(`$hostsPath = '${hostsPath}'`);
149
- scriptLines.push(`try {`);
150
- scriptLines.push(` $hostsContent = Get-Content -Path $hostsPath -Raw -ErrorAction SilentlyContinue`);
151
- scriptLines.push(` if (-not $hostsContent) { $hostsContent = '' }`);
152
-
153
- for (const host of entriesToAdd) {
154
- // Escape special regex chars in hostname
155
- const escapedHost = host.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
156
- scriptLines.push(` if ($hostsContent -notmatch '${escapedHost}') {`);
157
- scriptLines.push(` Add-Content -Path $hostsPath -Value '127.0.0.1 ${host}' -Encoding UTF8 -ErrorAction Stop`);
158
- scriptLines.push(` Write-Host "Added DNS entry: ${host}"`);
159
- scriptLines.push(` } else {`);
160
- scriptLines.push(` Write-Host "DNS entry already exists: ${host}"`);
161
- scriptLines.push(` }`);
162
- }
163
-
164
- scriptLines.push(` ipconfig /flushdns | Out-Null`);
165
- scriptLines.push(`} catch {`);
166
- scriptLines.push(` Write-Error "Failed to add DNS: $_"`);
167
- scriptLines.push(` exit 1`);
168
- scriptLines.push(`}`);
169
-
170
- const psScript = scriptLines.join("\n");
171
- const tmpPs1 = path.join(os.tmpdir(), `mitm_dns_add_${Date.now()}.ps1`);
172
- fs.writeFileSync(tmpPs1, psScript, "utf8");
173
-
174
- await executeElevatedPowerShell(tmpPs1, 30000);
143
+ // Process already has admin rights — edit hosts file directly
144
+ const toAppend = entriesToAdd.map(h => `127.0.0.1 ${h}`).join("\r\n") + "\r\n";
145
+ fs.appendFileSync(HOSTS_FILE, toAppend, "utf8");
146
+ require("child_process").execSync("ipconfig /flushdns", { windowsHide: true });
175
147
  } else {
176
148
  await execWithPassword(`echo "${entries}" >> ${HOSTS_FILE}`, sudoPassword);
177
149
  await flushDNS(sudoPassword);
@@ -198,37 +170,11 @@ async function removeDNSEntry(tool, sudoPassword) {
198
170
 
199
171
  try {
200
172
  if (IS_WIN) {
173
+ // Process already has admin rights — edit hosts file directly
201
174
  const content = fs.readFileSync(HOSTS_FILE, "utf8");
202
175
  const filtered = content.split(/\r?\n/).filter(l => !entriesToRemove.some(h => l.includes(h))).join("\r\n");
203
- const tmpFile = path.join(os.tmpdir(), `hosts_filtered_${Date.now()}.tmp`);
204
- fs.writeFileSync(tmpFile, filtered, "utf8");
205
-
206
- const tmpEsc = tmpFile.replace(/'/g, "''");
207
- const hostsEsc = HOSTS_FILE.replace(/'/g, "''");
208
-
209
- // Build PowerShell script with proper error handling
210
- const scriptLines = [];
211
- scriptLines.push(`$ErrorActionPreference = 'Stop'`);
212
- scriptLines.push(`try {`);
213
- scriptLines.push(` Copy-Item -Path '${tmpEsc}' -Destination '${hostsEsc}' -Force -ErrorAction Stop`);
214
- scriptLines.push(` Write-Host "Hosts file updated successfully"`);
215
- scriptLines.push(` ipconfig /flushdns | Out-Null`);
216
- scriptLines.push(` Write-Host "DNS cache flushed"`);
217
- scriptLines.push(` Remove-Item '${tmpEsc}' -ErrorAction SilentlyContinue`);
218
- scriptLines.push(`} catch {`);
219
- scriptLines.push(` Write-Error "Failed to remove DNS: $_"`);
220
- scriptLines.push(` Remove-Item '${tmpEsc}' -ErrorAction SilentlyContinue`);
221
- scriptLines.push(` exit 1`);
222
- scriptLines.push(`}`);
223
-
224
- const psScript = scriptLines.join("\n");
225
- const tmpPs1 = path.join(os.tmpdir(), `mitm_dns_remove_${Date.now()}.ps1`);
226
- fs.writeFileSync(tmpPs1, psScript, "utf8");
227
-
228
- await executeElevatedPowerShell(tmpPs1, 30000);
229
-
230
- // Cleanup temp file if still exists
231
- try { fs.unlinkSync(tmpFile); } catch { /* ignore */ }
176
+ fs.writeFileSync(HOSTS_FILE, filtered, "utf8");
177
+ require("child_process").execSync("ipconfig /flushdns", { windowsHide: true });
232
178
  } else {
233
179
  for (const host of entriesToRemove) {
234
180
  const sedCmd = IS_MAC
@@ -5,11 +5,12 @@ const os = require("os");
5
5
  const net = require("net");
6
6
  const https = require("https");
7
7
  const crypto = require("crypto");
8
- const { addDNSEntry, removeDNSEntry, removeAllDNSEntries, checkAllDNSStatus, executeElevatedPowerShell, TOOL_HOSTS } = require("./dns/dnsConfig");
8
+ const { addDNSEntry, removeDNSEntry, removeAllDNSEntries, checkAllDNSStatus, TOOL_HOSTS } = require("./dns/dnsConfig");
9
9
 
10
10
  const IS_WIN = process.platform === "win32";
11
11
  const { generateCert } = require("./cert/generate");
12
- const { installCert } = require("./cert/install");
12
+ const { installCert, uninstallCert } = require("./cert/install");
13
+ const { isCertExpired } = require("./cert/rootCA");
13
14
  const { MITM_DIR } = require("./paths");
14
15
  const { log, err } = require("./logger");
15
16
 
@@ -81,7 +82,7 @@ function isProcessAlive(pid) {
81
82
  function killProcess(pid, force = false, sudoPassword = null) {
82
83
  if (IS_WIN) {
83
84
  const flag = force ? "/F " : "";
84
- exec(`taskkill ${flag}/PID ${pid}`, () => { });
85
+ exec(`taskkill ${flag}/PID ${pid}`, { windowsHide: true }, () => { });
85
86
  } else {
86
87
  const sig = force ? "SIGKILL" : "SIGTERM";
87
88
  const cmd = `pkill -${sig} -P ${pid} 2>/dev/null; kill -${sig} ${pid} 2>/dev/null`;
@@ -375,12 +376,19 @@ async function startServer(apiKey, sudoPassword) {
375
376
  }
376
377
  }
377
378
 
378
- // Step 1: Auto-migration - Generate Root CA if not exists
379
+ // Step 1: Generate Root CA if missing or expired
379
380
  const rootCACertPath = path.join(MITM_DIR, "rootCA.crt");
380
381
  const rootCAKeyPath = path.join(MITM_DIR, "rootCA.key");
381
-
382
- if (!fs.existsSync(rootCACertPath) || !fs.existsSync(rootCAKeyPath)) {
383
- log("🔐 Generating Root CA (first time)...");
382
+ const certExists = fs.existsSync(rootCACertPath) && fs.existsSync(rootCAKeyPath);
383
+
384
+ if (!certExists || isCertExpired(rootCACertPath)) {
385
+ if (certExists) {
386
+ // Uninstall expired cert from system store before regenerating
387
+ log("🔐 Cert expired — uninstalling old cert...");
388
+ const password = sudoPassword || getCachedPassword() || await loadEncryptedPassword();
389
+ try { await uninstallCert(password, rootCACertPath); } catch { /* best effort */ }
390
+ }
391
+ log("🔐 Generating Root CA...");
384
392
  await generateCert();
385
393
  }
386
394
 
@@ -389,13 +397,16 @@ async function startServer(apiKey, sudoPassword) {
389
397
  const rootCATrusted = await checkCertInstalled(rootCACertPath);
390
398
  if (!rootCATrusted) {
391
399
  log("🔐 Cert: not trusted → installing...");
392
- // Use provided password or cached/stored password
393
400
  const password = sudoPassword || getCachedPassword() || await loadEncryptedPassword();
394
401
  if (!password && !IS_WIN) {
395
402
  throw new Error("Sudo password required to install Root CA certificate");
396
403
  }
397
- await installCert(password, rootCACertPath);
398
- log("🔐 Cert: ✅ trusted");
404
+ try {
405
+ await installCert(password, rootCACertPath);
406
+ log("🔐 Cert: ✅ trusted");
407
+ } catch (e) {
408
+ throw new Error(`Failed to trust certificate: ${e.message}`);
409
+ }
399
410
  } else {
400
411
  log("🔐 Cert: already trusted ✅");
401
412
  }
@@ -403,23 +414,24 @@ async function startServer(apiKey, sudoPassword) {
403
414
  // Step 2: Spawn server (Root CA already installed in Step 1.5)
404
415
  log("🚀 Starting server...");
405
416
  if (IS_WIN) {
406
- const psSQ = (s) => s.replace(/'/g, "''");
407
- const nodePs = psSQ(process.execPath);
408
- const serverPs = psSQ(SERVER_PATH);
409
-
410
- const psScript = [
411
- `$ErrorActionPreference = 'Stop'`,
412
- `$conn = Get-NetTCPConnection -LocalPort 443 -State Listen -ErrorAction SilentlyContinue | Select-Object -First 1`,
413
- `if ($conn -and $conn.OwningProcess -gt 4) { Stop-Process -Id $conn.OwningProcess -Force -ErrorAction SilentlyContinue }`,
414
- `Start-Sleep -Milliseconds 500`,
415
- `$nodeCmd = 'set ROUTER_API_KEY=${psSQ(apiKey)}&& set NODE_ENV=production&& "${nodePs}" "${serverPs}"'`,
416
- `Start-Process cmd -ArgumentList '/c',$nodeCmd -WindowStyle Hidden`,
417
- `Start-Sleep -Milliseconds 500`,
418
- ].join("\n");
419
-
420
- const tmpPs1 = path.join(os.tmpdir(), `mitm_start_${Date.now()}.ps1`);
421
- fs.writeFileSync(tmpPs1, psScript, "utf8");
422
- await executeElevatedPowerShell(tmpPs1, 90000);
417
+ // Kill any process using port 443 before spawning
418
+ try {
419
+ const psKill = `$c = Get-NetTCPConnection -LocalPort 443 -State Listen -ErrorAction SilentlyContinue | Select-Object -First 1; if ($c -and $c.OwningProcess -gt 4) { Stop-Process -Id $c.OwningProcess -Force -ErrorAction SilentlyContinue }`;
420
+ execSync(`powershell -NonInteractive -WindowStyle Hidden -Command "${psKill}"`, { windowsHide: true });
421
+ await new Promise(r => setTimeout(r, 500));
422
+ } catch { /* best effort */ }
423
+
424
+ // Spawn directly process already has admin rights
425
+ serverProcess = spawn(
426
+ process.execPath,
427
+ [SERVER_PATH],
428
+ {
429
+ detached: false,
430
+ windowsHide: true,
431
+ stdio: ["ignore", "pipe", "pipe"],
432
+ env: { ...process.env, ROUTER_API_KEY: apiKey, NODE_ENV: "production" },
433
+ }
434
+ );
423
435
 
424
436
  if (_updateSettings) await _updateSettings({ mitmCertInstalled: true }).catch(() => { });
425
437
  } else {
@@ -433,21 +445,22 @@ async function startServer(apiKey, sudoPassword) {
433
445
  serverProcess.stdin.end();
434
446
  }
435
447
 
436
- if (!IS_WIN && serverProcess) {
448
+ if (serverProcess) {
437
449
  serverPid = serverProcess.pid;
438
450
  fs.writeFileSync(PID_FILE, String(serverPid));
439
451
  mitmLastStartTime = Date.now();
440
452
  }
441
453
 
442
454
  let startError = null;
443
- if (!IS_WIN) {
455
+ if (serverProcess) {
444
456
  serverProcess.stdout.on("data", (data) => {
445
457
  // server.js already formats its own logs — print as-is
446
458
  process.stdout.write(data);
447
459
  });
448
460
  serverProcess.stderr.on("data", (data) => {
449
461
  const msg = data.toString().trim();
450
- if (msg && !msg.includes("Password:") && !msg.includes("password for")) {
462
+ // Mac/Linux: filter sudo password prompt noise
463
+ if (msg && (IS_WIN || (!msg.includes("Password:") && !msg.includes("password for")))) {
451
464
  err(msg);
452
465
  startError = msg;
453
466
  }
@@ -462,20 +475,16 @@ async function startServer(apiKey, sudoPassword) {
462
475
  });
463
476
  }
464
477
 
465
- const health = await pollMitmHealth(IS_WIN ? 15000 : 8000, MITM_PORT);
478
+ const health = await pollMitmHealth(8000, MITM_PORT);
466
479
  if (!health) {
467
- if (IS_WIN) serverProcess = null;
480
+ if (serverProcess && !serverProcess.killed) { try { serverProcess.kill(); } catch { /* ignore */ } serverProcess = null; }
468
481
  const processUsing443 = getProcessUsingPort443();
469
482
  const portInfo = processUsing443 ? ` Port 443 already in use by ${processUsing443}.` : "";
470
483
  const reason = startError || `Check sudo password or port 443 access.${portInfo}`;
471
484
  throw new Error(`MITM server failed to start. ${reason}`);
472
485
  }
473
486
 
474
- if (IS_WIN && _updateSettings) await _updateSettings({ mitmCertInstalled: true }).catch(() => { });
475
- if (IS_WIN && health.pid) {
476
- serverPid = health.pid;
477
- fs.writeFileSync(PID_FILE, String(serverPid));
478
- }
487
+ if (_updateSettings) await _updateSettings({ mitmCertInstalled: true }).catch(() => { });
479
488
 
480
489
  log(`✅ Server healthy (PID: ${serverPid || health.pid})`);
481
490
 
@@ -516,33 +525,15 @@ async function stopServer(sudoPassword) {
516
525
  serverPid = null;
517
526
 
518
527
  if (IS_WIN) {
519
- // Single elevated script: clean DNS + flush 1 UAC prompt only
528
+ // Process already has admin rightsedit hosts file directly
520
529
  const hostsFile = path.join(process.env.SystemRoot || "C:\\Windows", "System32", "drivers", "etc", "hosts");
521
- const psSQ = (s) => s.replace(/'/g, "''");
522
530
  const allHosts = Object.values(TOOL_HOSTS).flat();
523
-
524
- let hostsContent = "";
525
- try { hostsContent = fs.readFileSync(hostsFile, "utf8"); } catch { /* ignore */ }
526
- const filtered = hostsContent.split(/\r?\n/)
527
- .filter(l => !allHosts.some(h => l.includes(h)))
528
- .join("\r\n");
529
- const tmpHosts = path.join(os.tmpdir(), `mitm_hosts_clean_${Date.now()}.tmp`);
530
- fs.writeFileSync(tmpHosts, filtered, "utf8");
531
-
532
- const psScript = [
533
- `$ErrorActionPreference = 'Stop'`,
534
- `try {`,
535
- ` Copy-Item -Path '${psSQ(tmpHosts)}' -Destination '${psSQ(hostsFile)}' -Force -ErrorAction Stop`,
536
- ` ipconfig /flushdns | Out-Null`,
537
- ` Remove-Item '${psSQ(tmpHosts)}' -ErrorAction SilentlyContinue`,
538
- `} catch {`,
539
- ` Remove-Item '${psSQ(tmpHosts)}' -ErrorAction SilentlyContinue`,
540
- `}`,
541
- ].join("\n");
542
-
543
- const tmpPs1 = path.join(os.tmpdir(), `mitm_stop_${Date.now()}.ps1`);
544
- fs.writeFileSync(tmpPs1, psScript, "utf8");
545
- await executeElevatedPowerShell(tmpPs1, 30000);
531
+ try {
532
+ const hostsContent = fs.readFileSync(hostsFile, "utf8");
533
+ const filtered = hostsContent.split(/\r?\n/).filter(l => !allHosts.some(h => l.includes(h))).join("\r\n");
534
+ fs.writeFileSync(hostsFile, filtered, "utf8");
535
+ require("child_process").execSync("ipconfig /flushdns", { windowsHide: true });
536
+ } catch (e) { err(`Failed to clean hosts: ${e.message}`); }
546
537
  } else {
547
538
  await removeAllDNSEntries(sudoPassword);
548
539
  }
package/cli.js CHANGED
@@ -121,22 +121,20 @@ function killAllAppProcesses() {
121
121
  let pids = [];
122
122
 
123
123
  if (platform === "win32") {
124
- // Windows: use tasklist + findstr (works on all Windows versions)
124
+ // Windows: use WMI to get full CommandLine (tasklist /V doesn't include it)
125
125
  try {
126
- const output = execSync('tasklist /FO CSV /V 2>nul | findstr /I "node"', {
127
- encoding: 'utf8',
128
- shell: true,
126
+ const psCmd = `powershell -NonInteractive -WindowStyle Hidden -Command "Get-WmiObject Win32_Process -Filter 'Name=\\"node.exe\\"' | Select-Object ProcessId,CommandLine | ConvertTo-Csv -NoTypeInformation"`;
127
+ const output = execSync(psCmd, {
128
+ encoding: "utf8",
129
129
  windowsHide: true,
130
130
  timeout: 5000
131
131
  });
132
- const lines = output.split('\n').filter(l => l.trim());
133
-
132
+ const lines = output.split("\n").slice(1).filter(l => l.trim());
134
133
  lines.forEach(line => {
135
134
  const isAppProcess = line.toLowerCase().includes("9router") ||
136
135
  line.toLowerCase().includes("next-server");
137
136
  if (isAppProcess) {
138
- // CSV format: "name","pid",...
139
- const match = line.match(/"node\.exe","(\d+)"/i);
137
+ const match = line.match(/^"(\d+)"/);
140
138
  if (match && match[1] && match[1] !== process.pid.toString()) {
141
139
  pids.push(match[1]);
142
140
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "9router",
3
- "version": "0.3.54",
3
+ "version": "0.3.55",
4
4
  "description": "9Router CLI - Start and manage 9Router server",
5
5
  "bin": {
6
6
  "9router": "./cli.js"
@@ -1 +0,0 @@
1
- (self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[8460],{52154:(e,s,t)=>{"use strict";t.r(s),t.d(s,{default:()=>b});var r=t(95155),a=t(12115),l=t(5772),i=t(14051),n=t.n(i),o=t(35497),d=t(90620),c=t(52679),p=t(98500),m=t.n(p),x=t(65921);let u={available:{icon:"check_circle",color:"#22c55e",label:"Available"},cooldown:{icon:"schedule",color:"#f59e0b",label:"Cooldown"},unavailable:{icon:"error",color:"#ef4444",label:"Unavailable"},unknown:{icon:"help",color:"#6b7280",label:"Unknown"}};function h(){let[e,s]=(0,a.useState)(null),[t,l]=(0,a.useState)(!0),[i,n]=(0,a.useState)(!1),[d,c]=(0,a.useState)(null),p=(0,a.useRef)(null),m=(0,x.i)(),h=(0,a.useCallback)(async()=>{try{let e=await fetch("/api/models/availability");if(e.ok){let t=await e.json();s(t)}}catch{}finally{l(!1)}},[]);(0,a.useEffect)(()=>{h();let e=setInterval(h,3e4);return()=>clearInterval(e)},[h]),(0,a.useEffect)(()=>{let e=e=>{p.current&&!p.current.contains(e.target)&&n(!1)};return i&&document.addEventListener("mousedown",e),()=>document.removeEventListener("mousedown",e)},[i]);let f=async(e,s)=>{c(`${e}:${s}`);try{(await fetch("/api/models/availability",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({action:"clearCooldown",provider:e,model:s})})).ok?(m.success(`Cooldown cleared for ${s}`),await h()):m.error("Failed to clear cooldown")}catch{m.error("Failed to clear cooldown")}finally{c(null)}};if(t)return null;let b=e?.models||[],g=0===(e?.unavailableCount||b.filter(e=>"available"!==e.status).length),v={};return b.forEach(e=>{if("available"===e.status)return;let s=e.provider||"unknown";v[s]||(v[s]=[]),v[s].push(e)}),(0,r.jsx)("div",{className:"relative",ref:p,children:i&&(0,r.jsxs)("div",{className:"absolute top-full right-0 mt-2 w-80 bg-surface border border-border rounded-xl shadow-2xl z-50 overflow-hidden",children:[(0,r.jsxs)("div",{className:"flex items-center justify-between px-4 py-3 border-b border-border bg-bg",children:[(0,r.jsxs)("div",{className:"flex items-center gap-2",children:[(0,r.jsx)("span",{className:"material-symbols-outlined text-[16px]",style:{color:g?"#22c55e":"#f59e0b"},children:g?"verified":"warning"}),(0,r.jsx)("span",{className:"text-sm font-semibold text-text-main",children:"Model Status"})]}),(0,r.jsx)("button",{onClick:h,className:"p-1 rounded-lg hover:bg-surface text-text-muted hover:text-text-main transition-colors",title:"Refresh",children:(0,r.jsx)("span",{className:"material-symbols-outlined text-[14px]",children:"refresh"})})]}),(0,r.jsx)("div",{className:"px-4 py-3 max-h-60 overflow-y-auto",children:g?(0,r.jsx)("p",{className:"text-sm text-text-muted text-center py-2",children:"All models are responding normally."}):(0,r.jsx)("div",{className:"flex flex-col gap-2.5",children:Object.entries(v).map(([e,s])=>(0,r.jsxs)("div",{children:[(0,r.jsx)("p",{className:"text-xs font-semibold text-text-main mb-1.5 capitalize",children:e}),(0,r.jsx)("div",{className:"flex flex-col gap-1",children:s.map(e=>{let s=u[e.status]||u.unknown,t=d===`${e.provider}:${e.model}`;return(0,r.jsxs)("div",{className:"flex items-center justify-between px-2.5 py-1.5 rounded-lg bg-surface/30",children:[(0,r.jsxs)("div",{className:"flex items-center gap-1.5 min-w-0",children:[(0,r.jsx)("span",{className:"material-symbols-outlined text-[14px] shrink-0",style:{color:s.color},children:s.icon}),(0,r.jsx)("span",{className:"font-mono text-xs text-text-main truncate",children:e.model})]}),"cooldown"===e.status&&(0,r.jsx)(o.$n,{size:"sm",variant:"ghost",onClick:()=>f(e.provider,e.model),disabled:t,className:"text-[10px] px-1.5! py-0.5! ml-2",children:t?"...":"Clear"})]},`${e.provider}-${e.model}`)})})]},e))})})]})})}function f(e,s,t){let a=[];if(e>0&&a.push((0,r.jsxs)(o.Ex,{variant:"success",size:"sm",dot:!0,children:[e," Connected"]},"connected")),s>0){let e=t?`${s} Error (${t})`:`${s} Error`;a.push((0,r.jsx)(o.Ex,{variant:"error",size:"sm",dot:!0,children:e},"error"))}return 0===a.length?(0,r.jsx)("span",{className:"text-text-muted",children:"No connections"}):a}function b(){let[e,s]=(0,a.useState)([]),[t,l]=(0,a.useState)([]),[i,n]=(0,a.useState)(!0),[p,m]=(0,a.useState)(!1),[u,f]=(0,a.useState)(!1),[b,C]=(0,a.useState)(null),[w,k]=(0,a.useState)(null),T=(0,x.i)();(0,a.useEffect)(()=>{(async()=>{try{let[e,t]=await Promise.all([fetch("/api/providers"),fetch("/api/provider-nodes")]),r=await e.json(),a=await t.json();e.ok&&s(r.connections||[]),t.ok&&l(a.nodes||[])}catch(e){console.log("Error fetching data:",e)}finally{n(!1)}})()},[]);let A=(s,t)=>{let r=e.filter(e=>e.provider===s&&e.authType===t),a=e=>{let s=Object.entries(e).some(([e,s])=>e.startsWith("modelLock_")&&s&&new Date(s).getTime()>Date.now());return"unavailable"!==e.testStatus||s?e.testStatus:"active"},l=r.filter(e=>{let s=a(e);return"active"===s||"success"===s}).length,i=r.filter(e=>{let s=a(e);return"error"===s||"expired"===s||"unavailable"===s}),n=i.length,o=r.length,d=o>0&&r.every(e=>!1===e.isActive),c=i.sort((e,s)=>new Date(s.lastErrorAt||0)-new Date(e.lastErrorAt||0))[0];return{connected:l,error:n,total:o,errorCode:c?function(e){if(!e)return null;let s=e.lastErrorType;if("runtime_error"===s)return"RUNTIME";if("upstream_auth_error"===s||"auth_missing"===s||"token_refresh_failed"===s||"token_expired"===s)return"AUTH";if("upstream_rate_limited"===s)return"429";if("upstream_unavailable"===s)return"5XX";if("network_error"===s)return"NET";let t=Number(e.errorCode);if(Number.isFinite(t)&&t>=400)return String(t);let r=function(e){if(!e)return null;let s=e.match(/\b([45]\d{2})\b/);return s?s[1]:"ERR"}(e.lastError);if("401"===r||"403"===r)return"AUTH";if(r&&"ERR"!==r)return r;let a=(e.lastError||"").toLowerCase();return a.includes("runtime")||a.includes("not runnable")||a.includes("not installed")?"RUNTIME":a.includes("invalid api key")||a.includes("token invalid")||a.includes("revoked")||a.includes("unauthorized")?"AUTH":"ERR"}(c):null,errorTime:c?.lastErrorAt?function(e){if(!e)return"";let s=Math.floor((Date.now()-new Date(e).getTime())/6e4);if(s<1)return"just now";if(s<60)return`${s}m ago`;let t=Math.floor(s/60);if(t<24)return`${t}h ago`;let r=Math.floor(t/24);return`${r}d ago`}(c.lastErrorAt):null,allDisabled:d}},$=async(t,r,a)=>{let l=e.filter(e=>e.provider===t&&e.authType===r);s(e=>e.map(e=>e.provider===t&&e.authType===r?{...e,isActive:a}:e)),await Promise.allSettled(l.map(e=>fetch(`/api/providers/${e.id}`,{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({isActive:a})})))},E=async(e,s=null)=>{if(!b){C("provider"===e?s:e),k(null);try{let t=await fetch("/api/providers/test-batch",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({mode:e,providerId:s})}),r=await t.json();if(k(r),r.summary){let{passed:e,failed:s,total:t}=r.summary;0===s?T.success(`All ${t} tests passed`):T.warning(`${e}/${t} passed, ${s} failed`)}}catch(e){k({error:"Test request failed"}),T.error("Provider test failed")}finally{C(null)}}},S=t.filter(e=>"openai-compatible"===e.type).map(e=>({id:e.id,name:e.name||"OpenAI Compatible",color:"#10A37F",textIcon:"OC",apiType:e.apiType})),U=t.filter(e=>"anthropic-compatible"===e.type).map(e=>({id:e.id,name:e.name||"Anthropic Compatible",color:"#D97757",textIcon:"AC"}));return i?(0,r.jsxs)("div",{className:"flex flex-col gap-8",children:[(0,r.jsx)(o.Qv,{}),(0,r.jsx)(o.Qv,{})]}):(0,r.jsxs)("div",{className:"flex flex-col gap-6",children:[(0,r.jsxs)("div",{className:"flex flex-col gap-4",children:[(0,r.jsxs)("div",{className:"flex items-center justify-between",children:[(0,r.jsx)("h2",{className:"text-xl font-semibold flex items-center gap-2",children:"OAuth Providers"}),(0,r.jsxs)("div",{className:"flex items-center gap-2",children:[(0,r.jsx)(h,{}),(0,r.jsxs)("button",{onClick:()=>E("oauth"),disabled:!!b,className:`flex items-center gap-1.5 px-3 py-1.5 rounded-lg text-xs font-medium border transition-colors ${"oauth"===b?"bg-primary/20 border-primary/40 text-primary animate-pulse":"bg-bg border-border text-text-muted hover:text-text-main hover:border-primary/40"}`,title:"Test all OAuth connections","aria-label":"Test all OAuth connections",children:[(0,r.jsx)("span",{className:`material-symbols-outlined text-[14px]${"oauth"===b?" animate-spin":""}`,children:"oauth"===b?"sync":"play_arrow"}),"oauth"===b?"Testing...":"Test All"]})]})]}),(0,r.jsx)("div",{className:"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4",children:Object.entries(d.zN).map(([e,s])=>(0,r.jsx)(g,{providerId:e,provider:s,stats:A(e,"oauth"),authType:"oauth",onToggle:s=>$(e,"oauth",s)},e))})]}),(0,r.jsxs)("div",{className:"flex flex-col gap-4",children:[(0,r.jsxs)("div",{className:"flex items-center justify-between",children:[(0,r.jsx)("h2",{className:"text-xl font-semibold flex items-center gap-2",children:"Free Providers"}),(0,r.jsxs)("button",{onClick:()=>E("free"),disabled:!!b,className:`flex items-center gap-1.5 px-3 py-1.5 rounded-lg text-xs font-medium border transition-colors ${"free"===b?"bg-primary/20 border-primary/40 text-primary animate-pulse":"bg-bg border-border text-text-muted hover:text-text-main hover:border-primary/40"}`,title:"Test all Free connections","aria-label":"Test all Free provider connections",children:[(0,r.jsx)("span",{className:`material-symbols-outlined text-[14px]${"free"===b?" animate-spin":""}`,children:"free"===b?"sync":"play_arrow"}),"free"===b?"Testing...":"Test All"]})]}),(0,r.jsx)("div",{className:"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4",children:Object.entries(c.IS).map(([e,s])=>(0,r.jsx)(g,{providerId:e,provider:s,stats:A(e,"oauth"),authType:"free",onToggle:s=>$(e,"oauth",s)},e))})]}),(0,r.jsxs)("div",{className:"flex flex-col gap-4",children:[(0,r.jsxs)("div",{className:"flex items-center justify-between",children:[(0,r.jsxs)("h2",{className:"text-xl font-semibold flex items-center gap-2",children:["API Key Providers"," "]}),(0,r.jsxs)("button",{onClick:()=>E("apikey"),disabled:!!b,className:`flex items-center gap-1.5 px-3 py-1.5 rounded-lg text-xs font-medium border transition-colors ${"apikey"===b?"bg-primary/20 border-primary/40 text-primary animate-pulse":"bg-bg border-border text-text-muted hover:text-text-main hover:border-primary/40"}`,title:"Test all API Key connections","aria-label":"Test all API Key connections",children:[(0,r.jsx)("span",{className:`material-symbols-outlined text-[14px]${"apikey"===b?" animate-spin":""}`,children:"apikey"===b?"sync":"play_arrow"}),"apikey"===b?"Testing...":"Test All"]})]}),(0,r.jsx)("div",{className:"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4",children:Object.entries(d.fg).map(([e,s])=>(0,r.jsx)(v,{providerId:e,provider:s,stats:A(e,"apikey"),authType:"apikey",onToggle:s=>$(e,"apikey",s)},e))})]}),(0,r.jsxs)("div",{className:"flex flex-col gap-4",children:[(0,r.jsxs)("div",{className:"flex items-center justify-between",children:[(0,r.jsxs)("h2",{className:"text-xl font-semibold flex items-center gap-2",children:["API Key Compatible Providers"," "]}),(0,r.jsxs)("div",{className:"flex gap-2",children:[(0,r.jsx)(o.$n,{size:"sm",icon:"add",onClick:()=>f(!0),children:"Add Anthropic Compatible"}),(0,r.jsx)(o.$n,{size:"sm",variant:"secondary",icon:"add",onClick:()=>m(!0),className:"!bg-white !text-black hover:!bg-gray-100",children:"Add OpenAI Compatible"})]})]}),0===S.length&&0===U.length?(0,r.jsxs)("div",{className:"text-center py-8 border border-dashed border-border rounded-xl",children:[(0,r.jsx)("span",{className:"material-symbols-outlined text-[32px] text-text-muted mb-2",children:"extension"}),(0,r.jsx)("p",{className:"text-text-muted text-sm",children:"No compatible providers added yet"}),(0,r.jsx)("p",{className:"text-text-muted text-xs mt-1",children:"Use the buttons above to add OpenAI or Anthropic compatible endpoints"})]}):(0,r.jsx)("div",{className:"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4",children:[...S,...U].map(e=>(0,r.jsx)(v,{providerId:e.id,provider:e,stats:A(e.id,"apikey"),authType:"compatible",onToggle:s=>$(e.id,"apikey",s)},e.id))})]}),(0,r.jsx)(y,{isOpen:p,onClose:()=>m(!1),onCreated:e=>{l(s=>[...s,e]),m(!1)}}),(0,r.jsx)(j,{isOpen:u,onClose:()=>f(!1),onCreated:e=>{l(s=>[...s,e]),f(!1)}}),w&&(0,r.jsxs)("div",{className:"fixed inset-0 z-50 flex items-start justify-center pt-[10vh]",onClick:()=>k(null),children:[(0,r.jsx)("div",{className:"absolute inset-0 bg-black/60 backdrop-blur-sm"}),(0,r.jsxs)("div",{className:"relative bg-surface border border-border rounded-xl w-full max-w-[600px] max-h-[80vh] overflow-y-auto shadow-2xl",onClick:e=>e.stopPropagation(),children:[(0,r.jsxs)("div",{className:"sticky top-0 z-10 flex items-center justify-between px-5 py-3 border-b border-border bg-surface/95 backdrop-blur-sm rounded-t-xl",children:[(0,r.jsx)("h3",{className:"font-semibold",children:"Test Results"}),(0,r.jsx)("button",{onClick:()=>k(null),className:"p-1 rounded-lg hover:bg-bg text-text-muted hover:text-text-main transition-colors","aria-label":"Close test results",children:(0,r.jsx)("span",{className:"material-symbols-outlined text-lg",children:"close"})})]}),(0,r.jsx)("div",{className:"p-5",children:(0,r.jsx)(N,{results:w})})]})]})]})}function g({providerId:e,provider:s,stats:t,authType:i,onToggle:n}){let{connected:d,error:c,errorCode:p,errorTime:x,allDisabled:u}=t,[h,b]=(0,a.useState)(!1);return(0,r.jsx)(m(),{href:`/dashboard/providers/${e}`,className:"group",children:(0,r.jsx)(o.Zp,{padding:"xs",className:`h-full hover:bg-black/[0.01] dark:hover:bg-white/[0.01] transition-colors cursor-pointer ${u?"opacity-50":""}`,children:(0,r.jsxs)("div",{className:"flex items-center justify-between",children:[(0,r.jsxs)("div",{className:"flex items-center gap-3",children:[(0,r.jsx)("div",{className:"size-8 rounded-lg flex items-center justify-center",style:{backgroundColor:`${s.color?.length>7?s.color:s.color+"15"}`},children:h?(0,r.jsx)("span",{className:"text-xs font-bold",style:{color:s.color},children:s.textIcon||s.id.slice(0,2).toUpperCase()}):(0,r.jsx)(l.default,{src:`/providers/${s.id}.png`,alt:s.name,width:30,height:30,className:"object-contain rounded-lg max-w-[32px] max-h-[32px]",sizes:"32px",onError:()=>b(!0)})}),(0,r.jsxs)("div",{children:[(0,r.jsx)("h3",{className:"font-semibold",children:s.name}),(0,r.jsx)("div",{className:"flex items-center gap-2 text-xs flex-wrap",children:u?(0,r.jsx)(o.Ex,{variant:"default",size:"sm",children:(0,r.jsxs)("span",{className:"flex items-center gap-1",children:[(0,r.jsx)("span",{className:"material-symbols-outlined text-[12px]",children:"pause_circle"}),"Disabled"]})}):(0,r.jsxs)(r.Fragment,{children:[f(d,c,p),x&&(0,r.jsx)("span",{className:"text-text-muted",children:x})]})})]})]}),(0,r.jsx)("div",{className:"flex items-center gap-2",children:t.total>0&&(0,r.jsx)("div",{className:"opacity-0 group-hover:opacity-100 transition-opacity",onClick:e=>{e.preventDefault(),e.stopPropagation(),n(!!u)},children:(0,r.jsx)(o.lM,{size:"sm",checked:!u,onChange:()=>{},title:u?"Enable provider":"Disable provider"})})})]})})})}function v({providerId:e,provider:s,stats:t,authType:i,onToggle:n}){let{connected:d,error:p,errorCode:x,errorTime:u,allDisabled:h}=t,b=e.startsWith(c.JH),g=e.startsWith(c.DI),[v,y]=(0,a.useState)(!1);return(0,r.jsx)(m(),{href:`/dashboard/providers/${e}`,className:"group",children:(0,r.jsx)(o.Zp,{padding:"xs",className:`h-full hover:bg-black/[0.01] dark:hover:bg-white/[0.01] transition-colors cursor-pointer ${h?"opacity-50":""}`,children:(0,r.jsxs)("div",{className:"flex items-center justify-between",children:[(0,r.jsxs)("div",{className:"flex items-center gap-3",children:[(0,r.jsx)("div",{className:"size-8 rounded-lg flex items-center justify-center",style:{backgroundColor:`${s.color?.length>7?s.color:s.color+"15"}`},children:v?(0,r.jsx)("span",{className:"text-xs font-bold",style:{color:s.color},children:s.textIcon||s.id.slice(0,2).toUpperCase()}):(0,r.jsx)(l.default,{src:b?"responses"===s.apiType?"/providers/oai-r.png":"/providers/oai-cc.png":g?"/providers/anthropic-m.png":`/providers/${s.id}.png`,alt:s.name,width:30,height:30,className:"object-contain rounded-lg max-w-[30px] max-h-[30px]",sizes:"30px",onError:()=>y(!0)})}),(0,r.jsxs)("div",{children:[(0,r.jsx)("h3",{className:"font-semibold",children:s.name}),(0,r.jsx)("div",{className:"flex items-center gap-2 text-xs flex-wrap",children:h?(0,r.jsx)(o.Ex,{variant:"default",size:"sm",children:(0,r.jsxs)("span",{className:"flex items-center gap-1",children:[(0,r.jsx)("span",{className:"material-symbols-outlined text-[12px]",children:"pause_circle"}),"Disabled"]})}):(0,r.jsxs)(r.Fragment,{children:[f(d,p,x),b&&(0,r.jsx)(o.Ex,{variant:"default",size:"sm",children:"responses"===s.apiType?"Responses":"Chat"}),g&&(0,r.jsx)(o.Ex,{variant:"default",size:"sm",children:"Messages"}),u&&(0,r.jsx)("span",{className:"text-text-muted",children:u})]})})]})]}),(0,r.jsx)("div",{className:"flex items-center gap-2",children:t.total>0&&(0,r.jsx)("div",{className:"opacity-0 group-hover:opacity-100 transition-opacity",onClick:e=>{e.preventDefault(),e.stopPropagation(),n(!!h)},children:(0,r.jsx)(o.lM,{size:"sm",checked:!h,onChange:()=>{},title:h?"Enable provider":"Disable provider"})})})]})})})}function y({isOpen:e,onClose:s,onCreated:t}){let[l,i]=(0,a.useState)({name:"",prefix:"",apiType:"chat",baseUrl:"https://api.openai.com/v1"}),[n,d]=(0,a.useState)(!1),[c,p]=(0,a.useState)(""),[m,x]=(0,a.useState)(!1),[u,h]=(0,a.useState)(null);(0,a.useEffect)(()=>{i(e=>({...e,baseUrl:"https://api.openai.com/v1"}))},[l.apiType]);let f=async()=>{if(l.name.trim()&&l.prefix.trim()&&l.baseUrl.trim()){d(!0);try{let e=await fetch("/api/provider-nodes",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:l.name,prefix:l.prefix,apiType:l.apiType,baseUrl:l.baseUrl,type:"openai-compatible"})}),s=await e.json();e.ok&&(t(s.node),i({name:"",prefix:"",apiType:"chat",baseUrl:"https://api.openai.com/v1"}),p(""),h(null))}catch(e){console.log("Error creating OpenAI Compatible node:",e)}finally{d(!1)}}},b=async()=>{x(!0);try{let e=await fetch("/api/provider-nodes/validate",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({baseUrl:l.baseUrl,apiKey:c,type:"openai-compatible"})}),s=await e.json();h(s.valid?"success":"failed")}catch{h("failed")}finally{x(!1)}};return(0,r.jsx)(o.aF,{isOpen:e,title:"Add OpenAI Compatible",onClose:s,children:(0,r.jsxs)("div",{className:"flex flex-col gap-4",children:[(0,r.jsx)(o.pd,{label:"Name",value:l.name,onChange:e=>i({...l,name:e.target.value}),placeholder:"OpenAI Compatible (Prod)",hint:"Required. A friendly label for this node."}),(0,r.jsx)(o.pd,{label:"Prefix",value:l.prefix,onChange:e=>i({...l,prefix:e.target.value}),placeholder:"oc-prod",hint:"Required. Used as the provider prefix for model IDs."}),(0,r.jsx)(o.l6,{label:"API Type",options:[{value:"chat",label:"Chat Completions"},{value:"responses",label:"Responses API"}],value:l.apiType,onChange:e=>i({...l,apiType:e.target.value})}),(0,r.jsx)(o.pd,{label:"Base URL",value:l.baseUrl,onChange:e=>i({...l,baseUrl:e.target.value}),placeholder:"https://api.openai.com/v1",hint:"Use the base URL (ending in /v1) for your OpenAI-compatible API."}),(0,r.jsxs)("div",{className:"flex gap-2",children:[(0,r.jsx)(o.pd,{label:"API Key (for Check)",type:"password",value:c,onChange:e=>p(e.target.value),className:"flex-1"}),(0,r.jsx)("div",{className:"pt-6",children:(0,r.jsx)(o.$n,{onClick:b,disabled:!c||m||!l.baseUrl.trim(),variant:"secondary",children:m?"Checking...":"Check"})})]}),u&&(0,r.jsx)(o.Ex,{variant:"success"===u?"success":"error",children:"success"===u?"Valid":"Invalid"}),(0,r.jsxs)("div",{className:"flex gap-2",children:[(0,r.jsx)(o.$n,{onClick:f,fullWidth:!0,disabled:!l.name.trim()||!l.prefix.trim()||!l.baseUrl.trim()||n,children:n?"Creating...":"Create"}),(0,r.jsx)(o.$n,{onClick:s,variant:"ghost",fullWidth:!0,children:"Cancel"})]})]})})}function j({isOpen:e,onClose:s,onCreated:t}){let[l,i]=(0,a.useState)({name:"",prefix:"",baseUrl:"https://api.anthropic.com/v1"}),[n,d]=(0,a.useState)(!1),[c,p]=(0,a.useState)(""),[m,x]=(0,a.useState)(!1),[u,h]=(0,a.useState)(null);(0,a.useEffect)(()=>{e&&(h(null),p(""))},[e]);let f=async()=>{if(l.name.trim()&&l.prefix.trim()&&l.baseUrl.trim()){d(!0);try{let e=await fetch("/api/provider-nodes",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:l.name,prefix:l.prefix,baseUrl:l.baseUrl,type:"anthropic-compatible"})}),s=await e.json();e.ok&&(t(s.node),i({name:"",prefix:"",baseUrl:"https://api.anthropic.com/v1"}),p(""),h(null))}catch(e){console.log("Error creating Anthropic Compatible node:",e)}finally{d(!1)}}},b=async()=>{x(!0);try{let e=await fetch("/api/provider-nodes/validate",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({baseUrl:l.baseUrl,apiKey:c,type:"anthropic-compatible"})}),s=await e.json();h(s.valid?"success":"failed")}catch{h("failed")}finally{x(!1)}};return(0,r.jsx)(o.aF,{isOpen:e,title:"Add Anthropic Compatible",onClose:s,children:(0,r.jsxs)("div",{className:"flex flex-col gap-4",children:[(0,r.jsx)(o.pd,{label:"Name",value:l.name,onChange:e=>i({...l,name:e.target.value}),placeholder:"Anthropic Compatible (Prod)",hint:"Required. A friendly label for this node."}),(0,r.jsx)(o.pd,{label:"Prefix",value:l.prefix,onChange:e=>i({...l,prefix:e.target.value}),placeholder:"ac-prod",hint:"Required. Used as the provider prefix for model IDs."}),(0,r.jsx)(o.pd,{label:"Base URL",value:l.baseUrl,onChange:e=>i({...l,baseUrl:e.target.value}),placeholder:"https://api.anthropic.com/v1",hint:"Use the base URL (ending in /v1) for your Anthropic-compatible API. The system will append /messages."}),(0,r.jsxs)("div",{className:"flex gap-2",children:[(0,r.jsx)(o.pd,{label:"API Key (for Check)",type:"password",value:c,onChange:e=>p(e.target.value),className:"flex-1"}),(0,r.jsx)("div",{className:"pt-6",children:(0,r.jsx)(o.$n,{onClick:b,disabled:!c||m||!l.baseUrl.trim(),variant:"secondary",children:m?"Checking...":"Check"})})]}),u&&(0,r.jsx)(o.Ex,{variant:"success"===u?"success":"error",children:"success"===u?"Valid":"Invalid"}),(0,r.jsxs)("div",{className:"flex gap-2",children:[(0,r.jsx)(o.$n,{onClick:f,fullWidth:!0,disabled:!l.name.trim()||!l.prefix.trim()||!l.baseUrl.trim()||n,children:n?"Creating...":"Create"}),(0,r.jsx)(o.$n,{onClick:s,variant:"ghost",fullWidth:!0,children:"Cancel"})]})]})})}function N({results:e}){if(e.error&&!e.results)return(0,r.jsxs)("div",{className:"text-center py-6",children:[(0,r.jsx)("span",{className:"material-symbols-outlined text-red-500 text-[32px] mb-2 block",children:"error"}),(0,r.jsx)("p",{className:"text-sm text-red-400",children:e.error})]});let{summary:s,mode:t}=e,a=e.results||[];return(0,r.jsxs)("div",{className:"flex flex-col gap-3",children:[s&&(0,r.jsxs)("div",{className:"flex items-center gap-3 text-xs mb-1",children:[(0,r.jsxs)("span",{className:"text-text-muted",children:[{oauth:"OAuth",free:"Free",apikey:"API Key",provider:"Provider",all:"All"}[t]||t," Test"]}),(0,r.jsxs)("span",{className:"px-2 py-0.5 rounded bg-emerald-500/15 text-emerald-400 font-medium",children:[s.passed," passed"]}),s.failed>0&&(0,r.jsxs)("span",{className:"px-2 py-0.5 rounded bg-red-500/15 text-red-400 font-medium",children:[s.failed," failed"]}),(0,r.jsxs)("span",{className:"text-text-muted ml-auto",children:[s.total," tested"]})]}),a.map((e,s)=>(0,r.jsxs)("div",{className:"flex items-center gap-2 text-xs px-3 py-2 rounded-lg bg-black/[0.03] dark:bg-white/[0.03]",children:[(0,r.jsx)("span",{className:`material-symbols-outlined text-[16px] ${e.valid?"text-emerald-500":"text-red-500"}`,children:e.valid?"check_circle":"error"}),(0,r.jsxs)("div",{className:"flex-1 min-w-0",children:[(0,r.jsx)("span",{className:"font-medium",children:e.connectionName}),(0,r.jsxs)("span",{className:"text-text-muted ml-1.5",children:["(",e.provider,")"]})]}),void 0!==e.latencyMs&&(0,r.jsxs)("span",{className:"text-text-muted font-mono tabular-nums",children:[e.latencyMs,"ms"]}),(0,r.jsx)("span",{className:`text-[10px] uppercase font-bold px-1.5 py-0.5 rounded ${e.valid?"bg-emerald-500/15 text-emerald-400":"bg-red-500/15 text-red-400"}`,children:e.valid?"OK":e.diagnosis?.type||"ERROR"})]},e.connectionId||s)),0===a.length&&(0,r.jsx)("div",{className:"text-center py-4 text-text-muted text-sm",children:"No active connections found for this group."})]})}g.propTypes={providerId:n().string.isRequired,provider:n().shape({id:n().string.isRequired,name:n().string.isRequired,color:n().string,textIcon:n().string}).isRequired,stats:n().shape({connected:n().number,error:n().number,errorCode:n().string,errorTime:n().string}).isRequired,authType:n().string,onToggle:n().func},v.propTypes={providerId:n().string.isRequired,provider:n().shape({id:n().string.isRequired,name:n().string.isRequired,color:n().string,textIcon:n().string,apiType:n().string}).isRequired,stats:n().shape({connected:n().number,error:n().number,errorCode:n().string,errorTime:n().string}).isRequired,authType:n().string,onToggle:n().func},y.propTypes={isOpen:n().bool.isRequired,onClose:n().func.isRequired,onCreated:n().func.isRequired},j.propTypes={isOpen:n().bool.isRequired,onClose:n().func.isRequired,onCreated:n().func.isRequired},N.propTypes={results:n().shape({mode:n().string,results:n().array,summary:n().shape({total:n().number,passed:n().number,failed:n().number}),error:n().string}).isRequired}},63117:(e,s,t)=>{Promise.resolve().then(t.bind(t,52154))}},e=>{e.O(0,[5370,4335,5772,619,2652,5497,8441,3794,7358],()=>e(e.s=63117)),_N_E=e.O()}]);