9router 0.2.93 → 0.2.94
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/app/.next/BUILD_ID +1 -1
- package/app/.next/app-path-routes-manifest.json +34 -34
- package/app/.next/build-manifest.json +2 -2
- package/app/.next/server/app/(dashboard)/dashboard/cli-tools/page.js +2 -2
- package/app/.next/server/app/(dashboard)/dashboard/cli-tools/page.js.nft.json +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/cli-tools/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/combos/page.js +2 -2
- package/app/.next/server/app/(dashboard)/dashboard/combos/page.js.nft.json +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/combos/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/endpoint/page.js +2 -2
- package/app/.next/server/app/(dashboard)/dashboard/endpoint/page.js.nft.json +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/endpoint/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/page.js +2 -2
- package/app/.next/server/app/(dashboard)/dashboard/page.js.nft.json +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/profile/page.js +2 -2
- package/app/.next/server/app/(dashboard)/dashboard/profile/page.js.nft.json +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/profile/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/providers/[id]/page.js +2 -2
- package/app/.next/server/app/(dashboard)/dashboard/providers/[id]/page.js.nft.json +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/providers/[id]/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/providers/new/page.js +2 -2
- package/app/.next/server/app/(dashboard)/dashboard/providers/new/page.js.nft.json +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/providers/new/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/providers/page.js +2 -2
- package/app/.next/server/app/(dashboard)/dashboard/providers/page.js.nft.json +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/providers/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/translator/page.js +2 -2
- package/app/.next/server/app/(dashboard)/dashboard/translator/page.js.nft.json +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/translator/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/usage/page.js +2 -2
- package/app/.next/server/app/(dashboard)/dashboard/usage/page.js.nft.json +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/usage/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/_global-error.html +2 -2
- package/app/.next/server/app/_global-error.rsc +1 -1
- package/app/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/app/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/app/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/app/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/app/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/app/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/app/.next/server/app/_not-found/page.js +2 -2
- package/app/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/app/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/_not-found.html +1 -1
- package/app/.next/server/app/_not-found.rsc +2 -2
- package/app/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
- package/app/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/app/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
- package/app/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/app/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/app/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/app/.next/server/app/api/auth/login/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/auth/logout/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/cli-tools/antigravity-mitm/alias/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/cli-tools/antigravity-mitm/route.js +2 -5
- package/app/.next/server/app/api/cli-tools/antigravity-mitm/route.js.nft.json +1 -1
- package/app/.next/server/app/api/cli-tools/antigravity-mitm/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/cli-tools/claude-settings/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/cli-tools/codex-settings/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/cli-tools/droid-settings/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/cli-tools/openclaw-settings/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/cloud/auth/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/cloud/credentials/update/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/cloud/model/resolve/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/cloud/models/alias/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/combos/[id]/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/combos/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/init/route.js +1 -1
- package/app/.next/server/app/api/init/route.js.nft.json +1 -1
- package/app/.next/server/app/api/init/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/keys/[id]/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/keys/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/models/alias/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/models/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/oauth/[provider]/[action]/route.js +1 -1
- package/app/.next/server/app/api/oauth/[provider]/[action]/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/oauth/cursor/auto-import/route.js +7 -1
- package/app/.next/server/app/api/oauth/cursor/auto-import/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/oauth/cursor/import/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/oauth/kiro/auto-import/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/oauth/kiro/import/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/oauth/kiro/social-authorize/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/oauth/kiro/social-exchange/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/pricing/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/provider-nodes/[id]/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/provider-nodes/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/provider-nodes/validate/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/providers/[id]/models/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/providers/[id]/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/providers/[id]/test/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/providers/client/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/providers/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/providers/test-batch/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/providers/validate/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/settings/require-login/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/settings/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/tags/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/translator/load/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/translator/save/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/translator/send/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/translator/translate/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/tunnel/disable/route.js +1 -1
- package/app/.next/server/app/api/tunnel/disable/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/tunnel/enable/route.js +1 -1
- package/app/.next/server/app/api/tunnel/enable/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/tunnel/status/route.js +1 -1
- package/app/.next/server/app/api/tunnel/status/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/usage/[connectionId]/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/usage/chart/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/usage/history/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/usage/providers/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/usage/request-details/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/usage/request-logs/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/usage/stream/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/v1/api/chat/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/v1/chat/completions/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/v1/embeddings/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/v1/messages/count_tokens/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/v1/messages/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/v1/models/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/v1/responses/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/v1/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/v1beta/models/[...path]/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/v1beta/models/route_client-reference-manifest.js +1 -1
- package/app/.next/server/app/callback/page.js +2 -2
- package/app/.next/server/app/callback/page.js.nft.json +1 -1
- package/app/.next/server/app/callback/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/callback.html +1 -1
- package/app/.next/server/app/callback.rsc +2 -2
- package/app/.next/server/app/callback.segments/_full.segment.rsc +2 -2
- package/app/.next/server/app/callback.segments/_head.segment.rsc +1 -1
- package/app/.next/server/app/callback.segments/_index.segment.rsc +2 -2
- package/app/.next/server/app/callback.segments/_tree.segment.rsc +1 -1
- package/app/.next/server/app/callback.segments/callback/__PAGE__.segment.rsc +1 -1
- package/app/.next/server/app/callback.segments/callback.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/cli-tools.html +1 -1
- package/app/.next/server/app/dashboard/cli-tools.rsc +4 -4
- package/app/.next/server/app/dashboard/cli-tools.segments/!KGRhc2hib2FyZCk/dashboard/cli-tools/__PAGE__.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/cli-tools.segments/!KGRhc2hib2FyZCk/dashboard/cli-tools.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/cli-tools.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/cli-tools.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/cli-tools.segments/_full.segment.rsc +4 -4
- package/app/.next/server/app/dashboard/cli-tools.segments/_head.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/cli-tools.segments/_index.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/cli-tools.segments/_tree.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/combos.html +1 -1
- package/app/.next/server/app/dashboard/combos.rsc +4 -4
- package/app/.next/server/app/dashboard/combos.segments/!KGRhc2hib2FyZCk/dashboard/combos/__PAGE__.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/combos.segments/!KGRhc2hib2FyZCk/dashboard/combos.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/combos.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/combos.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/combos.segments/_full.segment.rsc +4 -4
- package/app/.next/server/app/dashboard/combos.segments/_head.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/combos.segments/_index.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/combos.segments/_tree.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/endpoint.html +1 -1
- package/app/.next/server/app/dashboard/endpoint.rsc +4 -4
- package/app/.next/server/app/dashboard/endpoint.segments/!KGRhc2hib2FyZCk/dashboard/endpoint/__PAGE__.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/endpoint.segments/!KGRhc2hib2FyZCk/dashboard/endpoint.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/endpoint.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/endpoint.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/endpoint.segments/_full.segment.rsc +4 -4
- package/app/.next/server/app/dashboard/endpoint.segments/_head.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/endpoint.segments/_index.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/endpoint.segments/_tree.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/profile.html +1 -1
- package/app/.next/server/app/dashboard/profile.rsc +4 -4
- package/app/.next/server/app/dashboard/profile.segments/!KGRhc2hib2FyZCk/dashboard/profile/__PAGE__.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/profile.segments/!KGRhc2hib2FyZCk/dashboard/profile.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/profile.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/profile.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/profile.segments/_full.segment.rsc +4 -4
- package/app/.next/server/app/dashboard/profile.segments/_head.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/profile.segments/_index.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/profile.segments/_tree.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/providers/new.html +1 -1
- package/app/.next/server/app/dashboard/providers/new.rsc +4 -4
- package/app/.next/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk/dashboard/providers/new/__PAGE__.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk/dashboard/providers/new.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk/dashboard/providers.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/providers/new.segments/_full.segment.rsc +4 -4
- package/app/.next/server/app/dashboard/providers/new.segments/_head.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/providers/new.segments/_index.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/providers/new.segments/_tree.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/providers.html +1 -1
- package/app/.next/server/app/dashboard/providers.rsc +4 -4
- package/app/.next/server/app/dashboard/providers.segments/!KGRhc2hib2FyZCk/dashboard/providers/__PAGE__.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/providers.segments/!KGRhc2hib2FyZCk/dashboard/providers.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/providers.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/providers.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/providers.segments/_full.segment.rsc +4 -4
- package/app/.next/server/app/dashboard/providers.segments/_head.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/providers.segments/_index.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/providers.segments/_tree.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/settings/pricing/page.js +1 -1
- package/app/.next/server/app/dashboard/settings/pricing/page.js.nft.json +1 -1
- package/app/.next/server/app/dashboard/settings/pricing/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/dashboard/settings/pricing.html +1 -1
- package/app/.next/server/app/dashboard/settings/pricing.rsc +2 -2
- package/app/.next/server/app/dashboard/settings/pricing.segments/_full.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/settings/pricing.segments/_head.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/settings/pricing.segments/_index.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/settings/pricing.segments/_tree.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/settings/pricing.segments/dashboard/settings/pricing/__PAGE__.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/settings/pricing.segments/dashboard/settings/pricing.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/settings/pricing.segments/dashboard/settings.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/settings/pricing.segments/dashboard.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/translator.html +1 -1
- package/app/.next/server/app/dashboard/translator.rsc +4 -4
- package/app/.next/server/app/dashboard/translator.segments/!KGRhc2hib2FyZCk/dashboard/translator/__PAGE__.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/translator.segments/!KGRhc2hib2FyZCk/dashboard/translator.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/translator.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/translator.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/translator.segments/_full.segment.rsc +4 -4
- package/app/.next/server/app/dashboard/translator.segments/_head.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/translator.segments/_index.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/translator.segments/_tree.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/usage.html +1 -1
- package/app/.next/server/app/dashboard/usage.rsc +4 -4
- package/app/.next/server/app/dashboard/usage.segments/!KGRhc2hib2FyZCk/dashboard/usage/__PAGE__.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/usage.segments/!KGRhc2hib2FyZCk/dashboard/usage.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/usage.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/usage.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/usage.segments/_full.segment.rsc +4 -4
- package/app/.next/server/app/dashboard/usage.segments/_head.segment.rsc +1 -1
- package/app/.next/server/app/dashboard/usage.segments/_index.segment.rsc +2 -2
- package/app/.next/server/app/dashboard/usage.segments/_tree.segment.rsc +1 -1
- package/app/.next/server/app/dashboard.html +1 -1
- package/app/.next/server/app/dashboard.rsc +4 -4
- package/app/.next/server/app/dashboard.segments/!KGRhc2hib2FyZCk/dashboard/__PAGE__.segment.rsc +2 -2
- package/app/.next/server/app/dashboard.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/app/.next/server/app/dashboard.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/app/.next/server/app/dashboard.segments/_full.segment.rsc +4 -4
- package/app/.next/server/app/dashboard.segments/_head.segment.rsc +1 -1
- package/app/.next/server/app/dashboard.segments/_index.segment.rsc +2 -2
- package/app/.next/server/app/dashboard.segments/_tree.segment.rsc +1 -1
- package/app/.next/server/app/index.html +1 -1
- package/app/.next/server/app/index.rsc +2 -2
- package/app/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/app/.next/server/app/index.segments/_full.segment.rsc +2 -2
- package/app/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/app/.next/server/app/index.segments/_index.segment.rsc +2 -2
- package/app/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/app/.next/server/app/landing/page.js +2 -2
- package/app/.next/server/app/landing/page.js.nft.json +1 -1
- package/app/.next/server/app/landing/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/landing.html +1 -1
- package/app/.next/server/app/landing.rsc +2 -2
- package/app/.next/server/app/landing.segments/_full.segment.rsc +2 -2
- package/app/.next/server/app/landing.segments/_head.segment.rsc +1 -1
- package/app/.next/server/app/landing.segments/_index.segment.rsc +2 -2
- package/app/.next/server/app/landing.segments/_tree.segment.rsc +1 -1
- package/app/.next/server/app/landing.segments/landing/__PAGE__.segment.rsc +1 -1
- package/app/.next/server/app/landing.segments/landing.segment.rsc +1 -1
- package/app/.next/server/app/login/page.js +2 -2
- package/app/.next/server/app/login/page.js.nft.json +1 -1
- package/app/.next/server/app/login/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/login.html +1 -1
- package/app/.next/server/app/login.rsc +3 -3
- package/app/.next/server/app/login.segments/_full.segment.rsc +3 -3
- package/app/.next/server/app/login.segments/_head.segment.rsc +1 -1
- package/app/.next/server/app/login.segments/_index.segment.rsc +2 -2
- package/app/.next/server/app/login.segments/_tree.segment.rsc +1 -1
- package/app/.next/server/app/login.segments/login/__PAGE__.segment.rsc +2 -2
- package/app/.next/server/app/login.segments/login.segment.rsc +1 -1
- package/app/.next/server/app/page.js +2 -2
- package/app/.next/server/app/page.js.nft.json +1 -1
- package/app/.next/server/app/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app-paths-manifest.json +34 -34
- package/app/.next/server/chunks/2044.js +2 -0
- package/app/.next/server/chunks/6186.js +4 -0
- package/app/.next/server/chunks/8694.js +1 -0
- package/app/.next/server/chunks/9201.js +1 -0
- package/app/.next/server/chunks/9489.js +1 -1
- package/app/.next/server/pages/404.html +1 -1
- package/app/.next/server/pages/500.html +2 -2
- package/app/.next/server/server-reference-manifest.js +1 -1
- package/app/.next/server/server-reference-manifest.json +1 -1
- package/app/.next/static/chunks/{8729-4759fbfb65755c55.js → 8729-a400665e59674a47.js} +1 -1
- package/app/package.json +1 -1
- package/app/src/mitm/manager.js +321 -99
- package/app/src/mitm/server.js +14 -10
- package/package.json +1 -1
- package/app/.next/server/chunks/8954.js +0 -1
- /package/app/.next/static/{cOujbAAf11k5ILzHxROwz → BrLPf6yJlpsLD6WkIP0hO}/_buildManifest.js +0 -0
- /package/app/.next/static/{cOujbAAf11k5ILzHxROwz → BrLPf6yJlpsLD6WkIP0hO}/_ssgManifest.js +0 -0
package/app/src/mitm/manager.js
CHANGED
|
@@ -2,22 +2,52 @@ const { spawn, exec } = require("child_process");
|
|
|
2
2
|
const path = require("path");
|
|
3
3
|
const fs = require("fs");
|
|
4
4
|
const os = require("os");
|
|
5
|
+
const net = require("net");
|
|
6
|
+
const crypto = require("crypto");
|
|
5
7
|
const { addDNSEntry, removeDNSEntry, checkDNSEntry } = require("./dns/dnsConfig");
|
|
6
8
|
|
|
7
9
|
const IS_WIN = process.platform === "win32";
|
|
8
10
|
const { generateCert } = require("./cert/generate");
|
|
9
11
|
const { installCert } = require("./cert/install");
|
|
10
12
|
|
|
11
|
-
|
|
13
|
+
const MITM_PORT = 443;
|
|
14
|
+
const PID_FILE = path.join(os.homedir(), ".9router", "mitm", ".mitm.pid");
|
|
15
|
+
|
|
16
|
+
// Resolve server.js path robustly:
|
|
17
|
+
// __dirname is unreliable inside Next.js bundles, so we use DATA_DIR env or
|
|
18
|
+
// fall back to locating the file relative to the app's source root.
|
|
19
|
+
function resolveServerPath() {
|
|
20
|
+
// 1. Explicit override via env (useful for packaged/standalone builds)
|
|
21
|
+
if (process.env.MITM_SERVER_PATH) return process.env.MITM_SERVER_PATH;
|
|
22
|
+
|
|
23
|
+
// 2. Try sibling of this file (works in dev where __dirname is real)
|
|
24
|
+
const sibling = path.join(__dirname, "server.js");
|
|
25
|
+
if (fs.existsSync(sibling)) return sibling;
|
|
26
|
+
|
|
27
|
+
// 3. Fallback: resolve from process.cwd() → src/mitm/server.js
|
|
28
|
+
const fromCwd = path.join(process.cwd(), "src", "mitm", "server.js");
|
|
29
|
+
if (fs.existsSync(fromCwd)) return fromCwd;
|
|
30
|
+
|
|
31
|
+
// 4. Standalone build: app root is parent of .next
|
|
32
|
+
const fromNext = path.join(process.cwd(), "..", "src", "mitm", "server.js");
|
|
33
|
+
if (fs.existsSync(fromNext)) return fromNext;
|
|
34
|
+
|
|
35
|
+
return fromCwd; // best guess
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const SERVER_PATH = resolveServerPath();
|
|
39
|
+
|
|
40
|
+
const ENCRYPT_ALGO = "aes-256-gcm";
|
|
41
|
+
const ENCRYPT_SALT = "9router-mitm-pwd";
|
|
42
|
+
|
|
43
|
+
// Store server process in-memory
|
|
12
44
|
let serverProcess = null;
|
|
13
45
|
let serverPid = null;
|
|
14
|
-
|
|
46
|
+
|
|
47
|
+
// Persist sudo password across Next.js hot reloads (in-memory only)
|
|
15
48
|
function getCachedPassword() { return globalThis.__mitmSudoPassword || null; }
|
|
16
49
|
function setCachedPassword(pwd) { globalThis.__mitmSudoPassword = pwd; }
|
|
17
50
|
|
|
18
|
-
// server.js is in same directory as this file
|
|
19
|
-
const PID_FILE = path.join(os.homedir(), ".9router", "mitm", ".mitm.pid");
|
|
20
|
-
|
|
21
51
|
// Check if a PID is alive
|
|
22
52
|
function isProcessAlive(pid) {
|
|
23
53
|
try {
|
|
@@ -34,7 +64,193 @@ function killProcess(pid, force = false) {
|
|
|
34
64
|
const flag = force ? "/F " : "";
|
|
35
65
|
exec(`taskkill ${flag}/PID ${pid}`, () => {});
|
|
36
66
|
} else {
|
|
37
|
-
process
|
|
67
|
+
// Use pkill to kill entire process group (catches sudo + child node process)
|
|
68
|
+
const sig = force ? "SIGKILL" : "SIGTERM";
|
|
69
|
+
exec(`pkill -${sig} -P ${pid} 2>/dev/null; kill -${sig} ${pid} 2>/dev/null`, () => {});
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** Derive a 32-byte encryption key from machineId */
|
|
74
|
+
function deriveKey() {
|
|
75
|
+
try {
|
|
76
|
+
const { machineIdSync } = require("node-machine-id");
|
|
77
|
+
const raw = machineIdSync();
|
|
78
|
+
return crypto.createHash("sha256").update(raw + ENCRYPT_SALT).digest();
|
|
79
|
+
} catch {
|
|
80
|
+
// Fallback: fixed key derived from salt (less secure but functional)
|
|
81
|
+
return crypto.createHash("sha256").update(ENCRYPT_SALT).digest();
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** Encrypt sudo password with AES-256-GCM */
|
|
86
|
+
function encryptPassword(plaintext) {
|
|
87
|
+
const key = deriveKey();
|
|
88
|
+
const iv = crypto.randomBytes(12);
|
|
89
|
+
const cipher = crypto.createCipheriv(ENCRYPT_ALGO, key, iv);
|
|
90
|
+
const encrypted = Buffer.concat([cipher.update(plaintext, "utf8"), cipher.final()]);
|
|
91
|
+
const tag = cipher.getAuthTag();
|
|
92
|
+
// Store as hex: iv:tag:ciphertext
|
|
93
|
+
return `${iv.toString("hex")}:${tag.toString("hex")}:${encrypted.toString("hex")}`;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** Decrypt sudo password */
|
|
97
|
+
function decryptPassword(stored) {
|
|
98
|
+
try {
|
|
99
|
+
const [ivHex, tagHex, dataHex] = stored.split(":");
|
|
100
|
+
if (!ivHex || !tagHex || !dataHex) return null;
|
|
101
|
+
const key = deriveKey();
|
|
102
|
+
const decipher = crypto.createDecipheriv(ENCRYPT_ALGO, key, Buffer.from(ivHex, "hex"));
|
|
103
|
+
decipher.setAuthTag(Buffer.from(tagHex, "hex"));
|
|
104
|
+
return decipher.update(Buffer.from(dataHex, "hex")) + decipher.final("utf8");
|
|
105
|
+
} catch {
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// DB hooks — injected from ESM context (initializeApp / route handlers)
|
|
111
|
+
// to avoid webpack bundling issues with dynamic imports in CJS modules.
|
|
112
|
+
let _getSettings = null;
|
|
113
|
+
let _updateSettings = null;
|
|
114
|
+
|
|
115
|
+
/** Called once from ESM context to inject DB access functions */
|
|
116
|
+
function initDbHooks(getSettingsFn, updateSettingsFn) {
|
|
117
|
+
_getSettings = getSettingsFn;
|
|
118
|
+
_updateSettings = updateSettingsFn;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/** Save encrypted sudo password + mitmEnabled to db */
|
|
122
|
+
async function saveMitmSettings(enabled, password) {
|
|
123
|
+
if (!_updateSettings) {
|
|
124
|
+
console.log("[MITM] DB hooks not initialized, skipping save");
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
try {
|
|
128
|
+
const updates = { mitmEnabled: enabled };
|
|
129
|
+
if (password) updates.mitmSudoEncrypted = encryptPassword(password);
|
|
130
|
+
await _updateSettings(updates);
|
|
131
|
+
} catch (e) {
|
|
132
|
+
console.log("[MITM] Failed to save settings:", e.message);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/** Load and decrypt sudo password from db */
|
|
137
|
+
async function loadEncryptedPassword() {
|
|
138
|
+
if (!_getSettings) return null;
|
|
139
|
+
try {
|
|
140
|
+
const settings = await _getSettings();
|
|
141
|
+
if (!settings.mitmSudoEncrypted) return null;
|
|
142
|
+
return decryptPassword(settings.mitmSudoEncrypted);
|
|
143
|
+
} catch {
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Check if port 443 is available
|
|
150
|
+
* Returns: "free" | "in-use" | "no-permission"
|
|
151
|
+
*/
|
|
152
|
+
function checkPort443Free() {
|
|
153
|
+
return new Promise((resolve) => {
|
|
154
|
+
const tester = net.createServer();
|
|
155
|
+
tester.once("error", (err) => {
|
|
156
|
+
if (err.code === "EADDRINUSE") resolve("in-use");
|
|
157
|
+
else resolve("no-permission"); // EACCES or other → port free but needs sudo
|
|
158
|
+
});
|
|
159
|
+
tester.once("listening", () => { tester.close(() => resolve("free")); });
|
|
160
|
+
tester.listen(MITM_PORT, "127.0.0.1");
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Get PID and process name currently holding port 443
|
|
166
|
+
* Returns { pid, name } or null if port is free / cannot determine
|
|
167
|
+
*/
|
|
168
|
+
function getPort443Owner() {
|
|
169
|
+
return new Promise((resolve) => {
|
|
170
|
+
const cmd = IS_WIN
|
|
171
|
+
? `netstat -ano | findstr ":443 "`
|
|
172
|
+
// Only match TCP processes actually LISTEN-ing on port 443 (not outbound UDP/QUIC)
|
|
173
|
+
: `lsof -i TCP:${MITM_PORT} -n -P -sTCP:LISTEN`;
|
|
174
|
+
|
|
175
|
+
exec(cmd, (err, stdout) => {
|
|
176
|
+
if (err || !stdout.trim()) return resolve(null);
|
|
177
|
+
|
|
178
|
+
let pid = null;
|
|
179
|
+
|
|
180
|
+
if (IS_WIN) {
|
|
181
|
+
// netstat line: " TCP 0.0.0.0:443 0.0.0.0:0 LISTENING 1234"
|
|
182
|
+
for (const line of stdout.split("\n")) {
|
|
183
|
+
const match = line.match(/LISTENING\s+(\d+)/i);
|
|
184
|
+
if (match) { pid = parseInt(match[1], 10); break; }
|
|
185
|
+
}
|
|
186
|
+
} else {
|
|
187
|
+
// lsof line: "node 1234 user ..."
|
|
188
|
+
for (const line of stdout.split("\n").slice(1)) {
|
|
189
|
+
const parts = line.trim().split(/\s+/);
|
|
190
|
+
if (parts.length >= 2) { pid = parseInt(parts[1], 10); break; }
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
if (!pid || isNaN(pid)) return resolve(null);
|
|
195
|
+
|
|
196
|
+
// Get process name by PID
|
|
197
|
+
const nameCmd = IS_WIN
|
|
198
|
+
? `tasklist /FI "PID eq ${pid}" /FO CSV /NH`
|
|
199
|
+
: `ps -p ${pid} -o comm=`;
|
|
200
|
+
|
|
201
|
+
exec(nameCmd, (e2, out2) => {
|
|
202
|
+
let name = "unknown";
|
|
203
|
+
if (!e2 && out2.trim()) {
|
|
204
|
+
if (IS_WIN) {
|
|
205
|
+
// CSV: "node.exe","1234",...
|
|
206
|
+
const m = out2.match(/"([^"]+)"/);
|
|
207
|
+
if (m) name = m[1];
|
|
208
|
+
} else {
|
|
209
|
+
name = out2.trim();
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
resolve({ pid, name });
|
|
213
|
+
});
|
|
214
|
+
});
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Kill any leftover MITM server process (from previous failed start)
|
|
220
|
+
* Uses sudo to kill the node process that was spawned with sudo
|
|
221
|
+
*/
|
|
222
|
+
async function killLeftoverMitm(sudoPassword) {
|
|
223
|
+
// Kill in-memory process if still alive
|
|
224
|
+
if (serverProcess && !serverProcess.killed) {
|
|
225
|
+
try { serverProcess.kill("SIGKILL"); } catch { /* ignore */ }
|
|
226
|
+
serverProcess = null;
|
|
227
|
+
serverPid = null;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Kill from PID file
|
|
231
|
+
try {
|
|
232
|
+
if (fs.existsSync(PID_FILE)) {
|
|
233
|
+
const savedPid = parseInt(fs.readFileSync(PID_FILE, "utf-8").trim(), 10);
|
|
234
|
+
if (savedPid && isProcessAlive(savedPid)) {
|
|
235
|
+
killProcess(savedPid, true);
|
|
236
|
+
await new Promise(r => setTimeout(r, 500));
|
|
237
|
+
}
|
|
238
|
+
fs.unlinkSync(PID_FILE);
|
|
239
|
+
}
|
|
240
|
+
} catch { /* ignore */ }
|
|
241
|
+
|
|
242
|
+
// Also kill any node process running server.js via sudo (belt-and-suspenders)
|
|
243
|
+
if (!IS_WIN && SERVER_PATH) {
|
|
244
|
+
try {
|
|
245
|
+
const escaped = SERVER_PATH.replace(/'/g, "'\\''");
|
|
246
|
+
if (sudoPassword) {
|
|
247
|
+
const { execWithPassword } = require("./dns/dnsConfig");
|
|
248
|
+
await execWithPassword(`pkill -SIGKILL -f "${escaped}" 2>/dev/null || true`, sudoPassword).catch(() => {});
|
|
249
|
+
} else {
|
|
250
|
+
exec(`pkill -SIGKILL -f "${escaped}" 2>/dev/null || true`, () => {});
|
|
251
|
+
}
|
|
252
|
+
await new Promise(r => setTimeout(r, 500));
|
|
253
|
+
} catch { /* ignore */ }
|
|
38
254
|
}
|
|
39
255
|
}
|
|
40
256
|
|
|
@@ -42,7 +258,6 @@ function killProcess(pid, force = false) {
|
|
|
42
258
|
* Get MITM status
|
|
43
259
|
*/
|
|
44
260
|
async function getMitmStatus() {
|
|
45
|
-
// Check in-memory process first, then fallback to PID file
|
|
46
261
|
let running = serverProcess !== null && !serverProcess.killed;
|
|
47
262
|
let pid = serverPid;
|
|
48
263
|
|
|
@@ -54,7 +269,6 @@ async function getMitmStatus() {
|
|
|
54
269
|
running = true;
|
|
55
270
|
pid = savedPid;
|
|
56
271
|
} else {
|
|
57
|
-
// Stale PID file, clean up
|
|
58
272
|
fs.unlinkSync(PID_FILE);
|
|
59
273
|
}
|
|
60
274
|
}
|
|
@@ -63,10 +277,7 @@ async function getMitmStatus() {
|
|
|
63
277
|
}
|
|
64
278
|
}
|
|
65
279
|
|
|
66
|
-
// Check DNS configuration (cross-platform via dnsConfig)
|
|
67
280
|
const dnsConfigured = checkDNSEntry();
|
|
68
|
-
|
|
69
|
-
// Check cert
|
|
70
281
|
const certDir = path.join(os.homedir(), ".9router", "mitm");
|
|
71
282
|
const certExists = fs.existsSync(path.join(certDir, "server.crt"));
|
|
72
283
|
|
|
@@ -79,109 +290,133 @@ async function getMitmStatus() {
|
|
|
79
290
|
* @param {string} sudoPassword - Sudo password for DNS/cert operations
|
|
80
291
|
*/
|
|
81
292
|
async function startMitm(apiKey, sudoPassword) {
|
|
82
|
-
// Check
|
|
293
|
+
// Check orphan process from PID file before spawning
|
|
294
|
+
if (!serverProcess || serverProcess.killed) {
|
|
295
|
+
try {
|
|
296
|
+
if (fs.existsSync(PID_FILE)) {
|
|
297
|
+
const savedPid = parseInt(fs.readFileSync(PID_FILE, "utf-8").trim(), 10);
|
|
298
|
+
if (savedPid && isProcessAlive(savedPid)) {
|
|
299
|
+
// Orphan MITM process still alive — reuse it
|
|
300
|
+
serverPid = savedPid;
|
|
301
|
+
console.log(`[MITM] Reusing existing process PID ${savedPid}`);
|
|
302
|
+
await saveMitmSettings(true, sudoPassword);
|
|
303
|
+
if (sudoPassword) setCachedPassword(sudoPassword);
|
|
304
|
+
return { running: true, pid: savedPid };
|
|
305
|
+
} else {
|
|
306
|
+
fs.unlinkSync(PID_FILE);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
} catch {
|
|
310
|
+
// Ignore stale PID file errors
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
83
314
|
if (serverProcess && !serverProcess.killed) {
|
|
84
315
|
throw new Error("MITM proxy is already running");
|
|
85
316
|
}
|
|
86
|
-
|
|
317
|
+
|
|
318
|
+
// Kill any leftover MITM server from a previous failed start attempt
|
|
319
|
+
await killLeftoverMitm(sudoPassword);
|
|
320
|
+
|
|
321
|
+
// Check port 443 availability BEFORE modifying system
|
|
322
|
+
const portStatus = await checkPort443Free();
|
|
323
|
+
if (portStatus === "in-use") {
|
|
324
|
+
const owner = await getPort443Owner();
|
|
325
|
+
let ownerDesc = "another process";
|
|
326
|
+
if (owner) {
|
|
327
|
+
const shortName = owner.name.includes("/")
|
|
328
|
+
? owner.name.split("/").filter(Boolean).pop()
|
|
329
|
+
: owner.name;
|
|
330
|
+
ownerDesc = `"${shortName}" (PID ${owner.pid})`;
|
|
331
|
+
}
|
|
332
|
+
throw new Error(
|
|
333
|
+
`Port 443 is already in use by ${ownerDesc}. Stop that process first, then retry.`
|
|
334
|
+
);
|
|
335
|
+
}
|
|
336
|
+
|
|
87
337
|
// 1. Generate SSL certificate if not exists
|
|
88
338
|
const certPath = path.join(os.homedir(), ".9router", "mitm", "server.crt");
|
|
89
339
|
if (!fs.existsSync(certPath)) {
|
|
90
340
|
console.log("Generating SSL certificate...");
|
|
91
341
|
await generateCert();
|
|
92
342
|
}
|
|
93
|
-
|
|
343
|
+
|
|
94
344
|
// 2. Install certificate to system keychain
|
|
95
|
-
|
|
96
|
-
|
|
345
|
+
// Skip if db flag says installed AND cert file still exists (same cert in keychain)
|
|
346
|
+
const settings = _getSettings ? await _getSettings().catch(() => ({})) : {};
|
|
347
|
+
const certAlreadyInstalled = settings.mitmCertInstalled && fs.existsSync(certPath);
|
|
348
|
+
if (!certAlreadyInstalled) {
|
|
349
|
+
await installCert(sudoPassword, certPath);
|
|
350
|
+
if (_updateSettings) await _updateSettings({ mitmCertInstalled: true }).catch(() => {});
|
|
351
|
+
}
|
|
352
|
+
|
|
97
353
|
// 3. Add DNS entry
|
|
98
354
|
console.log("Adding DNS entry...");
|
|
99
355
|
await addDNSEntry(sudoPassword);
|
|
100
|
-
|
|
101
|
-
// 4.
|
|
356
|
+
|
|
357
|
+
// 4. Spawn MITM server with sudo (port 443 requires root on macOS/Linux)
|
|
102
358
|
console.log("Starting MITM server...");
|
|
103
|
-
const serverPath = path.join(process.cwd(), "src/mitm/server.js");
|
|
104
359
|
|
|
105
360
|
if (IS_WIN) {
|
|
106
|
-
// Windows: spawn via powershell elevated to bind port 443
|
|
107
361
|
const nodePath = process.execPath;
|
|
108
|
-
const envArgs = `$env:ROUTER_API_KEY='${apiKey}'; $env:NODE_ENV='production'; & '${nodePath}' '${
|
|
362
|
+
const envArgs = `$env:ROUTER_API_KEY='${apiKey}'; $env:NODE_ENV='production'; & '${nodePath}' '${SERVER_PATH}'`;
|
|
109
363
|
serverProcess = spawn("powershell", [
|
|
110
364
|
"-Command",
|
|
111
365
|
`Start-Process powershell -ArgumentList '-NoProfile','-Command','${envArgs.replace(/'/g, "''")}' -Verb RunAs -PassThru`
|
|
112
|
-
], {
|
|
113
|
-
detached: false,
|
|
114
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
115
|
-
});
|
|
366
|
+
], { detached: false, stdio: ["ignore", "pipe", "pipe"] });
|
|
116
367
|
} else {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
});
|
|
368
|
+
// sudo -S: read password from stdin, -E: preserve env vars
|
|
369
|
+
// Pass ROUTER_API_KEY inline via env=... wrapper to avoid sudo stripping env
|
|
370
|
+
const inlineCmd = `ROUTER_API_KEY='${apiKey}' NODE_ENV='production' '${process.execPath}' '${SERVER_PATH}'`;
|
|
371
|
+
serverProcess = spawn(
|
|
372
|
+
"sudo", ["-S", "-E", "sh", "-c", inlineCmd],
|
|
373
|
+
{ detached: false, stdio: ["pipe", "pipe", "pipe"] }
|
|
374
|
+
);
|
|
375
|
+
// Write password then close stdin so sudo proceeds
|
|
376
|
+
serverProcess.stdin.write(`${sudoPassword}\n`);
|
|
377
|
+
serverProcess.stdin.end();
|
|
126
378
|
}
|
|
127
|
-
|
|
379
|
+
|
|
128
380
|
serverPid = serverProcess.pid;
|
|
129
|
-
|
|
130
|
-
// Save PID to file
|
|
131
381
|
fs.writeFileSync(PID_FILE, String(serverPid));
|
|
132
|
-
|
|
133
|
-
|
|
382
|
+
|
|
383
|
+
let startError = null;
|
|
134
384
|
serverProcess.stdout.on("data", (data) => {
|
|
135
385
|
console.log(`[MITM Server] ${data.toString().trim()}`);
|
|
136
386
|
});
|
|
137
|
-
|
|
138
387
|
serverProcess.stderr.on("data", (data) => {
|
|
139
|
-
|
|
388
|
+
const msg = data.toString().trim();
|
|
389
|
+
// Capture meaningful errors (ignore sudo password prompt noise)
|
|
390
|
+
if (msg && !msg.includes("Password:") && !msg.includes("password for")) {
|
|
391
|
+
console.error(`[MITM Server Error] ${msg}`);
|
|
392
|
+
startError = msg;
|
|
393
|
+
}
|
|
140
394
|
});
|
|
141
|
-
|
|
142
395
|
serverProcess.on("exit", (code) => {
|
|
143
396
|
console.log(`MITM server exited with code ${code}`);
|
|
144
397
|
serverProcess = null;
|
|
145
398
|
serverPid = null;
|
|
146
|
-
|
|
147
|
-
// Remove PID file
|
|
148
|
-
try {
|
|
149
|
-
fs.unlinkSync(PID_FILE);
|
|
150
|
-
} catch (error) {
|
|
151
|
-
// Ignore
|
|
152
|
-
}
|
|
399
|
+
try { fs.unlinkSync(PID_FILE); } catch { /* ignore */ }
|
|
153
400
|
});
|
|
154
|
-
|
|
155
|
-
// Wait
|
|
401
|
+
|
|
402
|
+
// Wait up to 8s — sudo + Node startup takes longer than plain spawn
|
|
156
403
|
const started = await new Promise((resolve) => {
|
|
157
404
|
let resolved = false;
|
|
158
|
-
const
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
serverProcess.on("exit", (code) => {
|
|
163
|
-
clearTimeout(timeout);
|
|
164
|
-
if (!resolved) { resolved = true; resolve(false); }
|
|
165
|
-
});
|
|
166
|
-
|
|
167
|
-
// Check stderr for error messages
|
|
168
|
-
serverProcess.stderr.on("data", (data) => {
|
|
169
|
-
const msg = data.toString().trim();
|
|
170
|
-
if (msg.includes("Port") && msg.includes("already in use")) {
|
|
171
|
-
clearTimeout(timeout);
|
|
172
|
-
if (!resolved) { resolved = true; resolve(false); }
|
|
173
|
-
}
|
|
174
|
-
});
|
|
405
|
+
const done = (val) => { if (!resolved) { resolved = true; resolve(val); } };
|
|
406
|
+
const timeout = setTimeout(() => done(true), 8000);
|
|
407
|
+
serverProcess.once("exit", () => { clearTimeout(timeout); done(false); });
|
|
175
408
|
});
|
|
176
409
|
|
|
177
410
|
if (!started) {
|
|
178
|
-
|
|
411
|
+
try { await removeDNSEntry(sudoPassword); } catch { /* best effort */ }
|
|
412
|
+
const reason = startError || "Check sudo password or port 443 access.";
|
|
413
|
+
throw new Error(`MITM server failed to start. ${reason}`);
|
|
179
414
|
}
|
|
180
415
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
};
|
|
416
|
+
await saveMitmSettings(true, sudoPassword);
|
|
417
|
+
if (sudoPassword) setCachedPassword(sudoPassword);
|
|
418
|
+
|
|
419
|
+
return { running: true, pid: serverPid };
|
|
185
420
|
}
|
|
186
421
|
|
|
187
422
|
/**
|
|
@@ -189,19 +424,15 @@ async function startMitm(apiKey, sudoPassword) {
|
|
|
189
424
|
* @param {string} sudoPassword - Sudo password for DNS cleanup
|
|
190
425
|
*/
|
|
191
426
|
async function stopMitm(sudoPassword) {
|
|
192
|
-
// 1. Kill server process (in-memory or from PID file)
|
|
193
427
|
const proc = serverProcess;
|
|
194
428
|
if (proc && !proc.killed) {
|
|
195
429
|
console.log("Stopping MITM server...");
|
|
196
430
|
killProcess(proc.pid, false);
|
|
197
431
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
198
|
-
if (isProcessAlive(proc.pid))
|
|
199
|
-
killProcess(proc.pid, true);
|
|
200
|
-
}
|
|
432
|
+
if (isProcessAlive(proc.pid)) killProcess(proc.pid, true);
|
|
201
433
|
serverProcess = null;
|
|
202
434
|
serverPid = null;
|
|
203
435
|
} else {
|
|
204
|
-
// Fallback: kill by PID file
|
|
205
436
|
try {
|
|
206
437
|
if (fs.existsSync(PID_FILE)) {
|
|
207
438
|
const savedPid = parseInt(fs.readFileSync(PID_FILE, "utf-8").trim(), 10);
|
|
@@ -209,33 +440,22 @@ async function stopMitm(sudoPassword) {
|
|
|
209
440
|
console.log(`Killing MITM server (PID: ${savedPid})...`);
|
|
210
441
|
killProcess(savedPid, false);
|
|
211
442
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
212
|
-
if (isProcessAlive(savedPid))
|
|
213
|
-
killProcess(savedPid, true);
|
|
214
|
-
}
|
|
443
|
+
if (isProcessAlive(savedPid)) killProcess(savedPid, true);
|
|
215
444
|
}
|
|
216
445
|
}
|
|
217
|
-
} catch {
|
|
218
|
-
// Ignore
|
|
219
|
-
}
|
|
446
|
+
} catch { /* ignore */ }
|
|
220
447
|
serverProcess = null;
|
|
221
448
|
serverPid = null;
|
|
222
449
|
}
|
|
223
|
-
|
|
224
|
-
// 2. Remove DNS entry
|
|
450
|
+
|
|
225
451
|
console.log("Removing DNS entry...");
|
|
226
452
|
await removeDNSEntry(sudoPassword);
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
return {
|
|
236
|
-
running: false,
|
|
237
|
-
pid: null
|
|
238
|
-
};
|
|
453
|
+
|
|
454
|
+
try { fs.unlinkSync(PID_FILE); } catch { /* ignore */ }
|
|
455
|
+
|
|
456
|
+
await saveMitmSettings(false, null);
|
|
457
|
+
|
|
458
|
+
return { running: false, pid: null };
|
|
239
459
|
}
|
|
240
460
|
|
|
241
461
|
module.exports = {
|
|
@@ -243,5 +463,7 @@ module.exports = {
|
|
|
243
463
|
startMitm,
|
|
244
464
|
stopMitm,
|
|
245
465
|
getCachedPassword,
|
|
246
|
-
setCachedPassword
|
|
466
|
+
setCachedPassword,
|
|
467
|
+
loadEncryptedPassword,
|
|
468
|
+
initDbHooks,
|
|
247
469
|
};
|
package/app/src/mitm/server.js
CHANGED
|
@@ -23,10 +23,16 @@ if (!API_KEY) {
|
|
|
23
23
|
|
|
24
24
|
// Load SSL certificates
|
|
25
25
|
const certDir = path.join(os.homedir(), ".9router", "mitm");
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
26
|
+
let sslOptions;
|
|
27
|
+
try {
|
|
28
|
+
sslOptions = {
|
|
29
|
+
key: fs.readFileSync(path.join(certDir, "server.key")),
|
|
30
|
+
cert: fs.readFileSync(path.join(certDir, "server.crt"))
|
|
31
|
+
};
|
|
32
|
+
} catch (e) {
|
|
33
|
+
console.error(`❌ SSL cert not found in ${certDir}: ${e.message}`);
|
|
34
|
+
process.exit(1);
|
|
35
|
+
}
|
|
30
36
|
|
|
31
37
|
// Chat endpoints that should be intercepted
|
|
32
38
|
const CHAT_URL_PATTERNS = [":generateContent", ":streamGenerateContent"];
|
|
@@ -146,12 +152,10 @@ async function intercept(req, res, bodyBuffer, mappedModel) {
|
|
|
146
152
|
throw new Error(`9Router ${response.status}: ${errText}`);
|
|
147
153
|
}
|
|
148
154
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
"X-Accel-Buffering": "no"
|
|
154
|
-
});
|
|
155
|
+
const ct = response.headers.get("content-type") || "application/json";
|
|
156
|
+
const resHeaders = { "Content-Type": ct, "Cache-Control": "no-cache", "Connection": "keep-alive" };
|
|
157
|
+
if (ct.includes("text/event-stream")) resHeaders["X-Accel-Buffering"] = "no";
|
|
158
|
+
res.writeHead(200, resHeaders);
|
|
155
159
|
|
|
156
160
|
const reader = response.body.getReader();
|
|
157
161
|
const decoder = new TextDecoder();
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
exports.id=8954,exports.ids=[8954],exports.modules={3179:(a,b,c)=>{"use strict";c.d(b,{Al:()=>t,F0:()=>v,nN:()=>x,ss:()=>w});var d=c(29021),e=c.n(d),f=c(33873),g=c.n(f),h=c(55591),i=c.n(h),j=c(21820),k=c.n(j),l=c(79646),m=c(85567);let n=g().join(k().homedir(),".9router","bin"),o="cloudflared",p="win32"===k().platform(),q=p?`${o}.exe`:o,r=g().join(n,q),s={darwin:{x64:"cloudflared-darwin-amd64.tgz",arm64:"cloudflared-darwin-amd64.tgz"},win32:{x64:"cloudflared-windows-amd64.exe"},linux:{x64:"cloudflared-linux-amd64",arm64:"cloudflared-linux-arm64"}};async function t(){if(e().existsSync(n)||e().mkdirSync(n,{recursive:!0}),e().existsSync(r))return p||e().chmodSync(r,"755"),r;let a=function(){let a=k().platform(),b=k().arch(),c=s[a];if(!c)throw Error(`Unsupported platform: ${a}`);let d=c[b];if(!d)throw Error(`Unsupported architecture: ${b} for platform ${a}`);return`https://github.com/cloudflare/cloudflared/releases/latest/download/${d}`}(),b=a.endsWith(".tgz"),c=b?g().join(n,"cloudflared.tgz"):r;return await function a(b,c){return new Promise((d,f)=>{let g=e().createWriteStream(c);i().get(b,b=>{if([301,302].includes(b.statusCode)){g.close(),e().unlinkSync(c),a(b.headers.location,c).then(d).catch(f);return}if(200!==b.statusCode){g.close(),e().unlinkSync(c),f(Error(`Download failed with status ${b.statusCode}`));return}b.pipe(g),g.on("finish",()=>{g.close(()=>d(c))}),g.on("error",a=>{g.close(),e().unlinkSync(c),f(a)})}).on("error",a=>{g.close(),e().existsSync(c)&&e().unlinkSync(c),f(a)})})}(a,c),b&&((0,l.execSync)(`tar -xzf "${c}" -C "${n}"`,{stdio:"pipe"}),e().unlinkSync(c)),p||e().chmodSync(r,"755"),r}let u=null;async function v(a){let b=await t(),c=(0,l.spawn)(b,["tunnel","run","--dns-resolver-addrs","1.1.1.1:53","--token",a],{detached:!1,stdio:["ignore","pipe","pipe"]});return u=c,(0,m.xS)(c.pid),new Promise((a,b)=>{let d=0,e=setTimeout(()=>{a(c)},9e4),f=b=>{b.toString().includes("Registered tunnel connection")&&++d>=4&&(clearTimeout(e),a(c))};c.stdout.on("data",f),c.stderr.on("data",f),c.on("error",a=>{clearTimeout(e),b(a)}),c.on("exit",a=>{clearTimeout(e),0===d&&b(Error(`cloudflared exited with code ${a}`))})})}function w(){if(u){try{u.kill()}catch(a){}u=null}let a=(0,m.Cr)();if(a){try{process.kill(a)}catch(a){}(0,m.r4)()}try{(0,l.execSync)("pkill -f cloudflared 2>/dev/null || true",{stdio:"ignore"})}catch(a){}}function x(){let a=(0,m.Cr)();if(!a)return!1;try{return process.kill(a,0),!0}catch(a){return!1}}},11020:(a,b,c)=>{Promise.resolve().then(c.t.bind(c,95547,23)),Promise.resolve().then(c.t.bind(c,15098,23)),Promise.resolve().then(c.t.bind(c,47644,23)),Promise.resolve().then(c.t.bind(c,33859,23)),Promise.resolve().then(c.t.bind(c,98099,23)),Promise.resolve().then(c.t.bind(c,16237,23)),Promise.resolve().then(c.t.bind(c,98562,23)),Promise.resolve().then(c.t.bind(c,36675,23))},12020:(a,b,c)=>{"use strict";c.d(b,{Q2:()=>d.Q2,fg:()=>d.fg,vQ:()=>e,MA:()=>d.MA,zN:()=>d.zN,B2:()=>f});var d=c(96919);c(91431);let e={name:"Endpoint Proxy",description:"AI Infrastructure Management",version:"0.2.93"},f={storageKey:"theme",defaultTheme:"system"}},13033:(a,b,c)=>{"use strict";c.d(b,{A:()=>g});var d=c(31417),e=c(300),f=c(12020);let g=(0,d.v)((0,e.Zr)((a,b)=>({theme:f.B2.defaultTheme,setTheme:b=>{a({theme:b})},toggleTheme:()=>{let c="dark"===b().theme?"light":"dark";a({theme:c})},initTheme:()=>{b().theme}}),{name:f.B2.storageKey}))},19201:(a,b,c)=>{"use strict";var d=c(89718),e=c(53855),f=c(3179);process.setMaxListeners(20);let g=!1;async function h(){try{if(await (0,d.bI)(),(await (0,d.getSettings)()).tunnelEnabled&&!(0,f.nN)()){console.log("[InitApp] Tunnel was enabled, auto-reconnecting...");try{await (0,e.cb)(),console.log("[InitApp] Tunnel reconnected")}catch(a){console.log("[InitApp] Tunnel reconnect failed:",a.message)}}if(!g){let a=()=>{(0,f.ss)(),process.exit()};process.on("SIGINT",a),process.on("SIGTERM",a),g=!0}(0,f.Al)().catch(()=>{})}catch(a){console.error("[InitApp] Error:",a)}}let i=!1;(async function(){if(!i)try{await h(),i=!0}catch(a){console.error("[ServerInit] Error initializing app:",a)}return i})().catch(console.log)},19308:(a,b,c)=>{"use strict";c.d(b,{ThemeProvider:()=>f});var d=c(48249);c(67484);var e=c(13033);function f({children:a}){let{initTheme:b}=(0,e.A)();return(0,d.jsx)(d.Fragment,{children:a})}},50385:(a,b,c)=>{"use strict";c.r(b),c.d(b,{default:()=>i,metadata:()=>h});var d=c(5735),e=c(75329),f=c.n(e);c(61135);var g=c(89886);c(19201);let h={title:"9Router - AI Infrastructure Management",description:"One endpoint for all your AI providers. Manage keys, monitor usage, and scale effortlessly.",icons:{icon:"/favicon.svg"}};function i({children:a}){return(0,d.jsxs)("html",{lang:"en",suppressHydrationWarning:!0,children:[(0,d.jsxs)("head",{children:[(0,d.jsx)("link",{rel:"preconnect",href:"https://fonts.googleapis.com"}),(0,d.jsx)("link",{rel:"preconnect",href:"https://fonts.gstatic.com",crossOrigin:"anonymous"}),(0,d.jsx)("link",{href:"https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200&display=swap",rel:"stylesheet"})]}),(0,d.jsx)("body",{className:`${f().variable} font-sans antialiased`,children:(0,d.jsx)(g.ThemeProvider,{children:a})})]})}},53855:(a,b,c)=>{"use strict";c.d(b,{Jv:()=>n,Rg:()=>m,cb:()=>l});var d=c(55511),e=c.n(d),f=c(85567),g=c(3179),h=c(89718);let i=process.env.TUNNEL_WORKER_URL||"https://tunnel.9router.com",j="abcdefghijklmnpqrstuvwxyz23456789";async function k(a,b={}){let c=`${i}${a}`;return(await fetch(c,{...b,headers:{"Content-Type":"application/json",...b.headers}})).json()}async function l(){let a=(0,f.C7)();if(a&&a.tunnelUrl&&(0,g.nN)())return{success:!0,tunnelUrl:a.tunnelUrl,shortId:a.shortId,alreadyRunning:!0};(0,g.ss)();let b=function(){try{let{machineIdSync:a}=c(19713),b=a();return e().createHash("sha256").update(b+"9router-tunnel-salt").digest("hex").substring(0,16)}catch(a){return e().randomUUID().replace(/-/g,"").substring(0,16)}}(),d=a?.shortId||function(){let a="";for(let b=0;b<6;b++)a+=j.charAt(Math.floor(Math.random()*j.length));return a}(),i=a?.apiKey||function(a){let b="abcdefghijklmnopqrstuvwxyz0123456789",c="";for(let a=0;a<6;a++)c+=b.charAt(Math.floor(Math.random()*b.length));let d=e().createHmac("sha256","9router-tunnel-api-key-secret").update(a+c).digest("hex").slice(0,8);return`sk-${a}-${c}-${d}`}(b);await k("/api/session/create",{method:"POST",body:JSON.stringify({apiKey:i,shortId:d})});let l=await k("/api/tunnel/create",{method:"POST",body:JSON.stringify({apiKey:i})});if(l.error)throw Error(l.error);let{token:m,hostname:n}=l;return await (0,g.F0)(m),(0,f.LZ)({shortId:d,apiKey:i,tunnelUrl:n,machineId:b}),await (0,h.Xx)({tunnelEnabled:!0,tunnelUrl:n}),{success:!0,tunnelUrl:n,shortId:d}}async function m(){let a=(0,f.C7)();if((0,g.ss)(),a?.apiKey)try{await k("/api/tunnel/delete",{method:"DELETE",body:JSON.stringify({apiKey:a.apiKey})})}catch(a){}return a&&(0,f.LZ)({shortId:a.shortId,apiKey:a.apiKey,machineId:a.machineId,tunnelUrl:null}),await (0,h.Xx)({tunnelEnabled:!1,tunnelUrl:""}),{success:!0}}async function n(){let a=(0,f.C7)(),b=(0,g.nN)();return{enabled:!0===(await (0,h.getSettings)()).tunnelEnabled&&b,tunnelUrl:a?.tunnelUrl||"",shortId:a?.shortId||"",running:b}}},56680:(a,b,c)=>{Promise.resolve().then(c.t.bind(c,81921,23))},60757:(a,b,c)=>{"use strict";c.d(b,{KC:()=>f,Xg:()=>e,vq:()=>d});let d={cc:[{id:"claude-opus-4-6",name:"Claude Opus 4.6"},{id:"claude-sonnet-4-6",name:"Claude Sonnet 4.6"},{id:"claude-opus-4-5-20251101",name:"Claude 4.5 Opus"},{id:"claude-sonnet-4-5-20250929",name:"Claude 4.5 Sonnet"},{id:"claude-haiku-4-5-20251001",name:"Claude 4.5 Haiku"}],cx:[{id:"gpt-5.3-codex",name:"GPT 5.3 Codex"},{id:"gpt-5.3-codex-xhigh",name:"GPT 5.3 Codex (xHigh)"},{id:"gpt-5.3-codex-high",name:"GPT 5.3 Codex (High)"},{id:"gpt-5.3-codex-low",name:"GPT 5.3 Codex (Low)"},{id:"gpt-5.3-codex-none",name:"GPT 5.3 Codex (None)"},{id:"gpt-5.3-codex-spark",name:"GPT 5.3 Codex Spark"},{id:"gpt-5.1-codex-mini",name:"GPT 5.1 Codex Mini"},{id:"gpt-5.1-codex-mini-high",name:"GPT 5.1 Codex Mini (High)"},{id:"gpt-5.2-codex",name:"GPT 5.2 Codex"},{id:"gpt-5.2",name:"GPT 5.2"},{id:"gpt-5.1-codex-max",name:"GPT 5.1 Codex Max"},{id:"gpt-5.1-codex",name:"GPT 5.1 Codex"},{id:"gpt-5.1",name:"GPT 5.1"},{id:"gpt-5-codex",name:"GPT 5 Codex"},{id:"gpt-5-codex-mini",name:"GPT 5 Codex Mini"}],gc:[{id:"gemini-3-flash-preview",name:"Gemini 3 Flash Preview"},{id:"gemini-3-pro-preview",name:"Gemini 3 Pro Preview"},{id:"gemini-2.5-pro",name:"Gemini 2.5 Pro"},{id:"gemini-2.5-flash",name:"Gemini 2.5 Flash"},{id:"gemini-2.5-flash-lite",name:"Gemini 2.5 Flash Lite"}],qw:[{id:"qwen3-coder-plus",name:"Qwen3 Coder Plus"},{id:"qwen3-coder-flash",name:"Qwen3 Coder Flash"},{id:"vision-model",name:"Qwen3 Vision Model"},{id:"coder-model",name:"Qwen3.5 Coder Model"}],if:[{id:"qwen3-coder-plus",name:"Qwen3 Coder Plus"},{id:"kimi-k2",name:"Kimi K2"},{id:"kimi-k2-thinking",name:"Kimi K2 Thinking"},{id:"kimi-k2.5",name:"Kimi K2.5"},{id:"deepseek-r1",name:"DeepSeek R1"},{id:"deepseek-v3.2-chat",name:"DeepSeek V3.2 Chat"},{id:"minimax-m2.1",name:"MiniMax M2.1"},{id:"minimax-m2.5",name:"MiniMax M2.5"},{id:"glm-4.7",name:"GLM 4.7"},{id:"glm-4.6",name:"GLM 4.6"},{id:"glm-5",name:"GLM 5"}],ag:[{id:"gemini-3.1-pro-high",name:"Gemini 3 Pro High"},{id:"gemini-3.1-pro-low",name:"Gemini 3 Pro Low"},{id:"gemini-3-flash",name:"Gemini 3 Flash"},{id:"claude-sonnet-4-6",name:"Claude Sonnet 4.6"},{id:"claude-opus-4-6-thinking",name:"Claude Opus 4.6 Thinking"},{id:"gpt-oss-120b-medium",name:"GPT OSS 120B Medium"}],gh:[{id:"gpt-3.5-turbo",name:"GPT-3.5 Turbo"},{id:"gpt-4",name:"GPT-4"},{id:"gpt-4o",name:"GPT-4o"},{id:"gpt-4o-mini",name:"GPT-4o mini"},{id:"gpt-4.1",name:"GPT-4.1"},{id:"gpt-5",name:"GPT-5"},{id:"gpt-5-mini",name:"GPT-5 Mini"},{id:"gpt-5-codex",name:"GPT-5 Codex"},{id:"gpt-5.1",name:"GPT-5.1"},{id:"gpt-5.1-codex",name:"GPT-5.1 Codex"},{id:"gpt-5.1-codex-mini",name:"GPT-5.1 Codex Mini"},{id:"gpt-5.1-codex-max",name:"GPT-5.1 Codex Max"},{id:"gpt-5.2",name:"GPT-5.2"},{id:"gpt-5.2-codex",name:"GPT-5.2 Codex"},{id:"gpt-5.3-codex",name:"GPT-5.3 Codex"},{id:"claude-haiku-4.5",name:"Claude Haiku 4.5"},{id:"claude-opus-4.1",name:"Claude Opus 4.1"},{id:"claude-opus-4.5",name:"Claude Opus 4.5"},{id:"claude-sonnet-4",name:"Claude Sonnet 4"},{id:"claude-sonnet-4.5",name:"Claude Sonnet 4.5"},{id:"claude-sonnet-4.6",name:"Claude Sonnet 4.6"},{id:"claude-opus-4.6",name:"Claude Opus 4.6"},{id:"gemini-2.5-pro",name:"Gemini 2.5 Pro"},{id:"gemini-3-flash-preview",name:"Gemini 3 Flash"},{id:"gemini-3-pro-preview",name:"Gemini 3 Pro"},{id:"grok-code-fast-1",name:"Grok Code Fast 1"},{id:"oswe-vscode-prime",name:"Raptor Mini"}],kr:[{id:"claude-sonnet-4.5",name:"Claude Sonnet 4.5"},{id:"claude-haiku-4.5",name:"Claude Haiku 4.5"}],cu:[{id:"default",name:"Auto (Server Picks)"},{id:"claude-4.5-opus-high-thinking",name:"Claude 4.5 Opus High Thinking"},{id:"claude-4.5-opus-high",name:"Claude 4.5 Opus High"},{id:"claude-4.5-sonnet-thinking",name:"Claude 4.5 Sonnet Thinking"},{id:"claude-4.5-sonnet",name:"Claude 4.5 Sonnet"},{id:"claude-4.5-haiku",name:"Claude 4.5 Haiku"},{id:"claude-4.5-opus",name:"Claude 4.5 Opus"},{id:"gpt-5.2-codex",name:"GPT 5.2 Codex"}],kmc:[{id:"kimi-k2.5",name:"Kimi K2.5"},{id:"kimi-k2.5-thinking",name:"Kimi K2.5 Thinking"},{id:"kimi-latest",name:"Kimi Latest"}],kc:[{id:"anthropic/claude-sonnet-4-20250514",name:"Claude Sonnet 4"},{id:"anthropic/claude-opus-4-20250514",name:"Claude Opus 4"},{id:"google/gemini-2.5-pro",name:"Gemini 2.5 Pro"},{id:"google/gemini-2.5-flash",name:"Gemini 2.5 Flash"},{id:"openai/gpt-4.1",name:"GPT-4.1"},{id:"openai/o3",name:"o3"},{id:"deepseek/deepseek-chat",name:"DeepSeek Chat"},{id:"deepseek/deepseek-reasoner",name:"DeepSeek Reasoner"}],cl:[{id:"anthropic/claude-sonnet-4-20250514",name:"Claude Sonnet 4"},{id:"anthropic/claude-opus-4-20250514",name:"Claude Opus 4"},{id:"google/gemini-2.5-pro",name:"Gemini 2.5 Pro"},{id:"google/gemini-2.5-flash",name:"Gemini 2.5 Flash"},{id:"openai/gpt-4.1",name:"GPT-4.1"},{id:"openai/o3",name:"o3"},{id:"deepseek/deepseek-chat",name:"DeepSeek Chat"}],openai:[{id:"gpt-4o",name:"GPT-4o"},{id:"gpt-4o-mini",name:"GPT-4o Mini"},{id:"gpt-4-turbo",name:"GPT-4 Turbo"},{id:"o1",name:"O1"},{id:"o1-mini",name:"O1 Mini"}],anthropic:[{id:"claude-sonnet-4-20250514",name:"Claude Sonnet 4"},{id:"claude-opus-4-20250514",name:"Claude Opus 4"},{id:"claude-3-5-sonnet-20241022",name:"Claude 3.5 Sonnet"}],gemini:[{id:"gemini-3-pro-preview",name:"Gemini 3 Pro Preview"},{id:"gemini-2.5-pro",name:"Gemini 2.5 Pro"},{id:"gemini-2.5-flash",name:"Gemini 2.5 Flash"},{id:"gemini-2.5-flash-lite",name:"Gemini 2.5 Flash Lite"},{id:"gemini-embedding-001",name:"Gemini Embedding 001",type:"embedding"},{id:"text-embedding-005",name:"Text Embedding 005",type:"embedding"},{id:"text-embedding-004",name:"Text Embedding 004 (Legacy)",type:"embedding"}],openrouter:[{id:"auto",name:"Auto (Best Available)"}],glm:[{id:"glm-5",name:"GLM 5"},{id:"glm-4.7",name:"GLM 4.7"},{id:"glm-4.6v",name:"GLM 4.6V (Vision)"}],"glm-cn":[{id:"glm-5",name:"GLM 5"},{id:"glm-4.7",name:"GLM-4.7"},{id:"glm-4.6",name:"GLM-4.6"},{id:"glm-4.5-air",name:"GLM-4.5-Air"}],kimi:[{id:"kimi-k2.5",name:"Kimi K2.5"},{id:"kimi-k2.5-thinking",name:"Kimi K2.5 Thinking"},{id:"kimi-latest",name:"Kimi Latest"}],minimax:[{id:"MiniMax-M2.5",name:"MiniMax M2.5"},{id:"MiniMax-M2.1",name:"MiniMax M2.1"}],"minimax-cn":[{id:"MiniMax-M2.5",name:"MiniMax M2.5"},{id:"MiniMax-M2.1",name:"MiniMax M2.1"}],deepseek:[{id:"deepseek-chat",name:"DeepSeek V3.2 Chat"},{id:"deepseek-reasoner",name:"DeepSeek V3.2 Reasoner"}],groq:[{id:"llama-3.3-70b-versatile",name:"Llama 3.3 70B"},{id:"meta-llama/llama-4-maverick-17b-128e-instruct",name:"Llama 4 Maverick"},{id:"qwen/qwen3-32b",name:"Qwen3 32B"},{id:"openai/gpt-oss-120b",name:"GPT-OSS 120B"}],xai:[{id:"grok-4",name:"Grok 4"},{id:"grok-4-fast-reasoning",name:"Grok 4 Fast Reasoning"},{id:"grok-code-fast-1",name:"Grok Code Fast"},{id:"grok-3",name:"Grok 3"}],mistral:[{id:"mistral-large-latest",name:"Mistral Large 3"},{id:"codestral-latest",name:"Codestral"},{id:"mistral-medium-latest",name:"Mistral Medium 3"}],perplexity:[{id:"sonar-pro",name:"Sonar Pro"},{id:"sonar",name:"Sonar"}],together:[{id:"meta-llama/Llama-3.3-70B-Instruct-Turbo",name:"Llama 3.3 70B Turbo"},{id:"deepseek-ai/DeepSeek-R1",name:"DeepSeek R1"},{id:"Qwen/Qwen3-235B-A22B",name:"Qwen3 235B"},{id:"meta-llama/Llama-4-Maverick-17B-128E-Instruct-FP8",name:"Llama 4 Maverick"}],fireworks:[{id:"accounts/fireworks/models/deepseek-v3p1",name:"DeepSeek V3.1"},{id:"accounts/fireworks/models/llama-v3p3-70b-instruct",name:"Llama 3.3 70B"},{id:"accounts/fireworks/models/qwen3-235b-a22b",name:"Qwen3 235B"}],cerebras:[{id:"gpt-oss-120b",name:"GPT OSS 120B"},{id:"zai-glm-4.7",name:"ZAI GLM 4.7"},{id:"llama-3.3-70b",name:"Llama 3.3 70B"},{id:"llama-4-scout-17b-16e-instruct",name:"Llama 4 Scout"},{id:"qwen-3-235b-a22b-instruct-2507",name:"Qwen3 235B A22B"},{id:"qwen-3-32b",name:"Qwen3 32B"}],cohere:[{id:"command-r-plus-08-2024",name:"Command R+ (Aug 2024)"},{id:"command-r-08-2024",name:"Command R (Aug 2024)"},{id:"command-a-03-2025",name:"Command A (Mar 2025)"}],nvidia:[{id:"moonshotai/kimi-k2.5",name:"Kimi K2.5"},{id:"z-ai/glm4.7",name:"GLM 4.7"},{id:"deepseek-ai/deepseek-v3.2",name:"DeepSeek V3.2"},{id:"nvidia/llama-3.3-70b-instruct",name:"Llama 3.3 70B"},{id:"meta/llama-4-maverick-17b-128e-instruct",name:"Llama 4 Maverick"},{id:"deepseek/deepseek-r1",name:"DeepSeek R1"}],nebius:[{id:"meta-llama/Llama-3.3-70B-Instruct",name:"Llama 3.3 70B Instruct"}],siliconflow:[{id:"deepseek-ai/DeepSeek-V3.2",name:"DeepSeek V3.2"},{id:"deepseek-ai/DeepSeek-V3.1",name:"DeepSeek V3.1"},{id:"deepseek-ai/DeepSeek-R1",name:"DeepSeek R1"},{id:"Qwen/Qwen3-235B-A22B-Instruct-2507",name:"Qwen3 235B"},{id:"Qwen/Qwen3-Coder-480B-A35B-Instruct",name:"Qwen3 Coder 480B"},{id:"Qwen/Qwen3-32B",name:"Qwen3 32B"},{id:"moonshotai/Kimi-K2.5",name:"Kimi K2.5"},{id:"zai-org/GLM-4.7",name:"GLM 4.7"},{id:"openai/gpt-oss-120b",name:"GPT OSS 120B"},{id:"baidu/ERNIE-4.5-300B-A47B",name:"ERNIE 4.5 300B"}],hyperbolic:[{id:"Qwen/QwQ-32B",name:"QwQ 32B"},{id:"deepseek-ai/DeepSeek-R1",name:"DeepSeek R1"},{id:"deepseek-ai/DeepSeek-V3",name:"DeepSeek V3"},{id:"meta-llama/Llama-3.3-70B-Instruct",name:"Llama 3.3 70B"},{id:"meta-llama/Llama-3.2-3B-Instruct",name:"Llama 3.2 3B"},{id:"Qwen/Qwen2.5-72B-Instruct",name:"Qwen 2.5 72B"},{id:"Qwen/Qwen2.5-Coder-32B-Instruct",name:"Qwen 2.5 Coder 32B"},{id:"NousResearch/Hermes-3-Llama-3.1-70B",name:"Hermes 3 70B"}]},e={claude:"cc",codex:"cx","gemini-cli":"gc",qwen:"qw",iflow:"if",antigravity:"ag",github:"gh",kiro:"kr",cursor:"cu","kimi-coding":"kmc",kilocode:"kc",cline:"cl",openai:"openai",anthropic:"anthropic",gemini:"gemini",openrouter:"openrouter",glm:"glm","glm-cn":"glm-cn",kimi:"kimi",minimax:"minimax","minimax-cn":"minimax-cn",deepseek:"deepseek",groq:"groq",xai:"xai",mistral:"mistral",perplexity:"perplexity",together:"together",fireworks:"fireworks",cerebras:"cerebras",cohere:"cohere",nvidia:"nvidia",nebius:"nebius",siliconflow:"siliconflow",hyperbolic:"hyperbolic"};function f(a){return d[e[a]||a]||[]}},61135:()=>{},69832:(a,b,c)=>{Promise.resolve().then(c.t.bind(c,95547,23))},70440:(a,b,c)=>{"use strict";c.r(b),c.d(b,{default:()=>e});var d=c(88868);let e=async a=>[{type:"image/x-icon",sizes:"16x16",url:(0,d.fillMetadataSegment)(".",await a.params,"favicon.ico")+"?603d046c9a6fdfbb"}]},78335:()=>{},85440:(a,b,c)=>{Promise.resolve().then(c.bind(c,19308))},85567:(a,b,c)=>{"use strict";c.d(b,{C7:()=>n,Cr:()=>q,LZ:()=>o,r4:()=>r,xS:()=>p});var d=c(29021),e=c.n(d),f=c(33873),g=c.n(f),h=c(21820),i=c.n(h);let j=g().join(i().homedir(),".9router","tunnel"),k=g().join(j,"state.json"),l=g().join(j,"cloudflared.pid");function m(){e().existsSync(j)||e().mkdirSync(j,{recursive:!0})}function n(){try{if(e().existsSync(k))return JSON.parse(e().readFileSync(k,"utf8"))}catch(a){}return null}function o(a){m(),e().writeFileSync(k,JSON.stringify(a,null,2))}function p(a){m(),e().writeFileSync(l,a.toString())}function q(){try{if(e().existsSync(l))return parseInt(e().readFileSync(l,"utf8"))}catch(a){}return null}function r(){try{e().existsSync(l)&&e().unlinkSync(l)}catch(a){}}},89886:(a,b,c)=>{"use strict";c.d(b,{ThemeProvider:()=>d});let d=(0,c(77943).registerClientReference)(function(){throw Error("Attempted to call ThemeProvider() from the server but ThemeProvider is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component.")},"/Users/Working/router4/app/src/shared/components/ThemeProvider.js","ThemeProvider")},91431:(a,b,c)=>{"use strict";c.d(b,{KC:()=>d.KC,Xg:()=>d.Xg});var d=c(60757);Object.entries(c(96919).Q2).filter(([,a])=>a.passthroughModels).map(([a])=>a),Object.entries(d.vq).flatMap(([a,b])=>b.map(b=>({provider:a,model:b.id,name:b.name})))},96487:()=>{},96919:(a,b,c)=>{"use strict";c.d(b,{DI:()=>h,IS:()=>d,JH:()=>g,MA:()=>l,Q2:()=>k,fg:()=>f,gb:()=>j,mq:()=>i,wG:()=>n,wb:()=>o,zN:()=>e,zt:()=>m});let d={iflow:{id:"iflow",alias:"if",name:"iFlow AI",icon:"water_drop",color:"#6366F1"},qwen:{id:"qwen",alias:"qw",name:"Qwen Code",icon:"psychology",color:"#10B981"},"gemini-cli":{id:"gemini-cli",alias:"gc",name:"Gemini CLI",icon:"terminal",color:"#4285F4"},kiro:{id:"kiro",alias:"kr",name:"Kiro AI",icon:"psychology_alt",color:"#FF6B35"}},e={claude:{id:"claude",alias:"cc",name:"Claude Code",icon:"smart_toy",color:"#D97757"},antigravity:{id:"antigravity",alias:"ag",name:"Antigravity",icon:"rocket_launch",color:"#F59E0B"},codex:{id:"codex",alias:"cx",name:"OpenAI Codex",icon:"code",color:"#3B82F6"},github:{id:"github",alias:"gh",name:"GitHub Copilot",icon:"code",color:"#333333"},cursor:{id:"cursor",alias:"cu",name:"Cursor IDE",icon:"edit_note",color:"#00D4AA"}},f={openrouter:{id:"openrouter",alias:"openrouter",name:"OpenRouter",icon:"router",color:"#F97316",textIcon:"OR",passthroughModels:!0,website:"https://openrouter.ai"},glm:{id:"glm",alias:"glm",name:"GLM Coding",icon:"code",color:"#2563EB",textIcon:"GL",website:"https://open.bigmodel.cn"},kimi:{id:"kimi",alias:"kimi",name:"Kimi",icon:"psychology",color:"#1E3A8A",textIcon:"KM",website:"https://kimi.moonshot.cn"},minimax:{id:"minimax",alias:"minimax",name:"Minimax Coding",icon:"memory",color:"#7C3AED",textIcon:"MM",website:"https://www.minimaxi.com"},"minimax-cn":{id:"minimax-cn",alias:"minimax-cn",name:"Minimax (China)",icon:"memory",color:"#DC2626",textIcon:"MC",website:"https://www.minimaxi.com"},openai:{id:"openai",alias:"openai",name:"OpenAI",icon:"auto_awesome",color:"#10A37F",textIcon:"OA",website:"https://platform.openai.com"},anthropic:{id:"anthropic",alias:"anthropic",name:"Anthropic",icon:"smart_toy",color:"#D97757",textIcon:"AN",website:"https://console.anthropic.com"},gemini:{id:"gemini",alias:"gemini",name:"Gemini",icon:"diamond",color:"#4285F4",textIcon:"GE",website:"https://ai.google.dev"},deepseek:{id:"deepseek",alias:"ds",name:"DeepSeek",icon:"bolt",color:"#4D6BFE",textIcon:"DS",website:"https://deepseek.com"},groq:{id:"groq",alias:"groq",name:"Groq",icon:"speed",color:"#F55036",textIcon:"GQ",website:"https://groq.com"},xai:{id:"xai",alias:"xai",name:"xAI (Grok)",icon:"auto_awesome",color:"#1DA1F2",textIcon:"XA",website:"https://x.ai"},mistral:{id:"mistral",alias:"mistral",name:"Mistral",icon:"air",color:"#FF7000",textIcon:"MI",website:"https://mistral.ai"},perplexity:{id:"perplexity",alias:"pplx",name:"Perplexity",icon:"search",color:"#20808D",textIcon:"PP",website:"https://www.perplexity.ai"},together:{id:"together",alias:"together",name:"Together AI",icon:"group_work",color:"#0F6FFF",textIcon:"TG",website:"https://www.together.ai"},fireworks:{id:"fireworks",alias:"fireworks",name:"Fireworks AI",icon:"local_fire_department",color:"#7B2EF2",textIcon:"FW",website:"https://fireworks.ai"},cerebras:{id:"cerebras",alias:"cerebras",name:"Cerebras",icon:"memory",color:"#FF4F00",textIcon:"CB",website:"https://www.cerebras.ai"},cohere:{id:"cohere",alias:"cohere",name:"Cohere",icon:"hub",color:"#39594D",textIcon:"CO",website:"https://cohere.com"},nvidia:{id:"nvidia",alias:"nvidia",name:"NVIDIA NIM",icon:"developer_board",color:"#76B900",textIcon:"NV",website:"https://developer.nvidia.com/nim"},nebius:{id:"nebius",alias:"nebius",name:"Nebius AI",icon:"cloud",color:"#6C5CE7",textIcon:"NB",website:"https://nebius.com"},siliconflow:{id:"siliconflow",alias:"siliconflow",name:"SiliconFlow",icon:"cloud_queue",color:"#5B6EF5",textIcon:"SF",website:"https://cloud.siliconflow.com"},hyperbolic:{id:"hyperbolic",alias:"hyp",name:"Hyperbolic",icon:"bolt",color:"#00D4FF",textIcon:"HY",website:"https://hyperbolic.xyz"},deepgram:{id:"deepgram",alias:"dg",name:"Deepgram",icon:"mic",color:"#13EF93",textIcon:"DG",website:"https://deepgram.com"},assemblyai:{id:"assemblyai",alias:"aai",name:"AssemblyAI",icon:"record_voice_over",color:"#0062FF",textIcon:"AA",website:"https://assemblyai.com"},nanobanana:{id:"nanobanana",alias:"nb",name:"NanoBanana",icon:"image",color:"#FFD700",textIcon:"NB",website:"https://nanobananaapi.ai"}},g="openai-compatible-",h="anthropic-compatible-";function i(a){return"string"==typeof a&&a.startsWith(g)}function j(a){return"string"==typeof a&&a.startsWith(h)}let k={...d,...e,...f},l={oauth:{id:"oauth",name:"OAuth",icon:"lock"},apikey:{id:"apikey",name:"API Key",icon:"key"}};function m(a){for(let b of Object.values(k))if(b.alias===a||b.id===a)return b;return null}function n(a){let b=k[a];return b?.alias||a}Object.values(k).reduce((a,b)=>(a[b.alias]=b.id,a),{}),Object.values(k).reduce((a,b)=>(a[b.id]=b.alias,a),{});let o=["antigravity","kiro","github","codex"]},97868:(a,b,c)=>{Promise.resolve().then(c.t.bind(c,81921,23)),Promise.resolve().then(c.t.bind(c,60440,23)),Promise.resolve().then(c.t.bind(c,84342,23)),Promise.resolve().then(c.t.bind(c,82265,23)),Promise.resolve().then(c.t.bind(c,35421,23)),Promise.resolve().then(c.t.bind(c,61335,23)),Promise.resolve().then(c.t.bind(c,70664,23)),Promise.resolve().then(c.bind(c,74661))},98592:(a,b,c)=>{Promise.resolve().then(c.bind(c,89886))}};
|
|
File without changes
|
|
File without changes
|