zevairouter 1.0.147 → 1.0.149
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/CHANGELOG.md +19 -0
- package/cli/app/.next-cli-build/BUILD_ID +1 -1
- package/cli/app/.next-cli-build/app-path-routes-manifest.json +10 -10
- package/cli/app/.next-cli-build/build-manifest.json +2 -2
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/automation/page_client-reference-manifest.js +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/basic-chat/page_client-reference-manifest.js +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/cli-tools/[toolId]/page_client-reference-manifest.js +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/cli-tools/page_client-reference-manifest.js +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/combos/page_client-reference-manifest.js +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/console-log/page_client-reference-manifest.js +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/context/page_client-reference-manifest.js +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/endpoint/page_client-reference-manifest.js +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/media-providers/[kind]/[id]/page_client-reference-manifest.js +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/media-providers/[kind]/page_client-reference-manifest.js +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/media-providers/combo/[id]/page_client-reference-manifest.js +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/media-providers/web/page_client-reference-manifest.js +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/mitm/page_client-reference-manifest.js +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/page_client-reference-manifest.js +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/playground/page_client-reference-manifest.js +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/profile/page_client-reference-manifest.js +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/providers/[id]/page_client-reference-manifest.js +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/providers/new/page_client-reference-manifest.js +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/providers/page_client-reference-manifest.js +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/proxy-pools/page_client-reference-manifest.js +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/pxpipe/page_client-reference-manifest.js +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/quota/page_client-reference-manifest.js +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/terminal/page_client-reference-manifest.js +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/token-saver/page_client-reference-manifest.js +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/translator/page_client-reference-manifest.js +1 -1
- package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/usage/page_client-reference-manifest.js +1 -1
- package/cli/app/.next-cli-build/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/cli/app/.next-cli-build/server/app/_global-error.html +1 -1
- package/cli/app/.next-cli-build/server/app/_global-error.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/cli/app/.next-cli-build/server/app/_not-found.html +1 -1
- package/cli/app/.next-cli-build/server/app/_not-found.rsc +3 -3
- package/cli/app/.next-cli-build/server/app/_not-found.segments/_full.segment.rsc +3 -3
- package/cli/app/.next-cli-build/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/_not-found.segments/_index.segment.rsc +3 -3
- package/cli/app/.next-cli-build/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/api/models/route.js +1 -1
- package/cli/app/.next-cli-build/server/app/api/providers/route.js +1 -1
- package/cli/app/.next-cli-build/server/app/api/providers/validate/route.js +1 -1
- package/cli/app/.next-cli-build/server/app/api/translator/console-logs/route.js +1 -1
- package/cli/app/.next-cli-build/server/app/api/translator/console-logs/stream/route.js +1 -1
- package/cli/app/.next-cli-build/server/app/api/version/route.js +1 -1
- package/cli/app/.next-cli-build/server/app/api/version/shutdown/route.js +1 -1
- package/cli/app/.next-cli-build/server/app/api/version/update/route.js +1 -1
- package/cli/app/.next-cli-build/server/app/callback/page_client-reference-manifest.js +1 -1
- package/cli/app/.next-cli-build/server/app/callback.html +1 -1
- package/cli/app/.next-cli-build/server/app/callback.rsc +3 -3
- package/cli/app/.next-cli-build/server/app/callback.segments/_full.segment.rsc +3 -3
- package/cli/app/.next-cli-build/server/app/callback.segments/_head.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/callback.segments/_index.segment.rsc +3 -3
- package/cli/app/.next-cli-build/server/app/callback.segments/_tree.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/callback.segments/callback/__PAGE__.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/callback.segments/callback.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/automation.html +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/automation.rsc +5 -5
- package/cli/app/.next-cli-build/server/app/dashboard/automation.segments/!KGRhc2hib2FyZCk/dashboard/automation/__PAGE__.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard/automation.segments/!KGRhc2hib2FyZCk/dashboard/automation.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/automation.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/automation.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard/automation.segments/_full.segment.rsc +5 -5
- package/cli/app/.next-cli-build/server/app/dashboard/automation.segments/_head.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/automation.segments/_index.segment.rsc +3 -3
- package/cli/app/.next-cli-build/server/app/dashboard/automation.segments/_tree.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/basic-chat.html +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/basic-chat.rsc +5 -5
- package/cli/app/.next-cli-build/server/app/dashboard/basic-chat.segments/!KGRhc2hib2FyZCk/dashboard/basic-chat/__PAGE__.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard/basic-chat.segments/!KGRhc2hib2FyZCk/dashboard/basic-chat.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/basic-chat.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/basic-chat.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard/basic-chat.segments/_full.segment.rsc +5 -5
- package/cli/app/.next-cli-build/server/app/dashboard/basic-chat.segments/_head.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/basic-chat.segments/_index.segment.rsc +3 -3
- package/cli/app/.next-cli-build/server/app/dashboard/basic-chat.segments/_tree.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/cli-tools.html +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/cli-tools.rsc +5 -5
- package/cli/app/.next-cli-build/server/app/dashboard/cli-tools.segments/!KGRhc2hib2FyZCk/dashboard/cli-tools/__PAGE__.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard/cli-tools.segments/!KGRhc2hib2FyZCk/dashboard/cli-tools.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/cli-tools.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/cli-tools.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard/cli-tools.segments/_full.segment.rsc +5 -5
- package/cli/app/.next-cli-build/server/app/dashboard/cli-tools.segments/_head.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/cli-tools.segments/_index.segment.rsc +3 -3
- package/cli/app/.next-cli-build/server/app/dashboard/cli-tools.segments/_tree.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/combos.html +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/combos.rsc +5 -5
- package/cli/app/.next-cli-build/server/app/dashboard/combos.segments/!KGRhc2hib2FyZCk/dashboard/combos/__PAGE__.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard/combos.segments/!KGRhc2hib2FyZCk/dashboard/combos.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/combos.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/combos.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard/combos.segments/_full.segment.rsc +5 -5
- package/cli/app/.next-cli-build/server/app/dashboard/combos.segments/_head.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/combos.segments/_index.segment.rsc +3 -3
- package/cli/app/.next-cli-build/server/app/dashboard/combos.segments/_tree.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/context.html +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/context.rsc +5 -5
- package/cli/app/.next-cli-build/server/app/dashboard/context.segments/!KGRhc2hib2FyZCk/dashboard/context/__PAGE__.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard/context.segments/!KGRhc2hib2FyZCk/dashboard/context.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/context.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/context.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard/context.segments/_full.segment.rsc +5 -5
- package/cli/app/.next-cli-build/server/app/dashboard/context.segments/_head.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/context.segments/_index.segment.rsc +3 -3
- package/cli/app/.next-cli-build/server/app/dashboard/context.segments/_tree.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/endpoint.html +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/endpoint.rsc +5 -5
- package/cli/app/.next-cli-build/server/app/dashboard/endpoint.segments/!KGRhc2hib2FyZCk/dashboard/endpoint/__PAGE__.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard/endpoint.segments/!KGRhc2hib2FyZCk/dashboard/endpoint.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/endpoint.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/endpoint.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard/endpoint.segments/_full.segment.rsc +5 -5
- package/cli/app/.next-cli-build/server/app/dashboard/endpoint.segments/_head.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/endpoint.segments/_index.segment.rsc +3 -3
- package/cli/app/.next-cli-build/server/app/dashboard/endpoint.segments/_tree.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/media-providers/web.html +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/media-providers/web.rsc +5 -5
- package/cli/app/.next-cli-build/server/app/dashboard/media-providers/web.segments/!KGRhc2hib2FyZCk/dashboard/media-providers/web/__PAGE__.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard/media-providers/web.segments/!KGRhc2hib2FyZCk/dashboard/media-providers/web.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/media-providers/web.segments/!KGRhc2hib2FyZCk/dashboard/media-providers.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/media-providers/web.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/media-providers/web.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard/media-providers/web.segments/_full.segment.rsc +5 -5
- package/cli/app/.next-cli-build/server/app/dashboard/media-providers/web.segments/_head.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/media-providers/web.segments/_index.segment.rsc +3 -3
- package/cli/app/.next-cli-build/server/app/dashboard/media-providers/web.segments/_tree.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/mitm.html +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/mitm.rsc +5 -5
- package/cli/app/.next-cli-build/server/app/dashboard/mitm.segments/!KGRhc2hib2FyZCk/dashboard/mitm/__PAGE__.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard/mitm.segments/!KGRhc2hib2FyZCk/dashboard/mitm.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/mitm.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/mitm.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard/mitm.segments/_full.segment.rsc +5 -5
- package/cli/app/.next-cli-build/server/app/dashboard/mitm.segments/_head.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/mitm.segments/_index.segment.rsc +3 -3
- package/cli/app/.next-cli-build/server/app/dashboard/mitm.segments/_tree.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/playground.html +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/playground.rsc +5 -5
- package/cli/app/.next-cli-build/server/app/dashboard/playground.segments/!KGRhc2hib2FyZCk/dashboard/playground/__PAGE__.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard/playground.segments/!KGRhc2hib2FyZCk/dashboard/playground.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/playground.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/playground.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard/playground.segments/_full.segment.rsc +5 -5
- package/cli/app/.next-cli-build/server/app/dashboard/playground.segments/_head.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/playground.segments/_index.segment.rsc +3 -3
- package/cli/app/.next-cli-build/server/app/dashboard/playground.segments/_tree.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/profile.html +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/profile.rsc +5 -5
- package/cli/app/.next-cli-build/server/app/dashboard/profile.segments/!KGRhc2hib2FyZCk/dashboard/profile/__PAGE__.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard/profile.segments/!KGRhc2hib2FyZCk/dashboard/profile.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/profile.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/profile.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard/profile.segments/_full.segment.rsc +5 -5
- package/cli/app/.next-cli-build/server/app/dashboard/profile.segments/_head.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/profile.segments/_index.segment.rsc +3 -3
- package/cli/app/.next-cli-build/server/app/dashboard/profile.segments/_tree.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/providers/new.html +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/providers/new.rsc +5 -5
- package/cli/app/.next-cli-build/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk/dashboard/providers/new/__PAGE__.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk/dashboard/providers/new.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk/dashboard/providers.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard/providers/new.segments/_full.segment.rsc +5 -5
- package/cli/app/.next-cli-build/server/app/dashboard/providers/new.segments/_head.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/providers/new.segments/_index.segment.rsc +3 -3
- package/cli/app/.next-cli-build/server/app/dashboard/providers/new.segments/_tree.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/providers.html +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/providers.rsc +5 -5
- package/cli/app/.next-cli-build/server/app/dashboard/providers.segments/!KGRhc2hib2FyZCk/dashboard/providers/__PAGE__.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard/providers.segments/!KGRhc2hib2FyZCk/dashboard/providers.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/providers.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/providers.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard/providers.segments/_full.segment.rsc +5 -5
- package/cli/app/.next-cli-build/server/app/dashboard/providers.segments/_head.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/providers.segments/_index.segment.rsc +3 -3
- package/cli/app/.next-cli-build/server/app/dashboard/providers.segments/_tree.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/proxy-pools.html +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/proxy-pools.rsc +5 -5
- package/cli/app/.next-cli-build/server/app/dashboard/proxy-pools.segments/!KGRhc2hib2FyZCk/dashboard/proxy-pools/__PAGE__.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard/proxy-pools.segments/!KGRhc2hib2FyZCk/dashboard/proxy-pools.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/proxy-pools.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/proxy-pools.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard/proxy-pools.segments/_full.segment.rsc +5 -5
- package/cli/app/.next-cli-build/server/app/dashboard/proxy-pools.segments/_head.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/proxy-pools.segments/_index.segment.rsc +3 -3
- package/cli/app/.next-cli-build/server/app/dashboard/proxy-pools.segments/_tree.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/pxpipe.html +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/pxpipe.rsc +5 -5
- package/cli/app/.next-cli-build/server/app/dashboard/pxpipe.segments/!KGRhc2hib2FyZCk/dashboard/pxpipe/__PAGE__.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard/pxpipe.segments/!KGRhc2hib2FyZCk/dashboard/pxpipe.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/pxpipe.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/pxpipe.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard/pxpipe.segments/_full.segment.rsc +5 -5
- package/cli/app/.next-cli-build/server/app/dashboard/pxpipe.segments/_head.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/pxpipe.segments/_index.segment.rsc +3 -3
- package/cli/app/.next-cli-build/server/app/dashboard/pxpipe.segments/_tree.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/quota.html +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard/quota.rsc +6 -6
- package/cli/app/.next-cli-build/server/app/dashboard/quota.segments/!KGRhc2hib2FyZCk/dashboard/quota/__PAGE__.segment.rsc +3 -3
- package/cli/app/.next-cli-build/server/app/dashboard/quota.segments/!KGRhc2hib2FyZCk/dashboard/quota.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/quota.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/quota.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard/quota.segments/_full.segment.rsc +6 -6
- package/cli/app/.next-cli-build/server/app/dashboard/quota.segments/_head.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/quota.segments/_index.segment.rsc +3 -3
- package/cli/app/.next-cli-build/server/app/dashboard/quota.segments/_tree.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/settings/pricing/page_client-reference-manifest.js +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/settings/pricing.html +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/settings/pricing.rsc +3 -3
- package/cli/app/.next-cli-build/server/app/dashboard/settings/pricing.segments/_full.segment.rsc +3 -3
- package/cli/app/.next-cli-build/server/app/dashboard/settings/pricing.segments/_head.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/settings/pricing.segments/_index.segment.rsc +3 -3
- package/cli/app/.next-cli-build/server/app/dashboard/settings/pricing.segments/_tree.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/settings/pricing.segments/dashboard/settings/pricing/__PAGE__.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/settings/pricing.segments/dashboard/settings/pricing.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/settings/pricing.segments/dashboard/settings.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/settings/pricing.segments/dashboard.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/token-saver.html +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/token-saver.rsc +5 -5
- package/cli/app/.next-cli-build/server/app/dashboard/token-saver.segments/!KGRhc2hib2FyZCk/dashboard/token-saver/__PAGE__.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard/token-saver.segments/!KGRhc2hib2FyZCk/dashboard/token-saver.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/token-saver.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/token-saver.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard/token-saver.segments/_full.segment.rsc +5 -5
- package/cli/app/.next-cli-build/server/app/dashboard/token-saver.segments/_head.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/token-saver.segments/_index.segment.rsc +3 -3
- package/cli/app/.next-cli-build/server/app/dashboard/token-saver.segments/_tree.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/translator.html +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/translator.rsc +5 -5
- package/cli/app/.next-cli-build/server/app/dashboard/translator.segments/!KGRhc2hib2FyZCk/dashboard/translator/__PAGE__.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard/translator.segments/!KGRhc2hib2FyZCk/dashboard/translator.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/translator.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/translator.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard/translator.segments/_full.segment.rsc +5 -5
- package/cli/app/.next-cli-build/server/app/dashboard/translator.segments/_head.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/translator.segments/_index.segment.rsc +3 -3
- package/cli/app/.next-cli-build/server/app/dashboard/translator.segments/_tree.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/usage.html +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/usage.rsc +5 -5
- package/cli/app/.next-cli-build/server/app/dashboard/usage.segments/!KGRhc2hib2FyZCk/dashboard/usage/__PAGE__.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard/usage.segments/!KGRhc2hib2FyZCk/dashboard/usage.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/usage.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/usage.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard/usage.segments/_full.segment.rsc +5 -5
- package/cli/app/.next-cli-build/server/app/dashboard/usage.segments/_head.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard/usage.segments/_index.segment.rsc +3 -3
- package/cli/app/.next-cli-build/server/app/dashboard/usage.segments/_tree.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard.html +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard.rsc +5 -5
- package/cli/app/.next-cli-build/server/app/dashboard.segments/!KGRhc2hib2FyZCk/dashboard/__PAGE__.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/dashboard.segments/_full.segment.rsc +5 -5
- package/cli/app/.next-cli-build/server/app/dashboard.segments/_head.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/dashboard.segments/_index.segment.rsc +3 -3
- package/cli/app/.next-cli-build/server/app/dashboard.segments/_tree.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/index.html +1 -1
- package/cli/app/.next-cli-build/server/app/index.rsc +3 -3
- package/cli/app/.next-cli-build/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/index.segments/_full.segment.rsc +3 -3
- package/cli/app/.next-cli-build/server/app/index.segments/_head.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/index.segments/_index.segment.rsc +3 -3
- package/cli/app/.next-cli-build/server/app/index.segments/_tree.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/landing/page_client-reference-manifest.js +1 -1
- package/cli/app/.next-cli-build/server/app/landing.html +1 -1
- package/cli/app/.next-cli-build/server/app/landing.rsc +4 -4
- package/cli/app/.next-cli-build/server/app/landing.segments/_full.segment.rsc +4 -4
- package/cli/app/.next-cli-build/server/app/landing.segments/_head.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/landing.segments/_index.segment.rsc +3 -3
- package/cli/app/.next-cli-build/server/app/landing.segments/_tree.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/landing.segments/landing/__PAGE__.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/landing.segments/landing.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/login/page_client-reference-manifest.js +1 -1
- package/cli/app/.next-cli-build/server/app/login.html +1 -1
- package/cli/app/.next-cli-build/server/app/login.rsc +4 -4
- package/cli/app/.next-cli-build/server/app/login.segments/_full.segment.rsc +4 -4
- package/cli/app/.next-cli-build/server/app/login.segments/_head.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/login.segments/_index.segment.rsc +3 -3
- package/cli/app/.next-cli-build/server/app/login.segments/_tree.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/login.segments/login/__PAGE__.segment.rsc +2 -2
- package/cli/app/.next-cli-build/server/app/login.segments/login.segment.rsc +1 -1
- package/cli/app/.next-cli-build/server/app/page_client-reference-manifest.js +1 -1
- package/cli/app/.next-cli-build/server/app-paths-manifest.json +10 -10
- package/cli/app/.next-cli-build/server/chunks/3155.js +1 -1
- package/cli/app/.next-cli-build/server/chunks/4566.js +1 -1
- package/cli/app/.next-cli-build/server/chunks/4746.js +1 -1
- package/cli/app/.next-cli-build/server/chunks/5307.js +1 -1
- package/cli/app/.next-cli-build/server/chunks/5949.js +3 -3
- package/cli/app/.next-cli-build/server/chunks/8306.js +1 -1
- package/cli/app/.next-cli-build/server/chunks/8371.js +1 -1
- package/cli/app/.next-cli-build/server/chunks/9621.js +1 -1
- package/cli/app/.next-cli-build/server/middleware-build-manifest.js +1 -1
- package/cli/app/.next-cli-build/server/pages/404.html +1 -1
- package/cli/app/.next-cli-build/server/pages/500.html +1 -1
- package/cli/app/.next-cli-build/static/chunks/{620-375754e53341e85b.js → 620-104e711e028e5a60.js} +1 -1
- package/cli/app/CHANGELOG.md +19 -0
- package/cli/app/cli/hooks/cloakbrowserRuntime.js +111 -4
- package/cli/app/package.json +1 -1
- package/cli/hooks/cloakbrowserRuntime.js +111 -4
- package/cli/package.json +1 -1
- package/package.json +1 -1
- package/src/lib/oauth/services/bulkImportBrowserEngine.js +36 -0
- package/src/lib/oauth/services/codebuddyCnBulkImportManager.js +603 -181
- package/src/lib/oauth/services/codebuddyCnPhoneAutomation.js +97 -47
- package/src/lib/oauth/services/kiroBulkImportManager.js +7 -1
- /package/cli/app/.next-cli-build/static/{y-U4C09T7DItXT7CZZV41 → w0fFe0wlenV7JedZI_N94}/_buildManifest.js +0 -0
- /package/cli/app/.next-cli-build/static/{y-U4C09T7DItXT7CZZV41 → w0fFe0wlenV7JedZI_N94}/_ssgManifest.js +0 -0
|
@@ -64,12 +64,26 @@ const CODEBUDDY_CN_POLL_TIMEOUT_MS = 15 * 60_000;
|
|
|
64
64
|
// input phone, click send code takes ~15-20s before SMS is actually requested).
|
|
65
65
|
const CODEBUDDY_CN_SMS_TIMEOUT_MS = 90_000;
|
|
66
66
|
|
|
67
|
-
// Hard wall-clock
|
|
68
|
-
//
|
|
67
|
+
// Hard wall-clock for phone registration (nav + form + SMS). Console/API work
|
|
68
|
+
// has separate bounded operations below.
|
|
69
69
|
const CODEBUDDY_CN_ACCOUNT_HARD_TIMEOUT_MS = Number.parseInt(
|
|
70
70
|
process.env.ZEVAI_CN_ACCOUNT_TIMEOUT_MS || "",
|
|
71
71
|
10,
|
|
72
|
-
) ||
|
|
72
|
+
) || 5 * 60_000;
|
|
73
|
+
|
|
74
|
+
const CODEBUDDY_CN_BROWSER_LAUNCH_TIMEOUT_MS = 90_000;
|
|
75
|
+
const CODEBUDDY_CN_CONTEXT_TIMEOUT_MS = 30_000;
|
|
76
|
+
const CODEBUDDY_CN_CONSOLE_NAV_TIMEOUT_MS = 18_000;
|
|
77
|
+
const CODEBUDDY_CN_CONSOLE_PROBE_TIMEOUT_MS = 10_000;
|
|
78
|
+
const CODEBUDDY_CN_API_KEY_REQUEST_TIMEOUT_MS = 60_000;
|
|
79
|
+
const CODEBUDDY_CN_OIDC_MAX_ATTEMPTS = 6;
|
|
80
|
+
const CODEBUDDY_CN_API_REHANDOFF_ROUNDS = 2;
|
|
81
|
+
const CODEBUDDY_CN_MANUAL_TIMEOUT_MS = 8 * 60_000;
|
|
82
|
+
const CODEBUDDY_CN_LOW_MEM_MANUAL_TIMEOUT_MS = 3 * 60_000;
|
|
83
|
+
const CODEBUDDY_CN_RESOURCE_CLOSE_TIMEOUT_MS = 5_000;
|
|
84
|
+
const CODEBUDDY_CN_FIVESIM_SETTLE_TIMEOUT_MS = 12_000;
|
|
85
|
+
const CODEBUDDY_CN_API_KEY_OUTCOME_UNKNOWN = "CN_API_KEY_OUTCOME_UNKNOWN";
|
|
86
|
+
const CODEBUDDY_CN_ACCOUNT_RESTRICTED = "CN_ACCOUNT_RESTRICTED";
|
|
73
87
|
|
|
74
88
|
// Supported 5sim regions
|
|
75
89
|
const SUPPORTED_REGIONS = new Set(["hongkong", "china", "any"]);
|
|
@@ -113,6 +127,199 @@ function clampCnConcurrency(value) {
|
|
|
113
127
|
return Math.min(hardMax, Math.max(CODEBUDDY_CN_MIN_CONCURRENCY, parsed));
|
|
114
128
|
}
|
|
115
129
|
|
|
130
|
+
async function withTimeoutCleanup(
|
|
131
|
+
task,
|
|
132
|
+
{
|
|
133
|
+
timeoutMs,
|
|
134
|
+
message,
|
|
135
|
+
code,
|
|
136
|
+
onTimeout,
|
|
137
|
+
onLateResolve,
|
|
138
|
+
},
|
|
139
|
+
) {
|
|
140
|
+
const operation = Promise.resolve(task);
|
|
141
|
+
let timer = null;
|
|
142
|
+
let timedOut = false;
|
|
143
|
+
const timeout = new Promise((_, reject) => {
|
|
144
|
+
timer = setTimeout(() => {
|
|
145
|
+
timedOut = true;
|
|
146
|
+
try {
|
|
147
|
+
if (typeof onTimeout === "function") onTimeout();
|
|
148
|
+
} catch {
|
|
149
|
+
// Timeout reporting must not be replaced by cleanup callback failures.
|
|
150
|
+
}
|
|
151
|
+
reject(Object.assign(new Error(message), { code }));
|
|
152
|
+
}, timeoutMs);
|
|
153
|
+
if (typeof timer.unref === "function") timer.unref();
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
try {
|
|
157
|
+
return await Promise.race([operation, timeout]);
|
|
158
|
+
} finally {
|
|
159
|
+
if (timer) clearTimeout(timer);
|
|
160
|
+
if (timedOut && typeof onLateResolve === "function") {
|
|
161
|
+
void operation.then(onLateResolve).catch(() => null);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function isLoginHtmlProbe(probe) {
|
|
167
|
+
const raw = `${probe?.text || ""} ${probe?.data?._raw || ""} ${probe?.url || ""}`;
|
|
168
|
+
return /<!doctype html|<html|login-pf|\/auth\/realms\//i.test(raw);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function parseConsoleProbeBody(status, text, extras = {}) {
|
|
172
|
+
const rawText = String(text || "");
|
|
173
|
+
let data = null;
|
|
174
|
+
try {
|
|
175
|
+
data = rawText ? JSON.parse(rawText) : null;
|
|
176
|
+
} catch {
|
|
177
|
+
data = { _raw: rawText.slice(0, 240), _notJson: true };
|
|
178
|
+
}
|
|
179
|
+
return {
|
|
180
|
+
status: Number(status) || 0,
|
|
181
|
+
data,
|
|
182
|
+
text: rawText.slice(0, 240),
|
|
183
|
+
...extras,
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function hasRestrictedConsoleEvidence(probe, cookieNames = []) {
|
|
188
|
+
const names = cookieNames instanceof Set ? cookieNames : new Set(cookieNames);
|
|
189
|
+
const raw = `${probe?.text || ""} ${probe?.data?._raw || ""}`;
|
|
190
|
+
if (/账号访问受限|安全策略限制|访问受限|account restricted|access restricted/i.test(raw)) {
|
|
191
|
+
return true;
|
|
192
|
+
}
|
|
193
|
+
if (!names.has("login_risk_state")) return false;
|
|
194
|
+
return isLoginHtmlProbe(probe)
|
|
195
|
+
|| probe?.status === 0
|
|
196
|
+
|| probe?.status === 401
|
|
197
|
+
|| probe?.status === 403;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
async function probeCodeBuddyConsoleAccounts({
|
|
201
|
+
context,
|
|
202
|
+
page,
|
|
203
|
+
timeoutMs = CODEBUDDY_CN_CONSOLE_PROBE_TIMEOUT_MS,
|
|
204
|
+
}) {
|
|
205
|
+
const headers = {
|
|
206
|
+
Accept: "application/json, text/plain, */*",
|
|
207
|
+
"x-requested-with": "XMLHttpRequest",
|
|
208
|
+
"X-Domain": "www.codebuddy.cn",
|
|
209
|
+
"X-Product": "SaaS",
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
// The context request shares browser cookies but bypasses page-origin CORS.
|
|
213
|
+
let requestContext = null;
|
|
214
|
+
try {
|
|
215
|
+
requestContext = context?.request || null;
|
|
216
|
+
} catch {
|
|
217
|
+
requestContext = null;
|
|
218
|
+
}
|
|
219
|
+
if (requestContext && typeof requestContext.get === "function") {
|
|
220
|
+
try {
|
|
221
|
+
const response = await requestContext.get(
|
|
222
|
+
"https://www.codebuddy.cn/console/accounts",
|
|
223
|
+
{ headers, timeout: timeoutMs, failOnStatusCode: false },
|
|
224
|
+
);
|
|
225
|
+
const text = await response.text().catch(() => "");
|
|
226
|
+
return parseConsoleProbeBody(response.status(), text, {
|
|
227
|
+
source: "context-request",
|
|
228
|
+
url: response.url(),
|
|
229
|
+
contentType: response.headers()?.["content-type"] || "",
|
|
230
|
+
});
|
|
231
|
+
} catch {
|
|
232
|
+
// Compatibility fallback for older CloakBrowser request contexts.
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
const probeTask = page.evaluate(async ({ requestTimeoutMs, requestHeaders }) => {
|
|
237
|
+
const controller = new AbortController();
|
|
238
|
+
const timer = setTimeout(() => controller.abort(), requestTimeoutMs);
|
|
239
|
+
try {
|
|
240
|
+
const host = window.location.hostname || "www.codebuddy.cn";
|
|
241
|
+
const base = host === "www.codebuddy.cn"
|
|
242
|
+
? `${window.location.origin}`
|
|
243
|
+
: "https://www.codebuddy.cn";
|
|
244
|
+
const response = await fetch(`${base}/console/accounts`, {
|
|
245
|
+
credentials: "include",
|
|
246
|
+
signal: controller.signal,
|
|
247
|
+
headers: requestHeaders,
|
|
248
|
+
});
|
|
249
|
+
const text = await response.text().catch(() => "");
|
|
250
|
+
let data = null;
|
|
251
|
+
try {
|
|
252
|
+
data = text ? JSON.parse(text) : null;
|
|
253
|
+
} catch {
|
|
254
|
+
data = { _raw: String(text || "").slice(0, 240), _notJson: true };
|
|
255
|
+
}
|
|
256
|
+
return {
|
|
257
|
+
status: response.status,
|
|
258
|
+
data,
|
|
259
|
+
text: String(text || "").slice(0, 240),
|
|
260
|
+
source: "page-fetch",
|
|
261
|
+
url: response.url,
|
|
262
|
+
contentType: response.headers.get("content-type") || "",
|
|
263
|
+
};
|
|
264
|
+
} catch (error) {
|
|
265
|
+
return {
|
|
266
|
+
status: 0,
|
|
267
|
+
timedOut: error?.name === "AbortError",
|
|
268
|
+
error: error?.message || String(error),
|
|
269
|
+
source: "page-fetch",
|
|
270
|
+
};
|
|
271
|
+
} finally {
|
|
272
|
+
clearTimeout(timer);
|
|
273
|
+
}
|
|
274
|
+
}, { requestTimeoutMs: timeoutMs, requestHeaders: headers });
|
|
275
|
+
|
|
276
|
+
return withTimeoutCleanup(probeTask, {
|
|
277
|
+
timeoutMs,
|
|
278
|
+
message: `Console account probe timed out after ${timeoutMs / 1000}s`,
|
|
279
|
+
code: "CN_CONSOLE_PROBE_TIMEOUT",
|
|
280
|
+
}).catch((error) => ({
|
|
281
|
+
status: 0,
|
|
282
|
+
timedOut: error?.code === "CN_CONSOLE_PROBE_TIMEOUT",
|
|
283
|
+
error: error?.message || String(error),
|
|
284
|
+
source: "page-fetch",
|
|
285
|
+
}));
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
async function closeResourceBounded(resource) {
|
|
289
|
+
if (!resource || typeof resource.close !== "function") return true;
|
|
290
|
+
try {
|
|
291
|
+
await withTimeoutCleanup(Promise.resolve().then(() => resource.close()), {
|
|
292
|
+
timeoutMs: CODEBUDDY_CN_RESOURCE_CLOSE_TIMEOUT_MS,
|
|
293
|
+
message: `Browser resource close timed out after ${CODEBUDDY_CN_RESOURCE_CLOSE_TIMEOUT_MS / 1000}s`,
|
|
294
|
+
code: "CN_RESOURCE_CLOSE_TIMEOUT",
|
|
295
|
+
});
|
|
296
|
+
return true;
|
|
297
|
+
} catch {
|
|
298
|
+
return false;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
async function closeContextOrBrowser(context, job) {
|
|
303
|
+
if (await closeResourceBounded(context)) return;
|
|
304
|
+
if (!job?.browser) return;
|
|
305
|
+
const browser = job.browser;
|
|
306
|
+
job.browser = null;
|
|
307
|
+
await forceCloseBrowser(browser).catch(() => null);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
async function settleFiveSimOrder(operation) {
|
|
311
|
+
try {
|
|
312
|
+
return await withTimeoutCleanup(Promise.resolve().then(operation), {
|
|
313
|
+
timeoutMs: CODEBUDDY_CN_FIVESIM_SETTLE_TIMEOUT_MS,
|
|
314
|
+
message: `5sim order settlement timed out after ${CODEBUDDY_CN_FIVESIM_SETTLE_TIMEOUT_MS / 1000}s`,
|
|
315
|
+
code: "CN_FIVESIM_SETTLE_TIMEOUT",
|
|
316
|
+
});
|
|
317
|
+
} catch {
|
|
318
|
+
// Finish/cancel/ban are best-effort and must not hold the browser worker.
|
|
319
|
+
return false;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
116
323
|
/**
|
|
117
324
|
* Save a CodeBuddy CN provider connection to the database.
|
|
118
325
|
*/
|
|
@@ -165,7 +372,10 @@ export class CodeBuddyCnBulkImportManager extends KiroBulkImportManager {
|
|
|
165
372
|
// CloakBrowser-only: proxy on launch + geoip. Headed by default (Turnstile/Tencent).
|
|
166
373
|
// Override: ZEVAI_CN_HEADLESS=0|1
|
|
167
374
|
const cnBrowserLauncher = browserLauncher || (async (job) => {
|
|
168
|
-
const {
|
|
375
|
+
const {
|
|
376
|
+
forceCloseBrowser,
|
|
377
|
+
launchBulkImportBrowser,
|
|
378
|
+
} = await import("./bulkImportBrowserEngine.js");
|
|
169
379
|
const proxyUrl = Array.isArray(job?.proxyUrls) && job.proxyUrls.length
|
|
170
380
|
? job.proxyUrls[0]
|
|
171
381
|
: null;
|
|
@@ -173,12 +383,18 @@ export class CodeBuddyCnBulkImportManager extends KiroBulkImportManager {
|
|
|
173
383
|
let headless = false;
|
|
174
384
|
if (envHeadless === "0" || envHeadless === "false") headless = false;
|
|
175
385
|
if (envHeadless === "1" || envHeadless === "true") headless = true;
|
|
176
|
-
|
|
386
|
+
const launchTask = launchBulkImportBrowser({
|
|
177
387
|
engine: job?.engine || "cloakbrowser",
|
|
178
388
|
proxyUrl,
|
|
179
389
|
headless,
|
|
180
390
|
windowSize: { width: 1280, height: 900 },
|
|
181
391
|
});
|
|
392
|
+
return withTimeoutCleanup(launchTask, {
|
|
393
|
+
timeoutMs: CODEBUDDY_CN_BROWSER_LAUNCH_TIMEOUT_MS,
|
|
394
|
+
message: `CloakBrowser launch timed out after ${CODEBUDDY_CN_BROWSER_LAUNCH_TIMEOUT_MS / 1000}s`,
|
|
395
|
+
code: "CN_BROWSER_LAUNCH_TIMEOUT",
|
|
396
|
+
onLateResolve: (browser) => forceCloseBrowser(browser),
|
|
397
|
+
});
|
|
182
398
|
});
|
|
183
399
|
super({ browserLauncher: cnBrowserLauncher, storageName });
|
|
184
400
|
this.requestDeviceCode = requestDeviceCodeFn;
|
|
@@ -358,10 +574,17 @@ export class CodeBuddyCnBulkImportManager extends KiroBulkImportManager {
|
|
|
358
574
|
// cause of 账号访问受限 right after OTP). Per-account fingerprint seed —
|
|
359
575
|
// sticky residential IP alone still clusters if every session shares HW.
|
|
360
576
|
if (!account.fingerprintSeed) account.fingerprintSeed = randomUUID();
|
|
361
|
-
const
|
|
577
|
+
const contextTask = createFreshContext(job.browser, account.proxyUrl, {
|
|
362
578
|
profile: "codebuddy-cn",
|
|
363
579
|
region: job.region || "hongkong",
|
|
364
580
|
fingerprintSeed: account.fingerprintSeed,
|
|
581
|
+
lowMemory: isLowMemHost(),
|
|
582
|
+
});
|
|
583
|
+
const freshContext = await withTimeoutCleanup(contextTask, {
|
|
584
|
+
timeoutMs: CODEBUDDY_CN_CONTEXT_TIMEOUT_MS,
|
|
585
|
+
message: `Browser context creation timed out after ${CODEBUDDY_CN_CONTEXT_TIMEOUT_MS / 1000}s`,
|
|
586
|
+
code: "CN_CONTEXT_TIMEOUT",
|
|
587
|
+
onLateResolve: (session) => Promise.resolve(session?.context?.close?.()).catch(() => null),
|
|
365
588
|
});
|
|
366
589
|
context = freshContext.context;
|
|
367
590
|
const page = freshContext.page;
|
|
@@ -470,24 +693,25 @@ export class CodeBuddyCnBulkImportManager extends KiroBulkImportManager {
|
|
|
470
693
|
// If automation failed early (e.g. page.goto timeout), the session won't be logged in
|
|
471
694
|
// and API key creation will 401 — so don't waste time. Only try bypass if automation
|
|
472
695
|
// reported "success" or "needs_manual" (meaning submit happened).
|
|
473
|
-
if (automationResult.status
|
|
696
|
+
if (String(automationResult.status || "").startsWith("failed")) {
|
|
474
697
|
// Automation failed before submit — no point trying API key
|
|
475
698
|
const errorMsg = automationResult.error || "Phone registration failed before submit";
|
|
476
|
-
|
|
699
|
+
const failureStatus = automationResult.status || "failed";
|
|
700
|
+
this.finalizeAccount(account, failureStatus, {
|
|
477
701
|
error: errorMsg,
|
|
478
|
-
step:
|
|
702
|
+
step: failureStatus,
|
|
479
703
|
message: errorMsg,
|
|
480
704
|
});
|
|
481
705
|
// Only touch 5sim if we actually bought a number (order is deferred until form ready)
|
|
482
706
|
if (fiveSimClient && fiveSimOrderId) {
|
|
483
707
|
if (smsReceived) {
|
|
484
|
-
await fiveSimClient.finishOrder(fiveSimOrderId);
|
|
708
|
+
await settleFiveSimOrder(() => fiveSimClient.finishOrder(fiveSimOrderId));
|
|
485
709
|
} else {
|
|
486
|
-
await fiveSimClient.cancelOrder(fiveSimOrderId);
|
|
710
|
+
await settleFiveSimOrder(() => fiveSimClient.cancelOrder(fiveSimOrderId));
|
|
487
711
|
}
|
|
488
712
|
}
|
|
489
713
|
account.runtimeSession = null;
|
|
490
|
-
await context
|
|
714
|
+
await closeContextOrBrowser(context, job);
|
|
491
715
|
await this.persistJobSnapshot(job, { forcePreview: true });
|
|
492
716
|
return;
|
|
493
717
|
}
|
|
@@ -510,19 +734,23 @@ export class CodeBuddyCnBulkImportManager extends KiroBulkImportManager {
|
|
|
510
734
|
// 5sim hygiene on error
|
|
511
735
|
if (fiveSimClient && fiveSimOrderId) {
|
|
512
736
|
if (smsReceived) {
|
|
513
|
-
await fiveSimClient.finishOrder(fiveSimOrderId);
|
|
737
|
+
await settleFiveSimOrder(() => fiveSimClient.finishOrder(fiveSimOrderId));
|
|
514
738
|
} else if (isSmsTimeout) {
|
|
515
|
-
// BAN: number
|
|
516
|
-
await fiveSimClient.banOrder(fiveSimOrderId);
|
|
739
|
+
// BAN: number did not receive CodeBuddy SMS within the OTP window.
|
|
740
|
+
await settleFiveSimOrder(() => fiveSimClient.banOrder(fiveSimOrderId));
|
|
517
741
|
} else {
|
|
518
|
-
await fiveSimClient.cancelOrder(fiveSimOrderId);
|
|
742
|
+
await settleFiveSimOrder(() => fiveSimClient.cancelOrder(fiveSimOrderId));
|
|
519
743
|
}
|
|
520
744
|
}
|
|
521
745
|
account.runtimeSession = null;
|
|
522
|
-
|
|
746
|
+
await closeContextOrBrowser(context, job);
|
|
523
747
|
// Hard timeout / blackhole nav: kill the shared browser so the worker unblocks
|
|
524
748
|
// and Chromium cannot pin 100% CPU on a 2GB VPS until reboot.
|
|
525
|
-
if (
|
|
749
|
+
if (
|
|
750
|
+
error?.code === "CN_ACCOUNT_HARD_TIMEOUT"
|
|
751
|
+
|| error?.code === "CN_CONTEXT_TIMEOUT"
|
|
752
|
+
|| job.cancelRequested
|
|
753
|
+
) {
|
|
526
754
|
if (job.browser) {
|
|
527
755
|
const b = job.browser;
|
|
528
756
|
job.browser = null;
|
|
@@ -592,34 +820,7 @@ export class CodeBuddyCnBulkImportManager extends KiroBulkImportManager {
|
|
|
592
820
|
|| names.has("qcmainCSRFToken")
|
|
593
821
|
|| names.has("x_host_key_access");
|
|
594
822
|
|
|
595
|
-
const probeConsoleAccounts =
|
|
596
|
-
try {
|
|
597
|
-
// Absolute URL — relative /console/accounts fails if we are still on login.tencent or keycloak host.
|
|
598
|
-
const host = window.location.hostname || "www.codebuddy.cn";
|
|
599
|
-
const base = host.endsWith("codebuddy.cn")
|
|
600
|
-
? `${window.location.origin}`
|
|
601
|
-
: "https://www.codebuddy.cn";
|
|
602
|
-
const res = await fetch(`${base}/console/accounts`, {
|
|
603
|
-
credentials: "include",
|
|
604
|
-
headers: {
|
|
605
|
-
Accept: "application/json, text/plain, */*",
|
|
606
|
-
"x-requested-with": "XMLHttpRequest",
|
|
607
|
-
"X-Domain": "www.codebuddy.cn",
|
|
608
|
-
"X-Product": "SaaS",
|
|
609
|
-
},
|
|
610
|
-
});
|
|
611
|
-
const text = await res.text().catch(() => "");
|
|
612
|
-
let data = null;
|
|
613
|
-
try {
|
|
614
|
-
data = text ? JSON.parse(text) : null;
|
|
615
|
-
} catch {
|
|
616
|
-
data = { _raw: String(text || "").slice(0, 240), _notJson: true };
|
|
617
|
-
}
|
|
618
|
-
return { status: res.status, data, text: String(text || "").slice(0, 240) };
|
|
619
|
-
} catch (error) {
|
|
620
|
-
return { status: 0, error: error?.message || String(error) };
|
|
621
|
-
}
|
|
622
|
-
}).catch(() => null);
|
|
823
|
+
const probeConsoleAccounts = () => probeCodeBuddyConsoleAccounts({ context, page });
|
|
623
824
|
|
|
624
825
|
const extractAccountList = (probe) => {
|
|
625
826
|
const d = probe?.data;
|
|
@@ -642,45 +843,63 @@ export class CodeBuddyCnBulkImportManager extends KiroBulkImportManager {
|
|
|
642
843
|
return [];
|
|
643
844
|
};
|
|
644
845
|
|
|
645
|
-
//
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
(
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
846
|
+
// A committed response is enough to start session probes. Waiting for the
|
|
847
|
+
// full SPA DOM is expensive and frequently stalls on small VPS hosts.
|
|
848
|
+
const waitAfterNav = async (timeoutMs = 2_500) => {
|
|
849
|
+
let settled = false;
|
|
850
|
+
let timer = null;
|
|
851
|
+
try {
|
|
852
|
+
await Promise.race([
|
|
853
|
+
page.waitForLoadState("domcontentloaded", { timeout: timeoutMs }).catch(() => null),
|
|
854
|
+
waitUntil(async () => {
|
|
855
|
+
if (settled) return true;
|
|
856
|
+
const snap = await cookieSnapshot();
|
|
857
|
+
return hasStrongKeycloak(snap.names);
|
|
858
|
+
}, { timeout: timeoutMs, interval: 200 }),
|
|
859
|
+
new Promise((resolve) => {
|
|
860
|
+
timer = setTimeout(resolve, timeoutMs);
|
|
861
|
+
}),
|
|
862
|
+
]);
|
|
863
|
+
} finally {
|
|
864
|
+
settled = true;
|
|
865
|
+
if (timer) clearTimeout(timer);
|
|
866
|
+
}
|
|
867
|
+
};
|
|
868
|
+
|
|
869
|
+
const navigateConsole = async (path) => {
|
|
870
|
+
const startedAt = Date.now();
|
|
871
|
+
try {
|
|
872
|
+
await page.goto(path, {
|
|
873
|
+
waitUntil: "commit",
|
|
874
|
+
timeout: CODEBUDDY_CN_CONSOLE_NAV_TIMEOUT_MS,
|
|
875
|
+
});
|
|
876
|
+
const remainingMs = CODEBUDDY_CN_CONSOLE_NAV_TIMEOUT_MS - (Date.now() - startedAt);
|
|
877
|
+
if (remainingMs > 0) await waitAfterNav(Math.min(2_500, remainingMs));
|
|
878
|
+
return true;
|
|
879
|
+
} catch {
|
|
880
|
+
return false;
|
|
881
|
+
}
|
|
662
882
|
};
|
|
663
883
|
|
|
664
884
|
// Navigate sequence to finish OIDC handoff when only AUTH_SESSION_ID is present.
|
|
665
|
-
//
|
|
885
|
+
// Never revisit /login here: it can wipe a valid partial OIDC session.
|
|
666
886
|
const oIDCNudgePaths = [
|
|
667
887
|
"https://www.codebuddy.cn/",
|
|
668
888
|
"https://www.codebuddy.cn/console",
|
|
669
889
|
"https://www.codebuddy.cn/console/",
|
|
670
890
|
"https://www.codebuddy.cn/profile",
|
|
671
891
|
"https://www.codebuddy.cn/profile/keys",
|
|
672
|
-
// only if still empty after console probes
|
|
673
|
-
"https://www.codebuddy.cn/login/",
|
|
674
892
|
];
|
|
675
893
|
|
|
676
894
|
let accountList = [];
|
|
677
895
|
let accountsProbe = null;
|
|
678
896
|
let sessionReady = false;
|
|
679
897
|
let lastPayloadSnippet = "";
|
|
898
|
+
let lastMeaningfulProbe = null;
|
|
899
|
+
let restrictedProbeCount = 0;
|
|
680
900
|
|
|
681
|
-
// Event-driven OIDC settle:
|
|
682
|
-
|
|
683
|
-
for (let attempt = 0; attempt < OIDC_MAX_ATTEMPTS; attempt += 1) {
|
|
901
|
+
// Event-driven OIDC settle: bounded attempts and no blind multi-second sleeps.
|
|
902
|
+
for (let attempt = 0; attempt < CODEBUDDY_CN_OIDC_MAX_ATTEMPTS; attempt += 1) {
|
|
684
903
|
if (job.cancelRequested) {
|
|
685
904
|
throw new Error("Job cancelled while establishing session");
|
|
686
905
|
}
|
|
@@ -697,31 +916,60 @@ export class CodeBuddyCnBulkImportManager extends KiroBulkImportManager {
|
|
|
697
916
|
this.setAccountStep(
|
|
698
917
|
account,
|
|
699
918
|
"waiting_session",
|
|
700
|
-
`OIDC handoff ${attempt + 1}/${
|
|
919
|
+
`OIDC handoff ${attempt + 1}/${CODEBUDDY_CN_OIDC_MAX_ATTEMPTS} → ${path.replace("https://www.codebuddy.cn", "")} (${strong ? "KEYCLOAK" : soft ? "soft-session" : "weak"})`,
|
|
701
920
|
);
|
|
702
921
|
await this.persistJobSnapshot(job, { forcePreview: false });
|
|
703
|
-
await
|
|
704
|
-
await waitAfterNav();
|
|
922
|
+
await navigateConsole(path);
|
|
705
923
|
} else {
|
|
706
924
|
// Soft session present — short yield then re-probe (no blind multi-second sleep).
|
|
707
925
|
await new Promise((r) => setTimeout(r, 300));
|
|
708
926
|
}
|
|
709
927
|
|
|
710
928
|
// Prefer landing on console for the API probe (absolute host)
|
|
711
|
-
const onCodebuddy =
|
|
712
|
-
if (!onCodebuddy
|
|
713
|
-
await
|
|
714
|
-
waitUntil: "domcontentloaded",
|
|
715
|
-
timeout: 25_000,
|
|
716
|
-
}).catch(() => null);
|
|
717
|
-
await waitAfterNav();
|
|
929
|
+
const onCodebuddy = /^https:\/\/www\.codebuddy\.cn(?:[/:]|$)/i.test(page.url?.() || "");
|
|
930
|
+
if (!onCodebuddy) {
|
|
931
|
+
await navigateConsole("https://www.codebuddy.cn/console");
|
|
718
932
|
}
|
|
719
933
|
|
|
720
934
|
accountsProbe = await probeConsoleAccounts();
|
|
721
935
|
accountList = extractAccountList(accountsProbe);
|
|
722
|
-
|
|
936
|
+
if (
|
|
937
|
+
accountsProbe?.status > 0
|
|
938
|
+
|| accountsProbe?.text
|
|
939
|
+
|| accountsProbe?.data
|
|
940
|
+
) {
|
|
941
|
+
lastMeaningfulProbe = accountsProbe;
|
|
942
|
+
}
|
|
943
|
+
lastPayloadSnippet = JSON.stringify(
|
|
944
|
+
accountsProbe?.data
|
|
945
|
+
?? accountsProbe?.text
|
|
946
|
+
?? accountsProbe?.error
|
|
947
|
+
?? null,
|
|
948
|
+
).slice(0, 180);
|
|
949
|
+
const loginHtml = isLoginHtmlProbe(accountsProbe);
|
|
950
|
+
const probeSnap = await cookieSnapshot();
|
|
951
|
+
const probeStrong = hasStrongKeycloak(probeSnap.names);
|
|
952
|
+
if (!probeStrong && hasRestrictedConsoleEvidence(accountsProbe, probeSnap.names)) {
|
|
953
|
+
restrictedProbeCount += 1;
|
|
954
|
+
} else {
|
|
955
|
+
restrictedProbeCount = 0;
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
if (restrictedProbeCount >= 2) {
|
|
959
|
+
throw Object.assign(
|
|
960
|
+
new Error(
|
|
961
|
+
`Tencent restricted the post-OTP session (${restrictedProbeCount} console probes returned login/risk evidence; source=${accountsProbe?.source || "unknown"})`,
|
|
962
|
+
),
|
|
963
|
+
{ code: CODEBUDDY_CN_ACCOUNT_RESTRICTED },
|
|
964
|
+
);
|
|
965
|
+
}
|
|
723
966
|
|
|
724
|
-
if (
|
|
967
|
+
if (
|
|
968
|
+
accountsProbe?.status === 200
|
|
969
|
+
&& !loginHtml
|
|
970
|
+
&& Array.isArray(accountList)
|
|
971
|
+
&& accountList.length > 0
|
|
972
|
+
) {
|
|
725
973
|
sessionReady = true;
|
|
726
974
|
this.setAccountStep(
|
|
727
975
|
account,
|
|
@@ -737,9 +985,11 @@ export class CodeBuddyCnBulkImportManager extends KiroBulkImportManager {
|
|
|
737
985
|
if (
|
|
738
986
|
soft
|
|
739
987
|
&& accountsProbe?.status === 200
|
|
988
|
+
&& !loginHtml
|
|
989
|
+
&& accountsProbe?.data?._notJson !== true
|
|
740
990
|
&& Array.isArray(accountList)
|
|
741
991
|
&& accountList.length === 0
|
|
742
|
-
&& attempt >=
|
|
992
|
+
&& attempt >= 3
|
|
743
993
|
) {
|
|
744
994
|
this.setAccountStep(
|
|
745
995
|
account,
|
|
@@ -754,15 +1004,23 @@ export class CodeBuddyCnBulkImportManager extends KiroBulkImportManager {
|
|
|
754
1004
|
this.setAccountStep(
|
|
755
1005
|
account,
|
|
756
1006
|
"resolving_enterprise",
|
|
757
|
-
`Console not ready (HTTP ${accountsProbe?.status || 0}, accounts=${accountList.length}) — ${attempt + 1}/${
|
|
1007
|
+
`Console not ready (HTTP ${accountsProbe?.status || 0}, accounts=${accountList.length}${loginHtml ? ", login HTML" : ""}, source=${accountsProbe?.source || "unknown"}) — ${attempt + 1}/${CODEBUDDY_CN_OIDC_MAX_ATTEMPTS} body=${lastPayloadSnippet.slice(0, 80)}`,
|
|
758
1008
|
);
|
|
759
1009
|
await this.persistJobSnapshot(job, { forcePreview: false });
|
|
760
1010
|
}
|
|
761
1011
|
|
|
762
1012
|
if (!sessionReady) {
|
|
763
1013
|
const snap = await cookieSnapshot();
|
|
764
|
-
|
|
765
|
-
|
|
1014
|
+
const diagnosticProbe = lastMeaningfulProbe || accountsProbe;
|
|
1015
|
+
const restricted = hasRestrictedConsoleEvidence(diagnosticProbe, snap.names)
|
|
1016
|
+
|| (snap.names.has("login_risk_state") && restrictedProbeCount > 0);
|
|
1017
|
+
throw Object.assign(
|
|
1018
|
+
new Error(
|
|
1019
|
+
restricted
|
|
1020
|
+
? `Tencent restricted the post-OTP session (HTTP ${diagnosticProbe?.status || 0}; login_risk_state present; source=${diagnosticProbe?.source || "unknown"})`
|
|
1021
|
+
: `Console accounts unavailable after login (HTTP ${diagnosticProbe?.status || 0}; cookies: ${snap.list.slice(0, 18).join(",") || "(none)"}; body=${lastPayloadSnippet.slice(0, 120)}; probeError=${accountsProbe?.error || "none"}) — session not accepted for API key`,
|
|
1022
|
+
),
|
|
1023
|
+
{ code: restricted ? CODEBUDDY_CN_ACCOUNT_RESTRICTED : "CN_CONSOLE_SESSION_UNAVAILABLE" },
|
|
766
1024
|
);
|
|
767
1025
|
}
|
|
768
1026
|
|
|
@@ -780,82 +1038,150 @@ export class CodeBuddyCnBulkImportManager extends KiroBulkImportManager {
|
|
|
780
1038
|
this.setAccountStep(account, "creating_api_key", `Creating API key (enterprise=${userEnterpriseId}, accounts=${accountList.length})`);
|
|
781
1039
|
await this.persistJobSnapshot(job, { forcePreview: true });
|
|
782
1040
|
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
Accept: "application/json, text/plain, */*",
|
|
794
|
-
"x-requested-with": "XMLHttpRequest",
|
|
795
|
-
"X-Domain": "www.codebuddy.cn",
|
|
796
|
-
"X-Product": "SaaS",
|
|
797
|
-
},
|
|
798
|
-
body: JSON.stringify({
|
|
799
|
-
name: `zevai-router-${Date.now()}`,
|
|
800
|
-
expire_in_days: 365,
|
|
801
|
-
user_enterprise_id: entId,
|
|
802
|
-
}),
|
|
803
|
-
});
|
|
804
|
-
const text = await res.text().catch(() => "");
|
|
805
|
-
let data = null;
|
|
1041
|
+
// Keep one name for every safe retry in this capture attempt. A timed-out
|
|
1042
|
+
// POST has an unknown outcome and must never be sent again automatically.
|
|
1043
|
+
const apiKeyName = `zevai-router-${account.workerId || "account"}-${Date.now()}`;
|
|
1044
|
+
const createKeyOnPage = async (enterpriseId) => page.evaluate(async ({
|
|
1045
|
+
enterpriseId: entId,
|
|
1046
|
+
keyName,
|
|
1047
|
+
timeoutMs,
|
|
1048
|
+
}) => {
|
|
1049
|
+
const controller = new AbortController();
|
|
1050
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
806
1051
|
try {
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
1052
|
+
const host = window.location.hostname || "www.codebuddy.cn";
|
|
1053
|
+
const base = host === "www.codebuddy.cn"
|
|
1054
|
+
? window.location.origin
|
|
1055
|
+
: "https://www.codebuddy.cn";
|
|
1056
|
+
const res = await fetch(`${base}/console/api/client/v1/api-keys`, {
|
|
1057
|
+
method: "POST",
|
|
1058
|
+
credentials: "include",
|
|
1059
|
+
signal: controller.signal,
|
|
1060
|
+
headers: {
|
|
1061
|
+
"Content-Type": "application/json",
|
|
1062
|
+
Accept: "application/json, text/plain, */*",
|
|
1063
|
+
"x-requested-with": "XMLHttpRequest",
|
|
1064
|
+
"X-Domain": "www.codebuddy.cn",
|
|
1065
|
+
"X-Product": "SaaS",
|
|
1066
|
+
},
|
|
1067
|
+
body: JSON.stringify({
|
|
1068
|
+
name: keyName,
|
|
1069
|
+
expire_in_days: 365,
|
|
1070
|
+
user_enterprise_id: entId,
|
|
1071
|
+
}),
|
|
1072
|
+
});
|
|
1073
|
+
const text = await res.text().catch(() => "");
|
|
1074
|
+
let data = null;
|
|
1075
|
+
try {
|
|
1076
|
+
data = text ? JSON.parse(text) : null;
|
|
1077
|
+
} catch {
|
|
1078
|
+
data = { _raw: String(text || "").slice(0, 200) };
|
|
1079
|
+
}
|
|
1080
|
+
return { ok: res.ok, status: res.status, data };
|
|
1081
|
+
} catch (error) {
|
|
1082
|
+
// Fetch/network failures after a POST starts are ambiguous: the server
|
|
1083
|
+
// may have created the key even if the browser lost the response.
|
|
1084
|
+
return {
|
|
1085
|
+
ok: false,
|
|
1086
|
+
status: 0,
|
|
1087
|
+
outcomeUnknown: true,
|
|
1088
|
+
timedOut: error?.name === "AbortError",
|
|
1089
|
+
error: error?.message || String(error),
|
|
1090
|
+
};
|
|
1091
|
+
} finally {
|
|
1092
|
+
clearTimeout(timer);
|
|
810
1093
|
}
|
|
811
|
-
|
|
812
|
-
|
|
1094
|
+
}, {
|
|
1095
|
+
enterpriseId,
|
|
1096
|
+
keyName: apiKeyName,
|
|
1097
|
+
timeoutMs: CODEBUDDY_CN_API_KEY_REQUEST_TIMEOUT_MS,
|
|
1098
|
+
});
|
|
1099
|
+
|
|
1100
|
+
const requestApiKey = async (enterpriseId, label) => {
|
|
1101
|
+
const startedAt = Date.now();
|
|
1102
|
+
let heartbeatPromise = null;
|
|
1103
|
+
const heartbeat = setInterval(() => {
|
|
1104
|
+
if (heartbeatPromise) return;
|
|
1105
|
+
const elapsedSeconds = Math.max(5, Math.round((Date.now() - startedAt) / 1000));
|
|
1106
|
+
this.setAccountStep(
|
|
1107
|
+
account,
|
|
1108
|
+
"creating_api_key",
|
|
1109
|
+
`${label} — waiting for CodeBuddy (${elapsedSeconds}s)`,
|
|
1110
|
+
);
|
|
1111
|
+
heartbeatPromise = this.persistJobSnapshot(job, { forcePreview: false })
|
|
1112
|
+
.catch(() => null)
|
|
1113
|
+
.finally(() => {
|
|
1114
|
+
heartbeatPromise = null;
|
|
1115
|
+
});
|
|
1116
|
+
}, 5_000);
|
|
1117
|
+
if (typeof heartbeat.unref === "function") heartbeat.unref();
|
|
1118
|
+
|
|
1119
|
+
let result;
|
|
1120
|
+
try {
|
|
1121
|
+
result = await withTimeoutCleanup(createKeyOnPage(enterpriseId), {
|
|
1122
|
+
timeoutMs: CODEBUDDY_CN_API_KEY_REQUEST_TIMEOUT_MS,
|
|
1123
|
+
message: `API key request timed out after ${CODEBUDDY_CN_API_KEY_REQUEST_TIMEOUT_MS / 1000}s; creation outcome is unknown`,
|
|
1124
|
+
code: CODEBUDDY_CN_API_KEY_OUTCOME_UNKNOWN,
|
|
1125
|
+
});
|
|
1126
|
+
} catch (error) {
|
|
1127
|
+
if (error?.code === CODEBUDDY_CN_API_KEY_OUTCOME_UNKNOWN) throw error;
|
|
1128
|
+
throw Object.assign(
|
|
1129
|
+
new Error(`API key request lost its response; creation outcome is unknown: ${error?.message || String(error)}`),
|
|
1130
|
+
{ code: CODEBUDDY_CN_API_KEY_OUTCOME_UNKNOWN },
|
|
1131
|
+
);
|
|
1132
|
+
} finally {
|
|
1133
|
+
clearInterval(heartbeat);
|
|
1134
|
+
if (heartbeatPromise) await heartbeatPromise.catch(() => null);
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1137
|
+
if (result?.outcomeUnknown) {
|
|
1138
|
+
const reason = result.timedOut
|
|
1139
|
+
? `timed out after ${CODEBUDDY_CN_API_KEY_REQUEST_TIMEOUT_MS / 1000}s`
|
|
1140
|
+
: `lost its response (${result.error || "network error"})`;
|
|
1141
|
+
throw Object.assign(
|
|
1142
|
+
new Error(`API key request ${reason}; creation outcome is unknown`),
|
|
1143
|
+
{ code: CODEBUDDY_CN_API_KEY_OUTCOME_UNKNOWN },
|
|
1144
|
+
);
|
|
1145
|
+
}
|
|
1146
|
+
return result;
|
|
1147
|
+
};
|
|
813
1148
|
|
|
814
1149
|
// Always open keys page first (SPA hydrates CSRF / host-key there).
|
|
815
|
-
await
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
1150
|
+
const keysPageReady = await navigateConsole("https://www.codebuddy.cn/profile/keys");
|
|
1151
|
+
if (!keysPageReady) {
|
|
1152
|
+
throw Object.assign(
|
|
1153
|
+
new Error(`Keys page navigation timed out after ${CODEBUDDY_CN_CONSOLE_NAV_TIMEOUT_MS / 1000}s`),
|
|
1154
|
+
{ code: "CN_CONSOLE_NAV_TIMEOUT" },
|
|
1155
|
+
);
|
|
1156
|
+
}
|
|
820
1157
|
|
|
821
|
-
let apiKeyResult = await
|
|
1158
|
+
let apiKeyResult = await requestApiKey(userEnterpriseId, "Creating API key");
|
|
822
1159
|
|
|
823
|
-
//
|
|
1160
|
+
// A confirmed 400 can safely retry with the personal enterprise id. Do
|
|
1161
|
+
// not retry 5xx/network failures because the POST outcome is ambiguous.
|
|
824
1162
|
if (
|
|
825
|
-
|
|
1163
|
+
apiKeyResult?.status === 400
|
|
826
1164
|
&& userEnterpriseId !== PERSONAL_ENTERPRISE_ID
|
|
827
1165
|
) {
|
|
828
1166
|
this.setAccountStep(account, "retrying_api_key", "Retrying with personal-edition enterprise id");
|
|
829
1167
|
await this.persistJobSnapshot(job, { forcePreview: false });
|
|
830
|
-
apiKeyResult = await
|
|
831
|
-
}
|
|
832
|
-
|
|
833
|
-
// Retry from console root if keys page POST failed.
|
|
834
|
-
if (!apiKeyResult || !apiKeyResult.ok) {
|
|
835
|
-
this.setAccountStep(account, "retrying_api_key", "Retrying API key from /console");
|
|
836
|
-
await this.persistJobSnapshot(job, { forcePreview: true });
|
|
837
|
-
await page.goto("https://www.codebuddy.cn/console", {
|
|
838
|
-
waitUntil: "domcontentloaded",
|
|
839
|
-
timeout: 45_000,
|
|
840
|
-
}).catch(() => null);
|
|
841
|
-
await waitAfterNav();
|
|
842
|
-
await page.goto("https://www.codebuddy.cn/profile/keys", {
|
|
843
|
-
waitUntil: "domcontentloaded",
|
|
844
|
-
timeout: 45_000,
|
|
845
|
-
}).catch(() => null);
|
|
846
|
-
await waitAfterNav();
|
|
847
|
-
apiKeyResult = await createKeyOnPage(PERSONAL_ENTERPRISE_ID).catch(() => null);
|
|
1168
|
+
apiKeyResult = await requestApiKey(PERSONAL_ENTERPRISE_ID, "Retrying personal API key");
|
|
848
1169
|
}
|
|
849
1170
|
|
|
850
1171
|
// Retry loop on 401/403 — openresty edge blocks create-key when Keycloak
|
|
851
1172
|
// cookies are half-synced (common on slow proxies). Nudge OIDC handoff,
|
|
852
|
-
// wait for strong session, then retry
|
|
853
|
-
const isAuthBlocked = (
|
|
854
|
-
|
|
1173
|
+
// wait for strong session, then retry with a strict round cap.
|
|
1174
|
+
const isAuthBlocked = (result) =>
|
|
1175
|
+
result?.ok === false && (result.status === 401 || result.status === 403);
|
|
1176
|
+
for (
|
|
1177
|
+
let round = 1;
|
|
1178
|
+
round <= CODEBUDDY_CN_API_REHANDOFF_ROUNDS && isAuthBlocked(apiKeyResult);
|
|
1179
|
+
round += 1
|
|
1180
|
+
) {
|
|
855
1181
|
this.setAccountStep(
|
|
856
1182
|
account,
|
|
857
1183
|
"retrying_api_key",
|
|
858
|
-
`API key 401/403 — OIDC re-handoff round ${round}
|
|
1184
|
+
`API key 401/403 — OIDC re-handoff round ${round}/${CODEBUDDY_CN_API_REHANDOFF_ROUNDS} (waiting strong session)`,
|
|
859
1185
|
);
|
|
860
1186
|
await this.persistJobSnapshot(job, { forcePreview: true });
|
|
861
1187
|
for (const path of [
|
|
@@ -863,15 +1189,17 @@ export class CodeBuddyCnBulkImportManager extends KiroBulkImportManager {
|
|
|
863
1189
|
"https://www.codebuddy.cn/console",
|
|
864
1190
|
"https://www.codebuddy.cn/profile/keys",
|
|
865
1191
|
]) {
|
|
866
|
-
await
|
|
867
|
-
await waitAfterNav();
|
|
1192
|
+
await navigateConsole(path);
|
|
868
1193
|
}
|
|
869
1194
|
// Wait for strong Keycloak cookie — openresty accepts api-keys only after full session.
|
|
870
1195
|
await waitUntil(async () => {
|
|
871
1196
|
const snap = await cookieSnapshot();
|
|
872
1197
|
return hasStrongKeycloak(snap.names);
|
|
873
1198
|
}, { timeout: 8_000 * round, interval: 300 }).catch(() => null);
|
|
874
|
-
apiKeyResult = await
|
|
1199
|
+
apiKeyResult = await requestApiKey(
|
|
1200
|
+
PERSONAL_ENTERPRISE_ID,
|
|
1201
|
+
`Retrying API key after OIDC handoff ${round}/${CODEBUDDY_CN_API_REHANDOFF_ROUNDS}`,
|
|
1202
|
+
);
|
|
875
1203
|
}
|
|
876
1204
|
|
|
877
1205
|
const businessCode = apiKeyResult?.data?.code;
|
|
@@ -904,8 +1232,9 @@ export class CodeBuddyCnBulkImportManager extends KiroBulkImportManager {
|
|
|
904
1232
|
apiKeyResult.data.secret;
|
|
905
1233
|
|
|
906
1234
|
if (!apiKey || typeof apiKey !== "string") {
|
|
907
|
-
throw
|
|
908
|
-
`API key response did not contain a key field: ${JSON.stringify(apiKeyResult.data).slice(0, 300)}
|
|
1235
|
+
throw Object.assign(
|
|
1236
|
+
new Error(`API key response did not contain a key field; creation outcome is unknown: ${JSON.stringify(apiKeyResult.data).slice(0, 300)}`),
|
|
1237
|
+
{ code: CODEBUDDY_CN_API_KEY_OUTCOME_UNKNOWN },
|
|
909
1238
|
);
|
|
910
1239
|
}
|
|
911
1240
|
|
|
@@ -925,7 +1254,7 @@ export class CodeBuddyCnBulkImportManager extends KiroBulkImportManager {
|
|
|
925
1254
|
});
|
|
926
1255
|
|
|
927
1256
|
// Step 10: Finish 5sim order + finalize
|
|
928
|
-
await fiveSimClient.finishOrder(fiveSimOrderId);
|
|
1257
|
+
await settleFiveSimOrder(() => fiveSimClient.finishOrder(fiveSimOrderId));
|
|
929
1258
|
|
|
930
1259
|
this.finalizeAccount(account, "success", {
|
|
931
1260
|
connectionId: connection.id,
|
|
@@ -933,21 +1262,48 @@ export class CodeBuddyCnBulkImportManager extends KiroBulkImportManager {
|
|
|
933
1262
|
message: `CodeBuddy CN connection saved (phone: ${account.phone})`,
|
|
934
1263
|
});
|
|
935
1264
|
account.runtimeSession = null;
|
|
936
|
-
await context
|
|
1265
|
+
await closeContextOrBrowser(context, job);
|
|
937
1266
|
await this.persistJobSnapshot(job, { forcePreview: true });
|
|
938
1267
|
} catch (error) {
|
|
939
1268
|
// If API key capture fails after registration, the account is registered
|
|
940
1269
|
// but we don't have a key. Surface as needs_manual so the operator can
|
|
941
1270
|
// create the key manually in the opened browser — number is NOT re-bought.
|
|
1271
|
+
const restricted = error?.code === CODEBUDDY_CN_ACCOUNT_RESTRICTED;
|
|
1272
|
+
const outcomeUnknown = error?.code === CODEBUDDY_CN_API_KEY_OUTCOME_UNKNOWN;
|
|
1273
|
+
if (restricted) {
|
|
1274
|
+
this.finalizeAccount(account, "failed_restricted", {
|
|
1275
|
+
error: `${error.message}. Use a different residential CN/HK proxy with concurrency 1.`,
|
|
1276
|
+
step: "failed_restricted",
|
|
1277
|
+
message: "Tencent restricted the post-OTP session; API-key capture was not attempted",
|
|
1278
|
+
});
|
|
1279
|
+
await settleFiveSimOrder(() => fiveSimClient.finishOrder(fiveSimOrderId));
|
|
1280
|
+
account.runtimeSession = null;
|
|
1281
|
+
await closeContextOrBrowser(context, job);
|
|
1282
|
+
await this.persistJobSnapshot(job, { forcePreview: true });
|
|
1283
|
+
return;
|
|
1284
|
+
}
|
|
1285
|
+
const failureMessage = outcomeUnknown
|
|
1286
|
+
? `${error.message}. Check the CodeBuddy keys page before creating another key.`
|
|
1287
|
+
: error.message;
|
|
942
1288
|
this.finalizeAccount(account, "needs_manual", {
|
|
943
|
-
error: `Registration succeeded but API key capture failed: ${
|
|
944
|
-
step: "awaiting_manual",
|
|
945
|
-
message:
|
|
1289
|
+
error: `Registration succeeded but API key capture failed: ${failureMessage}`,
|
|
1290
|
+
step: outcomeUnknown ? "api_key_outcome_unknown" : "awaiting_manual",
|
|
1291
|
+
message: outcomeUnknown
|
|
1292
|
+
? `Registration done; API key request outcome is unknown. Check existing keys before retrying.`
|
|
1293
|
+
: `Registration done, API key capture failed: ${error.message}`,
|
|
946
1294
|
});
|
|
947
1295
|
// The 5sim order was successful (SMS received) — finish it (no re-order)
|
|
948
|
-
await fiveSimClient.finishOrder(fiveSimOrderId)
|
|
1296
|
+
await settleFiveSimOrder(() => fiveSimClient.finishOrder(fiveSimOrderId));
|
|
949
1297
|
await this.persistJobSnapshot(job, { forcePreview: true });
|
|
950
1298
|
|
|
1299
|
+
if (outcomeUnknown) {
|
|
1300
|
+
// Closing the page aborts any late browser work. Automatic/manual POST
|
|
1301
|
+
// retries are intentionally disabled because the key may already exist.
|
|
1302
|
+
account.runtimeSession = null;
|
|
1303
|
+
await closeContextOrBrowser(context, job);
|
|
1304
|
+
return;
|
|
1305
|
+
}
|
|
1306
|
+
|
|
951
1307
|
// Start manual followup for API key capture (reuse same browser session)
|
|
952
1308
|
await this.runCnManualFollowup(job, account, account.workerId, context, page, fiveSimClient, fiveSimOrderId);
|
|
953
1309
|
}
|
|
@@ -963,18 +1319,21 @@ export class CodeBuddyCnBulkImportManager extends KiroBulkImportManager {
|
|
|
963
1319
|
const ms = account.manualSession;
|
|
964
1320
|
const ctx = ms?.context || context;
|
|
965
1321
|
const headed = ms?.headedBrowser || null;
|
|
966
|
-
|
|
967
|
-
if (headed) await headed
|
|
1322
|
+
await closeContextOrBrowser(ctx, job);
|
|
1323
|
+
if (headed) await forceCloseBrowser(headed).catch(() => null);
|
|
968
1324
|
};
|
|
969
1325
|
|
|
970
1326
|
try {
|
|
971
1327
|
this.setAccountStep(account, "manual_waiting", "Waiting for operator to complete in headed browser");
|
|
972
1328
|
await this.persistJobSnapshot(job, { forcePreview: true });
|
|
973
1329
|
|
|
974
|
-
// Wait
|
|
975
|
-
|
|
976
|
-
|
|
1330
|
+
// Wait up to 3 minutes on low-memory hosts, otherwise 8 minutes.
|
|
1331
|
+
const manualTimeoutMs = isLowMemHost()
|
|
1332
|
+
? CODEBUDDY_CN_LOW_MEM_MANUAL_TIMEOUT_MS
|
|
1333
|
+
: CODEBUDDY_CN_MANUAL_TIMEOUT_MS;
|
|
1334
|
+
const deadline = Date.now() + manualTimeoutMs;
|
|
977
1335
|
let apiKey = null;
|
|
1336
|
+
const manualApiKeyName = `zevai-router-manual-${account.workerId || "account"}-${Date.now()}`;
|
|
978
1337
|
|
|
979
1338
|
while (Date.now() < deadline && !job.cancelRequested) {
|
|
980
1339
|
await new Promise((r) => setTimeout(r, 10_000)); // Check every 10s
|
|
@@ -985,28 +1344,60 @@ export class CodeBuddyCnBulkImportManager extends KiroBulkImportManager {
|
|
|
985
1344
|
if (!currentUrl.includes("codebuddy.cn")) continue;
|
|
986
1345
|
|
|
987
1346
|
// Try to create an API key via the console API (include enterprise id)
|
|
988
|
-
const result = await page.evaluate(async () => {
|
|
989
|
-
const
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1347
|
+
const result = await withTimeoutCleanup(page.evaluate(async ({ keyName, timeoutMs }) => {
|
|
1348
|
+
const controller = new AbortController();
|
|
1349
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
1350
|
+
try {
|
|
1351
|
+
const host = window.location.hostname || "www.codebuddy.cn";
|
|
1352
|
+
const base = host === "www.codebuddy.cn"
|
|
1353
|
+
? window.location.origin
|
|
1354
|
+
: "https://www.codebuddy.cn";
|
|
1355
|
+
const res = await fetch(`${base}/console/api/client/v1/api-keys`, {
|
|
1356
|
+
method: "POST",
|
|
1357
|
+
headers: {
|
|
1358
|
+
"Content-Type": "application/json",
|
|
1359
|
+
Accept: "application/json, text/plain, */*",
|
|
1360
|
+
"x-requested-with": "XMLHttpRequest",
|
|
1361
|
+
"X-Domain": "www.codebuddy.cn",
|
|
1362
|
+
"X-Product": "SaaS",
|
|
1363
|
+
},
|
|
1364
|
+
credentials: "include",
|
|
1365
|
+
signal: controller.signal,
|
|
1366
|
+
body: JSON.stringify({
|
|
1367
|
+
name: keyName,
|
|
1368
|
+
expire_in_days: 365,
|
|
1369
|
+
user_enterprise_id: "personal-edition-user-id",
|
|
1370
|
+
}),
|
|
1371
|
+
});
|
|
1372
|
+
const data = await res.json().catch(() => null);
|
|
1373
|
+
return { ok: res.ok, status: res.status, data };
|
|
1374
|
+
} catch (error) {
|
|
1375
|
+
return {
|
|
1376
|
+
ok: false,
|
|
1377
|
+
status: 0,
|
|
1378
|
+
outcomeUnknown: true,
|
|
1379
|
+
error: error?.message || String(error),
|
|
1380
|
+
};
|
|
1381
|
+
} finally {
|
|
1382
|
+
clearTimeout(timer);
|
|
1383
|
+
}
|
|
1384
|
+
}, {
|
|
1385
|
+
keyName: manualApiKeyName,
|
|
1386
|
+
timeoutMs: CODEBUDDY_CN_API_KEY_REQUEST_TIMEOUT_MS,
|
|
1387
|
+
}), {
|
|
1388
|
+
timeoutMs: CODEBUDDY_CN_API_KEY_REQUEST_TIMEOUT_MS,
|
|
1389
|
+
message: "Manual API key request timed out; creation outcome is unknown",
|
|
1390
|
+
code: CODEBUDDY_CN_API_KEY_OUTCOME_UNKNOWN,
|
|
1007
1391
|
});
|
|
1008
1392
|
|
|
1009
|
-
if (result?.
|
|
1393
|
+
if (result?.outcomeUnknown) {
|
|
1394
|
+
throw Object.assign(
|
|
1395
|
+
new Error(`Manual API key request lost its response; creation outcome is unknown: ${result.error || "network error"}`),
|
|
1396
|
+
{ code: CODEBUDDY_CN_API_KEY_OUTCOME_UNKNOWN },
|
|
1397
|
+
);
|
|
1398
|
+
}
|
|
1399
|
+
|
|
1400
|
+
if (result?.ok) {
|
|
1010
1401
|
const payload = result.data?.data || result.data;
|
|
1011
1402
|
apiKey =
|
|
1012
1403
|
payload?.apiKey ||
|
|
@@ -1016,8 +1407,13 @@ export class CodeBuddyCnBulkImportManager extends KiroBulkImportManager {
|
|
|
1016
1407
|
payload?.api_key ||
|
|
1017
1408
|
(typeof payload === "string" ? payload : null);
|
|
1018
1409
|
if (apiKey && typeof apiKey === "string") break;
|
|
1410
|
+
throw Object.assign(
|
|
1411
|
+
new Error("Manual API key response was successful but did not contain the key; creation outcome is unknown"),
|
|
1412
|
+
{ code: CODEBUDDY_CN_API_KEY_OUTCOME_UNKNOWN },
|
|
1413
|
+
);
|
|
1019
1414
|
}
|
|
1020
|
-
} catch {
|
|
1415
|
+
} catch (error) {
|
|
1416
|
+
if (error?.code === CODEBUDDY_CN_API_KEY_OUTCOME_UNKNOWN) throw error;
|
|
1021
1417
|
// Operator might still be completing — keep waiting
|
|
1022
1418
|
}
|
|
1023
1419
|
}
|
|
@@ -1061,6 +1457,12 @@ export class CodeBuddyCnBulkImportManager extends KiroBulkImportManager {
|
|
|
1061
1457
|
step: "cancelled",
|
|
1062
1458
|
message: "Job cancelled while waiting for manual completion",
|
|
1063
1459
|
});
|
|
1460
|
+
} else if (error?.code === CODEBUDDY_CN_API_KEY_OUTCOME_UNKNOWN) {
|
|
1461
|
+
this.finalizeAccount(account, "needs_manual", {
|
|
1462
|
+
error: `${error.message}. Check existing CodeBuddy keys before retrying.`,
|
|
1463
|
+
step: "api_key_outcome_unknown",
|
|
1464
|
+
message: "Manual API key request outcome is unknown; automatic retries stopped",
|
|
1465
|
+
});
|
|
1064
1466
|
} else {
|
|
1065
1467
|
this.finalizeAccount(account, "failed", {
|
|
1066
1468
|
error: error.message || "Manual assist flow failed",
|
|
@@ -1150,7 +1552,7 @@ function buildCnSummary(accounts = []) {
|
|
|
1150
1552
|
if (status === "success") {
|
|
1151
1553
|
summary.success += 1;
|
|
1152
1554
|
summary.completed += 1;
|
|
1153
|
-
} else if (status
|
|
1555
|
+
} else if (status.startsWith("failed")) {
|
|
1154
1556
|
summary.failed += 1;
|
|
1155
1557
|
summary.completed += 1;
|
|
1156
1558
|
} else if (status === "needs_manual") {
|
|
@@ -1244,4 +1646,24 @@ export const __test__ = {
|
|
|
1244
1646
|
sanitizeCnJob,
|
|
1245
1647
|
defaultPhoneFormatter,
|
|
1246
1648
|
defaultSaveCodeBuddyCnConnection,
|
|
1649
|
+
buildCnSummary,
|
|
1650
|
+
hasRestrictedConsoleEvidence,
|
|
1651
|
+
isLoginHtmlProbe,
|
|
1652
|
+
parseConsoleProbeBody,
|
|
1653
|
+
probeCodeBuddyConsoleAccounts,
|
|
1654
|
+
withTimeoutCleanup,
|
|
1655
|
+
AUTOMATION_LIMITS: {
|
|
1656
|
+
registrationHardTimeoutMs: CODEBUDDY_CN_ACCOUNT_HARD_TIMEOUT_MS,
|
|
1657
|
+
browserLaunchTimeoutMs: CODEBUDDY_CN_BROWSER_LAUNCH_TIMEOUT_MS,
|
|
1658
|
+
contextTimeoutMs: CODEBUDDY_CN_CONTEXT_TIMEOUT_MS,
|
|
1659
|
+
consoleNavTimeoutMs: CODEBUDDY_CN_CONSOLE_NAV_TIMEOUT_MS,
|
|
1660
|
+
consoleProbeTimeoutMs: CODEBUDDY_CN_CONSOLE_PROBE_TIMEOUT_MS,
|
|
1661
|
+
apiKeyRequestTimeoutMs: CODEBUDDY_CN_API_KEY_REQUEST_TIMEOUT_MS,
|
|
1662
|
+
oidcMaxAttempts: CODEBUDDY_CN_OIDC_MAX_ATTEMPTS,
|
|
1663
|
+
apiRehandoffRounds: CODEBUDDY_CN_API_REHANDOFF_ROUNDS,
|
|
1664
|
+
manualTimeoutMs: CODEBUDDY_CN_MANUAL_TIMEOUT_MS,
|
|
1665
|
+
lowMemoryManualTimeoutMs: CODEBUDDY_CN_LOW_MEM_MANUAL_TIMEOUT_MS,
|
|
1666
|
+
resourceCloseTimeoutMs: CODEBUDDY_CN_RESOURCE_CLOSE_TIMEOUT_MS,
|
|
1667
|
+
fiveSimSettleTimeoutMs: CODEBUDDY_CN_FIVESIM_SETTLE_TIMEOUT_MS,
|
|
1668
|
+
},
|
|
1247
1669
|
};
|