@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.
- package/dist/cjs/lib/inference.js +2 -9
- package/dist/cjs/lib/inference.js.map +1 -1
- package/dist/cjs/lib/prompt.js +3 -1
- package/dist/cjs/lib/prompt.js.map +1 -1
- package/dist/cjs/lib/v3/agent/AgentProvider.js +3 -0
- package/dist/cjs/lib/v3/agent/AgentProvider.js.map +1 -1
- package/dist/cjs/lib/v3/agent/tools/fillFormVision.js +16 -12
- package/dist/cjs/lib/v3/agent/tools/fillFormVision.js.map +1 -1
- package/dist/cjs/lib/v3/agent/utils/validateExperimentalFeatures.js +0 -4
- package/dist/cjs/lib/v3/agent/utils/validateExperimentalFeatures.js.map +1 -1
- package/dist/cjs/lib/v3/api.d.ts +1 -0
- package/dist/cjs/lib/v3/api.js +15 -3
- package/dist/cjs/lib/v3/api.js.map +1 -1
- package/dist/cjs/lib/v3/dom/build/a11yScripts.generated.js +1 -1
- package/dist/cjs/lib/v3/dom/build/a11yScripts.generated.js.map +1 -1
- package/dist/cjs/lib/v3/dom/build/locatorScripts.generated.js +1 -1
- package/dist/cjs/lib/v3/dom/build/locatorScripts.generated.js.map +1 -1
- package/dist/cjs/lib/v3/dom/build/reRenderScriptContent.d.ts +1 -1
- package/dist/cjs/lib/v3/dom/build/reRenderScriptContent.js +1 -1
- package/dist/cjs/lib/v3/dom/build/reRenderScriptContent.js.map +1 -1
- package/dist/cjs/lib/v3/dom/build/screenshotScripts.generated.js +1 -1
- package/dist/cjs/lib/v3/dom/build/screenshotScripts.generated.js.map +1 -1
- package/dist/cjs/lib/v3/dom/build/scriptV3Content.d.ts +1 -1
- package/dist/cjs/lib/v3/dom/build/scriptV3Content.js +1 -1
- package/dist/cjs/lib/v3/dom/build/scriptV3Content.js.map +1 -1
- package/dist/cjs/lib/v3/dom/build/selectorRuntime.generated.d.ts +24 -0
- package/dist/cjs/lib/v3/dom/build/selectorRuntime.generated.js +31 -0
- package/dist/cjs/lib/v3/dom/build/selectorRuntime.generated.js.map +1 -0
- package/dist/cjs/lib/v3/handlers/extractHandler.js +3 -1
- package/dist/cjs/lib/v3/handlers/extractHandler.js.map +1 -1
- package/dist/cjs/lib/v3/handlers/observeHandler.js +2 -1
- package/dist/cjs/lib/v3/handlers/observeHandler.js.map +1 -1
- package/dist/cjs/lib/v3/handlers/v3AgentHandler.js +3 -5
- package/dist/cjs/lib/v3/handlers/v3AgentHandler.js.map +1 -1
- package/dist/cjs/lib/v3/index.d.ts +1 -1
- package/dist/cjs/lib/v3/llm/CerebrasClient.js +1 -1
- package/dist/cjs/lib/v3/llm/CerebrasClient.js.map +1 -1
- package/dist/cjs/lib/v3/llm/GroqClient.js +1 -1
- package/dist/cjs/lib/v3/llm/GroqClient.js.map +1 -1
- package/dist/cjs/lib/v3/types/private/agent.d.ts +5 -0
- package/dist/cjs/lib/v3/types/private/agent.js +11 -0
- package/dist/cjs/lib/v3/types/private/agent.js.map +1 -1
- package/dist/cjs/lib/v3/types/private/handlers.d.ts +2 -0
- package/dist/cjs/lib/v3/types/private/handlers.js.map +1 -1
- package/dist/cjs/lib/v3/types/private/snapshot.d.ts +8 -0
- package/dist/cjs/lib/v3/types/private/snapshot.js.map +1 -1
- package/dist/cjs/lib/v3/types/public/agent.d.ts +2 -3
- package/dist/cjs/lib/v3/types/public/agent.js +3 -0
- package/dist/cjs/lib/v3/types/public/agent.js.map +1 -1
- package/dist/cjs/lib/v3/types/public/api.d.ts +7 -1
- package/dist/cjs/lib/v3/types/public/api.js +22 -2
- package/dist/cjs/lib/v3/types/public/api.js.map +1 -1
- package/dist/cjs/lib/v3/types/public/methods.d.ts +2 -0
- package/dist/cjs/lib/v3/types/public/methods.js.map +1 -1
- package/dist/cjs/lib/v3/understudy/a11y/snapshot/a11yTree.js +21 -12
- package/dist/cjs/lib/v3/understudy/a11y/snapshot/a11yTree.js.map +1 -1
- package/dist/cjs/lib/v3/understudy/a11y/snapshot/capture.d.ts +11 -2
- package/dist/cjs/lib/v3/understudy/a11y/snapshot/capture.js +268 -21
- package/dist/cjs/lib/v3/understudy/a11y/snapshot/capture.js.map +1 -1
- package/dist/cjs/lib/v3/understudy/a11y/snapshot/domTree.js +60 -7
- package/dist/cjs/lib/v3/understudy/a11y/snapshot/domTree.js.map +1 -1
- package/dist/cjs/lib/v3/understudy/frameRegistry.js +16 -5
- package/dist/cjs/lib/v3/understudy/frameRegistry.js.map +1 -1
- package/dist/cjs/lib/v3/v3.d.ts +1 -0
- package/dist/cjs/lib/v3/v3.js +18 -14
- package/dist/cjs/lib/v3/v3.js.map +1 -1
- package/dist/cjs/lib/version.d.ts +1 -1
- package/dist/cjs/lib/version.js +1 -1
- package/dist/cjs/lib/version.js.map +1 -1
- package/dist/cjs/tests/integration/observe-element-id-format.spec.js +130 -0
- package/dist/cjs/tests/integration/observe-element-id-format.spec.js.map +1 -0
- package/dist/cjs/tests/unit/agent-mode-routing.test.js +88 -0
- package/dist/cjs/tests/unit/agent-mode-routing.test.js.map +1 -0
- package/dist/cjs/tests/unit/agent-temperature.test.d.ts +1 -0
- package/dist/cjs/tests/unit/agent-temperature.test.js +191 -0
- package/dist/cjs/tests/unit/agent-temperature.test.js.map +1 -0
- package/dist/cjs/tests/unit/agent-variables-validation.test.d.ts +1 -0
- package/dist/cjs/tests/unit/agent-variables-validation.test.js +43 -0
- package/dist/cjs/tests/unit/agent-variables-validation.test.js.map +1 -0
- package/dist/cjs/tests/unit/api-client-observe-variables.test.js +49 -0
- package/dist/cjs/tests/unit/api-client-observe-variables.test.js.map +1 -1
- package/dist/cjs/tests/unit/api-optional-model-api-key.test.js +60 -0
- package/dist/cjs/tests/unit/api-optional-model-api-key.test.js.map +1 -1
- package/dist/cjs/tests/unit/api-variables-schema.test.js +32 -0
- package/dist/cjs/tests/unit/api-variables-schema.test.js.map +1 -1
- package/dist/cjs/tests/unit/frame-registry-oopif-adoption.test.d.ts +1 -0
- package/dist/cjs/tests/unit/frame-registry-oopif-adoption.test.js +60 -0
- package/dist/cjs/tests/unit/frame-registry-oopif-adoption.test.js.map +1 -0
- package/dist/cjs/tests/unit/inference-temperature.test.d.ts +1 -0
- package/dist/cjs/tests/unit/inference-temperature.test.js +65 -0
- package/dist/cjs/tests/unit/inference-temperature.test.js.map +1 -0
- package/dist/cjs/tests/unit/openai-compatible-temperature.test.d.ts +1 -0
- package/dist/cjs/tests/unit/openai-compatible-temperature.test.js +84 -0
- package/dist/cjs/tests/unit/openai-compatible-temperature.test.js.map +1 -0
- package/dist/cjs/tests/unit/prompt-observe-variables.test.js +6 -0
- package/dist/cjs/tests/unit/prompt-observe-variables.test.js.map +1 -1
- package/dist/cjs/tests/unit/public-api/llm-and-agents.test.js +3 -0
- package/dist/cjs/tests/unit/public-api/llm-and-agents.test.js.map +1 -1
- package/dist/cjs/tests/unit/public-api/public-types.test.js.map +1 -1
- package/dist/cjs/tests/unit/snapshot-a11y-resolvers.test.js +106 -5
- package/dist/cjs/tests/unit/snapshot-a11y-resolvers.test.js.map +1 -1
- package/dist/cjs/tests/unit/snapshot-a11y-tree-utils.test.js +20 -0
- package/dist/cjs/tests/unit/snapshot-a11y-tree-utils.test.js.map +1 -1
- package/dist/cjs/tests/unit/snapshot-capture-orchestration.test.js +119 -9
- package/dist/cjs/tests/unit/snapshot-capture-orchestration.test.js.map +1 -1
- package/dist/cjs/tests/unit/timeout-handlers.test.js +36 -0
- package/dist/cjs/tests/unit/timeout-handlers.test.js.map +1 -1
- package/dist/esm/lib/inference.js +2 -9
- package/dist/esm/lib/inference.js.map +1 -1
- package/dist/esm/lib/prompt.js +3 -1
- package/dist/esm/lib/prompt.js.map +1 -1
- package/dist/esm/lib/v3/agent/AgentProvider.js +3 -0
- package/dist/esm/lib/v3/agent/AgentProvider.js.map +1 -1
- package/dist/esm/lib/v3/agent/tools/fillFormVision.js +16 -12
- package/dist/esm/lib/v3/agent/tools/fillFormVision.js.map +1 -1
- package/dist/esm/lib/v3/agent/utils/validateExperimentalFeatures.js +0 -4
- package/dist/esm/lib/v3/agent/utils/validateExperimentalFeatures.js.map +1 -1
- package/dist/esm/lib/v3/api.d.ts +1 -0
- package/dist/esm/lib/v3/api.js +15 -3
- package/dist/esm/lib/v3/api.js.map +1 -1
- package/dist/esm/lib/v3/dom/build/a11yScripts.generated.js +1 -1
- package/dist/esm/lib/v3/dom/build/a11yScripts.generated.js.map +1 -1
- package/dist/esm/lib/v3/dom/build/locatorScripts.generated.js +1 -1
- package/dist/esm/lib/v3/dom/build/locatorScripts.generated.js.map +1 -1
- package/dist/esm/lib/v3/dom/build/reRenderScriptContent.d.ts +1 -1
- package/dist/esm/lib/v3/dom/build/reRenderScriptContent.js +1 -1
- package/dist/esm/lib/v3/dom/build/reRenderScriptContent.js.map +1 -1
- package/dist/esm/lib/v3/dom/build/screenshotScripts.generated.js +1 -1
- package/dist/esm/lib/v3/dom/build/screenshotScripts.generated.js.map +1 -1
- package/dist/esm/lib/v3/dom/build/scriptV3Content.d.ts +1 -1
- package/dist/esm/lib/v3/dom/build/scriptV3Content.js +1 -1
- package/dist/esm/lib/v3/dom/build/scriptV3Content.js.map +1 -1
- package/dist/esm/lib/v3/dom/build/selectorRuntime.generated.d.ts +24 -0
- package/dist/esm/lib/v3/dom/build/selectorRuntime.generated.js +28 -0
- package/dist/esm/lib/v3/dom/build/selectorRuntime.generated.js.map +1 -0
- package/dist/esm/lib/v3/handlers/extractHandler.js +3 -1
- package/dist/esm/lib/v3/handlers/extractHandler.js.map +1 -1
- package/dist/esm/lib/v3/handlers/observeHandler.js +2 -1
- package/dist/esm/lib/v3/handlers/observeHandler.js.map +1 -1
- package/dist/esm/lib/v3/handlers/v3AgentHandler.js +3 -5
- package/dist/esm/lib/v3/handlers/v3AgentHandler.js.map +1 -1
- package/dist/esm/lib/v3/index.d.ts +1 -1
- package/dist/esm/lib/v3/llm/CerebrasClient.js +1 -1
- package/dist/esm/lib/v3/llm/CerebrasClient.js.map +1 -1
- package/dist/esm/lib/v3/llm/GroqClient.js +1 -1
- package/dist/esm/lib/v3/llm/GroqClient.js.map +1 -1
- package/dist/esm/lib/v3/types/private/agent.d.ts +5 -0
- package/dist/esm/lib/v3/types/private/agent.js +10 -1
- package/dist/esm/lib/v3/types/private/agent.js.map +1 -1
- package/dist/esm/lib/v3/types/private/handlers.d.ts +2 -0
- package/dist/esm/lib/v3/types/private/handlers.js.map +1 -1
- package/dist/esm/lib/v3/types/private/snapshot.d.ts +8 -0
- package/dist/esm/lib/v3/types/private/snapshot.js.map +1 -1
- package/dist/esm/lib/v3/types/public/agent.d.ts +2 -3
- package/dist/esm/lib/v3/types/public/agent.js +3 -0
- package/dist/esm/lib/v3/types/public/agent.js.map +1 -1
- package/dist/esm/lib/v3/types/public/api.d.ts +7 -1
- package/dist/esm/lib/v3/types/public/api.js +22 -2
- package/dist/esm/lib/v3/types/public/api.js.map +1 -1
- package/dist/esm/lib/v3/types/public/methods.d.ts +2 -0
- package/dist/esm/lib/v3/types/public/methods.js.map +1 -1
- package/dist/esm/lib/v3/understudy/a11y/snapshot/a11yTree.js +21 -12
- package/dist/esm/lib/v3/understudy/a11y/snapshot/a11yTree.js.map +1 -1
- package/dist/esm/lib/v3/understudy/a11y/snapshot/capture.d.ts +11 -2
- package/dist/esm/lib/v3/understudy/a11y/snapshot/capture.js +267 -22
- package/dist/esm/lib/v3/understudy/a11y/snapshot/capture.js.map +1 -1
- package/dist/esm/lib/v3/understudy/a11y/snapshot/domTree.js +60 -7
- package/dist/esm/lib/v3/understudy/a11y/snapshot/domTree.js.map +1 -1
- package/dist/esm/lib/v3/understudy/frameRegistry.js +16 -5
- package/dist/esm/lib/v3/understudy/frameRegistry.js.map +1 -1
- package/dist/esm/lib/v3/v3.d.ts +1 -0
- package/dist/esm/lib/v3/v3.js +18 -14
- package/dist/esm/lib/v3/v3.js.map +1 -1
- package/dist/esm/lib/version.d.ts +1 -1
- package/dist/esm/lib/version.js +1 -1
- package/dist/esm/lib/version.js.map +1 -1
- package/dist/esm/tests/integration/observe-element-id-format.spec.d.ts +1 -0
- package/dist/esm/tests/integration/observe-element-id-format.spec.js +128 -0
- package/dist/esm/tests/integration/observe-element-id-format.spec.js.map +1 -0
- package/dist/esm/tests/unit/agent-mode-routing.test.d.ts +1 -0
- package/dist/esm/tests/unit/agent-mode-routing.test.js +86 -0
- package/dist/esm/tests/unit/agent-mode-routing.test.js.map +1 -0
- package/dist/esm/tests/unit/agent-temperature.test.d.ts +1 -0
- package/dist/esm/tests/unit/agent-temperature.test.js +189 -0
- package/dist/esm/tests/unit/agent-temperature.test.js.map +1 -0
- package/dist/esm/tests/unit/agent-variables-validation.test.d.ts +1 -0
- package/dist/esm/tests/unit/agent-variables-validation.test.js +41 -0
- package/dist/esm/tests/unit/agent-variables-validation.test.js.map +1 -0
- package/dist/esm/tests/unit/api-client-observe-variables.test.js +49 -0
- package/dist/esm/tests/unit/api-client-observe-variables.test.js.map +1 -1
- package/dist/esm/tests/unit/api-optional-model-api-key.test.js +60 -0
- package/dist/esm/tests/unit/api-optional-model-api-key.test.js.map +1 -1
- package/dist/esm/tests/unit/api-variables-schema.test.js +32 -0
- package/dist/esm/tests/unit/api-variables-schema.test.js.map +1 -1
- package/dist/esm/tests/unit/frame-registry-oopif-adoption.test.d.ts +1 -0
- package/dist/esm/tests/unit/frame-registry-oopif-adoption.test.js +58 -0
- package/dist/esm/tests/unit/frame-registry-oopif-adoption.test.js.map +1 -0
- package/dist/esm/tests/unit/inference-temperature.test.d.ts +1 -0
- package/dist/esm/tests/unit/inference-temperature.test.js +63 -0
- package/dist/esm/tests/unit/inference-temperature.test.js.map +1 -0
- package/dist/esm/tests/unit/openai-compatible-temperature.test.d.ts +1 -0
- package/dist/esm/tests/unit/openai-compatible-temperature.test.js +82 -0
- package/dist/esm/tests/unit/openai-compatible-temperature.test.js.map +1 -0
- package/dist/esm/tests/unit/prompt-observe-variables.test.js +6 -0
- package/dist/esm/tests/unit/prompt-observe-variables.test.js.map +1 -1
- package/dist/esm/tests/unit/public-api/llm-and-agents.test.js +3 -0
- package/dist/esm/tests/unit/public-api/llm-and-agents.test.js.map +1 -1
- package/dist/esm/tests/unit/public-api/public-types.test.js.map +1 -1
- package/dist/esm/tests/unit/snapshot-a11y-resolvers.test.js +106 -5
- package/dist/esm/tests/unit/snapshot-a11y-resolvers.test.js.map +1 -1
- package/dist/esm/tests/unit/snapshot-a11y-tree-utils.test.js +20 -0
- package/dist/esm/tests/unit/snapshot-a11y-tree-utils.test.js.map +1 -1
- package/dist/esm/tests/unit/snapshot-capture-orchestration.test.js +119 -9
- package/dist/esm/tests/unit/snapshot-capture-orchestration.test.js.map +1 -1
- package/dist/esm/tests/unit/timeout-handlers.test.js +36 -0
- package/dist/esm/tests/unit/timeout-handlers.test.js.map +1 -1
- package/package.json +3 -3
- package/dist/cjs/tests/integration/agent-captcha-autosolve.spec.js +0 -56
- package/dist/cjs/tests/integration/agent-captcha-autosolve.spec.js.map +0 -1
- package/dist/esm/tests/integration/agent-captcha-autosolve.spec.js +0 -54
- package/dist/esm/tests/integration/agent-captcha-autosolve.spec.js.map +0 -1
- /package/dist/cjs/tests/integration/{agent-captcha-autosolve.spec.d.ts → observe-element-id-format.spec.d.ts} +0 -0
- /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;
|
|
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
|
|
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":"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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 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
|
|
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.
|
|
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
|
-
|
|
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
|