claude-chrome-parallel 1.0.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 (395) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +501 -0
  3. package/assets/demo.svg +278 -0
  4. package/dist/cdp/client.d.ts +218 -0
  5. package/dist/cdp/client.d.ts.map +1 -0
  6. package/dist/cdp/client.js +797 -0
  7. package/dist/cdp/client.js.map +1 -0
  8. package/dist/cdp/connection-pool.d.ts +125 -0
  9. package/dist/cdp/connection-pool.d.ts.map +1 -0
  10. package/dist/cdp/connection-pool.js +443 -0
  11. package/dist/cdp/connection-pool.js.map +1 -0
  12. package/dist/cdp/screenshot-scheduler.d.ts +54 -0
  13. package/dist/cdp/screenshot-scheduler.d.ts.map +1 -0
  14. package/dist/cdp/screenshot-scheduler.js +87 -0
  15. package/dist/cdp/screenshot-scheduler.js.map +1 -0
  16. package/dist/chrome/launcher.d.ts +55 -0
  17. package/dist/chrome/launcher.d.ts.map +1 -0
  18. package/dist/chrome/launcher.js +383 -0
  19. package/dist/chrome/launcher.js.map +1 -0
  20. package/dist/chrome/pool.d.ts +54 -0
  21. package/dist/chrome/pool.d.ts.map +1 -0
  22. package/dist/chrome/pool.js +301 -0
  23. package/dist/chrome/pool.js.map +1 -0
  24. package/dist/chrome/profile-detector.d.ts +52 -0
  25. package/dist/chrome/profile-detector.d.ts.map +1 -0
  26. package/dist/chrome/profile-detector.js +246 -0
  27. package/dist/chrome/profile-detector.js.map +1 -0
  28. package/dist/cli/claude-session.d.ts +11 -0
  29. package/dist/cli/claude-session.js +349 -0
  30. package/dist/cli/claude-session.js.map +1 -0
  31. package/dist/cli/index.d.ts +14 -0
  32. package/dist/cli/index.js +858 -0
  33. package/dist/cli/index.js.map +1 -0
  34. package/dist/cli/install.d.ts +16 -0
  35. package/dist/cli/install.js +185 -0
  36. package/dist/cli/install.js.map +1 -0
  37. package/dist/cli/uninstall.d.ts +7 -0
  38. package/dist/cli/uninstall.js +126 -0
  39. package/dist/cli/uninstall.js.map +1 -0
  40. package/dist/cli/update-check.d.ts +9 -0
  41. package/dist/cli/update-check.js +141 -0
  42. package/dist/cli/update-check.js.map +1 -0
  43. package/dist/config/config-recovery.d.ts +69 -0
  44. package/dist/config/config-recovery.d.ts.map +1 -0
  45. package/dist/config/config-recovery.js +302 -0
  46. package/dist/config/config-recovery.js.map +1 -0
  47. package/dist/config/global.d.ts +49 -0
  48. package/dist/config/global.d.ts.map +1 -0
  49. package/dist/config/global.js +24 -0
  50. package/dist/config/global.js.map +1 -0
  51. package/dist/config/index.d.ts +7 -0
  52. package/dist/config/index.d.ts.map +1 -0
  53. package/dist/config/index.js +23 -0
  54. package/dist/config/index.js.map +1 -0
  55. package/dist/config/session-isolator.d.ts +76 -0
  56. package/dist/config/session-isolator.d.ts.map +1 -0
  57. package/dist/config/session-isolator.js +268 -0
  58. package/dist/config/session-isolator.js.map +1 -0
  59. package/dist/dashboard/activity-tracker.d.ts +76 -0
  60. package/dist/dashboard/activity-tracker.d.ts.map +1 -0
  61. package/dist/dashboard/activity-tracker.js +219 -0
  62. package/dist/dashboard/activity-tracker.js.map +1 -0
  63. package/dist/dashboard/ansi.d.ts +117 -0
  64. package/dist/dashboard/ansi.d.ts.map +1 -0
  65. package/dist/dashboard/ansi.js +199 -0
  66. package/dist/dashboard/ansi.js.map +1 -0
  67. package/dist/dashboard/index.d.ts +110 -0
  68. package/dist/dashboard/index.d.ts.map +1 -0
  69. package/dist/dashboard/index.js +412 -0
  70. package/dist/dashboard/index.js.map +1 -0
  71. package/dist/dashboard/keyboard-handler.d.ts +43 -0
  72. package/dist/dashboard/keyboard-handler.d.ts.map +1 -0
  73. package/dist/dashboard/keyboard-handler.js +215 -0
  74. package/dist/dashboard/keyboard-handler.js.map +1 -0
  75. package/dist/dashboard/operation-controller.d.ts +76 -0
  76. package/dist/dashboard/operation-controller.d.ts.map +1 -0
  77. package/dist/dashboard/operation-controller.js +167 -0
  78. package/dist/dashboard/operation-controller.js.map +1 -0
  79. package/dist/dashboard/renderer.d.ts +76 -0
  80. package/dist/dashboard/renderer.d.ts.map +1 -0
  81. package/dist/dashboard/renderer.js +193 -0
  82. package/dist/dashboard/renderer.js.map +1 -0
  83. package/dist/dashboard/types.d.ts +56 -0
  84. package/dist/dashboard/types.d.ts.map +1 -0
  85. package/dist/dashboard/types.js +12 -0
  86. package/dist/dashboard/types.js.map +1 -0
  87. package/dist/dashboard/views/main-view.d.ts +23 -0
  88. package/dist/dashboard/views/main-view.d.ts.map +1 -0
  89. package/dist/dashboard/views/main-view.js +143 -0
  90. package/dist/dashboard/views/main-view.js.map +1 -0
  91. package/dist/dashboard/views/sessions-view.d.ts +22 -0
  92. package/dist/dashboard/views/sessions-view.d.ts.map +1 -0
  93. package/dist/dashboard/views/sessions-view.js +104 -0
  94. package/dist/dashboard/views/sessions-view.js.map +1 -0
  95. package/dist/dashboard/views/tabs-view.d.ts +21 -0
  96. package/dist/dashboard/views/tabs-view.d.ts.map +1 -0
  97. package/dist/dashboard/views/tabs-view.js +92 -0
  98. package/dist/dashboard/views/tabs-view.js.map +1 -0
  99. package/dist/hints/hint-engine.d.ts +77 -0
  100. package/dist/hints/hint-engine.d.ts.map +1 -0
  101. package/dist/hints/hint-engine.js +191 -0
  102. package/dist/hints/hint-engine.js.map +1 -0
  103. package/dist/hints/index.d.ts +8 -0
  104. package/dist/hints/index.d.ts.map +1 -0
  105. package/dist/hints/index.js +11 -0
  106. package/dist/hints/index.js.map +1 -0
  107. package/dist/hints/pattern-learner.d.ts +76 -0
  108. package/dist/hints/pattern-learner.d.ts.map +1 -0
  109. package/dist/hints/pattern-learner.js +254 -0
  110. package/dist/hints/pattern-learner.js.map +1 -0
  111. package/dist/hints/rules/composite-suggestions.d.ts +6 -0
  112. package/dist/hints/rules/composite-suggestions.d.ts.map +1 -0
  113. package/dist/hints/rules/composite-suggestions.js +66 -0
  114. package/dist/hints/rules/composite-suggestions.js.map +1 -0
  115. package/dist/hints/rules/error-recovery.d.ts +7 -0
  116. package/dist/hints/rules/error-recovery.d.ts.map +1 -0
  117. package/dist/hints/rules/error-recovery.js +55 -0
  118. package/dist/hints/rules/error-recovery.js.map +1 -0
  119. package/dist/hints/rules/learned-rules.d.ts +13 -0
  120. package/dist/hints/rules/learned-rules.d.ts.map +1 -0
  121. package/dist/hints/rules/learned-rules.js +27 -0
  122. package/dist/hints/rules/learned-rules.js.map +1 -0
  123. package/dist/hints/rules/repetition-detection.d.ts +7 -0
  124. package/dist/hints/rules/repetition-detection.d.ts.map +1 -0
  125. package/dist/hints/rules/repetition-detection.js +82 -0
  126. package/dist/hints/rules/repetition-detection.js.map +1 -0
  127. package/dist/hints/rules/sequence-detection.d.ts +6 -0
  128. package/dist/hints/rules/sequence-detection.d.ts.map +1 -0
  129. package/dist/hints/rules/sequence-detection.js +89 -0
  130. package/dist/hints/rules/sequence-detection.js.map +1 -0
  131. package/dist/hints/rules/success-hints.d.ts +6 -0
  132. package/dist/hints/rules/success-hints.d.ts.map +1 -0
  133. package/dist/hints/rules/success-hints.js +62 -0
  134. package/dist/hints/rules/success-hints.js.map +1 -0
  135. package/dist/index.d.ts +10 -0
  136. package/dist/index.d.ts.map +1 -0
  137. package/dist/index.js +272 -0
  138. package/dist/index.js.map +1 -0
  139. package/dist/lightpanda/launcher.d.ts +58 -0
  140. package/dist/lightpanda/launcher.d.ts.map +1 -0
  141. package/dist/lightpanda/launcher.js +199 -0
  142. package/dist/lightpanda/launcher.js.map +1 -0
  143. package/dist/mcp-server.d.ts +129 -0
  144. package/dist/mcp-server.d.ts.map +1 -0
  145. package/dist/mcp-server.js +641 -0
  146. package/dist/mcp-server.js.map +1 -0
  147. package/dist/memory/domain-memory.d.ts +68 -0
  148. package/dist/memory/domain-memory.d.ts.map +1 -0
  149. package/dist/memory/domain-memory.js +227 -0
  150. package/dist/memory/domain-memory.js.map +1 -0
  151. package/dist/orchestration/plan-executor.d.ts +19 -0
  152. package/dist/orchestration/plan-executor.d.ts.map +1 -0
  153. package/dist/orchestration/plan-executor.js +284 -0
  154. package/dist/orchestration/plan-executor.js.map +1 -0
  155. package/dist/orchestration/plan-registry.d.ts +55 -0
  156. package/dist/orchestration/plan-registry.d.ts.map +1 -0
  157. package/dist/orchestration/plan-registry.js +255 -0
  158. package/dist/orchestration/plan-registry.js.map +1 -0
  159. package/dist/orchestration/state-manager.d.ts +127 -0
  160. package/dist/orchestration/state-manager.d.ts.map +1 -0
  161. package/dist/orchestration/state-manager.js +438 -0
  162. package/dist/orchestration/state-manager.js.map +1 -0
  163. package/dist/orchestration/workflow-engine.d.ts +162 -0
  164. package/dist/orchestration/workflow-engine.d.ts.map +1 -0
  165. package/dist/orchestration/workflow-engine.js +731 -0
  166. package/dist/orchestration/workflow-engine.js.map +1 -0
  167. package/dist/resources/usage-guide.d.ts +13 -0
  168. package/dist/resources/usage-guide.d.ts.map +1 -0
  169. package/dist/resources/usage-guide.js +101 -0
  170. package/dist/resources/usage-guide.js.map +1 -0
  171. package/dist/router/browser-router.d.ts +51 -0
  172. package/dist/router/browser-router.d.ts.map +1 -0
  173. package/dist/router/browser-router.js +178 -0
  174. package/dist/router/browser-router.js.map +1 -0
  175. package/dist/router/cookie-sync.d.ts +48 -0
  176. package/dist/router/cookie-sync.d.ts.map +1 -0
  177. package/dist/router/cookie-sync.js +106 -0
  178. package/dist/router/cookie-sync.js.map +1 -0
  179. package/dist/router/index.d.ts +5 -0
  180. package/dist/router/index.d.ts.map +1 -0
  181. package/dist/router/index.js +10 -0
  182. package/dist/router/index.js.map +1 -0
  183. package/dist/router/tool-routing-registry.d.ts +21 -0
  184. package/dist/router/tool-routing-registry.d.ts.map +1 -0
  185. package/dist/router/tool-routing-registry.js +90 -0
  186. package/dist/router/tool-routing-registry.js.map +1 -0
  187. package/dist/session-manager.d.ts +251 -0
  188. package/dist/session-manager.d.ts.map +1 -0
  189. package/dist/session-manager.js +912 -0
  190. package/dist/session-manager.js.map +1 -0
  191. package/dist/tools/batch-execute.d.ts +11 -0
  192. package/dist/tools/batch-execute.d.ts.map +1 -0
  193. package/dist/tools/batch-execute.js +226 -0
  194. package/dist/tools/batch-execute.js.map +1 -0
  195. package/dist/tools/click-element.d.ts +8 -0
  196. package/dist/tools/click-element.d.ts.map +1 -0
  197. package/dist/tools/click-element.js +455 -0
  198. package/dist/tools/click-element.js.map +1 -0
  199. package/dist/tools/computer.d.ts +6 -0
  200. package/dist/tools/computer.d.ts.map +1 -0
  201. package/dist/tools/computer.js +638 -0
  202. package/dist/tools/computer.js.map +1 -0
  203. package/dist/tools/console-capture.d.ts +6 -0
  204. package/dist/tools/console-capture.d.ts.map +1 -0
  205. package/dist/tools/console-capture.js +320 -0
  206. package/dist/tools/console-capture.js.map +1 -0
  207. package/dist/tools/cookies.d.ts +6 -0
  208. package/dist/tools/cookies.d.ts.map +1 -0
  209. package/dist/tools/cookies.js +263 -0
  210. package/dist/tools/cookies.js.map +1 -0
  211. package/dist/tools/drag-drop.d.ts +6 -0
  212. package/dist/tools/drag-drop.d.ts.map +1 -0
  213. package/dist/tools/drag-drop.js +252 -0
  214. package/dist/tools/drag-drop.js.map +1 -0
  215. package/dist/tools/emulate-device.d.ts +6 -0
  216. package/dist/tools/emulate-device.d.ts.map +1 -0
  217. package/dist/tools/emulate-device.js +221 -0
  218. package/dist/tools/emulate-device.js.map +1 -0
  219. package/dist/tools/file-upload.d.ts +6 -0
  220. package/dist/tools/file-upload.d.ts.map +1 -0
  221. package/dist/tools/file-upload.js +208 -0
  222. package/dist/tools/file-upload.js.map +1 -0
  223. package/dist/tools/fill-form.d.ts +8 -0
  224. package/dist/tools/fill-form.d.ts.map +1 -0
  225. package/dist/tools/fill-form.js +342 -0
  226. package/dist/tools/fill-form.js.map +1 -0
  227. package/dist/tools/find.d.ts +6 -0
  228. package/dist/tools/find.d.ts.map +1 -0
  229. package/dist/tools/find.js +330 -0
  230. package/dist/tools/find.js.map +1 -0
  231. package/dist/tools/form-input.d.ts +6 -0
  232. package/dist/tools/form-input.d.ts.map +1 -0
  233. package/dist/tools/form-input.js +181 -0
  234. package/dist/tools/form-input.js.map +1 -0
  235. package/dist/tools/geolocation.d.ts +6 -0
  236. package/dist/tools/geolocation.d.ts.map +1 -0
  237. package/dist/tools/geolocation.js +172 -0
  238. package/dist/tools/geolocation.js.map +1 -0
  239. package/dist/tools/http-auth.d.ts +6 -0
  240. package/dist/tools/http-auth.d.ts.map +1 -0
  241. package/dist/tools/http-auth.js +136 -0
  242. package/dist/tools/http-auth.js.map +1 -0
  243. package/dist/tools/index.d.ts +6 -0
  244. package/dist/tools/index.d.ts.map +1 -0
  245. package/dist/tools/index.js +104 -0
  246. package/dist/tools/index.js.map +1 -0
  247. package/dist/tools/javascript.d.ts +6 -0
  248. package/dist/tools/javascript.d.ts.map +1 -0
  249. package/dist/tools/javascript.js +138 -0
  250. package/dist/tools/javascript.js.map +1 -0
  251. package/dist/tools/lightweight-scroll.d.ts +11 -0
  252. package/dist/tools/lightweight-scroll.d.ts.map +1 -0
  253. package/dist/tools/lightweight-scroll.js +266 -0
  254. package/dist/tools/lightweight-scroll.js.map +1 -0
  255. package/dist/tools/memory.d.ts +10 -0
  256. package/dist/tools/memory.d.ts.map +1 -0
  257. package/dist/tools/memory.js +141 -0
  258. package/dist/tools/memory.js.map +1 -0
  259. package/dist/tools/navigate.d.ts +6 -0
  260. package/dist/tools/navigate.d.ts.map +1 -0
  261. package/dist/tools/navigate.js +241 -0
  262. package/dist/tools/navigate.js.map +1 -0
  263. package/dist/tools/network.d.ts +6 -0
  264. package/dist/tools/network.d.ts.map +1 -0
  265. package/dist/tools/network.js +215 -0
  266. package/dist/tools/network.js.map +1 -0
  267. package/dist/tools/orchestration.d.ts +6 -0
  268. package/dist/tools/orchestration.d.ts.map +1 -0
  269. package/dist/tools/orchestration.js +746 -0
  270. package/dist/tools/orchestration.js.map +1 -0
  271. package/dist/tools/page-content.d.ts +6 -0
  272. package/dist/tools/page-content.d.ts.map +1 -0
  273. package/dist/tools/page-content.js +120 -0
  274. package/dist/tools/page-content.js.map +1 -0
  275. package/dist/tools/page-pdf.d.ts +6 -0
  276. package/dist/tools/page-pdf.d.ts.map +1 -0
  277. package/dist/tools/page-pdf.js +245 -0
  278. package/dist/tools/page-pdf.js.map +1 -0
  279. package/dist/tools/page-reload.d.ts +6 -0
  280. package/dist/tools/page-reload.d.ts.map +1 -0
  281. package/dist/tools/page-reload.js +89 -0
  282. package/dist/tools/page-reload.js.map +1 -0
  283. package/dist/tools/performance-metrics.d.ts +6 -0
  284. package/dist/tools/performance-metrics.d.ts.map +1 -0
  285. package/dist/tools/performance-metrics.js +158 -0
  286. package/dist/tools/performance-metrics.js.map +1 -0
  287. package/dist/tools/read-page.d.ts +6 -0
  288. package/dist/tools/read-page.d.ts.map +1 -0
  289. package/dist/tools/read-page.js +287 -0
  290. package/dist/tools/read-page.js.map +1 -0
  291. package/dist/tools/request-intercept.d.ts +6 -0
  292. package/dist/tools/request-intercept.d.ts.map +1 -0
  293. package/dist/tools/request-intercept.js +439 -0
  294. package/dist/tools/request-intercept.js.map +1 -0
  295. package/dist/tools/selector-query.d.ts +6 -0
  296. package/dist/tools/selector-query.d.ts.map +1 -0
  297. package/dist/tools/selector-query.js +206 -0
  298. package/dist/tools/selector-query.js.map +1 -0
  299. package/dist/tools/shutdown.d.ts +12 -0
  300. package/dist/tools/shutdown.d.ts.map +1 -0
  301. package/dist/tools/shutdown.js +120 -0
  302. package/dist/tools/shutdown.js.map +1 -0
  303. package/dist/tools/storage.d.ts +6 -0
  304. package/dist/tools/storage.d.ts.map +1 -0
  305. package/dist/tools/storage.js +264 -0
  306. package/dist/tools/storage.js.map +1 -0
  307. package/dist/tools/tabs-close.d.ts +6 -0
  308. package/dist/tools/tabs-close.d.ts.map +1 -0
  309. package/dist/tools/tabs-close.js +124 -0
  310. package/dist/tools/tabs-close.js.map +1 -0
  311. package/dist/tools/tabs-context.d.ts +6 -0
  312. package/dist/tools/tabs-context.d.ts.map +1 -0
  313. package/dist/tools/tabs-context.js +92 -0
  314. package/dist/tools/tabs-context.js.map +1 -0
  315. package/dist/tools/tabs-create.d.ts +6 -0
  316. package/dist/tools/tabs-create.d.ts.map +1 -0
  317. package/dist/tools/tabs-create.js +73 -0
  318. package/dist/tools/tabs-create.js.map +1 -0
  319. package/dist/tools/user-agent.d.ts +6 -0
  320. package/dist/tools/user-agent.d.ts.map +1 -0
  321. package/dist/tools/user-agent.js +128 -0
  322. package/dist/tools/user-agent.js.map +1 -0
  323. package/dist/tools/wait-and-click.d.ts +8 -0
  324. package/dist/tools/wait-and-click.d.ts.map +1 -0
  325. package/dist/tools/wait-and-click.js +290 -0
  326. package/dist/tools/wait-and-click.js.map +1 -0
  327. package/dist/tools/wait-for.d.ts +6 -0
  328. package/dist/tools/wait-for.d.ts.map +1 -0
  329. package/dist/tools/wait-for.js +248 -0
  330. package/dist/tools/wait-for.js.map +1 -0
  331. package/dist/tools/worker-create.d.ts +7 -0
  332. package/dist/tools/worker-create.d.ts.map +1 -0
  333. package/dist/tools/worker-create.js +62 -0
  334. package/dist/tools/worker-create.js.map +1 -0
  335. package/dist/tools/worker-delete.d.ts +6 -0
  336. package/dist/tools/worker-delete.d.ts.map +1 -0
  337. package/dist/tools/worker-delete.js +80 -0
  338. package/dist/tools/worker-delete.js.map +1 -0
  339. package/dist/tools/worker-list.d.ts +6 -0
  340. package/dist/tools/worker-list.d.ts.map +1 -0
  341. package/dist/tools/worker-list.js +67 -0
  342. package/dist/tools/worker-list.js.map +1 -0
  343. package/dist/tools/xpath-query.d.ts +6 -0
  344. package/dist/tools/xpath-query.d.ts.map +1 -0
  345. package/dist/tools/xpath-query.js +230 -0
  346. package/dist/tools/xpath-query.js.map +1 -0
  347. package/dist/types/browser-backend.d.ts +30 -0
  348. package/dist/types/browser-backend.d.ts.map +1 -0
  349. package/dist/types/browser-backend.js +9 -0
  350. package/dist/types/browser-backend.js.map +1 -0
  351. package/dist/types/index.d.ts +3 -0
  352. package/dist/types/index.d.ts.map +1 -0
  353. package/dist/types/index.js +19 -0
  354. package/dist/types/index.js.map +1 -0
  355. package/dist/types/mcp.d.ts +54 -0
  356. package/dist/types/mcp.d.ts.map +1 -0
  357. package/dist/types/mcp.js +14 -0
  358. package/dist/types/mcp.js.map +1 -0
  359. package/dist/types/plan-cache.d.ts +121 -0
  360. package/dist/types/plan-cache.d.ts.map +1 -0
  361. package/dist/types/plan-cache.js +9 -0
  362. package/dist/types/plan-cache.js.map +1 -0
  363. package/dist/types/profile.d.ts +76 -0
  364. package/dist/types/profile.d.ts.map +1 -0
  365. package/dist/types/profile.js +35 -0
  366. package/dist/types/profile.js.map +1 -0
  367. package/dist/types/session.d.ts +65 -0
  368. package/dist/types/session.d.ts.map +1 -0
  369. package/dist/types/session.js +6 -0
  370. package/dist/types/session.js.map +1 -0
  371. package/dist/types/tool-manifest.d.ts +52 -0
  372. package/dist/types/tool-manifest.d.ts.map +1 -0
  373. package/dist/types/tool-manifest.js +37 -0
  374. package/dist/types/tool-manifest.js.map +1 -0
  375. package/dist/utils/atomic-file.d.ts +50 -0
  376. package/dist/utils/atomic-file.d.ts.map +1 -0
  377. package/dist/utils/atomic-file.js +217 -0
  378. package/dist/utils/atomic-file.js.map +1 -0
  379. package/dist/utils/index.d.ts +6 -0
  380. package/dist/utils/index.d.ts.map +1 -0
  381. package/dist/utils/index.js +22 -0
  382. package/dist/utils/index.js.map +1 -0
  383. package/dist/utils/json-validator.d.ts +40 -0
  384. package/dist/utils/json-validator.d.ts.map +1 -0
  385. package/dist/utils/json-validator.js +295 -0
  386. package/dist/utils/json-validator.js.map +1 -0
  387. package/dist/utils/ref-id-manager.d.ts +26 -0
  388. package/dist/utils/ref-id-manager.d.ts.map +1 -0
  389. package/dist/utils/ref-id-manager.js +81 -0
  390. package/dist/utils/ref-id-manager.js.map +1 -0
  391. package/dist/utils/request-queue.d.ts +37 -0
  392. package/dist/utils/request-queue.d.ts.map +1 -0
  393. package/dist/utils/request-queue.js +110 -0
  394. package/dist/utils/request-queue.js.map +1 -0
  395. package/package.json +78 -0
@@ -0,0 +1,797 @@
1
+ "use strict";
2
+ /**
3
+ * CDP Client - Wrapper around puppeteer-core for Chrome DevTools Protocol
4
+ */
5
+ var __importDefault = (this && this.__importDefault) || function (mod) {
6
+ return (mod && mod.__esModule) ? mod : { "default": mod };
7
+ };
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.CDPClientFactory = exports.CDPClient = void 0;
10
+ exports.getCDPClient = getCDPClient;
11
+ exports.getCDPClientFactory = getCDPClientFactory;
12
+ const puppeteer_core_1 = __importDefault(require("puppeteer-core"));
13
+ const launcher_1 = require("../chrome/launcher");
14
+ const global_1 = require("../config/global");
15
+ // Helper to get target ID (internal puppeteer property)
16
+ function getTargetId(target) {
17
+ // Access the internal _targetId property
18
+ return target._targetId;
19
+ }
20
+ class CDPClient {
21
+ browser = null;
22
+ sessions = new Map();
23
+ port;
24
+ maxReconnectAttempts;
25
+ reconnectDelayMs;
26
+ heartbeatIntervalMs;
27
+ heartbeatTimer = null;
28
+ connectionState = 'disconnected';
29
+ eventListeners = [];
30
+ targetDestroyedListeners = [];
31
+ reconnectAttempts = 0;
32
+ autoLaunch;
33
+ cookieSourceCache = new Map();
34
+ cookieDataCache = new Map();
35
+ targetIdIndex = new Map();
36
+ inFlightCookieScans = new Map();
37
+ static COOKIE_CACHE_TTL = 300000; // 5 minutes
38
+ constructor(options = {}) {
39
+ const globalConfig = (0, global_1.getGlobalConfig)();
40
+ this.port = options.port || globalConfig.port;
41
+ this.maxReconnectAttempts = options.maxReconnectAttempts || 3;
42
+ this.reconnectDelayMs = options.reconnectDelayMs || 1000;
43
+ this.heartbeatIntervalMs = options.heartbeatIntervalMs || 5000;
44
+ // Use explicit option if provided, otherwise use global config
45
+ this.autoLaunch = options.autoLaunch !== undefined ? options.autoLaunch : globalConfig.autoLaunch;
46
+ }
47
+ /**
48
+ * Get current connection state
49
+ */
50
+ getConnectionState() {
51
+ return this.connectionState;
52
+ }
53
+ /**
54
+ * Add connection event listener
55
+ */
56
+ addConnectionListener(listener) {
57
+ this.eventListeners.push(listener);
58
+ }
59
+ /**
60
+ * Remove connection event listener
61
+ */
62
+ removeConnectionListener(listener) {
63
+ const index = this.eventListeners.indexOf(listener);
64
+ if (index !== -1) {
65
+ this.eventListeners.splice(index, 1);
66
+ }
67
+ }
68
+ /**
69
+ * Add target destroyed listener
70
+ */
71
+ addTargetDestroyedListener(listener) {
72
+ this.targetDestroyedListeners.push(listener);
73
+ }
74
+ /**
75
+ * Handle target destroyed event
76
+ */
77
+ onTargetDestroyed(targetId) {
78
+ this.sessions.delete(targetId);
79
+ // Clean up cookie source cache entries pointing to this target
80
+ for (const [key, entry] of this.cookieSourceCache) {
81
+ if (entry.targetId === targetId) {
82
+ this.cookieSourceCache.delete(key);
83
+ }
84
+ }
85
+ // Clean up cookie data cache for this target
86
+ this.cookieDataCache.delete(targetId);
87
+ this.targetIdIndex.delete(targetId);
88
+ for (const listener of this.targetDestroyedListeners) {
89
+ try {
90
+ listener(targetId);
91
+ }
92
+ catch (e) {
93
+ console.error('[CDPClient] Target destroyed listener error:', e);
94
+ }
95
+ }
96
+ }
97
+ /**
98
+ * Emit connection event
99
+ */
100
+ emitConnectionEvent(event) {
101
+ for (const listener of this.eventListeners) {
102
+ try {
103
+ listener(event);
104
+ }
105
+ catch (e) {
106
+ console.error('[CDPClient] Event listener error:', e);
107
+ }
108
+ }
109
+ }
110
+ /**
111
+ * Start heartbeat monitoring
112
+ */
113
+ startHeartbeat() {
114
+ this.stopHeartbeat();
115
+ this.heartbeatTimer = setInterval(() => {
116
+ this.checkConnection();
117
+ }, this.heartbeatIntervalMs);
118
+ }
119
+ /**
120
+ * Stop heartbeat monitoring
121
+ */
122
+ stopHeartbeat() {
123
+ if (this.heartbeatTimer) {
124
+ clearInterval(this.heartbeatTimer);
125
+ this.heartbeatTimer = null;
126
+ }
127
+ }
128
+ /**
129
+ * Check connection health
130
+ */
131
+ async checkConnection() {
132
+ if (!this.browser) {
133
+ return false;
134
+ }
135
+ try {
136
+ // Simple check - try to get browser version
137
+ if (!this.browser.isConnected()) {
138
+ console.error('[CDPClient] Heartbeat: Connection lost, attempting reconnect...');
139
+ await this.handleDisconnect();
140
+ return false;
141
+ }
142
+ return true;
143
+ }
144
+ catch (error) {
145
+ console.error('[CDPClient] Heartbeat check failed:', error);
146
+ await this.handleDisconnect();
147
+ return false;
148
+ }
149
+ }
150
+ /**
151
+ * Handle disconnection with automatic reconnection
152
+ */
153
+ async handleDisconnect() {
154
+ if (this.connectionState === 'reconnecting') {
155
+ return; // Already reconnecting
156
+ }
157
+ this.connectionState = 'reconnecting';
158
+ this.emitConnectionEvent({
159
+ type: 'disconnected',
160
+ timestamp: Date.now(),
161
+ });
162
+ // Clear existing sessions
163
+ this.sessions.clear();
164
+ this.targetIdIndex.clear();
165
+ this.inFlightCookieScans.clear();
166
+ this.browser = null;
167
+ // Attempt reconnection
168
+ while (this.reconnectAttempts < this.maxReconnectAttempts) {
169
+ this.reconnectAttempts++;
170
+ console.error(`[CDPClient] Reconnect attempt ${this.reconnectAttempts}/${this.maxReconnectAttempts}...`);
171
+ this.emitConnectionEvent({
172
+ type: 'reconnecting',
173
+ timestamp: Date.now(),
174
+ attempt: this.reconnectAttempts,
175
+ });
176
+ try {
177
+ await this.connectInternal();
178
+ console.error('[CDPClient] Reconnection successful');
179
+ this.reconnectAttempts = 0;
180
+ return;
181
+ }
182
+ catch (error) {
183
+ console.error(`[CDPClient] Reconnect attempt ${this.reconnectAttempts} failed:`, error);
184
+ if (this.reconnectAttempts < this.maxReconnectAttempts) {
185
+ await new Promise(resolve => setTimeout(resolve, this.reconnectDelayMs));
186
+ }
187
+ }
188
+ }
189
+ // All attempts failed
190
+ this.connectionState = 'disconnected';
191
+ this.emitConnectionEvent({
192
+ type: 'reconnect_failed',
193
+ timestamp: Date.now(),
194
+ error: `Failed after ${this.maxReconnectAttempts} attempts`,
195
+ });
196
+ console.error('[CDPClient] All reconnection attempts failed');
197
+ this.reconnectAttempts = 0;
198
+ }
199
+ /**
200
+ * Internal connect logic
201
+ */
202
+ async connectInternal() {
203
+ const launcher = (0, launcher_1.getChromeLauncher)(this.port);
204
+ const instance = await launcher.ensureChrome({ autoLaunch: this.autoLaunch });
205
+ this.browser = await puppeteer_core_1.default.connect({
206
+ browserWSEndpoint: instance.wsEndpoint,
207
+ defaultViewport: null,
208
+ });
209
+ // Set up disconnect handler
210
+ this.browser.on('disconnected', () => {
211
+ console.error('[CDPClient] Browser disconnected');
212
+ this.handleDisconnect();
213
+ });
214
+ // Set up target destroyed handler
215
+ this.browser.on('targetdestroyed', (target) => {
216
+ const targetId = getTargetId(target);
217
+ console.error(`[CDPClient] Target destroyed: ${targetId}`);
218
+ this.onTargetDestroyed(targetId);
219
+ });
220
+ // Maintain target-to-page index for O(1) lookups
221
+ this.browser.on('targetcreated', async (target) => {
222
+ if (target.type() === 'page') {
223
+ try {
224
+ const page = await target.page();
225
+ if (page) {
226
+ this.targetIdIndex.set(getTargetId(target), page);
227
+ }
228
+ }
229
+ catch {
230
+ // Target may have been destroyed before we could index it
231
+ }
232
+ }
233
+ });
234
+ this.connectionState = 'connected';
235
+ this.emitConnectionEvent({
236
+ type: 'connected',
237
+ timestamp: Date.now(),
238
+ });
239
+ }
240
+ /**
241
+ * Connect to Chrome instance
242
+ */
243
+ async connect() {
244
+ if (this.browser && this.browser.isConnected()) {
245
+ // Verify connection is actually working by checking Chrome endpoint
246
+ try {
247
+ const launcher = (0, launcher_1.getChromeLauncher)(this.port);
248
+ const instance = await launcher.ensureChrome({ autoLaunch: this.autoLaunch });
249
+ const currentWsUrl = instance.wsEndpoint;
250
+ // Check if the browser's WebSocket URL matches current Chrome
251
+ const browserWsUrl = this.browser.wsEndpoint();
252
+ if (browserWsUrl !== currentWsUrl) {
253
+ console.error('[CDPClient] WebSocket URL mismatch, reconnecting...');
254
+ await this.forceReconnect();
255
+ return;
256
+ }
257
+ return;
258
+ }
259
+ catch {
260
+ console.error('[CDPClient] Connection check failed, reconnecting...');
261
+ await this.forceReconnect();
262
+ return;
263
+ }
264
+ }
265
+ this.connectionState = 'connecting';
266
+ await this.connectInternal();
267
+ this.startHeartbeat();
268
+ console.error('[CDPClient] Connected to Chrome');
269
+ }
270
+ /**
271
+ * Force reconnect by disconnecting and reconnecting
272
+ */
273
+ async forceReconnect() {
274
+ this.stopHeartbeat();
275
+ if (this.browser) {
276
+ try {
277
+ this.browser.removeAllListeners('disconnected');
278
+ await this.browser.disconnect();
279
+ }
280
+ catch {
281
+ // Ignore disconnect errors
282
+ }
283
+ this.browser = null;
284
+ this.sessions.clear();
285
+ }
286
+ this.connectionState = 'connecting';
287
+ await this.connectInternal();
288
+ this.startHeartbeat();
289
+ console.error('[CDPClient] Reconnected to Chrome');
290
+ }
291
+ /**
292
+ * Disconnect from Chrome
293
+ */
294
+ async disconnect() {
295
+ this.stopHeartbeat();
296
+ if (this.browser) {
297
+ try {
298
+ await this.browser.disconnect();
299
+ }
300
+ catch {
301
+ // Browser might already be disconnected
302
+ }
303
+ this.browser = null;
304
+ this.sessions.clear();
305
+ this.connectionState = 'disconnected';
306
+ console.error('[CDPClient] Disconnected from Chrome');
307
+ }
308
+ }
309
+ /**
310
+ * Get browser instance
311
+ */
312
+ getBrowser() {
313
+ if (!this.browser) {
314
+ throw new Error('Not connected to Chrome. Call connect() first.');
315
+ }
316
+ return this.browser;
317
+ }
318
+ // Default viewport for consistent debugging experience
319
+ static DEFAULT_VIEWPORT = { width: 1920, height: 1080 };
320
+ /**
321
+ * Create a new isolated browser context for session isolation
322
+ * Each context has its own cookies, localStorage, sessionStorage
323
+ */
324
+ async createBrowserContext() {
325
+ const browser = this.getBrowser();
326
+ const context = await browser.createBrowserContext();
327
+ console.error(`[CDPClient] Created new browser context`);
328
+ return context;
329
+ }
330
+ /**
331
+ * Close a browser context and all its pages
332
+ */
333
+ async closeBrowserContext(context) {
334
+ try {
335
+ await context.close();
336
+ console.error(`[CDPClient] Closed browser context`);
337
+ }
338
+ catch (e) {
339
+ // Context may already be closed
340
+ console.error(`[CDPClient] Error closing browser context:`, e);
341
+ }
342
+ }
343
+ /**
344
+ * Check if a hostname is localhost
345
+ */
346
+ isLocalhost(url) {
347
+ try {
348
+ const hostname = new URL(url).hostname;
349
+ return hostname === 'localhost' || hostname === '127.0.0.1' || hostname === '::1';
350
+ }
351
+ catch {
352
+ return false;
353
+ }
354
+ }
355
+ /**
356
+ * Calculate domain match score between two URLs
357
+ * Higher score = better match
358
+ */
359
+ domainMatchScore(candidateUrl, targetDomain) {
360
+ try {
361
+ const candidateHostname = new URL(candidateUrl).hostname;
362
+ const candidateParts = candidateHostname.split('.').reverse();
363
+ const targetParts = targetDomain.split('.').reverse();
364
+ // Exact match
365
+ if (candidateHostname === targetDomain) {
366
+ return 100;
367
+ }
368
+ // Count matching TLD parts from right to left
369
+ let matchingParts = 0;
370
+ for (let i = 0; i < Math.min(candidateParts.length, targetParts.length); i++) {
371
+ if (candidateParts[i] === targetParts[i]) {
372
+ matchingParts++;
373
+ }
374
+ else {
375
+ break;
376
+ }
377
+ }
378
+ // Subdomain match (e.g., api.example.com matches example.com)
379
+ if (matchingParts >= 2) {
380
+ return 50 + matchingParts * 10;
381
+ }
382
+ // Same TLD only (e.g., both .com)
383
+ if (matchingParts === 1) {
384
+ return 10;
385
+ }
386
+ return 0;
387
+ }
388
+ catch {
389
+ return 0;
390
+ }
391
+ }
392
+ /**
393
+ * Find an authenticated page with cookies to copy from.
394
+ * Returns the targetId of a page that has cookies in Chrome's default context.
395
+ *
396
+ * Promise coalescing: concurrent callers for the same domain share one probe
397
+ * instead of independently hammering Chrome with 20 simultaneous scans.
398
+ *
399
+ * @param targetDomain Optional domain to prioritize when selecting cookie source
400
+ */
401
+ async findAuthenticatedPageTargetId(targetDomain) {
402
+ // Check cache first (stale targetId is handled gracefully: copyCookiesViaCDP returns 0)
403
+ const cacheKey = targetDomain || '*';
404
+ const cached = this.cookieSourceCache.get(cacheKey);
405
+ if (cached && Date.now() - cached.timestamp < CDPClient.COOKIE_CACHE_TTL) {
406
+ console.error(`[CDPClient] Cache hit for cookie source (domain: ${cacheKey}): ${cached.targetId.slice(0, 8)}`);
407
+ return cached.targetId;
408
+ }
409
+ // Promise coalescing: if a scan for this domain is already in-flight, reuse it
410
+ const existing = this.inFlightCookieScans.get(cacheKey);
411
+ if (existing) {
412
+ console.error(`[CDPClient] Coalescing cookie scan for domain: ${cacheKey}`);
413
+ return existing;
414
+ }
415
+ // Start the scan and register it so concurrent callers share this promise
416
+ const scanPromise = this._doFindAuthenticatedPageTargetId(targetDomain, cacheKey);
417
+ this.inFlightCookieScans.set(cacheKey, scanPromise);
418
+ try {
419
+ return await scanPromise;
420
+ }
421
+ finally {
422
+ this.inFlightCookieScans.delete(cacheKey);
423
+ }
424
+ }
425
+ /**
426
+ * Internal implementation of the authenticated-page probe.
427
+ * Uses Target.attachToTarget (multiplexed CDP) instead of raw WebSocket connections.
428
+ * Uses Target.getTargets result directly instead of /json/list HTTP calls.
429
+ */
430
+ async _doFindAuthenticatedPageTargetId(targetDomain, cacheKey) {
431
+ const browser = this.getBrowser();
432
+ const session = await browser.target().createCDPSession();
433
+ try {
434
+ const { targetInfos } = await session.send('Target.getTargets');
435
+ // Filter to candidate pages (not chrome://, not login pages, etc.)
436
+ let candidates = targetInfos.filter(target => target.type === 'page' &&
437
+ !target.url.startsWith('chrome://') &&
438
+ !target.url.startsWith('chrome-extension://') &&
439
+ target.url !== 'about:blank' &&
440
+ !target.url.includes('/login') &&
441
+ !target.url.includes('/signin') &&
442
+ !target.url.includes('/auth'));
443
+ if (candidates.length === 0) {
444
+ console.error('[CDPClient] No candidate pages found for cookie source');
445
+ return null;
446
+ }
447
+ // If targeting an external domain (not localhost), exclude localhost pages
448
+ if (targetDomain && !this.isLocalhost(`https://${targetDomain}`)) {
449
+ const externalCandidates = candidates.filter(c => !this.isLocalhost(c.url));
450
+ if (externalCandidates.length > 0) {
451
+ console.error(`[CDPClient] Filtered out ${candidates.length - externalCandidates.length} localhost pages for external domain target`);
452
+ candidates = externalCandidates;
453
+ }
454
+ }
455
+ // Sort candidates by domain match score (highest first)
456
+ if (targetDomain) {
457
+ candidates.sort((a, b) => {
458
+ const scoreA = this.domainMatchScore(a.url, targetDomain);
459
+ const scoreB = this.domainMatchScore(b.url, targetDomain);
460
+ return scoreB - scoreA;
461
+ });
462
+ console.error(`[CDPClient] Sorted ${candidates.length} candidates by domain match to ${targetDomain}`);
463
+ }
464
+ // Check each candidate to find one with actual cookies (in priority order).
465
+ // Uses Target.attachToTarget over the existing multiplexed session — no raw WebSocket,
466
+ // no /json/list HTTP round-trip.
467
+ for (const candidate of candidates) {
468
+ let attachedSessionId = null;
469
+ try {
470
+ const { sessionId } = await session.send('Target.attachToTarget', {
471
+ targetId: candidate.targetId,
472
+ flatten: true,
473
+ });
474
+ attachedSessionId = sessionId;
475
+ // Send Network.getAllCookies through the flat CDP session
476
+ const result = await session.send('Network.getAllCookies', undefined, { sessionId });
477
+ const cookieCount = result?.cookies?.length || 0;
478
+ if (cookieCount > 0) {
479
+ const domainScore = targetDomain ? this.domainMatchScore(candidate.url, targetDomain) : 0;
480
+ console.error(`[CDPClient] Found authenticated page ${candidate.targetId.slice(0, 8)} at ${candidate.url.slice(0, 50)} (${cookieCount} cookies, domain score: ${domainScore})`);
481
+ this.cookieSourceCache.set(cacheKey, { targetId: candidate.targetId, timestamp: Date.now() });
482
+ return candidate.targetId;
483
+ }
484
+ }
485
+ catch {
486
+ // Target may be unresponsive or already detached — skip
487
+ }
488
+ finally {
489
+ if (attachedSessionId) {
490
+ await session.send('Target.detachFromTarget', { sessionId: attachedSessionId }).catch(() => { });
491
+ }
492
+ }
493
+ }
494
+ console.error('[CDPClient] No pages with cookies found');
495
+ return null;
496
+ }
497
+ finally {
498
+ await session.detach().catch(() => { });
499
+ }
500
+ }
501
+ /**
502
+ * Copy all cookies from authenticated page to destination page.
503
+ * Uses Target.attachToTarget (multiplexed CDP) to bypass Puppeteer's context isolation —
504
+ * no raw WebSocket connections, no /json/list HTTP calls.
505
+ */
506
+ async copyCookiesViaCDP(sourceTargetId, destPage) {
507
+ console.error(`[CDPClient] copyCookiesViaCDP called with sourceTargetId: ${sourceTargetId.slice(0, 8)}`);
508
+ try {
509
+ // Check cookie data cache first — avoids re-probing Chrome entirely
510
+ const cachedData = this.cookieDataCache.get(sourceTargetId);
511
+ if (cachedData && Date.now() - cachedData.timestamp < CDPClient.COOKIE_CACHE_TTL) {
512
+ console.error(`[CDPClient] Cache hit for cookie data (${cachedData.cookies.length} cookies), skipping CDP attach`);
513
+ const destSession = await destPage.createCDPSession();
514
+ try {
515
+ const cookiesToSet = cachedData.cookies.map(c => ({
516
+ name: c.name,
517
+ value: c.value,
518
+ domain: c.domain,
519
+ path: c.path,
520
+ expires: c.expires,
521
+ httpOnly: c.httpOnly,
522
+ secure: c.secure,
523
+ sameSite: c.sameSite,
524
+ }));
525
+ await destSession.send('Network.setCookies', { cookies: cookiesToSet });
526
+ console.error(`[CDPClient] Successfully copied ${cachedData.cookies.length} cookies (from cache)`);
527
+ return cachedData.cookies.length;
528
+ }
529
+ finally {
530
+ await destSession.detach().catch(() => { });
531
+ }
532
+ }
533
+ // Attach to the source target via the multiplexed browser CDP session
534
+ const browser = this.getBrowser();
535
+ const browserSession = await browser.target().createCDPSession();
536
+ let attachedSessionId = null;
537
+ try {
538
+ // Verify the target exists before attaching
539
+ const { targetInfos } = await browserSession.send('Target.getTargets');
540
+ const sourceInfo = targetInfos.find(t => t.targetId === sourceTargetId);
541
+ if (!sourceInfo) {
542
+ console.error(`[CDPClient] Source target not found: ${sourceTargetId.slice(0, 8)}`);
543
+ console.error(`[CDPClient] Available targets: ${targetInfos.map(t => t.targetId.slice(0, 8) + ' ' + t.url.slice(0, 40)).join(', ')}`);
544
+ return 0;
545
+ }
546
+ console.error(`[CDPClient] Attaching to source target at ${sourceInfo.url.slice(0, 50)}`);
547
+ const { sessionId } = await browserSession.send('Target.attachToTarget', {
548
+ targetId: sourceTargetId,
549
+ flatten: true,
550
+ });
551
+ attachedSessionId = sessionId;
552
+ // Fetch cookies through the flat session (no raw WebSocket, no /json/list)
553
+ const result = await browserSession.send('Network.getAllCookies', undefined, { sessionId });
554
+ const cookies = result?.cookies || [];
555
+ // Store in cookie data cache
556
+ this.cookieDataCache.set(sourceTargetId, { cookies, timestamp: Date.now() });
557
+ if (cookies.length === 0) {
558
+ console.error('[CDPClient] No cookies found in source page');
559
+ return 0;
560
+ }
561
+ console.error(`[CDPClient] Found ${cookies.length} cookies, setting on destination page`);
562
+ // Set cookies on destination page via its own CDPSession
563
+ const destSession = await destPage.createCDPSession();
564
+ try {
565
+ const cookiesToSet = cookies.map(c => ({
566
+ name: c.name,
567
+ value: c.value,
568
+ domain: c.domain,
569
+ path: c.path,
570
+ expires: c.expires,
571
+ httpOnly: c.httpOnly,
572
+ secure: c.secure,
573
+ sameSite: c.sameSite,
574
+ }));
575
+ await destSession.send('Network.setCookies', { cookies: cookiesToSet });
576
+ console.error(`[CDPClient] Successfully copied ${cookies.length} cookies`);
577
+ return cookies.length;
578
+ }
579
+ finally {
580
+ await destSession.detach().catch(() => { });
581
+ }
582
+ }
583
+ finally {
584
+ if (attachedSessionId) {
585
+ await browserSession.send('Target.detachFromTarget', { sessionId: attachedSessionId }).catch(() => { });
586
+ }
587
+ await browserSession.detach().catch(() => { });
588
+ }
589
+ }
590
+ catch (error) {
591
+ console.error('[CDPClient] Error in copyCookiesViaCDP:', error);
592
+ return 0;
593
+ }
594
+ }
595
+ /**
596
+ * Create a new page with default viewport
597
+ * @param url Optional URL to navigate to
598
+ * @param context Optional browser context for session isolation (null/undefined = use Chrome's default context with cookies)
599
+ */
600
+ async createPage(url, context) {
601
+ let page;
602
+ const browser = this.getBrowser();
603
+ // Extract domain from URL for cookie source prioritization
604
+ let targetDomain;
605
+ if (url) {
606
+ try {
607
+ targetDomain = new URL(url).hostname;
608
+ console.error(`[CDPClient] createPage targeting domain: ${targetDomain}`);
609
+ }
610
+ catch {
611
+ // Invalid URL, proceed without domain preference
612
+ }
613
+ }
614
+ if (context) {
615
+ // Create page in isolated context (for worker isolation)
616
+ page = await context.newPage();
617
+ }
618
+ else {
619
+ // Create page and copy cookies from an authenticated page
620
+ // This allows the new page to share the authenticated session
621
+ page = await browser.newPage();
622
+ // Find an authenticated page to copy cookies from (with domain preference)
623
+ const authPageTargetId = await this.findAuthenticatedPageTargetId(targetDomain);
624
+ if (authPageTargetId) {
625
+ await this.copyCookiesViaCDP(authPageTargetId, page);
626
+ }
627
+ }
628
+ // Set default viewport for consistent debugging experience
629
+ await page.setViewport(CDPClient.DEFAULT_VIEWPORT);
630
+ if (url) {
631
+ await page.goto(url, { waitUntil: 'domcontentloaded' });
632
+ }
633
+ return page;
634
+ }
635
+ /**
636
+ * Get all page targets
637
+ */
638
+ async getPages() {
639
+ const browser = this.getBrowser();
640
+ return browser.pages();
641
+ }
642
+ /**
643
+ * Get page by target ID
644
+ */
645
+ async getPageByTargetId(targetId) {
646
+ // Fast path: check index first (O(1))
647
+ const indexed = this.targetIdIndex.get(targetId);
648
+ if (indexed && !indexed.isClosed()) {
649
+ return indexed;
650
+ }
651
+ // Fallback: linear scan (for pages created before indexing started)
652
+ const browser = this.getBrowser();
653
+ const targets = browser.targets();
654
+ for (const target of targets) {
655
+ if (getTargetId(target) === targetId && target.type() === 'page') {
656
+ const page = await target.page();
657
+ if (page) {
658
+ // Populate index for future lookups
659
+ this.targetIdIndex.set(targetId, page);
660
+ }
661
+ return page;
662
+ }
663
+ }
664
+ // Clean stale index entry
665
+ this.targetIdIndex.delete(targetId);
666
+ return null;
667
+ }
668
+ /**
669
+ * Get CDP session for a page
670
+ */
671
+ async getCDPSession(page) {
672
+ const target = page.target();
673
+ const targetId = getTargetId(target);
674
+ let session = this.sessions.get(targetId);
675
+ if (!session) {
676
+ session = await page.createCDPSession();
677
+ this.sessions.set(targetId, session);
678
+ }
679
+ return session;
680
+ }
681
+ /**
682
+ * Execute CDP command on a page
683
+ */
684
+ async send(page, method, params) {
685
+ const session = await this.getCDPSession(page);
686
+ return session.send(method, params);
687
+ }
688
+ /**
689
+ * Get all targets
690
+ */
691
+ getTargets() {
692
+ return this.getBrowser().targets();
693
+ }
694
+ /**
695
+ * Find target by ID
696
+ */
697
+ findTarget(targetId) {
698
+ return this.getTargets().find((t) => getTargetId(t) === targetId);
699
+ }
700
+ /**
701
+ * Trigger garbage collection on a page (best-effort)
702
+ */
703
+ async triggerGC(page) {
704
+ try {
705
+ const session = await this.getCDPSession(page);
706
+ await session.send('HeapProfiler.collectGarbage');
707
+ }
708
+ catch {
709
+ // Best-effort: silently ignore GC failures
710
+ }
711
+ }
712
+ /**
713
+ * Close a page by target ID
714
+ */
715
+ async closePage(targetId) {
716
+ const page = await this.getPageByTargetId(targetId);
717
+ if (page) {
718
+ await this.triggerGC(page);
719
+ await page.close();
720
+ this.sessions.delete(targetId);
721
+ }
722
+ }
723
+ /**
724
+ * Check if connected
725
+ */
726
+ isConnected() {
727
+ return this.browser !== null && this.browser.isConnected();
728
+ }
729
+ /**
730
+ * Get the port this client is connected to
731
+ */
732
+ getPort() {
733
+ return this.port;
734
+ }
735
+ /**
736
+ * Create a CDPClient instance for a specific port
737
+ */
738
+ static createForPort(port, options) {
739
+ return new CDPClient({ ...options, port });
740
+ }
741
+ }
742
+ exports.CDPClient = CDPClient;
743
+ // Singleton instance
744
+ let clientInstance = null;
745
+ function getCDPClient(options) {
746
+ if (!clientInstance) {
747
+ clientInstance = new CDPClient(options);
748
+ }
749
+ return clientInstance;
750
+ }
751
+ /**
752
+ * Factory for managing multiple CDPClient instances (one per Chrome port)
753
+ */
754
+ class CDPClientFactory {
755
+ clients = new Map();
756
+ /**
757
+ * Get an existing client for the given port, or create a new one
758
+ */
759
+ getOrCreate(port, options) {
760
+ let client = this.clients.get(port);
761
+ if (!client) {
762
+ client = CDPClient.createForPort(port, options);
763
+ this.clients.set(port, client);
764
+ }
765
+ return client;
766
+ }
767
+ /**
768
+ * Get an existing client for the given port, or undefined if not found
769
+ */
770
+ get(port) {
771
+ return this.clients.get(port);
772
+ }
773
+ /**
774
+ * Get all managed client instances
775
+ */
776
+ getAll() {
777
+ return Array.from(this.clients.values());
778
+ }
779
+ /**
780
+ * Disconnect all managed clients
781
+ */
782
+ async disconnectAll() {
783
+ const disconnectPromises = Array.from(this.clients.values()).map(client => client.disconnect().catch(err => console.error(`[CDPClientFactory] Error disconnecting client on port ${client.getPort()}:`, err)));
784
+ await Promise.all(disconnectPromises);
785
+ this.clients.clear();
786
+ }
787
+ }
788
+ exports.CDPClientFactory = CDPClientFactory;
789
+ // Singleton factory instance
790
+ let factoryInstance = null;
791
+ function getCDPClientFactory() {
792
+ if (!factoryInstance) {
793
+ factoryInstance = new CDPClientFactory();
794
+ }
795
+ return factoryInstance;
796
+ }
797
+ //# sourceMappingURL=client.js.map