zevairouter 1.0.147 → 1.0.148

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 +12 -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-16902cd352ef1d97.js} +1 -1
  307. package/cli/app/CHANGELOG.md +12 -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 +469 -172
  315. package/src/lib/oauth/services/codebuddyCnPhoneAutomation.js +16 -2
  316. package/src/lib/oauth/services/kiroBulkImportManager.js +7 -1
  317. /package/cli/app/.next-cli-build/static/{y-U4C09T7DItXT7CZZV41 → kmlfntQuBCJ_ni8__OiKd}/_buildManifest.js +0 -0
  318. /package/cli/app/.next-cli-build/static/{y-U4C09T7DItXT7CZZV41 → kmlfntQuBCJ_ni8__OiKd}/_ssgManifest.js +0 -0
@@ -64,12 +64,25 @@ 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";
73
86
 
74
87
  // Supported 5sim regions
75
88
  const SUPPORTED_REGIONS = new Set(["hongkong", "china", "any"]);
@@ -113,6 +126,83 @@ function clampCnConcurrency(value) {
113
126
  return Math.min(hardMax, Math.max(CODEBUDDY_CN_MIN_CONCURRENCY, parsed));
114
127
  }
115
128
 
129
+ async function withTimeoutCleanup(
130
+ task,
131
+ {
132
+ timeoutMs,
133
+ message,
134
+ code,
135
+ onTimeout,
136
+ onLateResolve,
137
+ },
138
+ ) {
139
+ const operation = Promise.resolve(task);
140
+ let timer = null;
141
+ let timedOut = false;
142
+ const timeout = new Promise((_, reject) => {
143
+ timer = setTimeout(() => {
144
+ timedOut = true;
145
+ try {
146
+ if (typeof onTimeout === "function") onTimeout();
147
+ } catch {
148
+ // Timeout reporting must not be replaced by cleanup callback failures.
149
+ }
150
+ reject(Object.assign(new Error(message), { code }));
151
+ }, timeoutMs);
152
+ if (typeof timer.unref === "function") timer.unref();
153
+ });
154
+
155
+ try {
156
+ return await Promise.race([operation, timeout]);
157
+ } finally {
158
+ if (timer) clearTimeout(timer);
159
+ if (timedOut && typeof onLateResolve === "function") {
160
+ void operation.then(onLateResolve).catch(() => null);
161
+ }
162
+ }
163
+ }
164
+
165
+ function isLoginHtmlProbe(probe) {
166
+ const raw = `${probe?.text || ""} ${probe?.data?._raw || ""}`;
167
+ return probe?.data?._notJson === true
168
+ || /<!doctype html|<html|login-pf|\/auth\/realms\//i.test(raw);
169
+ }
170
+
171
+ async function closeResourceBounded(resource) {
172
+ if (!resource || typeof resource.close !== "function") return true;
173
+ try {
174
+ await withTimeoutCleanup(Promise.resolve().then(() => resource.close()), {
175
+ timeoutMs: CODEBUDDY_CN_RESOURCE_CLOSE_TIMEOUT_MS,
176
+ message: `Browser resource close timed out after ${CODEBUDDY_CN_RESOURCE_CLOSE_TIMEOUT_MS / 1000}s`,
177
+ code: "CN_RESOURCE_CLOSE_TIMEOUT",
178
+ });
179
+ return true;
180
+ } catch {
181
+ return false;
182
+ }
183
+ }
184
+
185
+ async function closeContextOrBrowser(context, job) {
186
+ if (await closeResourceBounded(context)) return;
187
+ if (!job?.browser) return;
188
+ const browser = job.browser;
189
+ job.browser = null;
190
+ await forceCloseBrowser(browser).catch(() => null);
191
+ }
192
+
193
+ async function settleFiveSimOrder(operation) {
194
+ try {
195
+ return await withTimeoutCleanup(Promise.resolve().then(operation), {
196
+ timeoutMs: CODEBUDDY_CN_FIVESIM_SETTLE_TIMEOUT_MS,
197
+ message: `5sim order settlement timed out after ${CODEBUDDY_CN_FIVESIM_SETTLE_TIMEOUT_MS / 1000}s`,
198
+ code: "CN_FIVESIM_SETTLE_TIMEOUT",
199
+ });
200
+ } catch {
201
+ // Finish/cancel/ban are best-effort and must not hold the browser worker.
202
+ return false;
203
+ }
204
+ }
205
+
116
206
  /**
117
207
  * Save a CodeBuddy CN provider connection to the database.
118
208
  */
@@ -165,7 +255,10 @@ export class CodeBuddyCnBulkImportManager extends KiroBulkImportManager {
165
255
  // CloakBrowser-only: proxy on launch + geoip. Headed by default (Turnstile/Tencent).
166
256
  // Override: ZEVAI_CN_HEADLESS=0|1
167
257
  const cnBrowserLauncher = browserLauncher || (async (job) => {
168
- const { launchBulkImportBrowser } = await import("./bulkImportBrowserEngine.js");
258
+ const {
259
+ forceCloseBrowser,
260
+ launchBulkImportBrowser,
261
+ } = await import("./bulkImportBrowserEngine.js");
169
262
  const proxyUrl = Array.isArray(job?.proxyUrls) && job.proxyUrls.length
170
263
  ? job.proxyUrls[0]
171
264
  : null;
@@ -173,12 +266,18 @@ export class CodeBuddyCnBulkImportManager extends KiroBulkImportManager {
173
266
  let headless = false;
174
267
  if (envHeadless === "0" || envHeadless === "false") headless = false;
175
268
  if (envHeadless === "1" || envHeadless === "true") headless = true;
176
- return launchBulkImportBrowser({
269
+ const launchTask = launchBulkImportBrowser({
177
270
  engine: job?.engine || "cloakbrowser",
178
271
  proxyUrl,
179
272
  headless,
180
273
  windowSize: { width: 1280, height: 900 },
181
274
  });
275
+ return withTimeoutCleanup(launchTask, {
276
+ timeoutMs: CODEBUDDY_CN_BROWSER_LAUNCH_TIMEOUT_MS,
277
+ message: `CloakBrowser launch timed out after ${CODEBUDDY_CN_BROWSER_LAUNCH_TIMEOUT_MS / 1000}s`,
278
+ code: "CN_BROWSER_LAUNCH_TIMEOUT",
279
+ onLateResolve: (browser) => forceCloseBrowser(browser),
280
+ });
182
281
  });
183
282
  super({ browserLauncher: cnBrowserLauncher, storageName });
184
283
  this.requestDeviceCode = requestDeviceCodeFn;
@@ -358,10 +457,17 @@ export class CodeBuddyCnBulkImportManager extends KiroBulkImportManager {
358
457
  // cause of 账号访问受限 right after OTP). Per-account fingerprint seed —
359
458
  // sticky residential IP alone still clusters if every session shares HW.
360
459
  if (!account.fingerprintSeed) account.fingerprintSeed = randomUUID();
361
- const freshContext = await createFreshContext(job.browser, account.proxyUrl, {
460
+ const contextTask = createFreshContext(job.browser, account.proxyUrl, {
362
461
  profile: "codebuddy-cn",
363
462
  region: job.region || "hongkong",
364
463
  fingerprintSeed: account.fingerprintSeed,
464
+ lowMemory: isLowMemHost(),
465
+ });
466
+ const freshContext = await withTimeoutCleanup(contextTask, {
467
+ timeoutMs: CODEBUDDY_CN_CONTEXT_TIMEOUT_MS,
468
+ message: `Browser context creation timed out after ${CODEBUDDY_CN_CONTEXT_TIMEOUT_MS / 1000}s`,
469
+ code: "CN_CONTEXT_TIMEOUT",
470
+ onLateResolve: (session) => Promise.resolve(session?.context?.close?.()).catch(() => null),
365
471
  });
366
472
  context = freshContext.context;
367
473
  const page = freshContext.page;
@@ -481,13 +587,13 @@ export class CodeBuddyCnBulkImportManager extends KiroBulkImportManager {
481
587
  // Only touch 5sim if we actually bought a number (order is deferred until form ready)
482
588
  if (fiveSimClient && fiveSimOrderId) {
483
589
  if (smsReceived) {
484
- await fiveSimClient.finishOrder(fiveSimOrderId);
590
+ await settleFiveSimOrder(() => fiveSimClient.finishOrder(fiveSimOrderId));
485
591
  } else {
486
- await fiveSimClient.cancelOrder(fiveSimOrderId);
592
+ await settleFiveSimOrder(() => fiveSimClient.cancelOrder(fiveSimOrderId));
487
593
  }
488
594
  }
489
595
  account.runtimeSession = null;
490
- await context.close().catch(() => null);
596
+ await closeContextOrBrowser(context, job);
491
597
  await this.persistJobSnapshot(job, { forcePreview: true });
492
598
  return;
493
599
  }
@@ -510,19 +616,23 @@ export class CodeBuddyCnBulkImportManager extends KiroBulkImportManager {
510
616
  // 5sim hygiene on error
511
617
  if (fiveSimClient && fiveSimOrderId) {
512
618
  if (smsReceived) {
513
- await fiveSimClient.finishOrder(fiveSimOrderId);
619
+ await settleFiveSimOrder(() => fiveSimClient.finishOrder(fiveSimOrderId));
514
620
  } else if (isSmsTimeout) {
515
- // BAN: number didn't receive CodeBuddy SMS within 60s — it's a bad/burned number
516
- await fiveSimClient.banOrder(fiveSimOrderId);
621
+ // BAN: number did not receive CodeBuddy SMS within the OTP window.
622
+ await settleFiveSimOrder(() => fiveSimClient.banOrder(fiveSimOrderId));
517
623
  } else {
518
- await fiveSimClient.cancelOrder(fiveSimOrderId);
624
+ await settleFiveSimOrder(() => fiveSimClient.cancelOrder(fiveSimOrderId));
519
625
  }
520
626
  }
521
627
  account.runtimeSession = null;
522
- if (context) await context.close().catch(() => null);
628
+ await closeContextOrBrowser(context, job);
523
629
  // Hard timeout / blackhole nav: kill the shared browser so the worker unblocks
524
630
  // and Chromium cannot pin 100% CPU on a 2GB VPS until reboot.
525
- if (error?.code === "CN_ACCOUNT_HARD_TIMEOUT" || job.cancelRequested) {
631
+ if (
632
+ error?.code === "CN_ACCOUNT_HARD_TIMEOUT"
633
+ || error?.code === "CN_CONTEXT_TIMEOUT"
634
+ || job.cancelRequested
635
+ ) {
526
636
  if (job.browser) {
527
637
  const b = job.browser;
528
638
  job.browser = null;
@@ -592,34 +702,55 @@ export class CodeBuddyCnBulkImportManager extends KiroBulkImportManager {
592
702
  || names.has("qcmainCSRFToken")
593
703
  || names.has("x_host_key_access");
594
704
 
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;
705
+ const probeConsoleAccounts = async () => {
706
+ const probeTask = page.evaluate(async ({ timeoutMs }) => {
707
+ const controller = new AbortController();
708
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
613
709
  try {
614
- data = text ? JSON.parse(text) : null;
615
- } catch {
616
- data = { _raw: String(text || "").slice(0, 240), _notJson: true };
710
+ // Relative /console/accounts fails on Tencent/Keycloak login hosts.
711
+ const host = window.location.hostname || "www.codebuddy.cn";
712
+ const base = host === "www.codebuddy.cn"
713
+ ? `${window.location.origin}`
714
+ : "https://www.codebuddy.cn";
715
+ const res = await fetch(`${base}/console/accounts`, {
716
+ credentials: "include",
717
+ signal: controller.signal,
718
+ headers: {
719
+ Accept: "application/json, text/plain, */*",
720
+ "x-requested-with": "XMLHttpRequest",
721
+ "X-Domain": "www.codebuddy.cn",
722
+ "X-Product": "SaaS",
723
+ },
724
+ });
725
+ const text = await res.text().catch(() => "");
726
+ let data = null;
727
+ try {
728
+ data = text ? JSON.parse(text) : null;
729
+ } catch {
730
+ data = { _raw: String(text || "").slice(0, 240), _notJson: true };
731
+ }
732
+ return { status: res.status, data, text: String(text || "").slice(0, 240) };
733
+ } catch (error) {
734
+ return {
735
+ status: 0,
736
+ timedOut: error?.name === "AbortError",
737
+ error: error?.message || String(error),
738
+ };
739
+ } finally {
740
+ clearTimeout(timer);
617
741
  }
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);
742
+ }, { timeoutMs: CODEBUDDY_CN_CONSOLE_PROBE_TIMEOUT_MS });
743
+
744
+ return withTimeoutCleanup(probeTask, {
745
+ timeoutMs: CODEBUDDY_CN_CONSOLE_PROBE_TIMEOUT_MS,
746
+ message: `Console account probe timed out after ${CODEBUDDY_CN_CONSOLE_PROBE_TIMEOUT_MS / 1000}s`,
747
+ code: "CN_CONSOLE_PROBE_TIMEOUT",
748
+ }).catch((error) => ({
749
+ status: 0,
750
+ timedOut: error?.code === "CN_CONSOLE_PROBE_TIMEOUT",
751
+ error: error?.message || String(error),
752
+ }));
753
+ };
623
754
 
624
755
  const extractAccountList = (probe) => {
625
756
  const d = probe?.data;
@@ -642,35 +773,52 @@ export class CodeBuddyCnBulkImportManager extends KiroBulkImportManager {
642
773
  return [];
643
774
  };
644
775
 
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
- ]);
776
+ // A committed response is enough to start session probes. Waiting for the
777
+ // full SPA DOM is expensive and frequently stalls on small VPS hosts.
778
+ const waitAfterNav = async (timeoutMs = 2_500) => {
779
+ let settled = false;
780
+ let timer = null;
781
+ try {
782
+ await Promise.race([
783
+ page.waitForLoadState("domcontentloaded", { timeout: timeoutMs }).catch(() => null),
784
+ waitUntil(async () => {
785
+ if (settled) return true;
786
+ const snap = await cookieSnapshot();
787
+ return hasStrongKeycloak(snap.names);
788
+ }, { timeout: timeoutMs, interval: 200 }),
789
+ new Promise((resolve) => {
790
+ timer = setTimeout(resolve, timeoutMs);
791
+ }),
792
+ ]);
793
+ } finally {
794
+ settled = true;
795
+ if (timer) clearTimeout(timer);
796
+ }
797
+ };
798
+
799
+ const navigateConsole = async (path) => {
800
+ const startedAt = Date.now();
801
+ try {
802
+ await page.goto(path, {
803
+ waitUntil: "commit",
804
+ timeout: CODEBUDDY_CN_CONSOLE_NAV_TIMEOUT_MS,
805
+ });
806
+ const remainingMs = CODEBUDDY_CN_CONSOLE_NAV_TIMEOUT_MS - (Date.now() - startedAt);
807
+ if (remainingMs > 0) await waitAfterNav(Math.min(2_500, remainingMs));
808
+ return true;
809
+ } catch {
810
+ return false;
811
+ }
662
812
  };
663
813
 
664
814
  // 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).
815
+ // Never revisit /login here: it can wipe a valid partial OIDC session.
666
816
  const oIDCNudgePaths = [
667
817
  "https://www.codebuddy.cn/",
668
818
  "https://www.codebuddy.cn/console",
669
819
  "https://www.codebuddy.cn/console/",
670
820
  "https://www.codebuddy.cn/profile",
671
821
  "https://www.codebuddy.cn/profile/keys",
672
- // only if still empty after console probes
673
- "https://www.codebuddy.cn/login/",
674
822
  ];
675
823
 
676
824
  let accountList = [];
@@ -678,9 +826,8 @@ export class CodeBuddyCnBulkImportManager extends KiroBulkImportManager {
678
826
  let sessionReady = false;
679
827
  let lastPayloadSnippet = "";
680
828
 
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) {
829
+ // Event-driven OIDC settle: bounded attempts and no blind multi-second sleeps.
830
+ for (let attempt = 0; attempt < CODEBUDDY_CN_OIDC_MAX_ATTEMPTS; attempt += 1) {
684
831
  if (job.cancelRequested) {
685
832
  throw new Error("Job cancelled while establishing session");
686
833
  }
@@ -697,31 +844,32 @@ export class CodeBuddyCnBulkImportManager extends KiroBulkImportManager {
697
844
  this.setAccountStep(
698
845
  account,
699
846
  "waiting_session",
700
- `OIDC handoff ${attempt + 1}/${OIDC_MAX_ATTEMPTS} → ${path.replace("https://www.codebuddy.cn", "")} (${strong ? "KEYCLOAK" : soft ? "soft-session" : "weak"})`,
847
+ `OIDC handoff ${attempt + 1}/${CODEBUDDY_CN_OIDC_MAX_ATTEMPTS} → ${path.replace("https://www.codebuddy.cn", "")} (${strong ? "KEYCLOAK" : soft ? "soft-session" : "weak"})`,
701
848
  );
702
849
  await this.persistJobSnapshot(job, { forcePreview: false });
703
- await page.goto(path, { waitUntil: "domcontentloaded", timeout: 25_000 }).catch(() => null);
704
- await waitAfterNav();
850
+ await navigateConsole(path);
705
851
  } else {
706
852
  // Soft session present — short yield then re-probe (no blind multi-second sleep).
707
853
  await new Promise((r) => setTimeout(r, 300));
708
854
  }
709
855
 
710
856
  // 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();
857
+ const onCodebuddy = /^https:\/\/www\.codebuddy\.cn(?:[/:]|$)/i.test(page.url?.() || "");
858
+ if (!onCodebuddy) {
859
+ await navigateConsole("https://www.codebuddy.cn/console");
718
860
  }
719
861
 
720
862
  accountsProbe = await probeConsoleAccounts();
721
863
  accountList = extractAccountList(accountsProbe);
722
864
  lastPayloadSnippet = JSON.stringify(accountsProbe?.data ?? accountsProbe?.text ?? null).slice(0, 180);
865
+ const loginHtml = isLoginHtmlProbe(accountsProbe);
723
866
 
724
- if (accountsProbe?.status === 200 && Array.isArray(accountList) && accountList.length > 0) {
867
+ if (
868
+ accountsProbe?.status === 200
869
+ && !loginHtml
870
+ && Array.isArray(accountList)
871
+ && accountList.length > 0
872
+ ) {
725
873
  sessionReady = true;
726
874
  this.setAccountStep(
727
875
  account,
@@ -737,9 +885,11 @@ export class CodeBuddyCnBulkImportManager extends KiroBulkImportManager {
737
885
  if (
738
886
  soft
739
887
  && accountsProbe?.status === 200
888
+ && !loginHtml
889
+ && accountsProbe?.data?._notJson !== true
740
890
  && Array.isArray(accountList)
741
891
  && accountList.length === 0
742
- && attempt >= 4
892
+ && attempt >= 3
743
893
  ) {
744
894
  this.setAccountStep(
745
895
  account,
@@ -754,7 +904,7 @@ export class CodeBuddyCnBulkImportManager extends KiroBulkImportManager {
754
904
  this.setAccountStep(
755
905
  account,
756
906
  "resolving_enterprise",
757
- `Console not ready (HTTP ${accountsProbe?.status || 0}, accounts=${accountList.length}) — ${attempt + 1}/${OIDC_MAX_ATTEMPTS} body=${lastPayloadSnippet.slice(0, 80)}`,
907
+ `Console not ready (HTTP ${accountsProbe?.status || 0}, accounts=${accountList.length}${loginHtml ? ", login HTML" : ""}) — ${attempt + 1}/${CODEBUDDY_CN_OIDC_MAX_ATTEMPTS} body=${lastPayloadSnippet.slice(0, 80)}`,
758
908
  );
759
909
  await this.persistJobSnapshot(job, { forcePreview: false });
760
910
  }
@@ -780,82 +930,150 @@ export class CodeBuddyCnBulkImportManager extends KiroBulkImportManager {
780
930
  this.setAccountStep(account, "creating_api_key", `Creating API key (enterprise=${userEnterpriseId}, accounts=${accountList.length})`);
781
931
  await this.persistJobSnapshot(job, { forcePreview: true });
782
932
 
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;
933
+ // Keep one name for every safe retry in this capture attempt. A timed-out
934
+ // POST has an unknown outcome and must never be sent again automatically.
935
+ const apiKeyName = `zevai-router-${account.workerId || "account"}-${Date.now()}`;
936
+ const createKeyOnPage = async (enterpriseId) => page.evaluate(async ({
937
+ enterpriseId: entId,
938
+ keyName,
939
+ timeoutMs,
940
+ }) => {
941
+ const controller = new AbortController();
942
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
806
943
  try {
807
- data = text ? JSON.parse(text) : null;
808
- } catch {
809
- data = { _raw: String(text || "").slice(0, 200) };
944
+ const host = window.location.hostname || "www.codebuddy.cn";
945
+ const base = host === "www.codebuddy.cn"
946
+ ? window.location.origin
947
+ : "https://www.codebuddy.cn";
948
+ const res = await fetch(`${base}/console/api/client/v1/api-keys`, {
949
+ method: "POST",
950
+ credentials: "include",
951
+ signal: controller.signal,
952
+ headers: {
953
+ "Content-Type": "application/json",
954
+ Accept: "application/json, text/plain, */*",
955
+ "x-requested-with": "XMLHttpRequest",
956
+ "X-Domain": "www.codebuddy.cn",
957
+ "X-Product": "SaaS",
958
+ },
959
+ body: JSON.stringify({
960
+ name: keyName,
961
+ expire_in_days: 365,
962
+ user_enterprise_id: entId,
963
+ }),
964
+ });
965
+ const text = await res.text().catch(() => "");
966
+ let data = null;
967
+ try {
968
+ data = text ? JSON.parse(text) : null;
969
+ } catch {
970
+ data = { _raw: String(text || "").slice(0, 200) };
971
+ }
972
+ return { ok: res.ok, status: res.status, data };
973
+ } catch (error) {
974
+ // Fetch/network failures after a POST starts are ambiguous: the server
975
+ // may have created the key even if the browser lost the response.
976
+ return {
977
+ ok: false,
978
+ status: 0,
979
+ outcomeUnknown: true,
980
+ timedOut: error?.name === "AbortError",
981
+ error: error?.message || String(error),
982
+ };
983
+ } finally {
984
+ clearTimeout(timer);
985
+ }
986
+ }, {
987
+ enterpriseId,
988
+ keyName: apiKeyName,
989
+ timeoutMs: CODEBUDDY_CN_API_KEY_REQUEST_TIMEOUT_MS,
990
+ });
991
+
992
+ const requestApiKey = async (enterpriseId, label) => {
993
+ const startedAt = Date.now();
994
+ let heartbeatPromise = null;
995
+ const heartbeat = setInterval(() => {
996
+ if (heartbeatPromise) return;
997
+ const elapsedSeconds = Math.max(5, Math.round((Date.now() - startedAt) / 1000));
998
+ this.setAccountStep(
999
+ account,
1000
+ "creating_api_key",
1001
+ `${label} — waiting for CodeBuddy (${elapsedSeconds}s)`,
1002
+ );
1003
+ heartbeatPromise = this.persistJobSnapshot(job, { forcePreview: false })
1004
+ .catch(() => null)
1005
+ .finally(() => {
1006
+ heartbeatPromise = null;
1007
+ });
1008
+ }, 5_000);
1009
+ if (typeof heartbeat.unref === "function") heartbeat.unref();
1010
+
1011
+ let result;
1012
+ try {
1013
+ result = await withTimeoutCleanup(createKeyOnPage(enterpriseId), {
1014
+ timeoutMs: CODEBUDDY_CN_API_KEY_REQUEST_TIMEOUT_MS,
1015
+ message: `API key request timed out after ${CODEBUDDY_CN_API_KEY_REQUEST_TIMEOUT_MS / 1000}s; creation outcome is unknown`,
1016
+ code: CODEBUDDY_CN_API_KEY_OUTCOME_UNKNOWN,
1017
+ });
1018
+ } catch (error) {
1019
+ if (error?.code === CODEBUDDY_CN_API_KEY_OUTCOME_UNKNOWN) throw error;
1020
+ throw Object.assign(
1021
+ new Error(`API key request lost its response; creation outcome is unknown: ${error?.message || String(error)}`),
1022
+ { code: CODEBUDDY_CN_API_KEY_OUTCOME_UNKNOWN },
1023
+ );
1024
+ } finally {
1025
+ clearInterval(heartbeat);
1026
+ if (heartbeatPromise) await heartbeatPromise.catch(() => null);
810
1027
  }
811
- return { ok: res.ok, status: res.status, data };
812
- }, { enterpriseId });
1028
+
1029
+ if (result?.outcomeUnknown) {
1030
+ const reason = result.timedOut
1031
+ ? `timed out after ${CODEBUDDY_CN_API_KEY_REQUEST_TIMEOUT_MS / 1000}s`
1032
+ : `lost its response (${result.error || "network error"})`;
1033
+ throw Object.assign(
1034
+ new Error(`API key request ${reason}; creation outcome is unknown`),
1035
+ { code: CODEBUDDY_CN_API_KEY_OUTCOME_UNKNOWN },
1036
+ );
1037
+ }
1038
+ return result;
1039
+ };
813
1040
 
814
1041
  // 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();
1042
+ const keysPageReady = await navigateConsole("https://www.codebuddy.cn/profile/keys");
1043
+ if (!keysPageReady) {
1044
+ throw Object.assign(
1045
+ new Error(`Keys page navigation timed out after ${CODEBUDDY_CN_CONSOLE_NAV_TIMEOUT_MS / 1000}s`),
1046
+ { code: "CN_CONSOLE_NAV_TIMEOUT" },
1047
+ );
1048
+ }
820
1049
 
821
- let apiKeyResult = await createKeyOnPage(userEnterpriseId).catch(() => null);
1050
+ let apiKeyResult = await requestApiKey(userEnterpriseId, "Creating API key");
822
1051
 
823
- // Retry personal id if enterprise id failed or accounts were empty.
1052
+ // A confirmed 400 can safely retry with the personal enterprise id. Do
1053
+ // not retry 5xx/network failures because the POST outcome is ambiguous.
824
1054
  if (
825
- (!apiKeyResult || !apiKeyResult.ok)
1055
+ apiKeyResult?.status === 400
826
1056
  && userEnterpriseId !== PERSONAL_ENTERPRISE_ID
827
1057
  ) {
828
1058
  this.setAccountStep(account, "retrying_api_key", "Retrying with personal-edition enterprise id");
829
1059
  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);
1060
+ apiKeyResult = await requestApiKey(PERSONAL_ENTERPRISE_ID, "Retrying personal API key");
848
1061
  }
849
1062
 
850
1063
  // Retry loop on 401/403 — openresty edge blocks create-key when Keycloak
851
1064
  // 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) {
1065
+ // wait for strong session, then retry with a strict round cap.
1066
+ const isAuthBlocked = (result) =>
1067
+ result?.ok === false && (result.status === 401 || result.status === 403);
1068
+ for (
1069
+ let round = 1;
1070
+ round <= CODEBUDDY_CN_API_REHANDOFF_ROUNDS && isAuthBlocked(apiKeyResult);
1071
+ round += 1
1072
+ ) {
855
1073
  this.setAccountStep(
856
1074
  account,
857
1075
  "retrying_api_key",
858
- `API key 401/403 — OIDC re-handoff round ${round}/3 (waiting strong session)`,
1076
+ `API key 401/403 — OIDC re-handoff round ${round}/${CODEBUDDY_CN_API_REHANDOFF_ROUNDS} (waiting strong session)`,
859
1077
  );
860
1078
  await this.persistJobSnapshot(job, { forcePreview: true });
861
1079
  for (const path of [
@@ -863,15 +1081,17 @@ export class CodeBuddyCnBulkImportManager extends KiroBulkImportManager {
863
1081
  "https://www.codebuddy.cn/console",
864
1082
  "https://www.codebuddy.cn/profile/keys",
865
1083
  ]) {
866
- await page.goto(path, { waitUntil: "domcontentloaded", timeout: 45_000 }).catch(() => null);
867
- await waitAfterNav();
1084
+ await navigateConsole(path);
868
1085
  }
869
1086
  // Wait for strong Keycloak cookie — openresty accepts api-keys only after full session.
870
1087
  await waitUntil(async () => {
871
1088
  const snap = await cookieSnapshot();
872
1089
  return hasStrongKeycloak(snap.names);
873
1090
  }, { timeout: 8_000 * round, interval: 300 }).catch(() => null);
874
- apiKeyResult = await createKeyOnPage(PERSONAL_ENTERPRISE_ID).catch(() => null);
1091
+ apiKeyResult = await requestApiKey(
1092
+ PERSONAL_ENTERPRISE_ID,
1093
+ `Retrying API key after OIDC handoff ${round}/${CODEBUDDY_CN_API_REHANDOFF_ROUNDS}`,
1094
+ );
875
1095
  }
876
1096
 
877
1097
  const businessCode = apiKeyResult?.data?.code;
@@ -904,8 +1124,9 @@ export class CodeBuddyCnBulkImportManager extends KiroBulkImportManager {
904
1124
  apiKeyResult.data.secret;
905
1125
 
906
1126
  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)}`,
1127
+ throw Object.assign(
1128
+ new Error(`API key response did not contain a key field; creation outcome is unknown: ${JSON.stringify(apiKeyResult.data).slice(0, 300)}`),
1129
+ { code: CODEBUDDY_CN_API_KEY_OUTCOME_UNKNOWN },
909
1130
  );
910
1131
  }
911
1132
 
@@ -925,7 +1146,7 @@ export class CodeBuddyCnBulkImportManager extends KiroBulkImportManager {
925
1146
  });
926
1147
 
927
1148
  // Step 10: Finish 5sim order + finalize
928
- await fiveSimClient.finishOrder(fiveSimOrderId);
1149
+ await settleFiveSimOrder(() => fiveSimClient.finishOrder(fiveSimOrderId));
929
1150
 
930
1151
  this.finalizeAccount(account, "success", {
931
1152
  connectionId: connection.id,
@@ -933,21 +1154,35 @@ export class CodeBuddyCnBulkImportManager extends KiroBulkImportManager {
933
1154
  message: `CodeBuddy CN connection saved (phone: ${account.phone})`,
934
1155
  });
935
1156
  account.runtimeSession = null;
936
- await context.close().catch(() => null);
1157
+ await closeContextOrBrowser(context, job);
937
1158
  await this.persistJobSnapshot(job, { forcePreview: true });
938
1159
  } catch (error) {
939
1160
  // If API key capture fails after registration, the account is registered
940
1161
  // but we don't have a key. Surface as needs_manual so the operator can
941
1162
  // create the key manually in the opened browser — number is NOT re-bought.
1163
+ const outcomeUnknown = error?.code === CODEBUDDY_CN_API_KEY_OUTCOME_UNKNOWN;
1164
+ const failureMessage = outcomeUnknown
1165
+ ? `${error.message}. Check the CodeBuddy keys page before creating another key.`
1166
+ : error.message;
942
1167
  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}`,
1168
+ error: `Registration succeeded but API key capture failed: ${failureMessage}`,
1169
+ step: outcomeUnknown ? "api_key_outcome_unknown" : "awaiting_manual",
1170
+ message: outcomeUnknown
1171
+ ? `Registration done; API key request outcome is unknown. Check existing keys before retrying.`
1172
+ : `Registration done, API key capture failed: ${error.message}`,
946
1173
  });
947
1174
  // The 5sim order was successful (SMS received) — finish it (no re-order)
948
- await fiveSimClient.finishOrder(fiveSimOrderId).catch(() => null);
1175
+ await settleFiveSimOrder(() => fiveSimClient.finishOrder(fiveSimOrderId));
949
1176
  await this.persistJobSnapshot(job, { forcePreview: true });
950
1177
 
1178
+ if (outcomeUnknown) {
1179
+ // Closing the page aborts any late browser work. Automatic/manual POST
1180
+ // retries are intentionally disabled because the key may already exist.
1181
+ account.runtimeSession = null;
1182
+ await closeContextOrBrowser(context, job);
1183
+ return;
1184
+ }
1185
+
951
1186
  // Start manual followup for API key capture (reuse same browser session)
952
1187
  await this.runCnManualFollowup(job, account, account.workerId, context, page, fiveSimClient, fiveSimOrderId);
953
1188
  }
@@ -963,18 +1198,21 @@ export class CodeBuddyCnBulkImportManager extends KiroBulkImportManager {
963
1198
  const ms = account.manualSession;
964
1199
  const ctx = ms?.context || context;
965
1200
  const headed = ms?.headedBrowser || null;
966
- if (ctx) await ctx.close().catch(() => null);
967
- if (headed) await headed.close().catch(() => null);
1201
+ await closeContextOrBrowser(ctx, job);
1202
+ if (headed) await forceCloseBrowser(headed).catch(() => null);
968
1203
  };
969
1204
 
970
1205
  try {
971
1206
  this.setAccountStep(account, "manual_waiting", "Waiting for operator to complete in headed browser");
972
1207
  await this.persistJobSnapshot(job, { forcePreview: true });
973
1208
 
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;
1209
+ // Wait up to 3 minutes on low-memory hosts, otherwise 8 minutes.
1210
+ const manualTimeoutMs = isLowMemHost()
1211
+ ? CODEBUDDY_CN_LOW_MEM_MANUAL_TIMEOUT_MS
1212
+ : CODEBUDDY_CN_MANUAL_TIMEOUT_MS;
1213
+ const deadline = Date.now() + manualTimeoutMs;
977
1214
  let apiKey = null;
1215
+ const manualApiKeyName = `zevai-router-manual-${account.workerId || "account"}-${Date.now()}`;
978
1216
 
979
1217
  while (Date.now() < deadline && !job.cancelRequested) {
980
1218
  await new Promise((r) => setTimeout(r, 10_000)); // Check every 10s
@@ -985,28 +1223,60 @@ export class CodeBuddyCnBulkImportManager extends KiroBulkImportManager {
985
1223
  if (!currentUrl.includes("codebuddy.cn")) continue;
986
1224
 
987
1225
  // 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 };
1226
+ const result = await withTimeoutCleanup(page.evaluate(async ({ keyName, timeoutMs }) => {
1227
+ const controller = new AbortController();
1228
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
1229
+ try {
1230
+ const host = window.location.hostname || "www.codebuddy.cn";
1231
+ const base = host === "www.codebuddy.cn"
1232
+ ? window.location.origin
1233
+ : "https://www.codebuddy.cn";
1234
+ const res = await fetch(`${base}/console/api/client/v1/api-keys`, {
1235
+ method: "POST",
1236
+ headers: {
1237
+ "Content-Type": "application/json",
1238
+ Accept: "application/json, text/plain, */*",
1239
+ "x-requested-with": "XMLHttpRequest",
1240
+ "X-Domain": "www.codebuddy.cn",
1241
+ "X-Product": "SaaS",
1242
+ },
1243
+ credentials: "include",
1244
+ signal: controller.signal,
1245
+ body: JSON.stringify({
1246
+ name: keyName,
1247
+ expire_in_days: 365,
1248
+ user_enterprise_id: "personal-edition-user-id",
1249
+ }),
1250
+ });
1251
+ const data = await res.json().catch(() => null);
1252
+ return { ok: res.ok, status: res.status, data };
1253
+ } catch (error) {
1254
+ return {
1255
+ ok: false,
1256
+ status: 0,
1257
+ outcomeUnknown: true,
1258
+ error: error?.message || String(error),
1259
+ };
1260
+ } finally {
1261
+ clearTimeout(timer);
1262
+ }
1263
+ }, {
1264
+ keyName: manualApiKeyName,
1265
+ timeoutMs: CODEBUDDY_CN_API_KEY_REQUEST_TIMEOUT_MS,
1266
+ }), {
1267
+ timeoutMs: CODEBUDDY_CN_API_KEY_REQUEST_TIMEOUT_MS,
1268
+ message: "Manual API key request timed out; creation outcome is unknown",
1269
+ code: CODEBUDDY_CN_API_KEY_OUTCOME_UNKNOWN,
1007
1270
  });
1008
1271
 
1009
- if (result?.ok && result.data) {
1272
+ if (result?.outcomeUnknown) {
1273
+ throw Object.assign(
1274
+ new Error(`Manual API key request lost its response; creation outcome is unknown: ${result.error || "network error"}`),
1275
+ { code: CODEBUDDY_CN_API_KEY_OUTCOME_UNKNOWN },
1276
+ );
1277
+ }
1278
+
1279
+ if (result?.ok) {
1010
1280
  const payload = result.data?.data || result.data;
1011
1281
  apiKey =
1012
1282
  payload?.apiKey ||
@@ -1016,8 +1286,13 @@ export class CodeBuddyCnBulkImportManager extends KiroBulkImportManager {
1016
1286
  payload?.api_key ||
1017
1287
  (typeof payload === "string" ? payload : null);
1018
1288
  if (apiKey && typeof apiKey === "string") break;
1289
+ throw Object.assign(
1290
+ new Error("Manual API key response was successful but did not contain the key; creation outcome is unknown"),
1291
+ { code: CODEBUDDY_CN_API_KEY_OUTCOME_UNKNOWN },
1292
+ );
1019
1293
  }
1020
- } catch {
1294
+ } catch (error) {
1295
+ if (error?.code === CODEBUDDY_CN_API_KEY_OUTCOME_UNKNOWN) throw error;
1021
1296
  // Operator might still be completing — keep waiting
1022
1297
  }
1023
1298
  }
@@ -1061,6 +1336,12 @@ export class CodeBuddyCnBulkImportManager extends KiroBulkImportManager {
1061
1336
  step: "cancelled",
1062
1337
  message: "Job cancelled while waiting for manual completion",
1063
1338
  });
1339
+ } else if (error?.code === CODEBUDDY_CN_API_KEY_OUTCOME_UNKNOWN) {
1340
+ this.finalizeAccount(account, "needs_manual", {
1341
+ error: `${error.message}. Check existing CodeBuddy keys before retrying.`,
1342
+ step: "api_key_outcome_unknown",
1343
+ message: "Manual API key request outcome is unknown; automatic retries stopped",
1344
+ });
1064
1345
  } else {
1065
1346
  this.finalizeAccount(account, "failed", {
1066
1347
  error: error.message || "Manual assist flow failed",
@@ -1244,4 +1525,20 @@ export const __test__ = {
1244
1525
  sanitizeCnJob,
1245
1526
  defaultPhoneFormatter,
1246
1527
  defaultSaveCodeBuddyCnConnection,
1528
+ isLoginHtmlProbe,
1529
+ withTimeoutCleanup,
1530
+ AUTOMATION_LIMITS: {
1531
+ registrationHardTimeoutMs: CODEBUDDY_CN_ACCOUNT_HARD_TIMEOUT_MS,
1532
+ browserLaunchTimeoutMs: CODEBUDDY_CN_BROWSER_LAUNCH_TIMEOUT_MS,
1533
+ contextTimeoutMs: CODEBUDDY_CN_CONTEXT_TIMEOUT_MS,
1534
+ consoleNavTimeoutMs: CODEBUDDY_CN_CONSOLE_NAV_TIMEOUT_MS,
1535
+ consoleProbeTimeoutMs: CODEBUDDY_CN_CONSOLE_PROBE_TIMEOUT_MS,
1536
+ apiKeyRequestTimeoutMs: CODEBUDDY_CN_API_KEY_REQUEST_TIMEOUT_MS,
1537
+ oidcMaxAttempts: CODEBUDDY_CN_OIDC_MAX_ATTEMPTS,
1538
+ apiRehandoffRounds: CODEBUDDY_CN_API_REHANDOFF_ROUNDS,
1539
+ manualTimeoutMs: CODEBUDDY_CN_MANUAL_TIMEOUT_MS,
1540
+ lowMemoryManualTimeoutMs: CODEBUDDY_CN_LOW_MEM_MANUAL_TIMEOUT_MS,
1541
+ resourceCloseTimeoutMs: CODEBUDDY_CN_RESOURCE_CLOSE_TIMEOUT_MS,
1542
+ fiveSimSettleTimeoutMs: CODEBUDDY_CN_FIVESIM_SETTLE_TIMEOUT_MS,
1543
+ },
1247
1544
  };