@browserbasehq/orca 3.2.1-preview.2 → 3.4.0-preview-1

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 (223) hide show
  1. package/dist/cjs/lib/inference.js +2 -9
  2. package/dist/cjs/lib/inference.js.map +1 -1
  3. package/dist/cjs/lib/prompt.js +3 -1
  4. package/dist/cjs/lib/prompt.js.map +1 -1
  5. package/dist/cjs/lib/v3/agent/AgentProvider.js +3 -0
  6. package/dist/cjs/lib/v3/agent/AgentProvider.js.map +1 -1
  7. package/dist/cjs/lib/v3/agent/tools/fillFormVision.js +16 -12
  8. package/dist/cjs/lib/v3/agent/tools/fillFormVision.js.map +1 -1
  9. package/dist/cjs/lib/v3/agent/utils/validateExperimentalFeatures.js +0 -4
  10. package/dist/cjs/lib/v3/agent/utils/validateExperimentalFeatures.js.map +1 -1
  11. package/dist/cjs/lib/v3/api.d.ts +1 -0
  12. package/dist/cjs/lib/v3/api.js +15 -3
  13. package/dist/cjs/lib/v3/api.js.map +1 -1
  14. package/dist/cjs/lib/v3/dom/build/a11yScripts.generated.js +1 -1
  15. package/dist/cjs/lib/v3/dom/build/a11yScripts.generated.js.map +1 -1
  16. package/dist/cjs/lib/v3/dom/build/locatorScripts.generated.js +1 -1
  17. package/dist/cjs/lib/v3/dom/build/locatorScripts.generated.js.map +1 -1
  18. package/dist/cjs/lib/v3/dom/build/reRenderScriptContent.d.ts +1 -1
  19. package/dist/cjs/lib/v3/dom/build/reRenderScriptContent.js +1 -1
  20. package/dist/cjs/lib/v3/dom/build/reRenderScriptContent.js.map +1 -1
  21. package/dist/cjs/lib/v3/dom/build/screenshotScripts.generated.js +1 -1
  22. package/dist/cjs/lib/v3/dom/build/screenshotScripts.generated.js.map +1 -1
  23. package/dist/cjs/lib/v3/dom/build/scriptV3Content.d.ts +1 -1
  24. package/dist/cjs/lib/v3/dom/build/scriptV3Content.js +1 -1
  25. package/dist/cjs/lib/v3/dom/build/scriptV3Content.js.map +1 -1
  26. package/dist/cjs/lib/v3/dom/build/selectorRuntime.generated.d.ts +24 -0
  27. package/dist/cjs/lib/v3/dom/build/selectorRuntime.generated.js +31 -0
  28. package/dist/cjs/lib/v3/dom/build/selectorRuntime.generated.js.map +1 -0
  29. package/dist/cjs/lib/v3/handlers/extractHandler.js +3 -1
  30. package/dist/cjs/lib/v3/handlers/extractHandler.js.map +1 -1
  31. package/dist/cjs/lib/v3/handlers/observeHandler.js +2 -1
  32. package/dist/cjs/lib/v3/handlers/observeHandler.js.map +1 -1
  33. package/dist/cjs/lib/v3/handlers/v3AgentHandler.js +3 -5
  34. package/dist/cjs/lib/v3/handlers/v3AgentHandler.js.map +1 -1
  35. package/dist/cjs/lib/v3/index.d.ts +1 -1
  36. package/dist/cjs/lib/v3/llm/CerebrasClient.js +1 -1
  37. package/dist/cjs/lib/v3/llm/CerebrasClient.js.map +1 -1
  38. package/dist/cjs/lib/v3/llm/GroqClient.js +1 -1
  39. package/dist/cjs/lib/v3/llm/GroqClient.js.map +1 -1
  40. package/dist/cjs/lib/v3/types/private/agent.d.ts +5 -0
  41. package/dist/cjs/lib/v3/types/private/agent.js +11 -0
  42. package/dist/cjs/lib/v3/types/private/agent.js.map +1 -1
  43. package/dist/cjs/lib/v3/types/private/handlers.d.ts +2 -0
  44. package/dist/cjs/lib/v3/types/private/handlers.js.map +1 -1
  45. package/dist/cjs/lib/v3/types/private/snapshot.d.ts +8 -0
  46. package/dist/cjs/lib/v3/types/private/snapshot.js.map +1 -1
  47. package/dist/cjs/lib/v3/types/public/agent.d.ts +2 -3
  48. package/dist/cjs/lib/v3/types/public/agent.js +3 -0
  49. package/dist/cjs/lib/v3/types/public/agent.js.map +1 -1
  50. package/dist/cjs/lib/v3/types/public/api.d.ts +7 -1
  51. package/dist/cjs/lib/v3/types/public/api.js +22 -2
  52. package/dist/cjs/lib/v3/types/public/api.js.map +1 -1
  53. package/dist/cjs/lib/v3/types/public/methods.d.ts +2 -0
  54. package/dist/cjs/lib/v3/types/public/methods.js.map +1 -1
  55. package/dist/cjs/lib/v3/understudy/a11y/snapshot/a11yTree.js +21 -12
  56. package/dist/cjs/lib/v3/understudy/a11y/snapshot/a11yTree.js.map +1 -1
  57. package/dist/cjs/lib/v3/understudy/a11y/snapshot/capture.d.ts +11 -2
  58. package/dist/cjs/lib/v3/understudy/a11y/snapshot/capture.js +268 -21
  59. package/dist/cjs/lib/v3/understudy/a11y/snapshot/capture.js.map +1 -1
  60. package/dist/cjs/lib/v3/understudy/a11y/snapshot/domTree.js +60 -7
  61. package/dist/cjs/lib/v3/understudy/a11y/snapshot/domTree.js.map +1 -1
  62. package/dist/cjs/lib/v3/understudy/frameRegistry.js +16 -5
  63. package/dist/cjs/lib/v3/understudy/frameRegistry.js.map +1 -1
  64. package/dist/cjs/lib/v3/v3.d.ts +1 -0
  65. package/dist/cjs/lib/v3/v3.js +18 -14
  66. package/dist/cjs/lib/v3/v3.js.map +1 -1
  67. package/dist/cjs/lib/version.d.ts +1 -1
  68. package/dist/cjs/lib/version.js +1 -1
  69. package/dist/cjs/lib/version.js.map +1 -1
  70. package/dist/cjs/tests/integration/observe-element-id-format.spec.js +130 -0
  71. package/dist/cjs/tests/integration/observe-element-id-format.spec.js.map +1 -0
  72. package/dist/cjs/tests/unit/agent-mode-routing.test.js +88 -0
  73. package/dist/cjs/tests/unit/agent-mode-routing.test.js.map +1 -0
  74. package/dist/cjs/tests/unit/agent-temperature.test.d.ts +1 -0
  75. package/dist/cjs/tests/unit/agent-temperature.test.js +191 -0
  76. package/dist/cjs/tests/unit/agent-temperature.test.js.map +1 -0
  77. package/dist/cjs/tests/unit/agent-variables-validation.test.d.ts +1 -0
  78. package/dist/cjs/tests/unit/agent-variables-validation.test.js +43 -0
  79. package/dist/cjs/tests/unit/agent-variables-validation.test.js.map +1 -0
  80. package/dist/cjs/tests/unit/api-client-observe-variables.test.js +49 -0
  81. package/dist/cjs/tests/unit/api-client-observe-variables.test.js.map +1 -1
  82. package/dist/cjs/tests/unit/api-optional-model-api-key.test.js +60 -0
  83. package/dist/cjs/tests/unit/api-optional-model-api-key.test.js.map +1 -1
  84. package/dist/cjs/tests/unit/api-variables-schema.test.js +32 -0
  85. package/dist/cjs/tests/unit/api-variables-schema.test.js.map +1 -1
  86. package/dist/cjs/tests/unit/frame-registry-oopif-adoption.test.d.ts +1 -0
  87. package/dist/cjs/tests/unit/frame-registry-oopif-adoption.test.js +60 -0
  88. package/dist/cjs/tests/unit/frame-registry-oopif-adoption.test.js.map +1 -0
  89. package/dist/cjs/tests/unit/inference-temperature.test.d.ts +1 -0
  90. package/dist/cjs/tests/unit/inference-temperature.test.js +65 -0
  91. package/dist/cjs/tests/unit/inference-temperature.test.js.map +1 -0
  92. package/dist/cjs/tests/unit/openai-compatible-temperature.test.d.ts +1 -0
  93. package/dist/cjs/tests/unit/openai-compatible-temperature.test.js +84 -0
  94. package/dist/cjs/tests/unit/openai-compatible-temperature.test.js.map +1 -0
  95. package/dist/cjs/tests/unit/prompt-observe-variables.test.js +6 -0
  96. package/dist/cjs/tests/unit/prompt-observe-variables.test.js.map +1 -1
  97. package/dist/cjs/tests/unit/public-api/llm-and-agents.test.js +3 -0
  98. package/dist/cjs/tests/unit/public-api/llm-and-agents.test.js.map +1 -1
  99. package/dist/cjs/tests/unit/public-api/public-types.test.js.map +1 -1
  100. package/dist/cjs/tests/unit/snapshot-a11y-resolvers.test.js +106 -5
  101. package/dist/cjs/tests/unit/snapshot-a11y-resolvers.test.js.map +1 -1
  102. package/dist/cjs/tests/unit/snapshot-a11y-tree-utils.test.js +20 -0
  103. package/dist/cjs/tests/unit/snapshot-a11y-tree-utils.test.js.map +1 -1
  104. package/dist/cjs/tests/unit/snapshot-capture-orchestration.test.js +119 -9
  105. package/dist/cjs/tests/unit/snapshot-capture-orchestration.test.js.map +1 -1
  106. package/dist/cjs/tests/unit/timeout-handlers.test.js +36 -0
  107. package/dist/cjs/tests/unit/timeout-handlers.test.js.map +1 -1
  108. package/dist/esm/lib/inference.js +2 -9
  109. package/dist/esm/lib/inference.js.map +1 -1
  110. package/dist/esm/lib/prompt.js +3 -1
  111. package/dist/esm/lib/prompt.js.map +1 -1
  112. package/dist/esm/lib/v3/agent/AgentProvider.js +3 -0
  113. package/dist/esm/lib/v3/agent/AgentProvider.js.map +1 -1
  114. package/dist/esm/lib/v3/agent/tools/fillFormVision.js +16 -12
  115. package/dist/esm/lib/v3/agent/tools/fillFormVision.js.map +1 -1
  116. package/dist/esm/lib/v3/agent/utils/validateExperimentalFeatures.js +0 -4
  117. package/dist/esm/lib/v3/agent/utils/validateExperimentalFeatures.js.map +1 -1
  118. package/dist/esm/lib/v3/api.d.ts +1 -0
  119. package/dist/esm/lib/v3/api.js +15 -3
  120. package/dist/esm/lib/v3/api.js.map +1 -1
  121. package/dist/esm/lib/v3/dom/build/a11yScripts.generated.js +1 -1
  122. package/dist/esm/lib/v3/dom/build/a11yScripts.generated.js.map +1 -1
  123. package/dist/esm/lib/v3/dom/build/locatorScripts.generated.js +1 -1
  124. package/dist/esm/lib/v3/dom/build/locatorScripts.generated.js.map +1 -1
  125. package/dist/esm/lib/v3/dom/build/reRenderScriptContent.d.ts +1 -1
  126. package/dist/esm/lib/v3/dom/build/reRenderScriptContent.js +1 -1
  127. package/dist/esm/lib/v3/dom/build/reRenderScriptContent.js.map +1 -1
  128. package/dist/esm/lib/v3/dom/build/screenshotScripts.generated.js +1 -1
  129. package/dist/esm/lib/v3/dom/build/screenshotScripts.generated.js.map +1 -1
  130. package/dist/esm/lib/v3/dom/build/scriptV3Content.d.ts +1 -1
  131. package/dist/esm/lib/v3/dom/build/scriptV3Content.js +1 -1
  132. package/dist/esm/lib/v3/dom/build/scriptV3Content.js.map +1 -1
  133. package/dist/esm/lib/v3/dom/build/selectorRuntime.generated.d.ts +24 -0
  134. package/dist/esm/lib/v3/dom/build/selectorRuntime.generated.js +28 -0
  135. package/dist/esm/lib/v3/dom/build/selectorRuntime.generated.js.map +1 -0
  136. package/dist/esm/lib/v3/handlers/extractHandler.js +3 -1
  137. package/dist/esm/lib/v3/handlers/extractHandler.js.map +1 -1
  138. package/dist/esm/lib/v3/handlers/observeHandler.js +2 -1
  139. package/dist/esm/lib/v3/handlers/observeHandler.js.map +1 -1
  140. package/dist/esm/lib/v3/handlers/v3AgentHandler.js +3 -5
  141. package/dist/esm/lib/v3/handlers/v3AgentHandler.js.map +1 -1
  142. package/dist/esm/lib/v3/index.d.ts +1 -1
  143. package/dist/esm/lib/v3/llm/CerebrasClient.js +1 -1
  144. package/dist/esm/lib/v3/llm/CerebrasClient.js.map +1 -1
  145. package/dist/esm/lib/v3/llm/GroqClient.js +1 -1
  146. package/dist/esm/lib/v3/llm/GroqClient.js.map +1 -1
  147. package/dist/esm/lib/v3/types/private/agent.d.ts +5 -0
  148. package/dist/esm/lib/v3/types/private/agent.js +10 -1
  149. package/dist/esm/lib/v3/types/private/agent.js.map +1 -1
  150. package/dist/esm/lib/v3/types/private/handlers.d.ts +2 -0
  151. package/dist/esm/lib/v3/types/private/handlers.js.map +1 -1
  152. package/dist/esm/lib/v3/types/private/snapshot.d.ts +8 -0
  153. package/dist/esm/lib/v3/types/private/snapshot.js.map +1 -1
  154. package/dist/esm/lib/v3/types/public/agent.d.ts +2 -3
  155. package/dist/esm/lib/v3/types/public/agent.js +3 -0
  156. package/dist/esm/lib/v3/types/public/agent.js.map +1 -1
  157. package/dist/esm/lib/v3/types/public/api.d.ts +7 -1
  158. package/dist/esm/lib/v3/types/public/api.js +22 -2
  159. package/dist/esm/lib/v3/types/public/api.js.map +1 -1
  160. package/dist/esm/lib/v3/types/public/methods.d.ts +2 -0
  161. package/dist/esm/lib/v3/types/public/methods.js.map +1 -1
  162. package/dist/esm/lib/v3/understudy/a11y/snapshot/a11yTree.js +21 -12
  163. package/dist/esm/lib/v3/understudy/a11y/snapshot/a11yTree.js.map +1 -1
  164. package/dist/esm/lib/v3/understudy/a11y/snapshot/capture.d.ts +11 -2
  165. package/dist/esm/lib/v3/understudy/a11y/snapshot/capture.js +267 -22
  166. package/dist/esm/lib/v3/understudy/a11y/snapshot/capture.js.map +1 -1
  167. package/dist/esm/lib/v3/understudy/a11y/snapshot/domTree.js +60 -7
  168. package/dist/esm/lib/v3/understudy/a11y/snapshot/domTree.js.map +1 -1
  169. package/dist/esm/lib/v3/understudy/frameRegistry.js +16 -5
  170. package/dist/esm/lib/v3/understudy/frameRegistry.js.map +1 -1
  171. package/dist/esm/lib/v3/v3.d.ts +1 -0
  172. package/dist/esm/lib/v3/v3.js +18 -14
  173. package/dist/esm/lib/v3/v3.js.map +1 -1
  174. package/dist/esm/lib/version.d.ts +1 -1
  175. package/dist/esm/lib/version.js +1 -1
  176. package/dist/esm/lib/version.js.map +1 -1
  177. package/dist/esm/tests/integration/observe-element-id-format.spec.d.ts +1 -0
  178. package/dist/esm/tests/integration/observe-element-id-format.spec.js +128 -0
  179. package/dist/esm/tests/integration/observe-element-id-format.spec.js.map +1 -0
  180. package/dist/esm/tests/unit/agent-mode-routing.test.d.ts +1 -0
  181. package/dist/esm/tests/unit/agent-mode-routing.test.js +86 -0
  182. package/dist/esm/tests/unit/agent-mode-routing.test.js.map +1 -0
  183. package/dist/esm/tests/unit/agent-temperature.test.d.ts +1 -0
  184. package/dist/esm/tests/unit/agent-temperature.test.js +189 -0
  185. package/dist/esm/tests/unit/agent-temperature.test.js.map +1 -0
  186. package/dist/esm/tests/unit/agent-variables-validation.test.d.ts +1 -0
  187. package/dist/esm/tests/unit/agent-variables-validation.test.js +41 -0
  188. package/dist/esm/tests/unit/agent-variables-validation.test.js.map +1 -0
  189. package/dist/esm/tests/unit/api-client-observe-variables.test.js +49 -0
  190. package/dist/esm/tests/unit/api-client-observe-variables.test.js.map +1 -1
  191. package/dist/esm/tests/unit/api-optional-model-api-key.test.js +60 -0
  192. package/dist/esm/tests/unit/api-optional-model-api-key.test.js.map +1 -1
  193. package/dist/esm/tests/unit/api-variables-schema.test.js +32 -0
  194. package/dist/esm/tests/unit/api-variables-schema.test.js.map +1 -1
  195. package/dist/esm/tests/unit/frame-registry-oopif-adoption.test.d.ts +1 -0
  196. package/dist/esm/tests/unit/frame-registry-oopif-adoption.test.js +58 -0
  197. package/dist/esm/tests/unit/frame-registry-oopif-adoption.test.js.map +1 -0
  198. package/dist/esm/tests/unit/inference-temperature.test.d.ts +1 -0
  199. package/dist/esm/tests/unit/inference-temperature.test.js +63 -0
  200. package/dist/esm/tests/unit/inference-temperature.test.js.map +1 -0
  201. package/dist/esm/tests/unit/openai-compatible-temperature.test.d.ts +1 -0
  202. package/dist/esm/tests/unit/openai-compatible-temperature.test.js +82 -0
  203. package/dist/esm/tests/unit/openai-compatible-temperature.test.js.map +1 -0
  204. package/dist/esm/tests/unit/prompt-observe-variables.test.js +6 -0
  205. package/dist/esm/tests/unit/prompt-observe-variables.test.js.map +1 -1
  206. package/dist/esm/tests/unit/public-api/llm-and-agents.test.js +3 -0
  207. package/dist/esm/tests/unit/public-api/llm-and-agents.test.js.map +1 -1
  208. package/dist/esm/tests/unit/public-api/public-types.test.js.map +1 -1
  209. package/dist/esm/tests/unit/snapshot-a11y-resolvers.test.js +106 -5
  210. package/dist/esm/tests/unit/snapshot-a11y-resolvers.test.js.map +1 -1
  211. package/dist/esm/tests/unit/snapshot-a11y-tree-utils.test.js +20 -0
  212. package/dist/esm/tests/unit/snapshot-a11y-tree-utils.test.js.map +1 -1
  213. package/dist/esm/tests/unit/snapshot-capture-orchestration.test.js +119 -9
  214. package/dist/esm/tests/unit/snapshot-capture-orchestration.test.js.map +1 -1
  215. package/dist/esm/tests/unit/timeout-handlers.test.js +36 -0
  216. package/dist/esm/tests/unit/timeout-handlers.test.js.map +1 -1
  217. package/package.json +3 -3
  218. package/dist/cjs/tests/integration/agent-captcha-autosolve.spec.js +0 -56
  219. package/dist/cjs/tests/integration/agent-captcha-autosolve.spec.js.map +0 -1
  220. package/dist/esm/tests/integration/agent-captcha-autosolve.spec.js +0 -54
  221. package/dist/esm/tests/integration/agent-captcha-autosolve.spec.js.map +0 -1
  222. /package/dist/cjs/tests/integration/{agent-captcha-autosolve.spec.d.ts → observe-element-id-format.spec.d.ts} +0 -0
  223. /package/dist/{esm/tests/integration/agent-captcha-autosolve.spec.d.ts → cjs/tests/unit/agent-mode-routing.test.d.ts} +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"methods.js","sourceRoot":"","sources":["../../../../../../lib/v3/types/public/methods.ts"],"names":[],"mappings":";;;AAGA,6BAAwB;AA8DX,QAAA,oBAAoB,GAAG,OAAC,CAAC,MAAM,CAAC;IAC3C,UAAU,EAAE,OAAC,CAAC,MAAM,EAAE;CACvB,CAAC,CAAC;AAEU,QAAA,cAAc,GAAG,OAAC,CAAC,MAAM,CAAC;IACrC,QAAQ,EAAE,OAAC,CAAC,MAAM,EAAE;CACrB,CAAC,CAAC;AAwBH,IAAY,cAKX;AALD,WAAY,cAAc;IACxB,6BAAW,CAAA;IACX,qCAAmB,CAAA;IACnB,qCAAmB,CAAA;IACnB,iCAAe,CAAA;AACjB,CAAC,EALW,cAAc,8BAAd,cAAc,QAKzB","sourcesContent":["import { Page as PatchrightPage } from \"patchright-core\";\nimport { Page as PlaywrightPage } from \"playwright-core\";\nimport { Page as PuppeteerPage } from \"puppeteer-core\";\nimport { z } from \"zod\";\nimport type {\n InferStagehandSchema,\n StagehandZodSchema,\n} from \"../../zodCompat.js\";\nimport { Page } from \"../../understudy/page.js\";\nimport { ModelConfiguration } from \"../public/model.js\";\nimport type { Variables } from \"./agent.js\";\n\nexport interface ActOptions {\n model?: ModelConfiguration;\n variables?: Variables;\n timeout?: number;\n page?: PlaywrightPage | PuppeteerPage | PatchrightPage | Page;\n /**\n * Override the instance-level serverCache setting for this request.\n * When true, enables server-side caching.\n * When false, disables server-side caching.\n */\n serverCache?: boolean;\n}\n\nexport interface ActResult {\n success: boolean;\n message: string;\n actionDescription: string;\n actions: Action[];\n cacheStatus?: \"HIT\" | \"MISS\";\n}\n\nexport type ExtractResult<T extends StagehandZodSchema> =\n InferStagehandSchema<T> & {\n cacheStatus?: \"HIT\" | \"MISS\";\n };\n\nexport interface Action {\n selector: string;\n description: string;\n method?: string;\n arguments?: string[];\n}\n\nexport interface HistoryEntry {\n method: \"act\" | \"extract\" | \"observe\" | \"navigate\" | \"agent\";\n parameters: unknown;\n result: unknown;\n timestamp: string;\n}\n\nexport interface ExtractOptions {\n model?: ModelConfiguration;\n timeout?: number;\n selector?: string;\n page?: PlaywrightPage | PuppeteerPage | PatchrightPage | Page;\n /**\n * Override the instance-level serverCache setting for this request.\n * When true, enables server-side caching.\n * When false, disables server-side caching.\n */\n serverCache?: boolean;\n}\n\nexport const defaultExtractSchema = z.object({\n extraction: z.string(),\n});\n\nexport const pageTextSchema = z.object({\n pageText: z.string(),\n});\n\nexport interface ObserveOptions {\n model?: ModelConfiguration;\n variables?: Variables;\n timeout?: number;\n selector?: string;\n page?: PlaywrightPage | PuppeteerPage | PatchrightPage | Page;\n /**\n * Override the instance-level serverCache setting for this request.\n * When true, enables server-side caching.\n * When false, disables server-side caching.\n */\n serverCache?: boolean;\n}\n\n/**\n * Observe returns an array of candidate actions. The optional `cacheStatus`\n * property is attached when the server responds with a\n * `browserbase-cache-status` header so callers can tell whether the result\n * was served from the server-side cache.\n */\nexport type ObserveResult = Action[] & { cacheStatus?: \"HIT\" | \"MISS\" };\n\nexport enum V3FunctionName {\n ACT = \"ACT\",\n EXTRACT = \"EXTRACT\",\n OBSERVE = \"OBSERVE\",\n AGENT = \"AGENT\",\n}\n"]}
1
+ {"version":3,"file":"methods.js","sourceRoot":"","sources":["../../../../../../lib/v3/types/public/methods.ts"],"names":[],"mappings":";;;AAGA,6BAAwB;AA+DX,QAAA,oBAAoB,GAAG,OAAC,CAAC,MAAM,CAAC;IAC3C,UAAU,EAAE,OAAC,CAAC,MAAM,EAAE;CACvB,CAAC,CAAC;AAEU,QAAA,cAAc,GAAG,OAAC,CAAC,MAAM,CAAC;IACrC,QAAQ,EAAE,OAAC,CAAC,MAAM,EAAE;CACrB,CAAC,CAAC;AAyBH,IAAY,cAKX;AALD,WAAY,cAAc;IACxB,6BAAW,CAAA;IACX,qCAAmB,CAAA;IACnB,qCAAmB,CAAA;IACnB,iCAAe,CAAA;AACjB,CAAC,EALW,cAAc,8BAAd,cAAc,QAKzB","sourcesContent":["import { Page as PatchrightPage } from \"patchright-core\";\nimport { Page as PlaywrightPage } from \"playwright-core\";\nimport { Page as PuppeteerPage } from \"puppeteer-core\";\nimport { z } from \"zod\";\nimport type {\n InferStagehandSchema,\n StagehandZodSchema,\n} from \"../../zodCompat.js\";\nimport { Page } from \"../../understudy/page.js\";\nimport { ModelConfiguration } from \"../public/model.js\";\nimport type { Variables } from \"./agent.js\";\n\nexport interface ActOptions {\n model?: ModelConfiguration;\n variables?: Variables;\n timeout?: number;\n page?: PlaywrightPage | PuppeteerPage | PatchrightPage | Page;\n /**\n * Override the instance-level serverCache setting for this request.\n * When true, enables server-side caching.\n * When false, disables server-side caching.\n */\n serverCache?: boolean;\n}\n\nexport interface ActResult {\n success: boolean;\n message: string;\n actionDescription: string;\n actions: Action[];\n cacheStatus?: \"HIT\" | \"MISS\";\n}\n\nexport type ExtractResult<T extends StagehandZodSchema> =\n InferStagehandSchema<T> & {\n cacheStatus?: \"HIT\" | \"MISS\";\n };\n\nexport interface Action {\n selector: string;\n description: string;\n method?: string;\n arguments?: string[];\n}\n\nexport interface HistoryEntry {\n method: \"act\" | \"extract\" | \"observe\" | \"navigate\" | \"agent\";\n parameters: unknown;\n result: unknown;\n timestamp: string;\n}\n\nexport interface ExtractOptions {\n model?: ModelConfiguration;\n timeout?: number;\n selector?: string;\n ignoreSelectors?: string[];\n page?: PlaywrightPage | PuppeteerPage | PatchrightPage | Page;\n /**\n * Override the instance-level serverCache setting for this request.\n * When true, enables server-side caching.\n * When false, disables server-side caching.\n */\n serverCache?: boolean;\n}\n\nexport const defaultExtractSchema = z.object({\n extraction: z.string(),\n});\n\nexport const pageTextSchema = z.object({\n pageText: z.string(),\n});\n\nexport interface ObserveOptions {\n model?: ModelConfiguration;\n variables?: Variables;\n timeout?: number;\n selector?: string;\n ignoreSelectors?: string[];\n page?: PlaywrightPage | PuppeteerPage | PatchrightPage | Page;\n /**\n * Override the instance-level serverCache setting for this request.\n * When true, enables server-side caching.\n * When false, disables server-side caching.\n */\n serverCache?: boolean;\n}\n\n/**\n * Observe returns an array of candidate actions. The optional `cacheStatus`\n * property is attached when the server responds with a\n * `browserbase-cache-status` header so callers can tell whether the result\n * was served from the server-side cache.\n */\nexport type ObserveResult = Action[] & { cacheStatus?: \"HIT\" | \"MISS\" };\n\nexport enum V3FunctionName {\n ACT = \"ACT\",\n EXTRACT = \"EXTRACT\",\n OBSERVE = \"OBSERVE\",\n AGENT = \"AGENT\",\n}\n"]}
@@ -30,17 +30,6 @@ async function a11yForFrame(session, frameId, opts) {
30
30
  throw e;
31
31
  ({ nodes } = await session.send("Accessibility.getFullAXTree"));
32
32
  }
33
- const urlMap = {};
34
- for (const n of nodes) {
35
- const be = n.backendDOMNodeId;
36
- if (typeof be !== "number")
37
- continue;
38
- const url = extractUrlFromAXNode(n);
39
- if (!url)
40
- continue;
41
- const enc = opts.encode(be);
42
- urlMap[enc] = url;
43
- }
44
33
  let scopeApplied = false;
45
34
  const nodesForOutline = await (async () => {
46
35
  const sel = opts.focusSelector?.trim();
@@ -82,7 +71,22 @@ async function a11yForFrame(session, frameId, opts) {
82
71
  return nodes;
83
72
  }
84
73
  })();
85
- const decorated = decorateRoles(nodesForOutline, opts);
74
+ const filteredNodes = nodesForOutline.filter((node) => {
75
+ const be = node.backendDOMNodeId;
76
+ return typeof be !== "number" || !opts.isIgnoredBackendNode?.(be);
77
+ });
78
+ const urlMap = {};
79
+ for (const n of filteredNodes) {
80
+ const be = n.backendDOMNodeId;
81
+ if (typeof be !== "number")
82
+ continue;
83
+ const url = extractUrlFromAXNode(n);
84
+ if (!url)
85
+ continue;
86
+ const enc = opts.encode(be);
87
+ urlMap[enc] = url;
88
+ }
89
+ const decorated = decorateRoles(filteredNodes, opts);
86
90
  const { tree } = await buildHierarchicalTree(decorated, opts);
87
91
  const simplified = tree.map((n) => (0, treeFormatUtils_js_1.formatTreeLine)(n)).join("\n");
88
92
  return { outline: simplified.trimEnd(), urlMap, scopeApplied };
@@ -111,6 +115,11 @@ function decorateRoles(nodes, opts) {
111
115
  ? `scrollable, ${tagLabel}`
112
116
  : `scrollable${role ? `, ${role}` : ""}`;
113
117
  }
118
+ // File inputs typically get role "button" from Chrome's AX tree;
119
+ // override so they appear as "input, file" in the outline.
120
+ if (tag === "input, file") {
121
+ role = tag;
122
+ }
114
123
  return {
115
124
  role,
116
125
  name: n.name?.value,
@@ -1 +1 @@
1
- {"version":3,"file":"a11yTree.js","sourceRoot":"","sources":["../../../../../../../lib/v3/understudy/a11y/snapshot/a11yTree.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Protocol } from \"devtools-protocol\";\nimport type { CDPSessionLike } from \"../../cdp.js\";\nimport type {\n A11yNode,\n A11yOptions,\n AccessibilityTreeResult,\n} from \"../../../types/private/snapshot.js\";\nimport {\n resolveObjectIdForCss,\n resolveObjectIdForXPath,\n} from \"./focusSelectors.js\";\nimport { formatTreeLine, normaliseSpaces } from \"./treeFormatUtils.js\";\n\n/**\n * Fetch and prune the accessibility tree for a frame, optionally scoping the\n * output to a selector root for faster targeted snapshots.\n */\nexport async function a11yForFrame(\n session: CDPSessionLike,\n frameId: string | undefined,\n opts: A11yOptions,\n): Promise<AccessibilityTreeResult> {\n await session.send(\"Accessibility.enable\").catch(() => {});\n await session.send(\"Runtime.enable\").catch(() => {});\n await session.send(\"DOM.enable\").catch(() => {});\n\n let nodes: Protocol.Accessibility.AXNode[] = [];\n try {\n const params = frameId ? ({ frameId } as Record<string, unknown>) : {};\n ({ nodes } = await session.send<{\n nodes: Protocol.Accessibility.AXNode[];\n }>(\"Accessibility.getFullAXTree\", params));\n } catch (e) {\n const msg = String((e as Error)?.message ?? e ?? \"\");\n const isFrameScopeError =\n msg.includes(\"Frame with the given\") ||\n msg.includes(\"does not belong to the target\") ||\n msg.includes(\"is not found\");\n if (!isFrameScopeError || !frameId) throw e;\n ({ nodes } = await session.send<{\n nodes: Protocol.Accessibility.AXNode[];\n }>(\"Accessibility.getFullAXTree\"));\n }\n\n const urlMap: Record<string, string> = {};\n for (const n of nodes) {\n const be = n.backendDOMNodeId;\n if (typeof be !== \"number\") continue;\n const url = extractUrlFromAXNode(n);\n if (!url) continue;\n const enc = opts.encode(be);\n urlMap[enc] = url;\n }\n\n let scopeApplied = false;\n const nodesForOutline = await (async () => {\n const sel = opts.focusSelector?.trim();\n if (!sel) return nodes;\n try {\n const looksLikeXPath = /^xpath=/i.test(sel) || sel.startsWith(\"/\");\n const objectId = looksLikeXPath\n ? await resolveObjectIdForXPath(session, sel, frameId)\n : await resolveObjectIdForCss(session, sel, frameId);\n if (!objectId) return nodes;\n const desc = await session.send<{ node?: { backendNodeId?: number } }>(\n \"DOM.describeNode\",\n { objectId },\n );\n const be = desc.node?.backendNodeId;\n if (typeof be !== \"number\") return nodes;\n const target = nodes.find((n) => n.backendDOMNodeId === be);\n if (!target) return nodes;\n scopeApplied = true;\n const keep = new Set<string>([target.nodeId]);\n const queue: Protocol.Accessibility.AXNode[] = [target];\n while (queue.length) {\n const cur = queue.shift()!;\n for (const id of cur.childIds ?? []) {\n if (keep.has(id)) continue;\n keep.add(id);\n const child = nodes.find((n) => n.nodeId === id);\n if (child) queue.push(child);\n }\n }\n return nodes\n .filter((n) => keep.has(n.nodeId))\n .map((n) =>\n n.nodeId === target.nodeId ? { ...n, parentId: undefined } : n,\n );\n } catch {\n return nodes;\n }\n })();\n\n const decorated = decorateRoles(nodesForOutline, opts);\n const { tree } = await buildHierarchicalTree(decorated, opts);\n\n const simplified = tree.map((n) => formatTreeLine(n)).join(\"\\n\");\n return { outline: simplified.trimEnd(), urlMap, scopeApplied };\n}\n\nexport function decorateRoles(\n nodes: Protocol.Accessibility.AXNode[],\n opts: A11yOptions,\n): A11yNode[] {\n const asRole = (n: Protocol.Accessibility.AXNode) =>\n String(n.role?.value ?? \"\");\n\n return nodes.map((n) => {\n let encodedId: string | undefined;\n if (typeof n.backendDOMNodeId === \"number\") {\n try {\n encodedId = opts.encode(n.backendDOMNodeId);\n } catch {\n //\n }\n }\n\n let role = asRole(n);\n\n const domIsScrollable = encodedId\n ? opts.scrollableMap[encodedId] === true\n : false;\n const tag = encodedId ? opts.tagNameMap[encodedId] : undefined;\n const isHtmlElement = tag === \"html\";\n if ((domIsScrollable || isHtmlElement) && tag !== \"#document\") {\n const tagLabel = tag && tag.startsWith(\"#\") ? tag.slice(1) : tag;\n role = tagLabel\n ? `scrollable, ${tagLabel}`\n : `scrollable${role ? `, ${role}` : \"\"}`;\n }\n\n return {\n role,\n name: n.name?.value,\n description: n.description?.value,\n value: n.value?.value,\n nodeId: n.nodeId,\n backendDOMNodeId: n.backendDOMNodeId,\n parentId: n.parentId,\n childIds: n.childIds,\n encodedId,\n };\n });\n}\n\nexport async function buildHierarchicalTree(\n nodes: A11yNode[],\n opts: A11yOptions,\n): Promise<{ tree: A11yNode[] }> {\n const nodeMap = new Map<string, A11yNode>();\n\n for (const n of nodes) {\n const keep =\n !!(n.name && n.name.trim()) ||\n !!(n.childIds && n.childIds.length) ||\n !isStructural(n.role);\n if (!keep) continue;\n nodeMap.set(n.nodeId, { ...n });\n }\n\n for (const n of nodes) {\n if (!n.parentId) continue;\n const parent = nodeMap.get(n.parentId);\n const cur = nodeMap.get(n.nodeId);\n if (parent && cur) (parent.children ??= []).push(cur);\n }\n\n const roots = nodes\n .filter((n) => !n.parentId && nodeMap.has(n.nodeId))\n .map((n) => nodeMap.get(n.nodeId)!) as A11yNode[];\n\n const cleaned = (await Promise.all(roots.map(pruneStructuralSafe))).filter(\n Boolean,\n ) as A11yNode[];\n\n return { tree: cleaned };\n\n async function pruneStructuralSafe(node: A11yNode): Promise<A11yNode | null> {\n if (+node.nodeId < 0) return null;\n\n const children = node.children ?? [];\n if (!children.length) {\n return isStructural(node.role) ? null : node;\n }\n\n const cleanedKids = (\n await Promise.all(children.map(pruneStructuralSafe))\n ).filter(Boolean) as A11yNode[];\n\n const prunedStatic = removeRedundantStaticTextChildren(node, cleanedKids);\n\n if (isStructural(node.role)) {\n if (prunedStatic.length === 1) return prunedStatic[0]!;\n if (prunedStatic.length === 0) return null;\n }\n\n let newRole = node.role;\n if ((newRole === \"generic\" || newRole === \"none\") && node.encodedId) {\n const tagName = opts.tagNameMap[node.encodedId];\n if (tagName) newRole = tagName;\n }\n\n if (newRole === \"combobox\" && node.encodedId) {\n const tagName = opts.tagNameMap[node.encodedId];\n if (tagName === \"select\") newRole = \"select\";\n }\n\n return { ...node, role: newRole, children: prunedStatic };\n }\n}\n\nexport function isStructural(role: string): boolean {\n const r = role?.toLowerCase();\n return r === \"generic\" || r === \"none\" || r === \"inlinetextbox\";\n}\n\nexport function extractUrlFromAXNode(\n ax: Protocol.Accessibility.AXNode,\n): string | undefined {\n const props = ax.properties ?? [];\n const urlProp = props.find((p) => p.name === \"url\");\n const value = urlProp?.value?.value;\n return typeof value === \"string\" && value.trim() ? value.trim() : undefined;\n}\n\nexport function removeRedundantStaticTextChildren(\n parent: A11yNode,\n children: A11yNode[],\n): A11yNode[] {\n if (!parent.name) return children;\n const parentNorm = normaliseSpaces(parent.name).trim();\n let combined = \"\";\n for (const c of children) {\n if (c.role === \"StaticText\" && c.name) {\n combined += normaliseSpaces(c.name).trim();\n }\n }\n if (combined === parentNorm) {\n return children.filter((c) => c.role !== \"StaticText\");\n }\n return children;\n}\n"]}
1
+ {"version":3,"file":"a11yTree.js","sourceRoot":"","sources":["../../../../../../../lib/v3/understudy/a11y/snapshot/a11yTree.ts"],"names":[],"mappings":";;AAiBA,oCAuFC;AAED,sCAiDC;AAED,sDAgEC;AAED,oCAGC;AAED,oDAOC;AAED,8EAgBC;AAtPD,2DAG6B;AAC7B,6DAAuE;AAEvE;;;GAGG;AACI,KAAK,UAAU,YAAY,CAChC,OAAuB,EACvB,OAA2B,EAC3B,IAAiB;IAEjB,MAAM,OAAO,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IAC3D,MAAM,OAAO,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IACrD,MAAM,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IAEjD,IAAI,KAAK,GAAoC,EAAE,CAAC;IAChD,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,OAAO,CAAC,CAAC,CAAE,EAAE,OAAO,EAA8B,CAAC,CAAC,CAAC,EAAE,CAAC;QACvE,CAAC,EAAE,KAAK,EAAE,GAAG,MAAM,OAAO,CAAC,IAAI,CAE5B,6BAA6B,EAAE,MAAM,CAAC,CAAC,CAAC;IAC7C,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,MAAM,GAAG,GAAG,MAAM,CAAE,CAAW,EAAE,OAAO,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QACrD,MAAM,iBAAiB,GACrB,GAAG,CAAC,QAAQ,CAAC,sBAAsB,CAAC;YACpC,GAAG,CAAC,QAAQ,CAAC,+BAA+B,CAAC;YAC7C,GAAG,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC;QAC/B,IAAI,CAAC,iBAAiB,IAAI,CAAC,OAAO;YAAE,MAAM,CAAC,CAAC;QAC5C,CAAC,EAAE,KAAK,EAAE,GAAG,MAAM,OAAO,CAAC,IAAI,CAE5B,6BAA6B,CAAC,CAAC,CAAC;IACrC,CAAC;IAED,IAAI,YAAY,GAAG,KAAK,CAAC;IACzB,MAAM,eAAe,GAAG,MAAM,CAAC,KAAK,IAAI,EAAE;QACxC,MAAM,GAAG,GAAG,IAAI,CAAC,aAAa,EAAE,IAAI,EAAE,CAAC;QACvC,IAAI,CAAC,GAAG;YAAE,OAAO,KAAK,CAAC;QACvB,IAAI,CAAC;YACH,MAAM,cAAc,GAAG,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;YACnE,MAAM,QAAQ,GAAG,cAAc;gBAC7B,CAAC,CAAC,MAAM,IAAA,2CAAuB,EAAC,OAAO,EAAE,GAAG,EAAE,OAAO,CAAC;gBACtD,CAAC,CAAC,MAAM,IAAA,yCAAqB,EAAC,OAAO,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC;YACvD,IAAI,CAAC,QAAQ;gBAAE,OAAO,KAAK,CAAC;YAC5B,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,IAAI,CAC7B,kBAAkB,EAClB,EAAE,QAAQ,EAAE,CACb,CAAC;YACF,MAAM,EAAE,GAAG,IAAI,CAAC,IAAI,EAAE,aAAa,CAAC;YACpC,IAAI,OAAO,EAAE,KAAK,QAAQ;gBAAE,OAAO,KAAK,CAAC;YACzC,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,gBAAgB,KAAK,EAAE,CAAC,CAAC;YAC5D,IAAI,CAAC,MAAM;gBAAE,OAAO,KAAK,CAAC;YAC1B,YAAY,GAAG,IAAI,CAAC;YACpB,MAAM,IAAI,GAAG,IAAI,GAAG,CAAS,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;YAC9C,MAAM,KAAK,GAAoC,CAAC,MAAM,CAAC,CAAC;YACxD,OAAO,KAAK,CAAC,MAAM,EAAE,CAAC;gBACpB,MAAM,GAAG,GAAG,KAAK,CAAC,KAAK,EAAG,CAAC;gBAC3B,KAAK,MAAM,EAAE,IAAI,GAAG,CAAC,QAAQ,IAAI,EAAE,EAAE,CAAC;oBACpC,IAAI,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;wBAAE,SAAS;oBAC3B,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;oBACb,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,EAAE,CAAC,CAAC;oBACjD,IAAI,KAAK;wBAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBAC/B,CAAC;YACH,CAAC;YACD,OAAO,KAAK;iBACT,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;iBACjC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CACT,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,CAAC,CAC/D,CAAC;QACN,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC,CAAC,EAAE,CAAC;IAEL,MAAM,aAAa,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE;QACpD,MAAM,EAAE,GAAG,IAAI,CAAC,gBAAgB,CAAC;QACjC,OAAO,OAAO,EAAE,KAAK,QAAQ,IAAI,CAAC,IAAI,CAAC,oBAAoB,EAAE,CAAC,EAAE,CAAC,CAAC;IACpE,CAAC,CAAC,CAAC;IAEH,MAAM,MAAM,GAA2B,EAAE,CAAC;IAC1C,KAAK,MAAM,CAAC,IAAI,aAAa,EAAE,CAAC;QAC9B,MAAM,EAAE,GAAG,CAAC,CAAC,gBAAgB,CAAC;QAC9B,IAAI,OAAO,EAAE,KAAK,QAAQ;YAAE,SAAS;QACrC,MAAM,GAAG,GAAG,oBAAoB,CAAC,CAAC,CAAC,CAAC;QACpC,IAAI,CAAC,GAAG;YAAE,SAAS;QACnB,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAC5B,MAAM,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;IACpB,CAAC;IAED,MAAM,SAAS,GAAG,aAAa,CAAC,aAAa,EAAE,IAAI,CAAC,CAAC;IACrD,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,qBAAqB,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;IAE9D,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAA,mCAAc,EAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACjE,OAAO,EAAE,OAAO,EAAE,UAAU,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC;AACjE,CAAC;AAED,SAAgB,aAAa,CAC3B,KAAsC,EACtC,IAAiB;IAEjB,MAAM,MAAM,GAAG,CAAC,CAAgC,EAAE,EAAE,CAClD,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC;IAE9B,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QACrB,IAAI,SAA6B,CAAC;QAClC,IAAI,OAAO,CAAC,CAAC,gBAAgB,KAAK,QAAQ,EAAE,CAAC;YAC3C,IAAI,CAAC;gBACH,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC;YAC9C,CAAC;YAAC,MAAM,CAAC;gBACP,EAAE;YACJ,CAAC;QACH,CAAC;QAED,IAAI,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;QAErB,MAAM,eAAe,GAAG,SAAS;YAC/B,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC,KAAK,IAAI;YACxC,CAAC,CAAC,KAAK,CAAC;QACV,MAAM,GAAG,GAAG,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAC/D,MAAM,aAAa,GAAG,GAAG,KAAK,MAAM,CAAC;QACrC,IAAI,CAAC,eAAe,IAAI,aAAa,CAAC,IAAI,GAAG,KAAK,WAAW,EAAE,CAAC;YAC9D,MAAM,QAAQ,GAAG,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;YACjE,IAAI,GAAG,QAAQ;gBACb,CAAC,CAAC,eAAe,QAAQ,EAAE;gBAC3B,CAAC,CAAC,aAAa,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;QAC7C,CAAC;QAED,iEAAiE;QACjE,2DAA2D;QAC3D,IAAI,GAAG,KAAK,aAAa,EAAE,CAAC;YAC1B,IAAI,GAAG,GAAG,CAAC;QACb,CAAC;QAED,OAAO;YACL,IAAI;YACJ,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,KAAK;YACnB,WAAW,EAAE,CAAC,CAAC,WAAW,EAAE,KAAK;YACjC,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,KAAK;YACrB,MAAM,EAAE,CAAC,CAAC,MAAM;YAChB,gBAAgB,EAAE,CAAC,CAAC,gBAAgB;YACpC,QAAQ,EAAE,CAAC,CAAC,QAAQ;YACpB,QAAQ,EAAE,CAAC,CAAC,QAAQ;YACpB,SAAS;SACV,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC;AAEM,KAAK,UAAU,qBAAqB,CACzC,KAAiB,EACjB,IAAiB;IAEjB,MAAM,OAAO,GAAG,IAAI,GAAG,EAAoB,CAAC;IAE5C,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,MAAM,IAAI,GACR,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;YAC3B,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC;YACnC,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACxB,IAAI,CAAC,IAAI;YAAE,SAAS;QACpB,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;IAClC,CAAC;IAED,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,IAAI,CAAC,CAAC,CAAC,QAAQ;YAAE,SAAS;QAC1B,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;QACvC,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;QAClC,IAAI,MAAM,IAAI,GAAG;YAAE,CAAC,MAAM,CAAC,QAAQ,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACxD,CAAC;IAED,MAAM,KAAK,GAAG,KAAK;SAChB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,IAAI,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;SACnD,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAE,CAAe,CAAC;IAEpD,MAAM,OAAO,GAAG,CAAC,MAAM,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,MAAM,CACxE,OAAO,CACM,CAAC;IAEhB,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;IAEzB,KAAK,UAAU,mBAAmB,CAAC,IAAc;QAC/C,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,IAAI,CAAC;QAElC,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,EAAE,CAAC;QACrC,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;YACrB,OAAO,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;QAC/C,CAAC;QAED,MAAM,WAAW,GAAG,CAClB,MAAM,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC,CACrD,CAAC,MAAM,CAAC,OAAO,CAAe,CAAC;QAEhC,MAAM,YAAY,GAAG,iCAAiC,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;QAE1E,IAAI,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YAC5B,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO,YAAY,CAAC,CAAC,CAAE,CAAC;YACvD,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO,IAAI,CAAC;QAC7C,CAAC;QAED,IAAI,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC;QACxB,IAAI,CAAC,OAAO,KAAK,SAAS,IAAI,OAAO,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACpE,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YAChD,IAAI,OAAO;gBAAE,OAAO,GAAG,OAAO,CAAC;QACjC,CAAC;QAED,IAAI,OAAO,KAAK,UAAU,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YAC7C,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YAChD,IAAI,OAAO,KAAK,QAAQ;gBAAE,OAAO,GAAG,QAAQ,CAAC;QAC/C,CAAC;QAED,OAAO,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,CAAC;IAC5D,CAAC;AACH,CAAC;AAED,SAAgB,YAAY,CAAC,IAAY;IACvC,MAAM,CAAC,GAAG,IAAI,EAAE,WAAW,EAAE,CAAC;IAC9B,OAAO,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,MAAM,IAAI,CAAC,KAAK,eAAe,CAAC;AAClE,CAAC;AAED,SAAgB,oBAAoB,CAClC,EAAiC;IAEjC,MAAM,KAAK,GAAG,EAAE,CAAC,UAAU,IAAI,EAAE,CAAC;IAClC,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,KAAK,CAAC,CAAC;IACpD,MAAM,KAAK,GAAG,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC;IACpC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;AAC9E,CAAC;AAED,SAAgB,iCAAiC,CAC/C,MAAgB,EAChB,QAAoB;IAEpB,IAAI,CAAC,MAAM,CAAC,IAAI;QAAE,OAAO,QAAQ,CAAC;IAClC,MAAM,UAAU,GAAG,IAAA,oCAAe,EAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;IACvD,IAAI,QAAQ,GAAG,EAAE,CAAC;IAClB,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,IAAI,CAAC,CAAC,IAAI,KAAK,YAAY,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;YACtC,QAAQ,IAAI,IAAA,oCAAe,EAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;QAC7C,CAAC;IACH,CAAC;IACD,IAAI,QAAQ,KAAK,UAAU,EAAE,CAAC;QAC5B,OAAO,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,YAAY,CAAC,CAAC;IACzD,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC","sourcesContent":["import type { Protocol } from \"devtools-protocol\";\nimport type { CDPSessionLike } from \"../../cdp.js\";\nimport type {\n A11yNode,\n A11yOptions,\n AccessibilityTreeResult,\n} from \"../../../types/private/snapshot.js\";\nimport {\n resolveObjectIdForCss,\n resolveObjectIdForXPath,\n} from \"./focusSelectors.js\";\nimport { formatTreeLine, normaliseSpaces } from \"./treeFormatUtils.js\";\n\n/**\n * Fetch and prune the accessibility tree for a frame, optionally scoping the\n * output to a selector root for faster targeted snapshots.\n */\nexport async function a11yForFrame(\n session: CDPSessionLike,\n frameId: string | undefined,\n opts: A11yOptions,\n): Promise<AccessibilityTreeResult> {\n await session.send(\"Accessibility.enable\").catch(() => {});\n await session.send(\"Runtime.enable\").catch(() => {});\n await session.send(\"DOM.enable\").catch(() => {});\n\n let nodes: Protocol.Accessibility.AXNode[] = [];\n try {\n const params = frameId ? ({ frameId } as Record<string, unknown>) : {};\n ({ nodes } = await session.send<{\n nodes: Protocol.Accessibility.AXNode[];\n }>(\"Accessibility.getFullAXTree\", params));\n } catch (e) {\n const msg = String((e as Error)?.message ?? e ?? \"\");\n const isFrameScopeError =\n msg.includes(\"Frame with the given\") ||\n msg.includes(\"does not belong to the target\") ||\n msg.includes(\"is not found\");\n if (!isFrameScopeError || !frameId) throw e;\n ({ nodes } = await session.send<{\n nodes: Protocol.Accessibility.AXNode[];\n }>(\"Accessibility.getFullAXTree\"));\n }\n\n let scopeApplied = false;\n const nodesForOutline = await (async () => {\n const sel = opts.focusSelector?.trim();\n if (!sel) return nodes;\n try {\n const looksLikeXPath = /^xpath=/i.test(sel) || sel.startsWith(\"/\");\n const objectId = looksLikeXPath\n ? await resolveObjectIdForXPath(session, sel, frameId)\n : await resolveObjectIdForCss(session, sel, frameId);\n if (!objectId) return nodes;\n const desc = await session.send<{ node?: { backendNodeId?: number } }>(\n \"DOM.describeNode\",\n { objectId },\n );\n const be = desc.node?.backendNodeId;\n if (typeof be !== \"number\") return nodes;\n const target = nodes.find((n) => n.backendDOMNodeId === be);\n if (!target) return nodes;\n scopeApplied = true;\n const keep = new Set<string>([target.nodeId]);\n const queue: Protocol.Accessibility.AXNode[] = [target];\n while (queue.length) {\n const cur = queue.shift()!;\n for (const id of cur.childIds ?? []) {\n if (keep.has(id)) continue;\n keep.add(id);\n const child = nodes.find((n) => n.nodeId === id);\n if (child) queue.push(child);\n }\n }\n return nodes\n .filter((n) => keep.has(n.nodeId))\n .map((n) =>\n n.nodeId === target.nodeId ? { ...n, parentId: undefined } : n,\n );\n } catch {\n return nodes;\n }\n })();\n\n const filteredNodes = nodesForOutline.filter((node) => {\n const be = node.backendDOMNodeId;\n return typeof be !== \"number\" || !opts.isIgnoredBackendNode?.(be);\n });\n\n const urlMap: Record<string, string> = {};\n for (const n of filteredNodes) {\n const be = n.backendDOMNodeId;\n if (typeof be !== \"number\") continue;\n const url = extractUrlFromAXNode(n);\n if (!url) continue;\n const enc = opts.encode(be);\n urlMap[enc] = url;\n }\n\n const decorated = decorateRoles(filteredNodes, opts);\n const { tree } = await buildHierarchicalTree(decorated, opts);\n\n const simplified = tree.map((n) => formatTreeLine(n)).join(\"\\n\");\n return { outline: simplified.trimEnd(), urlMap, scopeApplied };\n}\n\nexport function decorateRoles(\n nodes: Protocol.Accessibility.AXNode[],\n opts: A11yOptions,\n): A11yNode[] {\n const asRole = (n: Protocol.Accessibility.AXNode) =>\n String(n.role?.value ?? \"\");\n\n return nodes.map((n) => {\n let encodedId: string | undefined;\n if (typeof n.backendDOMNodeId === \"number\") {\n try {\n encodedId = opts.encode(n.backendDOMNodeId);\n } catch {\n //\n }\n }\n\n let role = asRole(n);\n\n const domIsScrollable = encodedId\n ? opts.scrollableMap[encodedId] === true\n : false;\n const tag = encodedId ? opts.tagNameMap[encodedId] : undefined;\n const isHtmlElement = tag === \"html\";\n if ((domIsScrollable || isHtmlElement) && tag !== \"#document\") {\n const tagLabel = tag && tag.startsWith(\"#\") ? tag.slice(1) : tag;\n role = tagLabel\n ? `scrollable, ${tagLabel}`\n : `scrollable${role ? `, ${role}` : \"\"}`;\n }\n\n // File inputs typically get role \"button\" from Chrome's AX tree;\n // override so they appear as \"input, file\" in the outline.\n if (tag === \"input, file\") {\n role = tag;\n }\n\n return {\n role,\n name: n.name?.value,\n description: n.description?.value,\n value: n.value?.value,\n nodeId: n.nodeId,\n backendDOMNodeId: n.backendDOMNodeId,\n parentId: n.parentId,\n childIds: n.childIds,\n encodedId,\n };\n });\n}\n\nexport async function buildHierarchicalTree(\n nodes: A11yNode[],\n opts: A11yOptions,\n): Promise<{ tree: A11yNode[] }> {\n const nodeMap = new Map<string, A11yNode>();\n\n for (const n of nodes) {\n const keep =\n !!(n.name && n.name.trim()) ||\n !!(n.childIds && n.childIds.length) ||\n !isStructural(n.role);\n if (!keep) continue;\n nodeMap.set(n.nodeId, { ...n });\n }\n\n for (const n of nodes) {\n if (!n.parentId) continue;\n const parent = nodeMap.get(n.parentId);\n const cur = nodeMap.get(n.nodeId);\n if (parent && cur) (parent.children ??= []).push(cur);\n }\n\n const roots = nodes\n .filter((n) => !n.parentId && nodeMap.has(n.nodeId))\n .map((n) => nodeMap.get(n.nodeId)!) as A11yNode[];\n\n const cleaned = (await Promise.all(roots.map(pruneStructuralSafe))).filter(\n Boolean,\n ) as A11yNode[];\n\n return { tree: cleaned };\n\n async function pruneStructuralSafe(node: A11yNode): Promise<A11yNode | null> {\n if (+node.nodeId < 0) return null;\n\n const children = node.children ?? [];\n if (!children.length) {\n return isStructural(node.role) ? null : node;\n }\n\n const cleanedKids = (\n await Promise.all(children.map(pruneStructuralSafe))\n ).filter(Boolean) as A11yNode[];\n\n const prunedStatic = removeRedundantStaticTextChildren(node, cleanedKids);\n\n if (isStructural(node.role)) {\n if (prunedStatic.length === 1) return prunedStatic[0]!;\n if (prunedStatic.length === 0) return null;\n }\n\n let newRole = node.role;\n if ((newRole === \"generic\" || newRole === \"none\") && node.encodedId) {\n const tagName = opts.tagNameMap[node.encodedId];\n if (tagName) newRole = tagName;\n }\n\n if (newRole === \"combobox\" && node.encodedId) {\n const tagName = opts.tagNameMap[node.encodedId];\n if (tagName === \"select\") newRole = \"select\";\n }\n\n return { ...node, role: newRole, children: prunedStatic };\n }\n}\n\nexport function isStructural(role: string): boolean {\n const r = role?.toLowerCase();\n return r === \"generic\" || r === \"none\" || r === \"inlinetextbox\";\n}\n\nexport function extractUrlFromAXNode(\n ax: Protocol.Accessibility.AXNode,\n): string | undefined {\n const props = ax.properties ?? [];\n const urlProp = props.find((p) => p.name === \"url\");\n const value = urlProp?.value?.value;\n return typeof value === \"string\" && value.trim() ? value.trim() : undefined;\n}\n\nexport function removeRedundantStaticTextChildren(\n parent: A11yNode,\n children: A11yNode[],\n): A11yNode[] {\n if (!parent.name) return children;\n const parentNorm = normaliseSpaces(parent.name).trim();\n let combined = \"\";\n for (const c of children) {\n if (c.role === \"StaticText\" && c.name) {\n combined += normaliseSpaces(c.name).trim();\n }\n }\n if (combined === parentNorm) {\n return children.filter((c) => c.role !== \"StaticText\");\n }\n return children;\n}\n"]}
@@ -1,5 +1,11 @@
1
1
  import { Page } from "../../page.js";
2
2
  import type { FrameContext, FrameDomMaps, HybridSnapshot, SnapshotOptions, SessionDomIndex } from "../../../types/private/index.js";
3
+ type IgnoredNodeMap = Map<string, Set<number>>;
4
+ type Interval = {
5
+ start: number;
6
+ end: number;
7
+ };
8
+ type ExclusionIntervalsByFrame = Map<string, Interval[]>;
3
9
  /**
4
10
  * Capture a hybrid DOM + Accessibility snapshot for the provided page.
5
11
  *
@@ -34,7 +40,7 @@ export declare function buildFrameContext(page: Page): FrameContext;
34
40
  * Returns `null` when scoping fails (e.g., selector miss) so the caller can
35
41
  * fall back to the full multi-frame snapshot.
36
42
  */
37
- export declare function tryScopedSnapshot(page: Page, options: SnapshotOptions | undefined, context: FrameContext, pierce: boolean): Promise<HybridSnapshot | null>;
43
+ export declare function tryScopedSnapshot(page: Page, options: SnapshotOptions | undefined, context: FrameContext, pierce: boolean, sessionToIndex: Map<string, SessionDomIndex>, exclusionIntervalsByFrame: ExclusionIntervalsByFrame): Promise<HybridSnapshot | null>;
38
44
  /**
39
45
  * Step 2 – call DOM.getDocument once per unique CDP session and hydrate the
40
46
  * result so per-frame slices can share the structure. We key by session id
@@ -49,13 +55,15 @@ export declare function buildSessionIndexes(page: Page, frames: string[], pierce
49
55
  * - collects tag/xpath/scrollability maps for DOM-based lookups
50
56
  * - fetches its AX tree to produce outlines and URL maps
51
57
  */
52
- export declare function collectPerFrameMaps(page: Page, context: FrameContext, sessionToIndex: Map<string, SessionDomIndex>, options: SnapshotOptions | undefined, pierce: boolean, frameIds: string[]): Promise<{
58
+ export declare function collectPerFrameMaps(page: Page, context: FrameContext, sessionToIndex: Map<string, SessionDomIndex>, options: SnapshotOptions | undefined, pierce: boolean, frameIds: string[], exclusionIntervalsByFrame: ExclusionIntervalsByFrame): Promise<{
53
59
  perFrameMaps: Map<string, FrameDomMaps>;
54
60
  perFrameOutlines: Array<{
55
61
  frameId: string;
56
62
  outline: string;
57
63
  }>;
58
64
  }>;
65
+ export declare function resolveIgnoredNodes(page: Page, ignoreSelectors: string[] | undefined, context: FrameContext, sessionToIndex: Map<string, SessionDomIndex>): Promise<IgnoredNodeMap>;
66
+ export declare function buildFrameExclusionIntervals(page: Page, context: FrameContext, sessionToIndex: Map<string, SessionDomIndex>, ignoredNodesByFrame: IgnoredNodeMap): Promise<ExclusionIntervalsByFrame>;
59
67
  /**
60
68
  * Step 4 – walk the frame tree (parent-first) to compute absolute prefixes for
61
69
  * every frame. The prefix is the absolute XPath of the iframe element hosting
@@ -75,3 +83,4 @@ export declare function mergeFramesIntoSnapshot(context: FrameContext, perFrameM
75
83
  frameId: string;
76
84
  outline: string;
77
85
  }>, absPrefix: Map<string, string>, iframeHostEncByChild: Map<string, string>, frameIds: string[]): HybridSnapshot;
86
+ export {};
@@ -5,8 +5,12 @@ exports.buildFrameContext = buildFrameContext;
5
5
  exports.tryScopedSnapshot = tryScopedSnapshot;
6
6
  exports.buildSessionIndexes = buildSessionIndexes;
7
7
  exports.collectPerFrameMaps = collectPerFrameMaps;
8
+ exports.resolveIgnoredNodes = resolveIgnoredNodes;
9
+ exports.buildFrameExclusionIntervals = buildFrameExclusionIntervals;
8
10
  exports.computeFramePrefixes = computeFramePrefixes;
9
11
  exports.mergeFramesIntoSnapshot = mergeFramesIntoSnapshot;
12
+ const frame_js_1 = require("../../frame.js");
13
+ const selectorResolver_js_1 = require("../../selectorResolver.js");
10
14
  const logger_js_1 = require("../../../logger.js");
11
15
  const a11yTree_js_1 = require("./a11yTree.js");
12
16
  const focusSelectors_js_1 = require("./focusSelectors.js");
@@ -35,16 +39,26 @@ const xpathUtils_js_1 = require("./xpathUtils.js");
35
39
  async function captureHybridSnapshot(page, options) {
36
40
  const pierce = options?.pierceShadow ?? true;
37
41
  const includeIframes = options?.includeIframes !== false;
42
+ const hasIgnoreSelectors = (options?.ignoreSelectors?.length ?? 0) > 0;
38
43
  const context = buildFrameContext(page);
39
- const scopedSnapshot = await tryScopedSnapshot(page, options, context, pierce);
40
- if (scopedSnapshot)
41
- return scopedSnapshot;
42
44
  const framesInScope = includeIframes ? [...context.frames] : [context.rootId];
43
45
  if (!framesInScope.includes(context.rootId)) {
44
46
  framesInScope.unshift(context.rootId);
45
47
  }
48
+ if (!hasIgnoreSelectors) {
49
+ const scopedSnapshot = await tryScopedSnapshot(page, options, context, pierce, new Map(), new Map());
50
+ if (scopedSnapshot)
51
+ return scopedSnapshot;
52
+ }
46
53
  const sessionToIndex = await buildSessionIndexes(page, framesInScope, pierce);
47
- const { perFrameMaps, perFrameOutlines } = await collectPerFrameMaps(page, context, sessionToIndex, options, pierce, framesInScope);
54
+ const ignoredNodesByFrame = await resolveIgnoredNodes(page, options?.ignoreSelectors, context, sessionToIndex);
55
+ const exclusionIntervalsByFrame = await buildFrameExclusionIntervals(page, context, sessionToIndex, ignoredNodesByFrame);
56
+ if (hasIgnoreSelectors) {
57
+ const scopedSnapshot = await tryScopedSnapshot(page, options, context, pierce, sessionToIndex, exclusionIntervalsByFrame);
58
+ if (scopedSnapshot)
59
+ return scopedSnapshot;
60
+ }
61
+ const { perFrameMaps, perFrameOutlines } = await collectPerFrameMaps(page, context, sessionToIndex, options, pierce, framesInScope, exclusionIntervalsByFrame);
48
62
  const { absPrefix, iframeHostEncByChild } = await computeFramePrefixes(page, context, perFrameMaps, framesInScope);
49
63
  return mergeFramesIntoSnapshot(context, perFrameMaps, perFrameOutlines, absPrefix, iframeHostEncByChild, framesInScope);
50
64
  }
@@ -74,7 +88,7 @@ function buildFrameContext(page) {
74
88
  * Returns `null` when scoping fails (e.g., selector miss) so the caller can
75
89
  * fall back to the full multi-frame snapshot.
76
90
  */
77
- async function tryScopedSnapshot(page, options, context, pierce) {
91
+ async function tryScopedSnapshot(page, options, context, pierce, sessionToIndex, exclusionIntervalsByFrame) {
78
92
  const requestedFocus = options?.focusSelector?.trim();
79
93
  if (!requestedFocus)
80
94
  return null;
@@ -115,20 +129,34 @@ async function tryScopedSnapshot(page, options, context, pierce) {
115
129
  const { tagNameMap, xpathMap, scrollableMap } = await (0, domTree_js_1.domMapsForSession)(owningSess, targetFrameId, pierce, (fid, be) => `${page.getOrdinal(fid)}-${be}`, sameSessionAsParent);
116
130
  const { outline, urlMap, scopeApplied } = await (0, a11yTree_js_1.a11yForFrame)(owningSess, targetFrameId, {
117
131
  focusSelector: tailSelector || undefined,
132
+ isIgnoredBackendNode: makeIsIgnoredBackendNode(targetFrameId, ownerSessionIndexForFrame(page, targetFrameId, sessionToIndex), exclusionIntervalsByFrame),
118
133
  tagNameMap,
119
134
  experimental: options?.experimental ?? false,
120
135
  scrollableMap,
121
136
  encode: (backendNodeId) => `${page.getOrdinal(targetFrameId)}-${backendNodeId}`,
122
137
  });
123
138
  const scopedXpathMap = {};
139
+ const isIgnoredBackendNode = makeIsIgnoredBackendNode(targetFrameId, ownerSessionIndexForFrame(page, targetFrameId, sessionToIndex), exclusionIntervalsByFrame);
124
140
  const abs = absPrefix ?? "";
125
141
  const isRoot = !abs || abs === "/";
126
142
  if (isRoot) {
127
- Object.assign(scopedXpathMap, xpathMap);
143
+ for (const [encId, xp] of Object.entries(xpathMap)) {
144
+ const backendNodeId = parseEncodedBackendNodeId(encId);
145
+ if (typeof backendNodeId === "number" &&
146
+ isIgnoredBackendNode?.(backendNodeId)) {
147
+ continue;
148
+ }
149
+ scopedXpathMap[encId] = xp;
150
+ }
128
151
  }
129
152
  else {
130
153
  // Prefix relative XPaths so the scoped result matches the global encoding.
131
154
  for (const [encId, xp] of Object.entries(xpathMap)) {
155
+ const backendNodeId = parseEncodedBackendNodeId(encId);
156
+ if (typeof backendNodeId === "number" &&
157
+ isIgnoredBackendNode?.(backendNodeId)) {
158
+ continue;
159
+ }
132
160
  scopedXpathMap[encId] = (0, xpathUtils_js_1.prefixXPath)(abs, xp);
133
161
  }
134
162
  }
@@ -184,7 +212,7 @@ async function buildSessionIndexes(page, frames, pierce) {
184
212
  * - collects tag/xpath/scrollability maps for DOM-based lookups
185
213
  * - fetches its AX tree to produce outlines and URL maps
186
214
  */
187
- async function collectPerFrameMaps(page, context, sessionToIndex, options, pierce, frameIds) {
215
+ async function collectPerFrameMaps(page, context, sessionToIndex, options, pierce, frameIds, exclusionIntervalsByFrame) {
188
216
  const perFrameMaps = new Map();
189
217
  const perFrameOutlines = [];
190
218
  for (const frameId of frameIds) {
@@ -197,29 +225,19 @@ async function collectPerFrameMaps(page, context, sessionToIndex, options, pierc
197
225
  }
198
226
  const parentId = context.parentByFrame.get(frameId);
199
227
  const sameSessionAsParent = !!parentId && (0, sessions_js_1.ownerSession)(page, parentId) === sess;
200
- let docRootBe = idx.rootBackend;
201
- if (sameSessionAsParent) {
202
- try {
203
- const { backendNodeId } = await sess.send("DOM.getFrameOwner", { frameId });
204
- if (typeof backendNodeId === "number") {
205
- const cdBe = idx.contentDocRootByIframe.get(backendNodeId);
206
- if (typeof cdBe === "number")
207
- docRootBe = cdBe;
208
- }
209
- }
210
- catch {
211
- //
212
- }
213
- }
228
+ const docRootBe = await resolveFrameDocRootBackendId(page, frameId, idx, sameSessionAsParent);
214
229
  const tagNameMap = {};
215
230
  const xpathMap = {};
216
231
  const scrollableMap = {};
232
+ const isIgnoredBackendNode = makeIsIgnoredBackendNode(frameId, idx, exclusionIntervalsByFrame);
217
233
  const enc = (be) => `${page.getOrdinal(frameId)}-${be}`;
218
234
  const baseAbs = idx.absByBe.get(docRootBe) ?? "/";
219
235
  for (const [be, nodeAbs] of idx.absByBe.entries()) {
220
236
  const nodeDocRoot = idx.docRootOf.get(be);
221
237
  if (nodeDocRoot !== docRootBe)
222
238
  continue;
239
+ if (isIgnoredBackendNode?.(be))
240
+ continue;
223
241
  // Translate absolute XPaths into document-relative ones for this frame.
224
242
  const rel = (0, domTree_js_1.relativizeXPath)(baseAbs, nodeAbs);
225
243
  const key = enc(be);
@@ -231,6 +249,7 @@ async function collectPerFrameMaps(page, context, sessionToIndex, options, pierc
231
249
  scrollableMap[key] = true;
232
250
  }
233
251
  const { outline, urlMap } = await (0, a11yTree_js_1.a11yForFrame)(sess, frameId, {
252
+ isIgnoredBackendNode,
234
253
  experimental: options?.experimental ?? false,
235
254
  tagNameMap,
236
255
  scrollableMap,
@@ -241,6 +260,234 @@ async function collectPerFrameMaps(page, context, sessionToIndex, options, pierc
241
260
  }
242
261
  return { perFrameMaps, perFrameOutlines };
243
262
  }
263
+ async function resolveIgnoredNodes(page, ignoreSelectors, context, sessionToIndex) {
264
+ const ignoredNodesByFrame = new Map();
265
+ for (const rawSelector of ignoreSelectors ?? []) {
266
+ const selector = rawSelector.trim();
267
+ if (!selector)
268
+ continue;
269
+ try {
270
+ const resolved = await resolveIgnoredNodesForSelector(page, selector, context, sessionToIndex);
271
+ for (const match of resolved) {
272
+ const nodes = ignoredNodesByFrame.get(match.frameId) ?? new Set();
273
+ nodes.add(match.backendNodeId);
274
+ ignoredNodesByFrame.set(match.frameId, nodes);
275
+ }
276
+ }
277
+ catch {
278
+ continue;
279
+ }
280
+ }
281
+ return ignoredNodesByFrame;
282
+ }
283
+ async function resolveIgnoredNodesForSelector(page, selector, context, sessionToIndex) {
284
+ const looksLikeXPath = /^xpath=/i.test(selector) || selector.startsWith("/");
285
+ if (looksLikeXPath) {
286
+ const hit = await (0, focusSelectors_js_1.resolveFocusFrameAndTail)(page, (0, xpathUtils_js_1.normalizeXPath)(selector), context.parentByFrame, context.rootId);
287
+ const targetFrameId = hit.targetFrameId;
288
+ const tailXPath = hit.tailXPath || "/";
289
+ if (tailXPath === "/") {
290
+ const idx = ownerSessionIndexForFrame(page, targetFrameId, sessionToIndex);
291
+ if (!idx)
292
+ return [];
293
+ const parentId = context.parentByFrame.get(targetFrameId);
294
+ const sameSessionAsParent = !!parentId &&
295
+ (0, sessions_js_1.ownerSession)(page, parentId) === (0, sessions_js_1.ownerSession)(page, targetFrameId);
296
+ const backendNodeId = await resolveFrameDocRootBackendId(page, targetFrameId, idx, sameSessionAsParent);
297
+ return [{ frameId: targetFrameId, backendNodeId }];
298
+ }
299
+ return resolveIgnoredNodesInFrame(page, targetFrameId, {
300
+ kind: "xpath",
301
+ value: tailXPath,
302
+ });
303
+ }
304
+ const hit = await (0, focusSelectors_js_1.resolveCssFocusFrameAndTail)(page, selector, context.parentByFrame, context.rootId);
305
+ const targetFrameId = hit.targetFrameId;
306
+ return resolveIgnoredNodesInFrame(page, targetFrameId, {
307
+ kind: "css",
308
+ value: hit.tailSelector || selector,
309
+ });
310
+ }
311
+ async function resolveIgnoredNodesInFrame(page, frameId, query) {
312
+ const session = (0, sessions_js_1.ownerSession)(page, frameId);
313
+ const frame = new frame_js_1.Frame(session, frameId, "", false);
314
+ const resolver = new selectorResolver_js_1.FrameSelectorResolver(frame);
315
+ const resolvedNodes = await resolver.resolveAll(query);
316
+ if (!resolvedNodes.length)
317
+ return [];
318
+ const backendNodeIds = await describeResolvedNodes(session, resolvedNodes);
319
+ return backendNodeIds.map((backendNodeId) => ({ frameId, backendNodeId }));
320
+ }
321
+ async function describeResolvedNodes(session, resolvedNodes) {
322
+ const backendNodeIds = new Set();
323
+ try {
324
+ for (const resolvedNode of resolvedNodes) {
325
+ const desc = await session.send("DOM.describeNode", { objectId: resolvedNode.objectId });
326
+ const backendNodeId = desc.node.backendNodeId;
327
+ if (typeof backendNodeId === "number") {
328
+ backendNodeIds.add(backendNodeId);
329
+ }
330
+ }
331
+ }
332
+ finally {
333
+ await Promise.all(resolvedNodes.map((resolvedNode) => session
334
+ .send("Runtime.releaseObject", { objectId: resolvedNode.objectId })
335
+ .catch(() => { })));
336
+ }
337
+ return [...backendNodeIds];
338
+ }
339
+ async function buildFrameExclusionIntervals(page, context, sessionToIndex, ignoredNodesByFrame) {
340
+ const intervalsByFrame = new Map();
341
+ if (!ignoredNodesByFrame.size)
342
+ return intervalsByFrame;
343
+ const childFramesByParent = await resolveChildFramesByParent(page, context);
344
+ const excludedFrames = new Set();
345
+ const pushInterval = (frameId, start, end) => {
346
+ const intervals = intervalsByFrame.get(frameId) ?? [];
347
+ intervals.push({ start, end });
348
+ intervalsByFrame.set(frameId, intervals);
349
+ };
350
+ const excludeFrameSubtree = async (frameId) => {
351
+ if (excludedFrames.has(frameId))
352
+ return;
353
+ excludedFrames.add(frameId);
354
+ const idx = ownerSessionIndexForFrame(page, frameId, sessionToIndex);
355
+ if (!idx)
356
+ return;
357
+ const parentId = context.parentByFrame.get(frameId);
358
+ const sameSessionAsParent = !!parentId &&
359
+ (0, sessions_js_1.ownerSession)(page, parentId) === (0, sessions_js_1.ownerSession)(page, frameId);
360
+ const docRootBe = await resolveFrameDocRootBackendId(page, frameId, idx, sameSessionAsParent);
361
+ const start = idx.enterByBe.get(docRootBe);
362
+ const end = idx.exitByBe.get(docRootBe);
363
+ if (typeof start === "number" && typeof end === "number") {
364
+ pushInterval(frameId, start, end);
365
+ }
366
+ for (const childFrameId of (0, focusSelectors_js_1.listChildrenOf)(context.parentByFrame, frameId)) {
367
+ await excludeFrameSubtree(childFrameId);
368
+ }
369
+ };
370
+ const excludeIgnoredNode = async (frameId, backendNodeId) => {
371
+ const idx = ownerSessionIndexForFrame(page, frameId, sessionToIndex);
372
+ if (!idx)
373
+ return;
374
+ const start = idx.enterByBe.get(backendNodeId);
375
+ const end = idx.exitByBe.get(backendNodeId);
376
+ if (typeof start !== "number" || typeof end !== "number")
377
+ return;
378
+ pushInterval(frameId, start, end);
379
+ for (const childFrame of childFramesByParent.get(frameId) ?? []) {
380
+ const hostEnter = idx.enterByBe.get(childFrame.hostBackendNodeId);
381
+ if (typeof hostEnter !== "number")
382
+ continue;
383
+ if (hostEnter < start || hostEnter > end)
384
+ continue;
385
+ await excludeFrameSubtree(childFrame.childFrameId);
386
+ }
387
+ };
388
+ for (const [frameId, backendNodeIds] of ignoredNodesByFrame.entries()) {
389
+ for (const backendNodeId of backendNodeIds) {
390
+ await excludeIgnoredNode(frameId, backendNodeId);
391
+ }
392
+ }
393
+ for (const [frameId, intervals] of intervalsByFrame.entries()) {
394
+ intervals.sort((a, b) => a.start - b.start || a.end - b.end);
395
+ const merged = [];
396
+ for (const interval of intervals) {
397
+ const prev = merged[merged.length - 1];
398
+ if (!prev || interval.start > prev.end) {
399
+ merged.push({ ...interval });
400
+ continue;
401
+ }
402
+ if (interval.end > prev.end)
403
+ prev.end = interval.end;
404
+ }
405
+ intervalsByFrame.set(frameId, merged);
406
+ }
407
+ return intervalsByFrame;
408
+ }
409
+ async function resolveChildFramesByParent(page, context) {
410
+ const childFramesByParent = new Map();
411
+ for (const frameId of context.frames) {
412
+ const parentId = context.parentByFrame.get(frameId);
413
+ if (!parentId)
414
+ continue;
415
+ const session = (0, sessions_js_1.parentSession)(page, context.parentByFrame, frameId);
416
+ if (!session)
417
+ continue;
418
+ try {
419
+ const { backendNodeId } = await session.send("DOM.getFrameOwner", { frameId });
420
+ if (typeof backendNodeId !== "number")
421
+ continue;
422
+ const childFrames = childFramesByParent.get(parentId) ?? [];
423
+ childFrames.push({
424
+ childFrameId: frameId,
425
+ hostBackendNodeId: backendNodeId,
426
+ });
427
+ childFramesByParent.set(parentId, childFrames);
428
+ }
429
+ catch {
430
+ continue;
431
+ }
432
+ }
433
+ return childFramesByParent;
434
+ }
435
+ function makeIsIgnoredBackendNode(frameId, idx, exclusionIntervalsByFrame) {
436
+ if (!idx)
437
+ return undefined;
438
+ const intervals = exclusionIntervalsByFrame.get(frameId);
439
+ if (!intervals?.length)
440
+ return undefined;
441
+ return (backendNodeId) => {
442
+ const enter = idx.enterByBe.get(backendNodeId);
443
+ if (typeof enter !== "number")
444
+ return false;
445
+ let lo = 0;
446
+ let hi = intervals.length - 1;
447
+ while (lo <= hi) {
448
+ const mid = (lo + hi) >> 1;
449
+ const interval = intervals[mid];
450
+ if (enter < interval.start) {
451
+ hi = mid - 1;
452
+ }
453
+ else if (enter > interval.end) {
454
+ lo = mid + 1;
455
+ }
456
+ else {
457
+ return true;
458
+ }
459
+ }
460
+ return false;
461
+ };
462
+ }
463
+ function parseEncodedBackendNodeId(encodedId) {
464
+ const parts = encodedId.split("-");
465
+ if (parts.length !== 2)
466
+ return undefined;
467
+ const backendNodeId = Number(parts[1]);
468
+ return Number.isFinite(backendNodeId) ? backendNodeId : undefined;
469
+ }
470
+ function ownerSessionIndexForFrame(page, frameId, sessionToIndex) {
471
+ const session = (0, sessions_js_1.ownerSession)(page, frameId);
472
+ return sessionToIndex.get(session.id ?? "root");
473
+ }
474
+ async function resolveFrameDocRootBackendId(page, frameId, idx, sameSessionAsParent) {
475
+ if (!sameSessionAsParent)
476
+ return idx.rootBackend;
477
+ const session = (0, sessions_js_1.ownerSession)(page, frameId);
478
+ try {
479
+ const { backendNodeId } = await session.send("DOM.getFrameOwner", { frameId });
480
+ if (typeof backendNodeId === "number") {
481
+ const docRootBe = idx.contentDocRootByIframe.get(backendNodeId);
482
+ if (typeof docRootBe === "number")
483
+ return docRootBe;
484
+ }
485
+ }
486
+ catch {
487
+ //
488
+ }
489
+ return idx.rootBackend;
490
+ }
244
491
  /**
245
492
  * Step 4 – walk the frame tree (parent-first) to compute absolute prefixes for
246
493
  * every frame. The prefix is the absolute XPath of the iframe element hosting