browxai 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (520) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +139 -0
  3. package/THIRD_PARTY_NOTICES.md +45 -0
  4. package/dist/cli/chrome.d.ts +1 -0
  5. package/dist/cli/chrome.js +130 -0
  6. package/dist/cli/command-registry.d.ts +15 -0
  7. package/dist/cli/command-registry.js +35 -0
  8. package/dist/cli/doctor-plugins.d.ts +18 -0
  9. package/dist/cli/doctor-plugins.js +338 -0
  10. package/dist/cli/doctor.d.ts +9 -0
  11. package/dist/cli/doctor.js +407 -0
  12. package/dist/cli/init.d.ts +1 -0
  13. package/dist/cli/init.js +200 -0
  14. package/dist/cli/register-commands.d.ts +1 -0
  15. package/dist/cli/register-commands.js +22 -0
  16. package/dist/cli/serve.d.ts +14 -0
  17. package/dist/cli/serve.js +151 -0
  18. package/dist/cli.d.ts +3 -0
  19. package/dist/cli.js +129 -0
  20. package/dist/engine/adapters/adb.d.ts +72 -0
  21. package/dist/engine/adapters/adb.js +200 -0
  22. package/dist/engine/adapters/android-cdp.d.ts +54 -0
  23. package/dist/engine/adapters/android-cdp.js +110 -0
  24. package/dist/engine/adapters/android.engine.d.ts +1 -0
  25. package/dist/engine/adapters/android.engine.js +31 -0
  26. package/dist/engine/adapters/chromium.engine.d.ts +1 -0
  27. package/dist/engine/adapters/chromium.engine.js +44 -0
  28. package/dist/engine/adapters/firefox.engine.d.ts +1 -0
  29. package/dist/engine/adapters/firefox.engine.js +43 -0
  30. package/dist/engine/adapters/playwright-chromium.d.ts +43 -0
  31. package/dist/engine/adapters/playwright-chromium.js +56 -0
  32. package/dist/engine/adapters/playwright-firefox.d.ts +52 -0
  33. package/dist/engine/adapters/playwright-firefox.js +97 -0
  34. package/dist/engine/adapters/playwright-webkit.d.ts +40 -0
  35. package/dist/engine/adapters/playwright-webkit.js +79 -0
  36. package/dist/engine/adapters/safari/bidi-client.d.ts +46 -0
  37. package/dist/engine/adapters/safari/bidi-client.js +130 -0
  38. package/dist/engine/adapters/safari/launch.d.ts +56 -0
  39. package/dist/engine/adapters/safari/launch.js +104 -0
  40. package/dist/engine/adapters/safari/webdriver-client.d.ts +102 -0
  41. package/dist/engine/adapters/safari/webdriver-client.js +175 -0
  42. package/dist/engine/adapters/safari.engine.d.ts +1 -0
  43. package/dist/engine/adapters/safari.engine.js +52 -0
  44. package/dist/engine/adapters/safaridriver-hybrid.d.ts +56 -0
  45. package/dist/engine/adapters/safaridriver-hybrid.js +127 -0
  46. package/dist/engine/adapters/webkit.engine.d.ts +1 -0
  47. package/dist/engine/adapters/webkit.engine.js +47 -0
  48. package/dist/engine/capabilities.d.ts +53 -0
  49. package/dist/engine/capabilities.js +122 -0
  50. package/dist/engine/capability-registry.d.ts +9 -0
  51. package/dist/engine/capability-registry.js +20 -0
  52. package/dist/engine/index.d.ts +18 -0
  53. package/dist/engine/index.js +14 -0
  54. package/dist/engine/register-engines.d.ts +5 -0
  55. package/dist/engine/register-engines.js +16 -0
  56. package/dist/engine/registry.d.ts +145 -0
  57. package/dist/engine/registry.js +67 -0
  58. package/dist/engine/select.d.ts +48 -0
  59. package/dist/engine/select.js +128 -0
  60. package/dist/engine/session-cdp.d.ts +13 -0
  61. package/dist/engine/session-cdp.js +22 -0
  62. package/dist/engine/tool-gate.d.ts +19 -0
  63. package/dist/engine/tool-gate.js +226 -0
  64. package/dist/engine/types.d.ts +71 -0
  65. package/dist/engine/types.js +16 -0
  66. package/dist/helper/bridge.d.ts +48 -0
  67. package/dist/helper/bridge.js +200 -0
  68. package/dist/helper/browx-page.d.ts +1 -0
  69. package/dist/helper/browx-page.js +47 -0
  70. package/dist/helper/overlay-hide.d.ts +9 -0
  71. package/dist/helper/overlay-hide.js +49 -0
  72. package/dist/helper/stealth.d.ts +10 -0
  73. package/dist/helper/stealth.js +88 -0
  74. package/dist/index.d.ts +7 -0
  75. package/dist/index.js +15 -0
  76. package/dist/page/a11y.d.ts +81 -0
  77. package/dist/page/a11y.js +219 -0
  78. package/dist/page/action-substrate.d.ts +64 -0
  79. package/dist/page/action-substrate.js +118 -0
  80. package/dist/page/actionresult-blocks.d.ts +99 -0
  81. package/dist/page/actionresult-blocks.js +144 -0
  82. package/dist/page/actionresult-shape.d.ts +48 -0
  83. package/dist/page/actionresult-shape.js +155 -0
  84. package/dist/page/actionresult-types.d.ts +368 -0
  85. package/dist/page/actionresult-types.js +4 -0
  86. package/dist/page/actionresult.d.ts +4 -0
  87. package/dist/page/actionresult.js +299 -0
  88. package/dist/page/actions-probe.d.ts +32 -0
  89. package/dist/page/actions-probe.js +294 -0
  90. package/dist/page/actions-scroll.d.ts +40 -0
  91. package/dist/page/actions-scroll.js +53 -0
  92. package/dist/page/actions.d.ts +132 -0
  93. package/dist/page/actions.js +453 -0
  94. package/dist/page/archive-assets.d.ts +39 -0
  95. package/dist/page/archive-assets.js +187 -0
  96. package/dist/page/archive.d.ts +47 -0
  97. package/dist/page/archive.js +349 -0
  98. package/dist/page/asset-export.d.ts +122 -0
  99. package/dist/page/asset-export.js +376 -0
  100. package/dist/page/await_network.d.ts +16 -0
  101. package/dist/page/await_network.js +23 -0
  102. package/dist/page/bbox.d.ts +37 -0
  103. package/dist/page/bbox.js +115 -0
  104. package/dist/page/canvas-capture.d.ts +82 -0
  105. package/dist/page/canvas-capture.js +257 -0
  106. package/dist/page/canvas-diff.d.ts +51 -0
  107. package/dist/page/canvas-diff.js +131 -0
  108. package/dist/page/canvas-gesture.d.ts +53 -0
  109. package/dist/page/canvas-gesture.js +167 -0
  110. package/dist/page/canvas-transform.d.ts +96 -0
  111. package/dist/page/canvas-transform.js +150 -0
  112. package/dist/page/canvas.d.ts +8 -0
  113. package/dist/page/canvas.js +50 -0
  114. package/dist/page/capture-substrate.d.ts +111 -0
  115. package/dist/page/capture-substrate.js +139 -0
  116. package/dist/page/clipboard.d.ts +25 -0
  117. package/dist/page/clipboard.js +50 -0
  118. package/dist/page/clock.d.ts +36 -0
  119. package/dist/page/clock.js +167 -0
  120. package/dist/page/compose.d.ts +55 -0
  121. package/dist/page/compose.js +169 -0
  122. package/dist/page/console.d.ts +39 -0
  123. package/dist/page/console.js +73 -0
  124. package/dist/page/coverage.d.ts +97 -0
  125. package/dist/page/coverage.js +280 -0
  126. package/dist/page/dom-export.d.ts +41 -0
  127. package/dist/page/dom-export.js +193 -0
  128. package/dist/page/dom-walk.d.ts +91 -0
  129. package/dist/page/dom-walk.js +267 -0
  130. package/dist/page/dom_diff.d.ts +48 -0
  131. package/dist/page/dom_diff.js +121 -0
  132. package/dist/page/downloads.d.ts +80 -0
  133. package/dist/page/downloads.js +244 -0
  134. package/dist/page/drop-files.d.ts +78 -0
  135. package/dist/page/drop-files.js +310 -0
  136. package/dist/page/element-export-discovery.d.ts +64 -0
  137. package/dist/page/element-export-discovery.js +346 -0
  138. package/dist/page/element-export.d.ts +46 -0
  139. package/dist/page/element-export.js +251 -0
  140. package/dist/page/emulation-substrate.d.ts +53 -0
  141. package/dist/page/emulation-substrate.js +87 -0
  142. package/dist/page/emulation.d.ts +60 -0
  143. package/dist/page/emulation.js +162 -0
  144. package/dist/page/export-playwright-script.d.ts +47 -0
  145. package/dist/page/export-playwright-script.js +304 -0
  146. package/dist/page/extract-resolve.d.ts +22 -0
  147. package/dist/page/extract-resolve.js +341 -0
  148. package/dist/page/extract-schema.d.ts +20 -0
  149. package/dist/page/extract-schema.js +200 -0
  150. package/dist/page/extract-types.d.ts +127 -0
  151. package/dist/page/extract-types.js +8 -0
  152. package/dist/page/extract-warnings.d.ts +8 -0
  153. package/dist/page/extract-warnings.js +56 -0
  154. package/dist/page/extract.d.ts +9 -0
  155. package/dist/page/extract.js +174 -0
  156. package/dist/page/fill-form.d.ts +58 -0
  157. package/dist/page/fill-form.js +261 -0
  158. package/dist/page/find.d.ts +158 -0
  159. package/dist/page/find.js +470 -0
  160. package/dist/page/frames.d.ts +45 -0
  161. package/dist/page/frames.js +133 -0
  162. package/dist/page/generate-locator.d.ts +57 -0
  163. package/dist/page/generate-locator.js +136 -0
  164. package/dist/page/gestures.d.ts +128 -0
  165. package/dist/page/gestures.js +198 -0
  166. package/dist/page/har.d.ts +91 -0
  167. package/dist/page/har.js +174 -0
  168. package/dist/page/heap.d.ts +97 -0
  169. package/dist/page/heap.js +285 -0
  170. package/dist/page/inspect.d.ts +34 -0
  171. package/dist/page/inspect.js +75 -0
  172. package/dist/page/layout-thrash.d.ts +34 -0
  173. package/dist/page/layout-thrash.js +232 -0
  174. package/dist/page/learning.d.ts +21 -0
  175. package/dist/page/learning.js +84 -0
  176. package/dist/page/locator.d.ts +54 -0
  177. package/dist/page/locator.js +142 -0
  178. package/dist/page/memory-diff.d.ts +48 -0
  179. package/dist/page/memory-diff.js +105 -0
  180. package/dist/page/network-mask.d.ts +8 -0
  181. package/dist/page/network-mask.js +18 -0
  182. package/dist/page/network-playwright.d.ts +96 -0
  183. package/dist/page/network-playwright.js +353 -0
  184. package/dist/page/network-substrate-select.d.ts +18 -0
  185. package/dist/page/network-substrate-select.js +32 -0
  186. package/dist/page/network-substrate.d.ts +109 -0
  187. package/dist/page/network-substrate.js +161 -0
  188. package/dist/page/network-ws.d.ts +46 -0
  189. package/dist/page/network-ws.js +113 -0
  190. package/dist/page/network.d.ts +194 -0
  191. package/dist/page/network.js +415 -0
  192. package/dist/page/overflow-detect.d.ts +102 -0
  193. package/dist/page/overflow-detect.js +449 -0
  194. package/dist/page/pdf.d.ts +69 -0
  195. package/dist/page/pdf.js +109 -0
  196. package/dist/page/perf-audit-analysers.d.ts +40 -0
  197. package/dist/page/perf-audit-analysers.js +369 -0
  198. package/dist/page/perf-audit-runner.d.ts +20 -0
  199. package/dist/page/perf-audit-runner.js +195 -0
  200. package/dist/page/perf-audit-types.d.ts +41 -0
  201. package/dist/page/perf-audit-types.js +5 -0
  202. package/dist/page/perf-audit.d.ts +37 -0
  203. package/dist/page/perf-audit.js +377 -0
  204. package/dist/page/perf.d.ts +127 -0
  205. package/dist/page/perf.js +373 -0
  206. package/dist/page/plan.d.ts +192 -0
  207. package/dist/page/plan.js +308 -0
  208. package/dist/page/point_probe.d.ts +46 -0
  209. package/dist/page/point_probe.js +99 -0
  210. package/dist/page/recording.d.ts +67 -0
  211. package/dist/page/recording.js +172 -0
  212. package/dist/page/refs.d.ts +92 -0
  213. package/dist/page/refs.js +134 -0
  214. package/dist/page/regions.d.ts +23 -0
  215. package/dist/page/regions.js +32 -0
  216. package/dist/page/routes.d.ts +40 -0
  217. package/dist/page/routes.js +87 -0
  218. package/dist/page/safari-actions.d.ts +12 -0
  219. package/dist/page/safari-actions.js +144 -0
  220. package/dist/page/sample.d.ts +64 -0
  221. package/dist/page/sample.js +216 -0
  222. package/dist/page/screenshot-on.d.ts +51 -0
  223. package/dist/page/screenshot-on.js +150 -0
  224. package/dist/page/screenshot-save.d.ts +36 -0
  225. package/dist/page/screenshot-save.js +53 -0
  226. package/dist/page/screenshot-schedule.d.ts +50 -0
  227. package/dist/page/screenshot-schedule.js +155 -0
  228. package/dist/page/script-substrate.d.ts +32 -0
  229. package/dist/page/script-substrate.js +47 -0
  230. package/dist/page/seed-random.d.ts +45 -0
  231. package/dist/page/seed-random.js +144 -0
  232. package/dist/page/set-of-marks.d.ts +96 -0
  233. package/dist/page/set-of-marks.js +245 -0
  234. package/dist/page/shadow.d.ts +136 -0
  235. package/dist/page/shadow.js +400 -0
  236. package/dist/page/shortcut.d.ts +50 -0
  237. package/dist/page/shortcut.js +147 -0
  238. package/dist/page/snapshot-substrate-safari.d.ts +30 -0
  239. package/dist/page/snapshot-substrate-safari.js +84 -0
  240. package/dist/page/snapshot-substrate-select.d.ts +24 -0
  241. package/dist/page/snapshot-substrate-select.js +34 -0
  242. package/dist/page/snapshot-substrate.d.ts +58 -0
  243. package/dist/page/snapshot-substrate.js +135 -0
  244. package/dist/page/snapshot.d.ts +24 -0
  245. package/dist/page/snapshot.js +162 -0
  246. package/dist/page/solve-captcha.d.ts +76 -0
  247. package/dist/page/solve-captcha.js +286 -0
  248. package/dist/page/storage-substrate-types.d.ts +221 -0
  249. package/dist/page/storage-substrate-types.js +6 -0
  250. package/dist/page/storage-substrate.d.ts +215 -0
  251. package/dist/page/storage-substrate.js +280 -0
  252. package/dist/page/structural.d.ts +9 -0
  253. package/dist/page/structural.js +152 -0
  254. package/dist/page/substrate-bundle-safari.d.ts +8 -0
  255. package/dist/page/substrate-bundle-safari.js +42 -0
  256. package/dist/page/substrate-bundle.d.ts +6 -0
  257. package/dist/page/substrate-bundle.js +53 -0
  258. package/dist/page/text_search.d.ts +44 -0
  259. package/dist/page/text_search.js +90 -0
  260. package/dist/page/upload.d.ts +28 -0
  261. package/dist/page/upload.js +62 -0
  262. package/dist/page/verify.d.ts +63 -0
  263. package/dist/page/verify.js +451 -0
  264. package/dist/page/video.d.ts +115 -0
  265. package/dist/page/video.js +169 -0
  266. package/dist/page/visibility.d.ts +22 -0
  267. package/dist/page/visibility.js +94 -0
  268. package/dist/page/watch.d.ts +29 -0
  269. package/dist/page/watch.js +99 -0
  270. package/dist/page/workers.d.ts +126 -0
  271. package/dist/page/workers.js +490 -0
  272. package/dist/page/ws-interactive.d.ts +82 -0
  273. package/dist/page/ws-interactive.js +318 -0
  274. package/dist/plugin/cli.d.ts +45 -0
  275. package/dist/plugin/cli.js +496 -0
  276. package/dist/plugin/command-registry.d.ts +9 -0
  277. package/dist/plugin/command-registry.js +23 -0
  278. package/dist/plugin/depgraph.d.ts +37 -0
  279. package/dist/plugin/depgraph.js +186 -0
  280. package/dist/plugin/manifest.d.ts +182 -0
  281. package/dist/plugin/manifest.js +219 -0
  282. package/dist/plugin/package-manager.d.ts +22 -0
  283. package/dist/plugin/package-manager.js +40 -0
  284. package/dist/plugin/resolver.d.ts +85 -0
  285. package/dist/plugin/resolver.js +166 -0
  286. package/dist/plugin/runtime.d.ts +77 -0
  287. package/dist/plugin/runtime.js +402 -0
  288. package/dist/plugin/types.d.ts +113 -0
  289. package/dist/plugin/types.js +4 -0
  290. package/dist/policy/confirm.d.ts +76 -0
  291. package/dist/policy/confirm.js +162 -0
  292. package/dist/policy/origin.d.ts +17 -0
  293. package/dist/policy/origin.js +79 -0
  294. package/dist/sdk/client.d.ts +21 -0
  295. package/dist/sdk/client.js +174 -0
  296. package/dist/sdk/index.d.ts +32 -0
  297. package/dist/sdk/index.js +61 -0
  298. package/dist/sdk/plugin-types.d.ts +33 -0
  299. package/dist/sdk/plugin-types.js +22 -0
  300. package/dist/sdk/registry.d.ts +17 -0
  301. package/dist/sdk/registry.js +94 -0
  302. package/dist/sdk/socket-transport.d.ts +20 -0
  303. package/dist/sdk/socket-transport.js +90 -0
  304. package/dist/sdk/tool-types.d.ts +634 -0
  305. package/dist/sdk/tool-types.js +28 -0
  306. package/dist/sdk/transport-in-process.d.ts +21 -0
  307. package/dist/sdk/transport-in-process.js +44 -0
  308. package/dist/sdk/transport-registry.d.ts +19 -0
  309. package/dist/sdk/transport-registry.js +31 -0
  310. package/dist/sdk/transport-socket.d.ts +12 -0
  311. package/dist/sdk/transport-socket.js +77 -0
  312. package/dist/sdk/transport-stdio-child.d.ts +10 -0
  313. package/dist/sdk/transport-stdio-child.js +47 -0
  314. package/dist/sdk/transport.d.ts +10 -0
  315. package/dist/sdk/transport.js +35 -0
  316. package/dist/sdk/types.d.ts +176 -0
  317. package/dist/sdk/types.js +10 -0
  318. package/dist/server.d.ts +33 -0
  319. package/dist/server.js +327 -0
  320. package/dist/session/artifacts.d.ts +52 -0
  321. package/dist/session/artifacts.js +177 -0
  322. package/dist/session/byob-attach.d.ts +26 -0
  323. package/dist/session/byob-attach.js +187 -0
  324. package/dist/session/byob.d.ts +8 -0
  325. package/dist/session/byob.js +20 -0
  326. package/dist/session/cache-storage.d.ts +100 -0
  327. package/dist/session/cache-storage.js +166 -0
  328. package/dist/session/device-emu.d.ts +149 -0
  329. package/dist/session/device-emu.js +545 -0
  330. package/dist/session/device.d.ts +14 -0
  331. package/dist/session/device.js +44 -0
  332. package/dist/session/dialog.d.ts +62 -0
  333. package/dist/session/dialog.js +164 -0
  334. package/dist/session/emulation.d.ts +69 -0
  335. package/dist/session/emulation.js +168 -0
  336. package/dist/session/extensions.d.ts +113 -0
  337. package/dist/session/extensions.js +237 -0
  338. package/dist/session/fs-picker.d.ts +144 -0
  339. package/dist/session/fs-picker.js +666 -0
  340. package/dist/session/idb-storage.d.ts +86 -0
  341. package/dist/session/idb-storage.js +229 -0
  342. package/dist/session/incognito.d.ts +3 -0
  343. package/dist/session/incognito.js +20 -0
  344. package/dist/session/launch-options.d.ts +41 -0
  345. package/dist/session/launch-options.js +200 -0
  346. package/dist/session/managed.d.ts +3 -0
  347. package/dist/session/managed.js +16 -0
  348. package/dist/session/metrics.d.ts +45 -0
  349. package/dist/session/metrics.js +75 -0
  350. package/dist/session/notification.d.ts +122 -0
  351. package/dist/session/notification.js +426 -0
  352. package/dist/session/permission.d.ts +144 -0
  353. package/dist/session/permission.js +600 -0
  354. package/dist/session/playwright-post-wire.d.ts +8 -0
  355. package/dist/session/playwright-post-wire.js +148 -0
  356. package/dist/session/policy-buffer.d.ts +21 -0
  357. package/dist/session/policy-buffer.js +47 -0
  358. package/dist/session/profile-snapshot.d.ts +11 -0
  359. package/dist/session/profile-snapshot.js +53 -0
  360. package/dist/session/registry.d.ts +365 -0
  361. package/dist/session/registry.js +98 -0
  362. package/dist/session/safari-post-wire.d.ts +8 -0
  363. package/dist/session/safari-post-wire.js +28 -0
  364. package/dist/session/safari-session.d.ts +10 -0
  365. package/dist/session/safari-session.js +39 -0
  366. package/dist/session/storage.d.ts +148 -0
  367. package/dist/session/storage.js +350 -0
  368. package/dist/session/types.d.ts +113 -0
  369. package/dist/session/types.js +5 -0
  370. package/dist/session/wedge.d.ts +15 -0
  371. package/dist/session/wedge.js +41 -0
  372. package/dist/tools/action-core-tools.d.ts +13 -0
  373. package/dist/tools/action-core-tools.js +156 -0
  374. package/dist/tools/action-form-tools.d.ts +12 -0
  375. package/dist/tools/action-form-tools.js +179 -0
  376. package/dist/tools/action-gesture-tools.d.ts +9 -0
  377. package/dist/tools/action-gesture-tools.js +115 -0
  378. package/dist/tools/action-history-tools.d.ts +8 -0
  379. package/dist/tools/action-history-tools.js +67 -0
  380. package/dist/tools/action-tool.d.ts +42 -0
  381. package/dist/tools/action-tool.js +58 -0
  382. package/dist/tools/action-tools.d.ts +20 -0
  383. package/dist/tools/action-tools.js +28 -0
  384. package/dist/tools/batch-act-tools.d.ts +10 -0
  385. package/dist/tools/batch-act-tools.js +276 -0
  386. package/dist/tools/batch-human-tools.d.ts +8 -0
  387. package/dist/tools/batch-human-tools.js +148 -0
  388. package/dist/tools/canvas-tools.d.ts +40 -0
  389. package/dist/tools/canvas-tools.js +368 -0
  390. package/dist/tools/capture-report-diagnostics-tools.d.ts +7 -0
  391. package/dist/tools/capture-report-diagnostics-tools.js +318 -0
  392. package/dist/tools/capture-report-element-export-tools.d.ts +8 -0
  393. package/dist/tools/capture-report-element-export-tools.js +197 -0
  394. package/dist/tools/capture-report-export-tools.d.ts +8 -0
  395. package/dist/tools/capture-report-export-tools.js +246 -0
  396. package/dist/tools/capture-report-marks-tools.d.ts +9 -0
  397. package/dist/tools/capture-report-marks-tools.js +221 -0
  398. package/dist/tools/capture-report-upload-tools.d.ts +8 -0
  399. package/dist/tools/capture-report-upload-tools.js +277 -0
  400. package/dist/tools/config-approval-tools.d.ts +8 -0
  401. package/dist/tools/config-approval-tools.js +166 -0
  402. package/dist/tools/deep-coverage-tools.d.ts +8 -0
  403. package/dist/tools/deep-coverage-tools.js +325 -0
  404. package/dist/tools/deep-determinism-tools.d.ts +8 -0
  405. package/dist/tools/deep-determinism-tools.js +276 -0
  406. package/dist/tools/deep-perf-tools.d.ts +19 -0
  407. package/dist/tools/deep-perf-tools.js +324 -0
  408. package/dist/tools/device-emulation-tools.d.ts +9 -0
  409. package/dist/tools/device-emulation-tools.js +137 -0
  410. package/dist/tools/extensions-batch-tools.d.ts +18 -0
  411. package/dist/tools/extensions-batch-tools.js +24 -0
  412. package/dist/tools/extensions-rebuild.d.ts +22 -0
  413. package/dist/tools/extensions-rebuild.js +208 -0
  414. package/dist/tools/extensions-tools.d.ts +2 -0
  415. package/dist/tools/extensions-tools.js +331 -0
  416. package/dist/tools/forms-fill-tools.d.ts +8 -0
  417. package/dist/tools/forms-fill-tools.js +109 -0
  418. package/dist/tools/forms-plan-tools.d.ts +7 -0
  419. package/dist/tools/forms-plan-tools.js +159 -0
  420. package/dist/tools/forms-recording-mode-tools.d.ts +8 -0
  421. package/dist/tools/forms-recording-mode-tools.js +71 -0
  422. package/dist/tools/forms-recording-tools.d.ts +14 -0
  423. package/dist/tools/forms-recording-tools.js +22 -0
  424. package/dist/tools/forms-refs-tools.d.ts +8 -0
  425. package/dist/tools/forms-refs-tools.js +90 -0
  426. package/dist/tools/gesture-coord-tools.d.ts +8 -0
  427. package/dist/tools/gesture-coord-tools.js +168 -0
  428. package/dist/tools/gesture-emulation-tools.d.ts +8 -0
  429. package/dist/tools/gesture-emulation-tools.js +135 -0
  430. package/dist/tools/gesture-network-tools.d.ts +17 -0
  431. package/dist/tools/gesture-network-tools.js +27 -0
  432. package/dist/tools/gesture-route-tools.d.ts +8 -0
  433. package/dist/tools/gesture-route-tools.js +142 -0
  434. package/dist/tools/gesture-websocket-tools.d.ts +8 -0
  435. package/dist/tools/gesture-websocket-tools.js +122 -0
  436. package/dist/tools/gesture-worker-tools.d.ts +9 -0
  437. package/dist/tools/gesture-worker-tools.js +200 -0
  438. package/dist/tools/host-build.d.ts +76 -0
  439. package/dist/tools/host-build.js +516 -0
  440. package/dist/tools/host.d.ts +287 -0
  441. package/dist/tools/host.js +1 -0
  442. package/dist/tools/input-tools.d.ts +10 -0
  443. package/dist/tools/input-tools.js +176 -0
  444. package/dist/tools/live-emulation-tools.d.ts +9 -0
  445. package/dist/tools/live-emulation-tools.js +353 -0
  446. package/dist/tools/plugin-runtime.d.ts +36 -0
  447. package/dist/tools/plugin-runtime.js +274 -0
  448. package/dist/tools/read-observe-buffer-tools.d.ts +9 -0
  449. package/dist/tools/read-observe-buffer-tools.js +385 -0
  450. package/dist/tools/read-observe-capture-tools.d.ts +12 -0
  451. package/dist/tools/read-observe-capture-tools.js +376 -0
  452. package/dist/tools/read-observe-dom-tools.d.ts +8 -0
  453. package/dist/tools/read-observe-dom-tools.js +308 -0
  454. package/dist/tools/read-observe-extract-tools.d.ts +8 -0
  455. package/dist/tools/read-observe-extract-tools.js +232 -0
  456. package/dist/tools/read-observe-verify-tools.d.ts +8 -0
  457. package/dist/tools/read-observe-verify-tools.js +316 -0
  458. package/dist/tools/schemas.d.ts +29 -0
  459. package/dist/tools/schemas.js +58 -0
  460. package/dist/tools/secrets-captcha-tools.d.ts +9 -0
  461. package/dist/tools/secrets-captcha-tools.js +231 -0
  462. package/dist/tools/session-dialog-permission-tools.d.ts +9 -0
  463. package/dist/tools/session-dialog-permission-tools.js +287 -0
  464. package/dist/tools/session-lifecycle-tools.d.ts +8 -0
  465. package/dist/tools/session-lifecycle-tools.js +314 -0
  466. package/dist/tools/session-notification-device-tools.d.ts +9 -0
  467. package/dist/tools/session-notification-device-tools.js +156 -0
  468. package/dist/tools/session-policy-tools.d.ts +16 -0
  469. package/dist/tools/session-policy-tools.js +22 -0
  470. package/dist/tools/session-registry.d.ts +28 -0
  471. package/dist/tools/session-registry.js +427 -0
  472. package/dist/tools/storage-artifact-har-video-tools.d.ts +8 -0
  473. package/dist/tools/storage-artifact-har-video-tools.js +311 -0
  474. package/dist/tools/storage-cache-idb-tools.d.ts +8 -0
  475. package/dist/tools/storage-cache-idb-tools.js +347 -0
  476. package/dist/tools/storage-state-cookies-tools.d.ts +8 -0
  477. package/dist/tools/storage-state-cookies-tools.js +223 -0
  478. package/dist/tools/storage-tools.d.ts +17 -0
  479. package/dist/tools/storage-tools.js +25 -0
  480. package/dist/tools/storage-web-auth-tools.d.ts +10 -0
  481. package/dist/tools/storage-web-auth-tools.js +230 -0
  482. package/dist/tools/tool-metadata.d.ts +8 -0
  483. package/dist/tools/tool-metadata.js +185 -0
  484. package/dist/util/batch.d.ts +83 -0
  485. package/dist/util/batch.js +191 -0
  486. package/dist/util/capabilities.d.ts +504 -0
  487. package/dist/util/capabilities.js +254 -0
  488. package/dist/util/config-store.d.ts +103 -0
  489. package/dist/util/config-store.js +206 -0
  490. package/dist/util/config.d.ts +11 -0
  491. package/dist/util/config.js +28 -0
  492. package/dist/util/credentials.d.ts +136 -0
  493. package/dist/util/credentials.js +622 -0
  494. package/dist/util/deadline.d.ts +22 -0
  495. package/dist/util/deadline.js +62 -0
  496. package/dist/util/diagnostics.d.ts +161 -0
  497. package/dist/util/diagnostics.js +579 -0
  498. package/dist/util/egress-sanitiser.d.ts +29 -0
  499. package/dist/util/egress-sanitiser.js +52 -0
  500. package/dist/util/failure.d.ts +8 -0
  501. package/dist/util/failure.js +50 -0
  502. package/dist/util/flake-check.d.ts +109 -0
  503. package/dist/util/flake-check.js +342 -0
  504. package/dist/util/invariant.d.ts +25 -0
  505. package/dist/util/invariant.js +66 -0
  506. package/dist/util/logging.d.ts +6 -0
  507. package/dist/util/logging.js +12 -0
  508. package/dist/util/predicates.d.ts +62 -0
  509. package/dist/util/predicates.js +340 -0
  510. package/dist/util/secrets.d.ts +104 -0
  511. package/dist/util/secrets.js +219 -0
  512. package/dist/util/tokens.d.ts +6 -0
  513. package/dist/util/tokens.js +24 -0
  514. package/dist/util/url-sanitizer.d.ts +19 -0
  515. package/dist/util/url-sanitizer.js +70 -0
  516. package/dist/util/version.d.ts +2 -0
  517. package/dist/util/version.js +21 -0
  518. package/dist/util/workspace.d.ts +7 -0
  519. package/dist/util/workspace.js +22 -0
  520. package/package.json +120 -0
@@ -0,0 +1,75 @@
1
+ // Per-session cumulative metrics. Piggybacks on the existing per-call
2
+ // `tokensEstimate` + call-timing data the dispatch wrapper already has in hand —
3
+ // no new instrumentation in tool handlers, no per-call disk writes. Read-only
4
+ // from the agent's side via the `session_metrics` tool.
5
+ //
6
+ // Pairs with `export_session_report`: that one bundles the session's QA evidence
7
+ // (url, console errors, recent network summary, named regions, live sessions);
8
+ // this one rolls up the session's TOOL-CALL EVIDENCE (how many calls, how
9
+ // expensive, what failed, what was denied) so an agent / consumer can audit
10
+ // dispatch behaviour without re-walking a transcript.
11
+ //
12
+ // Tracks five counters per tool name (callsByTool, durationMsByTool,
13
+ // errorsByTool) plus two scalars (tokensEstimateSum, capabilityDenials).
14
+ // `capabilityDenials` is intentionally not per-tool: the denial is a property
15
+ // of the capability config, not the tool — when an agent hits one, the fix
16
+ // is at the capability layer and the count alone is the useful signal.
17
+ export class SessionMetrics {
18
+ /** Wall-clock instant the session was created. Mirrored on the rolled-up
19
+ * result so the consumer can derive duration without a second tool call. */
20
+ startedAt;
21
+ /** Per-tool counters. Lazily created on first dispatch of each tool. */
22
+ byTool = new Map();
23
+ /** Sum of `tokensEstimate` across every dispatched call. The field is on the
24
+ * result envelope (set by every tool that wraps a body via the standard
25
+ * helper); we read it back here so a session-wide token budget is one
26
+ * lookup rather than re-walking each tool's transcript. */
27
+ tokensSum = 0;
28
+ /** Count of capability-denied dispatches across the whole session — the
29
+ * config-shape signal, see module header. */
30
+ denials = 0;
31
+ constructor(startedAt = Date.now()) {
32
+ this.startedAt = startedAt;
33
+ }
34
+ /** Record one dispatch. `durationMs` is the wall-clock latency the wrapper
35
+ * measured; `tokensEstimate` is the `tokensEstimate` field from the result
36
+ * envelope (or `undefined` if the result didn't carry one — e.g. an image-
37
+ * only response). Outcome `denied` means the gate refused before dispatch. */
38
+ record(tool, outcome, durationMs, tokensEstimate) {
39
+ const row = this.byTool.get(tool) ?? { count: 0, durationMs: 0, errors: 0 };
40
+ row.count += 1;
41
+ row.durationMs += Math.max(0, durationMs);
42
+ if (outcome === "error")
43
+ row.errors += 1;
44
+ this.byTool.set(tool, row);
45
+ if (outcome === "denied")
46
+ this.denials += 1;
47
+ if (typeof tokensEstimate === "number" && Number.isFinite(tokensEstimate)) {
48
+ this.tokensSum += tokensEstimate;
49
+ }
50
+ }
51
+ /** Snapshot the current rollup. The returned object is plain JSON — safe to
52
+ * serialise straight onto the `session_metrics` tool envelope. */
53
+ snapshot(now = Date.now()) {
54
+ const callsByTool = {};
55
+ const durationMsByTool = {};
56
+ const errorsByTool = {};
57
+ // Emit tool entries in insertion order so two snapshots taken back-to-back
58
+ // are stable (matters for diff-based assertions in tests).
59
+ for (const [tool, row] of this.byTool) {
60
+ callsByTool[tool] = row.count;
61
+ durationMsByTool[tool] = row.durationMs;
62
+ if (row.errors > 0)
63
+ errorsByTool[tool] = row.errors;
64
+ }
65
+ return {
66
+ callsByTool,
67
+ durationMsByTool,
68
+ errorsByTool,
69
+ tokensEstimateSum: this.tokensSum,
70
+ capabilityDenials: this.denials,
71
+ sessionStartedAt: new Date(this.startedAt).toISOString(),
72
+ sessionDurationMs: Math.max(0, now - this.startedAt),
73
+ };
74
+ }
75
+ }
@@ -0,0 +1,122 @@
1
+ import type { BrowserContext } from "playwright-core";
2
+ export type NotificationPolicyMode = "allow" | "deny" | "raise" | "ask-human";
3
+ /** Public, runtime-mutable shape. */
4
+ export interface NotificationPolicy {
5
+ mode: NotificationPolicyMode;
6
+ }
7
+ /** One captured `new Notification(...)` call, exposed on
8
+ * `ActionResult.notifications[]`. */
9
+ export interface NotificationRecord {
10
+ /** Notification title — first argument to the constructor. */
11
+ title: string;
12
+ /** Optional fields from the constructor's `options` bag (`NotificationOptions`).
13
+ * Only the small documented subset is captured (body / icon / tag) — the
14
+ * full spec has actions/data/badge/etc but those are rarely useful in
15
+ * observability and bloat the result envelope. */
16
+ body?: string;
17
+ icon?: string;
18
+ tag?: string;
19
+ /** epoch ms — used by the action-window slice. */
20
+ timestamp: number;
21
+ /** origin of the page that constructed it; undefined when not parseable. */
22
+ origin?: string;
23
+ /** What the server actually did. `"raised"` means the wrapper threw AND
24
+ * the policy was `raise`, so the action will be marked failed. */
25
+ handledAs: "allowed" | "denied" | "raised" | "asked-human";
26
+ }
27
+ /** Hint emitted on `ActionResult.failure.hint` when `raise` mode fired.
28
+ * Stable, agent-facing string — referenced in docs/tool-reference.md. */
29
+ export declare const UNHANDLED_NOTIFICATION_HINT: string;
30
+ /** Mutable per-session state. The page-side check binding reads `current()`
31
+ * on every constructor call, so a `set_notification_policy` call takes effect
32
+ * on the very next construction without page reload. */
33
+ export declare class NotificationPolicyState {
34
+ private policy;
35
+ /** Bounded record ring (shared `PolicyRecordBuffer`; the hard cap so a chatty
36
+ * page can't grow this without bound). `NotificationRecord` carries its
37
+ * timestamp as `timestamp`, so the buffer reads it via an explicit extractor. */
38
+ private readonly records;
39
+ /** Contexts we've already installed the init-script + binding on. */
40
+ private wired;
41
+ constructor(initial?: NotificationPolicy, cap?: number);
42
+ /** Resolved policy snapshot. */
43
+ current(): NotificationPolicy;
44
+ set(next: NotificationPolicy): NotificationPolicy;
45
+ /** Append a record. Caps the buffer at `cap`. */
46
+ record(rec: NotificationRecord): void;
47
+ /** Slice records with `timestamp >= since`. Used by the action-window. */
48
+ since(since: number): NotificationRecord[];
49
+ /** True if any record in `[since, now]` was handled in `raise` mode. */
50
+ raisedSince(since: number): boolean;
51
+ /** Has this context already been wired? Idempotent install guard. */
52
+ hasContext(c: BrowserContext): boolean;
53
+ /** Mark a context as wired. */
54
+ markContext(c: BrowserContext): void;
55
+ }
56
+ /** Parse the spec's compact string form for the top-level mode, or accept the
57
+ * object form. Idempotent. */
58
+ export declare function parseNotificationPolicyArg(v: string | NotificationPolicy | undefined): NotificationPolicy;
59
+ /** Bridge callback type. The server-side binding wires this to await-human
60
+ * (when the policy is `ask-human`); the page-side wrapper script consults it
61
+ * before deciding whether to call through. Returns the decision the wrapper
62
+ * should enact: `"allow"` calls through, `"deny"` throws NotAllowedError. */
63
+ export type NotificationAskHandler = (payload: {
64
+ title: string;
65
+ body?: string;
66
+ icon?: string;
67
+ tag?: string;
68
+ origin?: string;
69
+ }) => Promise<"allow" | "deny">;
70
+ /** Init script that wraps the page-side `Notification` constructor. Stringified
71
+ * so it can be passed to `addInitScript` and `page.evaluate`. Browser-only JS
72
+ * — no TS syntax. Re-injected on `framenavigated` (idempotent: guards on
73
+ * `window.__browx_notification_installed`).
74
+ *
75
+ * The wrapper consults `window.__browx_notification_check({title, body, …})`
76
+ * (an exposeBinding callable from page context) — it returns `"allow" |
77
+ * "deny"`. The server's binding implementation records the construction +
78
+ * (for `ask-human`) blocks on the bridge before answering.
79
+ *
80
+ * IMPORTANT: this script does NOT touch `Notification.requestPermission` or
81
+ * the `Notification.permission` static getter — those are owned by
82
+ * `session/permission.ts` (permission_policy). Coordination is by-
83
+ * construction: each script owns disjoint surface area. */
84
+ export declare const NOTIFICATION_PAGE_SCRIPT = "(() => {\n if (window.__browx_notification_installed) return;\n if (typeof Notification === \"undefined\") return;\n window.__browx_notification_installed = true;\n\n var OrigNotification = Notification;\n\n function check(payload) {\n try {\n if (typeof window.__browx_notification_check === \"function\") {\n return Promise.resolve(window.__browx_notification_check(JSON.stringify(payload)));\n }\n } catch (_) {}\n return Promise.resolve(\"allow\");\n }\n function notAllowed(msg) {\n var e = new Error(msg || \"notification denied by browxai notificationPolicy\");\n try { e.name = \"NotAllowedError\"; } catch (_) {}\n return e;\n }\n\n // The constructed instance is a plain object whose prototype is set to\n // `OrigNotification.prototype` AFTER own-property assignment, so\n // accessor-only props on the platform prototype (`title`, `body`, etc.)\n // don't intercept our `this.title = ...` writes. (Setting them via\n // assignment with the prototype already in place throws TypeError in\n // headless Chromium \u2014 `Notification.prototype.title` is getter-only.)\n function ProxyNotification(title, options) {\n var safeTitle = String(title);\n var payload = {\n title: safeTitle,\n body: (options && options.body) || undefined,\n icon: (options && options.icon) || undefined,\n tag: (options && options.tag) || undefined,\n origin: location.origin,\n };\n\n // SYNC throw timing \u2014 read the pre-seeded decision hint. Spec requires\n // `new Notification(...)` to throw synchronously on failure. The async\n // `check()` below still records the call (and does the ask-human dance);\n // the sync hint is purely for the throw timing.\n var syncDecision = (typeof window.__browx_notification_sync_decision === \"string\")\n ? window.__browx_notification_sync_decision\n : \"allow\";\n if (syncDecision === \"deny\" || syncDecision === \"raise\") {\n // Still record the attempt before throwing.\n try { check(payload); } catch (_) {}\n throw notAllowed(syncDecision === \"raise\"\n ? \"notification raised \u2014 set notificationPolicy\"\n : \"Notification denied by browxai notificationPolicy\");\n }\n\n // Build the stub-as-this. Own data properties first; THEN set the\n // prototype so getter-only inherited accessors don't intercept writes.\n var listeners = {};\n var realRef = null;\n var pendingClose = false;\n Object.defineProperty(this, \"title\", { value: safeTitle, writable: true, configurable: true, enumerable: true });\n Object.defineProperty(this, \"body\", { value: (options && options.body) || \"\", writable: true, configurable: true, enumerable: true });\n Object.defineProperty(this, \"icon\", { value: (options && options.icon) || \"\", writable: true, configurable: true, enumerable: true });\n Object.defineProperty(this, \"tag\", { value: (options && options.tag) || \"\", writable: true, configurable: true, enumerable: true });\n Object.defineProperty(this, \"data\", { value: (options && options.data) !== undefined ? options.data : null, writable: true, configurable: true, enumerable: true });\n var self = this;\n Object.defineProperty(this, \"close\", { value: function () {\n if (realRef) { try { realRef.close(); } catch (_) {} return; }\n pendingClose = true;\n }, writable: true, configurable: true });\n Object.defineProperty(this, \"addEventListener\", { value: function (ev, cb) {\n (listeners[ev] = listeners[ev] || []).push(cb);\n if (realRef && realRef.addEventListener) { try { realRef.addEventListener(ev, cb); } catch (_) {} }\n }, writable: true, configurable: true });\n Object.defineProperty(this, \"removeEventListener\", { value: function (ev, cb) {\n var arr = listeners[ev]; if (!arr) return;\n var i = arr.indexOf(cb); if (i >= 0) arr.splice(i, 1);\n if (realRef && realRef.removeEventListener) { try { realRef.removeEventListener(ev, cb); } catch (_) {} }\n }, writable: true, configurable: true });\n\n // ask-human / allow: dispatch the policy check + (if allowed) construct\n // the real native Notification and route the page's listeners to it.\n check(payload).then(function (decision) {\n if (decision !== \"allow\") return;\n try {\n var real = new OrigNotification(safeTitle, options || {});\n realRef = real;\n for (var ev in listeners) {\n if (!Object.prototype.hasOwnProperty.call(listeners, ev)) continue;\n for (var i = 0; i < listeners[ev].length; i++) {\n try { real.addEventListener(ev, listeners[ev][i]); } catch (_) {}\n }\n }\n if (pendingClose) { try { real.close(); } catch (_) {} }\n } catch (_) {\n // Browser refused (e.g. `Notification.permission === \"denied\"`\n // because permission_policy denied). The stub remains a no-op,\n // matching the deny branch.\n }\n });\n\n void self; // referenced via closure above\n }\n // Use a fresh prototype object \u2014 NOT `OrigNotification.prototype`, whose\n // accessor-only properties (`title`, `body`, `tag`, etc.) would intercept\n // our writes on `this` via the prototype chain (`TypeError: Cannot set\n // property title of #<Notification> which has only a getter` in headless\n // Chromium). Trade-off: `instanceof Notification` returns false for our\n // stub; apps rarely runtime-check that, and the alternative (overriding\n // the platform prototype's accessors) is messier + version-fragile.\n ProxyNotification.prototype = {};\n // Preserve the static surface \u2014 permission_policy owns these. Forward\n // every static read/write to the original constructor so the existing\n // `permission_policy` wrapper script still wraps `requestPermission` /\n // observes `permission` unchanged.\n try {\n Object.defineProperty(ProxyNotification, \"permission\", {\n get: function () { return OrigNotification.permission; },\n configurable: true,\n });\n } catch (_) {}\n ProxyNotification.requestPermission = function () {\n return OrigNotification.requestPermission.apply(OrigNotification, arguments);\n };\n try { ProxyNotification.maxActions = OrigNotification.maxActions; } catch (_) {}\n\n try {\n // Replace the global. Some browsers refuse to delete `Notification` on\n // `window` (it's a configurable: false property in newer specs); fall\n // back to a defineProperty assignment if direct assignment is silent.\n window.Notification = ProxyNotification;\n if (window.Notification !== ProxyNotification) {\n Object.defineProperty(window, \"Notification\", {\n value: ProxyNotification, writable: true, configurable: true,\n });\n }\n } catch (_) {}\n})();";
85
+ /** Server-side wire-up. Installs:
86
+ * - `__browx_notification_check` exposeBinding: page-side records +
87
+ * ask-human resolves to allow/deny via the bridge.
88
+ * - The page-side init script (above), re-injected by Playwright on every
89
+ * new document via `addInitScript`.
90
+ * - Seeds the SYNCHRONOUS decision hint
91
+ * (`window.__browx_notification_sync_decision`) on every wired page so
92
+ * the constructor wrapper can throw without awaiting a binding round-
93
+ * trip; refreshed on `set_notification_policy` via
94
+ * `propagateSyncDecision`.
95
+ *
96
+ * Idempotent on the same context (the state's `WeakSet<BrowserContext>` guard).
97
+ * Errors during install are logged and swallowed — when bindings fail the
98
+ * wrapper falls back to call-through (browser default).
99
+ */
100
+ export declare function attachNotificationPolicy(context: BrowserContext, state: NotificationPolicyState, askHandler: NotificationAskHandler): Promise<void>;
101
+ /** Compute the sync decision the constructor wrapper inspects to know
102
+ * whether to throw synchronously. `allow` and `ask-human` BOTH yield
103
+ * `"allow"` here: ask-human's constructor surface is non-throwing (we
104
+ * return the stub and only dispatch the real notification once the human
105
+ * answers). `deny` and `raise` throw at construction time. */
106
+ export declare function syncDecisionFor(mode: NotificationPolicyMode): "allow" | "deny" | "raise";
107
+ /** Push the current policy's sync decision to every live page in the context
108
+ * AND register an additional init-script so future new documents see the
109
+ * fresh value. Called from `set_notification_policy` so a runtime mode flip
110
+ * takes effect on the very next constructor call without page reload.
111
+ *
112
+ * Init-scripts accumulate in Playwright (one per call); the seed is ~80
113
+ * bytes so even hundreds of flips are negligible. The constructor wrapper
114
+ * reads `window.__browx_notification_sync_decision` at each call, so the
115
+ * most-recently-evaluated seed wins. */
116
+ export declare function propagateSyncDecision(context: BrowserContext, state: NotificationPolicyState): Promise<void>;
117
+ /** Read-side: snapshot the current policy + recent records for the session.
118
+ * Used by tests and (potentially) a future `notification_state` tool. */
119
+ export declare function readNotifications(state: NotificationPolicyState, since?: number): {
120
+ policy: NotificationPolicy;
121
+ records: NotificationRecord[];
122
+ };
@@ -0,0 +1,426 @@
1
+ // Per-session notification policy. Sibling of `permission_policy`. Plugs the
2
+ // `new Notification(title, opts)` blind spot.
3
+ //
4
+ // Why a separate policy from `permission_policy.notifications`:
5
+ //
6
+ // - `permission_policy.notifications` governs the W3C *permission* check —
7
+ // `Notification.requestPermission()` and the `Notification.permission`
8
+ // state-getter. That tells the page whether it MAY display notifications.
9
+ // - `notification_policy` governs the *constructor invocation* —
10
+ // `new Notification(title, opts)`. The constructor only succeeds when
11
+ // permission is granted (browser-policy), but its construction is the
12
+ // observability event: it's what the page actually does when it tries to
13
+ // notify the human. Pre-v0.5.0 browxai had no visibility into these
14
+ // calls; an action that fired three notifications was indistinguishable
15
+ // from one that fired zero.
16
+ //
17
+ // The two policies compose:
18
+ //
19
+ // - `permission_policy.notifications: "allow"` + `notification_policy: "allow"` →
20
+ // the page can construct + display, every construct is captured on
21
+ // `ActionResult.notifications[]`.
22
+ // - `permission_policy.notifications: "deny"` + `notification_policy: "allow"` →
23
+ // the page sees `Notification.permission === "denied"` and most apps don't
24
+ // call the constructor at all; but if they do, the constructor still throws
25
+ // a `NotAllowedError` (browser-policy) and we capture the attempted call.
26
+ // - `permission_policy.notifications: "allow"` + `notification_policy: "deny"` →
27
+ // the constructor throws `NotAllowedError` (our policy) before the OS-level
28
+ // notification fires. The page sees permission is granted but the
29
+ // constructor surface refuses. Use when you want to observe + suppress.
30
+ //
31
+ // Modes mirror `permission_policy`'s posture:
32
+ //
33
+ // - "allow" — DEFAULT (browser default). Constructor proceeds normally;
34
+ // the OS displays per its own settings. Every call captured
35
+ // as `handledAs:"allowed"`. Matches the browser's
36
+ // pre-instrumentation behaviour so adopters can turn this
37
+ // on without breaking apps that expect notifications.
38
+ // - "deny" — Constructor throws `NotAllowedError` (the same exception
39
+ // the browser raises when permission is denied). Recorded
40
+ // as `handledAs:"denied"`. Use to suppress OS notifications
41
+ // while still observing what the page would have shown.
42
+ // - "raise" — Constructor throws + recorded as `handledAs:"raised"`.
43
+ // The next `ActionResult` flips `ok:false` with a stable
44
+ // hint pointing at `set_notification_policy`. Symmetric to
45
+ // `permission_policy`'s `raise` — useful when an agent
46
+ // wants notifications to be a hard signal that the action
47
+ // triggered an unexpected user-facing event.
48
+ // - "ask-human" — Constructor blocks on `await_human({kind:"confirm"})`
49
+ // (the `__browx.confirm(true|false)` mechanism) and
50
+ // proceeds or throws per the human's answer. The
51
+ // constructor call returns synchronously in the browser
52
+ // spec, so we serialise the await via the same
53
+ // page-side promise pattern as `permission_policy`.
54
+ // NOTE: the constructor surface in the page must observe a
55
+ // synchronous return from `new Notification(...)`. Our
56
+ // wrapper returns a stub that satisfies the typeof check,
57
+ // but the actual native notification is only fired *after*
58
+ // the human-decision resolves — so apps that read
59
+ // `notification.close()` immediately will observe a no-op
60
+ // stub. Documented in the docs/tool-reference.md entry.
61
+ //
62
+ // Init-script wraps the global `Notification` constructor (and preserves the
63
+ // static `requestPermission` / `permission` getters so the `permission_policy`
64
+ // wrappers — already injected by `session/permission.ts` — keep working
65
+ // untouched). The two policies compose; coordination is by-construction:
66
+ // `permission_policy` only touches `Notification.requestPermission`, this
67
+ // module only touches `new Notification(...)`.
68
+ import { log } from "../util/logging.js";
69
+ import { PolicyRecordBuffer } from "./policy-buffer.js";
70
+ /** Hint emitted on `ActionResult.failure.hint` when `raise` mode fired.
71
+ * Stable, agent-facing string — referenced in docs/tool-reference.md. */
72
+ export const UNHANDLED_NOTIFICATION_HINT = "unhandled notification — set notificationPolicy (open_session/set_notification_policy) " +
73
+ 'to "allow", "deny", or "ask-human" before driving an action that may construct ' +
74
+ "a Notification. The constructor was rejected page-side (NotAllowedError) so the page " +
75
+ "is not deadlocked, but the app effect is the deny branch.";
76
+ /** Mutable per-session state. The page-side check binding reads `current()`
77
+ * on every constructor call, so a `set_notification_policy` call takes effect
78
+ * on the very next construction without page reload. */
79
+ export class NotificationPolicyState {
80
+ policy;
81
+ /** Bounded record ring (shared `PolicyRecordBuffer`; the hard cap so a chatty
82
+ * page can't grow this without bound). `NotificationRecord` carries its
83
+ * timestamp as `timestamp`, so the buffer reads it via an explicit extractor. */
84
+ records;
85
+ /** Contexts we've already installed the init-script + binding on. */
86
+ wired = new WeakSet();
87
+ constructor(initial = { mode: "allow" }, cap = 200) {
88
+ this.policy = normalise(initial);
89
+ this.records = new PolicyRecordBuffer(cap, (r) => r.timestamp);
90
+ }
91
+ /** Resolved policy snapshot. */
92
+ current() {
93
+ return { mode: this.policy.mode };
94
+ }
95
+ set(next) {
96
+ this.policy = normalise(next);
97
+ return this.current();
98
+ }
99
+ /** Append a record. Caps the buffer at `cap`. */
100
+ record(rec) {
101
+ this.records.record(rec);
102
+ }
103
+ /** Slice records with `timestamp >= since`. Used by the action-window. */
104
+ since(since) {
105
+ return this.records.since(since);
106
+ }
107
+ /** True if any record in `[since, now]` was handled in `raise` mode. */
108
+ raisedSince(since) {
109
+ return this.records.matchedSince(since, (r) => r.handledAs === "raised");
110
+ }
111
+ /** Has this context already been wired? Idempotent install guard. */
112
+ hasContext(c) {
113
+ return this.wired.has(c);
114
+ }
115
+ /** Mark a context as wired. */
116
+ markContext(c) {
117
+ this.wired.add(c);
118
+ }
119
+ }
120
+ function normalise(p) {
121
+ if (!isPolicyMode(p.mode)) {
122
+ throw new Error(`notificationPolicy: invalid mode "${String(p.mode)}" — expected "allow" | "deny" | "raise" | "ask-human"`);
123
+ }
124
+ return { mode: p.mode };
125
+ }
126
+ function isPolicyMode(m) {
127
+ return m === "allow" || m === "deny" || m === "raise" || m === "ask-human";
128
+ }
129
+ /** Parse the spec's compact string form for the top-level mode, or accept the
130
+ * object form. Idempotent. */
131
+ export function parseNotificationPolicyArg(v) {
132
+ if (!v)
133
+ return { mode: "allow" };
134
+ if (typeof v === "object")
135
+ return normalise(v);
136
+ if (isPolicyMode(v))
137
+ return { mode: v };
138
+ throw new Error(`notificationPolicy: invalid value "${v}" — expected "allow" | "deny" | "raise" | "ask-human"`);
139
+ }
140
+ /** Init script that wraps the page-side `Notification` constructor. Stringified
141
+ * so it can be passed to `addInitScript` and `page.evaluate`. Browser-only JS
142
+ * — no TS syntax. Re-injected on `framenavigated` (idempotent: guards on
143
+ * `window.__browx_notification_installed`).
144
+ *
145
+ * The wrapper consults `window.__browx_notification_check({title, body, …})`
146
+ * (an exposeBinding callable from page context) — it returns `"allow" |
147
+ * "deny"`. The server's binding implementation records the construction +
148
+ * (for `ask-human`) blocks on the bridge before answering.
149
+ *
150
+ * IMPORTANT: this script does NOT touch `Notification.requestPermission` or
151
+ * the `Notification.permission` static getter — those are owned by
152
+ * `session/permission.ts` (permission_policy). Coordination is by-
153
+ * construction: each script owns disjoint surface area. */
154
+ export const NOTIFICATION_PAGE_SCRIPT = `(() => {
155
+ if (window.__browx_notification_installed) return;
156
+ if (typeof Notification === "undefined") return;
157
+ window.__browx_notification_installed = true;
158
+
159
+ var OrigNotification = Notification;
160
+
161
+ function check(payload) {
162
+ try {
163
+ if (typeof window.__browx_notification_check === "function") {
164
+ return Promise.resolve(window.__browx_notification_check(JSON.stringify(payload)));
165
+ }
166
+ } catch (_) {}
167
+ return Promise.resolve("allow");
168
+ }
169
+ function notAllowed(msg) {
170
+ var e = new Error(msg || "notification denied by browxai notificationPolicy");
171
+ try { e.name = "NotAllowedError"; } catch (_) {}
172
+ return e;
173
+ }
174
+
175
+ // The constructed instance is a plain object whose prototype is set to
176
+ // \`OrigNotification.prototype\` AFTER own-property assignment, so
177
+ // accessor-only props on the platform prototype (\`title\`, \`body\`, etc.)
178
+ // don't intercept our \`this.title = ...\` writes. (Setting them via
179
+ // assignment with the prototype already in place throws TypeError in
180
+ // headless Chromium — \`Notification.prototype.title\` is getter-only.)
181
+ function ProxyNotification(title, options) {
182
+ var safeTitle = String(title);
183
+ var payload = {
184
+ title: safeTitle,
185
+ body: (options && options.body) || undefined,
186
+ icon: (options && options.icon) || undefined,
187
+ tag: (options && options.tag) || undefined,
188
+ origin: location.origin,
189
+ };
190
+
191
+ // SYNC throw timing — read the pre-seeded decision hint. Spec requires
192
+ // \`new Notification(...)\` to throw synchronously on failure. The async
193
+ // \`check()\` below still records the call (and does the ask-human dance);
194
+ // the sync hint is purely for the throw timing.
195
+ var syncDecision = (typeof window.__browx_notification_sync_decision === "string")
196
+ ? window.__browx_notification_sync_decision
197
+ : "allow";
198
+ if (syncDecision === "deny" || syncDecision === "raise") {
199
+ // Still record the attempt before throwing.
200
+ try { check(payload); } catch (_) {}
201
+ throw notAllowed(syncDecision === "raise"
202
+ ? "notification raised — set notificationPolicy"
203
+ : "Notification denied by browxai notificationPolicy");
204
+ }
205
+
206
+ // Build the stub-as-this. Own data properties first; THEN set the
207
+ // prototype so getter-only inherited accessors don't intercept writes.
208
+ var listeners = {};
209
+ var realRef = null;
210
+ var pendingClose = false;
211
+ Object.defineProperty(this, "title", { value: safeTitle, writable: true, configurable: true, enumerable: true });
212
+ Object.defineProperty(this, "body", { value: (options && options.body) || "", writable: true, configurable: true, enumerable: true });
213
+ Object.defineProperty(this, "icon", { value: (options && options.icon) || "", writable: true, configurable: true, enumerable: true });
214
+ Object.defineProperty(this, "tag", { value: (options && options.tag) || "", writable: true, configurable: true, enumerable: true });
215
+ Object.defineProperty(this, "data", { value: (options && options.data) !== undefined ? options.data : null, writable: true, configurable: true, enumerable: true });
216
+ var self = this;
217
+ Object.defineProperty(this, "close", { value: function () {
218
+ if (realRef) { try { realRef.close(); } catch (_) {} return; }
219
+ pendingClose = true;
220
+ }, writable: true, configurable: true });
221
+ Object.defineProperty(this, "addEventListener", { value: function (ev, cb) {
222
+ (listeners[ev] = listeners[ev] || []).push(cb);
223
+ if (realRef && realRef.addEventListener) { try { realRef.addEventListener(ev, cb); } catch (_) {} }
224
+ }, writable: true, configurable: true });
225
+ Object.defineProperty(this, "removeEventListener", { value: function (ev, cb) {
226
+ var arr = listeners[ev]; if (!arr) return;
227
+ var i = arr.indexOf(cb); if (i >= 0) arr.splice(i, 1);
228
+ if (realRef && realRef.removeEventListener) { try { realRef.removeEventListener(ev, cb); } catch (_) {} }
229
+ }, writable: true, configurable: true });
230
+
231
+ // ask-human / allow: dispatch the policy check + (if allowed) construct
232
+ // the real native Notification and route the page's listeners to it.
233
+ check(payload).then(function (decision) {
234
+ if (decision !== "allow") return;
235
+ try {
236
+ var real = new OrigNotification(safeTitle, options || {});
237
+ realRef = real;
238
+ for (var ev in listeners) {
239
+ if (!Object.prototype.hasOwnProperty.call(listeners, ev)) continue;
240
+ for (var i = 0; i < listeners[ev].length; i++) {
241
+ try { real.addEventListener(ev, listeners[ev][i]); } catch (_) {}
242
+ }
243
+ }
244
+ if (pendingClose) { try { real.close(); } catch (_) {} }
245
+ } catch (_) {
246
+ // Browser refused (e.g. \`Notification.permission === "denied"\`
247
+ // because permission_policy denied). The stub remains a no-op,
248
+ // matching the deny branch.
249
+ }
250
+ });
251
+
252
+ void self; // referenced via closure above
253
+ }
254
+ // Use a fresh prototype object — NOT \`OrigNotification.prototype\`, whose
255
+ // accessor-only properties (\`title\`, \`body\`, \`tag\`, etc.) would intercept
256
+ // our writes on \`this\` via the prototype chain (\`TypeError: Cannot set
257
+ // property title of #<Notification> which has only a getter\` in headless
258
+ // Chromium). Trade-off: \`instanceof Notification\` returns false for our
259
+ // stub; apps rarely runtime-check that, and the alternative (overriding
260
+ // the platform prototype's accessors) is messier + version-fragile.
261
+ ProxyNotification.prototype = {};
262
+ // Preserve the static surface — permission_policy owns these. Forward
263
+ // every static read/write to the original constructor so the existing
264
+ // \`permission_policy\` wrapper script still wraps \`requestPermission\` /
265
+ // observes \`permission\` unchanged.
266
+ try {
267
+ Object.defineProperty(ProxyNotification, "permission", {
268
+ get: function () { return OrigNotification.permission; },
269
+ configurable: true,
270
+ });
271
+ } catch (_) {}
272
+ ProxyNotification.requestPermission = function () {
273
+ return OrigNotification.requestPermission.apply(OrigNotification, arguments);
274
+ };
275
+ try { ProxyNotification.maxActions = OrigNotification.maxActions; } catch (_) {}
276
+
277
+ try {
278
+ // Replace the global. Some browsers refuse to delete \`Notification\` on
279
+ // \`window\` (it's a configurable: false property in newer specs); fall
280
+ // back to a defineProperty assignment if direct assignment is silent.
281
+ window.Notification = ProxyNotification;
282
+ if (window.Notification !== ProxyNotification) {
283
+ Object.defineProperty(window, "Notification", {
284
+ value: ProxyNotification, writable: true, configurable: true,
285
+ });
286
+ }
287
+ } catch (_) {}
288
+ })();`;
289
+ /** Server-side wire-up. Installs:
290
+ * - `__browx_notification_check` exposeBinding: page-side records +
291
+ * ask-human resolves to allow/deny via the bridge.
292
+ * - The page-side init script (above), re-injected by Playwright on every
293
+ * new document via `addInitScript`.
294
+ * - Seeds the SYNCHRONOUS decision hint
295
+ * (`window.__browx_notification_sync_decision`) on every wired page so
296
+ * the constructor wrapper can throw without awaiting a binding round-
297
+ * trip; refreshed on `set_notification_policy` via
298
+ * `propagateSyncDecision`.
299
+ *
300
+ * Idempotent on the same context (the state's `WeakSet<BrowserContext>` guard).
301
+ * Errors during install are logged and swallowed — when bindings fail the
302
+ * wrapper falls back to call-through (browser default).
303
+ */
304
+ export async function attachNotificationPolicy(context, state, askHandler) {
305
+ if (state.hasContext(context))
306
+ return;
307
+ state.markContext(context);
308
+ try {
309
+ await context.exposeBinding("__browx_notification_check", async (_source, payload) => {
310
+ try {
311
+ const o = JSON.parse(payload);
312
+ const title = String(o.title ?? "");
313
+ const origin = o.origin;
314
+ const mode = state.current().mode;
315
+ const ts = Date.now();
316
+ const baseRec = {
317
+ title,
318
+ timestamp: ts,
319
+ ...(o.body !== undefined ? { body: o.body } : {}),
320
+ ...(o.icon !== undefined ? { icon: o.icon } : {}),
321
+ ...(o.tag !== undefined ? { tag: o.tag } : {}),
322
+ ...(origin !== undefined ? { origin } : {}),
323
+ };
324
+ switch (mode) {
325
+ case "allow":
326
+ state.record({ ...baseRec, handledAs: "allowed" });
327
+ return "allow";
328
+ case "deny":
329
+ state.record({ ...baseRec, handledAs: "denied" });
330
+ return "deny";
331
+ case "ask-human": {
332
+ const decision = await askHandler({
333
+ title,
334
+ ...(o.body !== undefined ? { body: o.body } : {}),
335
+ ...(o.icon !== undefined ? { icon: o.icon } : {}),
336
+ ...(o.tag !== undefined ? { tag: o.tag } : {}),
337
+ ...(origin !== undefined ? { origin } : {}),
338
+ }).catch(() => "deny");
339
+ state.record({ ...baseRec, handledAs: "asked-human" });
340
+ return decision;
341
+ }
342
+ case "raise":
343
+ default:
344
+ state.record({ ...baseRec, handledAs: "raised" });
345
+ return "deny";
346
+ }
347
+ }
348
+ catch (err) {
349
+ log.warn("session.notification: check handler error", {
350
+ error: err instanceof Error ? err.message : String(err),
351
+ });
352
+ return "allow";
353
+ }
354
+ });
355
+ }
356
+ catch (err) {
357
+ log.warn("session.notification: exposeBinding install failed; constructor falls back to call-through", {
358
+ error: err instanceof Error ? err.message : String(err),
359
+ });
360
+ }
361
+ // Init-script — Playwright re-runs it on every new document. Idempotent
362
+ // via the `__browx_notification_installed` guard inside the script.
363
+ try {
364
+ await context.addInitScript({ content: NOTIFICATION_PAGE_SCRIPT });
365
+ // Seed the sync decision before any page script runs, plus apply to
366
+ // already-attached pages so the wrapper installs on the current document.
367
+ await context.addInitScript({ content: syncDecisionSeed(state.current().mode) });
368
+ for (const page of context.pages()) {
369
+ await page.evaluate(syncDecisionSeed(state.current().mode)).catch(() => undefined);
370
+ await page.evaluate(NOTIFICATION_PAGE_SCRIPT).catch(() => undefined);
371
+ }
372
+ }
373
+ catch (err) {
374
+ log.warn("session.notification: addInitScript failed", {
375
+ error: err instanceof Error ? err.message : String(err),
376
+ });
377
+ }
378
+ }
379
+ /** Compute the sync decision the constructor wrapper inspects to know
380
+ * whether to throw synchronously. `allow` and `ask-human` BOTH yield
381
+ * `"allow"` here: ask-human's constructor surface is non-throwing (we
382
+ * return the stub and only dispatch the real notification once the human
383
+ * answers). `deny` and `raise` throw at construction time. */
384
+ export function syncDecisionFor(mode) {
385
+ switch (mode) {
386
+ case "deny":
387
+ return "deny";
388
+ case "raise":
389
+ return "raise";
390
+ case "allow":
391
+ case "ask-human":
392
+ default:
393
+ return "allow";
394
+ }
395
+ }
396
+ function syncDecisionSeed(mode) {
397
+ const dec = syncDecisionFor(mode);
398
+ // Init-script: runs before any page script, sets the hint on `window`.
399
+ return `(() => { try { window.__browx_notification_sync_decision = ${JSON.stringify(dec)}; } catch (_) {} })();`;
400
+ }
401
+ /** Push the current policy's sync decision to every live page in the context
402
+ * AND register an additional init-script so future new documents see the
403
+ * fresh value. Called from `set_notification_policy` so a runtime mode flip
404
+ * takes effect on the very next constructor call without page reload.
405
+ *
406
+ * Init-scripts accumulate in Playwright (one per call); the seed is ~80
407
+ * bytes so even hundreds of flips are negligible. The constructor wrapper
408
+ * reads `window.__browx_notification_sync_decision` at each call, so the
409
+ * most-recently-evaluated seed wins. */
410
+ export async function propagateSyncDecision(context, state) {
411
+ const seed = syncDecisionSeed(state.current().mode);
412
+ try {
413
+ await context.addInitScript({ content: seed });
414
+ }
415
+ catch {
416
+ /* best-effort */
417
+ }
418
+ for (const page of context.pages()) {
419
+ await page.evaluate(seed).catch(() => undefined);
420
+ }
421
+ }
422
+ /** Read-side: snapshot the current policy + recent records for the session.
423
+ * Used by tests and (potentially) a future `notification_state` tool. */
424
+ export function readNotifications(state, since = 0) {
425
+ return { policy: state.current(), records: state.since(since) };
426
+ }