n9router 0.3.93 → 0.3.95

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 (331) hide show
  1. package/.next/standalone/.next/BUILD_ID +1 -1
  2. package/.next/standalone/.next/build-manifest.json +3 -3
  3. package/.next/standalone/.next/server/app/(dashboard)/dashboard/basic-chat/page.js.nft.json +1 -1
  4. package/.next/standalone/.next/server/app/(dashboard)/dashboard/basic-chat/page_client-reference-manifest.js +1 -1
  5. package/.next/standalone/.next/server/app/(dashboard)/dashboard/cli-tools/page.js.nft.json +1 -1
  6. package/.next/standalone/.next/server/app/(dashboard)/dashboard/cli-tools/page_client-reference-manifest.js +1 -1
  7. package/.next/standalone/.next/server/app/(dashboard)/dashboard/combos/page.js.nft.json +1 -1
  8. package/.next/standalone/.next/server/app/(dashboard)/dashboard/combos/page_client-reference-manifest.js +1 -1
  9. package/.next/standalone/.next/server/app/(dashboard)/dashboard/console-log/page.js.nft.json +1 -1
  10. package/.next/standalone/.next/server/app/(dashboard)/dashboard/console-log/page_client-reference-manifest.js +1 -1
  11. package/.next/standalone/.next/server/app/(dashboard)/dashboard/endpoint/page.js.nft.json +1 -1
  12. package/.next/standalone/.next/server/app/(dashboard)/dashboard/endpoint/page_client-reference-manifest.js +1 -1
  13. package/.next/standalone/.next/server/app/(dashboard)/dashboard/mitm/page.js.nft.json +1 -1
  14. package/.next/standalone/.next/server/app/(dashboard)/dashboard/mitm/page_client-reference-manifest.js +1 -1
  15. package/.next/standalone/.next/server/app/(dashboard)/dashboard/page.js.nft.json +1 -1
  16. package/.next/standalone/.next/server/app/(dashboard)/dashboard/page_client-reference-manifest.js +1 -1
  17. package/.next/standalone/.next/server/app/(dashboard)/dashboard/profile/page.js.nft.json +1 -1
  18. package/.next/standalone/.next/server/app/(dashboard)/dashboard/profile/page_client-reference-manifest.js +1 -1
  19. package/.next/standalone/.next/server/app/(dashboard)/dashboard/providers/[id]/page.js.nft.json +1 -1
  20. package/.next/standalone/.next/server/app/(dashboard)/dashboard/providers/[id]/page_client-reference-manifest.js +1 -1
  21. package/.next/standalone/.next/server/app/(dashboard)/dashboard/providers/new/page.js.nft.json +1 -1
  22. package/.next/standalone/.next/server/app/(dashboard)/dashboard/providers/new/page_client-reference-manifest.js +1 -1
  23. package/.next/standalone/.next/server/app/(dashboard)/dashboard/providers/page.js.nft.json +1 -1
  24. package/.next/standalone/.next/server/app/(dashboard)/dashboard/providers/page_client-reference-manifest.js +1 -1
  25. package/.next/standalone/.next/server/app/(dashboard)/dashboard/proxy-pools/page.js.nft.json +1 -1
  26. package/.next/standalone/.next/server/app/(dashboard)/dashboard/proxy-pools/page_client-reference-manifest.js +1 -1
  27. package/.next/standalone/.next/server/app/(dashboard)/dashboard/quota/page.js.nft.json +1 -1
  28. package/.next/standalone/.next/server/app/(dashboard)/dashboard/quota/page_client-reference-manifest.js +1 -1
  29. package/.next/standalone/.next/server/app/(dashboard)/dashboard/translator/page.js.nft.json +1 -1
  30. package/.next/standalone/.next/server/app/(dashboard)/dashboard/translator/page_client-reference-manifest.js +1 -1
  31. package/.next/standalone/.next/server/app/(dashboard)/dashboard/usage/page.js.nft.json +1 -1
  32. package/.next/standalone/.next/server/app/(dashboard)/dashboard/usage/page_client-reference-manifest.js +1 -1
  33. package/.next/standalone/.next/server/app/_global-error.html +1 -1
  34. package/.next/standalone/.next/server/app/_global-error.rsc +1 -1
  35. package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  36. package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  37. package/.next/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  38. package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  39. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  40. package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  41. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  42. package/.next/standalone/.next/server/app/_not-found.html +1 -1
  43. package/.next/standalone/.next/server/app/_not-found.rsc +10 -10
  44. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +10 -10
  45. package/.next/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +4 -4
  46. package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +5 -5
  47. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
  48. package/.next/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
  49. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  50. package/.next/standalone/.next/server/app/api/antigravity-tools/import/route.js.nft.json +1 -1
  51. package/.next/standalone/.next/server/app/api/antigravity-tools/import-refresh-tokens/route.js.nft.json +1 -1
  52. package/.next/standalone/.next/server/app/api/auth/login/route.js.nft.json +1 -1
  53. package/.next/standalone/.next/server/app/api/cli-tools/antigravity-mitm/alias/route.js.nft.json +1 -1
  54. package/.next/standalone/.next/server/app/api/cli-tools/antigravity-mitm/route.js.nft.json +1 -1
  55. package/.next/standalone/.next/server/app/api/cloud/auth/route.js.nft.json +1 -1
  56. package/.next/standalone/.next/server/app/api/cloud/credentials/update/route.js.nft.json +1 -1
  57. package/.next/standalone/.next/server/app/api/cloud/model/resolve/route.js.nft.json +1 -1
  58. package/.next/standalone/.next/server/app/api/cloud/models/alias/route.js.nft.json +1 -1
  59. package/.next/standalone/.next/server/app/api/combos/[id]/route.js.nft.json +1 -1
  60. package/.next/standalone/.next/server/app/api/combos/route.js.nft.json +1 -1
  61. package/.next/standalone/.next/server/app/api/init/route.js.nft.json +1 -1
  62. package/.next/standalone/.next/server/app/api/internal/request-detail/route.js.nft.json +1 -1
  63. package/.next/standalone/.next/server/app/api/internal/usage/route.js.nft.json +1 -1
  64. package/.next/standalone/.next/server/app/api/keys/[id]/route.js.nft.json +1 -1
  65. package/.next/standalone/.next/server/app/api/keys/route.js.nft.json +1 -1
  66. package/.next/standalone/.next/server/app/api/models/alias/route.js.nft.json +1 -1
  67. package/.next/standalone/.next/server/app/api/models/availability/route.js.nft.json +1 -1
  68. package/.next/standalone/.next/server/app/api/models/route.js.nft.json +1 -1
  69. package/.next/standalone/.next/server/app/api/models/test/route.js.nft.json +1 -1
  70. package/.next/standalone/.next/server/app/api/oauth/[provider]/[action]/route.js.nft.json +1 -1
  71. package/.next/standalone/.next/server/app/api/oauth/cursor/import/route.js.nft.json +1 -1
  72. package/.next/standalone/.next/server/app/api/oauth/gitlab/pat/route.js.nft.json +1 -1
  73. package/.next/standalone/.next/server/app/api/oauth/iflow/cookie/route.js.nft.json +1 -1
  74. package/.next/standalone/.next/server/app/api/oauth/kiro/import/route.js.nft.json +1 -1
  75. package/.next/standalone/.next/server/app/api/oauth/kiro/social-exchange/route.js.nft.json +1 -1
  76. package/.next/standalone/.next/server/app/api/pricing/route.js.nft.json +1 -1
  77. package/.next/standalone/.next/server/app/api/provider-nodes/[id]/route.js.nft.json +1 -1
  78. package/.next/standalone/.next/server/app/api/provider-nodes/route.js.nft.json +1 -1
  79. package/.next/standalone/.next/server/app/api/providers/[id]/models/route.js.nft.json +1 -1
  80. package/.next/standalone/.next/server/app/api/providers/[id]/route.js.nft.json +1 -1
  81. package/.next/standalone/.next/server/app/api/providers/[id]/test/route.js.nft.json +1 -1
  82. package/.next/standalone/.next/server/app/api/providers/[id]/test-models/route.js.nft.json +1 -1
  83. package/.next/standalone/.next/server/app/api/providers/client/route.js.nft.json +1 -1
  84. package/.next/standalone/.next/server/app/api/providers/route.js.nft.json +1 -1
  85. package/.next/standalone/.next/server/app/api/providers/test-batch/route.js.nft.json +1 -1
  86. package/.next/standalone/.next/server/app/api/providers/validate/route.js.nft.json +1 -1
  87. package/.next/standalone/.next/server/app/api/proxy-pools/[id]/route.js.nft.json +1 -1
  88. package/.next/standalone/.next/server/app/api/proxy-pools/[id]/test/route.js.nft.json +1 -1
  89. package/.next/standalone/.next/server/app/api/proxy-pools/route.js.nft.json +1 -1
  90. package/.next/standalone/.next/server/app/api/settings/database/route.js.nft.json +1 -1
  91. package/.next/standalone/.next/server/app/api/settings/require-login/route.js.nft.json +1 -1
  92. package/.next/standalone/.next/server/app/api/settings/route.js.nft.json +1 -1
  93. package/.next/standalone/.next/server/app/api/translator/send/route.js.nft.json +1 -1
  94. package/.next/standalone/.next/server/app/api/translator/translate/route.js.nft.json +1 -1
  95. package/.next/standalone/.next/server/app/api/tunnel/disable/route.js.nft.json +1 -1
  96. package/.next/standalone/.next/server/app/api/tunnel/enable/route.js.nft.json +1 -1
  97. package/.next/standalone/.next/server/app/api/tunnel/status/route.js.nft.json +1 -1
  98. package/.next/standalone/.next/server/app/api/usage/[connectionId]/route.js.nft.json +1 -1
  99. package/.next/standalone/.next/server/app/api/usage/chart/route.js.nft.json +1 -1
  100. package/.next/standalone/.next/server/app/api/usage/history/route.js.nft.json +1 -1
  101. package/.next/standalone/.next/server/app/api/usage/logs/route.js.nft.json +1 -1
  102. package/.next/standalone/.next/server/app/api/usage/providers/route.js.nft.json +1 -1
  103. package/.next/standalone/.next/server/app/api/usage/request-details/route.js.nft.json +1 -1
  104. package/.next/standalone/.next/server/app/api/usage/request-logs/route.js.nft.json +1 -1
  105. package/.next/standalone/.next/server/app/api/usage/stats/route.js.nft.json +1 -1
  106. package/.next/standalone/.next/server/app/api/usage/stream/route.js.nft.json +1 -1
  107. package/.next/standalone/.next/server/app/api/v1/api/chat/route.js.nft.json +1 -1
  108. package/.next/standalone/.next/server/app/api/v1/chat/completions/route.js.nft.json +1 -1
  109. package/.next/standalone/.next/server/app/api/v1/embeddings/route.js.nft.json +1 -1
  110. package/.next/standalone/.next/server/app/api/v1/messages/route.js.nft.json +1 -1
  111. package/.next/standalone/.next/server/app/api/v1/models/route.js.nft.json +1 -1
  112. package/.next/standalone/.next/server/app/api/v1/responses/route.js.nft.json +1 -1
  113. package/.next/standalone/.next/server/app/api/v1beta/models/[...path]/route.js.nft.json +1 -1
  114. package/.next/standalone/.next/server/app/callback/page.js.nft.json +1 -1
  115. package/.next/standalone/.next/server/app/callback/page_client-reference-manifest.js +1 -1
  116. package/.next/standalone/.next/server/app/callback.html +1 -1
  117. package/.next/standalone/.next/server/app/callback.rsc +12 -12
  118. package/.next/standalone/.next/server/app/callback.segments/_full.segment.rsc +12 -12
  119. package/.next/standalone/.next/server/app/callback.segments/_head.segment.rsc +4 -4
  120. package/.next/standalone/.next/server/app/callback.segments/_index.segment.rsc +5 -5
  121. package/.next/standalone/.next/server/app/callback.segments/_tree.segment.rsc +1 -1
  122. package/.next/standalone/.next/server/app/callback.segments/callback/__PAGE__.segment.rsc +4 -4
  123. package/.next/standalone/.next/server/app/callback.segments/callback.segment.rsc +3 -3
  124. package/.next/standalone/.next/server/app/dashboard/basic-chat.html +1 -1
  125. package/.next/standalone/.next/server/app/dashboard/basic-chat.rsc +12 -12
  126. package/.next/standalone/.next/server/app/dashboard/basic-chat.segments/!KGRhc2hib2FyZCk/dashboard/basic-chat/__PAGE__.segment.rsc +3 -3
  127. package/.next/standalone/.next/server/app/dashboard/basic-chat.segments/!KGRhc2hib2FyZCk/dashboard/basic-chat.segment.rsc +3 -3
  128. package/.next/standalone/.next/server/app/dashboard/basic-chat.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +3 -3
  129. package/.next/standalone/.next/server/app/dashboard/basic-chat.segments/!KGRhc2hib2FyZCk.segment.rsc +4 -4
  130. package/.next/standalone/.next/server/app/dashboard/basic-chat.segments/_full.segment.rsc +12 -12
  131. package/.next/standalone/.next/server/app/dashboard/basic-chat.segments/_head.segment.rsc +4 -4
  132. package/.next/standalone/.next/server/app/dashboard/basic-chat.segments/_index.segment.rsc +5 -5
  133. package/.next/standalone/.next/server/app/dashboard/basic-chat.segments/_tree.segment.rsc +1 -1
  134. package/.next/standalone/.next/server/app/dashboard/cli-tools.html +1 -1
  135. package/.next/standalone/.next/server/app/dashboard/cli-tools.rsc +12 -12
  136. package/.next/standalone/.next/server/app/dashboard/cli-tools.segments/!KGRhc2hib2FyZCk/dashboard/cli-tools/__PAGE__.segment.rsc +3 -3
  137. package/.next/standalone/.next/server/app/dashboard/cli-tools.segments/!KGRhc2hib2FyZCk/dashboard/cli-tools.segment.rsc +3 -3
  138. package/.next/standalone/.next/server/app/dashboard/cli-tools.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +3 -3
  139. package/.next/standalone/.next/server/app/dashboard/cli-tools.segments/!KGRhc2hib2FyZCk.segment.rsc +4 -4
  140. package/.next/standalone/.next/server/app/dashboard/cli-tools.segments/_full.segment.rsc +12 -12
  141. package/.next/standalone/.next/server/app/dashboard/cli-tools.segments/_head.segment.rsc +4 -4
  142. package/.next/standalone/.next/server/app/dashboard/cli-tools.segments/_index.segment.rsc +5 -5
  143. package/.next/standalone/.next/server/app/dashboard/cli-tools.segments/_tree.segment.rsc +1 -1
  144. package/.next/standalone/.next/server/app/dashboard/combos.html +1 -1
  145. package/.next/standalone/.next/server/app/dashboard/combos.rsc +13 -13
  146. package/.next/standalone/.next/server/app/dashboard/combos.segments/!KGRhc2hib2FyZCk/dashboard/combos/__PAGE__.segment.rsc +4 -4
  147. package/.next/standalone/.next/server/app/dashboard/combos.segments/!KGRhc2hib2FyZCk/dashboard/combos.segment.rsc +3 -3
  148. package/.next/standalone/.next/server/app/dashboard/combos.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +3 -3
  149. package/.next/standalone/.next/server/app/dashboard/combos.segments/!KGRhc2hib2FyZCk.segment.rsc +4 -4
  150. package/.next/standalone/.next/server/app/dashboard/combos.segments/_full.segment.rsc +13 -13
  151. package/.next/standalone/.next/server/app/dashboard/combos.segments/_head.segment.rsc +4 -4
  152. package/.next/standalone/.next/server/app/dashboard/combos.segments/_index.segment.rsc +5 -5
  153. package/.next/standalone/.next/server/app/dashboard/combos.segments/_tree.segment.rsc +1 -1
  154. package/.next/standalone/.next/server/app/dashboard/endpoint.html +1 -1
  155. package/.next/standalone/.next/server/app/dashboard/endpoint.rsc +12 -12
  156. package/.next/standalone/.next/server/app/dashboard/endpoint.segments/!KGRhc2hib2FyZCk/dashboard/endpoint/__PAGE__.segment.rsc +3 -3
  157. package/.next/standalone/.next/server/app/dashboard/endpoint.segments/!KGRhc2hib2FyZCk/dashboard/endpoint.segment.rsc +3 -3
  158. package/.next/standalone/.next/server/app/dashboard/endpoint.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +3 -3
  159. package/.next/standalone/.next/server/app/dashboard/endpoint.segments/!KGRhc2hib2FyZCk.segment.rsc +4 -4
  160. package/.next/standalone/.next/server/app/dashboard/endpoint.segments/_full.segment.rsc +12 -12
  161. package/.next/standalone/.next/server/app/dashboard/endpoint.segments/_head.segment.rsc +4 -4
  162. package/.next/standalone/.next/server/app/dashboard/endpoint.segments/_index.segment.rsc +5 -5
  163. package/.next/standalone/.next/server/app/dashboard/endpoint.segments/_tree.segment.rsc +1 -1
  164. package/.next/standalone/.next/server/app/dashboard/mitm.html +1 -1
  165. package/.next/standalone/.next/server/app/dashboard/mitm.rsc +12 -12
  166. package/.next/standalone/.next/server/app/dashboard/mitm.segments/!KGRhc2hib2FyZCk/dashboard/mitm/__PAGE__.segment.rsc +3 -3
  167. package/.next/standalone/.next/server/app/dashboard/mitm.segments/!KGRhc2hib2FyZCk/dashboard/mitm.segment.rsc +3 -3
  168. package/.next/standalone/.next/server/app/dashboard/mitm.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +3 -3
  169. package/.next/standalone/.next/server/app/dashboard/mitm.segments/!KGRhc2hib2FyZCk.segment.rsc +4 -4
  170. package/.next/standalone/.next/server/app/dashboard/mitm.segments/_full.segment.rsc +12 -12
  171. package/.next/standalone/.next/server/app/dashboard/mitm.segments/_head.segment.rsc +4 -4
  172. package/.next/standalone/.next/server/app/dashboard/mitm.segments/_index.segment.rsc +5 -5
  173. package/.next/standalone/.next/server/app/dashboard/mitm.segments/_tree.segment.rsc +1 -1
  174. package/.next/standalone/.next/server/app/dashboard/profile.html +1 -1
  175. package/.next/standalone/.next/server/app/dashboard/profile.rsc +13 -13
  176. package/.next/standalone/.next/server/app/dashboard/profile.segments/!KGRhc2hib2FyZCk/dashboard/profile/__PAGE__.segment.rsc +4 -4
  177. package/.next/standalone/.next/server/app/dashboard/profile.segments/!KGRhc2hib2FyZCk/dashboard/profile.segment.rsc +3 -3
  178. package/.next/standalone/.next/server/app/dashboard/profile.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +3 -3
  179. package/.next/standalone/.next/server/app/dashboard/profile.segments/!KGRhc2hib2FyZCk.segment.rsc +4 -4
  180. package/.next/standalone/.next/server/app/dashboard/profile.segments/_full.segment.rsc +13 -13
  181. package/.next/standalone/.next/server/app/dashboard/profile.segments/_head.segment.rsc +4 -4
  182. package/.next/standalone/.next/server/app/dashboard/profile.segments/_index.segment.rsc +5 -5
  183. package/.next/standalone/.next/server/app/dashboard/profile.segments/_tree.segment.rsc +1 -1
  184. package/.next/standalone/.next/server/app/dashboard/providers/new.html +1 -1
  185. package/.next/standalone/.next/server/app/dashboard/providers/new.rsc +13 -13
  186. package/.next/standalone/.next/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk/dashboard/providers/new/__PAGE__.segment.rsc +4 -4
  187. package/.next/standalone/.next/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk/dashboard/providers/new.segment.rsc +3 -3
  188. package/.next/standalone/.next/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk/dashboard/providers.segment.rsc +3 -3
  189. package/.next/standalone/.next/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +3 -3
  190. package/.next/standalone/.next/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk.segment.rsc +4 -4
  191. package/.next/standalone/.next/server/app/dashboard/providers/new.segments/_full.segment.rsc +13 -13
  192. package/.next/standalone/.next/server/app/dashboard/providers/new.segments/_head.segment.rsc +4 -4
  193. package/.next/standalone/.next/server/app/dashboard/providers/new.segments/_index.segment.rsc +5 -5
  194. package/.next/standalone/.next/server/app/dashboard/providers/new.segments/_tree.segment.rsc +1 -1
  195. package/.next/standalone/.next/server/app/dashboard/providers.html +1 -1
  196. package/.next/standalone/.next/server/app/dashboard/providers.rsc +13 -13
  197. package/.next/standalone/.next/server/app/dashboard/providers.segments/!KGRhc2hib2FyZCk/dashboard/providers/__PAGE__.segment.rsc +4 -4
  198. package/.next/standalone/.next/server/app/dashboard/providers.segments/!KGRhc2hib2FyZCk/dashboard/providers.segment.rsc +3 -3
  199. package/.next/standalone/.next/server/app/dashboard/providers.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +3 -3
  200. package/.next/standalone/.next/server/app/dashboard/providers.segments/!KGRhc2hib2FyZCk.segment.rsc +4 -4
  201. package/.next/standalone/.next/server/app/dashboard/providers.segments/_full.segment.rsc +13 -13
  202. package/.next/standalone/.next/server/app/dashboard/providers.segments/_head.segment.rsc +4 -4
  203. package/.next/standalone/.next/server/app/dashboard/providers.segments/_index.segment.rsc +5 -5
  204. package/.next/standalone/.next/server/app/dashboard/providers.segments/_tree.segment.rsc +1 -1
  205. package/.next/standalone/.next/server/app/dashboard/proxy-pools.html +1 -1
  206. package/.next/standalone/.next/server/app/dashboard/proxy-pools.rsc +13 -13
  207. package/.next/standalone/.next/server/app/dashboard/proxy-pools.segments/!KGRhc2hib2FyZCk/dashboard/proxy-pools/__PAGE__.segment.rsc +4 -4
  208. package/.next/standalone/.next/server/app/dashboard/proxy-pools.segments/!KGRhc2hib2FyZCk/dashboard/proxy-pools.segment.rsc +3 -3
  209. package/.next/standalone/.next/server/app/dashboard/proxy-pools.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +3 -3
  210. package/.next/standalone/.next/server/app/dashboard/proxy-pools.segments/!KGRhc2hib2FyZCk.segment.rsc +4 -4
  211. package/.next/standalone/.next/server/app/dashboard/proxy-pools.segments/_full.segment.rsc +13 -13
  212. package/.next/standalone/.next/server/app/dashboard/proxy-pools.segments/_head.segment.rsc +4 -4
  213. package/.next/standalone/.next/server/app/dashboard/proxy-pools.segments/_index.segment.rsc +5 -5
  214. package/.next/standalone/.next/server/app/dashboard/proxy-pools.segments/_tree.segment.rsc +1 -1
  215. package/.next/standalone/.next/server/app/dashboard/quota.html +2 -2
  216. package/.next/standalone/.next/server/app/dashboard/quota.rsc +13 -13
  217. package/.next/standalone/.next/server/app/dashboard/quota.segments/!KGRhc2hib2FyZCk/dashboard/quota/__PAGE__.segment.rsc +4 -4
  218. package/.next/standalone/.next/server/app/dashboard/quota.segments/!KGRhc2hib2FyZCk/dashboard/quota.segment.rsc +3 -3
  219. package/.next/standalone/.next/server/app/dashboard/quota.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +3 -3
  220. package/.next/standalone/.next/server/app/dashboard/quota.segments/!KGRhc2hib2FyZCk.segment.rsc +4 -4
  221. package/.next/standalone/.next/server/app/dashboard/quota.segments/_full.segment.rsc +13 -13
  222. package/.next/standalone/.next/server/app/dashboard/quota.segments/_head.segment.rsc +4 -4
  223. package/.next/standalone/.next/server/app/dashboard/quota.segments/_index.segment.rsc +5 -5
  224. package/.next/standalone/.next/server/app/dashboard/quota.segments/_tree.segment.rsc +1 -1
  225. package/.next/standalone/.next/server/app/dashboard/settings/pricing/page.js.nft.json +1 -1
  226. package/.next/standalone/.next/server/app/dashboard/settings/pricing/page_client-reference-manifest.js +1 -1
  227. package/.next/standalone/.next/server/app/dashboard/settings/pricing.html +1 -1
  228. package/.next/standalone/.next/server/app/dashboard/settings/pricing.rsc +12 -12
  229. package/.next/standalone/.next/server/app/dashboard/settings/pricing.segments/_full.segment.rsc +12 -12
  230. package/.next/standalone/.next/server/app/dashboard/settings/pricing.segments/_head.segment.rsc +4 -4
  231. package/.next/standalone/.next/server/app/dashboard/settings/pricing.segments/_index.segment.rsc +5 -5
  232. package/.next/standalone/.next/server/app/dashboard/settings/pricing.segments/_tree.segment.rsc +1 -1
  233. package/.next/standalone/.next/server/app/dashboard/settings/pricing.segments/dashboard/settings/pricing/__PAGE__.segment.rsc +4 -4
  234. package/.next/standalone/.next/server/app/dashboard/settings/pricing.segments/dashboard/settings/pricing.segment.rsc +3 -3
  235. package/.next/standalone/.next/server/app/dashboard/settings/pricing.segments/dashboard/settings.segment.rsc +3 -3
  236. package/.next/standalone/.next/server/app/dashboard/settings/pricing.segments/dashboard.segment.rsc +3 -3
  237. package/.next/standalone/.next/server/app/dashboard/translator.html +1 -1
  238. package/.next/standalone/.next/server/app/dashboard/translator.rsc +13 -13
  239. package/.next/standalone/.next/server/app/dashboard/translator.segments/!KGRhc2hib2FyZCk/dashboard/translator/__PAGE__.segment.rsc +4 -4
  240. package/.next/standalone/.next/server/app/dashboard/translator.segments/!KGRhc2hib2FyZCk/dashboard/translator.segment.rsc +3 -3
  241. package/.next/standalone/.next/server/app/dashboard/translator.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +3 -3
  242. package/.next/standalone/.next/server/app/dashboard/translator.segments/!KGRhc2hib2FyZCk.segment.rsc +4 -4
  243. package/.next/standalone/.next/server/app/dashboard/translator.segments/_full.segment.rsc +13 -13
  244. package/.next/standalone/.next/server/app/dashboard/translator.segments/_head.segment.rsc +4 -4
  245. package/.next/standalone/.next/server/app/dashboard/translator.segments/_index.segment.rsc +5 -5
  246. package/.next/standalone/.next/server/app/dashboard/translator.segments/_tree.segment.rsc +1 -1
  247. package/.next/standalone/.next/server/app/dashboard/usage.html +1 -1
  248. package/.next/standalone/.next/server/app/dashboard/usage.rsc +13 -13
  249. package/.next/standalone/.next/server/app/dashboard/usage.segments/!KGRhc2hib2FyZCk/dashboard/usage/__PAGE__.segment.rsc +4 -4
  250. package/.next/standalone/.next/server/app/dashboard/usage.segments/!KGRhc2hib2FyZCk/dashboard/usage.segment.rsc +3 -3
  251. package/.next/standalone/.next/server/app/dashboard/usage.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +3 -3
  252. package/.next/standalone/.next/server/app/dashboard/usage.segments/!KGRhc2hib2FyZCk.segment.rsc +4 -4
  253. package/.next/standalone/.next/server/app/dashboard/usage.segments/_full.segment.rsc +13 -13
  254. package/.next/standalone/.next/server/app/dashboard/usage.segments/_head.segment.rsc +4 -4
  255. package/.next/standalone/.next/server/app/dashboard/usage.segments/_index.segment.rsc +5 -5
  256. package/.next/standalone/.next/server/app/dashboard/usage.segments/_tree.segment.rsc +1 -1
  257. package/.next/standalone/.next/server/app/dashboard.html +1 -1
  258. package/.next/standalone/.next/server/app/dashboard.rsc +12 -12
  259. package/.next/standalone/.next/server/app/dashboard.segments/!KGRhc2hib2FyZCk/dashboard/__PAGE__.segment.rsc +3 -3
  260. package/.next/standalone/.next/server/app/dashboard.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +3 -3
  261. package/.next/standalone/.next/server/app/dashboard.segments/!KGRhc2hib2FyZCk.segment.rsc +4 -4
  262. package/.next/standalone/.next/server/app/dashboard.segments/_full.segment.rsc +12 -12
  263. package/.next/standalone/.next/server/app/dashboard.segments/_head.segment.rsc +4 -4
  264. package/.next/standalone/.next/server/app/dashboard.segments/_index.segment.rsc +5 -5
  265. package/.next/standalone/.next/server/app/dashboard.segments/_tree.segment.rsc +1 -1
  266. package/.next/standalone/.next/server/app/index.html +1 -1
  267. package/.next/standalone/.next/server/app/index.rsc +10 -10
  268. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  269. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +10 -10
  270. package/.next/standalone/.next/server/app/index.segments/_head.segment.rsc +4 -4
  271. package/.next/standalone/.next/server/app/index.segments/_index.segment.rsc +5 -5
  272. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  273. package/.next/standalone/.next/server/app/landing/page.js.nft.json +1 -1
  274. package/.next/standalone/.next/server/app/landing/page_client-reference-manifest.js +1 -1
  275. package/.next/standalone/.next/server/app/landing.html +1 -1
  276. package/.next/standalone/.next/server/app/landing.rsc +12 -12
  277. package/.next/standalone/.next/server/app/landing.segments/_full.segment.rsc +12 -12
  278. package/.next/standalone/.next/server/app/landing.segments/_head.segment.rsc +4 -4
  279. package/.next/standalone/.next/server/app/landing.segments/_index.segment.rsc +5 -5
  280. package/.next/standalone/.next/server/app/landing.segments/_tree.segment.rsc +1 -1
  281. package/.next/standalone/.next/server/app/landing.segments/landing/__PAGE__.segment.rsc +4 -4
  282. package/.next/standalone/.next/server/app/landing.segments/landing.segment.rsc +3 -3
  283. package/.next/standalone/.next/server/app/login/page.js.nft.json +1 -1
  284. package/.next/standalone/.next/server/app/login/page_client-reference-manifest.js +1 -1
  285. package/.next/standalone/.next/server/app/login.html +1 -1
  286. package/.next/standalone/.next/server/app/login.rsc +12 -12
  287. package/.next/standalone/.next/server/app/login.segments/_full.segment.rsc +12 -12
  288. package/.next/standalone/.next/server/app/login.segments/_head.segment.rsc +4 -4
  289. package/.next/standalone/.next/server/app/login.segments/_index.segment.rsc +5 -5
  290. package/.next/standalone/.next/server/app/login.segments/_tree.segment.rsc +1 -1
  291. package/.next/standalone/.next/server/app/login.segments/login/__PAGE__.segment.rsc +4 -4
  292. package/.next/standalone/.next/server/app/login.segments/login.segment.rsc +3 -3
  293. package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
  294. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  295. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0.yvcis._.js +1 -1
  296. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0148t9m._.js +1 -1
  297. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0b802lh._.js +1 -1
  298. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0kpc-o6._.js +1 -1
  299. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0lc~.sk._.js +1 -1
  300. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0lp_pm5._.js +1 -1
  301. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0pwrfp1._.js +1 -1
  302. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0uw3x8s._.js +1 -1
  303. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0y.reft._.js +1 -1
  304. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0y5ae.7._.js +1 -1
  305. package/.next/standalone/.next/server/chunks/_0__-aqg._.js +1 -1
  306. package/.next/standalone/.next/server/chunks/_0_ovl1h._.js +1 -1
  307. package/.next/standalone/.next/server/chunks/ssr/src_0_xhepz._.js +1 -1
  308. package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
  309. package/.next/standalone/.next/server/pages/404.html +1 -1
  310. package/.next/standalone/.next/server/pages/500.html +1 -1
  311. package/.next/{static/chunks/0deg-_syv13xx.js → standalone/.next/static/chunks/11q6656-lc_oz.js} +1 -1
  312. package/.next/standalone/mitm/server.js +168 -113
  313. package/.next/standalone/mitm/tokenPool.js +168 -20
  314. package/.next/standalone/package-lock.json +2 -2
  315. package/.next/standalone/package.json +1 -1
  316. package/.next/standalone/plans/tauri-app/01-scope-and-architecture.md +218 -0
  317. package/.next/standalone/plans/tauri-app/02-backend-plan.md +237 -0
  318. package/.next/standalone/plans/tauri-app/03-tauri-native-plan.md +194 -0
  319. package/.next/standalone/plans/tauri-app/04-react-ui-plan.md +155 -0
  320. package/.next/standalone/plans/tauri-app/05-delivery-phases.md +171 -0
  321. package/.next/standalone/plans/tauri-app/README.md +87 -0
  322. package/.next/standalone/src/mitm/server.js +168 -113
  323. package/.next/standalone/src/mitm/tokenPool.js +168 -20
  324. package/.next/{standalone/.next/static/chunks/0deg-_syv13xx.js → static/chunks/11q6656-lc_oz.js} +1 -1
  325. package/package.json +1 -1
  326. /package/.next/standalone/.next/static/{b_Drjo0YdAiFCInKT62q9 → 03mW5vaG0Fogum-tDkkOQ}/_buildManifest.js +0 -0
  327. /package/.next/standalone/.next/static/{b_Drjo0YdAiFCInKT62q9 → 03mW5vaG0Fogum-tDkkOQ}/_clientMiddlewareManifest.js +0 -0
  328. /package/.next/standalone/.next/static/{b_Drjo0YdAiFCInKT62q9 → 03mW5vaG0Fogum-tDkkOQ}/_ssgManifest.js +0 -0
  329. /package/.next/static/{b_Drjo0YdAiFCInKT62q9 → 03mW5vaG0Fogum-tDkkOQ}/_buildManifest.js +0 -0
  330. /package/.next/static/{b_Drjo0YdAiFCInKT62q9 → 03mW5vaG0Fogum-tDkkOQ}/_clientMiddlewareManifest.js +0 -0
  331. /package/.next/static/{b_Drjo0YdAiFCInKT62q9 → 03mW5vaG0Fogum-tDkkOQ}/_ssgManifest.js +0 -0
@@ -0,0 +1,171 @@
1
+ # Delivery Phases
2
+
3
+ ## Phase 0: Setup
4
+
5
+ Goals:
6
+
7
+ - create app workspace structure
8
+ - choose package manager and monorepo layout
9
+ - define TypeScript, lint, and build conventions
10
+ - define target OS matrix: macOS, Windows, Linux
11
+
12
+ Tasks:
13
+
14
+ - add `apps/desktop-shell`
15
+ - add `apps/desktop-ui`
16
+ - add `apps/desktop-backend`
17
+ - add `packages/desktop-shared`
18
+ - define ports, app data path, and env conventions
19
+ - define platform support policy and supported Linux baseline
20
+
21
+ Exit criteria:
22
+
23
+ - all three apps boot locally in dev mode
24
+
25
+ ## Phase 1: Backend extraction
26
+
27
+ Goals:
28
+
29
+ - standalone local service without Next.js
30
+
31
+ Tasks:
32
+
33
+ - port `localDb`
34
+ - port `usageDb`
35
+ - add Express app and health endpoint
36
+ - port Antigravity account service
37
+ - port account import
38
+ - port usage APIs
39
+
40
+ Exit criteria:
41
+
42
+ - backend can manage accounts and serve usage data from existing files
43
+
44
+ ## Phase 2: MITM service
45
+
46
+ Goals:
47
+
48
+ - functional Antigravity interception under backend control
49
+
50
+ Tasks:
51
+
52
+ - extract MITM server and manager logic
53
+ - adapt internal usage and request detail ingestion
54
+ - preserve host/path matching logic
55
+ - preserve model alias routing for MITM if still required
56
+ - separate platform-specific cert/DNS behavior from backend-owned MITM logic
57
+
58
+ Exit criteria:
59
+
60
+ - backend can start MITM and capture Antigravity usage
61
+
62
+ ## Phase 3: Native integration
63
+
64
+ Goals:
65
+
66
+ - move privileged operations into Tauri
67
+
68
+ Tasks:
69
+
70
+ - backend process supervision
71
+ - cert trust command
72
+ - DNS enable/disable command
73
+ - secret storage integration
74
+ - health plumbing between shell and backend
75
+ - implement and verify flows on macOS, Windows, and Linux
76
+
77
+ Exit criteria:
78
+
79
+ - desktop app can control backend and OS operations from native commands
80
+ - supported OS matrix passes smoke tests
81
+
82
+ ## Phase 4: UI MVP
83
+
84
+ Goals:
85
+
86
+ - first usable desktop product
87
+
88
+ Tasks:
89
+
90
+ - build accounts page
91
+ - build MITM page
92
+ - build token swap page
93
+ - build usage page
94
+ - add loading/error/status states
95
+
96
+ Exit criteria:
97
+
98
+ - user can operate the full Antigravity MITM flow from the desktop app
99
+
100
+ ## Phase 5: Hardening
101
+
102
+ Goals:
103
+
104
+ - make the app stable enough for daily use
105
+
106
+ Tasks:
107
+
108
+ - crash recovery
109
+ - retry and restart policies
110
+ - clearer error messaging
111
+ - account pool edge-case handling
112
+ - better logs and diagnostics
113
+ - platform-specific QA and packaging fixes
114
+
115
+ Exit criteria:
116
+
117
+ - app survives common failures without manual cleanup
118
+
119
+ ## Suggested implementation order inside each phase
120
+
121
+ 1. extract minimal working path
122
+ 2. add tests for behavior already present in current app
123
+ 3. add UI affordances only after backend/native behavior is real
124
+ 4. avoid storage migration until feature parity is stable
125
+
126
+ ## Testing strategy
127
+
128
+ ### Automated
129
+
130
+ - unit tests for token pool
131
+ - unit tests for usage aggregation
132
+ - integration tests for backend APIs
133
+ - smoke tests for Tauri commands where feasible
134
+
135
+ ### Manual
136
+
137
+ - connect one account and intercept traffic
138
+ - connect multiple accounts and verify token rotation
139
+ - exhaust one account and verify cooldown behavior
140
+ - break cert/DNS state and verify UI diagnosis
141
+ - repeat the same smoke flows on macOS, Windows, and Linux
142
+
143
+ ## OS matrix
144
+
145
+ ### Required for v1
146
+
147
+ - macOS
148
+ - Windows
149
+ - Linux
150
+
151
+ ### Linux baseline
152
+
153
+ - pick one supported baseline distro for v1, preferably Ubuntu LTS
154
+ - document other distros as best effort until explicitly validated
155
+
156
+ ## Main project risks
157
+
158
+ - OS privilege behavior
159
+ - port 443 conflicts
160
+ - cert trust differences by OS
161
+ - race conditions in file-backed persistence
162
+ - accidental coupling to old Next.js imports
163
+
164
+ ## Completion checklist
165
+
166
+ - backend no longer depends on Next.js
167
+ - desktop shell controls backend lifecycle
168
+ - privileged actions no longer depend on React or browser APIs
169
+ - Antigravity MITM works on supported OS targets
170
+ - token swap and usage analyst are visible and operable in the desktop UI
171
+ - macOS, Windows, and Linux each have validated first-run and normal-run flows
@@ -0,0 +1,87 @@
1
+ # Tauri App Implementation Plan
2
+
3
+ This plan defines the desktop implementation target for a focused Antigravity tool, not a full 9Router port.
4
+
5
+ Target desktop OS support for v1:
6
+
7
+ - macOS
8
+ - Windows
9
+ - Linux
10
+
11
+ ## Product goal
12
+
13
+ Build a desktop app with:
14
+
15
+ - Antigravity account management
16
+ - Antigravity MITM proxy
17
+ - DNS/hosts toggling for Antigravity domains
18
+ - multi-account token swap for Antigravity
19
+ - usage analytics and request details for MITM traffic
20
+
21
+ Out of scope for v1:
22
+
23
+ - `/v1/chat/completions`
24
+ - OpenAI-compatible routing
25
+ - multi-provider routing gateway
26
+ - combo/fallback model router
27
+ - cloud worker and tunnel features
28
+ - non-Antigravity MITM tools
29
+
30
+ ## Deliverables
31
+
32
+ - `apps/desktop-shell`: Tauri app shell and native commands
33
+ - `apps/desktop-ui`: React desktop UI
34
+ - `apps/desktop-backend`: local Express service
35
+ - `packages/desktop-shared`: shared types, constants, API contracts
36
+ - migration docs and test plan
37
+
38
+ ## Recommended architecture
39
+
40
+ - Tauri Rust:
41
+ - app lifecycle
42
+ - secure storage
43
+ - privilege escalation boundary
44
+ - cert trust/untrust
45
+ - DNS/hosts mutation
46
+ - process supervision for backend/MITM
47
+ - React UI:
48
+ - accounts screen
49
+ - MITM/DNS screen
50
+ - token swap screen
51
+ - usage and request details screens
52
+ - Express backend:
53
+ - Antigravity OAuth/import
54
+ - persistence
55
+ - token pool logic
56
+ - MITM HTTPS server
57
+ - usage ingestion and query APIs
58
+
59
+ ## Why this split
60
+
61
+ The hardest domain logic already exists in JS and should be preserved first:
62
+
63
+ - MITM server: `src/mitm/server.js`
64
+ - token pool: `src/mitm/tokenPool.js`
65
+ - usage capture: `src/mitm/usageTracker.js`
66
+ - Antigravity OAuth: `src/lib/oauth/services/antigravity.js`
67
+ - local persistence: `src/lib/localDb.js`, `src/lib/usageDb.js`
68
+
69
+ The native-only work is OS integration, not request routing. Rewriting MITM/token swap in Rust first would add risk without product value.
70
+
71
+ ## Plan set
72
+
73
+ - [01-scope-and-architecture.md](/Users/cuongquach/projects/vibe/n9router/plans/tauri-app/01-scope-and-architecture.md)
74
+ - [02-backend-plan.md](/Users/cuongquach/projects/vibe/n9router/plans/tauri-app/02-backend-plan.md)
75
+ - [03-tauri-native-plan.md](/Users/cuongquach/projects/vibe/n9router/plans/tauri-app/03-tauri-native-plan.md)
76
+ - [04-react-ui-plan.md](/Users/cuongquach/projects/vibe/n9router/plans/tauri-app/04-react-ui-plan.md)
77
+ - [05-delivery-phases.md](/Users/cuongquach/projects/vibe/n9router/plans/tauri-app/05-delivery-phases.md)
78
+
79
+ ## Success criteria
80
+
81
+ - user can connect one or more Antigravity accounts
82
+ - app can trust local cert and toggle Antigravity DNS entries
83
+ - MITM can intercept Antigravity traffic reliably
84
+ - token swap rotates accounts and handles quota/auth cooldowns
85
+ - usage screens show recent requests, token usage, and request details
86
+ - desktop app can be packaged and started without Next.js
87
+ - the same core flows work on macOS, Windows, and Linux with platform-appropriate elevation and diagnostics
@@ -7,8 +7,8 @@ const { log, err } = require("./logger");
7
7
  const { TARGET_HOSTS, URL_PATTERNS, getToolForHost } = require("./config");
8
8
  const { DATA_DIR, MITM_DIR } = require("./paths");
9
9
  const { isTokenSwapEnabled, getAllActiveConnections, triggerRefreshIfNeeded,
10
- setCooldown, setModelCooldown, getTokenSwapStrategy,
11
- parseQuotaCooldown, markAccountUsed, getConnectionLabel } = require("./tokenPool");
10
+ forceRefreshConnection, setCooldown, setAuthCooldown, setModelCooldown, getTokenSwapStrategy,
11
+ parseQuotaCooldown, markAccountUsed, getConnectionLabel, getTokenSwapAvailabilitySummary } = require("./tokenPool");
12
12
  const { getCertForDomain } = require("./cert/generate");
13
13
  const { buildInputOnlyRequestDetail, createTokenSwapUsageObserver, generateDetailId } = require("./usageTracker");
14
14
 
@@ -187,120 +187,144 @@ async function tokenSwapForward(req, res, bodyBuffer, connections, model, strate
187
187
 
188
188
  for (let i = 0; i < connections.length; i++) {
189
189
  const originalConn = connections[i];
190
- const conn = await triggerRefreshIfNeeded(originalConn);
191
-
192
- const label = getConnectionLabel(conn);
193
- const modelTag = model ? ` model=${model}` : "";
194
- const posTag = connections.length > 1 ? ` [${i + 1}/${connections.length}]` : "";
195
- const useTag = conn.consecutiveUseCount > 1 ? ` uses=${conn.consecutiveUseCount}` : "";
196
- log(`🔑 [token-swap]${posTag} trying "${label}"${modelTag}${useTag}`);
197
-
198
- const swappedHeaders = {
199
- ...req.headers,
200
- host: targetHost,
201
- authorization: `Bearer ${conn.accessToken}`
202
- };
203
-
204
- try {
205
- const result = await new Promise((resolve, reject) => {
206
- const forwardReq = https.request({
207
- hostname: targetIP,
208
- port: 443,
209
- path: req.url,
210
- method: req.method,
211
- headers: swappedHeaders,
212
- servername: targetHost,
213
- rejectUnauthorized: false
214
- }, (forwardRes) => {
215
- if (forwardRes.statusCode === 429 || forwardRes.statusCode === 503) {
216
- // Buffer the short error body to parse cooldown duration
217
- const chunks = [];
218
- forwardRes.on("data", c => chunks.push(c));
219
- forwardRes.on("end", () => {
220
- const body = Buffer.concat(chunks).toString();
221
- resolve({ retry: true, body, statusCode: forwardRes.statusCode });
222
- });
190
+ let conn = await triggerRefreshIfNeeded(originalConn);
191
+ let authRefreshAttempted = false;
192
+
193
+ while (true) {
194
+ const label = getConnectionLabel(conn);
195
+ const modelTag = model ? ` model=${model}` : "";
196
+ const posTag = connections.length > 1 ? ` [${i + 1}/${connections.length}]` : "";
197
+ const useTag = conn.consecutiveUseCount > 1 ? ` uses=${conn.consecutiveUseCount}` : "";
198
+ log(`🔑 [token-swap]${posTag} trying "${label}"${modelTag}${useTag}`);
199
+
200
+ const swappedHeaders = {
201
+ ...req.headers,
202
+ host: targetHost,
203
+ authorization: `Bearer ${conn.accessToken}`
204
+ };
205
+
206
+ try {
207
+ const result = await new Promise((resolve, reject) => {
208
+ const forwardReq = https.request({
209
+ hostname: targetIP,
210
+ port: 443,
211
+ path: req.url,
212
+ method: req.method,
213
+ headers: swappedHeaders,
214
+ servername: targetHost,
215
+ rejectUnauthorized: false
216
+ }, (forwardRes) => {
217
+ if (forwardRes.statusCode === 429 || forwardRes.statusCode === 503 || forwardRes.statusCode === 401) {
218
+ const chunks = [];
219
+ forwardRes.on("data", c => chunks.push(c));
220
+ forwardRes.on("end", () => {
221
+ const body = Buffer.concat(chunks).toString();
222
+ const retryType = forwardRes.statusCode === 401 ? "auth" : "quota";
223
+ resolve({ retry: true, retryType, body, headers: forwardRes.headers, statusCode: forwardRes.statusCode });
224
+ });
225
+ } else {
226
+ resolve({ retry: false, response: forwardRes });
227
+ }
228
+ });
229
+ forwardReq.on("error", reject);
230
+ if (bodyBuffer.length > 0) forwardReq.write(bodyBuffer);
231
+ forwardReq.end();
232
+ });
233
+
234
+ if (result.retry && result.retryType === "quota") {
235
+ const cooldownMs = parseQuotaCooldown(result.body);
236
+ const cdLabel = cooldownMs ? ` cooldown=${Math.ceil(cooldownMs / 60000)}m` : "";
237
+ if (strategy === "sticky" && model) {
238
+ setModelCooldown(conn.id, model, cooldownMs);
239
+ log(`⚠️ [token-swap] "${label}" → ${result.statusCode} model=${model} quota exhausted${cdLabel}, trying next...`);
223
240
  } else {
224
- // Success or non-quota error → pipe to client
225
- resolve({ retry: false, response: forwardRes });
241
+ setCooldown(conn.id, cooldownMs);
242
+ log(`⚠️ [token-swap] "${label}" ${result.statusCode} account quota exhausted${cdLabel}, trying next...`);
226
243
  }
227
- });
228
- forwardReq.on("error", reject);
229
- if (bodyBuffer.length > 0) forwardReq.write(bodyBuffer);
230
- forwardReq.end();
231
- });
232
-
233
- if (result.retry) {
234
- const cooldownMs = parseQuotaCooldown(result.body);
235
- const cdLabel = cooldownMs ? ` cooldown=${Math.ceil(cooldownMs / 60000)}m` : "";
236
- if (strategy === "sticky" && model) {
237
- // Sticky: mark only this account+model as exhausted, not the whole account
238
- setModelCooldown(conn.id, model, cooldownMs);
239
- log(`⚠️ [token-swap] "${label}" → ${result.statusCode} model=${model} quota exhausted${cdLabel}, trying next...`);
240
- } else {
241
- // Round-robin: put whole account on cooldown
242
- setCooldown(conn.id, cooldownMs);
243
- log(`⚠️ [token-swap] "${label}" → ${result.statusCode} account quota exhausted${cdLabel}, trying next...`);
244
+ break;
244
245
  }
245
- continue;
246
- }
247
246
 
248
- const newCount = (conn.consecutiveUseCount || 0) + 1;
249
- const statusCode = result.response.statusCode || 0;
250
- const successModelTag = model ? ` model=${model}` : "";
251
- const successStrategyTag = strategy === "sticky" ? ` sticky(use #${newCount})` : ` rr`;
252
- log(`✅ [token-swap] "${label}" → ${statusCode}${successModelTag}${successStrategyTag}`);
253
- markAccountUsed(conn.id);
254
- res.writeHead(statusCode, result.response.headers);
255
-
256
- const detailId = generateDetailId(model);
257
- const inputOnlyDetail = buildInputOnlyRequestDetail({
258
- detailId,
259
- provider,
260
- model,
261
- connectionId: conn.id,
262
- bodyBuffer
263
- });
264
- fetch("http://127.0.0.1:20128/api/internal/request-detail", {
265
- method: "POST",
266
- headers: {
267
- "Content-Type": "application/json",
268
- [INTERNAL_REQUEST_HEADER.name]: INTERNAL_REQUEST_HEADER.value
269
- },
270
- body: JSON.stringify(inputOnlyDetail)
271
- }).catch((detailError) => {
272
- err(`[token-swap] failed to create request detail for "${label}": ${detailError.message}`);
273
- });
274
-
275
- const usageObserver = createTokenSwapUsageObserver({
276
- provider,
277
- model,
278
- connectionId: conn.id,
279
- accountLabel: label,
280
- bodyBuffer,
281
- contentType: result.response.headers["content-type"] || "",
282
- contentEncoding: result.response.headers["content-encoding"] || "",
283
- statusCode,
284
- detailRecord: inputOnlyDetail,
285
- requestStartTime
286
- });
287
-
288
- result.response.on("data", (chunk) => {
289
- usageObserver.onChunk(chunk);
290
- res.write(chunk);
291
- });
292
- result.response.on("end", () => {
293
- res.end();
294
- usageObserver.onEnd().catch(() => {});
295
- });
296
- result.response.on("error", (streamError) => {
297
- err(`[token-swap] upstream stream error for "${label}": ${streamError.message}`);
298
- if (!res.writableEnded) res.end();
299
- });
300
- return true;
301
- } catch (e) {
302
- err(`[token-swap] error for "${label}": ${e.message}`);
303
- continue;
247
+ if (result.retry && result.retryType === "auth") {
248
+ const retryableAuth = isRetryableAuthFailure(result.statusCode, result.headers, result.body);
249
+ if (!retryableAuth) {
250
+ res.writeHead(result.statusCode, result.headers);
251
+ res.end(result.body);
252
+ return true;
253
+ }
254
+
255
+ if (!authRefreshAttempted && conn.refreshToken) {
256
+ authRefreshAttempted = true;
257
+ log(`⚠️ [token-swap] "${label}" → 401 invalid_token, forcing refresh...`);
258
+ const refreshResult = await forceRefreshConnection(conn);
259
+ conn = refreshResult.connection || conn;
260
+ if (refreshResult.refreshed) {
261
+ log(`↻ [token-swap] "${label}" refreshed, retrying same account...`);
262
+ continue;
263
+ }
264
+ }
265
+
266
+ setAuthCooldown(conn.id);
267
+ log(`⚠️ [token-swap] "${label}" → 401 invalid_token, trying next...`);
268
+ break;
269
+ }
270
+
271
+ const newCount = (conn.consecutiveUseCount || 0) + 1;
272
+ const statusCode = result.response.statusCode || 0;
273
+ const successModelTag = model ? ` model=${model}` : "";
274
+ const successStrategyTag = strategy === "sticky" ? ` sticky(use #${newCount})` : ` rr`;
275
+ log(`✅ [token-swap] "${label}" → ${statusCode}${successModelTag}${successStrategyTag}`);
276
+ markAccountUsed(conn.id);
277
+ res.writeHead(statusCode, result.response.headers);
278
+
279
+ const detailId = generateDetailId(model);
280
+ const inputOnlyDetail = buildInputOnlyRequestDetail({
281
+ detailId,
282
+ provider,
283
+ model,
284
+ connectionId: conn.id,
285
+ bodyBuffer
286
+ });
287
+ fetch("http://127.0.0.1:20128/api/internal/request-detail", {
288
+ method: "POST",
289
+ headers: {
290
+ "Content-Type": "application/json",
291
+ [INTERNAL_REQUEST_HEADER.name]: INTERNAL_REQUEST_HEADER.value
292
+ },
293
+ body: JSON.stringify(inputOnlyDetail)
294
+ }).catch((detailError) => {
295
+ err(`[token-swap] failed to create request detail for "${label}": ${detailError.message}`);
296
+ });
297
+
298
+ const usageObserver = createTokenSwapUsageObserver({
299
+ provider,
300
+ model,
301
+ connectionId: conn.id,
302
+ accountLabel: label,
303
+ bodyBuffer,
304
+ contentType: result.response.headers["content-type"] || "",
305
+ contentEncoding: result.response.headers["content-encoding"] || "",
306
+ statusCode,
307
+ detailRecord: inputOnlyDetail,
308
+ requestStartTime
309
+ });
310
+
311
+ result.response.on("data", (chunk) => {
312
+ usageObserver.onChunk(chunk);
313
+ res.write(chunk);
314
+ });
315
+ result.response.on("end", () => {
316
+ res.end();
317
+ usageObserver.onEnd().catch(() => {});
318
+ });
319
+ result.response.on("error", (streamError) => {
320
+ err(`[token-swap] upstream stream error for "${label}": ${streamError.message}`);
321
+ if (!res.writableEnded) res.end();
322
+ });
323
+ return true;
324
+ } catch (e) {
325
+ err(`[token-swap] error for "${label}": ${e.message}`);
326
+ break;
327
+ }
304
328
  }
305
329
  }
306
330
 
@@ -308,6 +332,36 @@ async function tokenSwapForward(req, res, bodyBuffer, connections, model, strate
308
332
  return false;
309
333
  }
310
334
 
335
+ function getHeaderValue(headers, name) {
336
+ const value = headers?.[String(name).toLowerCase()];
337
+ if (Array.isArray(value)) return value.join(", ");
338
+ return typeof value === "string" ? value : "";
339
+ }
340
+
341
+ function isRetryableAuthFailure(statusCode, headers, body) {
342
+ if (statusCode !== 401) return false;
343
+
344
+ const authHeader = getHeaderValue(headers, "www-authenticate").toLowerCase();
345
+ if (authHeader.includes("invalid_token")) return true;
346
+
347
+ try {
348
+ const parsed = JSON.parse(body || "{}");
349
+ const status = String(parsed?.error?.status || parsed?.status || "").toUpperCase();
350
+ const message = String(parsed?.error?.message || parsed?.message || "").toLowerCase();
351
+ if (status === "UNAUTHENTICATED") return true;
352
+ if (message.includes("invalid authentication credentials")) return true;
353
+ if (message.includes("invalid token")) return true;
354
+ if (message.includes("unauthenticated")) return true;
355
+ } catch {
356
+ const fallback = String(body || "").toLowerCase();
357
+ if (fallback.includes("invalid authentication credentials")) return true;
358
+ if (fallback.includes("invalid token")) return true;
359
+ if (fallback.includes("unauthenticated")) return true;
360
+ }
361
+
362
+ return false;
363
+ }
364
+
311
365
  // ── Request handler ───────────────────────────────────────────
312
366
 
313
367
  const server = https.createServer(sslOptions, async (req, res) => {
@@ -357,7 +411,8 @@ const server = https.createServer(sslOptions, async (req, res) => {
357
411
  const strategy = getTokenSwapStrategy();
358
412
  const poolConns = getAllActiveConnections(swapProvider, model);
359
413
  if (poolConns.length > 0) {
360
- log(`🔑 [${tool}] token-swap: ${poolConns.length} account(s) available (strategy=${strategy}${model ? `, model=${model}` : ""})`);
414
+ const availability = getTokenSwapAvailabilitySummary(swapProvider, model);
415
+ log(`🔑 [${tool}] token-swap: ${availability.summaryText} (strategy=${strategy}${model ? `, model=${model}` : ""})`);
361
416
  const handled = await tokenSwapForward(req, res, bodyBuffer, poolConns, model, strategy, swapProvider, bodyCollectStart);
362
417
  if (handled) return;
363
418
  log(`⚠️ [${tool}] token-swap: all accounts exhausted, falling through to original token`);