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.
- package/.next/standalone/.next/BUILD_ID +1 -1
- package/.next/standalone/.next/build-manifest.json +3 -3
- package/.next/standalone/.next/server/app/(dashboard)/dashboard/basic-chat/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/(dashboard)/dashboard/basic-chat/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/(dashboard)/dashboard/cli-tools/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/(dashboard)/dashboard/cli-tools/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/(dashboard)/dashboard/combos/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/(dashboard)/dashboard/combos/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/(dashboard)/dashboard/console-log/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/(dashboard)/dashboard/console-log/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/(dashboard)/dashboard/endpoint/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/(dashboard)/dashboard/endpoint/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/(dashboard)/dashboard/mitm/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/(dashboard)/dashboard/mitm/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/(dashboard)/dashboard/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/(dashboard)/dashboard/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/(dashboard)/dashboard/profile/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/(dashboard)/dashboard/profile/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/(dashboard)/dashboard/providers/[id]/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/(dashboard)/dashboard/providers/[id]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/(dashboard)/dashboard/providers/new/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/(dashboard)/dashboard/providers/new/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/(dashboard)/dashboard/providers/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/(dashboard)/dashboard/providers/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/(dashboard)/dashboard/proxy-pools/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/(dashboard)/dashboard/proxy-pools/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/(dashboard)/dashboard/quota/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/(dashboard)/dashboard/quota/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/(dashboard)/dashboard/translator/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/(dashboard)/dashboard/translator/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/(dashboard)/dashboard/usage/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/(dashboard)/dashboard/usage/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_global-error.html +1 -1
- package/.next/standalone/.next/server/app/_global-error.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_not-found.html +1 -1
- package/.next/standalone/.next/server/app/_not-found.rsc +10 -10
- package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +10 -10
- package/.next/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +5 -5
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/api/antigravity-tools/import/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/antigravity-tools/import-refresh-tokens/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/login/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cli-tools/antigravity-mitm/alias/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cli-tools/antigravity-mitm/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cloud/auth/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cloud/credentials/update/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cloud/model/resolve/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cloud/models/alias/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/combos/[id]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/combos/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/init/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/internal/request-detail/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/internal/usage/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/keys/[id]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/keys/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/models/alias/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/models/availability/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/models/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/models/test/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/oauth/[provider]/[action]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/oauth/cursor/import/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/oauth/gitlab/pat/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/oauth/iflow/cookie/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/oauth/kiro/import/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/oauth/kiro/social-exchange/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/pricing/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/provider-nodes/[id]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/provider-nodes/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/providers/[id]/models/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/providers/[id]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/providers/[id]/test/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/providers/[id]/test-models/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/providers/client/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/providers/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/providers/test-batch/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/providers/validate/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/proxy-pools/[id]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/proxy-pools/[id]/test/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/proxy-pools/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/settings/database/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/settings/require-login/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/settings/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/translator/send/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/translator/translate/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/tunnel/disable/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/tunnel/enable/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/tunnel/status/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/usage/[connectionId]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/usage/chart/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/usage/history/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/usage/logs/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/usage/providers/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/usage/request-details/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/usage/request-logs/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/usage/stats/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/usage/stream/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/v1/api/chat/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/v1/chat/completions/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/v1/embeddings/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/v1/messages/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/v1/models/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/v1/responses/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/v1beta/models/[...path]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/callback/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/callback/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/callback.html +1 -1
- package/.next/standalone/.next/server/app/callback.rsc +12 -12
- package/.next/standalone/.next/server/app/callback.segments/_full.segment.rsc +12 -12
- package/.next/standalone/.next/server/app/callback.segments/_head.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/callback.segments/_index.segment.rsc +5 -5
- package/.next/standalone/.next/server/app/callback.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/callback.segments/callback/__PAGE__.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/callback.segments/callback.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/dashboard/basic-chat.html +1 -1
- package/.next/standalone/.next/server/app/dashboard/basic-chat.rsc +12 -12
- package/.next/standalone/.next/server/app/dashboard/basic-chat.segments/!KGRhc2hib2FyZCk/dashboard/basic-chat/__PAGE__.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/dashboard/basic-chat.segments/!KGRhc2hib2FyZCk/dashboard/basic-chat.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/dashboard/basic-chat.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/dashboard/basic-chat.segments/!KGRhc2hib2FyZCk.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/dashboard/basic-chat.segments/_full.segment.rsc +12 -12
- package/.next/standalone/.next/server/app/dashboard/basic-chat.segments/_head.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/dashboard/basic-chat.segments/_index.segment.rsc +5 -5
- package/.next/standalone/.next/server/app/dashboard/basic-chat.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/dashboard/cli-tools.html +1 -1
- package/.next/standalone/.next/server/app/dashboard/cli-tools.rsc +12 -12
- package/.next/standalone/.next/server/app/dashboard/cli-tools.segments/!KGRhc2hib2FyZCk/dashboard/cli-tools/__PAGE__.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/dashboard/cli-tools.segments/!KGRhc2hib2FyZCk/dashboard/cli-tools.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/dashboard/cli-tools.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/dashboard/cli-tools.segments/!KGRhc2hib2FyZCk.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/dashboard/cli-tools.segments/_full.segment.rsc +12 -12
- package/.next/standalone/.next/server/app/dashboard/cli-tools.segments/_head.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/dashboard/cli-tools.segments/_index.segment.rsc +5 -5
- package/.next/standalone/.next/server/app/dashboard/cli-tools.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/dashboard/combos.html +1 -1
- package/.next/standalone/.next/server/app/dashboard/combos.rsc +13 -13
- package/.next/standalone/.next/server/app/dashboard/combos.segments/!KGRhc2hib2FyZCk/dashboard/combos/__PAGE__.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/dashboard/combos.segments/!KGRhc2hib2FyZCk/dashboard/combos.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/dashboard/combos.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/dashboard/combos.segments/!KGRhc2hib2FyZCk.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/dashboard/combos.segments/_full.segment.rsc +13 -13
- package/.next/standalone/.next/server/app/dashboard/combos.segments/_head.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/dashboard/combos.segments/_index.segment.rsc +5 -5
- package/.next/standalone/.next/server/app/dashboard/combos.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/dashboard/endpoint.html +1 -1
- package/.next/standalone/.next/server/app/dashboard/endpoint.rsc +12 -12
- package/.next/standalone/.next/server/app/dashboard/endpoint.segments/!KGRhc2hib2FyZCk/dashboard/endpoint/__PAGE__.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/dashboard/endpoint.segments/!KGRhc2hib2FyZCk/dashboard/endpoint.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/dashboard/endpoint.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/dashboard/endpoint.segments/!KGRhc2hib2FyZCk.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/dashboard/endpoint.segments/_full.segment.rsc +12 -12
- package/.next/standalone/.next/server/app/dashboard/endpoint.segments/_head.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/dashboard/endpoint.segments/_index.segment.rsc +5 -5
- package/.next/standalone/.next/server/app/dashboard/endpoint.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/dashboard/mitm.html +1 -1
- package/.next/standalone/.next/server/app/dashboard/mitm.rsc +12 -12
- package/.next/standalone/.next/server/app/dashboard/mitm.segments/!KGRhc2hib2FyZCk/dashboard/mitm/__PAGE__.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/dashboard/mitm.segments/!KGRhc2hib2FyZCk/dashboard/mitm.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/dashboard/mitm.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/dashboard/mitm.segments/!KGRhc2hib2FyZCk.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/dashboard/mitm.segments/_full.segment.rsc +12 -12
- package/.next/standalone/.next/server/app/dashboard/mitm.segments/_head.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/dashboard/mitm.segments/_index.segment.rsc +5 -5
- package/.next/standalone/.next/server/app/dashboard/mitm.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/dashboard/profile.html +1 -1
- package/.next/standalone/.next/server/app/dashboard/profile.rsc +13 -13
- package/.next/standalone/.next/server/app/dashboard/profile.segments/!KGRhc2hib2FyZCk/dashboard/profile/__PAGE__.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/dashboard/profile.segments/!KGRhc2hib2FyZCk/dashboard/profile.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/dashboard/profile.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/dashboard/profile.segments/!KGRhc2hib2FyZCk.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/dashboard/profile.segments/_full.segment.rsc +13 -13
- package/.next/standalone/.next/server/app/dashboard/profile.segments/_head.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/dashboard/profile.segments/_index.segment.rsc +5 -5
- package/.next/standalone/.next/server/app/dashboard/profile.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/dashboard/providers/new.html +1 -1
- package/.next/standalone/.next/server/app/dashboard/providers/new.rsc +13 -13
- package/.next/standalone/.next/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk/dashboard/providers/new/__PAGE__.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk/dashboard/providers/new.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk/dashboard/providers.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/dashboard/providers/new.segments/_full.segment.rsc +13 -13
- package/.next/standalone/.next/server/app/dashboard/providers/new.segments/_head.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/dashboard/providers/new.segments/_index.segment.rsc +5 -5
- package/.next/standalone/.next/server/app/dashboard/providers/new.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/dashboard/providers.html +1 -1
- package/.next/standalone/.next/server/app/dashboard/providers.rsc +13 -13
- package/.next/standalone/.next/server/app/dashboard/providers.segments/!KGRhc2hib2FyZCk/dashboard/providers/__PAGE__.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/dashboard/providers.segments/!KGRhc2hib2FyZCk/dashboard/providers.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/dashboard/providers.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/dashboard/providers.segments/!KGRhc2hib2FyZCk.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/dashboard/providers.segments/_full.segment.rsc +13 -13
- package/.next/standalone/.next/server/app/dashboard/providers.segments/_head.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/dashboard/providers.segments/_index.segment.rsc +5 -5
- package/.next/standalone/.next/server/app/dashboard/providers.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/dashboard/proxy-pools.html +1 -1
- package/.next/standalone/.next/server/app/dashboard/proxy-pools.rsc +13 -13
- package/.next/standalone/.next/server/app/dashboard/proxy-pools.segments/!KGRhc2hib2FyZCk/dashboard/proxy-pools/__PAGE__.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/dashboard/proxy-pools.segments/!KGRhc2hib2FyZCk/dashboard/proxy-pools.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/dashboard/proxy-pools.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/dashboard/proxy-pools.segments/!KGRhc2hib2FyZCk.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/dashboard/proxy-pools.segments/_full.segment.rsc +13 -13
- package/.next/standalone/.next/server/app/dashboard/proxy-pools.segments/_head.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/dashboard/proxy-pools.segments/_index.segment.rsc +5 -5
- package/.next/standalone/.next/server/app/dashboard/proxy-pools.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/dashboard/quota.html +2 -2
- package/.next/standalone/.next/server/app/dashboard/quota.rsc +13 -13
- package/.next/standalone/.next/server/app/dashboard/quota.segments/!KGRhc2hib2FyZCk/dashboard/quota/__PAGE__.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/dashboard/quota.segments/!KGRhc2hib2FyZCk/dashboard/quota.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/dashboard/quota.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/dashboard/quota.segments/!KGRhc2hib2FyZCk.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/dashboard/quota.segments/_full.segment.rsc +13 -13
- package/.next/standalone/.next/server/app/dashboard/quota.segments/_head.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/dashboard/quota.segments/_index.segment.rsc +5 -5
- package/.next/standalone/.next/server/app/dashboard/quota.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/dashboard/settings/pricing/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/dashboard/settings/pricing/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/dashboard/settings/pricing.html +1 -1
- package/.next/standalone/.next/server/app/dashboard/settings/pricing.rsc +12 -12
- package/.next/standalone/.next/server/app/dashboard/settings/pricing.segments/_full.segment.rsc +12 -12
- package/.next/standalone/.next/server/app/dashboard/settings/pricing.segments/_head.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/dashboard/settings/pricing.segments/_index.segment.rsc +5 -5
- package/.next/standalone/.next/server/app/dashboard/settings/pricing.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/dashboard/settings/pricing.segments/dashboard/settings/pricing/__PAGE__.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/dashboard/settings/pricing.segments/dashboard/settings/pricing.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/dashboard/settings/pricing.segments/dashboard/settings.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/dashboard/settings/pricing.segments/dashboard.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/dashboard/translator.html +1 -1
- package/.next/standalone/.next/server/app/dashboard/translator.rsc +13 -13
- package/.next/standalone/.next/server/app/dashboard/translator.segments/!KGRhc2hib2FyZCk/dashboard/translator/__PAGE__.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/dashboard/translator.segments/!KGRhc2hib2FyZCk/dashboard/translator.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/dashboard/translator.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/dashboard/translator.segments/!KGRhc2hib2FyZCk.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/dashboard/translator.segments/_full.segment.rsc +13 -13
- package/.next/standalone/.next/server/app/dashboard/translator.segments/_head.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/dashboard/translator.segments/_index.segment.rsc +5 -5
- package/.next/standalone/.next/server/app/dashboard/translator.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/dashboard/usage.html +1 -1
- package/.next/standalone/.next/server/app/dashboard/usage.rsc +13 -13
- package/.next/standalone/.next/server/app/dashboard/usage.segments/!KGRhc2hib2FyZCk/dashboard/usage/__PAGE__.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/dashboard/usage.segments/!KGRhc2hib2FyZCk/dashboard/usage.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/dashboard/usage.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/dashboard/usage.segments/!KGRhc2hib2FyZCk.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/dashboard/usage.segments/_full.segment.rsc +13 -13
- package/.next/standalone/.next/server/app/dashboard/usage.segments/_head.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/dashboard/usage.segments/_index.segment.rsc +5 -5
- package/.next/standalone/.next/server/app/dashboard/usage.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/dashboard.html +1 -1
- package/.next/standalone/.next/server/app/dashboard.rsc +12 -12
- package/.next/standalone/.next/server/app/dashboard.segments/!KGRhc2hib2FyZCk/dashboard/__PAGE__.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/dashboard.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/dashboard.segments/!KGRhc2hib2FyZCk.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/dashboard.segments/_full.segment.rsc +12 -12
- package/.next/standalone/.next/server/app/dashboard.segments/_head.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/dashboard.segments/_index.segment.rsc +5 -5
- package/.next/standalone/.next/server/app/dashboard.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/index.html +1 -1
- package/.next/standalone/.next/server/app/index.rsc +10 -10
- package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +10 -10
- package/.next/standalone/.next/server/app/index.segments/_head.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/index.segments/_index.segment.rsc +5 -5
- package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/landing/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/landing/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/landing.html +1 -1
- package/.next/standalone/.next/server/app/landing.rsc +12 -12
- package/.next/standalone/.next/server/app/landing.segments/_full.segment.rsc +12 -12
- package/.next/standalone/.next/server/app/landing.segments/_head.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/landing.segments/_index.segment.rsc +5 -5
- package/.next/standalone/.next/server/app/landing.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/landing.segments/landing/__PAGE__.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/landing.segments/landing.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/login/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/login/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/login.html +1 -1
- package/.next/standalone/.next/server/app/login.rsc +12 -12
- package/.next/standalone/.next/server/app/login.segments/_full.segment.rsc +12 -12
- package/.next/standalone/.next/server/app/login.segments/_head.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/login.segments/_index.segment.rsc +5 -5
- package/.next/standalone/.next/server/app/login.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/login.segments/login/__PAGE__.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/login.segments/login.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0.yvcis._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0148t9m._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0b802lh._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0kpc-o6._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0lc~.sk._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0lp_pm5._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0pwrfp1._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0uw3x8s._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0y.reft._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0y5ae.7._.js +1 -1
- package/.next/standalone/.next/server/chunks/_0__-aqg._.js +1 -1
- package/.next/standalone/.next/server/chunks/_0_ovl1h._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/src_0_xhepz._.js +1 -1
- package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
- package/.next/standalone/.next/server/pages/404.html +1 -1
- package/.next/standalone/.next/server/pages/500.html +1 -1
- package/.next/{static/chunks/0deg-_syv13xx.js → standalone/.next/static/chunks/11q6656-lc_oz.js} +1 -1
- package/.next/standalone/mitm/server.js +168 -113
- package/.next/standalone/mitm/tokenPool.js +168 -20
- package/.next/standalone/package-lock.json +2 -2
- package/.next/standalone/package.json +1 -1
- package/.next/standalone/plans/tauri-app/01-scope-and-architecture.md +218 -0
- package/.next/standalone/plans/tauri-app/02-backend-plan.md +237 -0
- package/.next/standalone/plans/tauri-app/03-tauri-native-plan.md +194 -0
- package/.next/standalone/plans/tauri-app/04-react-ui-plan.md +155 -0
- package/.next/standalone/plans/tauri-app/05-delivery-phases.md +171 -0
- package/.next/standalone/plans/tauri-app/README.md +87 -0
- package/.next/standalone/src/mitm/server.js +168 -113
- package/.next/standalone/src/mitm/tokenPool.js +168 -20
- package/.next/{standalone/.next/static/chunks/0deg-_syv13xx.js → static/chunks/11q6656-lc_oz.js} +1 -1
- package/package.json +1 -1
- /package/.next/standalone/.next/static/{b_Drjo0YdAiFCInKT62q9 → 03mW5vaG0Fogum-tDkkOQ}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{b_Drjo0YdAiFCInKT62q9 → 03mW5vaG0Fogum-tDkkOQ}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{b_Drjo0YdAiFCInKT62q9 → 03mW5vaG0Fogum-tDkkOQ}/_ssgManifest.js +0 -0
- /package/.next/static/{b_Drjo0YdAiFCInKT62q9 → 03mW5vaG0Fogum-tDkkOQ}/_buildManifest.js +0 -0
- /package/.next/static/{b_Drjo0YdAiFCInKT62q9 → 03mW5vaG0Fogum-tDkkOQ}/_clientMiddlewareManifest.js +0 -0
- /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
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
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
|
-
|
|
225
|
-
|
|
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
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
[
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
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
|
-
|
|
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`);
|