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
@@ -14,9 +14,11 @@ const DB_FILE = path.join(DATA_DIR, "db.json");
14
14
  const TOKEN_EXPIRY_BUFFER_MS = 5 * 60 * 1000; // refresh 5min before expiry
15
15
  const ROUTER_PORT = process.env.PORT || 20128;
16
16
  const DEFAULT_COOLDOWN_MS = 5 * 60 * 1000;
17
+ const DEFAULT_AUTH_COOLDOWN_MS = 10 * 60 * 1000;
17
18
 
18
19
  // ── In-memory state ──────────────────────────────────────────
19
- const cooldownMap = {}; // { [connectionId]: expiresTimestamp }
20
+ const cooldownMap = {}; // { [connectionId]: expiresTimestamp } quota/general cooldown
21
+ const authCooldownMap = {}; // { [connectionId]: expiresTimestamp } invalid_token/auth cooldown
20
22
  const modelCooldownMap = {}; // { [connectionId]: { [model]: expiresTimestamp } }
21
23
  const rrState = {}; // { [provider]: roundRobinIndex }
22
24
 
@@ -28,13 +30,33 @@ function setCooldown(connId, durationMs) {
28
30
  log(`⏸ [token-pool] cooldown: ${connId.slice(0, 8)}… for ${Math.ceil(ms / 60000)}m`);
29
31
  }
30
32
 
31
- function isInCooldown(connId) {
32
- if (!cooldownMap[connId]) return false;
33
- if (Date.now() > cooldownMap[connId]) {
34
- delete cooldownMap[connId];
35
- return false;
33
+ function setAuthCooldown(connId, durationMs) {
34
+ const ms = durationMs || DEFAULT_AUTH_COOLDOWN_MS;
35
+ authCooldownMap[connId] = Date.now() + ms;
36
+ log(`🔒 [token-pool] auth-cooldown: ${connId.slice(0, 8)}… for ${Math.ceil(ms / 60000)}m`);
37
+ }
38
+
39
+ function getMapExpiry(map, connId) {
40
+ if (!map[connId]) return 0;
41
+ if (Date.now() > map[connId]) {
42
+ delete map[connId];
43
+ return 0;
36
44
  }
37
- return true;
45
+ return map[connId];
46
+ }
47
+
48
+ function getCooldownState(connId) {
49
+ const authExpiry = getMapExpiry(authCooldownMap, connId);
50
+ if (authExpiry) return { type: "auth", expiresAt: authExpiry };
51
+
52
+ const quotaExpiry = getMapExpiry(cooldownMap, connId);
53
+ if (quotaExpiry) return { type: "quota", expiresAt: quotaExpiry };
54
+
55
+ return null;
56
+ }
57
+
58
+ function isInCooldown(connId) {
59
+ return !!getCooldownState(connId);
38
60
  }
39
61
 
40
62
  // ── Per-model cooldown management ────────────────────────────
@@ -110,6 +132,90 @@ function getActiveConnections(provider) {
110
132
  } catch { return []; }
111
133
  }
112
134
 
135
+ function getTokenSwapAvailabilitySummary(provider, model) {
136
+ try {
137
+ if (!fs.existsSync(DB_FILE)) {
138
+ return {
139
+ total: 0,
140
+ eligible: 0,
141
+ skipped: 0,
142
+ reasons: {},
143
+ summaryText: "0/0 account(s) eligible"
144
+ };
145
+ }
146
+
147
+ const db = JSON.parse(fs.readFileSync(DB_FILE, "utf-8"));
148
+ const connections = (db.providerConnections || []).filter(c => c.provider === provider);
149
+ const now = Date.now();
150
+ const strategy = getTokenSwapStrategy();
151
+ const reasons = {
152
+ inactive: 0,
153
+ noToken: 0,
154
+ expiredNoRefresh: 0,
155
+ quotaCooldown: 0,
156
+ authCooldown: 0,
157
+ modelCooldown: 0,
158
+ };
159
+
160
+ let eligible = 0;
161
+
162
+ for (const connection of connections) {
163
+ if (connection.isActive === false) {
164
+ reasons.inactive += 1;
165
+ continue;
166
+ }
167
+ if (!connection.accessToken) {
168
+ reasons.noToken += 1;
169
+ continue;
170
+ }
171
+ if (connection.expiresAt && new Date(connection.expiresAt).getTime() < now && !connection.refreshToken) {
172
+ reasons.expiredNoRefresh += 1;
173
+ continue;
174
+ }
175
+
176
+ const cooldownState = getCooldownState(connection.id);
177
+ if (cooldownState?.type === "auth") {
178
+ reasons.authCooldown += 1;
179
+ continue;
180
+ }
181
+ if (cooldownState?.type === "quota") {
182
+ reasons.quotaCooldown += 1;
183
+ continue;
184
+ }
185
+
186
+ if (strategy === "sticky" && model && isModelExhausted(connection.id, model)) {
187
+ reasons.modelCooldown += 1;
188
+ continue;
189
+ }
190
+
191
+ eligible += 1;
192
+ }
193
+
194
+ const skipped = connections.length - eligible;
195
+ const reasonParts = [];
196
+ if (reasons.quotaCooldown) reasonParts.push(`${reasons.quotaCooldown} quota cooldown`);
197
+ if (reasons.authCooldown) reasonParts.push(`${reasons.authCooldown} auth cooldown`);
198
+ if (reasons.modelCooldown) reasonParts.push(`${reasons.modelCooldown} model cooldown`);
199
+ if (reasons.inactive) reasonParts.push(`${reasons.inactive} inactive`);
200
+ if (reasons.noToken) reasonParts.push(`${reasons.noToken} missing token`);
201
+ if (reasons.expiredNoRefresh) reasonParts.push(`${reasons.expiredNoRefresh} expired-no-refresh`);
202
+
203
+ const summaryText = skipped > 0
204
+ ? `${eligible}/${connections.length} account(s) eligible, skipped ${skipped} (${reasonParts.join(", ")})`
205
+ : `${eligible}/${connections.length} account(s) eligible`;
206
+
207
+ return { total: connections.length, eligible, skipped, reasons, summaryText };
208
+ } catch {
209
+ return {
210
+ total: 0,
211
+ eligible: 0,
212
+ skipped: 0,
213
+ reasons: {},
214
+ summaryText: "0/0 account(s) eligible"
215
+ };
216
+ }
217
+ }
218
+
113
219
  function getConnectionById(connId) {
114
220
  try {
115
221
  if (!fs.existsSync(DB_FILE)) return null;
@@ -287,41 +393,82 @@ function markAccountUsed(connId) {
287
393
  // checks expiry, refreshes token automatically, then returns the
288
394
  // latest persisted connection snapshot for the current request.
289
395
 
290
- async function triggerRefreshIfNeeded(connection) {
291
- if (!connection?.expiresAt || !connection?.refreshToken) return connection;
292
- const expiresAt = new Date(connection.expiresAt).getTime();
293
- if (Date.now() + TOKEN_EXPIRY_BUFFER_MS < expiresAt) return connection;
294
-
295
- log(`🔄 [token-pool] near-expiry refresh → ${getConnectionLabel(connection).slice(0, 20)}`);
396
+ async function runConnectionTest(connection) {
296
397
  return await new Promise((resolve) => {
398
+ if (!connection?.id) {
399
+ resolve({ connection, refreshed: false, valid: false });
400
+ return;
401
+ }
402
+
403
+ let responseBody = "";
404
+
297
405
  try {
298
406
  const req = http.request(
299
407
  { hostname: "127.0.0.1", port: ROUTER_PORT, path: `/api/providers/${connection.id}/test`, method: "POST" },
300
408
  (res) => {
301
- res.on("data", () => {});
409
+ res.on("data", (chunk) => {
410
+ responseBody += chunk.toString();
411
+ });
302
412
  res.on("end", () => {
303
- const refreshed = getConnectionById(connection.id);
304
- if (refreshed?.accessToken && refreshed.accessToken !== connection.accessToken) {
305
- log(`♻️ [token-pool] refreshed token applied → ${getConnectionLabel(connection).slice(0, 20)}`);
413
+ let payload = {};
414
+ try {
415
+ payload = JSON.parse(responseBody || "{}");
416
+ } catch {
417
+ payload = {};
306
418
  }
307
- resolve(refreshed || connection);
419
+
420
+ const refreshedConnection = getConnectionById(connection.id);
421
+ const tokenChanged = !!(refreshedConnection?.accessToken && refreshedConnection.accessToken !== connection.accessToken);
422
+ resolve({
423
+ connection: refreshedConnection || connection,
424
+ refreshed: !!payload.refreshed || tokenChanged,
425
+ valid: !!payload.valid,
426
+ });
308
427
  });
309
428
  }
310
429
  );
311
- req.on("error", () => resolve(connection));
430
+ req.on("error", () => resolve({ connection, refreshed: false, valid: false }));
312
431
  req.end();
313
432
  } catch {
314
- resolve(connection);
433
+ resolve({ connection, refreshed: false, valid: false });
315
434
  }
316
435
  });
317
436
  }
318
437
 
438
+ async function triggerRefreshIfNeeded(connection) {
439
+ if (!connection?.expiresAt || !connection?.refreshToken) return connection;
440
+ const expiresAt = new Date(connection.expiresAt).getTime();
441
+ if (Date.now() + TOKEN_EXPIRY_BUFFER_MS < expiresAt) return connection;
442
+
443
+ log(`🔄 [token-pool] near-expiry refresh → ${getConnectionLabel(connection).slice(0, 20)}`);
444
+ const result = await runConnectionTest(connection);
445
+ if (result.refreshed) {
446
+ log(`♻️ [token-pool] refreshed token applied → ${getConnectionLabel(connection).slice(0, 20)}`);
447
+ }
448
+ return result.connection || connection;
449
+ }
450
+
451
+ async function forceRefreshConnection(connection) {
452
+ if (!connection?.refreshToken) {
453
+ return { connection, refreshed: false, valid: false };
454
+ }
455
+
456
+ log(`🔄 [token-pool] auth refresh → ${getConnectionLabel(connection).slice(0, 20)}`);
457
+ const result = await runConnectionTest(connection);
458
+ if (result.refreshed) {
459
+ log(`♻️ [token-pool] refreshed token applied → ${getConnectionLabel(connection).slice(0, 20)}`);
460
+ }
461
+ return result;
462
+ }
463
+
319
464
  module.exports = {
320
465
  isTokenSwapEnabled,
321
466
  getNextConnection,
322
467
  getAllActiveConnections,
323
468
  triggerRefreshIfNeeded,
469
+ forceRefreshConnection,
324
470
  setCooldown,
471
+ setAuthCooldown,
325
472
  setModelCooldown,
326
473
  isModelExhausted,
327
474
  getTokenSwapStrategy,
@@ -329,4 +476,5 @@ module.exports = {
329
476
  markAccountUsed,
330
477
  getConnectionLabel,
331
478
  maskEmail,
479
+ getTokenSwapAvailabilitySummary,
332
480
  };
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "n9router",
3
- "version": "0.3.93",
3
+ "version": "0.3.95",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "n9router",
9
- "version": "0.3.93",
9
+ "version": "0.3.95",
10
10
  "license": "MIT",
11
11
  "dependencies": {
12
12
  "@monaco-editor/react": "^4.7.0",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n9router",
3
- "version": "0.3.93",
3
+ "version": "0.3.95",
4
4
  "description": "Self-hosted AI routing gateway — local proxy for Claude, Gemini, OpenAI and 40+ providers",
5
5
  "keywords": [
6
6
  "ai",
@@ -0,0 +1,218 @@
1
+ # Scope And Architecture
2
+
3
+ ## Scope
4
+
5
+ ### In scope
6
+
7
+ - Antigravity OAuth and account import
8
+ - project ID fetch/onboarding if needed by account validation or usage flows
9
+ - MITM HTTPS server for Antigravity domains
10
+ - DNS/hosts enable-disable for Antigravity
11
+ - root certificate generation and trust flow
12
+ - token swap across Antigravity accounts
13
+ - usage persistence, logs, request detail capture
14
+ - desktop-first UI for operating the above
15
+ - cross-platform support for macOS, Windows, and Linux
16
+
17
+ ### Out of scope
18
+
19
+ - generic AI router
20
+ - upstream model aliasing outside MITM use case
21
+ - generic provider CRUD for all existing providers
22
+ - all `src/app/api/v1/*` compatibility APIs
23
+ - cloud deployment and Workers support
24
+
25
+ ## Existing code to reuse
26
+
27
+ ### Core logic to preserve
28
+
29
+ - Antigravity OAuth flow:
30
+ - `src/lib/oauth/services/antigravity.js`
31
+ - MITM server:
32
+ - `src/mitm/server.js`
33
+ - `src/mitm/handlers/antigravity.js`
34
+ - `src/mitm/config.js`
35
+ - token swap:
36
+ - `src/mitm/tokenPool.js`
37
+ - usage capture:
38
+ - `src/mitm/usageTracker.js`
39
+ - `src/lib/usageDb.js`
40
+ - settings and account persistence:
41
+ - `src/lib/localDb.js`
42
+ - DNS and cert operations:
43
+ - `src/mitm/dns/dnsConfig.js`
44
+ - `src/mitm/cert/*`
45
+ - `src/mitm/manager.js`
46
+ - account import from local Antigravity install:
47
+ - `src/app/api/antigravity-tools/import/route.js`
48
+
49
+ ### UI logic to mine and adapt
50
+
51
+ - `src/app/(dashboard)/dashboard/mitm/MitmPageClient.js`
52
+ - `src/app/(dashboard)/dashboard/usage/page.js`
53
+ - `src/app/(dashboard)/dashboard/usage/components/RequestDetailsTab.js`
54
+ - `src/app/(dashboard)/dashboard/usage/components/OverviewCards.js`
55
+ - `src/shared/constants/cliTools.js`
56
+
57
+ ## Target workspace layout
58
+
59
+ ```text
60
+ apps/
61
+ desktop-shell/ # Tauri
62
+ desktop-ui/ # React SPA
63
+ desktop-backend/ # Express service
64
+ packages/
65
+ desktop-shared/ # API contracts, DTOs, constants
66
+ plans/
67
+ tauri-app/
68
+ ```
69
+
70
+ ## Runtime boundaries
71
+
72
+ ### Tauri Rust owns
73
+
74
+ - secure credential storage integration
75
+ - privileged actions
76
+ - backend process supervision
77
+ - MITM sidecar process supervision if separate from backend
78
+ - app data dir resolution
79
+ - native menu, tray, startup behavior
80
+ - platform adaptation for macOS, Windows, and Linux behaviors
81
+
82
+ ### Express backend owns
83
+
84
+ - account storage
85
+ - OAuth callback server or callback handling
86
+ - account import and validation
87
+ - MITM routing logic
88
+ - token swap state machine
89
+ - usage writes and reads
90
+ - internal APIs called by usage observer
91
+
92
+ ### React UI owns
93
+
94
+ - control plane only
95
+ - polling/subscribing to backend status
96
+ - visualization of pool state and usage data
97
+ - no direct filesystem or privileged OS operations
98
+
99
+ ## Critical design decisions
100
+
101
+ ### 1. Keep MITM logic in JS for v1
102
+
103
+ Reason:
104
+
105
+ - existing behavior is already implemented
106
+ - request interception and stream parsing are sensitive
107
+ - product value comes from shipping the desktop app, not from rewriting stable logic
108
+
109
+ ### 2. Move OS privilege work out of Node
110
+
111
+ Reason:
112
+
113
+ - current Node code handles passwords and host mutations directly
114
+ - desktop app should centralize privileged operations in Tauri
115
+ - Tauri offers a cleaner UX for elevation prompts and secret handling
116
+
117
+ ### 3. Keep JSON persistence first
118
+
119
+ Reason:
120
+
121
+ - current code already uses `db.json`, `usage.json`, and `log.txt`
122
+ - enough for a desktop MVP
123
+ - storage migration to SQLite is a separate concern and should not block v1
124
+
125
+ ### 4. Design for cross-platform from day one
126
+
127
+ Reason:
128
+
129
+ - DNS and certificate flows are different on each OS
130
+ - port 443 and elevation behavior differ across OSes
131
+ - retrofitting Windows and Linux after a macOS-first implementation will create avoidable rework
132
+
133
+ ## Platform support requirements
134
+
135
+ ### Shared
136
+
137
+ - same user-facing feature set on macOS, Windows, and Linux
138
+ - same backend API contract across all OSes
139
+ - same persistence format across all OSes
140
+ - same token swap semantics across all OSes
141
+
142
+ ### macOS
143
+
144
+ - support hosts-file mutation
145
+ - support certificate trust flow
146
+ - support DNS cache flush
147
+
148
+ ### Windows
149
+
150
+ - support hosts-file mutation under elevated privileges
151
+ - support certificate trust flow using Windows certificate store
152
+ - support UAC-based elevation flow without requiring terminal usage
153
+
154
+ ### Linux
155
+
156
+ - support hosts-file mutation on major desktop distros
157
+ - support root certificate installation at least for the app-documented path
158
+ - support DNS cache flush with distro-safe fallbacks
159
+ - gracefully handle environments without `sudo`
160
+
161
+ ## Architecture diagram
162
+
163
+ ```mermaid
164
+ flowchart LR
165
+ UI["React Desktop UI"] --> API["Local Express Backend"]
166
+ UI --> TAURI["Tauri Commands"]
167
+ TAURI --> OS["OS Cert / DNS / Secure Store"]
168
+ TAURI --> API
169
+ API --> DB["db.json / usage.json / log.txt"]
170
+ API --> MITM["MITM HTTPS Server"]
171
+ MITM --> AG["Antigravity Domains"]
172
+ MITM --> API
173
+ ```
174
+
175
+ ## MVP feature map
176
+
177
+ ### Accounts
178
+
179
+ - list accounts
180
+ - connect via browser OAuth
181
+ - import from `~/.antigravity_tools`
182
+ - enable/disable account
183
+ - show token expiry and refresh availability
184
+
185
+ ### MITM
186
+
187
+ - cert exists
188
+ - cert trusted
189
+ - server running
190
+ - DNS active
191
+ - health status
192
+ - start/stop controls
193
+ - platform-specific remediation text when a native action fails
194
+
195
+ ### Token swap
196
+
197
+ - enable/disable
198
+ - strategy selection
199
+ - account pool table
200
+ - cooldown visibility
201
+ - auth failure visibility
202
+ - last-used rotation indicator
203
+
204
+ ### Usage analyst
205
+
206
+ - totals
207
+ - recent requests
208
+ - token totals
209
+ - estimated cost
210
+ - request details drawer
211
+ - account-level and model-level filtering
212
+
213
+ ## Cross-platform acceptance criteria
214
+
215
+ - the app can be packaged and launched on macOS, Windows, and Linux
216
+ - backend startup path is identical from the UI perspective on all OSes
217
+ - cert/DNS/MITM state is surfaced consistently on all OSes
218
+ - platform-specific failure messages are understandable and actionable