onbuzz 4.9.13 → 4.10.0

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 (451) hide show
  1. package/node_modules/glob/README.md +31 -5
  2. package/node_modules/glob/dist/commonjs/glob.d.ts +8 -0
  3. package/node_modules/glob/dist/commonjs/glob.d.ts.map +1 -1
  4. package/node_modules/glob/dist/commonjs/glob.js +2 -1
  5. package/node_modules/glob/dist/commonjs/glob.js.map +1 -1
  6. package/node_modules/glob/dist/commonjs/index.min.js +3 -3
  7. package/node_modules/glob/dist/commonjs/index.min.js.map +4 -4
  8. package/node_modules/glob/dist/commonjs/pattern.d.ts +3 -0
  9. package/node_modules/glob/dist/commonjs/pattern.d.ts.map +1 -1
  10. package/node_modules/glob/dist/commonjs/pattern.js +4 -0
  11. package/node_modules/glob/dist/commonjs/pattern.js.map +1 -1
  12. package/node_modules/glob/dist/esm/glob.d.ts +8 -0
  13. package/node_modules/glob/dist/esm/glob.d.ts.map +1 -1
  14. package/node_modules/glob/dist/esm/glob.js +2 -1
  15. package/node_modules/glob/dist/esm/glob.js.map +1 -1
  16. package/node_modules/glob/dist/esm/index.min.js +3 -3
  17. package/node_modules/glob/dist/esm/index.min.js.map +4 -4
  18. package/node_modules/glob/dist/esm/pattern.d.ts +3 -0
  19. package/node_modules/glob/dist/esm/pattern.d.ts.map +1 -1
  20. package/node_modules/glob/dist/esm/pattern.js +4 -0
  21. package/node_modules/glob/dist/esm/pattern.js.map +1 -1
  22. package/node_modules/{@isaacs → glob/node_modules}/balanced-match/README.md +7 -10
  23. package/node_modules/{@isaacs → glob/node_modules}/balanced-match/package.json +7 -18
  24. package/node_modules/{@isaacs → glob/node_modules}/brace-expansion/README.md +3 -6
  25. package/node_modules/{@isaacs → glob/node_modules}/brace-expansion/dist/commonjs/index.js +6 -4
  26. package/node_modules/glob/node_modules/brace-expansion/dist/commonjs/index.js.map +1 -0
  27. package/node_modules/{@isaacs → glob/node_modules}/brace-expansion/dist/esm/index.js +6 -4
  28. package/node_modules/glob/node_modules/brace-expansion/dist/esm/index.js.map +1 -0
  29. package/node_modules/{@isaacs → glob/node_modules}/brace-expansion/package.json +11 -7
  30. package/node_modules/glob/node_modules/minimatch/README.md +76 -1
  31. package/node_modules/glob/node_modules/minimatch/dist/commonjs/assert-valid-pattern.d.ts +1 -1
  32. package/node_modules/glob/node_modules/minimatch/dist/commonjs/assert-valid-pattern.d.ts.map +1 -1
  33. package/node_modules/glob/node_modules/minimatch/dist/commonjs/assert-valid-pattern.js.map +1 -1
  34. package/node_modules/glob/node_modules/minimatch/dist/commonjs/ast.d.ts +4 -2
  35. package/node_modules/glob/node_modules/minimatch/dist/commonjs/ast.d.ts.map +1 -1
  36. package/node_modules/glob/node_modules/minimatch/dist/commonjs/ast.js +309 -55
  37. package/node_modules/glob/node_modules/minimatch/dist/commonjs/ast.js.map +1 -1
  38. package/node_modules/glob/node_modules/minimatch/dist/commonjs/brace-expressions.d.ts.map +1 -1
  39. package/node_modules/glob/node_modules/minimatch/dist/commonjs/brace-expressions.js +2 -4
  40. package/node_modules/glob/node_modules/minimatch/dist/commonjs/brace-expressions.js.map +1 -1
  41. package/node_modules/glob/node_modules/minimatch/dist/commonjs/escape.d.ts +1 -1
  42. package/node_modules/glob/node_modules/minimatch/dist/commonjs/escape.d.ts.map +1 -1
  43. package/node_modules/glob/node_modules/minimatch/dist/commonjs/escape.js +4 -4
  44. package/node_modules/glob/node_modules/minimatch/dist/commonjs/escape.js.map +1 -1
  45. package/node_modules/glob/node_modules/minimatch/dist/commonjs/index.d.ts +81 -1
  46. package/node_modules/glob/node_modules/minimatch/dist/commonjs/index.d.ts.map +1 -1
  47. package/node_modules/glob/node_modules/minimatch/dist/commonjs/index.js +232 -134
  48. package/node_modules/glob/node_modules/minimatch/dist/commonjs/index.js.map +1 -1
  49. package/node_modules/glob/node_modules/minimatch/dist/commonjs/unescape.d.ts +1 -1
  50. package/node_modules/glob/node_modules/minimatch/dist/commonjs/unescape.d.ts.map +1 -1
  51. package/node_modules/glob/node_modules/minimatch/dist/commonjs/unescape.js +8 -8
  52. package/node_modules/glob/node_modules/minimatch/dist/commonjs/unescape.js.map +1 -1
  53. package/node_modules/glob/node_modules/minimatch/dist/esm/assert-valid-pattern.d.ts +1 -1
  54. package/node_modules/glob/node_modules/minimatch/dist/esm/assert-valid-pattern.d.ts.map +1 -1
  55. package/node_modules/glob/node_modules/minimatch/dist/esm/assert-valid-pattern.js.map +1 -1
  56. package/node_modules/glob/node_modules/minimatch/dist/esm/ast.d.ts +4 -2
  57. package/node_modules/glob/node_modules/minimatch/dist/esm/ast.d.ts.map +1 -1
  58. package/node_modules/glob/node_modules/minimatch/dist/esm/ast.js +309 -55
  59. package/node_modules/glob/node_modules/minimatch/dist/esm/ast.js.map +1 -1
  60. package/node_modules/glob/node_modules/minimatch/dist/esm/brace-expressions.d.ts.map +1 -1
  61. package/node_modules/glob/node_modules/minimatch/dist/esm/brace-expressions.js +2 -4
  62. package/node_modules/glob/node_modules/minimatch/dist/esm/brace-expressions.js.map +1 -1
  63. package/node_modules/glob/node_modules/minimatch/dist/esm/escape.d.ts +1 -1
  64. package/node_modules/glob/node_modules/minimatch/dist/esm/escape.d.ts.map +1 -1
  65. package/node_modules/glob/node_modules/minimatch/dist/esm/escape.js +4 -4
  66. package/node_modules/glob/node_modules/minimatch/dist/esm/escape.js.map +1 -1
  67. package/node_modules/glob/node_modules/minimatch/dist/esm/index.d.ts +81 -1
  68. package/node_modules/glob/node_modules/minimatch/dist/esm/index.d.ts.map +1 -1
  69. package/node_modules/glob/node_modules/minimatch/dist/esm/index.js +232 -134
  70. package/node_modules/glob/node_modules/minimatch/dist/esm/index.js.map +1 -1
  71. package/node_modules/glob/node_modules/minimatch/dist/esm/unescape.d.ts +1 -1
  72. package/node_modules/glob/node_modules/minimatch/dist/esm/unescape.d.ts.map +1 -1
  73. package/node_modules/glob/node_modules/minimatch/dist/esm/unescape.js +8 -8
  74. package/node_modules/glob/node_modules/minimatch/dist/esm/unescape.js.map +1 -1
  75. package/node_modules/glob/node_modules/minimatch/package.json +17 -11
  76. package/node_modules/glob/package.json +10 -13
  77. package/node_modules/minipass/LICENSE.md +55 -0
  78. package/node_modules/minipass/dist/commonjs/index.d.ts +12 -16
  79. package/node_modules/minipass/dist/commonjs/index.d.ts.map +1 -1
  80. package/node_modules/minipass/dist/commonjs/index.js +13 -3
  81. package/node_modules/minipass/dist/commonjs/index.js.map +1 -1
  82. package/node_modules/minipass/dist/esm/index.d.ts +12 -16
  83. package/node_modules/minipass/dist/esm/index.d.ts.map +1 -1
  84. package/node_modules/minipass/dist/esm/index.js +3 -1
  85. package/node_modules/minipass/dist/esm/index.js.map +1 -1
  86. package/node_modules/minipass/package.json +9 -14
  87. package/node_modules/path-scurry/node_modules/lru-cache/README.md +96 -10
  88. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/diagnostics-channel-browser.d.ts.map +1 -0
  89. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/diagnostics-channel-browser.js.map +1 -0
  90. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/diagnostics-channel.d.ts +5 -0
  91. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/diagnostics-channel.js +7 -0
  92. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/index.d.ts +1400 -0
  93. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/index.d.ts.map +1 -0
  94. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/index.js +1726 -0
  95. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/index.js.map +1 -0
  96. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/index.min.js +2 -0
  97. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/index.min.js.map +7 -0
  98. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/perf.d.ts +12 -0
  99. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/perf.d.ts.map +1 -0
  100. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/perf.js +10 -0
  101. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/perf.js.map +1 -0
  102. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/diagnostics-channel-cjs.cjs.map +1 -0
  103. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/diagnostics-channel-cjs.d.cts.map +1 -0
  104. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/diagnostics-channel.d.ts +5 -0
  105. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/diagnostics-channel.js +7 -0
  106. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/index.d.ts +109 -32
  107. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/index.d.ts.map +1 -1
  108. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/index.js +334 -197
  109. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/index.js.map +1 -1
  110. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/index.min.js +1 -1
  111. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/index.min.js.map +4 -4
  112. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/diagnostics-channel-node.d.ts.map +1 -0
  113. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/diagnostics-channel-node.js.map +1 -0
  114. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/diagnostics-channel.d.ts +5 -0
  115. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/diagnostics-channel.js +9 -0
  116. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/index.d.ts +1400 -0
  117. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/index.d.ts.map +1 -0
  118. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/index.js +1726 -0
  119. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/index.js.map +1 -0
  120. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/index.min.js +2 -0
  121. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/index.min.js.map +7 -0
  122. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/perf.d.ts +12 -0
  123. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/perf.d.ts.map +1 -0
  124. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/perf.js +10 -0
  125. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/perf.js.map +1 -0
  126. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/perf.d.ts +12 -0
  127. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/perf.d.ts.map +1 -0
  128. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/perf.js +10 -0
  129. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/perf.js.map +1 -0
  130. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/diagnostics-channel-browser.d.ts.map +1 -0
  131. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/diagnostics-channel-browser.js.map +1 -0
  132. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/diagnostics-channel.d.ts +5 -0
  133. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/diagnostics-channel.js +4 -0
  134. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/index.d.ts +1400 -0
  135. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/index.d.ts.map +1 -0
  136. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/index.js +1722 -0
  137. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/index.js.map +1 -0
  138. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/index.min.js +2 -0
  139. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/index.min.js.map +7 -0
  140. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/perf.d.ts +12 -0
  141. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/perf.d.ts.map +1 -0
  142. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/perf.js +7 -0
  143. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/perf.js.map +1 -0
  144. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/diagnostics-channel-esm.d.mts.map +1 -0
  145. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/diagnostics-channel-esm.mjs.map +1 -0
  146. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/diagnostics-channel.d.ts +5 -0
  147. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/diagnostics-channel.js +19 -0
  148. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/index.d.ts +109 -32
  149. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/index.d.ts.map +1 -1
  150. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/index.js +333 -196
  151. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/index.js.map +1 -1
  152. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/index.min.js +1 -1
  153. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/index.min.js.map +4 -4
  154. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/diagnostics-channel-node.d.ts.map +1 -0
  155. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/diagnostics-channel-node.js.map +1 -0
  156. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/diagnostics-channel.d.ts +5 -0
  157. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/diagnostics-channel.js +6 -0
  158. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/index.d.ts +1400 -0
  159. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/index.d.ts.map +1 -0
  160. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/index.js +1722 -0
  161. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/index.js.map +1 -0
  162. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/index.min.js +2 -0
  163. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/index.min.js.map +7 -0
  164. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/perf.d.ts +12 -0
  165. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/perf.d.ts.map +1 -0
  166. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/perf.js +7 -0
  167. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/perf.js.map +1 -0
  168. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/perf.d.ts +12 -0
  169. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/perf.d.ts.map +1 -0
  170. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/perf.js +7 -0
  171. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/perf.js.map +1 -0
  172. package/node_modules/path-scurry/node_modules/lru-cache/package.json +71 -18
  173. package/node_modules/path-scurry/package.json +8 -24
  174. package/package.json +1 -1
  175. package/scripts/debug-balance-probe.mjs +35 -35
  176. package/scripts/push-image.sh +43 -43
  177. package/scripts/setup-acr.sh +65 -65
  178. package/scripts/verify-optional-deps.js +96 -1
  179. package/src/__tests__/composioCliFlags.test.js +239 -239
  180. package/src/analyzers/CSSAnalyzer.js +298 -297
  181. package/src/analyzers/ConfigValidator.js +691 -690
  182. package/src/analyzers/ESLintAnalyzer.js +320 -320
  183. package/src/analyzers/JavaScriptAnalyzer.js +260 -261
  184. package/src/analyzers/PrettierFormatter.js +246 -247
  185. package/src/analyzers/PythonAnalyzer.js +283 -283
  186. package/src/analyzers/SecurityAnalyzer.js +729 -729
  187. package/src/analyzers/SparrowAnalyzer.js +341 -341
  188. package/src/analyzers/TypeScriptAnalyzer.js +247 -247
  189. package/src/analyzers/__tests__/CSSAnalyzer.test.js +41 -41
  190. package/src/analyzers/__tests__/ConfigValidator.test.js +362 -362
  191. package/src/analyzers/__tests__/JavaScriptAnalyzer.test.js +40 -40
  192. package/src/analyzers/__tests__/PythonAnalyzer.test.js +205 -208
  193. package/src/analyzers/__tests__/SecurityAnalyzer.test.js +303 -303
  194. package/src/analyzers/__tests__/TypeScriptAnalyzer.test.js +187 -187
  195. package/src/analyzers/codeCloneDetector/analyzer.js +344 -344
  196. package/src/analyzers/codeCloneDetector/detector.js +250 -250
  197. package/src/analyzers/codeCloneDetector/index.js +194 -192
  198. package/src/analyzers/codeCloneDetector/parser.js +199 -199
  199. package/src/core/__tests__/agentPool.test.js +866 -866
  200. package/src/core/__tests__/agentPoolAutoResume.test.js +209 -209
  201. package/src/core/__tests__/agentPoolWakeOnMessage.test.js +315 -315
  202. package/src/core/__tests__/agentScheduler.emptyResponseChatStall.test.js +213 -213
  203. package/src/core/__tests__/agentScheduler.errorCategorisation.test.js +246 -246
  204. package/src/core/__tests__/agentScheduler.firstChunkTimeout.test.js +138 -138
  205. package/src/core/__tests__/agentScheduler.modeTransitions.test.js +233 -233
  206. package/src/core/__tests__/agentScheduler.nativePromptPick.test.js +319 -319
  207. package/src/core/__tests__/agentScheduler.taskLifecycleInstruction.test.js +78 -78
  208. package/src/core/__tests__/agentScheduler.visualizer.test.js +258 -258
  209. package/src/core/__tests__/flowCheckpointStore.test.js +140 -140
  210. package/src/core/__tests__/flowEndToEnd.test.js +565 -565
  211. package/src/core/__tests__/flowFieldMapping.test.js +188 -189
  212. package/src/core/__tests__/flowLintClientMirror.test.js +96 -98
  213. package/src/core/__tests__/flowSavePayload.test.js +170 -169
  214. package/src/core/__tests__/flowTemplates.test.js +311 -311
  215. package/src/core/__tests__/flowVersionStore.test.js +123 -123
  216. package/src/core/__tests__/messageProcessor.test.js +669 -669
  217. package/src/core/__tests__/stateManager.test.js +0 -1
  218. package/src/core/agentPool.js +2474 -2475
  219. package/src/core/agentScheduler.js +1 -4
  220. package/src/core/contextManager.js +708 -708
  221. package/src/core/flowExecutor.js +1510 -1510
  222. package/src/core/flowFieldMapping.js +136 -138
  223. package/src/core/messageProcessor.js +953 -954
  224. package/src/core/orchestrator.js +593 -595
  225. package/src/core/stateManager.js +1765 -1752
  226. package/src/index.js +1221 -1221
  227. package/src/interfaces/__tests__/archivedAgentDelete.test.js +207 -207
  228. package/src/interfaces/__tests__/bulkAgentRoute.test.js +361 -361
  229. package/src/interfaces/__tests__/imageServing.test.js +228 -228
  230. package/src/interfaces/__tests__/remoteSessionAuth.test.js +308 -308
  231. package/src/interfaces/__tests__/videoJobsRoutes.test.js +178 -179
  232. package/src/interfaces/__tests__/webServer.marketplace.test.js +629 -629
  233. package/src/interfaces/schedulerRoutes.js +50 -50
  234. package/src/interfaces/terminal/__tests__/smoke/connection.test.js +341 -350
  235. package/src/interfaces/terminal/__tests__/smoke/enhancements.test.js +156 -156
  236. package/src/interfaces/terminal/__tests__/smoke/imports.test.js +325 -330
  237. package/src/interfaces/terminal/__tests__/smoke/tools.test.js +385 -388
  238. package/src/interfaces/terminal/api/session.js +265 -266
  239. package/src/interfaces/terminal/api/websocket.js +496 -497
  240. package/src/interfaces/terminal/components/AgentCreator.js +691 -705
  241. package/src/interfaces/terminal/components/AgentEditor.js +676 -678
  242. package/src/interfaces/terminal/components/AgentSwitcher.js +331 -330
  243. package/src/interfaces/terminal/components/ErrorPanel.js +263 -264
  244. package/src/interfaces/terminal/components/Header.js +28 -28
  245. package/src/interfaces/terminal/components/Layout.js +598 -603
  246. package/src/interfaces/terminal/components/MessageList.js +280 -281
  247. package/src/interfaces/terminal/components/SettingsPanel.js +410 -415
  248. package/src/interfaces/terminal/components/StatusBar.js +2 -0
  249. package/src/interfaces/terminal/index.js +168 -168
  250. package/src/interfaces/terminal/state/useAgentControl.js +496 -496
  251. package/src/interfaces/terminal/state/useAgents.js +537 -537
  252. package/src/interfaces/terminal/state/useMessages.js +629 -630
  253. package/src/interfaces/terminal/state/useTools.js +554 -554
  254. package/src/interfaces/terminal/utils/debugLogger.js +44 -44
  255. package/src/interfaces/terminal/utils/settingsStorage.js +232 -232
  256. package/src/interfaces/webServer.js +7578 -7579
  257. package/src/interfaces/webServer.js.bak +7046 -7046
  258. package/src/modules/fileExplorer/__tests__/zipDownload.test.js +237 -237
  259. package/src/modules/fileExplorer/controller.js +470 -469
  260. package/src/modules/fileExplorer/routes.js +285 -286
  261. package/src/modules/widget/__tests__/isDisabled.test.js +41 -41
  262. package/src/modules/widget/__tests__/routes.test.js +677 -678
  263. package/src/modules/widget/__tests__/runtime.test.js +401 -401
  264. package/src/modules/widget/__tests__/versioning.test.js +309 -309
  265. package/src/modules/widget/__tests__/webComponentRuntime.test.js +565 -565
  266. package/src/modules/widget/__tests__/widgetTool.test.js +316 -316
  267. package/src/modules/widget/routes.js +435 -435
  268. package/src/modules/widget/runtime/bundle.js +640 -640
  269. package/src/modules/widget/runtime/webComponentBundle.js +470 -470
  270. package/src/modules/widget/schema.js +182 -181
  271. package/src/modules/widget/widgetTool.js +1389 -1389
  272. package/src/services/__tests__/agentActivityService.test.js +401 -402
  273. package/src/services/__tests__/benchmarkService.test.js +184 -184
  274. package/src/services/__tests__/contextInjectionService.test.js +246 -246
  275. package/src/services/__tests__/conversationQuery.test.js +721 -723
  276. package/src/services/__tests__/credentialVault.test.js +469 -469
  277. package/src/services/__tests__/discordService.integration.test.js +638 -639
  278. package/src/services/__tests__/flowContextService.test.js +590 -590
  279. package/src/services/__tests__/memoryService.test.js +1 -1
  280. package/src/services/__tests__/messageSource.test.js +380 -380
  281. package/src/services/__tests__/modelRouterNaming.test.js +111 -111
  282. package/src/services/__tests__/projectDetector.test.js +34 -34
  283. package/src/services/__tests__/promptService.test.js +242 -242
  284. package/src/services/__tests__/telegramService.test.js +941 -941
  285. package/src/services/__tests__/tokenCountingService.test.js +48 -48
  286. package/src/services/agentActivityService.js +419 -420
  287. package/src/services/aiService.js +2997 -3001
  288. package/src/services/apiKeyManager.js +359 -359
  289. package/src/services/benchmarkService.js +196 -196
  290. package/src/services/codebaseKnowledgeService.js +2 -2
  291. package/src/services/composioService.js +738 -738
  292. package/src/services/conversationCompactionService.js +1258 -1257
  293. package/src/services/credentialVault.js +685 -685
  294. package/src/services/discordService.js +792 -793
  295. package/src/services/embeddings/__tests__/azureCustomProvider.test.js +232 -232
  296. package/src/services/embeddings/__tests__/embeddingService.test.js +417 -417
  297. package/src/services/embeddings/__tests__/localProvider.test.js +263 -263
  298. package/src/services/embeddings/autoRecall.js +218 -219
  299. package/src/services/embeddings/indexers/__tests__/agentIndexer.test.js +232 -232
  300. package/src/services/embeddings/indexers/__tests__/memoryIndexer.test.js +418 -418
  301. package/src/services/embeddings/indexers/__tests__/reminisceIndexer.test.js +356 -357
  302. package/src/services/embeddings/indexers/__tests__/skillsIndexer.test.js +145 -145
  303. package/src/services/embeddings/indexers/__tests__/taskIndexer.test.js +146 -146
  304. package/src/services/embeddings/indexers/composioIndexer.js +279 -279
  305. package/src/services/embeddings/providerInterface.js +206 -206
  306. package/src/services/embeddings/providers/localProvider.js +11 -7
  307. package/src/services/embeddings/providers/openaiProvider.js +101 -101
  308. package/src/services/embeddings/vectorStore/inMemoryJsonStore.js +356 -356
  309. package/src/services/errorHandler.js +809 -809
  310. package/src/services/flowContextService.js +586 -586
  311. package/src/services/grounding/MockAdapter.js +125 -125
  312. package/src/services/modelRouterService.js +26 -31
  313. package/src/services/modelsService.js +322 -322
  314. package/src/services/ollamaService.js +452 -452
  315. package/src/services/projectDetector.js +403 -404
  316. package/src/services/promptService.js +418 -418
  317. package/src/services/qualityInspector.js +795 -795
  318. package/src/services/scheduleService.js +726 -726
  319. package/src/services/serviceRegistry.js +386 -386
  320. package/src/services/telegrafBot.js +174 -174
  321. package/src/services/telegramService.js +1972 -1972
  322. package/src/services/visualEditorBridge.js +1033 -1033
  323. package/src/services/visualEditorServer.js +1769 -1774
  324. package/src/services/whatsappService.js +667 -668
  325. package/src/tools/__tests__/agentCommunicationTool.findAgent.test.js +226 -226
  326. package/src/tools/__tests__/agentCommunicationTool.test.js +3 -3
  327. package/src/tools/__tests__/agentDelayTool.test.js +342 -342
  328. package/src/tools/__tests__/baseTool.test.js +3 -3
  329. package/src/tools/__tests__/codeMapTool.test.js +915 -915
  330. package/src/tools/__tests__/fileContentReplaceTool.test.js +309 -309
  331. package/src/tools/__tests__/fileTreeTool.test.js +274 -274
  332. package/src/tools/__tests__/filesystemTool.test.js +815 -815
  333. package/src/tools/__tests__/foundryWebSearchTool.test.js +252 -252
  334. package/src/tools/__tests__/imageTool.validator.test.js +194 -194
  335. package/src/tools/__tests__/jobDoneTool.test.js +580 -581
  336. package/src/tools/__tests__/memoryTool.forgetStale.test.js +272 -272
  337. package/src/tools/__tests__/memoryTool.reminisce.test.js +2 -2
  338. package/src/tools/__tests__/memoryTool.reminisceSemanticSearch.test.js +301 -301
  339. package/src/tools/__tests__/memoryTool.semanticSearch.test.js +405 -405
  340. package/src/tools/__tests__/memoryTool.teamPool.test.js +293 -293
  341. package/src/tools/__tests__/memoryTool.test.js +1 -1
  342. package/src/tools/__tests__/seekTool.test.js +282 -282
  343. package/src/tools/__tests__/skillsTool.search.test.js +164 -164
  344. package/src/tools/__tests__/skillsTool.test.js +226 -226
  345. package/src/tools/__tests__/staticAnalysisTool.test.js +509 -509
  346. package/src/tools/__tests__/taskManagerTool.discipline.test.js +137 -137
  347. package/src/tools/__tests__/taskManagerTool.search.test.js +143 -143
  348. package/src/tools/__tests__/taskManagerTool.test.js +866 -866
  349. package/src/tools/__tests__/terminalTool.test.js +448 -448
  350. package/src/tools/__tests__/toolShapeForgiveness.test.js +259 -260
  351. package/src/tools/__tests__/userPromptTool.test.js +297 -297
  352. package/src/tools/__tests__/videoTool.jobs.test.js +147 -147
  353. package/src/tools/__tests__/webTool.e2e.test.js +609 -603
  354. package/src/tools/__tests__/webTool.unit.test.js +195 -195
  355. package/src/tools/__tests__/webTool.visionModel.test.js +75 -75
  356. package/src/tools/agentCommunicationTool.js +8 -10
  357. package/src/tools/agentDelayTool.js +496 -497
  358. package/src/tools/asyncToolManager.js +602 -603
  359. package/src/tools/baseTool.js +12 -11
  360. package/src/tools/cloneDetectionTool.js +576 -581
  361. package/src/tools/codeMapTool.js +0 -6
  362. package/src/tools/composioTool.js +617 -617
  363. package/src/tools/dependencyResolverTool.js +1211 -1212
  364. package/src/tools/desktop/DesktopTool.js +629 -638
  365. package/src/tools/desktop/__tests__/DesktopTool.e2e.test.js +306 -306
  366. package/src/tools/desktop/__tests__/DesktopTool.test.js +507 -507
  367. package/src/tools/desktop/__tests__/osController.test.js +364 -364
  368. package/src/tools/desktop/osController.js +491 -491
  369. package/src/tools/docxTool.js +623 -623
  370. package/src/tools/excelTool.js +636 -636
  371. package/src/tools/fileContentReplaceTool.js +5 -7
  372. package/src/tools/fileSystemTool.js +12 -19
  373. package/src/tools/fileTreeTool.js +840 -840
  374. package/src/tools/foundryWebSearchTool.js +273 -273
  375. package/src/tools/helpTool.js +198 -198
  376. package/src/tools/imageTool.js +1397 -1397
  377. package/src/tools/importAnalyzerTool.js +1056 -1056
  378. package/src/tools/jobDoneTool.js +495 -495
  379. package/src/tools/memoryTool.js +1 -1
  380. package/src/tools/office/pres/__tests__/presSystem.test.js +365 -365
  381. package/src/tools/office/pres/archetypes/agenda.js +61 -61
  382. package/src/tools/office/pres/archetypes/bentoGrid.js +218 -219
  383. package/src/tools/office/pres/archetypes/bigStat.js +140 -142
  384. package/src/tools/office/pres/archetypes/closing.js +70 -70
  385. package/src/tools/office/pres/archetypes/hero.js +70 -70
  386. package/src/tools/office/pres/archetypes/productHero.js +93 -94
  387. package/src/tools/office/pres/archetypes/table.js +73 -74
  388. package/src/tools/office/pres/backgrounds/orb.js +66 -66
  389. package/src/tools/office/pres/components.js +422 -423
  390. package/src/tools/officeTool.js +441 -441
  391. package/src/tools/pdfTool.js +625 -627
  392. package/src/tools/platformControlTool.js +1081 -1081
  393. package/src/tools/seekTool.js +917 -918
  394. package/src/tools/skillsTool.js +1 -1
  395. package/src/tools/staticAnalysisTool.js +2143 -2146
  396. package/src/tools/taskManagerTool.js +3324 -3324
  397. package/src/tools/terminalTool.js +2615 -2618
  398. package/src/tools/videoTool.js +1303 -1303
  399. package/src/tools/visionTool.js +508 -508
  400. package/src/tools/visualEditorTool.js +1289 -1290
  401. package/src/tools/webTool.js +3368 -3368
  402. package/src/tools/whatsappTool.js +464 -464
  403. package/src/types/__tests__/agent.test.js +499 -499
  404. package/src/types/__tests__/contextReference.test.js +606 -606
  405. package/src/types/__tests__/conversation.test.js +555 -555
  406. package/src/types/__tests__/toolCommand.test.js +584 -584
  407. package/src/types/contextReference.js +974 -971
  408. package/src/types/conversation.js +729 -729
  409. package/src/types/toolCommand.js +746 -746
  410. package/src/utilities/__tests__/attachmentValidator.test.js +80 -80
  411. package/src/utilities/__tests__/auditReport.test.js +328 -328
  412. package/src/utilities/__tests__/directoryAccessManager.test.js +388 -388
  413. package/src/utilities/__tests__/jsonRepair.test.js +103 -104
  414. package/src/utilities/__tests__/modeTransitionReasons.test.js +105 -105
  415. package/src/utilities/__tests__/platformUtils.test.js +80 -87
  416. package/src/utilities/__tests__/structuredFileValidator.test.js +261 -263
  417. package/src/utilities/__tests__/toolConstants.test.js +92 -94
  418. package/src/utilities/__tests__/useIsTouchDevice.detect.test.js +114 -114
  419. package/src/utilities/__tests__/webUiUtilSync.test.js +117 -117
  420. package/src/utilities/attachmentValidator.js +284 -288
  421. package/src/utilities/authCache.js.backup-1779570472481 +121 -121
  422. package/src/utilities/browserStealth.js +631 -630
  423. package/src/utilities/configManager.js +616 -617
  424. package/src/utilities/directoryAccessManager.js +564 -565
  425. package/src/utilities/fileProcessor.js +308 -307
  426. package/src/utilities/humanBehavior.js +454 -453
  427. package/src/utilities/logger.js +479 -479
  428. package/src/utilities/structuredFileValidator.js +696 -699
  429. package/src/utilities/tagParser.js +5 -10
  430. package/src/utilities/userDataDir.js +308 -308
  431. package/node_modules/@isaacs/brace-expansion/dist/commonjs/index.js.map +0 -1
  432. package/node_modules/@isaacs/brace-expansion/dist/esm/index.js.map +0 -1
  433. package/node_modules/minipass/LICENSE +0 -15
  434. /package/node_modules/{@isaacs → glob/node_modules}/balanced-match/LICENSE.md +0 -0
  435. /package/node_modules/{@isaacs → glob/node_modules}/balanced-match/dist/commonjs/index.d.ts +0 -0
  436. /package/node_modules/{@isaacs → glob/node_modules}/balanced-match/dist/commonjs/index.d.ts.map +0 -0
  437. /package/node_modules/{@isaacs → glob/node_modules}/balanced-match/dist/commonjs/index.js +0 -0
  438. /package/node_modules/{@isaacs → glob/node_modules}/balanced-match/dist/commonjs/index.js.map +0 -0
  439. /package/node_modules/{@isaacs → glob/node_modules}/balanced-match/dist/commonjs/package.json +0 -0
  440. /package/node_modules/{@isaacs → glob/node_modules}/balanced-match/dist/esm/index.d.ts +0 -0
  441. /package/node_modules/{@isaacs → glob/node_modules}/balanced-match/dist/esm/index.d.ts.map +0 -0
  442. /package/node_modules/{@isaacs → glob/node_modules}/balanced-match/dist/esm/index.js +0 -0
  443. /package/node_modules/{@isaacs → glob/node_modules}/balanced-match/dist/esm/index.js.map +0 -0
  444. /package/node_modules/{@isaacs → glob/node_modules}/balanced-match/dist/esm/package.json +0 -0
  445. /package/node_modules/{@isaacs → glob/node_modules}/brace-expansion/LICENSE +0 -0
  446. /package/node_modules/{@isaacs → glob/node_modules}/brace-expansion/dist/commonjs/index.d.ts +0 -0
  447. /package/node_modules/{@isaacs → glob/node_modules}/brace-expansion/dist/commonjs/index.d.ts.map +0 -0
  448. /package/node_modules/{@isaacs → glob/node_modules}/brace-expansion/dist/commonjs/package.json +0 -0
  449. /package/node_modules/{@isaacs → glob/node_modules}/brace-expansion/dist/esm/index.d.ts +0 -0
  450. /package/node_modules/{@isaacs → glob/node_modules}/brace-expansion/dist/esm/index.d.ts.map +0 -0
  451. /package/node_modules/{@isaacs → glob/node_modules}/brace-expansion/dist/esm/package.json +0 -0
@@ -1,630 +1,631 @@
1
- /**
2
- * Browser Stealth Utility
3
- *
4
- * Provides a stealthy Puppeteer browser instance with anti-detection measures.
5
- * Uses puppeteer-extra with stealth plugin for fingerprint evasion.
6
- */
7
-
8
- import puppeteer from 'puppeteer-extra';
9
- import StealthPlugin from 'puppeteer-extra-plugin-stealth';
10
- import {
11
- BROWSER_CONFIG,
12
- USER_AGENTS,
13
- STEALTH_EVASIONS,
14
- STEALTH_LEVELS,
15
- DEFAULT_STEALTH_LEVEL
16
- } from './stealthConstants.js';
17
- import { getPlatform } from './platformUtils.js';
18
-
19
- // Track if stealth plugin has been configured
20
- let stealthPluginConfigured = false;
21
-
22
- /**
23
- * Configure and apply stealth plugin with all evasions enabled
24
- * @param {Object} options - Configuration options
25
- * @param {string[]} options.excludeEvasions - Evasions to exclude
26
- * @returns {void}
27
- */
28
- function configureStealthPlugin(options = {}) {
29
- // Only configure once (puppeteer-extra plugins are singletons)
30
- if (stealthPluginConfigured) return;
31
-
32
- const { excludeEvasions = STEALTH_EVASIONS.EXCLUDE } = options;
33
-
34
- const stealth = StealthPlugin();
35
-
36
- // Ensure ALL evasions are enabled for maximum stealth
37
- const allEvasions = new Set([
38
- 'chrome.app',
39
- 'chrome.csi',
40
- 'chrome.loadTimes',
41
- 'chrome.runtime',
42
- 'defaultArgs',
43
- 'iframe.contentWindow',
44
- 'media.codecs',
45
- 'navigator.hardwareConcurrency',
46
- 'navigator.languages',
47
- 'navigator.permissions',
48
- 'navigator.plugins',
49
- 'navigator.webdriver',
50
- 'sourceurl',
51
- 'user-agent-override',
52
- 'webgl.vendor',
53
- 'window.outerdimensions'
54
- ]);
55
-
56
- stealth.enabledEvasions = allEvasions;
57
-
58
- // Remove any excluded evasions
59
- if (excludeEvasions && excludeEvasions.length > 0) {
60
- excludeEvasions.forEach(evasion => {
61
- stealth.enabledEvasions.delete(evasion);
62
- });
63
- }
64
-
65
- puppeteer.use(stealth);
66
- stealthPluginConfigured = true;
67
- }
68
-
69
- /**
70
- * Get a random user agent string based on current platform
71
- * @param {string} [forcePlatform] - Force specific platform (windows, macos, linux)
72
- * @returns {string} Random user agent string
73
- */
74
- export function getRandomUserAgent(forcePlatform = null) {
75
- const platform = forcePlatform || getPlatform();
76
-
77
- let agents;
78
- switch (platform) {
79
- case 'darwin':
80
- case 'macos':
81
- agents = USER_AGENTS.MACOS;
82
- break;
83
- case 'linux':
84
- agents = USER_AGENTS.LINUX;
85
- break;
86
- case 'win32':
87
- case 'windows':
88
- default:
89
- agents = USER_AGENTS.WINDOWS;
90
- break;
91
- }
92
-
93
- return agents[Math.floor(Math.random() * agents.length)];
94
- }
95
-
96
- /**
97
- * Get a random viewport configuration
98
- * @returns {Object} Viewport configuration { width, height }
99
- */
100
- export function getRandomViewport() {
101
- const viewports = BROWSER_CONFIG.VIEWPORT_VARIANTS;
102
- return viewports[Math.floor(Math.random() * viewports.length)];
103
- }
104
-
105
- /**
106
- * Generate browser launch arguments for stealth mode
107
- * @param {Object} options - Configuration options
108
- * @param {string} options.userAgent - User agent to use (random if not specified)
109
- * @param {boolean} options.headless - Whether to run headless
110
- * @returns {string[]} Array of Chrome launch arguments
111
- */
112
- export function getStealthLaunchArgs(options = {}) {
113
- const { userAgent = getRandomUserAgent(), headless = true } = options;
114
-
115
- const args = [
116
- // Sandbox settings (required for some environments)
117
- '--no-sandbox',
118
- '--disable-setuid-sandbox',
119
-
120
- // Performance optimizations
121
- '--disable-dev-shm-usage',
122
-
123
- // CRITICAL: Disable automation detection flags
124
- '--disable-blink-features=AutomationControlled',
125
-
126
- // Disable infobars ("Chrome is being controlled by automated software")
127
- '--disable-infobars',
128
-
129
- // Disable extensions (but not in a detectable way)
130
- '--disable-extensions',
131
-
132
- // Set user agent
133
- `--user-agent=${userAgent}`,
134
-
135
- // Disable automation extension
136
- '--disable-component-extensions-with-background-pages',
137
-
138
- // Window size (matches viewport for consistency)
139
- '--window-size=1920,1080',
140
-
141
- // Additional anti-detection
142
- '--disable-background-networking',
143
- '--disable-default-apps',
144
- '--disable-sync',
145
- '--disable-translate',
146
- '--metrics-recording-only',
147
- '--no-first-run',
148
-
149
- // REMOVED: --use-gl=swiftshader (MAJOR DETECTION VECTOR - SwiftShader is bot indicator)
150
- // REMOVED: --disable-accelerated-2d-canvas (suspicious flag)
151
- // REMOVED: --disable-software-rasterizer (contradicts and is detectable)
152
-
153
- // Enable hardware acceleration for realistic fingerprint
154
- '--enable-webgl',
155
- '--enable-accelerated-2d-canvas',
156
-
157
- // Disable features that leak automation
158
- '--disable-hang-monitor',
159
- '--disable-ipc-flooding-protection',
160
- '--disable-popup-blocking',
161
- '--disable-prompt-on-repost',
162
- '--disable-renderer-backgrounding',
163
- '--disable-backgrounding-occluded-windows',
164
-
165
- // Privacy-related (appear more like real user)
166
- '--disable-client-side-phishing-detection',
167
-
168
- // Prevent WebRTC IP leak
169
- '--disable-webrtc-hw-encoding',
170
- '--disable-webrtc-hw-decoding',
171
- '--enforce-webrtc-ip-permission-check'
172
- ];
173
-
174
- // Only disable GPU in headless mode (detection vector otherwise)
175
- if (headless) {
176
- args.push('--disable-gpu');
177
- }
178
-
179
- return args;
180
- }
181
-
182
- /**
183
- * Create a stealthy browser instance
184
- * @param {Object} options - Browser options
185
- * @param {string} options.stealthLevel - Stealth level: 'standard' or 'maximum' (default: 'standard')
186
- * @param {boolean} options.headless - Override headless mode (uses stealthLevel if not specified)
187
- * @param {string} options.userAgent - Specific user agent (random if not specified)
188
- * @param {Object} options.viewport - Viewport dimensions (random if not specified)
189
- * @param {string[]} options.excludeEvasions - Stealth evasions to exclude
190
- * @param {Object} options.logger - Logger instance
191
- * @returns {Promise<Browser>} Puppeteer browser instance
192
- */
193
- export async function createStealthBrowser(options = {}) {
194
- const {
195
- stealthLevel = DEFAULT_STEALTH_LEVEL,
196
- headless,
197
- userAgent = getRandomUserAgent(),
198
- viewport = getRandomViewport(),
199
- excludeEvasions = []
200
- } = options;
201
-
202
- // Ensure logger is valid (null doesn't trigger default in destructuring)
203
- const logger = options.logger || console;
204
-
205
- // Resolve stealth level configuration
206
- const levelConfig = STEALTH_LEVELS[stealthLevel.toUpperCase()] || STEALTH_LEVELS.STANDARD;
207
-
208
- // headless parameter overrides stealthLevel if explicitly provided
209
- const useHeadless = headless !== undefined ? headless : levelConfig.headless;
210
- const isHeadless = useHeadless === true || useHeadless === 'new';
211
-
212
- // Configure stealth plugin (only needs to be done once)
213
- configureStealthPlugin({ excludeEvasions });
214
-
215
- logger.info?.('[BrowserStealth] Creating stealth browser', {
216
- stealthLevel,
217
- headless: useHeadless,
218
- viewport,
219
- userAgentPrefix: userAgent.substring(0, 50) + '...'
220
- });
221
-
222
- const browser = await puppeteer.launch({
223
- headless: useHeadless === true ? 'new' : useHeadless,
224
- args: getStealthLaunchArgs({ userAgent, headless: isHeadless }),
225
- ignoreDefaultArgs: ['--enable-automation'],
226
- defaultViewport: {
227
- width: viewport.width,
228
- height: viewport.height
229
- }
230
- });
231
-
232
- // Store configuration on browser instance for reference
233
- browser._stealthConfig = {
234
- stealthLevel,
235
- headless: useHeadless,
236
- userAgent,
237
- viewport,
238
- createdAt: Date.now()
239
- };
240
-
241
- logger.info?.('[BrowserStealth] Stealth browser created successfully', {
242
- stealthLevel,
243
- headless: useHeadless
244
- });
245
-
246
- return browser;
247
- }
248
-
249
- /**
250
- * Create a new page with stealth enhancements
251
- * @param {Browser} browser - Puppeteer browser instance
252
- * @param {Object} options - Page options
253
- * @param {string} options.userAgent - Override user agent for this page
254
- * @param {Object} options.viewport - Override viewport for this page
255
- * @param {Object} options.logger - Logger instance
256
- * @returns {Promise<Page>} Puppeteer page instance
257
- */
258
- export async function createStealthPage(browser, options = {}) {
259
- const {
260
- userAgent = browser._stealthConfig?.userAgent || getRandomUserAgent(),
261
- viewport = browser._stealthConfig?.viewport || getRandomViewport(),
262
- maxRetries = 3
263
- } = options;
264
-
265
- // Ensure logger is valid (null doesn't trigger default in destructuring)
266
- const logger = options.logger || console;
267
-
268
- let page;
269
- let lastError;
270
-
271
- // Retry page creation to handle race conditions with stealth plugin
272
- for (let attempt = 1; attempt <= maxRetries; attempt++) {
273
- try {
274
- page = await browser.newPage();
275
-
276
- // Give stealth plugin more time to apply evasions
277
- // puppeteer-extra-plugin-stealth has timing issues with newer puppeteer versions
278
- await new Promise(resolve => setTimeout(resolve, 300));
279
-
280
- // Wait for page to be ready (handles "Requesting main frame too early" issue)
281
- try {
282
- await page.waitForFunction(() => true, { timeout: 2000 });
283
- } catch (frameError) {
284
- // Ignore frame timing errors - page may still work
285
- logger.warn?.('[BrowserStealth] Frame wait warning (non-fatal):', frameError.message);
286
- }
287
-
288
- // Verify page is still open
289
- if (page.isClosed()) {
290
- throw new Error('Page closed during stealth setup');
291
- }
292
-
293
- break; // Success
294
- } catch (error) {
295
- lastError = error;
296
- const isRetryableError = error.message?.includes('Session closed') ||
297
- error.message?.includes('Target closed') ||
298
- error.message?.includes('Protocol error') ||
299
- error.message?.includes('Requesting main frame too early') ||
300
- error.message?.includes('Connection closed');
301
-
302
- if (isRetryableError && attempt < maxRetries) {
303
- logger.warn?.(`[BrowserStealth] Page creation failed (attempt ${attempt}/${maxRetries}), retrying...`);
304
- await new Promise(resolve => setTimeout(resolve, 500 * attempt)); // Longer backoff
305
- continue;
306
- }
307
-
308
- throw error;
309
- }
310
- }
311
-
312
- if (!page) {
313
- throw lastError || new Error('Failed to create page after retries');
314
- }
315
-
316
- // Configure page with error handling for race conditions
317
- try {
318
- // Check if page is still valid before configuring
319
- if (page.isClosed()) {
320
- throw new Error('Page was closed before configuration could complete');
321
- }
322
-
323
- // Set user agent
324
- await page.setUserAgent(userAgent);
325
-
326
- // Set viewport
327
- await page.setViewport({
328
- width: viewport.width,
329
- height: viewport.height,
330
- deviceScaleFactor: 1,
331
- hasTouch: false,
332
- isLandscape: true,
333
- isMobile: false
334
- });
335
-
336
- // Set additional headers to appear more human
337
- // IMPORTANT: Only set headers that are safe for ALL request types (navigation + XHR/fetch)
338
- // Headers like 'Upgrade-Insecure-Requests' and 'Sec-Fetch-*' are navigation-only
339
- // and will break CORS preflight checks on API calls if included here!
340
- await page.setExtraHTTPHeaders({
341
- 'Accept-Language': 'en-US,en;q=0.9'
342
- // REMOVED: 'Upgrade-Insecure-Requests' - breaks CORS on API calls
343
- // REMOVED: 'Sec-Fetch-*' headers - browser sets these automatically and correctly
344
- // REMOVED: 'Accept-Encoding' - browser handles this
345
- // REMOVED: 'Accept' - varies by request type, let browser handle it
346
- });
347
- } catch (configError) {
348
- // Close page if it's still open after config error
349
- try {
350
- if (!page.isClosed()) await page.close();
351
- } catch { /* ignore close error */ }
352
-
353
- // Re-throw with context
354
- const isTargetClosed = configError.message?.includes('Session closed') ||
355
- configError.message?.includes('Target closed');
356
- if (isTargetClosed) {
357
- throw new Error('Page closed during stealth configuration. Browser may have crashed or been closed externally.');
358
- }
359
- throw configError;
360
- }
361
-
362
- // Override navigator properties that stealth might miss
363
- await page.evaluateOnNewDocument(() => {
364
- // Override webdriver - multiple approaches for maximum coverage
365
- Object.defineProperty(navigator, 'webdriver', {
366
- get: () => false, // Return false instead of undefined (more realistic)
367
- configurable: true
368
- });
369
-
370
- // Also delete it if it exists
371
- try {
372
- delete navigator.webdriver;
373
- } catch (e) { /* ignore */ }
374
-
375
- // Add missing navigator.connection (NetworkInformation API) - sites check this!
376
- if (!navigator.connection) {
377
- Object.defineProperty(navigator, 'connection', {
378
- get: () => ({
379
- effectiveType: '4g',
380
- rtt: 50,
381
- downlink: 10,
382
- saveData: false,
383
- type: 'wifi',
384
- onchange: null,
385
- addEventListener: () => {},
386
- removeEventListener: () => {},
387
- dispatchEvent: () => true
388
- }),
389
- configurable: true
390
- });
391
- }
392
-
393
- // Add navigator.deviceMemory (sites check this for fingerprinting)
394
- if (!navigator.deviceMemory) {
395
- Object.defineProperty(navigator, 'deviceMemory', {
396
- get: () => 8, // 8GB - common value
397
- configurable: true
398
- });
399
- }
400
-
401
- // Add navigator.getBattery (some sites check this exists)
402
- if (!navigator.getBattery) {
403
- navigator.getBattery = () => Promise.resolve({
404
- charging: true,
405
- chargingTime: 0,
406
- dischargingTime: Infinity,
407
- level: 1,
408
- addEventListener: () => {},
409
- removeEventListener: () => {}
410
- });
411
- }
412
-
413
- // Override Notification.permission (sites check this)
414
- try {
415
- Object.defineProperty(Notification, 'permission', {
416
- get: () => 'default',
417
- configurable: true
418
- });
419
- } catch (e) { /* ignore */ }
420
-
421
- // Override plugins with realistic plugin array
422
- const mockPlugins = [
423
- {
424
- name: 'Chrome PDF Plugin',
425
- filename: 'internal-pdf-viewer',
426
- description: 'Portable Document Format',
427
- length: 1,
428
- item: () => null,
429
- namedItem: () => null,
430
- [Symbol.iterator]: function* () { yield this; }
431
- },
432
- {
433
- name: 'Chrome PDF Viewer',
434
- filename: 'mhjfbmdgcfjbbpaeojofohoefgiehjai',
435
- description: '',
436
- length: 1,
437
- item: () => null,
438
- namedItem: () => null,
439
- [Symbol.iterator]: function* () { yield this; }
440
- },
441
- {
442
- name: 'Native Client',
443
- filename: 'internal-nacl-plugin',
444
- description: '',
445
- length: 2,
446
- item: () => null,
447
- namedItem: () => null,
448
- [Symbol.iterator]: function* () { yield this; }
449
- }
450
- ];
451
-
452
- Object.defineProperty(navigator, 'plugins', {
453
- get: () => {
454
- const plugins = mockPlugins;
455
- plugins.item = (i) => plugins[i] || null;
456
- plugins.namedItem = (name) => plugins.find(p => p.name === name) || null;
457
- plugins.refresh = () => {};
458
- return plugins;
459
- }
460
- });
461
-
462
- // Override mimeTypes
463
- Object.defineProperty(navigator, 'mimeTypes', {
464
- get: () => {
465
- const mimeTypes = [
466
- { type: 'application/pdf', suffixes: 'pdf', description: 'Portable Document Format' },
467
- { type: 'application/x-google-chrome-pdf', suffixes: 'pdf', description: 'Portable Document Format' }
468
- ];
469
- mimeTypes.item = (i) => mimeTypes[i] || null;
470
- mimeTypes.namedItem = (name) => mimeTypes.find(m => m.type === name) || null;
471
- return mimeTypes;
472
- }
473
- });
474
-
475
- // Override languages
476
- Object.defineProperty(navigator, 'languages', {
477
- get: () => ['en-US', 'en']
478
- });
479
-
480
- // Override permissions query
481
- const originalQuery = window.navigator.permissions.query;
482
- window.navigator.permissions.query = (parameters) => (
483
- parameters.name === 'notifications' ?
484
- Promise.resolve({ state: Notification.permission }) :
485
- originalQuery(parameters)
486
- );
487
-
488
- // Enhanced WebGL vendor/renderer spoofing
489
- const spoofWebGL = (target) => {
490
- const getParameter = target.prototype.getParameter;
491
- target.prototype.getParameter = function(parameter) {
492
- // UNMASKED_VENDOR_WEBGL
493
- if (parameter === 37445) {
494
- return 'Intel Inc.';
495
- }
496
- // UNMASKED_RENDERER_WEBGL
497
- if (parameter === 37446) {
498
- return 'Intel Iris OpenGL Engine';
499
- }
500
- return getParameter.call(this, parameter);
501
- };
502
- };
503
-
504
- // Apply to both WebGL contexts
505
- if (typeof WebGLRenderingContext !== 'undefined') {
506
- spoofWebGL(WebGLRenderingContext);
507
- }
508
- if (typeof WebGL2RenderingContext !== 'undefined') {
509
- spoofWebGL(WebGL2RenderingContext);
510
- }
511
-
512
- // Hide automation-related properties (CDP detection)
513
- const automationProps = [
514
- 'cdc_adoQpoasnfa76pfcZLmcfl_Array',
515
- 'cdc_adoQpoasnfa76pfcZLmcfl_Promise',
516
- 'cdc_adoQpoasnfa76pfcZLmcfl_Symbol',
517
- '__webdriver_evaluate',
518
- '__selenium_evaluate',
519
- '__webdriver_script_function',
520
- '__webdriver_script_func',
521
- '__webdriver_script_fn',
522
- '__fxdriver_evaluate',
523
- '__driver_unwrapped',
524
- '__webdriver_unwrapped',
525
- '__driver_evaluate',
526
- '__selenium_unwrapped',
527
- '__fxdriver_unwrapped'
528
- ];
529
-
530
- automationProps.forEach(prop => {
531
- try {
532
- delete window[prop];
533
- } catch (e) { /* ignore */ }
534
- });
535
-
536
- // Override chrome runtime with more complete implementation
537
- window.chrome = {
538
- runtime: {
539
- id: undefined,
540
- onConnect: { addListener: () => {} },
541
- onMessage: { addListener: () => {} },
542
- sendMessage: () => {},
543
- connect: () => ({ postMessage: () => {}, onMessage: { addListener: () => {} } })
544
- },
545
- loadTimes: function() {
546
- return {
547
- commitLoadTime: Date.now() / 1000,
548
- connectionInfo: 'http/1.1',
549
- finishDocumentLoadTime: Date.now() / 1000,
550
- finishLoadTime: Date.now() / 1000,
551
- firstPaintAfterLoadTime: 0,
552
- firstPaintTime: Date.now() / 1000,
553
- navigationType: 'Other',
554
- npnNegotiatedProtocol: 'unknown',
555
- requestTime: Date.now() / 1000,
556
- startLoadTime: Date.now() / 1000,
557
- wasAlternateProtocolAvailable: false,
558
- wasFetchedViaSpdy: false,
559
- wasNpnNegotiated: false
560
- };
561
- },
562
- csi: function() {
563
- return {
564
- onloadT: Date.now(),
565
- pageT: Date.now() - performance.timing.navigationStart,
566
- startE: performance.timing.navigationStart,
567
- tran: 15
568
- };
569
- },
570
- app: {
571
- isInstalled: false,
572
- InstallState: { DISABLED: 'disabled', INSTALLED: 'installed', NOT_INSTALLED: 'not_installed' },
573
- RunningState: { CANNOT_RUN: 'cannot_run', READY_TO_RUN: 'ready_to_run', RUNNING: 'running' }
574
- }
575
- };
576
-
577
- // Prevent iframe detection
578
- try {
579
- Object.defineProperty(HTMLIFrameElement.prototype, 'contentWindow', {
580
- get: function() {
581
- return this._contentWindow || null;
582
- }
583
- });
584
- } catch (e) { /* ignore */ }
585
- });
586
-
587
- // Store page configuration
588
- page._stealthConfig = {
589
- userAgent,
590
- viewport,
591
- createdAt: Date.now()
592
- };
593
-
594
- logger.info?.('[BrowserStealth] Stealth page created');
595
-
596
- return page;
597
- }
598
-
599
- /**
600
- * Check if a browser instance has stealth configuration
601
- * @param {Browser} browser - Puppeteer browser instance
602
- * @returns {boolean} True if stealth configured
603
- */
604
- export function isStealthBrowser(browser) {
605
- return !!browser._stealthConfig;
606
- }
607
-
608
- /**
609
- * Get stealth configuration from browser or page
610
- * @param {Browser|Page} instance - Browser or page instance
611
- * @returns {Object|null} Stealth configuration or null
612
- */
613
- export function getStealthConfig(instance) {
614
- return instance._stealthConfig || null;
615
- }
616
-
617
- // Re-export stealth levels for convenience
618
- export { STEALTH_LEVELS, DEFAULT_STEALTH_LEVEL };
619
-
620
- export default {
621
- createStealthBrowser,
622
- createStealthPage,
623
- getRandomUserAgent,
624
- getRandomViewport,
625
- getStealthLaunchArgs,
626
- isStealthBrowser,
627
- getStealthConfig,
628
- STEALTH_LEVELS,
629
- DEFAULT_STEALTH_LEVEL
630
- };
1
+ /**
2
+ * Browser Stealth Utility
3
+ *
4
+ * Provides a stealthy Puppeteer browser instance with anti-detection measures.
5
+ * Uses puppeteer-extra with stealth plugin for fingerprint evasion.
6
+ */
7
+ /* global window, Notification, WebGLRenderingContext, WebGL2RenderingContext, HTMLIFrameElement */
8
+
9
+ import puppeteer from 'puppeteer-extra';
10
+ import StealthPlugin from 'puppeteer-extra-plugin-stealth';
11
+ import {
12
+ BROWSER_CONFIG,
13
+ USER_AGENTS,
14
+ STEALTH_EVASIONS,
15
+ STEALTH_LEVELS,
16
+ DEFAULT_STEALTH_LEVEL
17
+ } from './stealthConstants.js';
18
+ import { getPlatform } from './platformUtils.js';
19
+
20
+ // Track if stealth plugin has been configured
21
+ let stealthPluginConfigured = false;
22
+
23
+ /**
24
+ * Configure and apply stealth plugin with all evasions enabled
25
+ * @param {Object} options - Configuration options
26
+ * @param {string[]} options.excludeEvasions - Evasions to exclude
27
+ * @returns {void}
28
+ */
29
+ function configureStealthPlugin(options = {}) {
30
+ // Only configure once (puppeteer-extra plugins are singletons)
31
+ if (stealthPluginConfigured) return;
32
+
33
+ const { excludeEvasions = STEALTH_EVASIONS.EXCLUDE } = options;
34
+
35
+ const stealth = StealthPlugin();
36
+
37
+ // Ensure ALL evasions are enabled for maximum stealth
38
+ const allEvasions = new Set([
39
+ 'chrome.app',
40
+ 'chrome.csi',
41
+ 'chrome.loadTimes',
42
+ 'chrome.runtime',
43
+ 'defaultArgs',
44
+ 'iframe.contentWindow',
45
+ 'media.codecs',
46
+ 'navigator.hardwareConcurrency',
47
+ 'navigator.languages',
48
+ 'navigator.permissions',
49
+ 'navigator.plugins',
50
+ 'navigator.webdriver',
51
+ 'sourceurl',
52
+ 'user-agent-override',
53
+ 'webgl.vendor',
54
+ 'window.outerdimensions'
55
+ ]);
56
+
57
+ stealth.enabledEvasions = allEvasions;
58
+
59
+ // Remove any excluded evasions
60
+ if (excludeEvasions && excludeEvasions.length > 0) {
61
+ excludeEvasions.forEach(evasion => {
62
+ stealth.enabledEvasions.delete(evasion);
63
+ });
64
+ }
65
+
66
+ puppeteer.use(stealth);
67
+ stealthPluginConfigured = true;
68
+ }
69
+
70
+ /**
71
+ * Get a random user agent string based on current platform
72
+ * @param {string} [forcePlatform] - Force specific platform (windows, macos, linux)
73
+ * @returns {string} Random user agent string
74
+ */
75
+ export function getRandomUserAgent(forcePlatform = null) {
76
+ const platform = forcePlatform || getPlatform();
77
+
78
+ let agents;
79
+ switch (platform) {
80
+ case 'darwin':
81
+ case 'macos':
82
+ agents = USER_AGENTS.MACOS;
83
+ break;
84
+ case 'linux':
85
+ agents = USER_AGENTS.LINUX;
86
+ break;
87
+ case 'win32':
88
+ case 'windows':
89
+ default:
90
+ agents = USER_AGENTS.WINDOWS;
91
+ break;
92
+ }
93
+
94
+ return agents[Math.floor(Math.random() * agents.length)];
95
+ }
96
+
97
+ /**
98
+ * Get a random viewport configuration
99
+ * @returns {Object} Viewport configuration { width, height }
100
+ */
101
+ export function getRandomViewport() {
102
+ const viewports = BROWSER_CONFIG.VIEWPORT_VARIANTS;
103
+ return viewports[Math.floor(Math.random() * viewports.length)];
104
+ }
105
+
106
+ /**
107
+ * Generate browser launch arguments for stealth mode
108
+ * @param {Object} options - Configuration options
109
+ * @param {string} options.userAgent - User agent to use (random if not specified)
110
+ * @param {boolean} options.headless - Whether to run headless
111
+ * @returns {string[]} Array of Chrome launch arguments
112
+ */
113
+ export function getStealthLaunchArgs(options = {}) {
114
+ const { userAgent = getRandomUserAgent(), headless = true } = options;
115
+
116
+ const args = [
117
+ // Sandbox settings (required for some environments)
118
+ '--no-sandbox',
119
+ '--disable-setuid-sandbox',
120
+
121
+ // Performance optimizations
122
+ '--disable-dev-shm-usage',
123
+
124
+ // CRITICAL: Disable automation detection flags
125
+ '--disable-blink-features=AutomationControlled',
126
+
127
+ // Disable infobars ("Chrome is being controlled by automated software")
128
+ '--disable-infobars',
129
+
130
+ // Disable extensions (but not in a detectable way)
131
+ '--disable-extensions',
132
+
133
+ // Set user agent
134
+ `--user-agent=${userAgent}`,
135
+
136
+ // Disable automation extension
137
+ '--disable-component-extensions-with-background-pages',
138
+
139
+ // Window size (matches viewport for consistency)
140
+ '--window-size=1920,1080',
141
+
142
+ // Additional anti-detection
143
+ '--disable-background-networking',
144
+ '--disable-default-apps',
145
+ '--disable-sync',
146
+ '--disable-translate',
147
+ '--metrics-recording-only',
148
+ '--no-first-run',
149
+
150
+ // REMOVED: --use-gl=swiftshader (MAJOR DETECTION VECTOR - SwiftShader is bot indicator)
151
+ // REMOVED: --disable-accelerated-2d-canvas (suspicious flag)
152
+ // REMOVED: --disable-software-rasterizer (contradicts and is detectable)
153
+
154
+ // Enable hardware acceleration for realistic fingerprint
155
+ '--enable-webgl',
156
+ '--enable-accelerated-2d-canvas',
157
+
158
+ // Disable features that leak automation
159
+ '--disable-hang-monitor',
160
+ '--disable-ipc-flooding-protection',
161
+ '--disable-popup-blocking',
162
+ '--disable-prompt-on-repost',
163
+ '--disable-renderer-backgrounding',
164
+ '--disable-backgrounding-occluded-windows',
165
+
166
+ // Privacy-related (appear more like real user)
167
+ '--disable-client-side-phishing-detection',
168
+
169
+ // Prevent WebRTC IP leak
170
+ '--disable-webrtc-hw-encoding',
171
+ '--disable-webrtc-hw-decoding',
172
+ '--enforce-webrtc-ip-permission-check'
173
+ ];
174
+
175
+ // Only disable GPU in headless mode (detection vector otherwise)
176
+ if (headless) {
177
+ args.push('--disable-gpu');
178
+ }
179
+
180
+ return args;
181
+ }
182
+
183
+ /**
184
+ * Create a stealthy browser instance
185
+ * @param {Object} options - Browser options
186
+ * @param {string} options.stealthLevel - Stealth level: 'standard' or 'maximum' (default: 'standard')
187
+ * @param {boolean} options.headless - Override headless mode (uses stealthLevel if not specified)
188
+ * @param {string} options.userAgent - Specific user agent (random if not specified)
189
+ * @param {Object} options.viewport - Viewport dimensions (random if not specified)
190
+ * @param {string[]} options.excludeEvasions - Stealth evasions to exclude
191
+ * @param {Object} options.logger - Logger instance
192
+ * @returns {Promise<Browser>} Puppeteer browser instance
193
+ */
194
+ export async function createStealthBrowser(options = {}) {
195
+ const {
196
+ stealthLevel = DEFAULT_STEALTH_LEVEL,
197
+ headless,
198
+ userAgent = getRandomUserAgent(),
199
+ viewport = getRandomViewport(),
200
+ excludeEvasions = []
201
+ } = options;
202
+
203
+ // Ensure logger is valid (null doesn't trigger default in destructuring)
204
+ const logger = options.logger || console;
205
+
206
+ // Resolve stealth level configuration
207
+ const levelConfig = STEALTH_LEVELS[stealthLevel.toUpperCase()] || STEALTH_LEVELS.STANDARD;
208
+
209
+ // headless parameter overrides stealthLevel if explicitly provided
210
+ const useHeadless = headless !== undefined ? headless : levelConfig.headless;
211
+ const isHeadless = useHeadless === true || useHeadless === 'new';
212
+
213
+ // Configure stealth plugin (only needs to be done once)
214
+ configureStealthPlugin({ excludeEvasions });
215
+
216
+ logger.info?.('[BrowserStealth] Creating stealth browser', {
217
+ stealthLevel,
218
+ headless: useHeadless,
219
+ viewport,
220
+ userAgentPrefix: userAgent.substring(0, 50) + '...'
221
+ });
222
+
223
+ const browser = await puppeteer.launch({
224
+ headless: useHeadless === true ? 'new' : useHeadless,
225
+ args: getStealthLaunchArgs({ userAgent, headless: isHeadless }),
226
+ ignoreDefaultArgs: ['--enable-automation'],
227
+ defaultViewport: {
228
+ width: viewport.width,
229
+ height: viewport.height
230
+ }
231
+ });
232
+
233
+ // Store configuration on browser instance for reference
234
+ browser._stealthConfig = {
235
+ stealthLevel,
236
+ headless: useHeadless,
237
+ userAgent,
238
+ viewport,
239
+ createdAt: Date.now()
240
+ };
241
+
242
+ logger.info?.('[BrowserStealth] Stealth browser created successfully', {
243
+ stealthLevel,
244
+ headless: useHeadless
245
+ });
246
+
247
+ return browser;
248
+ }
249
+
250
+ /**
251
+ * Create a new page with stealth enhancements
252
+ * @param {Browser} browser - Puppeteer browser instance
253
+ * @param {Object} options - Page options
254
+ * @param {string} options.userAgent - Override user agent for this page
255
+ * @param {Object} options.viewport - Override viewport for this page
256
+ * @param {Object} options.logger - Logger instance
257
+ * @returns {Promise<Page>} Puppeteer page instance
258
+ */
259
+ export async function createStealthPage(browser, options = {}) {
260
+ const {
261
+ userAgent = browser._stealthConfig?.userAgent || getRandomUserAgent(),
262
+ viewport = browser._stealthConfig?.viewport || getRandomViewport(),
263
+ maxRetries = 3
264
+ } = options;
265
+
266
+ // Ensure logger is valid (null doesn't trigger default in destructuring)
267
+ const logger = options.logger || console;
268
+
269
+ let page;
270
+ let lastError;
271
+
272
+ // Retry page creation to handle race conditions with stealth plugin
273
+ for (let attempt = 1; attempt <= maxRetries; attempt++) {
274
+ try {
275
+ page = await browser.newPage();
276
+
277
+ // Give stealth plugin more time to apply evasions
278
+ // puppeteer-extra-plugin-stealth has timing issues with newer puppeteer versions
279
+ await new Promise(resolve => setTimeout(resolve, 300));
280
+
281
+ // Wait for page to be ready (handles "Requesting main frame too early" issue)
282
+ try {
283
+ await page.waitForFunction(() => true, { timeout: 2000 });
284
+ } catch (frameError) {
285
+ // Ignore frame timing errors - page may still work
286
+ logger.warn?.('[BrowserStealth] Frame wait warning (non-fatal):', frameError.message);
287
+ }
288
+
289
+ // Verify page is still open
290
+ if (page.isClosed()) {
291
+ throw new Error('Page closed during stealth setup');
292
+ }
293
+
294
+ break; // Success
295
+ } catch (error) {
296
+ lastError = error;
297
+ const isRetryableError = error.message?.includes('Session closed') ||
298
+ error.message?.includes('Target closed') ||
299
+ error.message?.includes('Protocol error') ||
300
+ error.message?.includes('Requesting main frame too early') ||
301
+ error.message?.includes('Connection closed');
302
+
303
+ if (isRetryableError && attempt < maxRetries) {
304
+ logger.warn?.(`[BrowserStealth] Page creation failed (attempt ${attempt}/${maxRetries}), retrying...`);
305
+ await new Promise(resolve => setTimeout(resolve, 500 * attempt)); // Longer backoff
306
+ continue;
307
+ }
308
+
309
+ throw error;
310
+ }
311
+ }
312
+
313
+ if (!page) {
314
+ throw lastError || new Error('Failed to create page after retries');
315
+ }
316
+
317
+ // Configure page with error handling for race conditions
318
+ try {
319
+ // Check if page is still valid before configuring
320
+ if (page.isClosed()) {
321
+ throw new Error('Page was closed before configuration could complete');
322
+ }
323
+
324
+ // Set user agent
325
+ await page.setUserAgent(userAgent);
326
+
327
+ // Set viewport
328
+ await page.setViewport({
329
+ width: viewport.width,
330
+ height: viewport.height,
331
+ deviceScaleFactor: 1,
332
+ hasTouch: false,
333
+ isLandscape: true,
334
+ isMobile: false
335
+ });
336
+
337
+ // Set additional headers to appear more human
338
+ // IMPORTANT: Only set headers that are safe for ALL request types (navigation + XHR/fetch)
339
+ // Headers like 'Upgrade-Insecure-Requests' and 'Sec-Fetch-*' are navigation-only
340
+ // and will break CORS preflight checks on API calls if included here!
341
+ await page.setExtraHTTPHeaders({
342
+ 'Accept-Language': 'en-US,en;q=0.9'
343
+ // REMOVED: 'Upgrade-Insecure-Requests' - breaks CORS on API calls
344
+ // REMOVED: 'Sec-Fetch-*' headers - browser sets these automatically and correctly
345
+ // REMOVED: 'Accept-Encoding' - browser handles this
346
+ // REMOVED: 'Accept' - varies by request type, let browser handle it
347
+ });
348
+ } catch (configError) {
349
+ // Close page if it's still open after config error
350
+ try {
351
+ if (!page.isClosed()) await page.close();
352
+ } catch { /* ignore close error */ }
353
+
354
+ // Re-throw with context
355
+ const isTargetClosed = configError.message?.includes('Session closed') ||
356
+ configError.message?.includes('Target closed');
357
+ if (isTargetClosed) {
358
+ throw new Error('Page closed during stealth configuration. Browser may have crashed or been closed externally.', { cause: configError });
359
+ }
360
+ throw configError;
361
+ }
362
+
363
+ // Override navigator properties that stealth might miss
364
+ await page.evaluateOnNewDocument(() => {
365
+ // Override webdriver - multiple approaches for maximum coverage
366
+ Object.defineProperty(navigator, 'webdriver', {
367
+ get: () => false, // Return false instead of undefined (more realistic)
368
+ configurable: true
369
+ });
370
+
371
+ // Also delete it if it exists
372
+ try {
373
+ delete navigator.webdriver;
374
+ } catch { /* ignore */ }
375
+
376
+ // Add missing navigator.connection (NetworkInformation API) - sites check this!
377
+ if (!navigator.connection) {
378
+ Object.defineProperty(navigator, 'connection', {
379
+ get: () => ({
380
+ effectiveType: '4g',
381
+ rtt: 50,
382
+ downlink: 10,
383
+ saveData: false,
384
+ type: 'wifi',
385
+ onchange: null,
386
+ addEventListener: () => {},
387
+ removeEventListener: () => {},
388
+ dispatchEvent: () => true
389
+ }),
390
+ configurable: true
391
+ });
392
+ }
393
+
394
+ // Add navigator.deviceMemory (sites check this for fingerprinting)
395
+ if (!navigator.deviceMemory) {
396
+ Object.defineProperty(navigator, 'deviceMemory', {
397
+ get: () => 8, // 8GB - common value
398
+ configurable: true
399
+ });
400
+ }
401
+
402
+ // Add navigator.getBattery (some sites check this exists)
403
+ if (!navigator.getBattery) {
404
+ navigator.getBattery = () => Promise.resolve({
405
+ charging: true,
406
+ chargingTime: 0,
407
+ dischargingTime: Infinity,
408
+ level: 1,
409
+ addEventListener: () => {},
410
+ removeEventListener: () => {}
411
+ });
412
+ }
413
+
414
+ // Override Notification.permission (sites check this)
415
+ try {
416
+ Object.defineProperty(Notification, 'permission', {
417
+ get: () => 'default',
418
+ configurable: true
419
+ });
420
+ } catch { /* ignore */ }
421
+
422
+ // Override plugins with realistic plugin array
423
+ const mockPlugins = [
424
+ {
425
+ name: 'Chrome PDF Plugin',
426
+ filename: 'internal-pdf-viewer',
427
+ description: 'Portable Document Format',
428
+ length: 1,
429
+ item: () => null,
430
+ namedItem: () => null,
431
+ [Symbol.iterator]: function* () { yield this; }
432
+ },
433
+ {
434
+ name: 'Chrome PDF Viewer',
435
+ filename: 'mhjfbmdgcfjbbpaeojofohoefgiehjai',
436
+ description: '',
437
+ length: 1,
438
+ item: () => null,
439
+ namedItem: () => null,
440
+ [Symbol.iterator]: function* () { yield this; }
441
+ },
442
+ {
443
+ name: 'Native Client',
444
+ filename: 'internal-nacl-plugin',
445
+ description: '',
446
+ length: 2,
447
+ item: () => null,
448
+ namedItem: () => null,
449
+ [Symbol.iterator]: function* () { yield this; }
450
+ }
451
+ ];
452
+
453
+ Object.defineProperty(navigator, 'plugins', {
454
+ get: () => {
455
+ const plugins = mockPlugins;
456
+ plugins.item = (i) => plugins[i] || null;
457
+ plugins.namedItem = (name) => plugins.find(p => p.name === name) || null;
458
+ plugins.refresh = () => {};
459
+ return plugins;
460
+ }
461
+ });
462
+
463
+ // Override mimeTypes
464
+ Object.defineProperty(navigator, 'mimeTypes', {
465
+ get: () => {
466
+ const mimeTypes = [
467
+ { type: 'application/pdf', suffixes: 'pdf', description: 'Portable Document Format' },
468
+ { type: 'application/x-google-chrome-pdf', suffixes: 'pdf', description: 'Portable Document Format' }
469
+ ];
470
+ mimeTypes.item = (i) => mimeTypes[i] || null;
471
+ mimeTypes.namedItem = (name) => mimeTypes.find(m => m.type === name) || null;
472
+ return mimeTypes;
473
+ }
474
+ });
475
+
476
+ // Override languages
477
+ Object.defineProperty(navigator, 'languages', {
478
+ get: () => ['en-US', 'en']
479
+ });
480
+
481
+ // Override permissions query
482
+ const originalQuery = window.navigator.permissions.query;
483
+ window.navigator.permissions.query = (parameters) => (
484
+ parameters.name === 'notifications' ?
485
+ Promise.resolve({ state: Notification.permission }) :
486
+ originalQuery(parameters)
487
+ );
488
+
489
+ // Enhanced WebGL vendor/renderer spoofing
490
+ const spoofWebGL = (target) => {
491
+ const getParameter = target.prototype.getParameter;
492
+ target.prototype.getParameter = function(parameter) {
493
+ // UNMASKED_VENDOR_WEBGL
494
+ if (parameter === 37445) {
495
+ return 'Intel Inc.';
496
+ }
497
+ // UNMASKED_RENDERER_WEBGL
498
+ if (parameter === 37446) {
499
+ return 'Intel Iris OpenGL Engine';
500
+ }
501
+ return getParameter.call(this, parameter);
502
+ };
503
+ };
504
+
505
+ // Apply to both WebGL contexts
506
+ if (typeof WebGLRenderingContext !== 'undefined') {
507
+ spoofWebGL(WebGLRenderingContext);
508
+ }
509
+ if (typeof WebGL2RenderingContext !== 'undefined') {
510
+ spoofWebGL(WebGL2RenderingContext);
511
+ }
512
+
513
+ // Hide automation-related properties (CDP detection)
514
+ const automationProps = [
515
+ 'cdc_adoQpoasnfa76pfcZLmcfl_Array',
516
+ 'cdc_adoQpoasnfa76pfcZLmcfl_Promise',
517
+ 'cdc_adoQpoasnfa76pfcZLmcfl_Symbol',
518
+ '__webdriver_evaluate',
519
+ '__selenium_evaluate',
520
+ '__webdriver_script_function',
521
+ '__webdriver_script_func',
522
+ '__webdriver_script_fn',
523
+ '__fxdriver_evaluate',
524
+ '__driver_unwrapped',
525
+ '__webdriver_unwrapped',
526
+ '__driver_evaluate',
527
+ '__selenium_unwrapped',
528
+ '__fxdriver_unwrapped'
529
+ ];
530
+
531
+ automationProps.forEach(prop => {
532
+ try {
533
+ delete window[prop];
534
+ } catch { /* ignore */ }
535
+ });
536
+
537
+ // Override chrome runtime with more complete implementation
538
+ window.chrome = {
539
+ runtime: {
540
+ id: undefined,
541
+ onConnect: { addListener: () => {} },
542
+ onMessage: { addListener: () => {} },
543
+ sendMessage: () => {},
544
+ connect: () => ({ postMessage: () => {}, onMessage: { addListener: () => {} } })
545
+ },
546
+ loadTimes: function() {
547
+ return {
548
+ commitLoadTime: Date.now() / 1000,
549
+ connectionInfo: 'http/1.1',
550
+ finishDocumentLoadTime: Date.now() / 1000,
551
+ finishLoadTime: Date.now() / 1000,
552
+ firstPaintAfterLoadTime: 0,
553
+ firstPaintTime: Date.now() / 1000,
554
+ navigationType: 'Other',
555
+ npnNegotiatedProtocol: 'unknown',
556
+ requestTime: Date.now() / 1000,
557
+ startLoadTime: Date.now() / 1000,
558
+ wasAlternateProtocolAvailable: false,
559
+ wasFetchedViaSpdy: false,
560
+ wasNpnNegotiated: false
561
+ };
562
+ },
563
+ csi: function() {
564
+ return {
565
+ onloadT: Date.now(),
566
+ pageT: Date.now() - performance.timing.navigationStart,
567
+ startE: performance.timing.navigationStart,
568
+ tran: 15
569
+ };
570
+ },
571
+ app: {
572
+ isInstalled: false,
573
+ InstallState: { DISABLED: 'disabled', INSTALLED: 'installed', NOT_INSTALLED: 'not_installed' },
574
+ RunningState: { CANNOT_RUN: 'cannot_run', READY_TO_RUN: 'ready_to_run', RUNNING: 'running' }
575
+ }
576
+ };
577
+
578
+ // Prevent iframe detection
579
+ try {
580
+ Object.defineProperty(HTMLIFrameElement.prototype, 'contentWindow', {
581
+ get: function() {
582
+ return this._contentWindow || null;
583
+ }
584
+ });
585
+ } catch { /* ignore */ }
586
+ });
587
+
588
+ // Store page configuration
589
+ page._stealthConfig = {
590
+ userAgent,
591
+ viewport,
592
+ createdAt: Date.now()
593
+ };
594
+
595
+ logger.info?.('[BrowserStealth] Stealth page created');
596
+
597
+ return page;
598
+ }
599
+
600
+ /**
601
+ * Check if a browser instance has stealth configuration
602
+ * @param {Browser} browser - Puppeteer browser instance
603
+ * @returns {boolean} True if stealth configured
604
+ */
605
+ export function isStealthBrowser(browser) {
606
+ return !!browser._stealthConfig;
607
+ }
608
+
609
+ /**
610
+ * Get stealth configuration from browser or page
611
+ * @param {Browser|Page} instance - Browser or page instance
612
+ * @returns {Object|null} Stealth configuration or null
613
+ */
614
+ export function getStealthConfig(instance) {
615
+ return instance._stealthConfig || null;
616
+ }
617
+
618
+ // Re-export stealth levels for convenience
619
+ export { STEALTH_LEVELS, DEFAULT_STEALTH_LEVEL };
620
+
621
+ export default {
622
+ createStealthBrowser,
623
+ createStealthPage,
624
+ getRandomUserAgent,
625
+ getRandomViewport,
626
+ getStealthLaunchArgs,
627
+ isStealthBrowser,
628
+ getStealthConfig,
629
+ STEALTH_LEVELS,
630
+ DEFAULT_STEALTH_LEVEL
631
+ };