opendevbrowser 0.0.15 → 0.0.17

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 (646) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +262 -43
  3. package/dist/annotate/direct-annotator.d.ts +22 -0
  4. package/dist/annotate/direct-annotator.d.ts.map +1 -0
  5. package/dist/annotate/output.d.ts +10 -0
  6. package/dist/annotate/output.d.ts.map +1 -0
  7. package/dist/browser/annotation-manager.d.ts +33 -0
  8. package/dist/browser/annotation-manager.d.ts.map +1 -0
  9. package/dist/browser/browser-manager.d.ts +402 -0
  10. package/dist/browser/browser-manager.d.ts.map +1 -0
  11. package/dist/browser/canvas-client.d.ts +53 -0
  12. package/dist/browser/canvas-client.d.ts.map +1 -0
  13. package/dist/browser/canvas-code-sync-manager.d.ts +79 -0
  14. package/dist/browser/canvas-code-sync-manager.d.ts.map +1 -0
  15. package/dist/browser/canvas-manager.d.ts +94 -0
  16. package/dist/browser/canvas-manager.d.ts.map +1 -0
  17. package/dist/browser/canvas-runtime-preview-bridge.d.ts +20 -0
  18. package/dist/browser/canvas-runtime-preview-bridge.d.ts.map +1 -0
  19. package/dist/browser/canvas-session-sync-manager.d.ts +21 -0
  20. package/dist/browser/canvas-session-sync-manager.d.ts.map +1 -0
  21. package/dist/browser/fingerprint/adapters.d.ts +26 -0
  22. package/dist/browser/fingerprint/adapters.d.ts.map +1 -0
  23. package/dist/browser/fingerprint/canary.d.ts +25 -0
  24. package/dist/browser/fingerprint/canary.d.ts.map +1 -0
  25. package/dist/browser/fingerprint/profiles.d.ts +16 -0
  26. package/dist/browser/fingerprint/profiles.d.ts.map +1 -0
  27. package/dist/browser/fingerprint/tier1-coherence.d.ts +36 -0
  28. package/dist/browser/fingerprint/tier1-coherence.d.ts.map +1 -0
  29. package/dist/browser/fingerprint/tier2-runtime.d.ts +40 -0
  30. package/dist/browser/fingerprint/tier2-runtime.d.ts.map +1 -0
  31. package/dist/browser/fingerprint/tier3-adaptive.d.ts +30 -0
  32. package/dist/browser/fingerprint/tier3-adaptive.d.ts.map +1 -0
  33. package/dist/browser/manager-types.d.ts +15 -0
  34. package/dist/browser/manager-types.d.ts.map +1 -0
  35. package/dist/browser/ops-browser-manager.d.ts +141 -0
  36. package/dist/browser/ops-browser-manager.d.ts.map +1 -0
  37. package/dist/browser/ops-client.d.ts +56 -0
  38. package/dist/browser/ops-client.d.ts.map +1 -0
  39. package/dist/browser/parallelism-governor.d.ts +31 -0
  40. package/dist/browser/parallelism-governor.d.ts.map +1 -0
  41. package/dist/browser/script-runner.d.ts +23 -0
  42. package/dist/browser/script-runner.d.ts.map +1 -0
  43. package/dist/browser/session-store.d.ts +63 -0
  44. package/dist/browser/session-store.d.ts.map +1 -0
  45. package/dist/browser/target-manager.d.ts +36 -0
  46. package/dist/browser/target-manager.d.ts.map +1 -0
  47. package/dist/cache/chrome-locator.d.ts +2 -0
  48. package/dist/cache/chrome-locator.d.ts.map +1 -0
  49. package/dist/cache/downloader.d.ts +6 -0
  50. package/dist/cache/downloader.d.ts.map +1 -0
  51. package/dist/cache/paths.d.ts +9 -0
  52. package/dist/cache/paths.d.ts.map +1 -0
  53. package/dist/canvas/code-sync/apply-tsx.d.ts +23 -0
  54. package/dist/canvas/code-sync/apply-tsx.d.ts.map +1 -0
  55. package/dist/canvas/code-sync/graph.d.ts +5 -0
  56. package/dist/canvas/code-sync/graph.d.ts.map +1 -0
  57. package/dist/canvas/code-sync/hash.d.ts +3 -0
  58. package/dist/canvas/code-sync/hash.d.ts.map +1 -0
  59. package/dist/canvas/code-sync/import.d.ts +18 -0
  60. package/dist/canvas/code-sync/import.d.ts.map +1 -0
  61. package/dist/canvas/code-sync/manifest.d.ts +5 -0
  62. package/dist/canvas/code-sync/manifest.d.ts.map +1 -0
  63. package/dist/canvas/code-sync/tsx-adapter.d.ts +8 -0
  64. package/dist/canvas/code-sync/tsx-adapter.d.ts.map +1 -0
  65. package/dist/canvas/code-sync/types.d.ts +152 -0
  66. package/dist/canvas/code-sync/types.d.ts.map +1 -0
  67. package/dist/canvas/code-sync/write.d.ts +9 -0
  68. package/dist/canvas/code-sync/write.d.ts.map +1 -0
  69. package/dist/canvas/document-store.d.ts +81 -0
  70. package/dist/canvas/document-store.d.ts.map +1 -0
  71. package/dist/canvas/export.d.ts +12 -0
  72. package/dist/canvas/export.d.ts.map +1 -0
  73. package/dist/canvas/repo-store.d.ts +10 -0
  74. package/dist/canvas/repo-store.d.ts.map +1 -0
  75. package/dist/canvas/surface-palette.d.ts +15 -0
  76. package/dist/canvas/surface-palette.d.ts.map +1 -0
  77. package/dist/canvas/types.d.ts +255 -0
  78. package/dist/canvas/types.d.ts.map +1 -0
  79. package/dist/canvas-runtime-preview-bridge-HBEHXM4T.js +7 -0
  80. package/dist/canvas-runtime-preview-bridge-HBEHXM4T.js.map +1 -0
  81. package/dist/chunk-5J3IFL3X.js +16706 -0
  82. package/dist/chunk-5J3IFL3X.js.map +1 -0
  83. package/dist/chunk-D633UO34.js +8149 -0
  84. package/dist/chunk-D633UO34.js.map +1 -0
  85. package/dist/chunk-FUSXMW3G.js +169 -0
  86. package/dist/chunk-FUSXMW3G.js.map +1 -0
  87. package/dist/chunk-TBUCZX4A.js +34 -0
  88. package/dist/chunk-TBUCZX4A.js.map +1 -0
  89. package/dist/chunk-V7KUDHDG.js +276 -0
  90. package/dist/chunk-V7KUDHDG.js.map +1 -0
  91. package/dist/chunk-Y2KL55OG.js +59 -0
  92. package/dist/chunk-Y2KL55OG.js.map +1 -0
  93. package/dist/cli/args.d.ts +25 -0
  94. package/dist/cli/args.d.ts.map +1 -0
  95. package/dist/cli/client.d.ts +2 -0
  96. package/dist/cli/client.d.ts.map +1 -0
  97. package/dist/cli/commands/annotate.d.ts +38 -0
  98. package/dist/cli/commands/annotate.d.ts.map +1 -0
  99. package/dist/cli/commands/artifacts.d.ts +24 -0
  100. package/dist/cli/commands/artifacts.d.ts.map +1 -0
  101. package/dist/cli/commands/canvas.d.ts +45 -0
  102. package/dist/cli/commands/canvas.d.ts.map +1 -0
  103. package/dist/cli/commands/daemon.d.ts +35 -0
  104. package/dist/cli/commands/daemon.d.ts.map +1 -0
  105. package/dist/cli/commands/devtools/console-poll.d.ts +7 -0
  106. package/dist/cli/commands/devtools/console-poll.d.ts.map +1 -0
  107. package/dist/cli/commands/devtools/debug-trace-snapshot.d.ts +20 -0
  108. package/dist/cli/commands/devtools/debug-trace-snapshot.d.ts.map +1 -0
  109. package/dist/cli/commands/devtools/network-poll.d.ts +7 -0
  110. package/dist/cli/commands/devtools/network-poll.d.ts.map +1 -0
  111. package/dist/cli/commands/devtools/perf.d.ts +7 -0
  112. package/dist/cli/commands/devtools/perf.d.ts.map +1 -0
  113. package/dist/cli/commands/devtools/screenshot.d.ts +18 -0
  114. package/dist/cli/commands/devtools/screenshot.d.ts.map +1 -0
  115. package/dist/cli/commands/dom/attr.d.ts +7 -0
  116. package/dist/cli/commands/dom/attr.d.ts.map +1 -0
  117. package/dist/cli/commands/dom/checked.d.ts +7 -0
  118. package/dist/cli/commands/dom/checked.d.ts.map +1 -0
  119. package/dist/cli/commands/dom/enabled.d.ts +7 -0
  120. package/dist/cli/commands/dom/enabled.d.ts.map +1 -0
  121. package/dist/cli/commands/dom/html.d.ts +7 -0
  122. package/dist/cli/commands/dom/html.d.ts.map +1 -0
  123. package/dist/cli/commands/dom/text.d.ts +7 -0
  124. package/dist/cli/commands/dom/text.d.ts.map +1 -0
  125. package/dist/cli/commands/dom/value.d.ts +7 -0
  126. package/dist/cli/commands/dom/value.d.ts.map +1 -0
  127. package/dist/cli/commands/dom/visible.d.ts +7 -0
  128. package/dist/cli/commands/dom/visible.d.ts.map +1 -0
  129. package/dist/cli/commands/export/clone-component.d.ts +16 -0
  130. package/dist/cli/commands/export/clone-component.d.ts.map +1 -0
  131. package/dist/cli/commands/export/clone-page.d.ts +15 -0
  132. package/dist/cli/commands/export/clone-page.d.ts.map +1 -0
  133. package/dist/cli/commands/interact/check.d.ts +7 -0
  134. package/dist/cli/commands/interact/check.d.ts.map +1 -0
  135. package/dist/cli/commands/interact/click.d.ts +7 -0
  136. package/dist/cli/commands/interact/click.d.ts.map +1 -0
  137. package/dist/cli/commands/interact/hover.d.ts +7 -0
  138. package/dist/cli/commands/interact/hover.d.ts.map +1 -0
  139. package/dist/cli/commands/interact/press.d.ts +7 -0
  140. package/dist/cli/commands/interact/press.d.ts.map +1 -0
  141. package/dist/cli/commands/interact/scroll-into-view.d.ts +7 -0
  142. package/dist/cli/commands/interact/scroll-into-view.d.ts.map +1 -0
  143. package/dist/cli/commands/interact/scroll.d.ts +7 -0
  144. package/dist/cli/commands/interact/scroll.d.ts.map +1 -0
  145. package/dist/cli/commands/interact/select.d.ts +7 -0
  146. package/dist/cli/commands/interact/select.d.ts.map +1 -0
  147. package/dist/cli/commands/interact/type.d.ts +7 -0
  148. package/dist/cli/commands/interact/type.d.ts.map +1 -0
  149. package/dist/cli/commands/interact/uncheck.d.ts +7 -0
  150. package/dist/cli/commands/interact/uncheck.d.ts.map +1 -0
  151. package/dist/cli/commands/macro-resolve.d.ts +18 -0
  152. package/dist/cli/commands/macro-resolve.d.ts.map +1 -0
  153. package/dist/cli/commands/native.d.ts +93 -0
  154. package/dist/cli/commands/native.d.ts.map +1 -0
  155. package/dist/cli/commands/nav/goto.d.ts +7 -0
  156. package/dist/cli/commands/nav/goto.d.ts.map +1 -0
  157. package/dist/cli/commands/nav/snapshot.d.ts +7 -0
  158. package/dist/cli/commands/nav/snapshot.d.ts.map +1 -0
  159. package/dist/cli/commands/nav/wait.d.ts +7 -0
  160. package/dist/cli/commands/nav/wait.d.ts.map +1 -0
  161. package/dist/cli/commands/pages/close.d.ts +6 -0
  162. package/dist/cli/commands/pages/close.d.ts.map +1 -0
  163. package/dist/cli/commands/pages/list.d.ts +7 -0
  164. package/dist/cli/commands/pages/list.d.ts.map +1 -0
  165. package/dist/cli/commands/pages/open.d.ts +7 -0
  166. package/dist/cli/commands/pages/open.d.ts.map +1 -0
  167. package/dist/cli/commands/product-video.d.ts +25 -0
  168. package/dist/cli/commands/product-video.d.ts.map +1 -0
  169. package/dist/cli/commands/registry.d.ts +5 -0
  170. package/dist/cli/commands/registry.d.ts.map +1 -0
  171. package/dist/cli/commands/research.d.ts +27 -0
  172. package/dist/cli/commands/research.d.ts.map +1 -0
  173. package/dist/cli/commands/rpc.d.ts +28 -0
  174. package/dist/cli/commands/rpc.d.ts.map +1 -0
  175. package/dist/cli/commands/run.d.ts +17 -0
  176. package/dist/cli/commands/run.d.ts.map +1 -0
  177. package/dist/cli/commands/serve.d.ts +64 -0
  178. package/dist/cli/commands/serve.d.ts.map +1 -0
  179. package/dist/cli/commands/session/connect.d.ts +9 -0
  180. package/dist/cli/commands/session/connect.d.ts.map +1 -0
  181. package/dist/cli/commands/session/cookie-import.d.ts +31 -0
  182. package/dist/cli/commands/session/cookie-import.d.ts.map +1 -0
  183. package/dist/cli/commands/session/cookie-list.d.ts +17 -0
  184. package/dist/cli/commands/session/cookie-list.d.ts.map +1 -0
  185. package/dist/cli/commands/session/disconnect.d.ts +6 -0
  186. package/dist/cli/commands/session/disconnect.d.ts.map +1 -0
  187. package/dist/cli/commands/session/launch.d.ts +29 -0
  188. package/dist/cli/commands/session/launch.d.ts.map +1 -0
  189. package/dist/cli/commands/session/status.d.ts +7 -0
  190. package/dist/cli/commands/session/status.d.ts.map +1 -0
  191. package/dist/cli/commands/shopping.d.ts +25 -0
  192. package/dist/cli/commands/shopping.d.ts.map +1 -0
  193. package/dist/cli/commands/status.d.ts +24 -0
  194. package/dist/cli/commands/status.d.ts.map +1 -0
  195. package/dist/cli/commands/targets/close.d.ts +6 -0
  196. package/dist/cli/commands/targets/close.d.ts.map +1 -0
  197. package/dist/cli/commands/targets/list.d.ts +7 -0
  198. package/dist/cli/commands/targets/list.d.ts.map +1 -0
  199. package/dist/cli/commands/targets/new.d.ts +7 -0
  200. package/dist/cli/commands/targets/new.d.ts.map +1 -0
  201. package/dist/cli/commands/targets/use.d.ts +7 -0
  202. package/dist/cli/commands/targets/use.d.ts.map +1 -0
  203. package/dist/cli/commands/types.d.ts +13 -0
  204. package/dist/cli/commands/types.d.ts.map +1 -0
  205. package/dist/cli/commands/uninstall.d.ts +14 -0
  206. package/dist/cli/commands/uninstall.d.ts.map +1 -0
  207. package/dist/cli/commands/update.d.ts +7 -0
  208. package/dist/cli/commands/update.d.ts.map +1 -0
  209. package/dist/cli/daemon-autostart.d.ts +46 -0
  210. package/dist/cli/daemon-autostart.d.ts.map +1 -0
  211. package/dist/cli/daemon-client.d.ts +33 -0
  212. package/dist/cli/daemon-client.d.ts.map +1 -0
  213. package/dist/cli/daemon-commands.d.ts +7 -0
  214. package/dist/cli/daemon-commands.d.ts.map +1 -0
  215. package/dist/cli/daemon-state.d.ts +56 -0
  216. package/dist/cli/daemon-state.d.ts.map +1 -0
  217. package/dist/cli/daemon-status.d.ts +19 -0
  218. package/dist/cli/daemon-status.d.ts.map +1 -0
  219. package/dist/cli/daemon.d.ts +29 -0
  220. package/dist/cli/daemon.d.ts.map +1 -0
  221. package/dist/cli/errors.d.ts +20 -0
  222. package/dist/cli/errors.d.ts.map +1 -0
  223. package/dist/cli/help.d.ts +33 -0
  224. package/dist/cli/help.d.ts.map +1 -0
  225. package/dist/cli/index.d.ts +2 -0
  226. package/dist/cli/index.d.ts.map +1 -0
  227. package/dist/cli/index.js +2825 -326
  228. package/dist/cli/index.js.map +1 -1
  229. package/dist/cli/installers/global.d.ts +9 -0
  230. package/dist/cli/installers/global.d.ts.map +1 -0
  231. package/dist/cli/installers/local.d.ts +9 -0
  232. package/dist/cli/installers/local.d.ts.map +1 -0
  233. package/dist/cli/installers/skills.d.ts +19 -0
  234. package/dist/cli/installers/skills.d.ts.map +1 -0
  235. package/dist/cli/output.d.ts +7 -0
  236. package/dist/cli/output.d.ts.map +1 -0
  237. package/dist/cli/remote-canvas-manager.d.ts +8 -0
  238. package/dist/cli/remote-canvas-manager.d.ts.map +1 -0
  239. package/dist/cli/remote-manager.d.ts +98 -0
  240. package/dist/cli/remote-manager.d.ts.map +1 -0
  241. package/dist/cli/remote-relay.d.ts +19 -0
  242. package/dist/cli/remote-relay.d.ts.map +1 -0
  243. package/dist/cli/templates/config.d.ts +7 -0
  244. package/dist/cli/templates/config.d.ts.map +1 -0
  245. package/dist/cli/utils/config.d.ts +20 -0
  246. package/dist/cli/utils/config.d.ts.map +1 -0
  247. package/dist/cli/utils/http.d.ts +5 -0
  248. package/dist/cli/utils/http.d.ts.map +1 -0
  249. package/dist/cli/utils/parse.d.ts +9 -0
  250. package/dist/cli/utils/parse.d.ts.map +1 -0
  251. package/dist/cli/utils/skills.d.ts +12 -0
  252. package/dist/cli/utils/skills.d.ts.map +1 -0
  253. package/dist/config.d.ts +208 -0
  254. package/dist/config.d.ts.map +1 -0
  255. package/dist/core/bootstrap.d.ts +3 -0
  256. package/dist/core/bootstrap.d.ts.map +1 -0
  257. package/dist/core/index.d.ts +3 -0
  258. package/dist/core/index.d.ts.map +1 -0
  259. package/dist/core/logging.d.ts +34 -0
  260. package/dist/core/logging.d.ts.map +1 -0
  261. package/dist/core/types.d.ts +36 -0
  262. package/dist/core/types.d.ts.map +1 -0
  263. package/dist/devtools/console-tracker.d.ts +44 -0
  264. package/dist/devtools/console-tracker.d.ts.map +1 -0
  265. package/dist/devtools/exception-tracker.d.ts +42 -0
  266. package/dist/devtools/exception-tracker.d.ts.map +1 -0
  267. package/dist/devtools/network-tracker.d.ts +34 -0
  268. package/dist/devtools/network-tracker.d.ts.map +1 -0
  269. package/dist/export/css-extract.d.ts +5 -0
  270. package/dist/export/css-extract.d.ts.map +1 -0
  271. package/dist/export/dom-capture.d.ts +15 -0
  272. package/dist/export/dom-capture.d.ts.map +1 -0
  273. package/dist/export/react-emitter.d.ts +11 -0
  274. package/dist/export/react-emitter.d.ts.map +1 -0
  275. package/dist/extension-extractor.d.ts +3 -0
  276. package/dist/extension-extractor.d.ts.map +1 -0
  277. package/dist/fs-UMRKOBNN.js +7 -0
  278. package/dist/fs-UMRKOBNN.js.map +1 -0
  279. package/dist/index.d.ts +3 -4
  280. package/dist/index.d.ts.map +1 -0
  281. package/dist/index.js +1028 -123
  282. package/dist/index.js.map +1 -1
  283. package/dist/macros/execute.d.ts +44 -0
  284. package/dist/macros/execute.d.ts.map +1 -0
  285. package/dist/macros/index.d.ts +9 -0
  286. package/dist/macros/index.d.ts.map +1 -0
  287. package/dist/macros/packs/core.d.ts +3 -0
  288. package/dist/macros/packs/core.d.ts.map +1 -0
  289. package/dist/macros/registry.d.ts +48 -0
  290. package/dist/macros/registry.d.ts.map +1 -0
  291. package/dist/macros-ND2M7LWU.js +399 -0
  292. package/dist/macros-ND2M7LWU.js.map +1 -0
  293. package/dist/opendevbrowser.d.ts +3 -4
  294. package/dist/opendevbrowser.d.ts.map +1 -0
  295. package/dist/opendevbrowser.js +1028 -123
  296. package/dist/opendevbrowser.js.map +1 -1
  297. package/dist/providers/adaptive-concurrency.d.ts +42 -0
  298. package/dist/providers/adaptive-concurrency.d.ts.map +1 -0
  299. package/dist/providers/artifacts.d.ts +34 -0
  300. package/dist/providers/artifacts.d.ts.map +1 -0
  301. package/dist/providers/blocker.d.ts +47 -0
  302. package/dist/providers/blocker.d.ts.map +1 -0
  303. package/dist/providers/community/index.d.ts +44 -0
  304. package/dist/providers/community/index.d.ts.map +1 -0
  305. package/dist/providers/enrichment.d.ts +33 -0
  306. package/dist/providers/enrichment.d.ts.map +1 -0
  307. package/dist/providers/errors.d.ts +41 -0
  308. package/dist/providers/errors.d.ts.map +1 -0
  309. package/dist/providers/index.d.ts +121 -0
  310. package/dist/providers/index.d.ts.map +1 -0
  311. package/dist/providers/normalize.d.ts +39 -0
  312. package/dist/providers/normalize.d.ts.map +1 -0
  313. package/dist/providers/policy.d.ts +5 -0
  314. package/dist/providers/policy.d.ts.map +1 -0
  315. package/dist/providers/registry.d.ts +22 -0
  316. package/dist/providers/registry.d.ts.map +1 -0
  317. package/dist/providers/renderer.d.ts +49 -0
  318. package/dist/providers/renderer.d.ts.map +1 -0
  319. package/dist/providers/runtime-factory.d.ts +20 -0
  320. package/dist/providers/runtime-factory.d.ts.map +1 -0
  321. package/dist/providers/safety/prompt-guard.d.ts +34 -0
  322. package/dist/providers/safety/prompt-guard.d.ts.map +1 -0
  323. package/dist/providers/shared/anti-bot-policy.d.ts +51 -0
  324. package/dist/providers/shared/anti-bot-policy.d.ts.map +1 -0
  325. package/dist/providers/shared/post-policy.d.ts +31 -0
  326. package/dist/providers/shared/post-policy.d.ts.map +1 -0
  327. package/dist/providers/shared/request-headers.d.ts +5 -0
  328. package/dist/providers/shared/request-headers.d.ts.map +1 -0
  329. package/dist/providers/shared/traversal-url.d.ts +2 -0
  330. package/dist/providers/shared/traversal-url.d.ts.map +1 -0
  331. package/dist/providers/shopping/index.d.ts +63 -0
  332. package/dist/providers/shopping/index.d.ts.map +1 -0
  333. package/dist/providers/social/bluesky.d.ts +3 -0
  334. package/dist/providers/social/bluesky.d.ts.map +1 -0
  335. package/dist/providers/social/facebook.d.ts +3 -0
  336. package/dist/providers/social/facebook.d.ts.map +1 -0
  337. package/dist/providers/social/index.d.ts +31 -0
  338. package/dist/providers/social/index.d.ts.map +1 -0
  339. package/dist/providers/social/instagram.d.ts +3 -0
  340. package/dist/providers/social/instagram.d.ts.map +1 -0
  341. package/dist/providers/social/linkedin.d.ts +3 -0
  342. package/dist/providers/social/linkedin.d.ts.map +1 -0
  343. package/dist/providers/social/platform.d.ts +40 -0
  344. package/dist/providers/social/platform.d.ts.map +1 -0
  345. package/dist/providers/social/reddit.d.ts +3 -0
  346. package/dist/providers/social/reddit.d.ts.map +1 -0
  347. package/dist/providers/social/threads.d.ts +3 -0
  348. package/dist/providers/social/threads.d.ts.map +1 -0
  349. package/dist/providers/social/tiktok.d.ts +3 -0
  350. package/dist/providers/social/tiktok.d.ts.map +1 -0
  351. package/dist/providers/social/x.d.ts +3 -0
  352. package/dist/providers/social/x.d.ts.map +1 -0
  353. package/dist/providers/social/youtube-resolver.d.ts +78 -0
  354. package/dist/providers/social/youtube-resolver.d.ts.map +1 -0
  355. package/dist/providers/social/youtube.d.ts +34 -0
  356. package/dist/providers/social/youtube.d.ts.map +1 -0
  357. package/dist/providers/tier-router.d.ts +30 -0
  358. package/dist/providers/tier-router.d.ts.map +1 -0
  359. package/dist/providers/timebox.d.ts +20 -0
  360. package/dist/providers/timebox.d.ts.map +1 -0
  361. package/dist/providers/types.d.ts +344 -0
  362. package/dist/providers/types.d.ts.map +1 -0
  363. package/dist/providers/web/crawl-worker.d.ts +36 -0
  364. package/dist/providers/web/crawl-worker.d.ts.map +1 -0
  365. package/dist/providers/web/crawler.d.ts +101 -0
  366. package/dist/providers/web/crawler.d.ts.map +1 -0
  367. package/dist/providers/web/extract.d.ts +11 -0
  368. package/dist/providers/web/extract.d.ts.map +1 -0
  369. package/dist/providers/web/index.d.ts +24 -0
  370. package/dist/providers/web/index.d.ts.map +1 -0
  371. package/dist/providers/web/policy.d.ts +14 -0
  372. package/dist/providers/web/policy.d.ts.map +1 -0
  373. package/dist/providers/workflows.d.ts +67 -0
  374. package/dist/providers/workflows.d.ts.map +1 -0
  375. package/dist/providers-G3LRHQXX.js +121 -0
  376. package/dist/providers-G3LRHQXX.js.map +1 -0
  377. package/dist/relay/protocol.d.ts +399 -0
  378. package/dist/relay/protocol.d.ts.map +1 -0
  379. package/dist/relay/relay-endpoints.d.ts +16 -0
  380. package/dist/relay/relay-endpoints.d.ts.map +1 -0
  381. package/dist/relay/relay-server.d.ts +124 -0
  382. package/dist/relay/relay-server.d.ts.map +1 -0
  383. package/dist/relay/relay-types.d.ts +12 -0
  384. package/dist/relay/relay-types.d.ts.map +1 -0
  385. package/dist/runtime-factory-BICHDPE7.js +13 -0
  386. package/dist/runtime-factory-BICHDPE7.js.map +1 -0
  387. package/dist/skills/continuity-nudge.d.ts +12 -0
  388. package/dist/skills/continuity-nudge.d.ts.map +1 -0
  389. package/dist/skills/skill-loader.d.ts +20 -0
  390. package/dist/skills/skill-loader.d.ts.map +1 -0
  391. package/dist/skills/skill-nudge.d.ts +18 -0
  392. package/dist/skills/skill-nudge.d.ts.map +1 -0
  393. package/dist/skills/types.d.ts +12 -0
  394. package/dist/skills/types.d.ts.map +1 -0
  395. package/dist/snapshot/ops-snapshot.d.ts +16 -0
  396. package/dist/snapshot/ops-snapshot.d.ts.map +1 -0
  397. package/dist/snapshot/refs.d.ts +23 -0
  398. package/dist/snapshot/refs.d.ts.map +1 -0
  399. package/dist/snapshot/snapshotter.d.ts +27 -0
  400. package/dist/snapshot/snapshotter.d.ts.map +1 -0
  401. package/dist/tools/annotate.d.ts +4 -0
  402. package/dist/tools/annotate.d.ts.map +1 -0
  403. package/dist/tools/canvas.d.ts +4 -0
  404. package/dist/tools/canvas.d.ts.map +1 -0
  405. package/dist/tools/check.d.ts +4 -0
  406. package/dist/tools/check.d.ts.map +1 -0
  407. package/dist/tools/click.d.ts +4 -0
  408. package/dist/tools/click.d.ts.map +1 -0
  409. package/dist/tools/clone_component.d.ts +4 -0
  410. package/dist/tools/clone_component.d.ts.map +1 -0
  411. package/dist/tools/clone_page.d.ts +4 -0
  412. package/dist/tools/clone_page.d.ts.map +1 -0
  413. package/dist/tools/close.d.ts +4 -0
  414. package/dist/tools/close.d.ts.map +1 -0
  415. package/dist/tools/connect.d.ts +4 -0
  416. package/dist/tools/connect.d.ts.map +1 -0
  417. package/dist/tools/console_poll.d.ts +4 -0
  418. package/dist/tools/console_poll.d.ts.map +1 -0
  419. package/dist/tools/cookie_import.d.ts +25 -0
  420. package/dist/tools/cookie_import.d.ts.map +1 -0
  421. package/dist/tools/cookie_list.d.ts +9 -0
  422. package/dist/tools/cookie_list.d.ts.map +1 -0
  423. package/dist/tools/debug_trace_snapshot.d.ts +4 -0
  424. package/dist/tools/debug_trace_snapshot.d.ts.map +1 -0
  425. package/dist/tools/deps.d.ts +28 -0
  426. package/dist/tools/deps.d.ts.map +1 -0
  427. package/dist/tools/disconnect.d.ts +4 -0
  428. package/dist/tools/disconnect.d.ts.map +1 -0
  429. package/dist/tools/dom_get_html.d.ts +4 -0
  430. package/dist/tools/dom_get_html.d.ts.map +1 -0
  431. package/dist/tools/dom_get_text.d.ts +4 -0
  432. package/dist/tools/dom_get_text.d.ts.map +1 -0
  433. package/dist/tools/get_attr.d.ts +4 -0
  434. package/dist/tools/get_attr.d.ts.map +1 -0
  435. package/dist/tools/get_value.d.ts +4 -0
  436. package/dist/tools/get_value.d.ts.map +1 -0
  437. package/dist/tools/goto.d.ts +4 -0
  438. package/dist/tools/goto.d.ts.map +1 -0
  439. package/dist/tools/hover.d.ts +4 -0
  440. package/dist/tools/hover.d.ts.map +1 -0
  441. package/dist/tools/index.d.ts +4 -0
  442. package/dist/tools/index.d.ts.map +1 -0
  443. package/dist/tools/is_checked.d.ts +4 -0
  444. package/dist/tools/is_checked.d.ts.map +1 -0
  445. package/dist/tools/is_enabled.d.ts +4 -0
  446. package/dist/tools/is_enabled.d.ts.map +1 -0
  447. package/dist/tools/is_visible.d.ts +4 -0
  448. package/dist/tools/is_visible.d.ts.map +1 -0
  449. package/dist/tools/launch.d.ts +4 -0
  450. package/dist/tools/launch.d.ts.map +1 -0
  451. package/dist/tools/list.d.ts +4 -0
  452. package/dist/tools/list.d.ts.map +1 -0
  453. package/dist/tools/macro_resolve.d.ts +25 -0
  454. package/dist/tools/macro_resolve.d.ts.map +1 -0
  455. package/dist/tools/network_poll.d.ts +4 -0
  456. package/dist/tools/network_poll.d.ts.map +1 -0
  457. package/dist/tools/page.d.ts +4 -0
  458. package/dist/tools/page.d.ts.map +1 -0
  459. package/dist/tools/perf.d.ts +4 -0
  460. package/dist/tools/perf.d.ts.map +1 -0
  461. package/dist/tools/press.d.ts +4 -0
  462. package/dist/tools/press.d.ts.map +1 -0
  463. package/dist/tools/product_video_run.d.ts +4 -0
  464. package/dist/tools/product_video_run.d.ts.map +1 -0
  465. package/dist/tools/prompting_guide.d.ts +4 -0
  466. package/dist/tools/prompting_guide.d.ts.map +1 -0
  467. package/dist/tools/research_run.d.ts +4 -0
  468. package/dist/tools/research_run.d.ts.map +1 -0
  469. package/dist/tools/response.d.ts +19 -0
  470. package/dist/tools/response.d.ts.map +1 -0
  471. package/dist/tools/run.d.ts +4 -0
  472. package/dist/tools/run.d.ts.map +1 -0
  473. package/dist/tools/screenshot.d.ts +4 -0
  474. package/dist/tools/screenshot.d.ts.map +1 -0
  475. package/dist/tools/scroll.d.ts +4 -0
  476. package/dist/tools/scroll.d.ts.map +1 -0
  477. package/dist/tools/scroll_into_view.d.ts +4 -0
  478. package/dist/tools/scroll_into_view.d.ts.map +1 -0
  479. package/dist/tools/select.d.ts +4 -0
  480. package/dist/tools/select.d.ts.map +1 -0
  481. package/dist/tools/shopping_run.d.ts +4 -0
  482. package/dist/tools/shopping_run.d.ts.map +1 -0
  483. package/dist/tools/skill_list.d.ts +4 -0
  484. package/dist/tools/skill_list.d.ts.map +1 -0
  485. package/dist/tools/skill_load.d.ts +4 -0
  486. package/dist/tools/skill_load.d.ts.map +1 -0
  487. package/dist/tools/snapshot.d.ts +4 -0
  488. package/dist/tools/snapshot.d.ts.map +1 -0
  489. package/dist/tools/status.d.ts +4 -0
  490. package/dist/tools/status.d.ts.map +1 -0
  491. package/dist/tools/target_close.d.ts +4 -0
  492. package/dist/tools/target_close.d.ts.map +1 -0
  493. package/dist/tools/target_new.d.ts +4 -0
  494. package/dist/tools/target_new.d.ts.map +1 -0
  495. package/dist/tools/target_use.d.ts +4 -0
  496. package/dist/tools/target_use.d.ts.map +1 -0
  497. package/dist/tools/targets_list.d.ts +4 -0
  498. package/dist/tools/targets_list.d.ts.map +1 -0
  499. package/dist/tools/type.d.ts +4 -0
  500. package/dist/tools/type.d.ts.map +1 -0
  501. package/dist/tools/uncheck.d.ts +4 -0
  502. package/dist/tools/uncheck.d.ts.map +1 -0
  503. package/dist/tools/wait.d.ts +4 -0
  504. package/dist/tools/wait.d.ts.map +1 -0
  505. package/dist/tools/workflow-runtime.d.ts +3 -0
  506. package/dist/tools/workflow-runtime.d.ts.map +1 -0
  507. package/dist/utils/crypto.d.ts +2 -0
  508. package/dist/utils/crypto.d.ts.map +1 -0
  509. package/dist/utils/endpoint-validation.d.ts +2 -0
  510. package/dist/utils/endpoint-validation.d.ts.map +1 -0
  511. package/dist/utils/fs.d.ts +5 -0
  512. package/dist/utils/fs.d.ts.map +1 -0
  513. package/dist/utils/hub-enabled.d.ts +3 -0
  514. package/dist/utils/hub-enabled.d.ts.map +1 -0
  515. package/extension/canvas.html +636 -0
  516. package/extension/dist/annotate-content.css +15 -6
  517. package/extension/dist/annotate-content.js +119 -9
  518. package/extension/dist/annotation-payload.js +163 -0
  519. package/extension/dist/background.js +158 -22
  520. package/extension/dist/canvas/canvas-runtime.js +1061 -0
  521. package/extension/dist/canvas/model.js +213 -0
  522. package/extension/dist/canvas/viewport-fit.js +67 -0
  523. package/extension/dist/canvas-page.js +1801 -0
  524. package/extension/dist/ops/dom-bridge.js +116 -3
  525. package/extension/dist/ops/ops-runtime.js +1014 -48
  526. package/extension/dist/ops/ops-session-store.js +37 -116
  527. package/extension/dist/ops/parallelism-governor.js +117 -0
  528. package/extension/dist/ops/snapshot-shared.js +21 -5
  529. package/extension/dist/ops/target-session-coordinator.js +157 -0
  530. package/extension/dist/popup.js +155 -31
  531. package/extension/dist/services/CDPRouter.js +70 -5
  532. package/extension/dist/services/ConnectionManager.js +22 -3
  533. package/extension/dist/services/RelayClient.js +9 -0
  534. package/extension/dist/services/TabManager.js +35 -12
  535. package/extension/dist/types.js +2 -0
  536. package/extension/icons/icon128.png +0 -0
  537. package/extension/icons/icon16.png +0 -0
  538. package/extension/icons/icon32.png +0 -0
  539. package/extension/icons/icon48.png +0 -0
  540. package/extension/manifest.json +1 -1
  541. package/extension/popup.html +52 -0
  542. package/package.json +30 -19
  543. package/scripts/native/host.cjs +230 -0
  544. package/scripts/native/install.ps1 +73 -0
  545. package/scripts/native/install.sh +66 -0
  546. package/scripts/native/uninstall.ps1 +25 -0
  547. package/scripts/native/uninstall.sh +26 -0
  548. package/skills/AGENTS.md +20 -8
  549. package/skills/opendevbrowser-best-practices/SKILL.md +248 -74
  550. package/skills/opendevbrowser-best-practices/artifacts/browser-agent-known-issues-matrix.md +44 -0
  551. package/skills/opendevbrowser-best-practices/artifacts/canvas-governance-playbook.md +141 -0
  552. package/skills/opendevbrowser-best-practices/artifacts/command-channel-reference.md +191 -0
  553. package/skills/opendevbrowser-best-practices/artifacts/debug-trace-playbook.md +36 -0
  554. package/skills/opendevbrowser-best-practices/artifacts/fingerprint-tiers.md +36 -0
  555. package/skills/opendevbrowser-best-practices/artifacts/macro-workflows.md +43 -0
  556. package/skills/opendevbrowser-best-practices/artifacts/parity-gates.md +36 -0
  557. package/skills/opendevbrowser-best-practices/artifacts/provider-workflows.md +89 -0
  558. package/skills/opendevbrowser-best-practices/assets/templates/canvas-blocker-checklist.json +70 -0
  559. package/skills/opendevbrowser-best-practices/assets/templates/canvas-feedback-eval.json +73 -0
  560. package/skills/opendevbrowser-best-practices/assets/templates/canvas-generation-plan.v1.json +67 -0
  561. package/skills/opendevbrowser-best-practices/assets/templates/canvas-handshake-example.json +126 -0
  562. package/skills/opendevbrowser-best-practices/assets/templates/cdp-forward-envelope.json +11 -0
  563. package/skills/opendevbrowser-best-practices/assets/templates/mode-flag-matrix.json +56 -0
  564. package/skills/opendevbrowser-best-practices/assets/templates/ops-request-envelope.json +9 -0
  565. package/skills/opendevbrowser-best-practices/assets/templates/robustness-checklist.json +136 -0
  566. package/skills/opendevbrowser-best-practices/assets/templates/surface-audit-checklist.json +28 -0
  567. package/skills/opendevbrowser-best-practices/scripts/odb-workflow.sh +170 -0
  568. package/skills/opendevbrowser-best-practices/scripts/run-robustness-audit.sh +164 -0
  569. package/skills/opendevbrowser-best-practices/scripts/validate-skill-assets.sh +234 -0
  570. package/skills/opendevbrowser-continuity-ledger/SKILL.md +10 -0
  571. package/skills/opendevbrowser-data-extraction/SKILL.md +126 -0
  572. package/skills/opendevbrowser-data-extraction/artifacts/extraction-workflows.md +31 -0
  573. package/skills/opendevbrowser-data-extraction/assets/templates/compliance-checklist.md +7 -0
  574. package/skills/opendevbrowser-data-extraction/assets/templates/extraction-schema.json +17 -0
  575. package/skills/opendevbrowser-data-extraction/assets/templates/pagination-state.json +11 -0
  576. package/skills/opendevbrowser-data-extraction/assets/templates/quality-gates.json +10 -0
  577. package/skills/opendevbrowser-data-extraction/examples/sample-schema.json +19 -0
  578. package/skills/opendevbrowser-data-extraction/scripts/run-extraction-workflow.sh +83 -0
  579. package/skills/opendevbrowser-data-extraction/scripts/validate-skill-assets.sh +49 -0
  580. package/skills/opendevbrowser-form-testing/SKILL.md +143 -0
  581. package/skills/opendevbrowser-form-testing/artifacts/form-workflows.md +37 -0
  582. package/skills/opendevbrowser-form-testing/assets/templates/a11y-assertions.md +7 -0
  583. package/skills/opendevbrowser-form-testing/assets/templates/challenge-decision-tree.json +16 -0
  584. package/skills/opendevbrowser-form-testing/assets/templates/multi-step-state.json +11 -0
  585. package/skills/opendevbrowser-form-testing/assets/templates/validation-matrix.json +24 -0
  586. package/skills/opendevbrowser-form-testing/examples/sample-validation-matrix.json +29 -0
  587. package/skills/opendevbrowser-form-testing/scripts/run-form-workflow.sh +82 -0
  588. package/skills/opendevbrowser-form-testing/scripts/validate-skill-assets.sh +49 -0
  589. package/skills/opendevbrowser-login-automation/SKILL.md +159 -0
  590. package/skills/opendevbrowser-login-automation/artifacts/login-workflows.md +39 -0
  591. package/skills/opendevbrowser-login-automation/assets/templates/auth-signals.json +21 -0
  592. package/skills/opendevbrowser-login-automation/assets/templates/challenge-checkpoint.md +10 -0
  593. package/skills/opendevbrowser-login-automation/assets/templates/login-scenario-matrix.json +26 -0
  594. package/skills/opendevbrowser-login-automation/examples/sample-auth-signals.json +14 -0
  595. package/skills/opendevbrowser-login-automation/scripts/record-auth-signals.sh +18 -0
  596. package/skills/opendevbrowser-login-automation/scripts/run-login-workflow.sh +99 -0
  597. package/skills/opendevbrowser-login-automation/scripts/validate-skill-assets.sh +50 -0
  598. package/skills/opendevbrowser-product-presentation-asset/SKILL.md +98 -0
  599. package/skills/opendevbrowser-product-presentation-asset/artifacts/asset-pack-assembly.md +23 -0
  600. package/skills/opendevbrowser-product-presentation-asset/artifacts/ugc-creative-guide.md +21 -0
  601. package/skills/opendevbrowser-product-presentation-asset/assets/templates/claims-evidence-map.md +5 -0
  602. package/skills/opendevbrowser-product-presentation-asset/assets/templates/copy.md +5 -0
  603. package/skills/opendevbrowser-product-presentation-asset/assets/templates/features.md +4 -0
  604. package/skills/opendevbrowser-product-presentation-asset/assets/templates/manifest.schema.json +14 -0
  605. package/skills/opendevbrowser-product-presentation-asset/assets/templates/shot-list.md +7 -0
  606. package/skills/opendevbrowser-product-presentation-asset/assets/templates/ugc-concepts.md +17 -0
  607. package/skills/opendevbrowser-product-presentation-asset/assets/templates/user-actions.md +7 -0
  608. package/skills/opendevbrowser-product-presentation-asset/assets/templates/video-assembly.md +18 -0
  609. package/skills/opendevbrowser-product-presentation-asset/examples/sample-input.json +6 -0
  610. package/skills/opendevbrowser-product-presentation-asset/examples/sample-manifest.json +18 -0
  611. package/skills/opendevbrowser-product-presentation-asset/scripts/capture-screenshots.sh +9 -0
  612. package/skills/opendevbrowser-product-presentation-asset/scripts/collect-product.sh +14 -0
  613. package/skills/opendevbrowser-product-presentation-asset/scripts/download-images.sh +9 -0
  614. package/skills/opendevbrowser-product-presentation-asset/scripts/render-video-brief.sh +96 -0
  615. package/skills/opendevbrowser-product-presentation-asset/scripts/validate-skill-assets.sh +56 -0
  616. package/skills/opendevbrowser-product-presentation-asset/scripts/write-manifest.sh +43 -0
  617. package/skills/opendevbrowser-research/SKILL.md +73 -0
  618. package/skills/opendevbrowser-research/artifacts/research-workflows.md +29 -0
  619. package/skills/opendevbrowser-research/assets/templates/compact.md +7 -0
  620. package/skills/opendevbrowser-research/assets/templates/context.json +18 -0
  621. package/skills/opendevbrowser-research/assets/templates/report.md +9 -0
  622. package/skills/opendevbrowser-research/examples/sample-input.json +6 -0
  623. package/skills/opendevbrowser-research/examples/sample-output.md +4 -0
  624. package/skills/opendevbrowser-research/scripts/render-output.sh +12 -0
  625. package/skills/opendevbrowser-research/scripts/run-research.sh +23 -0
  626. package/skills/opendevbrowser-research/scripts/validate-skill-assets.sh +48 -0
  627. package/skills/opendevbrowser-research/scripts/write-artifacts.sh +29 -0
  628. package/skills/opendevbrowser-shopping/SKILL.md +118 -0
  629. package/skills/opendevbrowser-shopping/artifacts/deal-hunting-workflows.md +37 -0
  630. package/skills/opendevbrowser-shopping/assets/templates/deal-thresholds.json +8 -0
  631. package/skills/opendevbrowser-shopping/assets/templates/deals-context.json +9 -0
  632. package/skills/opendevbrowser-shopping/assets/templates/deals-table.md +4 -0
  633. package/skills/opendevbrowser-shopping/assets/templates/market-analysis.json +30 -0
  634. package/skills/opendevbrowser-shopping/examples/sample-deals.md +4 -0
  635. package/skills/opendevbrowser-shopping/examples/sample-query.json +5 -0
  636. package/skills/opendevbrowser-shopping/scripts/analyze-market.sh +307 -0
  637. package/skills/opendevbrowser-shopping/scripts/normalize-offers.sh +28 -0
  638. package/skills/opendevbrowser-shopping/scripts/render-deals.sh +13 -0
  639. package/skills/opendevbrowser-shopping/scripts/run-deal-hunt.sh +32 -0
  640. package/skills/opendevbrowser-shopping/scripts/run-shopping.sh +19 -0
  641. package/skills/opendevbrowser-shopping/scripts/validate-skill-assets.sh +53 -0
  642. package/dist/chunk-JVBMT2O5.js +0 -7173
  643. package/dist/chunk-JVBMT2O5.js.map +0 -1
  644. package/skills/data-extraction/SKILL.md +0 -128
  645. package/skills/form-testing/SKILL.md +0 -106
  646. package/skills/login-automation/SKILL.md +0 -108
@@ -5,24 +5,59 @@ import { logError } from "../logging.js";
5
5
  import { DomBridge } from "./dom-bridge.js";
6
6
  import { buildSnapshot } from "./snapshot-builder.js";
7
7
  import { OpsSessionStore } from "./ops-session-store.js";
8
+ import { DEFAULT_OPS_PARALLELISM_POLICY, evaluateOpsGovernor } from "./parallelism-governor.js";
8
9
  import { redactConsoleText, redactUrl } from "./redaction.js";
9
10
  const MAX_CONSOLE_EVENTS = 200;
10
11
  const MAX_NETWORK_EVENTS = 300;
11
12
  const SESSION_TTL_MS = 20_000;
12
13
  const SCREENSHOT_TIMEOUT_MS = 8000;
13
14
  const TAB_CLOSE_TIMEOUT_MS = 5000;
15
+ const TARGET_SCOPED_COMMANDS = new Set([
16
+ "storage.setCookies",
17
+ "storage.getCookies",
18
+ "nav.goto",
19
+ "nav.wait",
20
+ "nav.snapshot",
21
+ "interact.click",
22
+ "interact.hover",
23
+ "interact.press",
24
+ "interact.check",
25
+ "interact.uncheck",
26
+ "interact.type",
27
+ "interact.select",
28
+ "interact.scroll",
29
+ "interact.scrollIntoView",
30
+ "dom.getHtml",
31
+ "dom.getText",
32
+ "dom.getAttr",
33
+ "dom.getValue",
34
+ "dom.isVisible",
35
+ "dom.isEnabled",
36
+ "dom.isChecked",
37
+ "canvas.applyRuntimePreviewBridge",
38
+ "export.clonePage",
39
+ "export.cloneComponent",
40
+ "devtools.perf",
41
+ "page.screenshot"
42
+ ]);
14
43
  export class OpsRuntime {
15
44
  sendEnvelope;
16
45
  cdp;
46
+ getCanvasPageState;
47
+ performCanvasPageAction;
17
48
  tabs = new TabManager();
18
49
  dom = new DomBridge();
19
50
  sessions = new OpsSessionStore();
20
51
  encoder = new TextEncoder();
21
52
  closingTimers = new Map();
53
+ parallelWaiters = new Map();
22
54
  constructor(options) {
23
55
  this.sendEnvelope = options.send;
24
56
  this.cdp = options.cdp;
57
+ this.getCanvasPageState = options.getCanvasPageState;
58
+ this.performCanvasPageAction = options.performCanvasPageAction;
25
59
  chrome.tabs.onRemoved.addListener(this.handleTabRemoved);
60
+ chrome.tabs.onUpdated.addListener(this.handleTabUpdated);
26
61
  chrome.debugger.onEvent.addListener(this.handleDebuggerEvent);
27
62
  chrome.debugger.onDetach.addListener(this.handleDebuggerDetach);
28
63
  }
@@ -95,6 +130,19 @@ export class OpsRuntime {
95
130
  handleTabRemoved = (tabId) => {
96
131
  this.handleClosedTarget(tabId, "ops_tab_closed");
97
132
  };
133
+ handleTabUpdated = (tabId, changeInfo, tab) => {
134
+ const session = this.sessions.getByTabId(tabId);
135
+ if (!session)
136
+ return;
137
+ if (changeInfo.discarded === true || tab.discarded === true) {
138
+ session.discardedSignals += 1;
139
+ }
140
+ const frozenChange = changeInfo.frozen === true;
141
+ const frozenTab = tab.frozen === true;
142
+ if (frozenChange || frozenTab) {
143
+ session.frozenSignals += 1;
144
+ }
145
+ };
98
146
  handleDebuggerDetach = (source) => {
99
147
  if (typeof source.tabId !== "number")
100
148
  return;
@@ -197,12 +245,21 @@ export class OpsRuntime {
197
245
  case "session.status":
198
246
  await this.handleSessionStatus(message, clientId);
199
247
  return;
248
+ case "storage.setCookies":
249
+ await this.withSession(message, clientId, (session) => this.handleStorageSetCookies(message, session));
250
+ return;
251
+ case "storage.getCookies":
252
+ await this.withSession(message, clientId, (session) => this.handleStorageGetCookies(message, session));
253
+ return;
200
254
  case "targets.list":
201
255
  await this.withSession(message, clientId, (session) => this.handleTargetsList(message, session));
202
256
  return;
203
257
  case "targets.use":
204
258
  await this.withSession(message, clientId, (session) => this.handleTargetsUse(message, session));
205
259
  return;
260
+ case "targets.registerCanvas":
261
+ await this.withSession(message, clientId, (session) => this.handleTargetsRegisterCanvas(message, session));
262
+ return;
206
263
  case "targets.new":
207
264
  await this.withSession(message, clientId, (session) => this.handleTargetsNew(message, session));
208
265
  return;
@@ -275,6 +332,9 @@ export class OpsRuntime {
275
332
  case "dom.isChecked":
276
333
  await this.withSession(message, clientId, (session) => this.handleDomIsChecked(message, session));
277
334
  return;
335
+ case "canvas.applyRuntimePreviewBridge":
336
+ await this.withSession(message, clientId, (session) => this.handleCanvasRuntimePreviewBridge(message, session));
337
+ return;
278
338
  case "export.clonePage":
279
339
  await this.withSession(message, clientId, (session) => this.handleClonePage(message, session));
280
340
  return;
@@ -299,6 +359,7 @@ export class OpsRuntime {
299
359
  }
300
360
  async handleSessionLaunch(message, clientId) {
301
361
  const payload = isRecord(message.payload) ? message.payload : {};
362
+ const parallelismPolicy = parseParallelismPolicy(payload.parallelismPolicy);
302
363
  const startUrl = typeof payload.startUrl === "string" ? payload.startUrl : undefined;
303
364
  if (startUrl) {
304
365
  try {
@@ -320,28 +381,38 @@ export class OpsRuntime {
320
381
  this.sendError(message, buildError("ops_unavailable", "No active tab to attach.", true));
321
382
  return;
322
383
  }
323
- if (activeTab.url) {
324
- const restriction = isRestrictedUrl(activeTab.url);
384
+ const activeTabId = activeTab.id;
385
+ const resolvedTab = startUrl
386
+ ? await this.tabs.waitForTabComplete(activeTabId)
387
+ .catch(() => undefined)
388
+ .then(async () => await this.tabs.getTab(activeTabId) ?? activeTab)
389
+ : activeTab;
390
+ if (resolvedTab.url) {
391
+ const restriction = isRestrictedUrl(resolvedTab.url);
325
392
  if (restriction.restricted) {
326
393
  this.sendError(message, buildError("restricted_url", restriction.message ?? "Restricted tab.", false));
327
394
  return;
328
395
  }
329
396
  }
330
397
  try {
331
- await this.cdp.attach(activeTab.id);
398
+ await this.cdp.attach(activeTabId);
332
399
  }
333
400
  catch (error) {
334
401
  const detail = error instanceof Error ? error.message : "Debugger attach failed";
335
402
  this.sendError(message, buildError("cdp_attach_failed", detail, false));
336
403
  return;
337
404
  }
338
- await this.tabs.waitForTabComplete(activeTab.id).catch(() => undefined);
405
+ if (!startUrl) {
406
+ await this.tabs.waitForTabComplete(activeTab.id).catch(() => undefined);
407
+ }
339
408
  const leaseId = typeof message.leaseId === "string" && message.leaseId.trim().length > 0
340
409
  ? message.leaseId.trim()
341
410
  : createId();
342
- const session = this.sessions.createSession(clientId, activeTab.id, leaseId, {
343
- url: activeTab.url ?? undefined,
344
- title: activeTab.title ?? undefined
411
+ const session = this.sessions.createSession(clientId, activeTabId, leaseId, {
412
+ url: resolvedTab.url ?? undefined,
413
+ title: resolvedTab.title ?? undefined
414
+ }, {
415
+ parallelismPolicy
345
416
  });
346
417
  await this.enableSessionDomains(session);
347
418
  this.sendEvent({
@@ -354,8 +425,8 @@ export class OpsRuntime {
354
425
  this.sendResponse(message, {
355
426
  opsSessionId: session.id,
356
427
  activeTargetId: session.activeTargetId,
357
- url: activeTab.url ?? undefined,
358
- title: activeTab.title ?? undefined,
428
+ url: resolvedTab.url ?? undefined,
429
+ title: resolvedTab.title ?? undefined,
359
430
  leaseId: session.leaseId
360
431
  });
361
432
  }
@@ -385,11 +456,12 @@ export class OpsRuntime {
385
456
  const includeUrls = payload.includeUrls === true;
386
457
  const targets = await Promise.all(Array.from(session.targets.values()).map(async (target) => {
387
458
  const tab = await this.tabs.getTab(target.tabId);
459
+ const synthetic = session.syntheticTargets.get(target.targetId);
388
460
  return {
389
461
  targetId: target.targetId,
390
462
  type: "page",
391
- title: tab?.title ?? target.title,
392
- url: includeUrls ? tab?.url ?? target.url : undefined
463
+ title: resolveReportedTargetTitle(target, tab?.title, synthetic),
464
+ url: includeUrls ? resolveReportedTargetUrl(target, tab?.url, synthetic) : undefined
393
465
  };
394
466
  }));
395
467
  this.sendResponse(message, { activeTargetId: session.activeTargetId || null, targets });
@@ -407,10 +479,66 @@ export class OpsRuntime {
407
479
  await this.tabs.activateTab(target.tabId).catch(() => undefined);
408
480
  }
409
481
  const tab = target ? await this.tabs.getTab(target.tabId) : null;
482
+ const synthetic = target ? session.syntheticTargets.get(target.targetId) : undefined;
410
483
  this.sendResponse(message, {
411
484
  activeTargetId: targetId,
412
- url: tab?.url ?? target?.url,
413
- title: tab?.title ?? target?.title
485
+ url: target ? resolveReportedTargetUrl(target, tab?.url, synthetic) : undefined,
486
+ title: target ? resolveReportedTargetTitle(target, tab?.title, synthetic) : undefined
487
+ });
488
+ }
489
+ async handleTargetsRegisterCanvas(message, session) {
490
+ const payload = isRecord(message.payload) ? message.payload : {};
491
+ const targetId = typeof payload.targetId === "string" ? payload.targetId.trim() : "";
492
+ if (!targetId) {
493
+ this.sendError(message, buildError("invalid_request", "Missing targetId", false));
494
+ return;
495
+ }
496
+ const tabId = parseTabTargetId(targetId);
497
+ if (tabId === null) {
498
+ this.sendError(message, buildError("invalid_request", "Canvas targetId must be tab-<id>.", false));
499
+ return;
500
+ }
501
+ let tab = await this.tabs.getTab(tabId);
502
+ if (!tab) {
503
+ this.sendError(message, buildError("invalid_request", "Unknown targetId", false));
504
+ return;
505
+ }
506
+ await this.tabs.waitForTabComplete(tabId, 5000).catch(() => undefined);
507
+ tab = await this.tabs.getTab(tabId) ?? tab;
508
+ if (!this.isAllowedCanvasTargetUrl(tab.url)) {
509
+ this.sendError(message, buildError("restricted_url", "Only the extension canvas tab can be registered.", false));
510
+ return;
511
+ }
512
+ const existing = session.targets.get(targetId);
513
+ if (existing) {
514
+ existing.url = tab.url ?? existing.url;
515
+ existing.title = tab.title ?? existing.title;
516
+ session.activeTargetId = targetId;
517
+ this.sendResponse(message, {
518
+ targetId,
519
+ url: existing.url,
520
+ title: existing.title,
521
+ adopted: false
522
+ });
523
+ return;
524
+ }
525
+ try {
526
+ await this.cdp.attach(tabId);
527
+ await this.enableTargetDomains(tabId);
528
+ }
529
+ catch (error) {
530
+ logError("ops.register_canvas_target", error, {
531
+ code: "canvas_target_attach_failed",
532
+ extra: { tabId, targetId }
533
+ });
534
+ }
535
+ const target = this.sessions.addTarget(session.id, tabId, { url: tab.url ?? undefined, title: tab.title ?? undefined });
536
+ session.activeTargetId = target.targetId;
537
+ this.sendResponse(message, {
538
+ targetId: target.targetId,
539
+ url: target.url,
540
+ title: target.title,
541
+ adopted: true
414
542
  });
415
543
  }
416
544
  async handleTargetsNew(message, session) {
@@ -492,11 +620,12 @@ export class OpsRuntime {
492
620
  const pages = await Promise.all(this.sessions.listNamedTargets(session.id).map(async ({ name, targetId }) => {
493
621
  const target = session.targets.get(targetId);
494
622
  const tab = target ? await this.tabs.getTab(target.tabId) : null;
623
+ const synthetic = session.syntheticTargets.get(targetId);
495
624
  return {
496
625
  name,
497
626
  targetId,
498
- url: tab?.url ?? target?.url,
499
- title: tab?.title ?? target?.title
627
+ url: resolveReportedTargetUrl(target, tab?.url, synthetic),
628
+ title: resolveReportedTargetTitle(target, tab?.title, synthetic)
500
629
  };
501
630
  }));
502
631
  this.sendResponse(message, { pages });
@@ -549,6 +678,24 @@ export class OpsRuntime {
549
678
  if (!target)
550
679
  return;
551
680
  await this.tabs.activateTab(target.tabId).catch(() => undefined);
681
+ const targetRecord = session.targets.get(target.targetId);
682
+ const syntheticHtml = decodeHtmlDataUrl(url);
683
+ if (syntheticHtml !== null) {
684
+ const result = await executeInTab(target.tabId, replaceDocumentWithHtmlScript, [{ html: syntheticHtml }]);
685
+ session.refStore.clearTarget(target.targetId);
686
+ session.syntheticTargets.set(target.targetId, {
687
+ url,
688
+ title: typeof result?.title === "string" && result.title.trim().length > 0
689
+ ? result.title
690
+ : targetRecord?.title
691
+ });
692
+ this.sendResponse(message, {
693
+ finalUrl: url,
694
+ status: undefined,
695
+ timingMs: Date.now() - start
696
+ });
697
+ return;
698
+ }
552
699
  const updated = await new Promise((resolve) => {
553
700
  chrome.tabs.update(target.tabId, { url }, (tab) => {
554
701
  resolve(tab ?? null);
@@ -556,10 +703,13 @@ export class OpsRuntime {
556
703
  });
557
704
  await this.tabs.waitForTabComplete(target.tabId, timeoutMs).catch(() => undefined);
558
705
  const refreshed = await this.tabs.getTab(target.tabId);
559
- const targetRecord = session.targets.get(target.targetId);
706
+ session.syntheticTargets.delete(target.targetId);
560
707
  if (targetRecord) {
561
- targetRecord.url = refreshed?.url ?? updated?.url ?? url;
562
- targetRecord.title = refreshed?.title ?? updated?.title ?? targetRecord.title;
708
+ session.targets.set(target.targetId, {
709
+ ...targetRecord,
710
+ url: refreshed?.url ?? updated?.url ?? url,
711
+ title: refreshed?.title ?? updated?.title ?? targetRecord.title
712
+ });
563
713
  }
564
714
  this.sendResponse(message, {
565
715
  finalUrl: refreshed?.url ?? updated?.url ?? url,
@@ -580,7 +730,7 @@ export class OpsRuntime {
580
730
  if (!selector)
581
731
  return;
582
732
  try {
583
- await this.waitForSelector(target.tabId, selector, state, timeoutMs);
733
+ await this.waitForSelector(target, selector, state, timeoutMs);
584
734
  this.sendResponse(message, { timingMs: Date.now() - start });
585
735
  }
586
736
  catch (error) {
@@ -619,10 +769,12 @@ export class OpsRuntime {
619
769
  return;
620
770
  }
621
771
  const tab = await this.tabs.getTab(target.tabId);
772
+ const targetRecord = session.targets.get(target.targetId);
773
+ const synthetic = session.syntheticTargets.get(target.targetId);
622
774
  this.sendResponse(message, {
623
775
  snapshotId: snapshot.snapshotId,
624
- url: tab?.url ?? undefined,
625
- title: tab?.title ?? undefined,
776
+ url: resolveReportedTargetUrl(targetRecord ?? null, tab?.url, synthetic),
777
+ title: resolveReportedTargetTitle(targetRecord ?? null, tab?.title, synthetic),
626
778
  content,
627
779
  truncated,
628
780
  nextCursor,
@@ -640,7 +792,7 @@ export class OpsRuntime {
640
792
  return;
641
793
  const start = Date.now();
642
794
  const before = await this.tabs.getTab(target.tabId);
643
- await this.dom.click(target.tabId, selector);
795
+ await this.runElementAction(target, selector, { type: "click" }, () => this.dom.click(target.tabId, selector));
644
796
  const after = await this.tabs.getTab(target.tabId);
645
797
  const navigated = Boolean(before?.url && after?.url && before.url !== after.url);
646
798
  this.sendResponse(message, { timingMs: Date.now() - start, navigated });
@@ -653,7 +805,7 @@ export class OpsRuntime {
653
805
  if (!target)
654
806
  return;
655
807
  const start = Date.now();
656
- await this.dom.hover(target.tabId, selector);
808
+ await this.runElementAction(target, selector, { type: "hover" }, () => this.dom.hover(target.tabId, selector));
657
809
  this.sendResponse(message, { timingMs: Date.now() - start });
658
810
  }
659
811
  async handlePress(message, session) {
@@ -670,7 +822,7 @@ export class OpsRuntime {
670
822
  if (payload.ref && !selector)
671
823
  return;
672
824
  const start = Date.now();
673
- await this.dom.press(target.tabId, selector, key);
825
+ await this.runCanvasPageAction(target, { type: "press", key }, selector, () => this.dom.press(target.tabId, selector, key));
674
826
  this.sendResponse(message, { timingMs: Date.now() - start });
675
827
  }
676
828
  async handleCheck(message, session, checked) {
@@ -681,7 +833,7 @@ export class OpsRuntime {
681
833
  if (!target)
682
834
  return;
683
835
  const start = Date.now();
684
- await this.dom.setChecked(target.tabId, selector, checked);
836
+ await this.runElementAction(target, selector, { type: "setChecked", checked }, () => this.dom.setChecked(target.tabId, selector, checked));
685
837
  this.sendResponse(message, { timingMs: Date.now() - start });
686
838
  }
687
839
  async handleType(message, session) {
@@ -699,7 +851,7 @@ export class OpsRuntime {
699
851
  if (!target)
700
852
  return;
701
853
  const start = Date.now();
702
- await this.dom.type(target.tabId, selector, text, payload.clear === true, payload.submit === true);
854
+ await this.runElementAction(target, selector, { type: "type", value: text, clear: payload.clear === true, submit: payload.submit === true }, () => this.dom.type(target.tabId, selector, text, payload.clear === true, payload.submit === true));
703
855
  this.sendResponse(message, { timingMs: Date.now() - start });
704
856
  }
705
857
  async handleSelect(message, session) {
@@ -716,7 +868,7 @@ export class OpsRuntime {
716
868
  const target = this.requireActiveTarget(session, message);
717
869
  if (!target)
718
870
  return;
719
- await this.dom.select(target.tabId, selector, values);
871
+ await this.runElementAction(target, selector, { type: "select", values: values }, () => this.dom.select(target.tabId, selector, values));
720
872
  this.sendResponse(message, {});
721
873
  }
722
874
  async handleScroll(message, session) {
@@ -729,7 +881,7 @@ export class OpsRuntime {
729
881
  const target = this.requireActiveTarget(session, message);
730
882
  if (!target)
731
883
  return;
732
- await this.dom.scroll(target.tabId, dy, selector);
884
+ await this.runCanvasPageAction(target, { type: "scroll", dy }, selector ?? null, () => this.dom.scroll(target.tabId, dy, selector));
733
885
  this.sendResponse(message, {});
734
886
  }
735
887
  async handleScrollIntoView(message, session) {
@@ -740,7 +892,7 @@ export class OpsRuntime {
740
892
  if (!target)
741
893
  return;
742
894
  const start = Date.now();
743
- await this.dom.scrollIntoView(target.tabId, selector);
895
+ await this.runElementAction(target, selector, { type: "scrollIntoView" }, () => this.dom.scrollIntoView(target.tabId, selector));
744
896
  this.sendResponse(message, { timingMs: Date.now() - start });
745
897
  }
746
898
  async handleDomGetHtml(message, session) {
@@ -757,7 +909,7 @@ export class OpsRuntime {
757
909
  const target = this.requireActiveTarget(session, message);
758
910
  if (!target)
759
911
  return;
760
- const html = await this.dom.getOuterHtml(target.tabId, selector);
912
+ const html = await this.runElementAction(target, selector, { type: "outerHTML" }, () => this.dom.getOuterHtml(target.tabId, selector));
761
913
  const truncated = html.length > maxChars;
762
914
  const outerHTML = truncated ? html.slice(0, maxChars) : html;
763
915
  this.sendResponse(message, { outerHTML, truncated });
@@ -776,7 +928,7 @@ export class OpsRuntime {
776
928
  const target = this.requireActiveTarget(session, message);
777
929
  if (!target)
778
930
  return;
779
- const text = await this.dom.getInnerText(target.tabId, selector);
931
+ const text = await this.runElementAction(target, selector, { type: "innerText" }, () => this.dom.getInnerText(target.tabId, selector));
780
932
  const truncated = text.length > maxChars;
781
933
  this.sendResponse(message, { text: truncated ? text.slice(0, maxChars) : text, truncated });
782
934
  }
@@ -794,7 +946,7 @@ export class OpsRuntime {
794
946
  const target = this.requireActiveTarget(session, message);
795
947
  if (!target)
796
948
  return;
797
- const value = await this.dom.getAttr(target.tabId, selector, name);
949
+ const value = await this.runElementAction(target, selector, { type: "getAttr", name }, () => this.dom.getAttr(target.tabId, selector, name));
798
950
  this.sendResponse(message, { value });
799
951
  }
800
952
  async handleDomGetValue(message, session) {
@@ -810,7 +962,7 @@ export class OpsRuntime {
810
962
  const target = this.requireActiveTarget(session, message);
811
963
  if (!target)
812
964
  return;
813
- const value = await this.dom.getValue(target.tabId, selector);
965
+ const value = await this.runElementAction(target, selector, { type: "getValue" }, () => this.dom.getValue(target.tabId, selector));
814
966
  this.sendResponse(message, { value });
815
967
  }
816
968
  async handleDomIsVisible(message, session) {
@@ -820,8 +972,11 @@ export class OpsRuntime {
820
972
  const target = this.requireActiveTarget(session, message);
821
973
  if (!target)
822
974
  return;
823
- const visible = await this.dom.isVisible(target.tabId, selector);
824
- this.sendResponse(message, { value: visible });
975
+ const visible = await this.runElementAction(target, selector, { type: "getSelectorState" }, async () => await this.dom.getSelectorState(target.tabId, selector));
976
+ const isVisible = typeof visible === "object" && visible !== null && "visible" in visible
977
+ ? Boolean(visible.visible)
978
+ : Boolean(visible);
979
+ this.sendResponse(message, { value: isVisible });
825
980
  }
826
981
  async handleDomIsEnabled(message, session) {
827
982
  const selector = this.resolveSelector(session, message.payload, message);
@@ -830,7 +985,7 @@ export class OpsRuntime {
830
985
  const target = this.requireActiveTarget(session, message);
831
986
  if (!target)
832
987
  return;
833
- const enabled = await this.dom.isEnabled(target.tabId, selector);
988
+ const enabled = await this.runElementAction(target, selector, { type: "isEnabled" }, () => this.dom.isEnabled(target.tabId, selector));
834
989
  this.sendResponse(message, { value: enabled });
835
990
  }
836
991
  async handleDomIsChecked(message, session) {
@@ -840,14 +995,34 @@ export class OpsRuntime {
840
995
  const target = this.requireActiveTarget(session, message);
841
996
  if (!target)
842
997
  return;
843
- const checked = await this.dom.isChecked(target.tabId, selector);
998
+ const checked = await this.runElementAction(target, selector, { type: "isChecked" }, () => this.dom.isChecked(target.tabId, selector));
844
999
  this.sendResponse(message, { value: checked });
845
1000
  }
1001
+ async handleCanvasRuntimePreviewBridge(message, session) {
1002
+ const payload = isRecord(message.payload) ? message.payload : {};
1003
+ const bindingId = typeof payload.bindingId === "string" ? payload.bindingId.trim() : "";
1004
+ const rootSelector = typeof payload.rootSelector === "string" ? payload.rootSelector.trim() : "";
1005
+ const html = typeof payload.html === "string" ? payload.html : "";
1006
+ if (!bindingId || !rootSelector) {
1007
+ this.sendError(message, buildError("invalid_request", "Missing bindingId or rootSelector", false));
1008
+ return;
1009
+ }
1010
+ const target = this.requireActiveTarget(session, message);
1011
+ if (!target)
1012
+ return;
1013
+ const result = await this.dom.applyRuntimePreviewBridge(target.tabId, bindingId, rootSelector, html);
1014
+ this.sendResponse(message, result);
1015
+ }
846
1016
  async handleClonePage(message, session) {
847
1017
  const payload = isRecord(message.payload) ? message.payload : {};
848
1018
  const target = this.requireActiveTarget(session, message);
849
1019
  if (!target)
850
1020
  return;
1021
+ const canvasCapture = await this.captureCanvasPage(target.tabId, target.targetId);
1022
+ if (canvasCapture) {
1023
+ this.sendResponse(message, { capture: canvasCapture });
1024
+ return;
1025
+ }
851
1026
  const capture = await this.dom.captureDom(target.tabId, "body", {
852
1027
  sanitize: payload.sanitize !== false,
853
1028
  maxNodes: typeof payload.maxNodes === "number" ? payload.maxNodes : undefined,
@@ -925,11 +1100,98 @@ export class OpsRuntime {
925
1100
  const nextSeq = lastEvent ? lastEvent.seq : sinceSeq;
926
1101
  this.sendResponse(message, { events, nextSeq });
927
1102
  }
1103
+ async handleStorageSetCookies(message, session) {
1104
+ const payload = isRecord(message.payload) ? message.payload : {};
1105
+ const cookies = Array.isArray(payload.cookies) ? payload.cookies : null;
1106
+ if (!cookies) {
1107
+ this.sendError(message, buildError("invalid_request", "Missing cookies", false));
1108
+ return;
1109
+ }
1110
+ const strict = payload.strict !== false;
1111
+ const requestId = typeof payload.requestId === "string" && payload.requestId.trim().length > 0
1112
+ ? payload.requestId
1113
+ : createId();
1114
+ const normalized = [];
1115
+ const rejected = [];
1116
+ cookies.forEach((entry, index) => {
1117
+ if (!isRecord(entry)) {
1118
+ rejected.push({ index, reason: "Invalid cookie entry: expected object." });
1119
+ return;
1120
+ }
1121
+ const validation = validateCookieRecord(entry);
1122
+ if (!validation.valid) {
1123
+ rejected.push({ index, reason: validation.reason });
1124
+ return;
1125
+ }
1126
+ normalized.push(validation.cookie);
1127
+ });
1128
+ if (strict && rejected.length > 0) {
1129
+ this.sendError(message, buildError("invalid_request", `Cookie import rejected ${rejected.length} entries.`, false));
1130
+ return;
1131
+ }
1132
+ if (normalized.length > 0) {
1133
+ const target = this.requireActiveTarget(session, message);
1134
+ if (!target)
1135
+ return;
1136
+ try {
1137
+ await this.cdp.sendCommand({ tabId: target.tabId }, "Network.setCookies", { cookies: normalized });
1138
+ }
1139
+ catch (error) {
1140
+ const detail = error instanceof Error ? error.message : "Cookie import failed";
1141
+ this.sendError(message, buildError("execution_failed", detail, false));
1142
+ return;
1143
+ }
1144
+ }
1145
+ this.sendResponse(message, {
1146
+ requestId,
1147
+ imported: normalized.length,
1148
+ rejected
1149
+ });
1150
+ }
1151
+ async handleStorageGetCookies(message, session) {
1152
+ const payload = isRecord(message.payload) ? message.payload : {};
1153
+ const requestId = typeof payload.requestId === "string" && payload.requestId.trim().length > 0
1154
+ ? payload.requestId
1155
+ : createId();
1156
+ let urls;
1157
+ try {
1158
+ urls = parseCookieFilterUrls(payload.urls);
1159
+ }
1160
+ catch (error) {
1161
+ const detail = error instanceof Error ? error.message : "Invalid cookie url filter.";
1162
+ this.sendError(message, buildError("invalid_request", detail, false));
1163
+ return;
1164
+ }
1165
+ const target = this.requireActiveTarget(session, message);
1166
+ if (!target)
1167
+ return;
1168
+ let rawCookies = [];
1169
+ try {
1170
+ const response = await this.cdp.sendCommand({ tabId: target.tabId }, "Network.getCookies", urls ? { urls } : {});
1171
+ rawCookies = Array.isArray(response.cookies) ? response.cookies : [];
1172
+ }
1173
+ catch (error) {
1174
+ const detail = error instanceof Error ? error.message : "Cookie list failed";
1175
+ this.sendError(message, buildError("execution_failed", detail, false));
1176
+ return;
1177
+ }
1178
+ const cookies = rawCookies
1179
+ .map((entry) => toCookieListRecord(entry))
1180
+ .filter((entry) => entry !== null);
1181
+ this.sendResponse(message, {
1182
+ requestId,
1183
+ cookies,
1184
+ count: cookies.length
1185
+ });
1186
+ }
928
1187
  async enableSessionDomains(session) {
1188
+ await this.enableTargetDomains(session.tabId);
1189
+ }
1190
+ async enableTargetDomains(tabId) {
929
1191
  try {
930
- await this.cdp.sendCommand({ tabId: session.tabId }, "Runtime.enable", {});
931
- await this.cdp.sendCommand({ tabId: session.tabId }, "Network.enable", {});
932
- await this.cdp.sendCommand({ tabId: session.tabId }, "Performance.enable", {});
1192
+ await this.cdp.sendCommand({ tabId }, "Runtime.enable", {});
1193
+ await this.cdp.sendCommand({ tabId }, "Network.enable", {});
1194
+ await this.cdp.sendCommand({ tabId }, "Performance.enable", {});
933
1195
  }
934
1196
  catch (error) {
935
1197
  logError("ops.enable_domains", error, { code: "enable_domains_failed" });
@@ -939,8 +1201,175 @@ export class OpsRuntime {
939
1201
  const session = this.getSessionForMessage(message, clientId);
940
1202
  if (!session)
941
1203
  return;
942
- session.queue = session.queue.then(() => handler(session), () => handler(session));
943
- await session.queue;
1204
+ if (!TARGET_SCOPED_COMMANDS.has(message.command)) {
1205
+ session.queue = session.queue.then(() => handler(session), () => handler(session));
1206
+ await session.queue;
1207
+ return;
1208
+ }
1209
+ try {
1210
+ await this.withTargetQueue(message, session, handler);
1211
+ }
1212
+ catch (error) {
1213
+ if (isParallelismBackpressureError(error)) {
1214
+ this.sendError(message, buildError("parallelism_backpressure", error.message, true, error.details));
1215
+ return;
1216
+ }
1217
+ throw error;
1218
+ }
1219
+ }
1220
+ resolveTargetIdForQueue(session, message) {
1221
+ const payload = isRecord(message.payload) ? message.payload : {};
1222
+ const requested = typeof payload.targetId === "string" ? payload.targetId.trim() : "";
1223
+ return requested || session.activeTargetId || session.targetId;
1224
+ }
1225
+ sessionQueueAgeMs(session) {
1226
+ let oldest = null;
1227
+ for (const value of session.targetQueueOldestAt.values()) {
1228
+ if (oldest === null || value < oldest) {
1229
+ oldest = value;
1230
+ }
1231
+ }
1232
+ return oldest === null ? 0 : Math.max(0, Date.now() - oldest);
1233
+ }
1234
+ sampleParallelism(session) {
1235
+ const now = Date.now();
1236
+ const policy = session.parallelismPolicy;
1237
+ if (session.parallelismState.lastSampleAt > 0
1238
+ && now - session.parallelismState.lastSampleAt < policy.sampleIntervalMs) {
1239
+ return {
1240
+ state: session.parallelismState,
1241
+ pressure: session.parallelismState.lastPressure,
1242
+ targetCap: session.parallelismState.effectiveCap,
1243
+ waitQueueDepth: session.pendingParallel,
1244
+ waitQueueAgeMs: this.sessionQueueAgeMs(session)
1245
+ };
1246
+ }
1247
+ const snapshot = evaluateOpsGovernor(policy, session.parallelismState, {
1248
+ hostFreeMemPct: 100,
1249
+ rssUsagePct: 0,
1250
+ queueAgeMs: this.sessionQueueAgeMs(session),
1251
+ queueDepth: session.pendingParallel,
1252
+ discardedSignals: session.discardedSignals,
1253
+ frozenSignals: session.frozenSignals
1254
+ }, now);
1255
+ session.parallelismState = snapshot.state;
1256
+ session.discardedSignals = 0;
1257
+ session.frozenSignals = 0;
1258
+ return snapshot;
1259
+ }
1260
+ wakeParallelWaiters(session) {
1261
+ const waiters = this.parallelWaiters.get(session.id);
1262
+ if (!waiters || waiters.length === 0) {
1263
+ return;
1264
+ }
1265
+ this.sampleParallelism(session);
1266
+ while (waiters.length > 0 && session.parallelInFlight < session.parallelismState.effectiveCap) {
1267
+ const waiter = waiters.shift();
1268
+ if (!waiter)
1269
+ break;
1270
+ if (waiter.timer !== null) {
1271
+ clearTimeout(waiter.timer);
1272
+ waiter.timer = null;
1273
+ }
1274
+ session.parallelInFlight += 1;
1275
+ waiter.resolve();
1276
+ }
1277
+ if (waiters.length === 0) {
1278
+ this.parallelWaiters.delete(session.id);
1279
+ }
1280
+ }
1281
+ createParallelismBackpressureError(session, targetId, timeoutMs) {
1282
+ const snapshot = this.sampleParallelism(session);
1283
+ const details = {
1284
+ sessionId: session.id,
1285
+ targetId,
1286
+ effectiveParallelCap: session.parallelismState.effectiveCap,
1287
+ inFlight: session.parallelInFlight,
1288
+ waitQueueDepth: snapshot.waitQueueDepth,
1289
+ waitQueueAgeMs: snapshot.waitQueueAgeMs,
1290
+ pressure: snapshot.pressure,
1291
+ timeoutMs
1292
+ };
1293
+ const error = new Error(`Parallelism cap reached for target ${targetId}; retry later.`);
1294
+ error.code = "parallelism_backpressure";
1295
+ error.details = details;
1296
+ return error;
1297
+ }
1298
+ async acquireParallelSlot(session, targetId, timeoutMs) {
1299
+ const waiters = this.parallelWaiters.get(session.id) ?? [];
1300
+ this.parallelWaiters.set(session.id, waiters);
1301
+ this.sampleParallelism(session);
1302
+ if (session.parallelInFlight < session.parallelismState.effectiveCap && waiters.length === 0) {
1303
+ session.parallelInFlight += 1;
1304
+ return;
1305
+ }
1306
+ await new Promise((resolve, reject) => {
1307
+ const waiter = {
1308
+ targetId,
1309
+ enqueuedAt: Date.now(),
1310
+ timeoutMs,
1311
+ resolve,
1312
+ reject,
1313
+ timer: null
1314
+ };
1315
+ waiter.timer = setTimeout(() => {
1316
+ const index = waiters.indexOf(waiter);
1317
+ if (index >= 0) {
1318
+ waiters.splice(index, 1);
1319
+ }
1320
+ if (waiters.length === 0) {
1321
+ this.parallelWaiters.delete(session.id);
1322
+ }
1323
+ reject(this.createParallelismBackpressureError(session, targetId, timeoutMs));
1324
+ }, timeoutMs);
1325
+ waiters.push(waiter);
1326
+ this.wakeParallelWaiters(session);
1327
+ });
1328
+ }
1329
+ releaseParallelSlot(session) {
1330
+ session.parallelInFlight = Math.max(0, session.parallelInFlight - 1);
1331
+ this.wakeParallelWaiters(session);
1332
+ }
1333
+ async withTargetQueue(message, session, handler) {
1334
+ const targetId = this.resolveTargetIdForQueue(session, message);
1335
+ const enqueuedAt = Date.now();
1336
+ const previous = session.targetQueues.get(targetId) ?? Promise.resolve();
1337
+ let releaseQueue = () => { };
1338
+ const gate = new Promise((resolve) => {
1339
+ releaseQueue = resolve;
1340
+ });
1341
+ const tail = previous.then(() => gate, () => gate);
1342
+ session.targetQueues.set(targetId, tail);
1343
+ session.pendingParallel += 1;
1344
+ session.targetQueueDepth.set(targetId, (session.targetQueueDepth.get(targetId) ?? 0) + 1);
1345
+ if (!session.targetQueueOldestAt.has(targetId)) {
1346
+ session.targetQueueOldestAt.set(targetId, enqueuedAt);
1347
+ }
1348
+ await previous;
1349
+ let acquired = false;
1350
+ try {
1351
+ await this.acquireParallelSlot(session, targetId, session.parallelismPolicy.backpressureTimeoutMs);
1352
+ acquired = true;
1353
+ await handler(session);
1354
+ }
1355
+ finally {
1356
+ if (acquired) {
1357
+ this.releaseParallelSlot(session);
1358
+ }
1359
+ releaseQueue();
1360
+ const depth = (session.targetQueueDepth.get(targetId) ?? 1) - 1;
1361
+ if (depth <= 0) {
1362
+ session.targetQueueDepth.delete(targetId);
1363
+ session.targetQueueOldestAt.delete(targetId);
1364
+ }
1365
+ else {
1366
+ session.targetQueueDepth.set(targetId, depth);
1367
+ }
1368
+ session.pendingParallel = Math.max(0, session.pendingParallel - 1);
1369
+ if (session.targetQueues.get(targetId) === tail) {
1370
+ session.targetQueues.delete(targetId);
1371
+ }
1372
+ }
944
1373
  }
945
1374
  getSessionForMessage(message, clientId) {
946
1375
  const opsSessionId = message.opsSessionId;
@@ -974,8 +1403,15 @@ export class OpsRuntime {
974
1403
  session.lastUsedAt = Date.now();
975
1404
  return session;
976
1405
  }
1406
+ requestedTargetId(session, message) {
1407
+ const payload = isRecord(message.payload) ? message.payload : {};
1408
+ if (typeof payload.targetId === "string" && payload.targetId.trim().length > 0) {
1409
+ return payload.targetId.trim();
1410
+ }
1411
+ return session.activeTargetId || null;
1412
+ }
977
1413
  requireActiveTarget(session, message) {
978
- const targetId = session.activeTargetId;
1414
+ const targetId = this.requestedTargetId(session, message);
979
1415
  if (!targetId) {
980
1416
  this.sendError(message, buildError("invalid_request", "No active target", false));
981
1417
  return null;
@@ -987,12 +1423,99 @@ export class OpsRuntime {
987
1423
  }
988
1424
  if (target.url) {
989
1425
  const restriction = isRestrictedUrl(target.url);
990
- if (restriction.restricted) {
1426
+ if (restriction.restricted && !this.isAllowedCanvasTargetUrl(target.url)) {
991
1427
  this.sendError(message, buildError("restricted_url", restriction.message ?? "Restricted tab.", false));
992
1428
  return null;
993
1429
  }
994
1430
  }
995
- return { tabId: target.tabId, targetId: target.targetId };
1431
+ return { tabId: target.tabId, targetId: target.targetId, url: target.url };
1432
+ }
1433
+ isAllowedCanvasTargetUrl(rawUrl) {
1434
+ if (typeof rawUrl !== "string" || rawUrl.length === 0) {
1435
+ return false;
1436
+ }
1437
+ try {
1438
+ const allowedUrl = chrome.runtime.getURL("canvas.html");
1439
+ return rawUrl === allowedUrl || rawUrl.startsWith(`${allowedUrl}#`) || rawUrl.startsWith(`${allowedUrl}?`);
1440
+ }
1441
+ catch {
1442
+ return false;
1443
+ }
1444
+ }
1445
+ async captureCanvasPage(tabId, targetId) {
1446
+ if (!this.getCanvasPageState) {
1447
+ return null;
1448
+ }
1449
+ const state = this.getCanvasPageState(targetId);
1450
+ if (!state) {
1451
+ return null;
1452
+ }
1453
+ const previewHtml = typeof state.html === "string" && state.html.length > 0
1454
+ ? extractBodyHtml(state.html)
1455
+ : null;
1456
+ const shouldProbeLiveStage = Boolean(state.pendingMutation)
1457
+ || (canvasStateContainsRichMedia(state) && !htmlContainsRichMedia(previewHtml));
1458
+ if (shouldProbeLiveStage) {
1459
+ const liveStageCapture = await this.captureLiveCanvasStage(tabId);
1460
+ if (liveStageCapture) {
1461
+ return liveStageCapture;
1462
+ }
1463
+ const documentCapture = buildCanvasDocumentCapture(state);
1464
+ if (documentCapture) {
1465
+ return documentCapture;
1466
+ }
1467
+ }
1468
+ if (!previewHtml) {
1469
+ return buildCanvasDocumentCapture(state);
1470
+ }
1471
+ return {
1472
+ html: previewHtml,
1473
+ styles: {},
1474
+ warnings: ["canvas_state_capture"],
1475
+ inlineStyles: false
1476
+ };
1477
+ }
1478
+ async runElementAction(target, selector, action, fallback) {
1479
+ return await this.runCanvasPageAction(target, action, selector, fallback);
1480
+ }
1481
+ async runCanvasPageAction(target, action, selector, fallback) {
1482
+ if (!this.isAllowedCanvasTargetUrl(target.url) || !this.performCanvasPageAction) {
1483
+ return await fallback();
1484
+ }
1485
+ return await this.performCanvasPageAction(target.targetId, action, selector ?? null);
1486
+ }
1487
+ async captureLiveCanvasStage(tabId) {
1488
+ try {
1489
+ const results = await chrome.scripting.executeScript({
1490
+ target: { tabId },
1491
+ func: () => {
1492
+ const stage = document.getElementById("canvas-stage-inner");
1493
+ if (!(stage instanceof HTMLElement)) {
1494
+ return null;
1495
+ }
1496
+ const html = stage.innerHTML.trim();
1497
+ if (!html) {
1498
+ return null;
1499
+ }
1500
+ const width = stage.style.width || `${Math.max(stage.scrollWidth, 320)}px`;
1501
+ const height = stage.style.height || `${Math.max(stage.scrollHeight, 240)}px`;
1502
+ return `<body><main data-surface="canvas" style="position:relative;width:${width};min-height:${height};">${html}</main></body>`;
1503
+ }
1504
+ });
1505
+ const html = typeof results[0]?.result === "string" ? results[0].result : null;
1506
+ if (!html) {
1507
+ return null;
1508
+ }
1509
+ return {
1510
+ html,
1511
+ styles: {},
1512
+ warnings: ["canvas_state_capture"],
1513
+ inlineStyles: true
1514
+ };
1515
+ }
1516
+ catch {
1517
+ return null;
1518
+ }
996
1519
  }
997
1520
  resolveSelector(session, refOrPayload, message) {
998
1521
  const ref = typeof refOrPayload === "string"
@@ -1002,17 +1525,22 @@ export class OpsRuntime {
1002
1525
  this.sendError(message, buildError("invalid_request", "Missing ref", false));
1003
1526
  return null;
1004
1527
  }
1005
- const entry = session.refStore.resolve(session.activeTargetId, ref);
1528
+ const targetId = this.requestedTargetId(session, message);
1529
+ if (!targetId) {
1530
+ this.sendError(message, buildError("invalid_request", "No active target", false));
1531
+ return null;
1532
+ }
1533
+ const entry = session.refStore.resolve(targetId, ref);
1006
1534
  if (!entry) {
1007
1535
  this.sendError(message, buildError("invalid_request", `Unknown ref: ${ref}`, false));
1008
1536
  return null;
1009
1537
  }
1010
1538
  return entry.selector;
1011
1539
  }
1012
- async waitForSelector(tabId, selector, state, timeoutMs) {
1540
+ async waitForSelector(target, selector, state, timeoutMs) {
1013
1541
  const start = Date.now();
1014
1542
  while (Date.now() - start < timeoutMs) {
1015
- const snapshot = await this.dom.getSelectorState(tabId, selector);
1543
+ const snapshot = await this.runElementAction(target, selector, { type: "getSelectorState" }, () => this.dom.getSelectorState(target.tabId, selector));
1016
1544
  if (state === "attached" && snapshot.attached)
1017
1545
  return;
1018
1546
  if (state === "visible" && snapshot.visible)
@@ -1025,6 +1553,17 @@ export class OpsRuntime {
1025
1553
  }
1026
1554
  cleanupSession(session, event) {
1027
1555
  this.clearClosingTimer(session.id);
1556
+ const waiters = this.parallelWaiters.get(session.id);
1557
+ if (waiters) {
1558
+ for (const waiter of waiters) {
1559
+ if (waiter.timer !== null) {
1560
+ clearTimeout(waiter.timer);
1561
+ waiter.timer = null;
1562
+ }
1563
+ waiter.reject(new Error("Ops session closed while waiting for parallelism slot."));
1564
+ }
1565
+ this.parallelWaiters.delete(session.id);
1566
+ }
1028
1567
  this.sessions.delete(session.id);
1029
1568
  for (const target of session.targets.values()) {
1030
1569
  void this.cdp.detachTab(target.tabId).catch(() => undefined);
@@ -1185,12 +1724,188 @@ export class OpsRuntime {
1185
1724
  });
1186
1725
  }
1187
1726
  }
1727
+ const numberInRange = (value, fallback, min, max) => {
1728
+ if (typeof value !== "number" || !Number.isFinite(value)) {
1729
+ return fallback;
1730
+ }
1731
+ return Math.min(max, Math.max(min, value));
1732
+ };
1733
+ const parseParallelismPolicy = (value) => {
1734
+ if (!isRecord(value)) {
1735
+ return DEFAULT_OPS_PARALLELISM_POLICY;
1736
+ }
1737
+ const modeCapsInput = isRecord(value.modeCaps) ? value.modeCaps : {};
1738
+ return {
1739
+ floor: numberInRange(value.floor, DEFAULT_OPS_PARALLELISM_POLICY.floor, 1, 32),
1740
+ backpressureTimeoutMs: numberInRange(value.backpressureTimeoutMs, DEFAULT_OPS_PARALLELISM_POLICY.backpressureTimeoutMs, 100, 120000),
1741
+ sampleIntervalMs: numberInRange(value.sampleIntervalMs, DEFAULT_OPS_PARALLELISM_POLICY.sampleIntervalMs, 250, 60000),
1742
+ recoveryStableWindows: numberInRange(value.recoveryStableWindows, DEFAULT_OPS_PARALLELISM_POLICY.recoveryStableWindows, 1, 20),
1743
+ hostFreeMemMediumPct: numberInRange(value.hostFreeMemMediumPct, DEFAULT_OPS_PARALLELISM_POLICY.hostFreeMemMediumPct, 1, 99),
1744
+ hostFreeMemHighPct: numberInRange(value.hostFreeMemHighPct, DEFAULT_OPS_PARALLELISM_POLICY.hostFreeMemHighPct, 1, 99),
1745
+ hostFreeMemCriticalPct: numberInRange(value.hostFreeMemCriticalPct, DEFAULT_OPS_PARALLELISM_POLICY.hostFreeMemCriticalPct, 1, 99),
1746
+ rssBudgetMb: numberInRange(value.rssBudgetMb, DEFAULT_OPS_PARALLELISM_POLICY.rssBudgetMb, 64, 65536),
1747
+ rssSoftPct: numberInRange(value.rssSoftPct, DEFAULT_OPS_PARALLELISM_POLICY.rssSoftPct, 1, 99),
1748
+ rssHighPct: numberInRange(value.rssHighPct, DEFAULT_OPS_PARALLELISM_POLICY.rssHighPct, 1, 99),
1749
+ rssCriticalPct: numberInRange(value.rssCriticalPct, DEFAULT_OPS_PARALLELISM_POLICY.rssCriticalPct, 1, 99),
1750
+ queueAgeHighMs: numberInRange(value.queueAgeHighMs, DEFAULT_OPS_PARALLELISM_POLICY.queueAgeHighMs, 100, 120000),
1751
+ queueAgeCriticalMs: numberInRange(value.queueAgeCriticalMs, DEFAULT_OPS_PARALLELISM_POLICY.queueAgeCriticalMs, 100, 120000),
1752
+ modeCaps: {
1753
+ managedHeaded: numberInRange(modeCapsInput.managedHeaded, DEFAULT_OPS_PARALLELISM_POLICY.modeCaps.managedHeaded, 1, 64),
1754
+ managedHeadless: numberInRange(modeCapsInput.managedHeadless, DEFAULT_OPS_PARALLELISM_POLICY.modeCaps.managedHeadless, 1, 64),
1755
+ cdpConnectHeaded: numberInRange(modeCapsInput.cdpConnectHeaded, DEFAULT_OPS_PARALLELISM_POLICY.modeCaps.cdpConnectHeaded, 1, 64),
1756
+ cdpConnectHeadless: numberInRange(modeCapsInput.cdpConnectHeadless, DEFAULT_OPS_PARALLELISM_POLICY.modeCaps.cdpConnectHeadless, 1, 64),
1757
+ extensionOpsHeaded: numberInRange(modeCapsInput.extensionOpsHeaded, DEFAULT_OPS_PARALLELISM_POLICY.modeCaps.extensionOpsHeaded, 1, 64),
1758
+ extensionLegacyCdpHeaded: numberInRange(modeCapsInput.extensionLegacyCdpHeaded, DEFAULT_OPS_PARALLELISM_POLICY.modeCaps.extensionLegacyCdpHeaded, 1, 64)
1759
+ }
1760
+ };
1761
+ };
1762
+ const isParallelismBackpressureError = (error) => {
1763
+ if (!(error instanceof Error)) {
1764
+ return false;
1765
+ }
1766
+ const typed = error;
1767
+ return typed.code === "parallelism_backpressure" && typeof typed.details === "object" && typed.details !== null;
1768
+ };
1188
1769
  const buildError = (code, message, retryable, details) => ({
1189
1770
  code,
1190
1771
  message,
1191
1772
  retryable,
1192
1773
  details
1193
1774
  });
1775
+ const validateCookieRecord = (cookie) => {
1776
+ const name = cookie.name?.trim();
1777
+ if (!name) {
1778
+ return { valid: false, reason: "Cookie name is required.", cookie };
1779
+ }
1780
+ if (!/^[^\s;=]+$/.test(name)) {
1781
+ return { valid: false, reason: `Invalid cookie name: ${cookie.name}.`, cookie };
1782
+ }
1783
+ if (typeof cookie.value !== "string" || /\r|\n|;/.test(cookie.value)) {
1784
+ return { valid: false, reason: `Invalid cookie value for ${name}.`, cookie };
1785
+ }
1786
+ const hasUrl = typeof cookie.url === "string" && cookie.url.trim().length > 0;
1787
+ const hasDomain = typeof cookie.domain === "string" && cookie.domain.trim().length > 0;
1788
+ if (!hasUrl && !hasDomain) {
1789
+ return { valid: false, reason: `Cookie ${name} requires url or domain.`, cookie };
1790
+ }
1791
+ let normalizedUrl;
1792
+ if (hasUrl) {
1793
+ try {
1794
+ const parsedUrl = new URL(cookie.url);
1795
+ if (parsedUrl.protocol !== "http:" && parsedUrl.protocol !== "https:") {
1796
+ return { valid: false, reason: `Cookie ${name} url must be http(s).`, cookie };
1797
+ }
1798
+ normalizedUrl = parsedUrl.toString();
1799
+ }
1800
+ catch {
1801
+ return { valid: false, reason: `Cookie ${name} has invalid url.`, cookie };
1802
+ }
1803
+ }
1804
+ let normalizedDomain;
1805
+ if (hasDomain) {
1806
+ normalizedDomain = String(cookie.domain).trim().toLowerCase();
1807
+ if (!/^\.?[a-z0-9.-]+$/.test(normalizedDomain) || normalizedDomain.includes("..")) {
1808
+ return { valid: false, reason: `Cookie ${name} has invalid domain.`, cookie };
1809
+ }
1810
+ }
1811
+ const normalizedPath = typeof cookie.path === "string" ? cookie.path.trim() : undefined;
1812
+ if (typeof normalizedPath === "string" && !normalizedPath.startsWith("/")) {
1813
+ return { valid: false, reason: `Cookie ${name} path must start with '/'.`, cookie };
1814
+ }
1815
+ if (typeof cookie.expires !== "undefined") {
1816
+ if (!Number.isFinite(cookie.expires) || cookie.expires < -1) {
1817
+ return { valid: false, reason: `Cookie ${name} has invalid expires.`, cookie };
1818
+ }
1819
+ }
1820
+ if (cookie.sameSite === "None" && cookie.secure !== true) {
1821
+ return { valid: false, reason: `Cookie ${name} with SameSite=None must set secure=true.`, cookie };
1822
+ }
1823
+ const normalizedCookie = {
1824
+ name,
1825
+ value: cookie.value,
1826
+ ...(typeof cookie.expires === "number" ? { expires: cookie.expires } : {}),
1827
+ ...(typeof cookie.httpOnly === "boolean" ? { httpOnly: cookie.httpOnly } : {}),
1828
+ ...(typeof cookie.secure === "boolean" ? { secure: cookie.secure } : {}),
1829
+ ...(cookie.sameSite ? { sameSite: cookie.sameSite } : {})
1830
+ };
1831
+ if (normalizedDomain) {
1832
+ normalizedCookie.domain = normalizedDomain;
1833
+ normalizedCookie.path = normalizedPath ?? "/";
1834
+ }
1835
+ else if (normalizedUrl) {
1836
+ normalizedCookie.url = normalizedUrl;
1837
+ }
1838
+ return {
1839
+ valid: true,
1840
+ reason: "",
1841
+ cookie: normalizedCookie
1842
+ };
1843
+ };
1844
+ const parseCookieFilterUrls = (value) => {
1845
+ if (typeof value === "undefined") {
1846
+ return undefined;
1847
+ }
1848
+ if (!Array.isArray(value)) {
1849
+ throw new Error("Cookie url filters must be an array of strings.");
1850
+ }
1851
+ const normalized = [];
1852
+ const seen = new Set();
1853
+ for (const entry of value) {
1854
+ if (typeof entry !== "string") {
1855
+ throw new Error("Cookie url filters must be an array of strings.");
1856
+ }
1857
+ const trimmed = entry.trim();
1858
+ if (!trimmed) {
1859
+ throw new Error("Cookie url filters must be non-empty strings.");
1860
+ }
1861
+ let parsedUrl;
1862
+ try {
1863
+ parsedUrl = new URL(trimmed);
1864
+ }
1865
+ catch {
1866
+ throw new Error(`Cookie url filter is invalid: ${trimmed}`);
1867
+ }
1868
+ if (parsedUrl.protocol !== "http:" && parsedUrl.protocol !== "https:") {
1869
+ throw new Error(`Cookie url filter must be http(s): ${trimmed}`);
1870
+ }
1871
+ const normalizedUrl = parsedUrl.toString();
1872
+ if (seen.has(normalizedUrl)) {
1873
+ continue;
1874
+ }
1875
+ seen.add(normalizedUrl);
1876
+ normalized.push(normalizedUrl);
1877
+ }
1878
+ return normalized.length > 0 ? normalized : undefined;
1879
+ };
1880
+ const toCookieListRecord = (entry) => {
1881
+ if (!isRecord(entry)) {
1882
+ return null;
1883
+ }
1884
+ const name = typeof entry.name === "string" ? entry.name : "";
1885
+ const value = typeof entry.value === "string" ? entry.value : "";
1886
+ const domain = typeof entry.domain === "string" ? entry.domain : "";
1887
+ const path = typeof entry.path === "string" ? entry.path : "";
1888
+ const expires = typeof entry.expires === "number" && Number.isFinite(entry.expires) ? entry.expires : -1;
1889
+ const httpOnly = entry.httpOnly === true;
1890
+ const secure = entry.secure === true;
1891
+ if (!name || !domain || !path) {
1892
+ return null;
1893
+ }
1894
+ const sameSiteRaw = entry.sameSite;
1895
+ const sameSite = sameSiteRaw === "Strict" || sameSiteRaw === "Lax" || sameSiteRaw === "None"
1896
+ ? sameSiteRaw
1897
+ : undefined;
1898
+ return {
1899
+ name,
1900
+ value,
1901
+ domain,
1902
+ path,
1903
+ expires,
1904
+ httpOnly,
1905
+ secure,
1906
+ ...(sameSite ? { sameSite } : {})
1907
+ };
1908
+ };
1194
1909
  const isRecord = (value) => {
1195
1910
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
1196
1911
  };
@@ -1227,6 +1942,257 @@ const paginate = (lines, startIndex, maxChars) => {
1227
1942
  };
1228
1943
  };
1229
1944
  const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
1945
+ const parseTabTargetId = (targetId) => {
1946
+ const raw = targetId.startsWith("tab-") ? targetId.slice(4) : targetId;
1947
+ const parsed = Number.parseInt(raw, 10);
1948
+ if (!Number.isFinite(parsed) || parsed <= 0) {
1949
+ return null;
1950
+ }
1951
+ return parsed;
1952
+ };
1953
+ const extractBodyHtml = (html) => {
1954
+ const bodyMatch = html.match(/<body\b[^>]*>[\s\S]*<\/body>/i);
1955
+ if (bodyMatch) {
1956
+ return bodyMatch[0];
1957
+ }
1958
+ return html;
1959
+ };
1960
+ const htmlContainsRichMedia = (html) => {
1961
+ return typeof html === "string" && /<(img|video|audio)\b/i.test(html);
1962
+ };
1963
+ const canvasStateContainsRichMedia = (state) => {
1964
+ const document = isRecord(state.document) ? state.document : null;
1965
+ const pages = Array.isArray(document?.pages) ? document.pages : [];
1966
+ const assets = Array.isArray(document?.assets) ? document.assets : [];
1967
+ const assetsById = new Map(assets.flatMap((asset) => typeof asset?.id === "string" ? [[asset.id, asset]] : []));
1968
+ return pages.some((page) => Array.isArray(page?.nodes) && page.nodes.some((node) => nodeContainsRichMedia(node, assetsById)));
1969
+ };
1970
+ const nodeContainsRichMedia = (node, assetsById) => {
1971
+ const tagName = readCanvasMediaTagName(node);
1972
+ if (tagName === "img" || tagName === "video" || tagName === "audio") {
1973
+ return true;
1974
+ }
1975
+ const assetIds = Array.isArray(node.metadata.assetIds)
1976
+ ? node.metadata.assetIds.filter((entry) => typeof entry === "string" && entry.trim().length > 0)
1977
+ : [];
1978
+ return assetIds.some((assetId) => {
1979
+ const asset = assetsById.get(assetId);
1980
+ const kind = typeof asset?.kind === "string" ? asset.kind.toLowerCase() : "";
1981
+ const mime = typeof asset?.mime === "string" ? asset.mime.toLowerCase() : "";
1982
+ return kind === "image" || kind === "video" || kind === "audio" || mime.startsWith("image/") || mime.startsWith("video/") || mime.startsWith("audio/");
1983
+ });
1984
+ };
1985
+ const readCanvasMediaTagName = (node) => {
1986
+ if (typeof node.props.tagName === "string" && node.props.tagName.trim().length > 0) {
1987
+ return node.props.tagName.trim().toLowerCase();
1988
+ }
1989
+ const codeSync = isRecord(node.metadata.codeSync) ? node.metadata.codeSync : null;
1990
+ if (codeSync && typeof codeSync.tagName === "string" && codeSync.tagName.trim().length > 0) {
1991
+ return codeSync.tagName.trim().toLowerCase();
1992
+ }
1993
+ return null;
1994
+ };
1995
+ const buildCanvasDocumentCapture = (state) => {
1996
+ const page = Array.isArray(state.document.pages) ? state.document.pages[0] : null;
1997
+ if (!page || !Array.isArray(page.nodes) || page.nodes.length === 0) {
1998
+ return null;
1999
+ }
2000
+ const { width, height } = computeCanvasDocumentBounds(page.nodes);
2001
+ const nodes = [...page.nodes]
2002
+ .sort(compareCanvasCaptureNodes)
2003
+ .map((node) => renderCanvasDocumentNode(state.document, node))
2004
+ .join("");
2005
+ return {
2006
+ html: `<body><main data-surface="canvas" style="position:relative;width:${width}px;min-height:${height}px;">${nodes}</main></body>`,
2007
+ styles: {},
2008
+ warnings: ["canvas_state_capture"],
2009
+ inlineStyles: true
2010
+ };
2011
+ };
2012
+ const computeCanvasDocumentBounds = (nodes) => {
2013
+ if (nodes.length === 0) {
2014
+ return { width: 1600, height: 1200 };
2015
+ }
2016
+ const maxX = Math.max(...nodes.map((node) => node.rect.x + node.rect.width));
2017
+ const maxY = Math.max(...nodes.map((node) => node.rect.y + node.rect.height));
2018
+ return {
2019
+ width: Math.max(maxX + 240, 1600),
2020
+ height: Math.max(maxY + 240, 1200)
2021
+ };
2022
+ };
2023
+ const compareCanvasCaptureNodes = (left, right) => {
2024
+ const rootOrder = Number(left.parentId !== null) - Number(right.parentId !== null);
2025
+ if (rootOrder !== 0) {
2026
+ return rootOrder;
2027
+ }
2028
+ const areaOrder = (right.rect.width * right.rect.height) - (left.rect.width * left.rect.height);
2029
+ if (areaOrder !== 0) {
2030
+ return areaOrder;
2031
+ }
2032
+ const verticalOrder = left.rect.y - right.rect.y;
2033
+ return verticalOrder !== 0 ? verticalOrder : left.rect.x - right.rect.x;
2034
+ };
2035
+ const renderCanvasDocumentNode = (document, node) => {
2036
+ const media = resolveCanvasDocumentMedia(document, node);
2037
+ const text = escapeCanvasHtml(nodeTextForCapture(node) || node.name);
2038
+ const style = serializeCanvasCaptureStyle({
2039
+ position: "absolute",
2040
+ left: `${node.rect.x}px`,
2041
+ top: `${node.rect.y}px`,
2042
+ width: `${Math.max(node.rect.width, 40)}px`,
2043
+ minHeight: `${Math.max(node.rect.height, readCanvasMediaTagName(node) === "audio" ? 64 : 40)}px`,
2044
+ overflow: "hidden",
2045
+ ...node.style
2046
+ });
2047
+ const title = escapeCanvasAttribute(`${node.kind} • ${node.name}`);
2048
+ if (media?.kind === "image" && media.src) {
2049
+ return `<div data-node-id="${escapeCanvasAttribute(node.id)}" title="${title}" style="${style}"><img src="${escapeCanvasAttribute(media.src)}" alt="${escapeCanvasAttribute(media.alt ?? node.name)}" loading="lazy" draggable="false" style="width:100%;height:100%;object-fit:cover;display:block;" /></div>`;
2050
+ }
2051
+ if (media?.kind === "video" && media.src) {
2052
+ const poster = media.poster ? ` poster="${escapeCanvasAttribute(media.poster)}"` : "";
2053
+ return `<div data-node-id="${escapeCanvasAttribute(node.id)}" title="${title}" style="${style}"><video src="${escapeCanvasAttribute(media.src)}"${poster} muted loop autoplay playsinline preload="metadata" style="width:100%;height:100%;object-fit:cover;display:block;"></video></div>`;
2054
+ }
2055
+ if (media?.kind === "audio" && media.src) {
2056
+ return `<div data-node-id="${escapeCanvasAttribute(node.id)}" title="${title}" style="${style}"><audio src="${escapeCanvasAttribute(media.src)}" controls preload="metadata" style="width:100%;display:block;"></audio>${text ? `<div style="margin-top:8px;font:500 12px/1.4 sans-serif;">${text}</div>` : ""}</div>`;
2057
+ }
2058
+ return `<div data-node-id="${escapeCanvasAttribute(node.id)}" title="${title}" style="${style}">${text}</div>`;
2059
+ };
2060
+ const nodeTextForCapture = (node) => {
2061
+ const raw = node.props.text ?? node.metadata.text;
2062
+ if (raw !== undefined && raw !== null) {
2063
+ return typeof raw === "string" ? raw : String(raw);
2064
+ }
2065
+ return node.kind === "text" || node.kind === "note" || node.kind === "component-instance"
2066
+ ? node.name
2067
+ : "";
2068
+ };
2069
+ const resolveCanvasDocumentMedia = (document, node) => {
2070
+ const tagName = readCanvasMediaTagName(node);
2071
+ const attributes = isRecord(node.props.attributes) ? node.props.attributes : {};
2072
+ const assetIds = Array.isArray(node.metadata.assetIds)
2073
+ ? node.metadata.assetIds.filter((entry) => typeof entry === "string" && entry.trim().length > 0)
2074
+ : [];
2075
+ const asset = assetIds.length > 0
2076
+ ? document.assets.find((entry) => entry.id === assetIds[0])
2077
+ : null;
2078
+ const assetKind = typeof asset?.kind === "string" ? asset.kind.toLowerCase() : null;
2079
+ const assetMime = typeof asset?.mime === "string" ? asset.mime.toLowerCase() : null;
2080
+ const src = typeof node.props.src === "string"
2081
+ ? node.props.src
2082
+ : typeof attributes.src === "string"
2083
+ ? attributes.src
2084
+ : typeof asset?.url === "string"
2085
+ ? asset.url
2086
+ : typeof asset?.repoPath === "string"
2087
+ ? asset.repoPath
2088
+ : null;
2089
+ const poster = typeof node.props.poster === "string"
2090
+ ? node.props.poster
2091
+ : typeof attributes.poster === "string"
2092
+ ? attributes.poster
2093
+ : null;
2094
+ const alt = typeof node.props.alt === "string"
2095
+ ? node.props.alt
2096
+ : typeof attributes.alt === "string"
2097
+ ? attributes.alt
2098
+ : node.name;
2099
+ if (tagName === "img" || assetKind === "image" || assetMime?.startsWith("image/")) {
2100
+ return { kind: "image", src, poster: null, alt };
2101
+ }
2102
+ if (tagName === "video" || assetKind === "video" || assetMime?.startsWith("video/")) {
2103
+ return { kind: "video", src, poster, alt };
2104
+ }
2105
+ if (tagName === "audio" || assetKind === "audio" || assetMime?.startsWith("audio/")) {
2106
+ return { kind: "audio", src, poster: null, alt };
2107
+ }
2108
+ return null;
2109
+ };
2110
+ const serializeCanvasCaptureStyle = (style) => {
2111
+ return Object.entries(style)
2112
+ .flatMap(([key, value]) => {
2113
+ if (typeof value !== "string" && typeof value !== "number") {
2114
+ return [];
2115
+ }
2116
+ const cssKey = key.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`);
2117
+ const cssValue = typeof value === "number" && !CANVAS_CAPTURE_UNITLESS_STYLES.has(key) ? `${value}px` : String(value);
2118
+ return `${cssKey}:${escapeCanvasAttribute(cssValue)};`;
2119
+ })
2120
+ .join("");
2121
+ };
2122
+ const escapeCanvasHtml = (value) => {
2123
+ return value
2124
+ .replaceAll("&", "&amp;")
2125
+ .replaceAll("<", "&lt;")
2126
+ .replaceAll(">", "&gt;");
2127
+ };
2128
+ const escapeCanvasAttribute = (value) => {
2129
+ return escapeCanvasHtml(value)
2130
+ .replaceAll("\"", "&quot;")
2131
+ .replaceAll("'", "&#39;");
2132
+ };
2133
+ const CANVAS_CAPTURE_UNITLESS_STYLES = new Set(["fontWeight", "lineHeight", "opacity", "zIndex"]);
2134
+ const resolveReportedTargetUrl = (target, liveUrl, synthetic) => {
2135
+ if (typeof synthetic?.url === "string" && isHtmlDataUrl(synthetic.url)) {
2136
+ return synthetic.url;
2137
+ }
2138
+ if (typeof target?.url === "string" && isHtmlDataUrl(target.url)) {
2139
+ return target.url;
2140
+ }
2141
+ return liveUrl ?? target?.url;
2142
+ };
2143
+ const resolveReportedTargetTitle = (target, liveTitle, synthetic) => {
2144
+ if (typeof synthetic?.title === "string" && synthetic.title.length > 0) {
2145
+ return synthetic.title;
2146
+ }
2147
+ if (typeof target?.url === "string" && isHtmlDataUrl(target.url) && typeof target.title === "string" && target.title.length > 0) {
2148
+ return target.title;
2149
+ }
2150
+ return liveTitle ?? target?.title;
2151
+ };
2152
+ const isHtmlDataUrl = (url) => {
2153
+ return url.startsWith("data:text/html");
2154
+ };
2155
+ const decodeHtmlDataUrl = (url) => {
2156
+ if (!isHtmlDataUrl(url)) {
2157
+ return null;
2158
+ }
2159
+ const commaIndex = url.indexOf(",");
2160
+ if (commaIndex === -1) {
2161
+ return null;
2162
+ }
2163
+ const metadata = url.slice(0, commaIndex).toLowerCase();
2164
+ const payload = url.slice(commaIndex + 1);
2165
+ if (metadata.includes(";base64")) {
2166
+ const decoded = atob(payload);
2167
+ const bytes = Uint8Array.from(decoded, (char) => char.charCodeAt(0));
2168
+ return new TextDecoder().decode(bytes);
2169
+ }
2170
+ try {
2171
+ return decodeURIComponent(payload);
2172
+ }
2173
+ catch {
2174
+ return payload;
2175
+ }
2176
+ };
2177
+ const executeInTab = async (tabId, func, args) => {
2178
+ return await new Promise((resolve, reject) => {
2179
+ chrome.scripting.executeScript({ target: { tabId }, func: func, args }, (results) => {
2180
+ const lastError = chrome.runtime.lastError;
2181
+ if (lastError) {
2182
+ reject(new Error(lastError.message));
2183
+ return;
2184
+ }
2185
+ const [first] = results ?? [];
2186
+ resolve((first?.result ?? null));
2187
+ });
2188
+ });
2189
+ };
2190
+ function replaceDocumentWithHtmlScript(input) {
2191
+ document.open();
2192
+ document.write(input.html);
2193
+ document.close();
2194
+ return { title: document.title };
2195
+ }
1230
2196
  const withTimeout = async (promise, timeoutMs, message) => {
1231
2197
  return await new Promise((resolve, reject) => {
1232
2198
  const timeoutId = setTimeout(() => {