n9router 0.3.97 → 0.3.99
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/app-path-routes-manifest.json +3 -3
- package/.next/standalone/.next/build-manifest.json +2 -2
- package/.next/standalone/.next/prerender-manifest.json +3 -3
- 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 +2 -2
- 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_client-reference-manifest.js +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_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/(dashboard)/dashboard/media-providers/[kind]/[id]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/(dashboard)/dashboard/media-providers/[kind]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/(dashboard)/dashboard/mitm/page.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_client-reference-manifest.js +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_client-reference-manifest.js +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_client-reference-manifest.js +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 +2 -2
- 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_client-reference-manifest.js +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/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/_full.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/_global-error.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_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 +3 -3
- package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- 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 +1 -1
- package/.next/standalone/.next/server/app/api/antigravity-tools/import-refresh-tokens/route.js +1 -1
- package/.next/standalone/.next/server/app/api/cli-tools/antigravity-mitm/alias/route.js +2 -2
- package/.next/standalone/.next/server/app/api/cli-tools/antigravity-mitm/route.js +1 -1
- package/.next/standalone/.next/server/app/api/cli-tools/claude-settings/route.js +2 -2
- package/.next/standalone/.next/server/app/api/cli-tools/codex-settings/route.js +2 -2
- package/.next/standalone/.next/server/app/api/cli-tools/copilot-settings/route.js +2 -2
- package/.next/standalone/.next/server/app/api/cli-tools/droid-settings/route.js +1 -1
- package/.next/standalone/.next/server/app/api/cli-tools/openclaw-settings/route.js +2 -2
- package/.next/standalone/.next/server/app/api/cli-tools/opencode-settings/route.js +1 -1
- package/.next/standalone/.next/server/app/api/oauth/[provider]/[action]/route.js +1 -1
- package/.next/standalone/.next/server/app/api/oauth/cursor/import/route.js +1 -1
- package/.next/standalone/.next/server/app/api/providers/[id]/models/route.js +1 -1
- package/.next/standalone/.next/server/app/api/providers/[id]/test/route.js +1 -1
- package/.next/standalone/.next/server/app/api/providers/test-batch/route.js +1 -1
- package/.next/standalone/.next/server/app/api/shutdown/route.js +1 -1
- package/.next/standalone/.next/server/app/api/shutdown/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/translator/send/route.js +1 -1
- package/.next/standalone/.next/server/app/api/translator/translate/route.js +1 -1
- package/.next/standalone/.next/server/app/api/usage/[connectionId]/route.js +1 -1
- package/.next/standalone/.next/server/app/api/v1/api/chat/route.js +1 -1
- package/.next/standalone/.next/server/app/api/v1/chat/completions/route.js +1 -1
- package/.next/standalone/.next/server/app/api/v1/embeddings/route.js +1 -1
- package/.next/standalone/.next/server/app/api/v1/messages/route.js +1 -1
- package/.next/standalone/.next/server/app/api/v1/responses/route.js +1 -1
- package/.next/standalone/.next/server/app/api/v1beta/models/[...path]/route.js +1 -1
- package/.next/standalone/.next/server/app/api/version/route.js +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 +3 -3
- package/.next/standalone/.next/server/app/callback.segments/_full.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/callback.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/callback.segments/_index.segment.rsc +3 -3
- 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 +1 -1
- package/.next/standalone/.next/server/app/callback.segments/callback.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/dashboard/basic-chat.html +1 -1
- package/.next/standalone/.next/server/app/dashboard/basic-chat.rsc +5 -5
- package/.next/standalone/.next/server/app/dashboard/basic-chat.segments/!KGRhc2hib2FyZCk/dashboard/basic-chat/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/dashboard/basic-chat.segments/!KGRhc2hib2FyZCk/dashboard/basic-chat.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/dashboard/basic-chat.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/dashboard/basic-chat.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/dashboard/basic-chat.segments/_full.segment.rsc +5 -5
- package/.next/standalone/.next/server/app/dashboard/basic-chat.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/dashboard/basic-chat.segments/_index.segment.rsc +3 -3
- 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 +5 -5
- package/.next/standalone/.next/server/app/dashboard/cli-tools.segments/!KGRhc2hib2FyZCk/dashboard/cli-tools/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/dashboard/cli-tools.segments/!KGRhc2hib2FyZCk/dashboard/cli-tools.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/dashboard/cli-tools.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/dashboard/cli-tools.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/dashboard/cli-tools.segments/_full.segment.rsc +5 -5
- package/.next/standalone/.next/server/app/dashboard/cli-tools.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/dashboard/cli-tools.segments/_index.segment.rsc +3 -3
- 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 +5 -5
- package/.next/standalone/.next/server/app/dashboard/combos.segments/!KGRhc2hib2FyZCk/dashboard/combos/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/dashboard/combos.segments/!KGRhc2hib2FyZCk/dashboard/combos.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/dashboard/combos.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/dashboard/combos.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/dashboard/combos.segments/_full.segment.rsc +5 -5
- package/.next/standalone/.next/server/app/dashboard/combos.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/dashboard/combos.segments/_index.segment.rsc +3 -3
- 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 +5 -5
- package/.next/standalone/.next/server/app/dashboard/endpoint.segments/!KGRhc2hib2FyZCk/dashboard/endpoint/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/dashboard/endpoint.segments/!KGRhc2hib2FyZCk/dashboard/endpoint.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/dashboard/endpoint.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/dashboard/endpoint.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/dashboard/endpoint.segments/_full.segment.rsc +5 -5
- package/.next/standalone/.next/server/app/dashboard/endpoint.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/dashboard/endpoint.segments/_index.segment.rsc +3 -3
- 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 +5 -5
- package/.next/standalone/.next/server/app/dashboard/mitm.segments/!KGRhc2hib2FyZCk/dashboard/mitm/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/dashboard/mitm.segments/!KGRhc2hib2FyZCk/dashboard/mitm.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/dashboard/mitm.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/dashboard/mitm.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/dashboard/mitm.segments/_full.segment.rsc +5 -5
- package/.next/standalone/.next/server/app/dashboard/mitm.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/dashboard/mitm.segments/_index.segment.rsc +3 -3
- 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 +5 -5
- package/.next/standalone/.next/server/app/dashboard/profile.segments/!KGRhc2hib2FyZCk/dashboard/profile/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/dashboard/profile.segments/!KGRhc2hib2FyZCk/dashboard/profile.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/dashboard/profile.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/dashboard/profile.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/dashboard/profile.segments/_full.segment.rsc +5 -5
- package/.next/standalone/.next/server/app/dashboard/profile.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/dashboard/profile.segments/_index.segment.rsc +3 -3
- 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 +5 -5
- package/.next/standalone/.next/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk/dashboard/providers/new/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk/dashboard/providers/new.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk/dashboard/providers.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/dashboard/providers/new.segments/_full.segment.rsc +5 -5
- package/.next/standalone/.next/server/app/dashboard/providers/new.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/dashboard/providers/new.segments/_index.segment.rsc +3 -3
- 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 +5 -5
- package/.next/standalone/.next/server/app/dashboard/providers.segments/!KGRhc2hib2FyZCk/dashboard/providers/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/dashboard/providers.segments/!KGRhc2hib2FyZCk/dashboard/providers.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/dashboard/providers.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/dashboard/providers.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/dashboard/providers.segments/_full.segment.rsc +5 -5
- package/.next/standalone/.next/server/app/dashboard/providers.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/dashboard/providers.segments/_index.segment.rsc +3 -3
- 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 +5 -5
- package/.next/standalone/.next/server/app/dashboard/proxy-pools.segments/!KGRhc2hib2FyZCk/dashboard/proxy-pools/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/dashboard/proxy-pools.segments/!KGRhc2hib2FyZCk/dashboard/proxy-pools.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/dashboard/proxy-pools.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/dashboard/proxy-pools.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/dashboard/proxy-pools.segments/_full.segment.rsc +5 -5
- package/.next/standalone/.next/server/app/dashboard/proxy-pools.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/dashboard/proxy-pools.segments/_index.segment.rsc +3 -3
- 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 +6 -6
- package/.next/standalone/.next/server/app/dashboard/quota.segments/!KGRhc2hib2FyZCk/dashboard/quota/__PAGE__.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/dashboard/quota.segments/!KGRhc2hib2FyZCk/dashboard/quota.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/dashboard/quota.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/dashboard/quota.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/dashboard/quota.segments/_full.segment.rsc +6 -6
- package/.next/standalone/.next/server/app/dashboard/quota.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/dashboard/quota.segments/_index.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/dashboard/quota.segments/_tree.segment.rsc +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 +3 -3
- package/.next/standalone/.next/server/app/dashboard/settings/pricing.segments/_full.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/dashboard/settings/pricing.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/dashboard/settings/pricing.segments/_index.segment.rsc +3 -3
- 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 +1 -1
- package/.next/standalone/.next/server/app/dashboard/settings/pricing.segments/dashboard/settings/pricing.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/dashboard/settings/pricing.segments/dashboard/settings.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/dashboard/settings/pricing.segments/dashboard.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/dashboard/translator.html +1 -1
- package/.next/standalone/.next/server/app/dashboard/translator.rsc +5 -5
- package/.next/standalone/.next/server/app/dashboard/translator.segments/!KGRhc2hib2FyZCk/dashboard/translator/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/dashboard/translator.segments/!KGRhc2hib2FyZCk/dashboard/translator.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/dashboard/translator.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/dashboard/translator.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/dashboard/translator.segments/_full.segment.rsc +5 -5
- package/.next/standalone/.next/server/app/dashboard/translator.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/dashboard/translator.segments/_index.segment.rsc +3 -3
- 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 +5 -5
- package/.next/standalone/.next/server/app/dashboard/usage.segments/!KGRhc2hib2FyZCk/dashboard/usage/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/dashboard/usage.segments/!KGRhc2hib2FyZCk/dashboard/usage.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/dashboard/usage.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/dashboard/usage.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/dashboard/usage.segments/_full.segment.rsc +5 -5
- package/.next/standalone/.next/server/app/dashboard/usage.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/dashboard/usage.segments/_index.segment.rsc +3 -3
- 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 +5 -5
- package/.next/standalone/.next/server/app/dashboard.segments/!KGRhc2hib2FyZCk/dashboard/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/dashboard.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/dashboard.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/dashboard.segments/_full.segment.rsc +5 -5
- package/.next/standalone/.next/server/app/dashboard.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/dashboard.segments/_index.segment.rsc +3 -3
- 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 +3 -3
- package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/index.segments/_index.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +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 +3 -3
- package/.next/standalone/.next/server/app/landing.segments/_full.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/landing.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/landing.segments/_index.segment.rsc +3 -3
- 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 +1 -1
- package/.next/standalone/.next/server/app/landing.segments/landing.segment.rsc +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 +4 -4
- package/.next/standalone/.next/server/app/login.segments/_full.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/login.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/login.segments/_index.segment.rsc +3 -3
- 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 +2 -2
- package/.next/standalone/.next/server/app/login.segments/login.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app-paths-manifest.json +3 -3
- package/.next/standalone/.next/server/chunks/318.js +2 -2
- package/.next/standalone/.next/server/chunks/3245.js +1 -1
- package/.next/standalone/.next/server/chunks/3646.js +1 -1
- package/.next/standalone/.next/server/chunks/3832.js +1 -1
- package/.next/standalone/.next/server/chunks/5573.js +1 -1
- package/.next/standalone/.next/server/chunks/{1098.js → 7491.js} +8 -8
- package/.next/standalone/.next/server/chunks/8220.js +1 -1
- package/.next/standalone/.next/server/chunks/869.js +1 -1
- package/.next/standalone/.next/server/chunks/9609.js +1 -1
- package/.next/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/.next/standalone/.next/server/pages/404.html +1 -1
- package/.next/standalone/.next/server/pages/500.html +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.json +1 -1
- package/.next/{static/chunks/1321-cf269630cd35f374.js → standalone/.next/static/chunks/1321-a1aa9f7980d68e31.js} +1 -1
- package/.next/standalone/.next/static/chunks/{384-4395af7f56148fe2.js → 5507-ee4bdb0d72f2bf5a.js} +10 -10
- package/.next/standalone/.next/static/chunks/app/(dashboard)/dashboard/cli-tools/page-c0a16328f9656c4a.js +1 -0
- package/.next/standalone/.next/static/chunks/app/(dashboard)/dashboard/mitm/page-1c784308396f8f41.js +1 -0
- package/.next/standalone/.next/static/chunks/app/(dashboard)/dashboard/quota/page-e2666b9d85a3dd55.js +1 -0
- package/.next/standalone/mitm/server.js +44 -8
- package/.next/standalone/mitm/tokenPool.js +149 -19
- package/.next/standalone/mitm/usageTracker.js +76 -0
- package/.next/standalone/package.json +1 -1
- package/.next/standalone/src/mitm/server.js +44 -8
- package/.next/{standalone/.next/static/chunks/1321-cf269630cd35f374.js → static/chunks/1321-a1aa9f7980d68e31.js} +1 -1
- package/.next/static/chunks/{384-4395af7f56148fe2.js → 5507-ee4bdb0d72f2bf5a.js} +10 -10
- package/.next/static/chunks/app/(dashboard)/dashboard/cli-tools/page-c0a16328f9656c4a.js +1 -0
- package/.next/static/chunks/app/(dashboard)/dashboard/mitm/page-1c784308396f8f41.js +1 -0
- package/.next/static/chunks/app/(dashboard)/dashboard/quota/page-e2666b9d85a3dd55.js +1 -0
- package/package.json +1 -1
- package/.next/standalone/.next/static/chunks/app/(dashboard)/dashboard/cli-tools/page-7c9916c696b32907.js +0 -1
- package/.next/standalone/.next/static/chunks/app/(dashboard)/dashboard/mitm/page-f54107ea6e406ea9.js +0 -1
- package/.next/standalone/.next/static/chunks/app/(dashboard)/dashboard/quota/page-9353bb8383654485.js +0 -1
- package/.next/static/chunks/app/(dashboard)/dashboard/cli-tools/page-7c9916c696b32907.js +0 -1
- package/.next/static/chunks/app/(dashboard)/dashboard/mitm/page-f54107ea6e406ea9.js +0 -1
- package/.next/static/chunks/app/(dashboard)/dashboard/quota/page-9353bb8383654485.js +0 -1
- /package/.next/standalone/.next/static/{3_VzVlqirsfVCEDfYRtW1 → gpb-csizE4h9ZQ3ZXLajG}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{3_VzVlqirsfVCEDfYRtW1 → gpb-csizE4h9ZQ3ZXLajG}/_ssgManifest.js +0 -0
- /package/.next/static/{3_VzVlqirsfVCEDfYRtW1 → gpb-csizE4h9ZQ3ZXLajG}/_buildManifest.js +0 -0
- /package/.next/static/{3_VzVlqirsfVCEDfYRtW1 → gpb-csizE4h9ZQ3ZXLajG}/_ssgManifest.js +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[2326],{70044:(e,t,a)=>{Promise.resolve().then(a.bind(a,75228))},75228:(e,t,a)=>{"use strict";a.d(t,{default:()=>u});var s=a(95155),i=a(12115),o=a(35497),l=a(3534),r=a(28777),c=a(3176);let n="https://9router.com",d={claude:"/api/cli-tools/claude-settings",codex:"/api/cli-tools/codex-settings",opencode:"/api/cli-tools/opencode-settings",droid:"/api/cli-tools/droid-settings",openclaw:"/api/cli-tools/openclaw-settings"};function u({machineId:e}){let t,a,p,[v,h]=(0,i.useState)([]),[f,g]=(0,i.useState)(!0),[x,j]=(0,i.useState)(null),[w,E]=(0,i.useState)({}),[b,y]=(0,i.useState)(!1),[S,m]=(0,i.useState)(!1),[k,P]=(0,i.useState)(""),[N,A]=(0,i.useState)([]),[O,_]=(0,i.useState)({});(0,i.useEffect)(()=>{I(),M(),$(),C()},[]);let C=async()=>{try{let e=await Promise.all(Object.entries(d).map(async([e,t])=>{try{let a=await fetch(t),s=await a.json();return[e,s]}catch{return[e,null]}}));_(Object.fromEntries(e))}catch(e){console.log("Error fetching tool statuses:",e)}},M=async()=>{try{let[e,t]=await Promise.all([fetch("/api/settings"),fetch("/api/tunnel/status")]);if(e.ok){let t=await e.json();y(t.cloudEnabled||!1)}if(t.ok){let e=await t.json();m(e.enabled||!1),P(e.publicUrl||"")}}catch(e){console.log("Error loading settings:",e)}},$=async()=>{try{let e=await fetch("/api/keys");if(e.ok){let t=await e.json();A(t.keys||[])}}catch(e){console.log("Error fetching API keys:",e)}},I=async()=>{try{let e=await fetch("/api/providers"),t=await e.json();e.ok&&h(t.connections||[])}catch(e){console.log("Error fetching connections:",e)}finally{g(!1)}},Q=()=>v.filter(e=>!1!==e.isActive),T=(0,i.useCallback)((e,t,a)=>{E(s=>s[e]?.[t]===a?s:{...s,[e]:{...s[e],[t]:a}})},[]);if(f)return(0,s.jsxs)("div",{className:"flex flex-col gap-4",children:[(0,s.jsx)(o.Qv,{}),(0,s.jsx)(o.Qv,{}),(0,s.jsx)(o.Qv,{})]});let U=(t=Q(),a=[],p=new Set,t.forEach(e=>{let t=r.Xg[e.provider]||e.provider;(0,r.KC)(e.provider).forEach(s=>{let i=`${t}/${s.id}`;p.has(i)||(p.add(i),a.push({value:i,label:`${t}/${s.id}`,provider:e.provider,alias:t,connectionName:e.name,modelId:s.id}))})}),a).length>0,Z=Object.entries(l.dM);return(0,s.jsx)("div",{className:"flex flex-col gap-6",children:(0,s.jsx)("div",{className:"flex flex-col gap-4",children:Z.map(([e,t])=>((e,t)=>{let a={tool:t,isExpanded:x===e,onToggle:()=>j(x===e?null:e),baseUrl:S&&k?k:b&&n?n:window.location.origin,apiKeys:N};switch(e){case"claude":return(0,s.jsx)(c.Tk,{...a,activeProviders:Q(),modelMappings:w[e]||{},onModelMappingChange:(t,a)=>T(e,t,a),hasActiveProviders:U,cloudEnabled:b,initialStatus:O.claude},e);case"codex":return(0,s.jsx)(c.Ah,{...a,activeProviders:Q(),cloudEnabled:b,initialStatus:O.codex},e);case"opencode":return(0,s.jsx)(c.qO,{...a,activeProviders:Q(),cloudEnabled:b,initialStatus:O.opencode},e);case"droid":return(0,s.jsx)(c.ZM,{...a,activeProviders:Q(),hasActiveProviders:U,cloudEnabled:b,initialStatus:O.droid},e);case"openclaw":return(0,s.jsx)(c.yZ,{...a,activeProviders:Q(),hasActiveProviders:U,cloudEnabled:b,initialStatus:O.openclaw},e);default:return(0,s.jsx)(c.a7,{toolId:e,...a,activeProviders:Q(),cloudEnabled:b,tunnelEnabled:S},e)}})(e,t))})})}}},e=>{e.O(0,[2574,3862,123,5772,1321,5497,5507,8441,3794,7358],()=>e(e.s=70044)),_N_E=e.O()}]);
|
package/.next/standalone/.next/static/chunks/app/(dashboard)/dashboard/mitm/page-1c784308396f8f41.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[6607],{23879:(e,s,t)=>{"use strict";t.d(s,{default:()=>r});var a=t(95155),n=t(12115),i=t(3534),o=t(28777),l=t(52679),c=t(3176);function r(){let[e,s]=(0,n.useState)([]),[t,r]=(0,n.useState)([]),[d,u]=(0,n.useState)({}),[h,p]=(0,n.useState)(!1),[f,w]=(0,n.useState)(null),[v,S]=(0,n.useState)({running:!1,certExists:!1,dnsStatus:{},hasCachedPassword:!1}),[g,k]=(0,n.useState)(!1),x=async()=>{try{let e=await fetch("/api/providers");if(e.ok){let t=await e.json();s(t.connections||[])}}catch{}},y=async()=>{try{let e=await fetch("/api/keys");if(e.ok){let s=await e.json();r(s.keys||[])}}catch{}},j=async()=>{try{let e=await fetch("/api/models/alias");if(e.ok){let s=await e.json();u(s.aliases||{})}}catch{}},m=async()=>{try{let e=await fetch("/api/settings");if(e.ok){let s=await e.json();p(s.cloudEnabled||!1),k(!!s.tokenSwapEnabled)}}catch{}};(0,n.useEffect)(()=>{(async()=>{await Promise.all([x(),y(),j(),m()])})()},[]);let E=()=>e.filter(e=>!1!==e.isActive),b=Object.entries(i.wn);return(0,a.jsxs)("div",{className:"flex flex-col gap-6",children:[(0,a.jsx)(c.tA,{apiKeys:t,cloudEnabled:h,onStatusChange:S}),(0,a.jsx)("div",{className:"flex flex-col gap-2",children:b.map(([s,i])=>(0,a.jsxs)(n.Fragment,{children:[(0,a.jsx)(c.kn,{tool:i,isExpanded:f===s,onToggle:()=>w(f===s?null:s),serverRunning:v.running,dnsActive:v.dnsStatus?.[s]||!1,hasCachedPassword:v.hasCachedPassword||!1,apiKeys:t,activeProviders:E(),hasActiveProviders:E().some(e=>(0,o.KC)(e.provider).length>0||(0,l.mq)(e.provider)||(0,l.gb)(e.provider)),modelAliases:d,cloudEnabled:h,tokenSwapActive:i.supportsTokenSwap&&g,onDnsChange:e=>S(s=>({...s,dnsStatus:e.dnsStatus??s.dnsStatus}))}),i.supportsTokenSwap&&(0,a.jsx)(c.xm,{tool:i,connections:e,serverRunning:v.running,dnsActive:v.dnsStatus?.[s]||!1,onToggle:e=>k(e),onRefreshConnections:x})]},s))})]})}},60817:(e,s,t)=>{Promise.resolve().then(t.bind(t,23879))}},e=>{e.O(0,[2574,3862,123,5772,1321,5497,5507,8441,3794,7358],()=>e(e.s=60817)),_N_E=e.O()}]);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[3826],{40869:(e,t,r)=>{"use strict";r.d(t,{default:()=>x});var s=r(95155),a=r(12115),l=r(57250),n=r(57294);function i({quotas:e=[],compact:t=!1}){if(!e||0===e.length)return null;let r=t?"py-1.5 px-2":"py-2 px-3",a=t?"text-xs":"text-sm",l=t?"text-xs":"text-sm",o=t?"text-[10px] leading-tight":"text-xs";return(0,s.jsx)("div",{className:"overflow-x-auto",children:(0,s.jsxs)("table",{className:"w-full table-fixed text-left",children:[(0,s.jsxs)("colgroup",{children:[(0,s.jsx)("col",{className:"w-[30%]"})," ",(0,s.jsx)("col",{className:"w-[45%]"})," ",(0,s.jsx)("col",{className:"w-[25%]"})," "]}),(0,s.jsx)("tbody",{children:e.map((e,i)=>{let c=void 0!==e.remainingPercentage?Math.round(e.remainingPercentage):(0,n.$4)(e.used,e.total),d=c>70?{text:"text-green-600 dark:text-green-400",bg:"bg-green-500",bgLight:"bg-green-500/10",emoji:"\uD83D\uDFE2"}:c>=30?{text:"text-yellow-600 dark:text-yellow-400",bg:"bg-yellow-500",bgLight:"bg-yellow-500/10",emoji:"\uD83D\uDFE1"}:{text:"text-red-600 dark:text-red-400",bg:"bg-red-500",bgLight:"bg-red-500/10",emoji:"\uD83D\uDD34"},u=(0,n.mO)(e.resetAt),m=(0,n.sQ)(e.resetAt);return(0,s.jsxs)("tr",{className:"border-b border-black/5 dark:border-white/5 hover:bg-black/[0.02] dark:hover:bg-white/[0.02] transition-colors",children:[(0,s.jsx)("td",{className:r,children:(0,s.jsxs)("div",{className:"flex items-center gap-1.5 min-w-0",children:[(0,s.jsx)("span",{className:"text-[10px] shrink-0",children:d.emoji}),(0,s.jsx)("span",{className:`${a} font-medium text-text-primary truncate`,children:e.name})]})}),(0,s.jsx)("td",{className:r,children:(0,s.jsxs)("div",{className:t?"space-y-1":"space-y-1.5",children:[(0,s.jsx)("div",{className:`${t?"h-1":"h-1.5"} rounded-full overflow-hidden border ${d.bgLight} ${0===c?"border-black/10 dark:border-white/10":"border-transparent"}`,children:(0,s.jsx)("div",{className:`h-full transition-all duration-300 ${d.bg}`,style:{width:`${Math.min(c,100)}%`}})}),(0,s.jsxs)("div",{className:`flex items-center justify-between ${t?"text-[10px]":"text-xs"}`,children:[(0,s.jsxs)("span",{className:"text-text-muted",children:[e.used.toLocaleString()," / ",e.total>0?e.total.toLocaleString():"∞"]}),(0,s.jsxs)("span",{className:`font-medium ${d.text}`,children:[c,"%"]})]})]})}),(0,s.jsx)("td",{className:r,children:"-"!==u||m?(0,s.jsxs)("div",{className:"space-y-0.5",children:["-"!==u&&(0,s.jsxs)("div",{className:`${l} text-text-primary font-medium`,children:["in ",u]}),m&&(0,s.jsx)("div",{className:`${o} text-text-muted`,children:m})]}):(0,s.jsx)("div",{className:`${l} text-text-muted italic`,children:"N/A"})})]},i)})})]})})}var o=r(98542),c=r(84588),d=r(92542),u=r(35497),m=r(52679);function x(){let[e,t]=(0,a.useState)([]),[r,x]=(0,a.useState)({}),[h,p]=(0,a.useState)({}),[f,g]=(0,a.useState)({}),[b,v]=(0,a.useState)(!0),[y,j]=(0,a.useState)(null),[w,N]=(0,a.useState)(!1),[k,$]=(0,a.useState)(60),[E,C]=(0,a.useState)(!0),[q,A]=(0,a.useState)(null),[P,S]=(0,a.useState)(null),[D,L]=(0,a.useState)(!1),[O,T]=(0,a.useState)(null),[I,_]=(0,a.useState)([]),M=(0,a.useRef)(null),R=(0,a.useRef)(null),U=(0,a.useCallback)(async()=>{try{let e=await fetch("/api/providers/client");if(!e.ok)throw Error("Failed to fetch connections");let r=(await e.json()).connections||[];return t(r),r}catch(e){return console.error("Error fetching connections:",e),t([]),[]}},[]),z=(0,a.useCallback)(async(e,t)=>{p(t=>({...t,[e]:!0})),g(t=>({...t,[e]:null}));try{console.log(`[ProviderLimits] Fetching quota for ${t} (${e})`);let r=await fetch(`/api/usage/${e}`);if(!r.ok){let s=(await r.json().catch(()=>({}))).error||r.statusText;if(404===r.status)return void console.warn(`[ProviderLimits] Connection not found for ${t}, skipping`);if(401===r.status){console.warn(`[ProviderLimits] Auth error for ${t}:`,s),x(t=>({...t,[e]:{quotas:[],message:s}}));return}throw Error(`HTTP ${r.status}: ${s}`)}let s=await r.json();console.log(`[ProviderLimits] Got quota for ${t}:`,s);let a=(0,n.W_)(t,s);x(t=>({...t,[e]:{quotas:a,plan:s.plan||null,message:s.message||null,raw:s}}))}catch(r){console.error(`[ProviderLimits] Error fetching quota for ${t} (${e}):`,r),g(t=>({...t,[e]:r.message||"Failed to fetch quota"}))}finally{p(t=>({...t,[e]:!1}))}},[]),F=(0,a.useCallback)(async(e,t)=>{await z(e,t),j(new Date)},[z]),K=(0,a.useCallback)(async e=>{if(confirm("Delete this connection?")){A(e);try{(await fetch(`/api/providers/${e}`,{method:"DELETE"})).ok&&(t(t=>t.filter(t=>t.id!==e)),x(t=>{let r={...t};return delete r[e],r}),p(t=>{let r={...t};return delete r[e],r}),g(t=>{let r={...t};return delete r[e],r}))}catch(e){console.error("Error deleting connection:",e)}finally{A(null)}}},[]),J=(0,a.useCallback)(async(e,r)=>{S(e);try{(await fetch(`/api/providers/${e}`,{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({isActive:r})})).ok&&t(t=>t.map(t=>t.id===e?{...t,isActive:r}:t))}catch(e){console.error("Error updating connection status:",e)}finally{S(null)}},[]),Q=(0,a.useCallback)(async e=>{if(!O?.id)return;let t=O.id,r=O.provider;try{(await fetch(`/api/providers/${t}`,{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)})).ok&&(await U(),L(!1),T(null),m.wb.includes(r)&&await z(t,r))}catch(e){console.error("Error saving connection:",e)}},[O,U,z]);(0,a.useEffect)(()=>{let e=!1;return fetch("/api/proxy-pools?isActive=true",{cache:"no-store"}).then(e=>e.json()).then(t=>{!e&&t?.proxyPools&&_(t.proxyPools)}).catch(()=>{}),()=>{e=!0}},[]);let W=(0,a.useCallback)(async()=>{if(!w){N(!0),$(60);try{let e=(await U()).filter(e=>m.wb.includes(e.provider)&&"oauth"===e.authType);await Promise.all(e.map(e=>z(e.id,e.provider))),j(new Date)}catch(e){console.error("Error refreshing all providers:",e)}finally{N(!1)}}},[w,U,z]);(0,a.useEffect)(()=>{(async()=>{C(!0);let e=await U();C(!1);let t=e.filter(e=>m.wb.includes(e.provider)&&"oauth"===e.authType),r={};t.forEach(e=>{r[e.id]=!0}),p(r),await Promise.all(t.map(e=>z(e.id,e.provider))),j(new Date)})()},[]),(0,a.useEffect)(()=>{if(!b){M.current&&(clearInterval(M.current),M.current=null),R.current&&(clearInterval(R.current),R.current=null);return}return M.current=setInterval(()=>{W()},6e4),R.current=setInterval(()=>{$(e=>e<=1?60:e-1)},1e3),()=>{M.current&&clearInterval(M.current),R.current&&clearInterval(R.current)}},[b,W]),(0,a.useEffect)(()=>{let e=()=>{document.hidden?(M.current&&(clearInterval(M.current),M.current=null),R.current&&(clearInterval(R.current),R.current=null)):b&&(M.current=setInterval(W,6e4),R.current=setInterval(()=>{$(e=>e<=1?60:e-1)},1e3))};return document.addEventListener("visibilitychange",e),()=>{document.removeEventListener("visibilitychange",e)}},[b,W]);let G=(0,a.useCallback)(()=>{if(!y)return"Never";let e=Math.floor((new Date-y)/6e4),t=Math.floor(e/60),r=Math.floor(t/24);return r>0?`${r}d ago`:t>0?`${t}h ago`:e>0?`${e}m ago`:"Just now"},[y]),H=[...e.filter(e=>m.wb.includes(e.provider)&&"oauth"===e.authType)].sort((e,t)=>{let r=m.wb.indexOf(e.provider),s=m.wb.indexOf(t.provider);return r!==s?r-s:e.provider.localeCompare(t.provider)});return(H.length,Object.values(r).filter(e=>e?.quotas?.length>0).length,Object.values(r).reduce((e,t)=>t?.quotas?e+ +!!t.quotas.some(e=>30>(0,n.$4)(e.used,e.total)&&e.total>0):e,0),E||0!==H.length)?(0,s.jsxs)("div",{className:"space-y-6",children:[(0,s.jsxs)("div",{className:"flex items-center justify-between flex-wrap gap-4",children:[(0,s.jsxs)("div",{className:"flex items-center gap-3",children:[(0,s.jsx)("h2",{className:"text-xl font-semibold text-text-primary",children:"Provider Limits"}),(0,s.jsxs)("span",{className:"text-sm text-text-muted",children:["Last updated: ",G()]})]}),(0,s.jsxs)("div",{className:"flex items-center gap-2",children:[(0,s.jsxs)("button",{onClick:()=>v(e=>!e),className:"flex items-center gap-2 px-3 py-2 rounded-lg border border-black/10 dark:border-white/10 hover:bg-black/5 dark:hover:bg-white/5 transition-colors",title:b?"Disable auto-refresh":"Enable auto-refresh",children:[(0,s.jsx)("span",{className:`material-symbols-outlined text-[18px] ${b?"text-primary":"text-text-muted"}`,children:b?"toggle_on":"toggle_off"}),(0,s.jsx)("span",{className:"text-sm text-text-primary",children:"Auto-refresh"}),b&&(0,s.jsxs)("span",{className:"text-xs text-text-muted",children:["(",k,"s)"]})]}),(0,s.jsx)(d.default,{variant:"secondary",size:"md",icon:"refresh",onClick:W,disabled:w,loading:w,children:"Refresh All"})]})]}),(0,s.jsx)("div",{className:"grid grid-cols-1 md:grid-cols-2 gap-3",children:H.map(e=>{let t=r[e.id],a=h[e.id],n=f[e.id],d=!1===e.isActive,u=q===e.id||P===e.id;return(0,s.jsxs)(c.default,{padding:"none",className:`min-w-0 ${d?"opacity-60":""}`,children:[(0,s.jsx)("div",{className:"px-4 py-3 border-b border-black/10 dark:border-white/10",children:(0,s.jsxs)("div",{className:"flex items-center justify-between gap-2",children:[(0,s.jsxs)("div",{className:"flex items-center gap-2 min-w-0",children:[(0,s.jsx)("div",{className:"w-8 h-8 shrink-0 rounded-md flex items-center justify-center overflow-hidden",children:(0,s.jsx)(l.A,{src:`/providers/${e.provider}.png`,alt:e.provider,size:32,className:"object-contain",fallbackText:e.provider?.slice(0,2).toUpperCase()||"PR"})}),(0,s.jsxs)("div",{className:"min-w-0",children:[(0,s.jsx)("h3",{className:"text-sm font-semibold text-text-primary capitalize truncate",children:e.provider}),e.name&&(0,s.jsx)("p",{className:"text-xs text-text-muted truncate",children:e.name})]})]}),(0,s.jsxs)("div",{className:"flex items-center gap-1 shrink-0",children:[(0,s.jsx)("button",{type:"button",onClick:()=>F(e.id,e.provider),disabled:a||u,className:"p-1.5 rounded-lg hover:bg-black/5 dark:hover:bg-white/5 transition-colors disabled:opacity-50",title:"Refresh quota",children:(0,s.jsx)("span",{className:`material-symbols-outlined text-[18px] text-text-muted ${a?"animate-spin":""}`,children:"refresh"})}),(0,s.jsx)("button",{type:"button",onClick:()=>{T(e),L(!0)},disabled:u,className:"p-1.5 rounded-lg hover:bg-black/5 dark:hover:bg-white/5 text-text-muted hover:text-primary transition-colors disabled:opacity-50",title:"Edit connection",children:(0,s.jsx)("span",{className:"material-symbols-outlined text-[18px]",children:"edit"})}),(0,s.jsx)("button",{type:"button",onClick:()=>K(e.id),disabled:u,className:"p-1.5 rounded-lg hover:bg-red-500/10 text-red-500 transition-colors disabled:opacity-50",title:"Delete connection",children:(0,s.jsx)("span",{className:`material-symbols-outlined text-[18px] ${q===e.id?"animate-pulse":""}`,children:"delete"})}),(0,s.jsx)("div",{className:"inline-flex items-center pl-0.5",title:e.isActive??!0?"Disable connection":"Enable connection",children:(0,s.jsx)(o.default,{size:"sm",checked:e.isActive??!0,disabled:u,onChange:t=>J(e.id,t)})})]})]})}),(0,s.jsx)("div",{className:"px-3 py-3",children:a?(0,s.jsx)("div",{className:"text-center py-5 text-text-muted",children:(0,s.jsx)("span",{className:"material-symbols-outlined text-[28px] animate-spin",children:"progress_activity"})}):n?(0,s.jsxs)("div",{className:"text-center py-5",children:[(0,s.jsx)("span",{className:"material-symbols-outlined text-[28px] text-red-500",children:"error"}),(0,s.jsx)("p",{className:"mt-1.5 text-xs text-text-muted",children:n})]}):t?.message?(0,s.jsx)("div",{className:"text-center py-5",children:(0,s.jsx)("p",{className:"text-xs text-text-muted",children:t.message})}):(0,s.jsx)(i,{quotas:t?.quotas,compact:!0})})]},e.id)})}),(0,s.jsx)(u.wI,{isOpen:D,connection:O,proxyPools:I,onSave:Q,onClose:()=>{L(!1),T(null)}})]}):(0,s.jsx)(c.default,{padding:"lg",children:(0,s.jsxs)("div",{className:"text-center py-12",children:[(0,s.jsx)("span",{className:"material-symbols-outlined text-[64px] text-text-muted opacity-20",children:"cloud_off"}),(0,s.jsx)("h3",{className:"mt-4 text-lg font-semibold text-text-primary",children:"No Providers Connected"}),(0,s.jsx)("p",{className:"mt-2 text-sm text-text-muted max-w-md mx-auto",children:"Connect to providers with OAuth to track your API quota limits and usage."})]})})}},57294:(e,t,r)=>{"use strict";r.d(t,{$4:()=>n,W_:()=>i,mO:()=>a,sQ:()=>l});var s=r(45564);function a(e){if(!e)return"-";try{let t="string"==typeof e?new Date(e):e,r=new Date,s=t-r;if(s<=0)return"-";let a=Math.ceil(s/6e4);if(a<60)return`${a}m`;let l=Math.floor(a/60),n=a%60;if(l<24)return`${l}h ${n}m`;let i=Math.floor(l/24);return`${i}d ${l%24}h ${n}m`}catch(e){return"-"}}function l(e){if(!e)return null;try{let t="string"==typeof e?new Date(e):e,r=new Date,s=new Date(r.getFullYear(),r.getMonth(),r.getDate()),a=new Date(s);a.setDate(a.getDate()+1);let l=new Date(a);l.setDate(l.getDate()+1);let n="";n=t>=s&&t<a?"Today":t>=a&&t<l?"Tomorrow":t.toLocaleDateString("en-US",{month:"short",day:"numeric"});let i=t.toLocaleTimeString("en-US",{hour:"numeric",minute:"2-digit",hour12:!0});return`${n}, ${i}`}catch{return null}}function n(e,t){return t&&0!==t?!e||e<0?100:e>=t?0:Math.round((t-e)/t*100):0}function i(e,t){if(!t||"object"!=typeof t)return[];let r=[];try{switch(e.toLowerCase()){case"github":default:t.quotas&&Object.entries(t.quotas).forEach(([e,t])=>{r.push({name:e,used:t.used||0,total:t.total||0,resetAt:t.resetAt||null})});break;case"antigravity":t.quotas&&Object.entries(t.quotas).forEach(([e,t])=>{r.push({name:t.displayName||e,modelKey:e,used:t.used||0,total:t.total||0,resetAt:t.resetAt||null,remainingPercentage:t.remainingPercentage})});break;case"codex":t.quotas&&Object.entries(t.quotas).forEach(([e,t])=>{r.push({name:e,used:t.used||0,total:t.total||0,resetAt:t.resetAt||null})});break;case"kiro":t.quotas&&Object.entries(t.quotas).forEach(([e,t])=>{r.push({name:e,used:t.used||0,total:t.total||0,resetAt:t.resetAt||null})});break;case"claude":t.message?r.push({name:"error",used:0,total:0,resetAt:null,message:t.message}):t.quotas&&Object.entries(t.quotas).forEach(([e,t])=>{r.push({name:e,used:t.used||0,total:t.total||0,resetAt:t.resetAt||null})})}}catch(t){return console.error(`Error parsing quota data for ${e}:`,t),[]}let a=(0,s.KC)(e);if(a.length>0){let e=new Map(a.map((e,t)=>[e.id,t]));r.sort((t,r)=>{let s=t.modelKey||t.name,a=r.modelKey||r.name;return(e.get(s)??999)-(e.get(a)??999)})}return r}},68818:(e,t,r)=>{Promise.resolve().then(r.bind(r,40869)),Promise.resolve().then(r.bind(r,25086))}},e=>{e.O(0,[2574,3862,123,1321,5497,8441,3794,7358],()=>e(e.s=68818)),_N_E=e.O()}]);
|
|
@@ -4,11 +4,14 @@ const path = require("path");
|
|
|
4
4
|
const dns = require("dns");
|
|
5
5
|
const { promisify } = require("util");
|
|
6
6
|
const { log, err } = require("./logger");
|
|
7
|
-
const { TARGET_HOSTS, URL_PATTERNS, getToolForHost } = require("./config");
|
|
7
|
+
const { TARGET_HOSTS, URL_PATTERNS, getToolForHost, isTargetHost } = require("./config");
|
|
8
8
|
const { DATA_DIR, MITM_DIR } = require("./paths");
|
|
9
9
|
const { isTokenSwapEnabled, getAllActiveConnections, triggerRefreshIfNeeded,
|
|
10
|
-
forceRefreshConnection, setCooldown, setAuthCooldown, setModelCooldown,
|
|
11
|
-
|
|
10
|
+
forceRefreshConnection, setCooldown, setAuthCooldown, setModelCooldown,
|
|
11
|
+
recordStrike, recordModelStrike, clearStrikes, clearModelStrikes,
|
|
12
|
+
getTokenSwapStrategy,
|
|
13
|
+
parseQuotaCooldown, shouldImmediateQuotaCooldown,
|
|
14
|
+
markAccountUsed, getConnectionLabel, getTokenSwapAvailabilitySummary } = require("./tokenPool");
|
|
12
15
|
const { getCertForDomain } = require("./cert/generate");
|
|
13
16
|
const { buildInputOnlyRequestDetail, createTokenSwapUsageObserver, generateDetailId } = require("./usageTracker");
|
|
14
17
|
|
|
@@ -184,6 +187,7 @@ async function passthrough(req, res, bodyBuffer, onResponse) {
|
|
|
184
187
|
async function tokenSwapForward(req, res, bodyBuffer, connections, model, strategy, provider, requestStartTime) {
|
|
185
188
|
const targetHost = (req.headers.host || TARGET_HOSTS[0]).split(":")[0];
|
|
186
189
|
const targetIP = await resolveTargetIP(targetHost);
|
|
190
|
+
let lastRetryResponse = null;
|
|
187
191
|
|
|
188
192
|
for (let i = 0; i < connections.length; i++) {
|
|
189
193
|
const originalConn = connections[i];
|
|
@@ -234,12 +238,28 @@ async function tokenSwapForward(req, res, bodyBuffer, connections, model, strate
|
|
|
234
238
|
if (result.retry && result.retryType === "quota") {
|
|
235
239
|
const cooldownMs = parseQuotaCooldown(result.body);
|
|
236
240
|
const cdLabel = cooldownMs ? ` cooldown=${Math.ceil(cooldownMs / 60000)}m` : "";
|
|
241
|
+
const immediateCooldown = shouldImmediateQuotaCooldown(result.statusCode, result.body);
|
|
242
|
+
lastRetryResponse = {
|
|
243
|
+
statusCode: result.statusCode,
|
|
244
|
+
headers: result.headers,
|
|
245
|
+
body: result.body,
|
|
246
|
+
};
|
|
237
247
|
if (strategy === "sticky" && model) {
|
|
238
|
-
|
|
239
|
-
|
|
248
|
+
if (immediateCooldown) {
|
|
249
|
+
setModelCooldown(conn.id, model, cooldownMs);
|
|
250
|
+
log(`⚠️ [token-swap] "${label}" → ${result.statusCode} model=${model} COOLDOWN${cdLabel}, trying next...`);
|
|
251
|
+
} else {
|
|
252
|
+
const locked = recordModelStrike(conn.id, model, cooldownMs);
|
|
253
|
+
log(`⚠️ [token-swap] "${label}" → ${result.statusCode} model=${model}${locked ? " LOCKED" : " strike"}${cdLabel}, trying next...`);
|
|
254
|
+
}
|
|
240
255
|
} else {
|
|
241
|
-
|
|
242
|
-
|
|
256
|
+
if (immediateCooldown) {
|
|
257
|
+
setCooldown(conn.id, cooldownMs);
|
|
258
|
+
log(`⚠️ [token-swap] "${label}" → ${result.statusCode} COOLDOWN${cdLabel}, trying next...`);
|
|
259
|
+
} else {
|
|
260
|
+
const locked = recordStrike(conn.id, cooldownMs);
|
|
261
|
+
log(`⚠️ [token-swap] "${label}" → ${result.statusCode}${locked ? " LOCKED" : " strike"}${cdLabel}, trying next...`);
|
|
262
|
+
}
|
|
243
263
|
}
|
|
244
264
|
break;
|
|
245
265
|
}
|
|
@@ -264,6 +284,11 @@ async function tokenSwapForward(req, res, bodyBuffer, connections, model, strate
|
|
|
264
284
|
}
|
|
265
285
|
|
|
266
286
|
setAuthCooldown(conn.id);
|
|
287
|
+
lastRetryResponse = {
|
|
288
|
+
statusCode: result.statusCode,
|
|
289
|
+
headers: result.headers,
|
|
290
|
+
body: result.body,
|
|
291
|
+
};
|
|
267
292
|
log(`⚠️ [token-swap] "${label}" → 401 invalid_token, trying next...`);
|
|
268
293
|
break;
|
|
269
294
|
}
|
|
@@ -273,6 +298,9 @@ async function tokenSwapForward(req, res, bodyBuffer, connections, model, strate
|
|
|
273
298
|
const successModelTag = model ? ` model=${model}` : "";
|
|
274
299
|
const successStrategyTag = strategy === "sticky" ? ` sticky(use #${newCount})` : ` rr`;
|
|
275
300
|
log(`✅ [token-swap] "${label}" → ${statusCode}${successModelTag}${successStrategyTag}`);
|
|
301
|
+
// Clear strikes on success — previous 429s were likely false positives
|
|
302
|
+
clearStrikes(conn.id);
|
|
303
|
+
if (model) clearModelStrikes(conn.id, model);
|
|
276
304
|
markAccountUsed(conn.id);
|
|
277
305
|
res.writeHead(statusCode, result.response.headers);
|
|
278
306
|
|
|
@@ -328,7 +356,14 @@ async function tokenSwapForward(req, res, bodyBuffer, connections, model, strate
|
|
|
328
356
|
}
|
|
329
357
|
}
|
|
330
358
|
|
|
331
|
-
|
|
359
|
+
if (lastRetryResponse) {
|
|
360
|
+
log(`⚠️ [token-swap] exhausted ${connections.length} account(s), returning last retryable ${lastRetryResponse.statusCode}`);
|
|
361
|
+
res.writeHead(lastRetryResponse.statusCode, lastRetryResponse.headers);
|
|
362
|
+
res.end(lastRetryResponse.body);
|
|
363
|
+
return true;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
// All accounts exhausted with no retryable upstream response captured
|
|
332
367
|
return false;
|
|
333
368
|
}
|
|
334
369
|
|
|
@@ -457,6 +492,7 @@ server.on("error", (e) => {
|
|
|
457
492
|
});
|
|
458
493
|
|
|
459
494
|
const shutdown = () => server.close(() => process.exit(0));
|
|
495
|
+
process.setMaxListeners(0);
|
|
460
496
|
process.on("SIGTERM", shutdown);
|
|
461
497
|
process.on("SIGINT", shutdown);
|
|
462
498
|
if (process.platform === "win32") process.on("SIGBREAK", shutdown);
|
|
@@ -13,20 +13,62 @@ const { log } = require("./logger");
|
|
|
13
13
|
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
|
-
const DEFAULT_COOLDOWN_MS =
|
|
16
|
+
const DEFAULT_COOLDOWN_MS = 2 * 60 * 1000;
|
|
17
17
|
const DEFAULT_AUTH_COOLDOWN_MS = 10 * 60 * 1000;
|
|
18
|
+
const DEFAULT_STRIKE_THRESHOLD = 3; // consecutive 429s before hard cooldown
|
|
19
|
+
const CAPACITY_EXHAUSTED_COOLDOWN_MS = 60 * 1000;
|
|
18
20
|
|
|
19
21
|
// ── In-memory state ──────────────────────────────────────────
|
|
20
22
|
const cooldownMap = {}; // { [connectionId]: expiresTimestamp } quota/general cooldown
|
|
21
23
|
const authCooldownMap = {}; // { [connectionId]: expiresTimestamp } invalid_token/auth cooldown
|
|
22
24
|
const modelCooldownMap = {}; // { [connectionId]: { [model]: expiresTimestamp } }
|
|
25
|
+
const strikeMap = {}; // { [connectionId]: consecutiveHitCount }
|
|
26
|
+
const modelStrikeMap = {}; // { [connectionId]: { [model]: consecutiveHitCount } }
|
|
23
27
|
const rrState = {}; // { [provider]: roundRobinIndex }
|
|
24
28
|
|
|
25
|
-
// ──
|
|
29
|
+
// ── Strike + cooldown management ─────────────────────────────
|
|
30
|
+
// Upstream often returns false-positive 429s. Instead of locking
|
|
31
|
+
// an account on the first hit, we count consecutive strikes.
|
|
32
|
+
// Hard cooldown only triggers after STRIKE_THRESHOLD consecutive 429s.
|
|
33
|
+
|
|
34
|
+
function getStrikeThreshold() {
|
|
35
|
+
try {
|
|
36
|
+
if (!fs.existsSync(DB_FILE)) return DEFAULT_STRIKE_THRESHOLD;
|
|
37
|
+
const db = JSON.parse(fs.readFileSync(DB_FILE, "utf-8"));
|
|
38
|
+
return db.settings?.cooldownStrikeThreshold || DEFAULT_STRIKE_THRESHOLD;
|
|
39
|
+
} catch { return DEFAULT_STRIKE_THRESHOLD; }
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Record a 429 strike for an account. Returns true if the account
|
|
44
|
+
* just entered hard cooldown (threshold reached), false if it's
|
|
45
|
+
* still within tolerance.
|
|
46
|
+
*/
|
|
47
|
+
function recordStrike(connId, durationMs) {
|
|
48
|
+
const count = (strikeMap[connId] || 0) + 1;
|
|
49
|
+
strikeMap[connId] = count;
|
|
50
|
+
const threshold = getStrikeThreshold();
|
|
51
|
+
|
|
52
|
+
if (count >= threshold) {
|
|
53
|
+
const ms = durationMs || DEFAULT_COOLDOWN_MS;
|
|
54
|
+
cooldownMap[connId] = Date.now() + ms;
|
|
55
|
+
delete strikeMap[connId];
|
|
56
|
+
log(`⏸ [token-pool] cooldown: ${connId.slice(0, 8)}… for ${Math.ceil(ms / 60000)}m (after ${count} strikes)`);
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
log(`⚡ [token-pool] strike ${count}/${threshold}: ${connId.slice(0, 8)}… (not locked yet)`);
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function clearStrikes(connId) {
|
|
65
|
+
delete strikeMap[connId];
|
|
66
|
+
}
|
|
26
67
|
|
|
27
68
|
function setCooldown(connId, durationMs) {
|
|
28
69
|
const ms = durationMs || DEFAULT_COOLDOWN_MS;
|
|
29
70
|
cooldownMap[connId] = Date.now() + ms;
|
|
71
|
+
delete strikeMap[connId];
|
|
30
72
|
log(`⏸ [token-pool] cooldown: ${connId.slice(0, 8)}… for ${Math.ceil(ms / 60000)}m`);
|
|
31
73
|
}
|
|
32
74
|
|
|
@@ -59,15 +101,45 @@ function isInCooldown(connId) {
|
|
|
59
101
|
return !!getCooldownState(connId);
|
|
60
102
|
}
|
|
61
103
|
|
|
62
|
-
// ── Per-model cooldown management
|
|
104
|
+
// ── Per-model strike + cooldown management ───────────────────
|
|
63
105
|
// Tracks which account+model combinations are quota-exhausted.
|
|
64
|
-
//
|
|
106
|
+
// Same strike-before-cooldown logic as account-level.
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Record a 429 strike for a specific account+model. Returns true
|
|
110
|
+
* if the model just entered hard cooldown.
|
|
111
|
+
*/
|
|
112
|
+
function recordModelStrike(connId, model, durationMs) {
|
|
113
|
+
const key = model || "__unknown__";
|
|
114
|
+
if (!modelStrikeMap[connId]) modelStrikeMap[connId] = {};
|
|
115
|
+
const count = (modelStrikeMap[connId][key] || 0) + 1;
|
|
116
|
+
modelStrikeMap[connId][key] = count;
|
|
117
|
+
const threshold = getStrikeThreshold();
|
|
118
|
+
|
|
119
|
+
if (count >= threshold) {
|
|
120
|
+
const ms = durationMs || DEFAULT_COOLDOWN_MS;
|
|
121
|
+
if (!modelCooldownMap[connId]) modelCooldownMap[connId] = {};
|
|
122
|
+
modelCooldownMap[connId][key] = Date.now() + ms;
|
|
123
|
+
delete modelStrikeMap[connId][key];
|
|
124
|
+
log(`⏸ [token-pool] model-cooldown: ${connId.slice(0, 8)}… model="${key}" for ${Math.ceil(ms / 60000)}m (after ${count} strikes)`);
|
|
125
|
+
return true;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
log(`⚡ [token-pool] model-strike ${count}/${threshold}: ${connId.slice(0, 8)}… model="${key}" (not locked yet)`);
|
|
129
|
+
return false;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function clearModelStrikes(connId, model) {
|
|
133
|
+
const key = model || "__unknown__";
|
|
134
|
+
if (modelStrikeMap[connId]?.[key]) delete modelStrikeMap[connId][key];
|
|
135
|
+
}
|
|
65
136
|
|
|
66
137
|
function setModelCooldown(connId, model, durationMs) {
|
|
67
138
|
const ms = durationMs || DEFAULT_COOLDOWN_MS;
|
|
68
139
|
const key = model || "__unknown__";
|
|
69
140
|
if (!modelCooldownMap[connId]) modelCooldownMap[connId] = {};
|
|
70
141
|
modelCooldownMap[connId][key] = Date.now() + ms;
|
|
142
|
+
if (modelStrikeMap[connId]?.[key]) delete modelStrikeMap[connId][key];
|
|
71
143
|
log(`⏸ [token-pool] model-cooldown: ${connId.slice(0, 8)}… model="${key}" for ${Math.ceil(ms / 60000)}m`);
|
|
72
144
|
}
|
|
73
145
|
|
|
@@ -84,6 +156,17 @@ function isModelExhausted(connId, model) {
|
|
|
84
156
|
return true;
|
|
85
157
|
}
|
|
86
158
|
|
|
159
|
+
function isStoredModelQuotaExhausted(connection, model) {
|
|
160
|
+
if (!connection || !model) return false;
|
|
161
|
+
const status = connection.modelQuotaStatus;
|
|
162
|
+
if (!status || typeof status !== "object") return false;
|
|
163
|
+
|
|
164
|
+
const modelStatus = status[model];
|
|
165
|
+
if (!modelStatus || typeof modelStatus !== "object") return false;
|
|
166
|
+
|
|
167
|
+
return modelStatus.exhausted === true || modelStatus.remainingPercentage === 0;
|
|
168
|
+
}
|
|
169
|
+
|
|
87
170
|
// ── Strategy reader ───────────────────────────────────────────
|
|
88
171
|
|
|
89
172
|
function getTokenSwapStrategy() {
|
|
@@ -97,17 +180,44 @@ function getTokenSwapStrategy() {
|
|
|
97
180
|
// ── Quota cooldown parser ────────────────────────────────────
|
|
98
181
|
// Antigravity error format: "Your quota will reset after 2h7m23s"
|
|
99
182
|
function parseQuotaCooldown(errorBody) {
|
|
183
|
+
const raw = String(errorBody || "");
|
|
184
|
+
|
|
100
185
|
try {
|
|
101
|
-
const json = JSON.parse(
|
|
186
|
+
const json = JSON.parse(raw);
|
|
102
187
|
const msg = json?.error?.message || json?.message || "";
|
|
188
|
+
const reason = String(
|
|
189
|
+
json?.error?.details?.[0]?.reason ||
|
|
190
|
+
json?.error?.reason ||
|
|
191
|
+
json?.reason ||
|
|
192
|
+
""
|
|
193
|
+
).toUpperCase();
|
|
103
194
|
const match = msg.match(/reset after (\d+h)?(\d+m)?(\d+s)?/i);
|
|
104
|
-
if (
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
195
|
+
if (match) {
|
|
196
|
+
let ms = 0;
|
|
197
|
+
if (match[1]) ms += parseInt(match[1]) * 3600000;
|
|
198
|
+
if (match[2]) ms += parseInt(match[2]) * 60000;
|
|
199
|
+
if (match[3]) ms += parseInt(match[3]) * 1000;
|
|
200
|
+
return ms > 0 ? ms : null;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (
|
|
204
|
+
reason === "MODEL_CAPACITY_EXHAUSTED" ||
|
|
205
|
+
/no capacity available for model|model capacity exhausted|capacity exhausted/i.test(msg)
|
|
206
|
+
) {
|
|
207
|
+
return CAPACITY_EXHAUSTED_COOLDOWN_MS;
|
|
208
|
+
}
|
|
209
|
+
} catch {
|
|
210
|
+
if (/no capacity available for model|model capacity exhausted|capacity exhausted/i.test(raw)) {
|
|
211
|
+
return CAPACITY_EXHAUSTED_COOLDOWN_MS;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
return null;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function shouldImmediateQuotaCooldown(statusCode, errorBody) {
|
|
219
|
+
if (statusCode !== 503) return false;
|
|
220
|
+
return parseQuotaCooldown(errorBody) != null;
|
|
111
221
|
}
|
|
112
222
|
|
|
113
223
|
// ── Read connections from db.json (sync) ─────────────────────
|
|
@@ -183,6 +293,11 @@ function getTokenSwapAvailabilitySummary(provider, model) {
|
|
|
183
293
|
continue;
|
|
184
294
|
}
|
|
185
295
|
|
|
296
|
+
if (model && isStoredModelQuotaExhausted(connection, model)) {
|
|
297
|
+
reasons.modelCooldown += 1;
|
|
298
|
+
continue;
|
|
299
|
+
}
|
|
300
|
+
|
|
186
301
|
if (strategy === "sticky" && model && isModelExhausted(connection.id, model)) {
|
|
187
302
|
reasons.modelCooldown += 1;
|
|
188
303
|
continue;
|
|
@@ -298,16 +413,24 @@ function getAllActiveConnections(provider, model) {
|
|
|
298
413
|
if (connections.length <= 1) return connections;
|
|
299
414
|
|
|
300
415
|
const strategy = getTokenSwapStrategy();
|
|
416
|
+
const hardAvailable = model
|
|
417
|
+
? connections.filter(c => !isStoredModelQuotaExhausted(c, model))
|
|
418
|
+
: connections;
|
|
419
|
+
|
|
420
|
+
if (model && hardAvailable.length === 0) {
|
|
421
|
+
return [];
|
|
422
|
+
}
|
|
301
423
|
|
|
302
424
|
if (strategy === "sticky") {
|
|
303
425
|
// Sticky strategy: filter out accounts exhausted for this specific model,
|
|
304
426
|
// then sort most-recently-used first so the same account sticks across requests.
|
|
305
427
|
const available = model
|
|
306
|
-
?
|
|
307
|
-
:
|
|
428
|
+
? hardAvailable.filter(c => !isModelExhausted(c.id, model))
|
|
429
|
+
: hardAvailable;
|
|
308
430
|
|
|
309
|
-
//
|
|
310
|
-
|
|
431
|
+
// Runtime model cooldowns are temporary and may be false positives,
|
|
432
|
+
// so sticky mode can still fall back to hard-eligible accounts.
|
|
433
|
+
const pool = available.length > 0 ? available : hardAvailable;
|
|
311
434
|
|
|
312
435
|
// Most-recently-used first (sticky within session)
|
|
313
436
|
return [...pool].sort((a, b) => {
|
|
@@ -318,11 +441,13 @@ function getAllActiveConnections(provider, model) {
|
|
|
318
441
|
});
|
|
319
442
|
}
|
|
320
443
|
|
|
444
|
+
const roundRobinConnections = hardAvailable;
|
|
445
|
+
|
|
321
446
|
// Round-robin strategy: sticky round-robin matching the main routing engine
|
|
322
447
|
// (src/sse/services/auth.js). Least-recently-used account starts each request.
|
|
323
448
|
const stickyLimit = getStickyLimit(provider);
|
|
324
449
|
|
|
325
|
-
const byRecency = [...
|
|
450
|
+
const byRecency = [...roundRobinConnections].sort((a, b) => {
|
|
326
451
|
if (!a.lastUsedAt && !b.lastUsedAt) return (a.priority || 999) - (b.priority || 999);
|
|
327
452
|
if (!a.lastUsedAt) return 1;
|
|
328
453
|
if (!b.lastUsedAt) return -1;
|
|
@@ -333,7 +458,7 @@ function getAllActiveConnections(provider, model) {
|
|
|
333
458
|
|
|
334
459
|
if (current?.lastUsedAt && currentCount < stickyLimit) {
|
|
335
460
|
// Keep current account first, rest sorted oldest-first for fallback
|
|
336
|
-
const rest =
|
|
461
|
+
const rest = roundRobinConnections.filter(c => c.id !== current.id).sort((a, b) => {
|
|
337
462
|
if (!a.lastUsedAt && !b.lastUsedAt) return (a.priority || 999) - (b.priority || 999);
|
|
338
463
|
if (!a.lastUsedAt) return -1;
|
|
339
464
|
if (!b.lastUsedAt) return 1;
|
|
@@ -343,7 +468,7 @@ function getAllActiveConnections(provider, model) {
|
|
|
343
468
|
}
|
|
344
469
|
|
|
345
470
|
// Rotate: least-recently-used first
|
|
346
|
-
return [...
|
|
471
|
+
return [...roundRobinConnections].sort((a, b) => {
|
|
347
472
|
if (!a.lastUsedAt && !b.lastUsedAt) return (a.priority || 999) - (b.priority || 999);
|
|
348
473
|
if (!a.lastUsedAt) return -1;
|
|
349
474
|
if (!b.lastUsedAt) return 1;
|
|
@@ -470,9 +595,14 @@ module.exports = {
|
|
|
470
595
|
setCooldown,
|
|
471
596
|
setAuthCooldown,
|
|
472
597
|
setModelCooldown,
|
|
598
|
+
recordStrike,
|
|
599
|
+
recordModelStrike,
|
|
600
|
+
clearStrikes,
|
|
601
|
+
clearModelStrikes,
|
|
473
602
|
isModelExhausted,
|
|
474
603
|
getTokenSwapStrategy,
|
|
475
604
|
parseQuotaCooldown,
|
|
605
|
+
shouldImmediateQuotaCooldown,
|
|
476
606
|
markAccountUsed,
|
|
477
607
|
getConnectionLabel,
|
|
478
608
|
maskEmail,
|
|
@@ -150,6 +150,63 @@ function extractContentLength(chunk) {
|
|
|
150
150
|
return total;
|
|
151
151
|
}
|
|
152
152
|
|
|
153
|
+
function extractContentText(chunk) {
|
|
154
|
+
if (!chunk || typeof chunk !== "object") return { content: "", thinking: "" };
|
|
155
|
+
|
|
156
|
+
let content = "";
|
|
157
|
+
let thinking = "";
|
|
158
|
+
|
|
159
|
+
// Anthropic streaming
|
|
160
|
+
if (typeof chunk.delta?.text === "string") content += chunk.delta.text;
|
|
161
|
+
if (typeof chunk.delta?.thinking === "string") thinking += chunk.delta.thinking;
|
|
162
|
+
|
|
163
|
+
// OpenAI streaming
|
|
164
|
+
if (typeof chunk.choices?.[0]?.delta?.content === "string") content += chunk.choices[0].delta.content;
|
|
165
|
+
if (typeof chunk.choices?.[0]?.delta?.reasoning_content === "string") thinking += chunk.choices[0].delta.reasoning_content;
|
|
166
|
+
|
|
167
|
+
// OpenAI non-streaming
|
|
168
|
+
if (chunk.choices?.[0]?.message) {
|
|
169
|
+
const msg = chunk.choices[0].message;
|
|
170
|
+
if (typeof msg.content === "string") content += msg.content;
|
|
171
|
+
if (typeof msg.reasoning_content === "string") thinking += msg.reasoning_content;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Anthropic content blocks
|
|
175
|
+
if (Array.isArray(chunk.content)) {
|
|
176
|
+
for (const item of chunk.content) {
|
|
177
|
+
if (typeof item?.text === "string" && item?.type !== "thinking") content += item.text;
|
|
178
|
+
if (item?.type === "thinking" && typeof item?.thinking === "string") thinking += item.thinking;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// OpenAI Responses API
|
|
183
|
+
if (chunk.response?.output_text && typeof chunk.response.output_text === "string") content += chunk.response.output_text;
|
|
184
|
+
if (chunk.response?.output && Array.isArray(chunk.response.output)) {
|
|
185
|
+
for (const item of chunk.response.output) {
|
|
186
|
+
if (typeof item?.content === "string") content += item.content;
|
|
187
|
+
if (Array.isArray(item?.content)) {
|
|
188
|
+
for (const part of item.content) {
|
|
189
|
+
if (typeof part?.text === "string") content += part.text;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Gemini
|
|
196
|
+
const geminiParts = chunk.candidates?.[0]?.content?.parts || chunk.response?.candidates?.[0]?.content?.parts;
|
|
197
|
+
if (Array.isArray(geminiParts)) {
|
|
198
|
+
for (const part of geminiParts) {
|
|
199
|
+
if (part?.thought === true && typeof part?.text === "string") {
|
|
200
|
+
thinking += part.text;
|
|
201
|
+
} else if (typeof part?.text === "string") {
|
|
202
|
+
content += part.text;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
return { content, thinking };
|
|
208
|
+
}
|
|
209
|
+
|
|
153
210
|
function estimateInputTokens(body) {
|
|
154
211
|
if (!body || typeof body !== "object") return 0;
|
|
155
212
|
try {
|
|
@@ -412,11 +469,23 @@ function createTokenSwapUsageObserver({ provider, model, connectionId, accountLa
|
|
|
412
469
|
let contentLength = 0;
|
|
413
470
|
let usage = null;
|
|
414
471
|
let finished = false;
|
|
472
|
+
let responseContent = "";
|
|
473
|
+
let thinkingContent = "";
|
|
474
|
+
let contentCapped = false;
|
|
475
|
+
const MAX_CAPTURE_BYTES = 512 * 1024;
|
|
415
476
|
|
|
416
477
|
const processParsedChunk = (parsed) => {
|
|
417
478
|
const extracted = extractUsage(parsed);
|
|
418
479
|
if (extracted) usage = extracted;
|
|
419
480
|
contentLength += extractContentLength(parsed);
|
|
481
|
+
if (!contentCapped) {
|
|
482
|
+
const text = extractContentText(parsed);
|
|
483
|
+
responseContent += text.content;
|
|
484
|
+
thinkingContent += text.thinking;
|
|
485
|
+
if (responseContent.length + thinkingContent.length > MAX_CAPTURE_BYTES) {
|
|
486
|
+
contentCapped = true;
|
|
487
|
+
}
|
|
488
|
+
}
|
|
420
489
|
};
|
|
421
490
|
|
|
422
491
|
const processSseLine = (line) => {
|
|
@@ -504,10 +573,17 @@ function createTokenSwapUsageObserver({ provider, model, connectionId, accountLa
|
|
|
504
573
|
try {
|
|
505
574
|
await persistRequestDetail({
|
|
506
575
|
...detailRecord,
|
|
576
|
+
status: "completed",
|
|
507
577
|
tokens: usage,
|
|
508
578
|
latency: {
|
|
509
579
|
ttft: 0,
|
|
510
580
|
total: requestStartTime ? Date.now() - requestStartTime : 0
|
|
581
|
+
},
|
|
582
|
+
providerResponse: "[SSE stream — content captured in response field]",
|
|
583
|
+
response: {
|
|
584
|
+
content: responseContent || null,
|
|
585
|
+
thinking: thinkingContent || null,
|
|
586
|
+
type: contentCapped ? "token_swap_capped" : "token_swap"
|
|
511
587
|
}
|
|
512
588
|
});
|
|
513
589
|
} catch (error) {
|
|
@@ -4,11 +4,14 @@ const path = require("path");
|
|
|
4
4
|
const dns = require("dns");
|
|
5
5
|
const { promisify } = require("util");
|
|
6
6
|
const { log, err } = require("./logger");
|
|
7
|
-
const { TARGET_HOSTS, URL_PATTERNS, getToolForHost } = require("./config");
|
|
7
|
+
const { TARGET_HOSTS, URL_PATTERNS, getToolForHost, isTargetHost } = require("./config");
|
|
8
8
|
const { DATA_DIR, MITM_DIR } = require("./paths");
|
|
9
9
|
const { isTokenSwapEnabled, getAllActiveConnections, triggerRefreshIfNeeded,
|
|
10
|
-
forceRefreshConnection, setCooldown, setAuthCooldown, setModelCooldown,
|
|
11
|
-
|
|
10
|
+
forceRefreshConnection, setCooldown, setAuthCooldown, setModelCooldown,
|
|
11
|
+
recordStrike, recordModelStrike, clearStrikes, clearModelStrikes,
|
|
12
|
+
getTokenSwapStrategy,
|
|
13
|
+
parseQuotaCooldown, shouldImmediateQuotaCooldown,
|
|
14
|
+
markAccountUsed, getConnectionLabel, getTokenSwapAvailabilitySummary } = require("./tokenPool");
|
|
12
15
|
const { getCertForDomain } = require("./cert/generate");
|
|
13
16
|
const { buildInputOnlyRequestDetail, createTokenSwapUsageObserver, generateDetailId } = require("./usageTracker");
|
|
14
17
|
|
|
@@ -184,6 +187,7 @@ async function passthrough(req, res, bodyBuffer, onResponse) {
|
|
|
184
187
|
async function tokenSwapForward(req, res, bodyBuffer, connections, model, strategy, provider, requestStartTime) {
|
|
185
188
|
const targetHost = (req.headers.host || TARGET_HOSTS[0]).split(":")[0];
|
|
186
189
|
const targetIP = await resolveTargetIP(targetHost);
|
|
190
|
+
let lastRetryResponse = null;
|
|
187
191
|
|
|
188
192
|
for (let i = 0; i < connections.length; i++) {
|
|
189
193
|
const originalConn = connections[i];
|
|
@@ -234,12 +238,28 @@ async function tokenSwapForward(req, res, bodyBuffer, connections, model, strate
|
|
|
234
238
|
if (result.retry && result.retryType === "quota") {
|
|
235
239
|
const cooldownMs = parseQuotaCooldown(result.body);
|
|
236
240
|
const cdLabel = cooldownMs ? ` cooldown=${Math.ceil(cooldownMs / 60000)}m` : "";
|
|
241
|
+
const immediateCooldown = shouldImmediateQuotaCooldown(result.statusCode, result.body);
|
|
242
|
+
lastRetryResponse = {
|
|
243
|
+
statusCode: result.statusCode,
|
|
244
|
+
headers: result.headers,
|
|
245
|
+
body: result.body,
|
|
246
|
+
};
|
|
237
247
|
if (strategy === "sticky" && model) {
|
|
238
|
-
|
|
239
|
-
|
|
248
|
+
if (immediateCooldown) {
|
|
249
|
+
setModelCooldown(conn.id, model, cooldownMs);
|
|
250
|
+
log(`⚠️ [token-swap] "${label}" → ${result.statusCode} model=${model} COOLDOWN${cdLabel}, trying next...`);
|
|
251
|
+
} else {
|
|
252
|
+
const locked = recordModelStrike(conn.id, model, cooldownMs);
|
|
253
|
+
log(`⚠️ [token-swap] "${label}" → ${result.statusCode} model=${model}${locked ? " LOCKED" : " strike"}${cdLabel}, trying next...`);
|
|
254
|
+
}
|
|
240
255
|
} else {
|
|
241
|
-
|
|
242
|
-
|
|
256
|
+
if (immediateCooldown) {
|
|
257
|
+
setCooldown(conn.id, cooldownMs);
|
|
258
|
+
log(`⚠️ [token-swap] "${label}" → ${result.statusCode} COOLDOWN${cdLabel}, trying next...`);
|
|
259
|
+
} else {
|
|
260
|
+
const locked = recordStrike(conn.id, cooldownMs);
|
|
261
|
+
log(`⚠️ [token-swap] "${label}" → ${result.statusCode}${locked ? " LOCKED" : " strike"}${cdLabel}, trying next...`);
|
|
262
|
+
}
|
|
243
263
|
}
|
|
244
264
|
break;
|
|
245
265
|
}
|
|
@@ -264,6 +284,11 @@ async function tokenSwapForward(req, res, bodyBuffer, connections, model, strate
|
|
|
264
284
|
}
|
|
265
285
|
|
|
266
286
|
setAuthCooldown(conn.id);
|
|
287
|
+
lastRetryResponse = {
|
|
288
|
+
statusCode: result.statusCode,
|
|
289
|
+
headers: result.headers,
|
|
290
|
+
body: result.body,
|
|
291
|
+
};
|
|
267
292
|
log(`⚠️ [token-swap] "${label}" → 401 invalid_token, trying next...`);
|
|
268
293
|
break;
|
|
269
294
|
}
|
|
@@ -273,6 +298,9 @@ async function tokenSwapForward(req, res, bodyBuffer, connections, model, strate
|
|
|
273
298
|
const successModelTag = model ? ` model=${model}` : "";
|
|
274
299
|
const successStrategyTag = strategy === "sticky" ? ` sticky(use #${newCount})` : ` rr`;
|
|
275
300
|
log(`✅ [token-swap] "${label}" → ${statusCode}${successModelTag}${successStrategyTag}`);
|
|
301
|
+
// Clear strikes on success — previous 429s were likely false positives
|
|
302
|
+
clearStrikes(conn.id);
|
|
303
|
+
if (model) clearModelStrikes(conn.id, model);
|
|
276
304
|
markAccountUsed(conn.id);
|
|
277
305
|
res.writeHead(statusCode, result.response.headers);
|
|
278
306
|
|
|
@@ -328,7 +356,14 @@ async function tokenSwapForward(req, res, bodyBuffer, connections, model, strate
|
|
|
328
356
|
}
|
|
329
357
|
}
|
|
330
358
|
|
|
331
|
-
|
|
359
|
+
if (lastRetryResponse) {
|
|
360
|
+
log(`⚠️ [token-swap] exhausted ${connections.length} account(s), returning last retryable ${lastRetryResponse.statusCode}`);
|
|
361
|
+
res.writeHead(lastRetryResponse.statusCode, lastRetryResponse.headers);
|
|
362
|
+
res.end(lastRetryResponse.body);
|
|
363
|
+
return true;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
// All accounts exhausted with no retryable upstream response captured
|
|
332
367
|
return false;
|
|
333
368
|
}
|
|
334
369
|
|
|
@@ -457,6 +492,7 @@ server.on("error", (e) => {
|
|
|
457
492
|
});
|
|
458
493
|
|
|
459
494
|
const shutdown = () => server.close(() => process.exit(0));
|
|
495
|
+
process.setMaxListeners(0);
|
|
460
496
|
process.on("SIGTERM", shutdown);
|
|
461
497
|
process.on("SIGINT", shutdown);
|
|
462
498
|
if (process.platform === "win32") process.on("SIGBREAK", shutdown);
|