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.
Files changed (318) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/cli/app/.next-cli-build/BUILD_ID +1 -1
  3. package/cli/app/.next-cli-build/app-path-routes-manifest.json +10 -10
  4. package/cli/app/.next-cli-build/build-manifest.json +2 -2
  5. package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/automation/page_client-reference-manifest.js +1 -1
  6. package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/basic-chat/page_client-reference-manifest.js +1 -1
  7. package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/cli-tools/[toolId]/page_client-reference-manifest.js +1 -1
  8. package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/cli-tools/page_client-reference-manifest.js +1 -1
  9. package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/combos/page_client-reference-manifest.js +1 -1
  10. package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/console-log/page_client-reference-manifest.js +1 -1
  11. package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/context/page_client-reference-manifest.js +1 -1
  12. package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/endpoint/page_client-reference-manifest.js +1 -1
  13. package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/media-providers/[kind]/[id]/page_client-reference-manifest.js +1 -1
  14. package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/media-providers/[kind]/page_client-reference-manifest.js +1 -1
  15. package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/media-providers/combo/[id]/page_client-reference-manifest.js +1 -1
  16. package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/media-providers/web/page_client-reference-manifest.js +1 -1
  17. package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/mitm/page_client-reference-manifest.js +1 -1
  18. package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/page_client-reference-manifest.js +1 -1
  19. package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/playground/page_client-reference-manifest.js +1 -1
  20. package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/profile/page_client-reference-manifest.js +1 -1
  21. package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/providers/[id]/page_client-reference-manifest.js +1 -1
  22. package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/providers/new/page_client-reference-manifest.js +1 -1
  23. package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/providers/page_client-reference-manifest.js +1 -1
  24. package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/proxy-pools/page_client-reference-manifest.js +1 -1
  25. package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/pxpipe/page_client-reference-manifest.js +1 -1
  26. package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/quota/page_client-reference-manifest.js +1 -1
  27. package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/terminal/page_client-reference-manifest.js +1 -1
  28. package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/token-saver/page_client-reference-manifest.js +1 -1
  29. package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/translator/page_client-reference-manifest.js +1 -1
  30. package/cli/app/.next-cli-build/server/app/(dashboard)/dashboard/usage/page_client-reference-manifest.js +1 -1
  31. package/cli/app/.next-cli-build/server/app/_global-error/page_client-reference-manifest.js +1 -1
  32. package/cli/app/.next-cli-build/server/app/_global-error.html +1 -1
  33. package/cli/app/.next-cli-build/server/app/_global-error.rsc +1 -1
  34. package/cli/app/.next-cli-build/server/app/_global-error.segments/_full.segment.rsc +1 -1
  35. package/cli/app/.next-cli-build/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  36. package/cli/app/.next-cli-build/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  37. package/cli/app/.next-cli-build/server/app/_global-error.segments/_head.segment.rsc +1 -1
  38. package/cli/app/.next-cli-build/server/app/_global-error.segments/_index.segment.rsc +1 -1
  39. package/cli/app/.next-cli-build/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  40. package/cli/app/.next-cli-build/server/app/_not-found/page_client-reference-manifest.js +1 -1
  41. package/cli/app/.next-cli-build/server/app/_not-found.html +1 -1
  42. package/cli/app/.next-cli-build/server/app/_not-found.rsc +3 -3
  43. package/cli/app/.next-cli-build/server/app/_not-found.segments/_full.segment.rsc +3 -3
  44. package/cli/app/.next-cli-build/server/app/_not-found.segments/_head.segment.rsc +1 -1
  45. package/cli/app/.next-cli-build/server/app/_not-found.segments/_index.segment.rsc +3 -3
  46. package/cli/app/.next-cli-build/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  47. package/cli/app/.next-cli-build/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  48. package/cli/app/.next-cli-build/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  49. package/cli/app/.next-cli-build/server/app/api/models/route.js +1 -1
  50. package/cli/app/.next-cli-build/server/app/api/providers/route.js +1 -1
  51. package/cli/app/.next-cli-build/server/app/api/providers/validate/route.js +1 -1
  52. package/cli/app/.next-cli-build/server/app/api/translator/console-logs/route.js +1 -1
  53. package/cli/app/.next-cli-build/server/app/api/translator/console-logs/stream/route.js +1 -1
  54. package/cli/app/.next-cli-build/server/app/api/version/route.js +1 -1
  55. package/cli/app/.next-cli-build/server/app/api/version/shutdown/route.js +1 -1
  56. package/cli/app/.next-cli-build/server/app/api/version/update/route.js +1 -1
  57. package/cli/app/.next-cli-build/server/app/callback/page_client-reference-manifest.js +1 -1
  58. package/cli/app/.next-cli-build/server/app/callback.html +1 -1
  59. package/cli/app/.next-cli-build/server/app/callback.rsc +3 -3
  60. package/cli/app/.next-cli-build/server/app/callback.segments/_full.segment.rsc +3 -3
  61. package/cli/app/.next-cli-build/server/app/callback.segments/_head.segment.rsc +1 -1
  62. package/cli/app/.next-cli-build/server/app/callback.segments/_index.segment.rsc +3 -3
  63. package/cli/app/.next-cli-build/server/app/callback.segments/_tree.segment.rsc +1 -1
  64. package/cli/app/.next-cli-build/server/app/callback.segments/callback/__PAGE__.segment.rsc +1 -1
  65. package/cli/app/.next-cli-build/server/app/callback.segments/callback.segment.rsc +1 -1
  66. package/cli/app/.next-cli-build/server/app/dashboard/automation.html +1 -1
  67. package/cli/app/.next-cli-build/server/app/dashboard/automation.rsc +5 -5
  68. package/cli/app/.next-cli-build/server/app/dashboard/automation.segments/!KGRhc2hib2FyZCk/dashboard/automation/__PAGE__.segment.rsc +2 -2
  69. package/cli/app/.next-cli-build/server/app/dashboard/automation.segments/!KGRhc2hib2FyZCk/dashboard/automation.segment.rsc +1 -1
  70. package/cli/app/.next-cli-build/server/app/dashboard/automation.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  71. package/cli/app/.next-cli-build/server/app/dashboard/automation.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  72. package/cli/app/.next-cli-build/server/app/dashboard/automation.segments/_full.segment.rsc +5 -5
  73. package/cli/app/.next-cli-build/server/app/dashboard/automation.segments/_head.segment.rsc +1 -1
  74. package/cli/app/.next-cli-build/server/app/dashboard/automation.segments/_index.segment.rsc +3 -3
  75. package/cli/app/.next-cli-build/server/app/dashboard/automation.segments/_tree.segment.rsc +1 -1
  76. package/cli/app/.next-cli-build/server/app/dashboard/basic-chat.html +1 -1
  77. package/cli/app/.next-cli-build/server/app/dashboard/basic-chat.rsc +5 -5
  78. package/cli/app/.next-cli-build/server/app/dashboard/basic-chat.segments/!KGRhc2hib2FyZCk/dashboard/basic-chat/__PAGE__.segment.rsc +2 -2
  79. package/cli/app/.next-cli-build/server/app/dashboard/basic-chat.segments/!KGRhc2hib2FyZCk/dashboard/basic-chat.segment.rsc +1 -1
  80. package/cli/app/.next-cli-build/server/app/dashboard/basic-chat.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  81. package/cli/app/.next-cli-build/server/app/dashboard/basic-chat.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  82. package/cli/app/.next-cli-build/server/app/dashboard/basic-chat.segments/_full.segment.rsc +5 -5
  83. package/cli/app/.next-cli-build/server/app/dashboard/basic-chat.segments/_head.segment.rsc +1 -1
  84. package/cli/app/.next-cli-build/server/app/dashboard/basic-chat.segments/_index.segment.rsc +3 -3
  85. package/cli/app/.next-cli-build/server/app/dashboard/basic-chat.segments/_tree.segment.rsc +1 -1
  86. package/cli/app/.next-cli-build/server/app/dashboard/cli-tools.html +1 -1
  87. package/cli/app/.next-cli-build/server/app/dashboard/cli-tools.rsc +5 -5
  88. package/cli/app/.next-cli-build/server/app/dashboard/cli-tools.segments/!KGRhc2hib2FyZCk/dashboard/cli-tools/__PAGE__.segment.rsc +2 -2
  89. package/cli/app/.next-cli-build/server/app/dashboard/cli-tools.segments/!KGRhc2hib2FyZCk/dashboard/cli-tools.segment.rsc +1 -1
  90. package/cli/app/.next-cli-build/server/app/dashboard/cli-tools.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  91. package/cli/app/.next-cli-build/server/app/dashboard/cli-tools.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  92. package/cli/app/.next-cli-build/server/app/dashboard/cli-tools.segments/_full.segment.rsc +5 -5
  93. package/cli/app/.next-cli-build/server/app/dashboard/cli-tools.segments/_head.segment.rsc +1 -1
  94. package/cli/app/.next-cli-build/server/app/dashboard/cli-tools.segments/_index.segment.rsc +3 -3
  95. package/cli/app/.next-cli-build/server/app/dashboard/cli-tools.segments/_tree.segment.rsc +1 -1
  96. package/cli/app/.next-cli-build/server/app/dashboard/combos.html +1 -1
  97. package/cli/app/.next-cli-build/server/app/dashboard/combos.rsc +5 -5
  98. package/cli/app/.next-cli-build/server/app/dashboard/combos.segments/!KGRhc2hib2FyZCk/dashboard/combos/__PAGE__.segment.rsc +2 -2
  99. package/cli/app/.next-cli-build/server/app/dashboard/combos.segments/!KGRhc2hib2FyZCk/dashboard/combos.segment.rsc +1 -1
  100. package/cli/app/.next-cli-build/server/app/dashboard/combos.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  101. package/cli/app/.next-cli-build/server/app/dashboard/combos.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  102. package/cli/app/.next-cli-build/server/app/dashboard/combos.segments/_full.segment.rsc +5 -5
  103. package/cli/app/.next-cli-build/server/app/dashboard/combos.segments/_head.segment.rsc +1 -1
  104. package/cli/app/.next-cli-build/server/app/dashboard/combos.segments/_index.segment.rsc +3 -3
  105. package/cli/app/.next-cli-build/server/app/dashboard/combos.segments/_tree.segment.rsc +1 -1
  106. package/cli/app/.next-cli-build/server/app/dashboard/context.html +1 -1
  107. package/cli/app/.next-cli-build/server/app/dashboard/context.rsc +5 -5
  108. package/cli/app/.next-cli-build/server/app/dashboard/context.segments/!KGRhc2hib2FyZCk/dashboard/context/__PAGE__.segment.rsc +2 -2
  109. package/cli/app/.next-cli-build/server/app/dashboard/context.segments/!KGRhc2hib2FyZCk/dashboard/context.segment.rsc +1 -1
  110. package/cli/app/.next-cli-build/server/app/dashboard/context.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  111. package/cli/app/.next-cli-build/server/app/dashboard/context.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  112. package/cli/app/.next-cli-build/server/app/dashboard/context.segments/_full.segment.rsc +5 -5
  113. package/cli/app/.next-cli-build/server/app/dashboard/context.segments/_head.segment.rsc +1 -1
  114. package/cli/app/.next-cli-build/server/app/dashboard/context.segments/_index.segment.rsc +3 -3
  115. package/cli/app/.next-cli-build/server/app/dashboard/context.segments/_tree.segment.rsc +1 -1
  116. package/cli/app/.next-cli-build/server/app/dashboard/endpoint.html +1 -1
  117. package/cli/app/.next-cli-build/server/app/dashboard/endpoint.rsc +5 -5
  118. package/cli/app/.next-cli-build/server/app/dashboard/endpoint.segments/!KGRhc2hib2FyZCk/dashboard/endpoint/__PAGE__.segment.rsc +2 -2
  119. package/cli/app/.next-cli-build/server/app/dashboard/endpoint.segments/!KGRhc2hib2FyZCk/dashboard/endpoint.segment.rsc +1 -1
  120. package/cli/app/.next-cli-build/server/app/dashboard/endpoint.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  121. package/cli/app/.next-cli-build/server/app/dashboard/endpoint.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  122. package/cli/app/.next-cli-build/server/app/dashboard/endpoint.segments/_full.segment.rsc +5 -5
  123. package/cli/app/.next-cli-build/server/app/dashboard/endpoint.segments/_head.segment.rsc +1 -1
  124. package/cli/app/.next-cli-build/server/app/dashboard/endpoint.segments/_index.segment.rsc +3 -3
  125. package/cli/app/.next-cli-build/server/app/dashboard/endpoint.segments/_tree.segment.rsc +1 -1
  126. package/cli/app/.next-cli-build/server/app/dashboard/media-providers/web.html +1 -1
  127. package/cli/app/.next-cli-build/server/app/dashboard/media-providers/web.rsc +5 -5
  128. package/cli/app/.next-cli-build/server/app/dashboard/media-providers/web.segments/!KGRhc2hib2FyZCk/dashboard/media-providers/web/__PAGE__.segment.rsc +2 -2
  129. package/cli/app/.next-cli-build/server/app/dashboard/media-providers/web.segments/!KGRhc2hib2FyZCk/dashboard/media-providers/web.segment.rsc +1 -1
  130. package/cli/app/.next-cli-build/server/app/dashboard/media-providers/web.segments/!KGRhc2hib2FyZCk/dashboard/media-providers.segment.rsc +1 -1
  131. package/cli/app/.next-cli-build/server/app/dashboard/media-providers/web.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  132. package/cli/app/.next-cli-build/server/app/dashboard/media-providers/web.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  133. package/cli/app/.next-cli-build/server/app/dashboard/media-providers/web.segments/_full.segment.rsc +5 -5
  134. package/cli/app/.next-cli-build/server/app/dashboard/media-providers/web.segments/_head.segment.rsc +1 -1
  135. package/cli/app/.next-cli-build/server/app/dashboard/media-providers/web.segments/_index.segment.rsc +3 -3
  136. package/cli/app/.next-cli-build/server/app/dashboard/media-providers/web.segments/_tree.segment.rsc +1 -1
  137. package/cli/app/.next-cli-build/server/app/dashboard/mitm.html +1 -1
  138. package/cli/app/.next-cli-build/server/app/dashboard/mitm.rsc +5 -5
  139. package/cli/app/.next-cli-build/server/app/dashboard/mitm.segments/!KGRhc2hib2FyZCk/dashboard/mitm/__PAGE__.segment.rsc +2 -2
  140. package/cli/app/.next-cli-build/server/app/dashboard/mitm.segments/!KGRhc2hib2FyZCk/dashboard/mitm.segment.rsc +1 -1
  141. package/cli/app/.next-cli-build/server/app/dashboard/mitm.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  142. package/cli/app/.next-cli-build/server/app/dashboard/mitm.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  143. package/cli/app/.next-cli-build/server/app/dashboard/mitm.segments/_full.segment.rsc +5 -5
  144. package/cli/app/.next-cli-build/server/app/dashboard/mitm.segments/_head.segment.rsc +1 -1
  145. package/cli/app/.next-cli-build/server/app/dashboard/mitm.segments/_index.segment.rsc +3 -3
  146. package/cli/app/.next-cli-build/server/app/dashboard/mitm.segments/_tree.segment.rsc +1 -1
  147. package/cli/app/.next-cli-build/server/app/dashboard/playground.html +1 -1
  148. package/cli/app/.next-cli-build/server/app/dashboard/playground.rsc +5 -5
  149. package/cli/app/.next-cli-build/server/app/dashboard/playground.segments/!KGRhc2hib2FyZCk/dashboard/playground/__PAGE__.segment.rsc +2 -2
  150. package/cli/app/.next-cli-build/server/app/dashboard/playground.segments/!KGRhc2hib2FyZCk/dashboard/playground.segment.rsc +1 -1
  151. package/cli/app/.next-cli-build/server/app/dashboard/playground.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  152. package/cli/app/.next-cli-build/server/app/dashboard/playground.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  153. package/cli/app/.next-cli-build/server/app/dashboard/playground.segments/_full.segment.rsc +5 -5
  154. package/cli/app/.next-cli-build/server/app/dashboard/playground.segments/_head.segment.rsc +1 -1
  155. package/cli/app/.next-cli-build/server/app/dashboard/playground.segments/_index.segment.rsc +3 -3
  156. package/cli/app/.next-cli-build/server/app/dashboard/playground.segments/_tree.segment.rsc +1 -1
  157. package/cli/app/.next-cli-build/server/app/dashboard/profile.html +1 -1
  158. package/cli/app/.next-cli-build/server/app/dashboard/profile.rsc +5 -5
  159. package/cli/app/.next-cli-build/server/app/dashboard/profile.segments/!KGRhc2hib2FyZCk/dashboard/profile/__PAGE__.segment.rsc +2 -2
  160. package/cli/app/.next-cli-build/server/app/dashboard/profile.segments/!KGRhc2hib2FyZCk/dashboard/profile.segment.rsc +1 -1
  161. package/cli/app/.next-cli-build/server/app/dashboard/profile.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  162. package/cli/app/.next-cli-build/server/app/dashboard/profile.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  163. package/cli/app/.next-cli-build/server/app/dashboard/profile.segments/_full.segment.rsc +5 -5
  164. package/cli/app/.next-cli-build/server/app/dashboard/profile.segments/_head.segment.rsc +1 -1
  165. package/cli/app/.next-cli-build/server/app/dashboard/profile.segments/_index.segment.rsc +3 -3
  166. package/cli/app/.next-cli-build/server/app/dashboard/profile.segments/_tree.segment.rsc +1 -1
  167. package/cli/app/.next-cli-build/server/app/dashboard/providers/new.html +1 -1
  168. package/cli/app/.next-cli-build/server/app/dashboard/providers/new.rsc +5 -5
  169. package/cli/app/.next-cli-build/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk/dashboard/providers/new/__PAGE__.segment.rsc +2 -2
  170. package/cli/app/.next-cli-build/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk/dashboard/providers/new.segment.rsc +1 -1
  171. package/cli/app/.next-cli-build/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk/dashboard/providers.segment.rsc +1 -1
  172. package/cli/app/.next-cli-build/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  173. package/cli/app/.next-cli-build/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  174. package/cli/app/.next-cli-build/server/app/dashboard/providers/new.segments/_full.segment.rsc +5 -5
  175. package/cli/app/.next-cli-build/server/app/dashboard/providers/new.segments/_head.segment.rsc +1 -1
  176. package/cli/app/.next-cli-build/server/app/dashboard/providers/new.segments/_index.segment.rsc +3 -3
  177. package/cli/app/.next-cli-build/server/app/dashboard/providers/new.segments/_tree.segment.rsc +1 -1
  178. package/cli/app/.next-cli-build/server/app/dashboard/providers.html +1 -1
  179. package/cli/app/.next-cli-build/server/app/dashboard/providers.rsc +5 -5
  180. package/cli/app/.next-cli-build/server/app/dashboard/providers.segments/!KGRhc2hib2FyZCk/dashboard/providers/__PAGE__.segment.rsc +2 -2
  181. package/cli/app/.next-cli-build/server/app/dashboard/providers.segments/!KGRhc2hib2FyZCk/dashboard/providers.segment.rsc +1 -1
  182. package/cli/app/.next-cli-build/server/app/dashboard/providers.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  183. package/cli/app/.next-cli-build/server/app/dashboard/providers.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  184. package/cli/app/.next-cli-build/server/app/dashboard/providers.segments/_full.segment.rsc +5 -5
  185. package/cli/app/.next-cli-build/server/app/dashboard/providers.segments/_head.segment.rsc +1 -1
  186. package/cli/app/.next-cli-build/server/app/dashboard/providers.segments/_index.segment.rsc +3 -3
  187. package/cli/app/.next-cli-build/server/app/dashboard/providers.segments/_tree.segment.rsc +1 -1
  188. package/cli/app/.next-cli-build/server/app/dashboard/proxy-pools.html +1 -1
  189. package/cli/app/.next-cli-build/server/app/dashboard/proxy-pools.rsc +5 -5
  190. package/cli/app/.next-cli-build/server/app/dashboard/proxy-pools.segments/!KGRhc2hib2FyZCk/dashboard/proxy-pools/__PAGE__.segment.rsc +2 -2
  191. package/cli/app/.next-cli-build/server/app/dashboard/proxy-pools.segments/!KGRhc2hib2FyZCk/dashboard/proxy-pools.segment.rsc +1 -1
  192. package/cli/app/.next-cli-build/server/app/dashboard/proxy-pools.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  193. package/cli/app/.next-cli-build/server/app/dashboard/proxy-pools.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  194. package/cli/app/.next-cli-build/server/app/dashboard/proxy-pools.segments/_full.segment.rsc +5 -5
  195. package/cli/app/.next-cli-build/server/app/dashboard/proxy-pools.segments/_head.segment.rsc +1 -1
  196. package/cli/app/.next-cli-build/server/app/dashboard/proxy-pools.segments/_index.segment.rsc +3 -3
  197. package/cli/app/.next-cli-build/server/app/dashboard/proxy-pools.segments/_tree.segment.rsc +1 -1
  198. package/cli/app/.next-cli-build/server/app/dashboard/pxpipe.html +1 -1
  199. package/cli/app/.next-cli-build/server/app/dashboard/pxpipe.rsc +5 -5
  200. package/cli/app/.next-cli-build/server/app/dashboard/pxpipe.segments/!KGRhc2hib2FyZCk/dashboard/pxpipe/__PAGE__.segment.rsc +2 -2
  201. package/cli/app/.next-cli-build/server/app/dashboard/pxpipe.segments/!KGRhc2hib2FyZCk/dashboard/pxpipe.segment.rsc +1 -1
  202. package/cli/app/.next-cli-build/server/app/dashboard/pxpipe.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  203. package/cli/app/.next-cli-build/server/app/dashboard/pxpipe.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  204. package/cli/app/.next-cli-build/server/app/dashboard/pxpipe.segments/_full.segment.rsc +5 -5
  205. package/cli/app/.next-cli-build/server/app/dashboard/pxpipe.segments/_head.segment.rsc +1 -1
  206. package/cli/app/.next-cli-build/server/app/dashboard/pxpipe.segments/_index.segment.rsc +3 -3
  207. package/cli/app/.next-cli-build/server/app/dashboard/pxpipe.segments/_tree.segment.rsc +1 -1
  208. package/cli/app/.next-cli-build/server/app/dashboard/quota.html +2 -2
  209. package/cli/app/.next-cli-build/server/app/dashboard/quota.rsc +6 -6
  210. package/cli/app/.next-cli-build/server/app/dashboard/quota.segments/!KGRhc2hib2FyZCk/dashboard/quota/__PAGE__.segment.rsc +3 -3
  211. package/cli/app/.next-cli-build/server/app/dashboard/quota.segments/!KGRhc2hib2FyZCk/dashboard/quota.segment.rsc +1 -1
  212. package/cli/app/.next-cli-build/server/app/dashboard/quota.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  213. package/cli/app/.next-cli-build/server/app/dashboard/quota.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  214. package/cli/app/.next-cli-build/server/app/dashboard/quota.segments/_full.segment.rsc +6 -6
  215. package/cli/app/.next-cli-build/server/app/dashboard/quota.segments/_head.segment.rsc +1 -1
  216. package/cli/app/.next-cli-build/server/app/dashboard/quota.segments/_index.segment.rsc +3 -3
  217. package/cli/app/.next-cli-build/server/app/dashboard/quota.segments/_tree.segment.rsc +1 -1
  218. package/cli/app/.next-cli-build/server/app/dashboard/settings/pricing/page_client-reference-manifest.js +1 -1
  219. package/cli/app/.next-cli-build/server/app/dashboard/settings/pricing.html +1 -1
  220. package/cli/app/.next-cli-build/server/app/dashboard/settings/pricing.rsc +3 -3
  221. package/cli/app/.next-cli-build/server/app/dashboard/settings/pricing.segments/_full.segment.rsc +3 -3
  222. package/cli/app/.next-cli-build/server/app/dashboard/settings/pricing.segments/_head.segment.rsc +1 -1
  223. package/cli/app/.next-cli-build/server/app/dashboard/settings/pricing.segments/_index.segment.rsc +3 -3
  224. package/cli/app/.next-cli-build/server/app/dashboard/settings/pricing.segments/_tree.segment.rsc +1 -1
  225. package/cli/app/.next-cli-build/server/app/dashboard/settings/pricing.segments/dashboard/settings/pricing/__PAGE__.segment.rsc +1 -1
  226. package/cli/app/.next-cli-build/server/app/dashboard/settings/pricing.segments/dashboard/settings/pricing.segment.rsc +1 -1
  227. package/cli/app/.next-cli-build/server/app/dashboard/settings/pricing.segments/dashboard/settings.segment.rsc +1 -1
  228. package/cli/app/.next-cli-build/server/app/dashboard/settings/pricing.segments/dashboard.segment.rsc +1 -1
  229. package/cli/app/.next-cli-build/server/app/dashboard/token-saver.html +1 -1
  230. package/cli/app/.next-cli-build/server/app/dashboard/token-saver.rsc +5 -5
  231. package/cli/app/.next-cli-build/server/app/dashboard/token-saver.segments/!KGRhc2hib2FyZCk/dashboard/token-saver/__PAGE__.segment.rsc +2 -2
  232. package/cli/app/.next-cli-build/server/app/dashboard/token-saver.segments/!KGRhc2hib2FyZCk/dashboard/token-saver.segment.rsc +1 -1
  233. package/cli/app/.next-cli-build/server/app/dashboard/token-saver.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  234. package/cli/app/.next-cli-build/server/app/dashboard/token-saver.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  235. package/cli/app/.next-cli-build/server/app/dashboard/token-saver.segments/_full.segment.rsc +5 -5
  236. package/cli/app/.next-cli-build/server/app/dashboard/token-saver.segments/_head.segment.rsc +1 -1
  237. package/cli/app/.next-cli-build/server/app/dashboard/token-saver.segments/_index.segment.rsc +3 -3
  238. package/cli/app/.next-cli-build/server/app/dashboard/token-saver.segments/_tree.segment.rsc +1 -1
  239. package/cli/app/.next-cli-build/server/app/dashboard/translator.html +1 -1
  240. package/cli/app/.next-cli-build/server/app/dashboard/translator.rsc +5 -5
  241. package/cli/app/.next-cli-build/server/app/dashboard/translator.segments/!KGRhc2hib2FyZCk/dashboard/translator/__PAGE__.segment.rsc +2 -2
  242. package/cli/app/.next-cli-build/server/app/dashboard/translator.segments/!KGRhc2hib2FyZCk/dashboard/translator.segment.rsc +1 -1
  243. package/cli/app/.next-cli-build/server/app/dashboard/translator.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  244. package/cli/app/.next-cli-build/server/app/dashboard/translator.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  245. package/cli/app/.next-cli-build/server/app/dashboard/translator.segments/_full.segment.rsc +5 -5
  246. package/cli/app/.next-cli-build/server/app/dashboard/translator.segments/_head.segment.rsc +1 -1
  247. package/cli/app/.next-cli-build/server/app/dashboard/translator.segments/_index.segment.rsc +3 -3
  248. package/cli/app/.next-cli-build/server/app/dashboard/translator.segments/_tree.segment.rsc +1 -1
  249. package/cli/app/.next-cli-build/server/app/dashboard/usage.html +1 -1
  250. package/cli/app/.next-cli-build/server/app/dashboard/usage.rsc +5 -5
  251. package/cli/app/.next-cli-build/server/app/dashboard/usage.segments/!KGRhc2hib2FyZCk/dashboard/usage/__PAGE__.segment.rsc +2 -2
  252. package/cli/app/.next-cli-build/server/app/dashboard/usage.segments/!KGRhc2hib2FyZCk/dashboard/usage.segment.rsc +1 -1
  253. package/cli/app/.next-cli-build/server/app/dashboard/usage.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  254. package/cli/app/.next-cli-build/server/app/dashboard/usage.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  255. package/cli/app/.next-cli-build/server/app/dashboard/usage.segments/_full.segment.rsc +5 -5
  256. package/cli/app/.next-cli-build/server/app/dashboard/usage.segments/_head.segment.rsc +1 -1
  257. package/cli/app/.next-cli-build/server/app/dashboard/usage.segments/_index.segment.rsc +3 -3
  258. package/cli/app/.next-cli-build/server/app/dashboard/usage.segments/_tree.segment.rsc +1 -1
  259. package/cli/app/.next-cli-build/server/app/dashboard.html +1 -1
  260. package/cli/app/.next-cli-build/server/app/dashboard.rsc +5 -5
  261. package/cli/app/.next-cli-build/server/app/dashboard.segments/!KGRhc2hib2FyZCk/dashboard/__PAGE__.segment.rsc +2 -2
  262. package/cli/app/.next-cli-build/server/app/dashboard.segments/!KGRhc2hib2FyZCk/dashboard.segment.rsc +1 -1
  263. package/cli/app/.next-cli-build/server/app/dashboard.segments/!KGRhc2hib2FyZCk.segment.rsc +2 -2
  264. package/cli/app/.next-cli-build/server/app/dashboard.segments/_full.segment.rsc +5 -5
  265. package/cli/app/.next-cli-build/server/app/dashboard.segments/_head.segment.rsc +1 -1
  266. package/cli/app/.next-cli-build/server/app/dashboard.segments/_index.segment.rsc +3 -3
  267. package/cli/app/.next-cli-build/server/app/dashboard.segments/_tree.segment.rsc +1 -1
  268. package/cli/app/.next-cli-build/server/app/index.html +1 -1
  269. package/cli/app/.next-cli-build/server/app/index.rsc +3 -3
  270. package/cli/app/.next-cli-build/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  271. package/cli/app/.next-cli-build/server/app/index.segments/_full.segment.rsc +3 -3
  272. package/cli/app/.next-cli-build/server/app/index.segments/_head.segment.rsc +1 -1
  273. package/cli/app/.next-cli-build/server/app/index.segments/_index.segment.rsc +3 -3
  274. package/cli/app/.next-cli-build/server/app/index.segments/_tree.segment.rsc +1 -1
  275. package/cli/app/.next-cli-build/server/app/landing/page_client-reference-manifest.js +1 -1
  276. package/cli/app/.next-cli-build/server/app/landing.html +1 -1
  277. package/cli/app/.next-cli-build/server/app/landing.rsc +4 -4
  278. package/cli/app/.next-cli-build/server/app/landing.segments/_full.segment.rsc +4 -4
  279. package/cli/app/.next-cli-build/server/app/landing.segments/_head.segment.rsc +1 -1
  280. package/cli/app/.next-cli-build/server/app/landing.segments/_index.segment.rsc +3 -3
  281. package/cli/app/.next-cli-build/server/app/landing.segments/_tree.segment.rsc +1 -1
  282. package/cli/app/.next-cli-build/server/app/landing.segments/landing/__PAGE__.segment.rsc +2 -2
  283. package/cli/app/.next-cli-build/server/app/landing.segments/landing.segment.rsc +1 -1
  284. package/cli/app/.next-cli-build/server/app/login/page_client-reference-manifest.js +1 -1
  285. package/cli/app/.next-cli-build/server/app/login.html +1 -1
  286. package/cli/app/.next-cli-build/server/app/login.rsc +4 -4
  287. package/cli/app/.next-cli-build/server/app/login.segments/_full.segment.rsc +4 -4
  288. package/cli/app/.next-cli-build/server/app/login.segments/_head.segment.rsc +1 -1
  289. package/cli/app/.next-cli-build/server/app/login.segments/_index.segment.rsc +3 -3
  290. package/cli/app/.next-cli-build/server/app/login.segments/_tree.segment.rsc +1 -1
  291. package/cli/app/.next-cli-build/server/app/login.segments/login/__PAGE__.segment.rsc +2 -2
  292. package/cli/app/.next-cli-build/server/app/login.segments/login.segment.rsc +1 -1
  293. package/cli/app/.next-cli-build/server/app/page_client-reference-manifest.js +1 -1
  294. package/cli/app/.next-cli-build/server/app-paths-manifest.json +10 -10
  295. package/cli/app/.next-cli-build/server/chunks/3155.js +1 -1
  296. package/cli/app/.next-cli-build/server/chunks/4566.js +1 -1
  297. package/cli/app/.next-cli-build/server/chunks/4746.js +1 -1
  298. package/cli/app/.next-cli-build/server/chunks/5307.js +1 -1
  299. package/cli/app/.next-cli-build/server/chunks/5949.js +3 -3
  300. package/cli/app/.next-cli-build/server/chunks/8306.js +1 -1
  301. package/cli/app/.next-cli-build/server/chunks/8371.js +1 -1
  302. package/cli/app/.next-cli-build/server/chunks/9621.js +1 -1
  303. package/cli/app/.next-cli-build/server/middleware-build-manifest.js +1 -1
  304. package/cli/app/.next-cli-build/server/pages/404.html +1 -1
  305. package/cli/app/.next-cli-build/server/pages/500.html +1 -1
  306. package/cli/app/.next-cli-build/static/chunks/{620-375754e53341e85b.js → 620-104e711e028e5a60.js} +1 -1
  307. package/cli/app/CHANGELOG.md +19 -0
  308. package/cli/app/cli/hooks/cloakbrowserRuntime.js +111 -4
  309. package/cli/app/package.json +1 -1
  310. package/cli/hooks/cloakbrowserRuntime.js +111 -4
  311. package/cli/package.json +1 -1
  312. package/package.json +1 -1
  313. package/src/lib/oauth/services/bulkImportBrowserEngine.js +36 -0
  314. package/src/lib/oauth/services/codebuddyCnBulkImportManager.js +603 -181
  315. package/src/lib/oauth/services/codebuddyCnPhoneAutomation.js +97 -47
  316. package/src/lib/oauth/services/kiroBulkImportManager.js +7 -1
  317. /package/cli/app/.next-cli-build/static/{y-U4C09T7DItXT7CZZV41 → w0fFe0wlenV7JedZI_N94}/_buildManifest.js +0 -0
  318. /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 per account (nav + form + SMS + API key). Prevents infinite
68
- // Chromium can spin when proxy/nav blackholes and Playwright timeouts do not fire.
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
- ) || 12 * 60_000;
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 { launchBulkImportBrowser } = await import("./bulkImportBrowserEngine.js");
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
- return launchBulkImportBrowser({
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 freshContext = await createFreshContext(job.browser, account.proxyUrl, {
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 === "failed") {
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
- this.finalizeAccount(account, "failed", {
699
+ const failureStatus = automationResult.status || "failed";
700
+ this.finalizeAccount(account, failureStatus, {
477
701
  error: errorMsg,
478
- step: "failed",
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.close().catch(() => null);
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 didn't receive CodeBuddy SMS within 60s — it's a bad/burned 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
- if (context) await context.close().catch(() => null);
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 (error?.code === "CN_ACCOUNT_HARD_TIMEOUT" || job.cancelRequested) {
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 = async () => page.evaluate(async () => {
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
- // After goto: wait for accounts XHR or Keycloak cookie — not a fixed sleep.
646
- const waitAfterNav = async () => {
647
- await Promise.race([
648
- page.waitForResponse(
649
- (r) => /\/console\/accounts/i.test(r.url()) && r.status() < 500,
650
- { timeout: 10_000 },
651
- ).catch(() => null),
652
- page.waitForResponse(
653
- (r) => /\/console\/api\//i.test(r.url()) && r.status() < 500,
654
- { timeout: 10_000 },
655
- ).catch(() => null),
656
- waitUntil(async () => {
657
- const snap = await cookieSnapshot();
658
- return hasStrongKeycloak(snap.names);
659
- }, { timeout: 10_000, interval: 200 }),
660
- new Promise((r) => setTimeout(r, 2_500)), // hard cap only
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
- // Order matters: home → console → keys (login/ last — re-triggering login can wipe soft session).
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: more attempts but each wait is response-driven, not blind multi-sec sleep.
682
- const OIDC_MAX_ATTEMPTS = 10;
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}/${OIDC_MAX_ATTEMPTS} → ${path.replace("https://www.codebuddy.cn", "")} (${strong ? "KEYCLOAK" : soft ? "soft-session" : "weak"})`,
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 page.goto(path, { waitUntil: "domcontentloaded", timeout: 25_000 }).catch(() => null);
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 = /codebuddy\.cn/i.test(page.url?.() || "");
712
- if (!onCodebuddy || (!String(page.url() || "").includes("/console") && attempt >= 1)) {
713
- await page.goto("https://www.codebuddy.cn/console", {
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
- lastPayloadSnippet = JSON.stringify(accountsProbe?.data ?? accountsProbe?.text ?? null).slice(0, 180);
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 (accountsProbe?.status === 200 && Array.isArray(accountList) && accountList.length > 0) {
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 >= 4
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}/${OIDC_MAX_ATTEMPTS} body=${lastPayloadSnippet.slice(0, 80)}`,
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
- throw new Error(
765
- `Console accounts unavailable after login (HTTP ${accountsProbe?.status || 0}; cookies: ${snap.list.slice(0, 18).join(",") || "(none)"}; body=${lastPayloadSnippet.slice(0, 120)}) — session not accepted for API key`,
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
- const createKeyOnPage = async (enterpriseId) => page.evaluate(async ({ enterpriseId: entId }) => {
784
- const host = window.location.hostname || "www.codebuddy.cn";
785
- const base = host.endsWith("codebuddy.cn")
786
- ? window.location.origin
787
- : "https://www.codebuddy.cn";
788
- const res = await fetch(`${base}/console/api/client/v1/api-keys`, {
789
- method: "POST",
790
- credentials: "include",
791
- headers: {
792
- "Content-Type": "application/json",
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
- data = text ? JSON.parse(text) : null;
808
- } catch {
809
- data = { _raw: String(text || "").slice(0, 200) };
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
- return { ok: res.ok, status: res.status, data };
812
- }, { enterpriseId });
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 page.goto("https://www.codebuddy.cn/profile/keys", {
816
- waitUntil: "domcontentloaded",
817
- timeout: 45_000,
818
- }).catch(() => null);
819
- await waitAfterNav();
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 createKeyOnPage(userEnterpriseId).catch(() => null);
1158
+ let apiKeyResult = await requestApiKey(userEnterpriseId, "Creating API key");
822
1159
 
823
- // Retry personal id if enterprise id failed or accounts were empty.
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
- (!apiKeyResult || !apiKeyResult.ok)
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 createKeyOnPage(PERSONAL_ENTERPRISE_ID).catch(() => null);
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. Up to 3 rounds with backoff.
853
- const isAuthBlocked = (r) => !r?.ok && (r?.status === 401 || r?.status === 403 || r?.status === 0 || !r);
854
- for (let round = 1; round <= 3 && isAuthBlocked(apiKeyResult); round += 1) {
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}/3 (waiting strong session)`,
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 page.goto(path, { waitUntil: "domcontentloaded", timeout: 45_000 }).catch(() => null);
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 createKeyOnPage(PERSONAL_ENTERPRISE_ID).catch(() => null);
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 new Error(
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.close().catch(() => null);
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: ${error.message}`,
944
- step: "awaiting_manual",
945
- message: `Registration done, API key capture failed: ${error.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).catch(() => null);
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
- if (ctx) await ctx.close().catch(() => null);
967
- if (headed) await headed.close().catch(() => null);
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 for the operator to complete — poll for the API keys page being loaded
975
- // and an API key being available. Give them up to 15 minutes.
976
- const deadline = Date.now() + 15 * 60_000;
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 res = await fetch("/console/api/client/v1/api-keys", {
990
- method: "POST",
991
- headers: {
992
- "Content-Type": "application/json",
993
- Accept: "application/json, text/plain, */*",
994
- "x-requested-with": "XMLHttpRequest",
995
- "X-Domain": window.location.hostname || "www.codebuddy.cn",
996
- "X-Product": "SaaS",
997
- },
998
- credentials: "include",
999
- body: JSON.stringify({
1000
- name: "zevai-router-manual-" + Date.now(),
1001
- expire_in_days: 365,
1002
- user_enterprise_id: "personal-edition-user-id",
1003
- }),
1004
- });
1005
- const data = await res.json().catch(() => null);
1006
- return { ok: res.ok, status: res.status, data };
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?.ok && result.data) {
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 === "failed" || status === "failed_exchange") {
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
  };