@browserbasehq/orca 3.0.9-alpha-4 → 3.1.0-patch.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/index.d.ts +3 -0
- package/dist/esm/index.js +3 -0
- package/dist/esm/lib/inference.d.ts +65 -0
- package/dist/esm/lib/inference.js +333 -0
- package/dist/esm/lib/inference.js.map +1 -0
- package/dist/esm/lib/inferenceLogUtils.d.ts +12 -0
- package/dist/esm/lib/inferenceLogUtils.js +92 -0
- package/dist/esm/lib/inferenceLogUtils.js.map +1 -0
- package/dist/esm/lib/logger.d.ts +69 -0
- package/dist/esm/lib/logger.js +323 -0
- package/dist/esm/lib/logger.js.map +1 -0
- package/dist/esm/lib/modelUtils.d.ts +14 -0
- package/dist/esm/lib/modelUtils.js +48 -0
- package/dist/esm/lib/modelUtils.js.map +1 -0
- package/dist/esm/lib/prompt.d.ts +14 -0
- package/dist/esm/lib/prompt.js +230 -0
- package/dist/esm/lib/prompt.js.map +1 -0
- package/dist/esm/lib/utils.d.ts +68 -0
- package/dist/esm/lib/utils.js +654 -0
- package/dist/esm/lib/utils.js.map +1 -0
- package/dist/esm/lib/v3/agent/AgentClient.d.ts +19 -0
- package/dist/esm/lib/v3/agent/AgentClient.js +17 -0
- package/dist/esm/lib/v3/agent/AgentClient.js.map +1 -0
- package/dist/esm/lib/v3/agent/AgentProvider.d.ts +20 -0
- package/dist/esm/lib/v3/agent/AgentProvider.js +77 -0
- package/dist/esm/lib/v3/agent/AgentProvider.js.map +1 -0
- package/dist/esm/lib/v3/agent/AnthropicCUAClient.d.ts +57 -0
- package/dist/esm/lib/v3/agent/AnthropicCUAClient.js +822 -0
- package/dist/esm/lib/v3/agent/AnthropicCUAClient.js.map +1 -0
- package/dist/esm/lib/v3/agent/GoogleCUAClient.d.ts +74 -0
- package/dist/esm/lib/v3/agent/GoogleCUAClient.js +799 -0
- package/dist/esm/lib/v3/agent/GoogleCUAClient.js.map +1 -0
- package/dist/esm/lib/v3/agent/MicrosoftCUAClient.d.ts +71 -0
- package/dist/esm/lib/v3/agent/MicrosoftCUAClient.js +770 -0
- package/dist/esm/lib/v3/agent/MicrosoftCUAClient.js.map +1 -0
- package/dist/esm/lib/v3/agent/OpenAICUAClient.d.ts +69 -0
- package/dist/esm/lib/v3/agent/OpenAICUAClient.js +615 -0
- package/dist/esm/lib/v3/agent/OpenAICUAClient.js.map +1 -0
- package/dist/esm/lib/v3/agent/prompts/agentSystemPrompt.d.ts +12 -0
- package/dist/esm/lib/v3/agent/prompts/agentSystemPrompt.js +186 -0
- package/dist/esm/lib/v3/agent/prompts/agentSystemPrompt.js.map +1 -0
- package/dist/esm/lib/v3/agent/tools/act.d.ts +13 -0
- package/dist/esm/lib/v3/agent/tools/act.js +49 -0
- package/dist/esm/lib/v3/agent/tools/act.js.map +1 -0
- package/dist/esm/lib/v3/agent/tools/ariaTree.d.ts +5 -0
- package/dist/esm/lib/v3/agent/tools/ariaTree.js +31 -0
- package/dist/esm/lib/v3/agent/tools/ariaTree.js.map +1 -0
- package/dist/esm/lib/v3/agent/tools/click.d.ts +6 -0
- package/dist/esm/lib/v3/agent/tools/click.js +104 -0
- package/dist/esm/lib/v3/agent/tools/click.js.map +1 -0
- package/dist/esm/lib/v3/agent/tools/clickAndHold.d.ts +14 -0
- package/dist/esm/lib/v3/agent/tools/clickAndHold.js +68 -0
- package/dist/esm/lib/v3/agent/tools/clickAndHold.js.map +1 -0
- package/dist/esm/lib/v3/agent/tools/dragAndDrop.d.ts +7 -0
- package/dist/esm/lib/v3/agent/tools/dragAndDrop.js +105 -0
- package/dist/esm/lib/v3/agent/tools/dragAndDrop.js.map +1 -0
- package/dist/esm/lib/v3/agent/tools/extract.d.ts +21 -0
- package/dist/esm/lib/v3/agent/tools/extract.js +93 -0
- package/dist/esm/lib/v3/agent/tools/extract.js.map +1 -0
- package/dist/esm/lib/v3/agent/tools/fillFormVision.d.ts +12 -0
- package/dist/esm/lib/v3/agent/tools/fillFormVision.js +143 -0
- package/dist/esm/lib/v3/agent/tools/fillFormVision.js.map +1 -0
- package/dist/esm/lib/v3/agent/tools/fillform.d.ts +13 -0
- package/dist/esm/lib/v3/agent/tools/fillform.js +56 -0
- package/dist/esm/lib/v3/agent/tools/fillform.js.map +1 -0
- package/dist/esm/lib/v3/agent/tools/goto.d.ts +12 -0
- package/dist/esm/lib/v3/agent/tools/goto.js +31 -0
- package/dist/esm/lib/v3/agent/tools/goto.js.map +1 -0
- package/dist/esm/lib/v3/agent/tools/index.d.ts +92 -0
- package/dist/esm/lib/v3/agent/tools/index.js +74 -0
- package/dist/esm/lib/v3/agent/tools/index.js.map +1 -0
- package/dist/esm/lib/v3/agent/tools/keys.d.ts +24 -0
- package/dist/esm/lib/v3/agent/tools/keys.js +60 -0
- package/dist/esm/lib/v3/agent/tools/keys.js.map +1 -0
- package/dist/esm/lib/v3/agent/tools/navback.d.ts +6 -0
- package/dist/esm/lib/v3/agent/tools/navback.js +23 -0
- package/dist/esm/lib/v3/agent/tools/navback.js.map +1 -0
- package/dist/esm/lib/v3/agent/tools/screenshot.d.ts +6 -0
- package/dist/esm/lib/v3/agent/tools/screenshot.js +26 -0
- package/dist/esm/lib/v3/agent/tools/screenshot.js.map +1 -0
- package/dist/esm/lib/v3/agent/tools/scroll.d.ts +19 -0
- package/dist/esm/lib/v3/agent/tools/scroll.js +142 -0
- package/dist/esm/lib/v3/agent/tools/scroll.js.map +1 -0
- package/dist/esm/lib/v3/agent/tools/search.d.ts +15 -0
- package/dist/esm/lib/v3/agent/tools/search.js +73 -0
- package/dist/esm/lib/v3/agent/tools/search.js.map +1 -0
- package/dist/esm/lib/v3/agent/tools/think.d.ts +6 -0
- package/dist/esm/lib/v3/agent/tools/think.js +24 -0
- package/dist/esm/lib/v3/agent/tools/think.js.map +1 -0
- package/dist/esm/lib/v3/agent/tools/type.d.ts +7 -0
- package/dist/esm/lib/v3/agent/tools/type.js +106 -0
- package/dist/esm/lib/v3/agent/tools/type.js.map +1 -0
- package/dist/esm/lib/v3/agent/tools/wait.d.ts +5 -0
- package/dist/esm/lib/v3/agent/tools/wait.js +53 -0
- package/dist/esm/lib/v3/agent/tools/wait.js.map +1 -0
- package/dist/esm/lib/v3/agent/utils/actionMapping.d.ts +3 -0
- package/dist/esm/lib/v3/agent/utils/actionMapping.js +100 -0
- package/dist/esm/lib/v3/agent/utils/actionMapping.js.map +1 -0
- package/dist/esm/lib/v3/agent/utils/coordinateNormalization.d.ts +13 -0
- package/dist/esm/lib/v3/agent/utils/coordinateNormalization.js +28 -0
- package/dist/esm/lib/v3/agent/utils/coordinateNormalization.js.map +1 -0
- package/dist/esm/lib/v3/agent/utils/cuaKeyMapping.d.ts +10 -0
- package/dist/esm/lib/v3/agent/utils/cuaKeyMapping.js +62 -0
- package/dist/esm/lib/v3/agent/utils/cuaKeyMapping.js.map +1 -0
- package/dist/esm/lib/v3/agent/utils/googleCustomToolHandler.d.ts +25 -0
- package/dist/esm/lib/v3/agent/utils/googleCustomToolHandler.js +145 -0
- package/dist/esm/lib/v3/agent/utils/googleCustomToolHandler.js.map +1 -0
- package/dist/esm/lib/v3/agent/utils/handleDoneToolCall.d.ts +22 -0
- package/dist/esm/lib/v3/agent/utils/handleDoneToolCall.js +101 -0
- package/dist/esm/lib/v3/agent/utils/handleDoneToolCall.js.map +1 -0
- package/dist/esm/lib/v3/agent/utils/imageCompression.d.ts +53 -0
- package/dist/esm/lib/v3/agent/utils/imageCompression.js +204 -0
- package/dist/esm/lib/v3/agent/utils/imageCompression.js.map +1 -0
- package/dist/esm/lib/v3/agent/utils/messageProcessing.d.ts +12 -0
- package/dist/esm/lib/v3/agent/utils/messageProcessing.js +164 -0
- package/dist/esm/lib/v3/agent/utils/messageProcessing.js.map +1 -0
- package/dist/esm/lib/v3/agent/utils/screenshotHandler.d.ts +10 -0
- package/dist/esm/lib/v3/agent/utils/screenshotHandler.js +26 -0
- package/dist/esm/lib/v3/agent/utils/screenshotHandler.js.map +1 -0
- package/dist/esm/lib/v3/agent/utils/validateExperimentalFeatures.d.ts +26 -0
- package/dist/esm/lib/v3/agent/utils/validateExperimentalFeatures.js +79 -0
- package/dist/esm/lib/v3/agent/utils/validateExperimentalFeatures.js.map +1 -0
- package/dist/esm/lib/v3/agent/utils/xpath.d.ts +11 -0
- package/dist/esm/lib/v3/agent/utils/xpath.js +19 -0
- package/dist/esm/lib/v3/agent/utils/xpath.js.map +1 -0
- package/dist/esm/lib/v3/api.d.ts +86 -0
- package/dist/esm/lib/v3/api.js +484 -0
- package/dist/esm/lib/v3/api.js.map +1 -0
- package/dist/esm/lib/v3/cache/ActCache.d.ts +23 -0
- package/dist/esm/lib/v3/cache/ActCache.js +292 -0
- package/dist/esm/lib/v3/cache/ActCache.js.map +1 -0
- package/dist/esm/lib/v3/cache/AgentCache.d.ts +109 -0
- package/dist/esm/lib/v3/cache/AgentCache.js +640 -0
- package/dist/esm/lib/v3/cache/AgentCache.js.map +1 -0
- package/dist/esm/lib/v3/cache/CacheStorage.d.ts +17 -0
- package/dist/esm/lib/v3/cache/CacheStorage.js +98 -0
- package/dist/esm/lib/v3/cache/CacheStorage.js.map +1 -0
- package/dist/esm/lib/v3/cache/serverAgentCache.d.ts +7 -0
- package/dist/esm/lib/v3/cache/serverAgentCache.js +49 -0
- package/dist/esm/lib/v3/cache/serverAgentCache.js.map +1 -0
- package/dist/esm/lib/v3/cache/utils.d.ts +15 -0
- package/dist/esm/lib/v3/cache/utils.js +39 -0
- package/dist/esm/lib/v3/cache/utils.js.map +1 -0
- package/dist/esm/lib/v3/dom/a11yScripts/index.d.ts +11 -0
- package/dist/esm/lib/v3/dom/a11yScripts/index.js +117 -0
- package/dist/esm/lib/v3/dom/a11yScripts/index.js.map +1 -0
- package/dist/esm/lib/v3/dom/build/a11yScripts.generated.d.ts +16 -0
- package/dist/esm/lib/v3/dom/build/a11yScripts.generated.js +20 -0
- package/dist/esm/lib/v3/dom/build/a11yScripts.generated.js.map +1 -0
- package/dist/esm/lib/v3/dom/build/locatorScripts.generated.d.ts +52 -0
- package/dist/esm/lib/v3/dom/build/locatorScripts.generated.js +56 -0
- package/dist/esm/lib/v3/dom/build/locatorScripts.generated.js.map +1 -0
- package/dist/esm/lib/v3/dom/build/reRenderScriptContent.d.ts +1 -0
- package/dist/esm/lib/v3/dom/build/reRenderScriptContent.js +2 -0
- package/dist/esm/lib/v3/dom/build/reRenderScriptContent.js.map +1 -0
- package/dist/esm/lib/v3/dom/build/rerender-index.js +1 -0
- package/dist/esm/lib/v3/dom/build/screenshotScripts.generated.d.ts +4 -0
- package/dist/esm/lib/v3/dom/build/screenshotScripts.generated.js +8 -0
- package/dist/esm/lib/v3/dom/build/screenshotScripts.generated.js.map +1 -0
- package/dist/esm/lib/v3/dom/build/scriptV3Content.d.ts +1 -0
- package/dist/esm/lib/v3/dom/build/scriptV3Content.js +2 -0
- package/dist/esm/lib/v3/dom/build/scriptV3Content.js.map +1 -0
- package/dist/esm/lib/v3/dom/build/v3-index.js +1 -0
- package/dist/esm/lib/v3/dom/genA11yScripts.d.ts +1 -0
- package/dist/esm/lib/v3/dom/genA11yScripts.js +54 -0
- package/dist/esm/lib/v3/dom/genA11yScripts.js.map +1 -0
- package/dist/esm/lib/v3/dom/genDomScripts.d.ts +1 -0
- package/dist/esm/lib/v3/dom/genDomScripts.js +38 -0
- package/dist/esm/lib/v3/dom/genDomScripts.js.map +1 -0
- package/dist/esm/lib/v3/dom/genLocatorScripts.d.ts +1 -0
- package/dist/esm/lib/v3/dom/genLocatorScripts.js +51 -0
- package/dist/esm/lib/v3/dom/genLocatorScripts.js.map +1 -0
- package/dist/esm/lib/v3/dom/genScreenshotScripts.d.ts +1 -0
- package/dist/esm/lib/v3/dom/genScreenshotScripts.js +37 -0
- package/dist/esm/lib/v3/dom/genScreenshotScripts.js.map +1 -0
- package/dist/esm/lib/v3/dom/index.d.ts +1 -0
- package/dist/esm/lib/v3/dom/index.js +2 -0
- package/dist/esm/lib/v3/dom/index.js.map +1 -0
- package/dist/esm/lib/v3/dom/locatorScripts/counts.d.ts +15 -0
- package/dist/esm/lib/v3/dom/locatorScripts/counts.js +272 -0
- package/dist/esm/lib/v3/dom/locatorScripts/counts.js.map +1 -0
- package/dist/esm/lib/v3/dom/locatorScripts/index.d.ts +4 -0
- package/dist/esm/lib/v3/dom/locatorScripts/index.js +5 -0
- package/dist/esm/lib/v3/dom/locatorScripts/index.js.map +1 -0
- package/dist/esm/lib/v3/dom/locatorScripts/scripts.d.ts +37 -0
- package/dist/esm/lib/v3/dom/locatorScripts/scripts.js +458 -0
- package/dist/esm/lib/v3/dom/locatorScripts/scripts.js.map +1 -0
- package/dist/esm/lib/v3/dom/locatorScripts/selectors.d.ts +4 -0
- package/dist/esm/lib/v3/dom/locatorScripts/selectors.js +283 -0
- package/dist/esm/lib/v3/dom/locatorScripts/selectors.js.map +1 -0
- package/dist/esm/lib/v3/dom/locatorScripts/waitForSelector.d.ts +19 -0
- package/dist/esm/lib/v3/dom/locatorScripts/waitForSelector.js +283 -0
- package/dist/esm/lib/v3/dom/locatorScripts/waitForSelector.js.map +1 -0
- package/dist/esm/lib/v3/dom/locatorScripts/xpathParser.d.ts +76 -0
- package/dist/esm/lib/v3/dom/locatorScripts/xpathParser.js +376 -0
- package/dist/esm/lib/v3/dom/locatorScripts/xpathParser.js.map +1 -0
- package/dist/esm/lib/v3/dom/locatorScripts/xpathResolver.d.ts +9 -0
- package/dist/esm/lib/v3/dom/locatorScripts/xpathResolver.js +196 -0
- package/dist/esm/lib/v3/dom/locatorScripts/xpathResolver.js.map +1 -0
- package/dist/esm/lib/v3/dom/piercer.entry.d.ts +1 -0
- package/dist/esm/lib/v3/dom/piercer.entry.js +3 -0
- package/dist/esm/lib/v3/dom/piercer.entry.js.map +1 -0
- package/dist/esm/lib/v3/dom/piercer.runtime.d.ts +23 -0
- package/dist/esm/lib/v3/dom/piercer.runtime.js +90 -0
- package/dist/esm/lib/v3/dom/piercer.runtime.js.map +1 -0
- package/dist/esm/lib/v3/dom/rerenderMissingShadows.entry.d.ts +1 -0
- package/dist/esm/lib/v3/dom/rerenderMissingShadows.entry.js +3 -0
- package/dist/esm/lib/v3/dom/rerenderMissingShadows.entry.js.map +1 -0
- package/dist/esm/lib/v3/dom/rerenderMissingShadows.runtime.d.ts +1 -0
- package/dist/esm/lib/v3/dom/rerenderMissingShadows.runtime.js +40 -0
- package/dist/esm/lib/v3/dom/rerenderMissingShadows.runtime.js.map +1 -0
- package/dist/esm/lib/v3/dom/screenshotScripts/index.d.ts +1 -0
- package/dist/esm/lib/v3/dom/screenshotScripts/index.js +2 -0
- package/dist/esm/lib/v3/dom/screenshotScripts/index.js.map +1 -0
- package/dist/esm/lib/v3/dom/screenshotScripts/resolveMaskRect.d.ts +8 -0
- package/dist/esm/lib/v3/dom/screenshotScripts/resolveMaskRect.js +82 -0
- package/dist/esm/lib/v3/dom/screenshotScripts/resolveMaskRect.js.map +1 -0
- package/dist/esm/lib/v3/external_clients/aisdk.d.ts +11 -0
- package/dist/esm/lib/v3/external_clients/aisdk.js +103 -0
- package/dist/esm/lib/v3/external_clients/aisdk.js.map +1 -0
- package/dist/esm/lib/v3/external_clients/customOpenAI.d.ts +18 -0
- package/dist/esm/lib/v3/external_clients/customOpenAI.js +220 -0
- package/dist/esm/lib/v3/external_clients/customOpenAI.js.map +1 -0
- package/dist/esm/lib/v3/flowLogger.d.ts +139 -0
- package/dist/esm/lib/v3/flowLogger.js +868 -0
- package/dist/esm/lib/v3/flowLogger.js.map +1 -0
- package/dist/esm/lib/v3/handlers/actHandler.d.ts +21 -0
- package/dist/esm/lib/v3/handlers/actHandler.js +340 -0
- package/dist/esm/lib/v3/handlers/actHandler.js.map +1 -0
- package/dist/esm/lib/v3/handlers/extractHandler.d.ts +31 -0
- package/dist/esm/lib/v3/handlers/extractHandler.js +139 -0
- package/dist/esm/lib/v3/handlers/extractHandler.js.map +1 -0
- package/dist/esm/lib/v3/handlers/handlerUtils/actHandlerUtils.d.ts +24 -0
- package/dist/esm/lib/v3/handlers/handlerUtils/actHandlerUtils.js +623 -0
- package/dist/esm/lib/v3/handlers/handlerUtils/actHandlerUtils.js.map +1 -0
- package/dist/esm/lib/v3/handlers/handlerUtils/timeoutGuard.d.ts +2 -0
- package/dist/esm/lib/v3/handlers/handlerUtils/timeoutGuard.js +14 -0
- package/dist/esm/lib/v3/handlers/handlerUtils/timeoutGuard.js.map +1 -0
- package/dist/esm/lib/v3/handlers/observeHandler.d.ts +17 -0
- package/dist/esm/lib/v3/handlers/observeHandler.js +156 -0
- package/dist/esm/lib/v3/handlers/observeHandler.js.map +1 -0
- package/dist/esm/lib/v3/handlers/v3AgentHandler.d.ts +32 -0
- package/dist/esm/lib/v3/handlers/v3AgentHandler.js +461 -0
- package/dist/esm/lib/v3/handlers/v3AgentHandler.js.map +1 -0
- package/dist/esm/lib/v3/handlers/v3CuaAgentHandler.d.ts +33 -0
- package/dist/esm/lib/v3/handlers/v3CuaAgentHandler.js +528 -0
- package/dist/esm/lib/v3/handlers/v3CuaAgentHandler.js.map +1 -0
- package/dist/esm/lib/v3/index.d.ts +17 -0
- package/dist/esm/lib/v3/index.js +13 -0
- package/dist/esm/lib/v3/index.js.map +1 -0
- package/dist/esm/lib/v3/launch/browserbase.d.ts +7 -0
- package/dist/esm/lib/v3/launch/browserbase.js +46 -0
- package/dist/esm/lib/v3/launch/browserbase.js.map +1 -0
- package/dist/esm/lib/v3/launch/local.d.ts +15 -0
- package/dist/esm/lib/v3/launch/local.js +98 -0
- package/dist/esm/lib/v3/launch/local.js.map +1 -0
- package/dist/esm/lib/v3/llm/AnthropicClient.d.ts +16 -0
- package/dist/esm/lib/v3/llm/AnthropicClient.js +239 -0
- package/dist/esm/lib/v3/llm/AnthropicClient.js.map +1 -0
- package/dist/esm/lib/v3/llm/CerebrasClient.d.ts +17 -0
- package/dist/esm/lib/v3/llm/CerebrasClient.js +235 -0
- package/dist/esm/lib/v3/llm/CerebrasClient.js.map +1 -0
- package/dist/esm/lib/v3/llm/GoogleClient.d.ts +19 -0
- package/dist/esm/lib/v3/llm/GoogleClient.js +369 -0
- package/dist/esm/lib/v3/llm/GoogleClient.js.map +1 -0
- package/dist/esm/lib/v3/llm/GroqClient.d.ts +17 -0
- package/dist/esm/lib/v3/llm/GroqClient.js +236 -0
- package/dist/esm/lib/v3/llm/GroqClient.js.map +1 -0
- package/dist/esm/lib/v3/llm/LLMClient.d.ts +121 -0
- package/dist/esm/lib/v3/llm/LLMClient.js +23 -0
- package/dist/esm/lib/v3/llm/LLMClient.js.map +1 -0
- package/dist/esm/lib/v3/llm/LLMProvider.d.ts +13 -0
- package/dist/esm/lib/v3/llm/LLMProvider.js +194 -0
- package/dist/esm/lib/v3/llm/LLMProvider.js.map +1 -0
- package/dist/esm/lib/v3/llm/OpenAIClient.d.ts +15 -0
- package/dist/esm/lib/v3/llm/OpenAIClient.js +329 -0
- package/dist/esm/lib/v3/llm/OpenAIClient.js.map +1 -0
- package/dist/esm/lib/v3/llm/aisdk.d.ts +15 -0
- package/dist/esm/lib/v3/llm/aisdk.js +348 -0
- package/dist/esm/lib/v3/llm/aisdk.js.map +1 -0
- package/dist/esm/lib/v3/logger.d.ts +9 -0
- package/dist/esm/lib/v3/logger.js +96 -0
- package/dist/esm/lib/v3/logger.js.map +1 -0
- package/dist/esm/lib/v3/mcp/connection.d.ts +11 -0
- package/dist/esm/lib/v3/mcp/connection.js +49 -0
- package/dist/esm/lib/v3/mcp/connection.js.map +1 -0
- package/dist/esm/lib/v3/mcp/utils.d.ts +3 -0
- package/dist/esm/lib/v3/mcp/utils.js +36 -0
- package/dist/esm/lib/v3/mcp/utils.js.map +1 -0
- package/dist/esm/lib/v3/shutdown/cleanupLocal.d.ts +14 -0
- package/dist/esm/lib/v3/shutdown/cleanupLocal.js +30 -0
- package/dist/esm/lib/v3/shutdown/cleanupLocal.js.map +1 -0
- package/dist/esm/lib/v3/shutdown/supervisor.d.ts +9 -0
- package/dist/esm/lib/v3/shutdown/supervisor.js +156 -0
- package/dist/esm/lib/v3/shutdown/supervisor.js.map +1 -0
- package/dist/esm/lib/v3/shutdown/supervisorClient.d.ts +15 -0
- package/dist/esm/lib/v3/shutdown/supervisorClient.js +97 -0
- package/dist/esm/lib/v3/shutdown/supervisorClient.js.map +1 -0
- package/dist/esm/lib/v3/tests/agent-abort-signal.spec.js +113 -0
- package/dist/esm/lib/v3/tests/agent-abort-signal.spec.js.map +7 -0
- package/dist/esm/lib/v3/tests/agent-cache-self-heal.spec.js +80 -0
- package/dist/esm/lib/v3/tests/agent-cache-self-heal.spec.js.map +7 -0
- package/dist/esm/lib/v3/tests/agent-callbacks.spec.js +374 -0
- package/dist/esm/lib/v3/tests/agent-callbacks.spec.js.map +7 -0
- package/dist/esm/lib/v3/tests/agent-experimental-validation.spec.js +357 -0
- package/dist/esm/lib/v3/tests/agent-experimental-validation.spec.js.map +7 -0
- package/dist/esm/lib/v3/tests/agent-hybrid-mode.spec.js +247 -0
- package/dist/esm/lib/v3/tests/agent-hybrid-mode.spec.js.map +7 -0
- package/dist/esm/lib/v3/tests/agent-message-continuation.spec.js +105 -0
- package/dist/esm/lib/v3/tests/agent-message-continuation.spec.js.map +7 -0
- package/dist/esm/lib/v3/tests/agent-streaming.spec.js +126 -0
- package/dist/esm/lib/v3/tests/agent-streaming.spec.js.map +7 -0
- package/dist/esm/lib/v3/tests/cdp-session-detached.spec.js +44 -0
- package/dist/esm/lib/v3/tests/cdp-session-detached.spec.js.map +7 -0
- package/dist/esm/lib/v3/tests/click-count.spec.js +112 -0
- package/dist/esm/lib/v3/tests/click-count.spec.js.map +7 -0
- package/dist/esm/lib/v3/tests/connect-to-existing-browser.spec.js +54 -0
- package/dist/esm/lib/v3/tests/connect-to-existing-browser.spec.js.map +7 -0
- package/dist/esm/lib/v3/tests/context-addInitScript.spec.js +176 -0
- package/dist/esm/lib/v3/tests/context-addInitScript.spec.js.map +7 -0
- package/dist/esm/lib/v3/tests/default-page-tracking.spec.js +53 -0
- package/dist/esm/lib/v3/tests/default-page-tracking.spec.js.map +7 -0
- package/dist/esm/lib/v3/tests/downloads.spec.js +58 -0
- package/dist/esm/lib/v3/tests/downloads.spec.js.map +7 -0
- package/dist/esm/lib/v3/tests/envReporter.js +57 -0
- package/dist/esm/lib/v3/tests/envReporter.js.map +7 -0
- package/dist/esm/lib/v3/tests/frame-get-location-and-click.spec.js +53 -0
- package/dist/esm/lib/v3/tests/frame-get-location-and-click.spec.js.map +7 -0
- package/dist/esm/lib/v3/tests/iframe-ctx-addInitScript.spec.js +447 -0
- package/dist/esm/lib/v3/tests/iframe-ctx-addInitScript.spec.js.map +7 -0
- package/dist/esm/lib/v3/tests/keep-alive.child.js +92 -0
- package/dist/esm/lib/v3/tests/keep-alive.child.js.map +7 -0
- package/dist/esm/lib/v3/tests/keep-alive.helpers.js +532 -0
- package/dist/esm/lib/v3/tests/keep-alive.helpers.js.map +7 -0
- package/dist/esm/lib/v3/tests/keep-alive.spec.js +19 -0
- package/dist/esm/lib/v3/tests/keep-alive.spec.js.map +7 -0
- package/dist/esm/lib/v3/tests/keyboard.spec.js +296 -0
- package/dist/esm/lib/v3/tests/keyboard.spec.js.map +7 -0
- package/dist/esm/lib/v3/tests/locator-backend-node-id.spec.js +159 -0
- package/dist/esm/lib/v3/tests/locator-backend-node-id.spec.js.map +7 -0
- package/dist/esm/lib/v3/tests/locator-content-methods.spec.js +191 -0
- package/dist/esm/lib/v3/tests/locator-content-methods.spec.js.map +7 -0
- package/dist/esm/lib/v3/tests/locator-count-iframe.spec.js +108 -0
- package/dist/esm/lib/v3/tests/locator-count-iframe.spec.js.map +7 -0
- package/dist/esm/lib/v3/tests/locator-count.spec.js +71 -0
- package/dist/esm/lib/v3/tests/locator-count.spec.js.map +7 -0
- package/dist/esm/lib/v3/tests/locator-fill.spec.js +118 -0
- package/dist/esm/lib/v3/tests/locator-fill.spec.js.map +7 -0
- package/dist/esm/lib/v3/tests/locator-input-methods.spec.js +136 -0
- package/dist/esm/lib/v3/tests/locator-input-methods.spec.js.map +7 -0
- package/dist/esm/lib/v3/tests/locator-nth.spec.js +157 -0
- package/dist/esm/lib/v3/tests/locator-nth.spec.js.map +7 -0
- package/dist/esm/lib/v3/tests/locator-select-option.spec.js +242 -0
- package/dist/esm/lib/v3/tests/locator-select-option.spec.js.map +7 -0
- package/dist/esm/lib/v3/tests/logger-initialization.spec.js +552 -0
- package/dist/esm/lib/v3/tests/logger-initialization.spec.js.map +7 -0
- package/dist/esm/lib/v3/tests/multi-instance-logger.spec.js +269 -0
- package/dist/esm/lib/v3/tests/multi-instance-logger.spec.js.map +7 -0
- package/dist/esm/lib/v3/tests/nested-div.spec.js +23 -0
- package/dist/esm/lib/v3/tests/nested-div.spec.js.map +7 -0
- package/dist/esm/lib/v3/tests/page-addInitScript.spec.js +90 -0
- package/dist/esm/lib/v3/tests/page-addInitScript.spec.js.map +7 -0
- package/dist/esm/lib/v3/tests/page-console.spec.js +56 -0
- package/dist/esm/lib/v3/tests/page-console.spec.js.map +7 -0
- package/dist/esm/lib/v3/tests/page-drag-and-drop.spec.js +418 -0
- package/dist/esm/lib/v3/tests/page-drag-and-drop.spec.js.map +7 -0
- package/dist/esm/lib/v3/tests/page-goto-response.spec.js +35 -0
- package/dist/esm/lib/v3/tests/page-goto-response.spec.js.map +7 -0
- package/dist/esm/lib/v3/tests/page-hover.spec.js +167 -0
- package/dist/esm/lib/v3/tests/page-hover.spec.js.map +7 -0
- package/dist/esm/lib/v3/tests/page-screenshot.spec.js +273 -0
- package/dist/esm/lib/v3/tests/page-screenshot.spec.js.map +7 -0
- package/dist/esm/lib/v3/tests/page-scroll.spec.js +182 -0
- package/dist/esm/lib/v3/tests/page-scroll.spec.js.map +7 -0
- package/dist/esm/lib/v3/tests/page-send-cdp.spec.js +46 -0
- package/dist/esm/lib/v3/tests/page-send-cdp.spec.js.map +7 -0
- package/dist/esm/lib/v3/tests/perform-understudy-method.spec.js +98 -0
- package/dist/esm/lib/v3/tests/perform-understudy-method.spec.js.map +7 -0
- package/dist/esm/lib/v3/tests/setinputfiles.spec.js +126 -0
- package/dist/esm/lib/v3/tests/setinputfiles.spec.js.map +7 -0
- package/dist/esm/lib/v3/tests/shadow-iframe-oopif.spec.js +134 -0
- package/dist/esm/lib/v3/tests/shadow-iframe-oopif.spec.js.map +7 -0
- package/dist/esm/lib/v3/tests/shadow-iframe-spif.spec.js +134 -0
- package/dist/esm/lib/v3/tests/shadow-iframe-spif.spec.js.map +7 -0
- package/dist/esm/lib/v3/tests/testUtils.js +31 -0
- package/dist/esm/lib/v3/tests/testUtils.js.map +7 -0
- package/dist/esm/lib/v3/tests/text-selector-innermost.spec.js +100 -0
- package/dist/esm/lib/v3/tests/text-selector-innermost.spec.js.map +7 -0
- package/dist/esm/lib/v3/tests/timeouts.spec.js +32 -0
- package/dist/esm/lib/v3/tests/timeouts.spec.js.map +7 -0
- package/dist/esm/lib/v3/tests/user-data-dir.spec.js +43 -0
- package/dist/esm/lib/v3/tests/user-data-dir.spec.js.map +7 -0
- package/dist/esm/lib/v3/tests/v3.config.js +15 -0
- package/dist/esm/lib/v3/tests/v3.config.js.map +7 -0
- package/dist/esm/lib/v3/tests/v3.dynamic.config.js +43 -0
- package/dist/esm/lib/v3/tests/v3.dynamic.config.js.map +7 -0
- package/dist/esm/lib/v3/tests/v3.playwright.config.js +98 -0
- package/dist/esm/lib/v3/tests/v3.playwright.config.js.map +7 -0
- package/dist/esm/lib/v3/tests/wait-for-selector.spec.js +593 -0
- package/dist/esm/lib/v3/tests/wait-for-selector.spec.js.map +7 -0
- package/dist/esm/lib/v3/tests/wait-for-timeout.spec.js +97 -0
- package/dist/esm/lib/v3/tests/wait-for-timeout.spec.js.map +7 -0
- package/dist/esm/lib/v3/tests/xpath-for-location-deep.spec.js +77 -0
- package/dist/esm/lib/v3/tests/xpath-for-location-deep.spec.js.map +7 -0
- package/dist/esm/lib/v3/timeoutConfig.d.ts +2 -0
- package/dist/esm/lib/v3/timeoutConfig.js +27 -0
- package/dist/esm/lib/v3/timeoutConfig.js.map +1 -0
- package/dist/esm/lib/v3/types/private/agent.d.ts +6 -0
- package/dist/esm/lib/v3/types/private/agent.js +2 -0
- package/dist/esm/lib/v3/types/private/agent.js.map +1 -0
- package/dist/esm/lib/v3/types/private/api.d.ts +11 -0
- package/dist/esm/lib/v3/types/private/api.js +2 -0
- package/dist/esm/lib/v3/types/private/api.js.map +1 -0
- package/dist/esm/lib/v3/types/private/cache.d.ts +128 -0
- package/dist/esm/lib/v3/types/private/cache.js +2 -0
- package/dist/esm/lib/v3/types/private/cache.js.map +1 -0
- package/dist/esm/lib/v3/types/private/evaluator.d.ts +40 -0
- package/dist/esm/lib/v3/types/private/evaluator.js +2 -0
- package/dist/esm/lib/v3/types/private/evaluator.js.map +1 -0
- package/dist/esm/lib/v3/types/private/handlers.d.ts +38 -0
- package/dist/esm/lib/v3/types/private/handlers.js +16 -0
- package/dist/esm/lib/v3/types/private/handlers.js.map +1 -0
- package/dist/esm/lib/v3/types/private/index.d.ts +7 -0
- package/dist/esm/lib/v3/types/private/index.js +8 -0
- package/dist/esm/lib/v3/types/private/index.js.map +1 -0
- package/dist/esm/lib/v3/types/private/internal.d.ts +39 -0
- package/dist/esm/lib/v3/types/private/internal.js +2 -0
- package/dist/esm/lib/v3/types/private/internal.js.map +1 -0
- package/dist/esm/lib/v3/types/private/locator.d.ts +9 -0
- package/dist/esm/lib/v3/types/private/locator.js +2 -0
- package/dist/esm/lib/v3/types/private/locator.js.map +1 -0
- package/dist/esm/lib/v3/types/private/network.d.ts +34 -0
- package/dist/esm/lib/v3/types/private/network.js +3 -0
- package/dist/esm/lib/v3/types/private/network.js.map +1 -0
- package/dist/esm/lib/v3/types/private/shutdown.d.ts +31 -0
- package/dist/esm/lib/v3/types/private/shutdown.js +5 -0
- package/dist/esm/lib/v3/types/private/shutdown.js.map +1 -0
- package/dist/esm/lib/v3/types/private/shutdownErrors.d.ts +12 -0
- package/dist/esm/lib/v3/types/private/shutdownErrors.js +22 -0
- package/dist/esm/lib/v3/types/private/shutdownErrors.js.map +1 -0
- package/dist/esm/lib/v3/types/private/snapshot.d.ts +117 -0
- package/dist/esm/lib/v3/types/private/snapshot.js +2 -0
- package/dist/esm/lib/v3/types/private/snapshot.js.map +1 -0
- package/dist/esm/lib/v3/types/public/agent.d.ts +595 -0
- package/dist/esm/lib/v3/types/public/agent.js +15 -0
- package/dist/esm/lib/v3/types/public/agent.js.map +1 -0
- package/dist/esm/lib/v3/types/public/api.d.ts +1211 -0
- package/dist/esm/lib/v3/types/public/api.js +915 -0
- package/dist/esm/lib/v3/types/public/api.js.map +1 -0
- package/dist/esm/lib/v3/types/public/apiErrors.d.ts +18 -0
- package/dist/esm/lib/v3/types/public/apiErrors.js +32 -0
- package/dist/esm/lib/v3/types/public/apiErrors.js.map +1 -0
- package/dist/esm/lib/v3/types/public/index.d.ts +12 -0
- package/dist/esm/lib/v3/types/public/index.js +14 -0
- package/dist/esm/lib/v3/types/public/index.js.map +1 -0
- package/dist/esm/lib/v3/types/public/locator.d.ts +9 -0
- package/dist/esm/lib/v3/types/public/locator.js +2 -0
- package/dist/esm/lib/v3/types/public/locator.js.map +1 -0
- package/dist/esm/lib/v3/types/public/logs.d.ts +23 -0
- package/dist/esm/lib/v3/types/public/logs.js +13 -0
- package/dist/esm/lib/v3/types/public/logs.js.map +1 -0
- package/dist/esm/lib/v3/types/public/methods.d.ts +56 -0
- package/dist/esm/lib/v3/types/public/methods.js +15 -0
- package/dist/esm/lib/v3/types/public/methods.js.map +1 -0
- package/dist/esm/lib/v3/types/public/metrics.d.ts +27 -0
- package/dist/esm/lib/v3/types/public/metrics.js +2 -0
- package/dist/esm/lib/v3/types/public/metrics.js.map +1 -0
- package/dist/esm/lib/v3/types/public/model.d.ts +65 -0
- package/dist/esm/lib/v3/types/public/model.js +2 -0
- package/dist/esm/lib/v3/types/public/model.js.map +1 -0
- package/dist/esm/lib/v3/types/public/options.d.ts +70 -0
- package/dist/esm/lib/v3/types/public/options.js +4 -0
- package/dist/esm/lib/v3/types/public/options.js.map +1 -0
- package/dist/esm/lib/v3/types/public/page.d.ts +18 -0
- package/dist/esm/lib/v3/types/public/page.js +3 -0
- package/dist/esm/lib/v3/types/public/page.js.map +1 -0
- package/dist/esm/lib/v3/types/public/screenshotTypes.d.ts +25 -0
- package/dist/esm/lib/v3/types/public/screenshotTypes.js +2 -0
- package/dist/esm/lib/v3/types/public/screenshotTypes.js.map +1 -0
- package/dist/esm/lib/v3/types/public/sdkErrors.d.ts +152 -0
- package/dist/esm/lib/v3/types/public/sdkErrors.js +305 -0
- package/dist/esm/lib/v3/types/public/sdkErrors.js.map +1 -0
- package/dist/esm/lib/v3/understudy/a11y/snapshot/a11yTree.d.ts +15 -0
- package/dist/esm/lib/v3/understudy/a11y/snapshot/a11yTree.js +196 -0
- package/dist/esm/lib/v3/understudy/a11y/snapshot/a11yTree.js.map +1 -0
- package/dist/esm/lib/v3/understudy/a11y/snapshot/activeElement.d.ts +8 -0
- package/dist/esm/lib/v3/understudy/a11y/snapshot/activeElement.js +121 -0
- package/dist/esm/lib/v3/understudy/a11y/snapshot/activeElement.js.map +1 -0
- package/dist/esm/lib/v3/understudy/a11y/snapshot/capture.d.ts +77 -0
- package/dist/esm/lib/v3/understudy/a11y/snapshot/capture.js +336 -0
- package/dist/esm/lib/v3/understudy/a11y/snapshot/capture.js.map +1 -0
- package/dist/esm/lib/v3/understudy/a11y/snapshot/coordinateResolver.d.ts +7 -0
- package/dist/esm/lib/v3/understudy/a11y/snapshot/coordinateResolver.js +129 -0
- package/dist/esm/lib/v3/understudy/a11y/snapshot/coordinateResolver.js.map +1 -0
- package/dist/esm/lib/v3/understudy/a11y/snapshot/domTree.d.ts +46 -0
- package/dist/esm/lib/v3/understudy/a11y/snapshot/domTree.js +274 -0
- package/dist/esm/lib/v3/understudy/a11y/snapshot/domTree.js.map +1 -0
- package/dist/esm/lib/v3/understudy/a11y/snapshot/focusSelectors.d.ts +24 -0
- package/dist/esm/lib/v3/understudy/a11y/snapshot/focusSelectors.js +216 -0
- package/dist/esm/lib/v3/understudy/a11y/snapshot/focusSelectors.js.map +1 -0
- package/dist/esm/lib/v3/understudy/a11y/snapshot/index.d.ts +4 -0
- package/dist/esm/lib/v3/understudy/a11y/snapshot/index.js +5 -0
- package/dist/esm/lib/v3/understudy/a11y/snapshot/index.js.map +1 -0
- package/dist/esm/lib/v3/understudy/a11y/snapshot/sessions.d.ts +16 -0
- package/dist/esm/lib/v3/understudy/a11y/snapshot/sessions.js +22 -0
- package/dist/esm/lib/v3/understudy/a11y/snapshot/sessions.js.map +1 -0
- package/dist/esm/lib/v3/understudy/a11y/snapshot/treeFormatUtils.d.ts +28 -0
- package/dist/esm/lib/v3/understudy/a11y/snapshot/treeFormatUtils.js +135 -0
- package/dist/esm/lib/v3/understudy/a11y/snapshot/treeFormatUtils.js.map +1 -0
- package/dist/esm/lib/v3/understudy/a11y/snapshot/xpathUtils.d.ts +26 -0
- package/dist/esm/lib/v3/understudy/a11y/snapshot/xpathUtils.js +102 -0
- package/dist/esm/lib/v3/understudy/a11y/snapshot/xpathUtils.js.map +1 -0
- package/dist/esm/lib/v3/understudy/a11yInvocation.d.ts +8 -0
- package/dist/esm/lib/v3/understudy/a11yInvocation.js +12 -0
- package/dist/esm/lib/v3/understudy/a11yInvocation.js.map +1 -0
- package/dist/esm/lib/v3/understudy/cdp.d.ts +69 -0
- package/dist/esm/lib/v3/understudy/cdp.js +251 -0
- package/dist/esm/lib/v3/understudy/cdp.js.map +1 -0
- package/dist/esm/lib/v3/understudy/consoleMessage.d.ts +22 -0
- package/dist/esm/lib/v3/understudy/consoleMessage.js +66 -0
- package/dist/esm/lib/v3/understudy/consoleMessage.js.map +1 -0
- package/dist/esm/lib/v3/understudy/context.d.ts +132 -0
- package/dist/esm/lib/v3/understudy/context.js +687 -0
- package/dist/esm/lib/v3/understudy/context.js.map +1 -0
- package/dist/esm/lib/v3/understudy/deepLocator.d.ts +87 -0
- package/dist/esm/lib/v3/understudy/deepLocator.js +218 -0
- package/dist/esm/lib/v3/understudy/deepLocator.js.map +1 -0
- package/dist/esm/lib/v3/understudy/executionContextRegistry.d.ts +15 -0
- package/dist/esm/lib/v3/understudy/executionContextRegistry.js +83 -0
- package/dist/esm/lib/v3/understudy/executionContextRegistry.js.map +1 -0
- package/dist/esm/lib/v3/understudy/fileUploadUtils.d.ts +13 -0
- package/dist/esm/lib/v3/understudy/fileUploadUtils.js +81 -0
- package/dist/esm/lib/v3/understudy/fileUploadUtils.js.map +1 -0
- package/dist/esm/lib/v3/understudy/frame.d.ts +69 -0
- package/dist/esm/lib/v3/understudy/frame.js +211 -0
- package/dist/esm/lib/v3/understudy/frame.js.map +1 -0
- package/dist/esm/lib/v3/understudy/frameLocator.d.ts +50 -0
- package/dist/esm/lib/v3/understudy/frameLocator.js +255 -0
- package/dist/esm/lib/v3/understudy/frameLocator.js.map +1 -0
- package/dist/esm/lib/v3/understudy/frameRegistry.d.ts +101 -0
- package/dist/esm/lib/v3/understudy/frameRegistry.js +298 -0
- package/dist/esm/lib/v3/understudy/frameRegistry.js.map +1 -0
- package/dist/esm/lib/v3/understudy/initScripts.d.ts +2 -0
- package/dist/esm/lib/v3/understudy/initScripts.js +33 -0
- package/dist/esm/lib/v3/understudy/initScripts.js.map +1 -0
- package/dist/esm/lib/v3/understudy/lifecycleWatcher.d.ts +64 -0
- package/dist/esm/lib/v3/understudy/lifecycleWatcher.js +245 -0
- package/dist/esm/lib/v3/understudy/lifecycleWatcher.js.map +1 -0
- package/dist/esm/lib/v3/understudy/locator.d.ts +194 -0
- package/dist/esm/lib/v3/understudy/locator.js +753 -0
- package/dist/esm/lib/v3/understudy/locator.js.map +1 -0
- package/dist/esm/lib/v3/understudy/locatorInvocation.d.ts +8 -0
- package/dist/esm/lib/v3/understudy/locatorInvocation.js +12 -0
- package/dist/esm/lib/v3/understudy/locatorInvocation.js.map +1 -0
- package/dist/esm/lib/v3/understudy/navigationResponseTracker.d.ts +84 -0
- package/dist/esm/lib/v3/understudy/navigationResponseTracker.js +224 -0
- package/dist/esm/lib/v3/understudy/navigationResponseTracker.js.map +1 -0
- package/dist/esm/lib/v3/understudy/networkManager.d.ts +53 -0
- package/dist/esm/lib/v3/understudy/networkManager.js +306 -0
- package/dist/esm/lib/v3/understudy/networkManager.js.map +1 -0
- package/dist/esm/lib/v3/understudy/page.d.ts +354 -0
- package/dist/esm/lib/v3/understudy/page.js +1941 -0
- package/dist/esm/lib/v3/understudy/page.js.map +1 -0
- package/dist/esm/lib/v3/understudy/piercer.d.ts +4 -0
- package/dist/esm/lib/v3/understudy/piercer.js +61 -0
- package/dist/esm/lib/v3/understudy/piercer.js.map +1 -0
- package/dist/esm/lib/v3/understudy/response.d.ts +137 -0
- package/dist/esm/lib/v3/understudy/response.js +330 -0
- package/dist/esm/lib/v3/understudy/response.js.map +1 -0
- package/dist/esm/lib/v3/understudy/screenshotUtils.d.ts +16 -0
- package/dist/esm/lib/v3/understudy/screenshotUtils.js +352 -0
- package/dist/esm/lib/v3/understudy/screenshotUtils.js.map +1 -0
- package/dist/esm/lib/v3/understudy/selectorResolver.d.ts +38 -0
- package/dist/esm/lib/v3/understudy/selectorResolver.js +296 -0
- package/dist/esm/lib/v3/understudy/selectorResolver.js.map +1 -0
- package/dist/esm/lib/v3/v3.d.ts +191 -0
- package/dist/esm/lib/v3/v3.js +1572 -0
- package/dist/esm/lib/v3/v3.js.map +1 -0
- package/dist/esm/lib/v3/zodCompat.d.ts +12 -0
- package/dist/esm/lib/v3/zodCompat.js +17 -0
- package/dist/esm/lib/v3/zodCompat.js.map +1 -0
- package/dist/esm/lib/v3Evaluator.d.ts +19 -0
- package/dist/esm/lib/v3Evaluator.js +210 -0
- package/dist/esm/lib/v3Evaluator.js.map +1 -0
- package/dist/esm/lib/version.d.ts +5 -0
- package/dist/esm/lib/version.js +6 -0
- package/dist/esm/lib/version.js.map +1 -0
- package/dist/esm/package.json +3 -0
- package/dist/esm/tests/agent-execution-model.test.js +139 -0
- package/dist/esm/tests/agent-execution-model.test.js.map +7 -0
- package/dist/esm/tests/browserbase-session-accessors.test.js +101 -0
- package/dist/esm/tests/browserbase-session-accessors.test.js.map +7 -0
- package/dist/esm/tests/cache-llm-resolution.test.js +187 -0
- package/dist/esm/tests/cache-llm-resolution.test.js.map +7 -0
- package/dist/esm/tests/helpers/mockCDPSession.js +27 -0
- package/dist/esm/tests/helpers/mockCDPSession.js.map +7 -0
- package/dist/esm/tests/llm-provider.test.js +57 -0
- package/dist/esm/tests/llm-provider.test.js.map +7 -0
- package/dist/esm/tests/model-deprecation.test.js +135 -0
- package/dist/esm/tests/model-deprecation.test.js.map +7 -0
- package/dist/esm/tests/model-utils.test.js +43 -0
- package/dist/esm/tests/model-utils.test.js.map +7 -0
- package/dist/esm/tests/page-snapshot.test.js +36 -0
- package/dist/esm/tests/page-snapshot.test.js.map +7 -0
- package/dist/esm/tests/public-api/export-surface.test.js +53 -0
- package/dist/esm/tests/public-api/export-surface.test.js.map +7 -0
- package/dist/esm/tests/public-api/llm-and-agents.test.js +128 -0
- package/dist/esm/tests/public-api/llm-and-agents.test.js.map +7 -0
- package/dist/esm/tests/public-api/public-error-types.test.js +71 -0
- package/dist/esm/tests/public-api/public-error-types.test.js.map +7 -0
- package/dist/esm/tests/public-api/public-types.test.js +74 -0
- package/dist/esm/tests/public-api/public-types.test.js.map +7 -0
- package/dist/esm/tests/public-api/runtime-utils.test.js +31 -0
- package/dist/esm/tests/public-api/runtime-utils.test.js.map +7 -0
- package/dist/esm/tests/public-api/schema-utils.test.js +78 -0
- package/dist/esm/tests/public-api/schema-utils.test.js.map +7 -0
- package/dist/esm/tests/public-api/timeout-error-types.test.js +81 -0
- package/dist/esm/tests/public-api/timeout-error-types.test.js.map +7 -0
- package/dist/esm/tests/public-api/tool-type-export.test.js +25 -0
- package/dist/esm/tests/public-api/tool-type-export.test.js.map +7 -0
- package/dist/esm/tests/public-api/v3-core.test.js +82 -0
- package/dist/esm/tests/public-api/v3-core.test.js.map +7 -0
- package/dist/esm/tests/safety-confirmation.test.js +134 -0
- package/dist/esm/tests/safety-confirmation.test.js.map +7 -0
- package/dist/esm/tests/snapshot-a11y-resolvers.test.js +348 -0
- package/dist/esm/tests/snapshot-a11y-resolvers.test.js.map +7 -0
- package/dist/esm/tests/snapshot-a11y-tree-utils.test.js +300 -0
- package/dist/esm/tests/snapshot-a11y-tree-utils.test.js.map +7 -0
- package/dist/esm/tests/snapshot-capture-orchestration.test.js +381 -0
- package/dist/esm/tests/snapshot-capture-orchestration.test.js.map +7 -0
- package/dist/esm/tests/snapshot-cbor.test.js +197 -0
- package/dist/esm/tests/snapshot-cbor.test.js.map +7 -0
- package/dist/esm/tests/snapshot-dom-session-builders.test.js +251 -0
- package/dist/esm/tests/snapshot-dom-session-builders.test.js.map +7 -0
- package/dist/esm/tests/snapshot-dom-tree-utils.test.js +109 -0
- package/dist/esm/tests/snapshot-dom-tree-utils.test.js.map +7 -0
- package/dist/esm/tests/snapshot-focus-selectors-utils.test.js +49 -0
- package/dist/esm/tests/snapshot-focus-selectors-utils.test.js.map +7 -0
- package/dist/esm/tests/snapshot-frame-merge.test.js +391 -0
- package/dist/esm/tests/snapshot-frame-merge.test.js.map +7 -0
- package/dist/esm/tests/snapshot-tree-format-utils.test.js +113 -0
- package/dist/esm/tests/snapshot-tree-format-utils.test.js.map +7 -0
- package/dist/esm/tests/snapshot-xpath-utils.test.js +79 -0
- package/dist/esm/tests/snapshot-xpath-utils.test.js.map +7 -0
- package/dist/esm/tests/timeout-handlers.test.js +850 -0
- package/dist/esm/tests/timeout-handlers.test.js.map +7 -0
- package/dist/esm/tests/xpath-parser.test.js +317 -0
- package/dist/esm/tests/xpath-parser.test.js.map +7 -0
- package/dist/esm/tests/xpath-resolver.test.js +73 -0
- package/dist/esm/tests/xpath-resolver.test.js.map +7 -0
- package/dist/esm/tests/zod-enum-compatibility.test.js +97 -0
- package/dist/esm/tests/zod-enum-compatibility.test.js.map +7 -0
- package/package.json +37 -24
- package/dist/index.d.ts +0 -4363
- package/dist/index.js +0 -76530
|
@@ -0,0 +1,1941 @@
|
|
|
1
|
+
var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
|
|
2
|
+
var useValue = arguments.length > 2;
|
|
3
|
+
for (var i = 0; i < initializers.length; i++) {
|
|
4
|
+
value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
|
|
5
|
+
}
|
|
6
|
+
return useValue ? value : void 0;
|
|
7
|
+
};
|
|
8
|
+
var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
|
|
9
|
+
function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
|
|
10
|
+
var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
|
|
11
|
+
var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
|
|
12
|
+
var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
|
|
13
|
+
var _, done = false;
|
|
14
|
+
for (var i = decorators.length - 1; i >= 0; i--) {
|
|
15
|
+
var context = {};
|
|
16
|
+
for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
|
|
17
|
+
for (var p in contextIn.access) context.access[p] = contextIn.access[p];
|
|
18
|
+
context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
|
|
19
|
+
var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
|
|
20
|
+
if (kind === "accessor") {
|
|
21
|
+
if (result === void 0) continue;
|
|
22
|
+
if (result === null || typeof result !== "object") throw new TypeError("Object expected");
|
|
23
|
+
if (_ = accept(result.get)) descriptor.get = _;
|
|
24
|
+
if (_ = accept(result.set)) descriptor.set = _;
|
|
25
|
+
if (_ = accept(result.init)) initializers.unshift(_);
|
|
26
|
+
}
|
|
27
|
+
else if (_ = accept(result)) {
|
|
28
|
+
if (kind === "field") initializers.unshift(_);
|
|
29
|
+
else descriptor[key] = _;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
if (target) Object.defineProperty(target, contextIn.name, descriptor);
|
|
33
|
+
done = true;
|
|
34
|
+
};
|
|
35
|
+
import { promises as fs } from "fs";
|
|
36
|
+
import { v3Logger } from "../logger.js";
|
|
37
|
+
import { logAction } from "../flowLogger.js";
|
|
38
|
+
import { Frame } from "./frame.js";
|
|
39
|
+
import { FrameLocator } from "./frameLocator.js";
|
|
40
|
+
import { deepLocatorFromPage, resolveLocatorTarget } from "./deepLocator.js";
|
|
41
|
+
import { captureHybridSnapshot, resolveXpathForLocation, } from "./a11y/snapshot/index.js";
|
|
42
|
+
import { FrameRegistry } from "./frameRegistry.js";
|
|
43
|
+
import { executionContexts } from "./executionContextRegistry.js";
|
|
44
|
+
import { NetworkManager } from "./networkManager.js";
|
|
45
|
+
import { LifecycleWatcher } from "./lifecycleWatcher.js";
|
|
46
|
+
import { NavigationResponseTracker } from "./navigationResponseTracker.js";
|
|
47
|
+
import { Response, isSerializableResponse } from "./response.js";
|
|
48
|
+
import { ConsoleMessage } from "./consoleMessage.js";
|
|
49
|
+
import { StagehandSnapshotError, } from "../types/public/index.js";
|
|
50
|
+
import { StagehandInvalidArgumentError, StagehandEvalError, } from "../types/public/sdkErrors.js";
|
|
51
|
+
import { normalizeInitScriptSource } from "./initScripts.js";
|
|
52
|
+
import { buildLocatorInvocation } from "./locatorInvocation.js";
|
|
53
|
+
import { applyMaskOverlays, applyStyleToFrames, collectFramesForScreenshot, computeScreenshotScale, disableAnimations, hideCaret, normalizeScreenshotClip, runScreenshotCleanups, setTransparentBackground, withScreenshotTimeout, } from "./screenshotUtils.js";
|
|
54
|
+
/**
|
|
55
|
+
* Page
|
|
56
|
+
*
|
|
57
|
+
* One instance per **top-level target**. It owns:
|
|
58
|
+
* - the top-level CDP session (for the page target)
|
|
59
|
+
* - all adopted OOPIF child sessions (Target.attachToTarget with flatten: true)
|
|
60
|
+
* - a **FrameRegistry** that is the single source of truth for BOTH:
|
|
61
|
+
* • frame topology (parent/children, root swaps, last-seen CDP Frame)
|
|
62
|
+
* • frame → session ownership (which session owns which frameId)
|
|
63
|
+
*
|
|
64
|
+
* Page exposes convenient APIs (goto/reload/url/screenshot/locator),
|
|
65
|
+
* and simple bridges that Context uses to feed Page/Target events in.
|
|
66
|
+
*/
|
|
67
|
+
const LIFECYCLE_NAME = {
|
|
68
|
+
load: "load",
|
|
69
|
+
domcontentloaded: "DOMContentLoaded",
|
|
70
|
+
networkidle: "networkIdle",
|
|
71
|
+
};
|
|
72
|
+
let Page = (() => {
|
|
73
|
+
let _instanceExtraInitializers = [];
|
|
74
|
+
let _close_decorators;
|
|
75
|
+
let _goto_decorators;
|
|
76
|
+
let _reload_decorators;
|
|
77
|
+
let _goBack_decorators;
|
|
78
|
+
let _goForward_decorators;
|
|
79
|
+
let _screenshot_decorators;
|
|
80
|
+
let _waitForLoadState_decorators;
|
|
81
|
+
let _waitForSelector_decorators;
|
|
82
|
+
let _evaluate_decorators;
|
|
83
|
+
let _click_decorators;
|
|
84
|
+
let _hover_decorators;
|
|
85
|
+
let _scroll_decorators;
|
|
86
|
+
let _dragAndDrop_decorators;
|
|
87
|
+
let _type_decorators;
|
|
88
|
+
let _keyPress_decorators;
|
|
89
|
+
let _snapshot_decorators;
|
|
90
|
+
return class Page {
|
|
91
|
+
static {
|
|
92
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
|
|
93
|
+
_close_decorators = [logAction("Page.close")];
|
|
94
|
+
_goto_decorators = [logAction("Page.goto")];
|
|
95
|
+
_reload_decorators = [logAction("Page.reload")];
|
|
96
|
+
_goBack_decorators = [logAction("Page.goBack")];
|
|
97
|
+
_goForward_decorators = [logAction("Page.goForward")];
|
|
98
|
+
_screenshot_decorators = [logAction("Page.screenshot")];
|
|
99
|
+
_waitForLoadState_decorators = [logAction("Page.waitForLoadState")];
|
|
100
|
+
_waitForSelector_decorators = [logAction("Page.waitForSelector")];
|
|
101
|
+
_evaluate_decorators = [logAction("Page.evaluate")];
|
|
102
|
+
_click_decorators = [logAction("Page.click")];
|
|
103
|
+
_hover_decorators = [logAction("Page.hover")];
|
|
104
|
+
_scroll_decorators = [logAction("Page.scroll")];
|
|
105
|
+
_dragAndDrop_decorators = [logAction("Page.dragAndDrop")];
|
|
106
|
+
_type_decorators = [logAction("Page.type")];
|
|
107
|
+
_keyPress_decorators = [logAction("Page.keyPress")];
|
|
108
|
+
_snapshot_decorators = [logAction("Page.snapshot")];
|
|
109
|
+
__esDecorate(this, null, _close_decorators, { kind: "method", name: "close", static: false, private: false, access: { has: obj => "close" in obj, get: obj => obj.close }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
110
|
+
__esDecorate(this, null, _goto_decorators, { kind: "method", name: "goto", static: false, private: false, access: { has: obj => "goto" in obj, get: obj => obj.goto }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
111
|
+
__esDecorate(this, null, _reload_decorators, { kind: "method", name: "reload", static: false, private: false, access: { has: obj => "reload" in obj, get: obj => obj.reload }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
112
|
+
__esDecorate(this, null, _goBack_decorators, { kind: "method", name: "goBack", static: false, private: false, access: { has: obj => "goBack" in obj, get: obj => obj.goBack }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
113
|
+
__esDecorate(this, null, _goForward_decorators, { kind: "method", name: "goForward", static: false, private: false, access: { has: obj => "goForward" in obj, get: obj => obj.goForward }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
114
|
+
__esDecorate(this, null, _screenshot_decorators, { kind: "method", name: "screenshot", static: false, private: false, access: { has: obj => "screenshot" in obj, get: obj => obj.screenshot }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
115
|
+
__esDecorate(this, null, _waitForLoadState_decorators, { kind: "method", name: "waitForLoadState", static: false, private: false, access: { has: obj => "waitForLoadState" in obj, get: obj => obj.waitForLoadState }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
116
|
+
__esDecorate(this, null, _waitForSelector_decorators, { kind: "method", name: "waitForSelector", static: false, private: false, access: { has: obj => "waitForSelector" in obj, get: obj => obj.waitForSelector }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
117
|
+
__esDecorate(this, null, _evaluate_decorators, { kind: "method", name: "evaluate", static: false, private: false, access: { has: obj => "evaluate" in obj, get: obj => obj.evaluate }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
118
|
+
__esDecorate(this, null, _click_decorators, { kind: "method", name: "click", static: false, private: false, access: { has: obj => "click" in obj, get: obj => obj.click }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
119
|
+
__esDecorate(this, null, _hover_decorators, { kind: "method", name: "hover", static: false, private: false, access: { has: obj => "hover" in obj, get: obj => obj.hover }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
120
|
+
__esDecorate(this, null, _scroll_decorators, { kind: "method", name: "scroll", static: false, private: false, access: { has: obj => "scroll" in obj, get: obj => obj.scroll }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
121
|
+
__esDecorate(this, null, _dragAndDrop_decorators, { kind: "method", name: "dragAndDrop", static: false, private: false, access: { has: obj => "dragAndDrop" in obj, get: obj => obj.dragAndDrop }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
122
|
+
__esDecorate(this, null, _type_decorators, { kind: "method", name: "type", static: false, private: false, access: { has: obj => "type" in obj, get: obj => obj.type }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
123
|
+
__esDecorate(this, null, _keyPress_decorators, { kind: "method", name: "keyPress", static: false, private: false, access: { has: obj => "keyPress" in obj, get: obj => obj.keyPress }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
124
|
+
__esDecorate(this, null, _snapshot_decorators, { kind: "method", name: "snapshot", static: false, private: false, access: { has: obj => "snapshot" in obj, get: obj => obj.snapshot }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
125
|
+
if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
126
|
+
}
|
|
127
|
+
conn = __runInitializers(this, _instanceExtraInitializers);
|
|
128
|
+
mainSession;
|
|
129
|
+
_targetId;
|
|
130
|
+
/** Every CDP child session this page owns (top-level + adopted OOPIF sessions). */
|
|
131
|
+
sessions = new Map(); // sessionId -> session
|
|
132
|
+
/** Unified truth for frame topology + ownership. */
|
|
133
|
+
registry;
|
|
134
|
+
/** A convenience wrapper bound to the current main frame id (top-level session). */
|
|
135
|
+
mainFrameWrapper;
|
|
136
|
+
/** Compact ordinal per frameId (used by snapshot encoding). */
|
|
137
|
+
frameOrdinals = new Map();
|
|
138
|
+
nextOrdinal = 0;
|
|
139
|
+
/** cache Frames per frameId so everyone uses the same one */
|
|
140
|
+
frameCache = new Map();
|
|
141
|
+
browserIsRemote;
|
|
142
|
+
/** Stable id for Frames created by this Page (use top-level TargetId). */
|
|
143
|
+
pageId;
|
|
144
|
+
/** Cached current URL for synchronous page.url() */
|
|
145
|
+
_currentUrl = "about:blank";
|
|
146
|
+
navigationCommandSeq = 0;
|
|
147
|
+
latestNavigationCommandId = 0;
|
|
148
|
+
networkManager;
|
|
149
|
+
/** Optional API client for routing page operations to the API */
|
|
150
|
+
apiClient = null;
|
|
151
|
+
consoleListeners = new Set();
|
|
152
|
+
consoleHandlers = new Map();
|
|
153
|
+
/** Document-start scripts installed across every session this page owns. */
|
|
154
|
+
initScripts = [];
|
|
155
|
+
constructor(conn, mainSession, _targetId, mainFrameId, apiClient, browserIsRemote = false) {
|
|
156
|
+
this.conn = conn;
|
|
157
|
+
this.mainSession = mainSession;
|
|
158
|
+
this._targetId = _targetId;
|
|
159
|
+
this.pageId = _targetId;
|
|
160
|
+
this.apiClient = apiClient ?? null;
|
|
161
|
+
this.browserIsRemote = browserIsRemote;
|
|
162
|
+
// own the main session
|
|
163
|
+
if (mainSession.id)
|
|
164
|
+
this.sessions.set(mainSession.id, mainSession);
|
|
165
|
+
// initialize registry with root/main frame id
|
|
166
|
+
this.registry = new FrameRegistry(_targetId, mainFrameId);
|
|
167
|
+
// main-frame wrapper is always bound to the **top-level** session
|
|
168
|
+
this.mainFrameWrapper = new Frame(this.mainSession, mainFrameId, this.pageId, this.browserIsRemote);
|
|
169
|
+
this.networkManager = new NetworkManager();
|
|
170
|
+
this.networkManager.trackSession(this.mainSession);
|
|
171
|
+
}
|
|
172
|
+
// Send a single init script to a specific CDP session.
|
|
173
|
+
async installInitScriptOnSession(session, source) {
|
|
174
|
+
await session.send("Page.addScriptToEvaluateOnNewDocument", {
|
|
175
|
+
source: source,
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
// Replay every previously registered init script onto a newly adopted session.
|
|
179
|
+
async applyInitScriptsToSession(session) {
|
|
180
|
+
for (const source of this.initScripts) {
|
|
181
|
+
await this.installInitScriptOnSession(session, source);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
// Register a new init script and fan it out to all active sessions for this page.
|
|
185
|
+
async registerInitScript(source) {
|
|
186
|
+
if (this.initScripts.includes(source))
|
|
187
|
+
return;
|
|
188
|
+
this.initScripts.push(source);
|
|
189
|
+
const installs = [];
|
|
190
|
+
installs.push(this.installInitScriptOnSession(this.mainSession, source));
|
|
191
|
+
for (const session of this.sessions.values()) {
|
|
192
|
+
if (session === this.mainSession)
|
|
193
|
+
continue;
|
|
194
|
+
installs.push(this.installInitScriptOnSession(session, source));
|
|
195
|
+
}
|
|
196
|
+
await Promise.all(installs);
|
|
197
|
+
}
|
|
198
|
+
// Seed an init script without re-installing it on the current sessions.
|
|
199
|
+
seedInitScript(source) {
|
|
200
|
+
if (this.initScripts.includes(source))
|
|
201
|
+
return;
|
|
202
|
+
this.initScripts.push(source);
|
|
203
|
+
}
|
|
204
|
+
// --- Optional visual cursor overlay management ---
|
|
205
|
+
cursorEnabled = false;
|
|
206
|
+
async ensureCursorScript() {
|
|
207
|
+
const script = `(() => {
|
|
208
|
+
const ID = '__v3_cursor_overlay__';
|
|
209
|
+
const state = { el: null, last: null };
|
|
210
|
+
// Expose API early so move() calls before install are buffered
|
|
211
|
+
try {
|
|
212
|
+
if (!window.__v3Cursor || !window.__v3Cursor.__installed) {
|
|
213
|
+
const api = {
|
|
214
|
+
__installed: false,
|
|
215
|
+
move(x, y) {
|
|
216
|
+
if (state.el) {
|
|
217
|
+
state.el.style.left = Math.max(0, x) + 'px';
|
|
218
|
+
state.el.style.top = Math.max(0, y) + 'px';
|
|
219
|
+
} else {
|
|
220
|
+
state.last = [x, y];
|
|
221
|
+
}
|
|
222
|
+
},
|
|
223
|
+
show() { if (state.el) state.el.style.display = 'block'; },
|
|
224
|
+
hide() { if (state.el) state.el.style.display = 'none'; },
|
|
225
|
+
};
|
|
226
|
+
window.__v3Cursor = api;
|
|
227
|
+
}
|
|
228
|
+
} catch {}
|
|
229
|
+
|
|
230
|
+
function install() {
|
|
231
|
+
try {
|
|
232
|
+
if (state.el) return; // already installed
|
|
233
|
+
let el = document.getElementById(ID);
|
|
234
|
+
if (!el) {
|
|
235
|
+
const root = document.documentElement || document.body || document.head;
|
|
236
|
+
if (!root) { setTimeout(install, 50); return; }
|
|
237
|
+
el = document.createElement('div');
|
|
238
|
+
el.id = ID;
|
|
239
|
+
el.style.position = 'fixed';
|
|
240
|
+
el.style.left = '0px';
|
|
241
|
+
el.style.top = '0px';
|
|
242
|
+
el.style.width = '16px';
|
|
243
|
+
el.style.height = '24px';
|
|
244
|
+
el.style.zIndex = '2147483647';
|
|
245
|
+
el.style.pointerEvents = 'none';
|
|
246
|
+
el.style.userSelect = 'none';
|
|
247
|
+
el.style.mixBlendMode = 'normal';
|
|
248
|
+
el.style.contain = 'layout style paint';
|
|
249
|
+
el.style.willChange = 'transform,left,top';
|
|
250
|
+
el.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="24" viewBox="0 0 16 24"><path d="M1 0 L1 22 L6 14 L15 14 Z" fill="black" stroke="white" stroke-width="0.7"/></svg>';
|
|
251
|
+
root.appendChild(el);
|
|
252
|
+
}
|
|
253
|
+
state.el = el;
|
|
254
|
+
try { window.__v3Cursor.__installed = true; } catch {}
|
|
255
|
+
if (state.last) {
|
|
256
|
+
window.__v3Cursor.move(state.last[0], state.last[1]);
|
|
257
|
+
state.last = null;
|
|
258
|
+
}
|
|
259
|
+
} catch {}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
if (document.readyState === 'complete' || document.readyState === 'interactive') {
|
|
263
|
+
install();
|
|
264
|
+
} else {
|
|
265
|
+
document.addEventListener('DOMContentLoaded', install, { once: true });
|
|
266
|
+
setTimeout(install, 100);
|
|
267
|
+
}
|
|
268
|
+
})();`;
|
|
269
|
+
// Ensure future documents get the cursor at doc-start
|
|
270
|
+
await this.mainSession
|
|
271
|
+
.send("Page.addScriptToEvaluateOnNewDocument", { source: script })
|
|
272
|
+
.catch(() => { });
|
|
273
|
+
// Inject into current document now
|
|
274
|
+
await this.mainSession
|
|
275
|
+
.send("Runtime.evaluate", {
|
|
276
|
+
expression: script,
|
|
277
|
+
includeCommandLineAPI: false,
|
|
278
|
+
})
|
|
279
|
+
.catch(() => { });
|
|
280
|
+
}
|
|
281
|
+
async enableCursorOverlay() {
|
|
282
|
+
if (this.cursorEnabled)
|
|
283
|
+
return;
|
|
284
|
+
await this.ensureCursorScript();
|
|
285
|
+
this.cursorEnabled = true;
|
|
286
|
+
}
|
|
287
|
+
async updateCursor(x, y) {
|
|
288
|
+
if (!this.cursorEnabled)
|
|
289
|
+
return;
|
|
290
|
+
try {
|
|
291
|
+
await this.mainSession.send("Runtime.evaluate", {
|
|
292
|
+
expression: `typeof window.__v3Cursor!=="undefined"&&window.__v3Cursor.move(${Math.round(x)}, ${Math.round(y)})`,
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
catch {
|
|
296
|
+
//
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
async addInitScript(script, arg) {
|
|
300
|
+
const source = await normalizeInitScriptSource(script, arg, "page.addInitScript");
|
|
301
|
+
await this.registerInitScript(source);
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* Factory: create Page and seed registry with the shallow tree from Page.getFrameTree.
|
|
305
|
+
* Assumes Page domain is already enabled on the session passed in.
|
|
306
|
+
*/
|
|
307
|
+
static async create(conn, session, targetId, apiClient, localBrowserLaunchOptions, browserIsRemote = false) {
|
|
308
|
+
await session.send("Page.enable").catch(() => { });
|
|
309
|
+
await session
|
|
310
|
+
.send("Page.setLifecycleEventsEnabled", { enabled: true })
|
|
311
|
+
.catch(() => { });
|
|
312
|
+
const { frameTree } = await session.send("Page.getFrameTree");
|
|
313
|
+
const mainFrameId = frameTree.frame.id;
|
|
314
|
+
const page = new Page(conn, session, targetId, mainFrameId, apiClient, browserIsRemote);
|
|
315
|
+
// Seed current URL from initial frame tree
|
|
316
|
+
try {
|
|
317
|
+
page._currentUrl = String(frameTree?.frame?.url ?? page._currentUrl);
|
|
318
|
+
if (localBrowserLaunchOptions?.viewport) {
|
|
319
|
+
await page.setViewportSize(localBrowserLaunchOptions.viewport.width, localBrowserLaunchOptions.viewport.height, {
|
|
320
|
+
deviceScaleFactor: localBrowserLaunchOptions.deviceScaleFactor ?? 1,
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
catch {
|
|
325
|
+
// ignore
|
|
326
|
+
}
|
|
327
|
+
// Seed topology + ownership for nodes known at creation time.
|
|
328
|
+
page.registry.seedFromFrameTree(session.id ?? "root", frameTree);
|
|
329
|
+
return page;
|
|
330
|
+
}
|
|
331
|
+
// ---------------- Event-driven updates from Context ----------------
|
|
332
|
+
/**
|
|
333
|
+
* Parent/child session emitted a `frameAttached`.
|
|
334
|
+
* Topology update + ownership stamped to **emitting session**.
|
|
335
|
+
*/
|
|
336
|
+
onFrameAttached(frameId, parentId, session) {
|
|
337
|
+
this.ensureOrdinal(frameId);
|
|
338
|
+
this.registry.onFrameAttached(frameId, parentId, session.id ?? "root");
|
|
339
|
+
// Cache is keyed by frameId → invalidate to ensure future frameForId resolves with latest owner
|
|
340
|
+
this.frameCache.delete(frameId);
|
|
341
|
+
}
|
|
342
|
+
/**
|
|
343
|
+
* Parent/child session emitted a `frameDetached`.
|
|
344
|
+
*/
|
|
345
|
+
onFrameDetached(frameId, reason = "remove") {
|
|
346
|
+
this.registry.onFrameDetached(frameId, reason);
|
|
347
|
+
this.frameCache.delete(frameId);
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* Parent/child session emitted a `frameNavigated`.
|
|
351
|
+
* Topology + ownership update. Handles root swaps.
|
|
352
|
+
*/
|
|
353
|
+
onFrameNavigated(frame, session) {
|
|
354
|
+
const prevRoot = this.mainFrameId();
|
|
355
|
+
this.registry.onFrameNavigated(frame, session.id ?? "root");
|
|
356
|
+
// If the root changed, keep the convenience wrapper in sync
|
|
357
|
+
const newRoot = this.mainFrameId();
|
|
358
|
+
if (newRoot !== prevRoot) {
|
|
359
|
+
const oldOrd = this.frameOrdinals.get(prevRoot) ?? 0;
|
|
360
|
+
this.frameOrdinals.set(newRoot, oldOrd);
|
|
361
|
+
this.mainFrameWrapper = new Frame(this.mainSession, newRoot, this.pageId, this.browserIsRemote);
|
|
362
|
+
}
|
|
363
|
+
// Update cached URL if this navigation pertains to the current main frame
|
|
364
|
+
if (frame.id === this.mainFrameId()) {
|
|
365
|
+
try {
|
|
366
|
+
// Prefer frame.url; fallback keeps previous value
|
|
367
|
+
this._currentUrl = String(frame?.url ?? this._currentUrl);
|
|
368
|
+
}
|
|
369
|
+
catch {
|
|
370
|
+
// ignore
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
// Invalidate the cached Frame for this id (session may have changed)
|
|
374
|
+
this.frameCache.delete(frame.id);
|
|
375
|
+
}
|
|
376
|
+
onNavigatedWithinDocument(frameId, url, session) {
|
|
377
|
+
const normalized = String(url ?? "").trim();
|
|
378
|
+
if (!normalized)
|
|
379
|
+
return;
|
|
380
|
+
this.registry.onNavigatedWithinDocument(frameId, normalized, session.id ?? "root");
|
|
381
|
+
if (frameId === this.mainFrameId()) {
|
|
382
|
+
this._currentUrl = normalized;
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* An OOPIF child session whose **main** frame id equals the parent iframe’s frameId
|
|
387
|
+
* has been attached; adopt the session into this Page and seed ownership for its subtree.
|
|
388
|
+
*/
|
|
389
|
+
adoptOopifSession(childSession, childMainFrameId) {
|
|
390
|
+
if (childSession.id)
|
|
391
|
+
this.sessions.set(childSession.id, childSession);
|
|
392
|
+
this.networkManager.trackSession(childSession);
|
|
393
|
+
void this.applyInitScriptsToSession(childSession).catch(() => { });
|
|
394
|
+
if (this.consoleListeners.size > 0) {
|
|
395
|
+
this.installConsoleTap(childSession);
|
|
396
|
+
}
|
|
397
|
+
// session will start emitting its own page events; mark ownership seed now
|
|
398
|
+
this.registry.adoptChildSession(childSession.id ?? "child", childMainFrameId);
|
|
399
|
+
this.frameCache.delete(childMainFrameId);
|
|
400
|
+
// Bridge events from the child session to keep registry in sync
|
|
401
|
+
childSession.on("Page.frameNavigated", (evt) => {
|
|
402
|
+
this.onFrameNavigated(evt.frame, childSession);
|
|
403
|
+
});
|
|
404
|
+
childSession.on("Page.frameAttached", (evt) => {
|
|
405
|
+
this.onFrameAttached(evt.frameId, evt.parentFrameId ?? null, childSession);
|
|
406
|
+
});
|
|
407
|
+
childSession.on("Page.frameDetached", (evt) => {
|
|
408
|
+
this.onFrameDetached(evt.frameId, evt.reason ?? "remove");
|
|
409
|
+
});
|
|
410
|
+
// One-shot seed the child's subtree ownership from its current tree
|
|
411
|
+
void (async () => {
|
|
412
|
+
try {
|
|
413
|
+
await childSession.send("Page.enable").catch(() => { });
|
|
414
|
+
let { frameTree } = await childSession.send("Page.getFrameTree");
|
|
415
|
+
// Normalize: ensure the child’s reported root id matches our known main id
|
|
416
|
+
if (frameTree.frame.id !== childMainFrameId) {
|
|
417
|
+
frameTree = {
|
|
418
|
+
...frameTree,
|
|
419
|
+
frame: { ...frameTree.frame, id: childMainFrameId },
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
this.registry.seedFromFrameTree(childSession.id ?? "child", frameTree);
|
|
423
|
+
}
|
|
424
|
+
catch {
|
|
425
|
+
// If snapshot races, live events will still converge the registry.
|
|
426
|
+
}
|
|
427
|
+
})();
|
|
428
|
+
}
|
|
429
|
+
/** Detach an adopted child session and prune its subtree */
|
|
430
|
+
detachOopifSession(sessionId) {
|
|
431
|
+
// Find which frames were owned by this session and prune by tree starting from each root.
|
|
432
|
+
for (const fid of this.registry.framesForSession(sessionId)) {
|
|
433
|
+
this.registry.onFrameDetached(fid, "remove");
|
|
434
|
+
this.frameCache.delete(fid);
|
|
435
|
+
}
|
|
436
|
+
this.teardownConsoleTap(sessionId);
|
|
437
|
+
this.sessions.delete(sessionId);
|
|
438
|
+
this.networkManager.untrackSession(sessionId);
|
|
439
|
+
}
|
|
440
|
+
// ---------------- Ownership helpers / lookups ----------------
|
|
441
|
+
/** Return the owning CDP session for a frameId (falls back to main session) */
|
|
442
|
+
getSessionForFrame(frameId) {
|
|
443
|
+
const sid = this.registry.getOwnerSessionId(frameId);
|
|
444
|
+
if (!sid)
|
|
445
|
+
return this.mainSession;
|
|
446
|
+
return this.sessions.get(sid) ?? this.mainSession;
|
|
447
|
+
}
|
|
448
|
+
/** Always returns a Frame bound to the owning session */
|
|
449
|
+
frameForId(frameId) {
|
|
450
|
+
const hit = this.frameCache.get(frameId);
|
|
451
|
+
if (hit)
|
|
452
|
+
return hit;
|
|
453
|
+
const sess = this.getSessionForFrame(frameId);
|
|
454
|
+
const f = new Frame(sess, frameId, this.pageId, this.browserIsRemote);
|
|
455
|
+
this.frameCache.set(frameId, f);
|
|
456
|
+
return f;
|
|
457
|
+
}
|
|
458
|
+
/** Expose a session by id (used by snapshot to resolve session id -> session) */
|
|
459
|
+
getSessionById(id) {
|
|
460
|
+
return this.sessions.get(id);
|
|
461
|
+
}
|
|
462
|
+
registerSessionForNetwork(session) {
|
|
463
|
+
this.networkManager.trackSession(session);
|
|
464
|
+
}
|
|
465
|
+
unregisterSessionForNetwork(sessionId) {
|
|
466
|
+
this.networkManager.untrackSession(sessionId);
|
|
467
|
+
}
|
|
468
|
+
on(event, listener) {
|
|
469
|
+
if (event !== "console") {
|
|
470
|
+
throw new StagehandInvalidArgumentError(`Unsupported event: ${event}`);
|
|
471
|
+
}
|
|
472
|
+
const firstListener = this.consoleListeners.size === 0;
|
|
473
|
+
this.consoleListeners.add(listener);
|
|
474
|
+
if (firstListener) {
|
|
475
|
+
this.ensureConsoleTaps();
|
|
476
|
+
}
|
|
477
|
+
return this;
|
|
478
|
+
}
|
|
479
|
+
once(event, listener) {
|
|
480
|
+
if (event !== "console") {
|
|
481
|
+
throw new StagehandInvalidArgumentError(`Unsupported event: ${event}`);
|
|
482
|
+
}
|
|
483
|
+
const wrapper = (message) => {
|
|
484
|
+
this.off("console", wrapper);
|
|
485
|
+
listener(message);
|
|
486
|
+
};
|
|
487
|
+
return this.on("console", wrapper);
|
|
488
|
+
}
|
|
489
|
+
off(event, listener) {
|
|
490
|
+
if (event !== "console") {
|
|
491
|
+
throw new StagehandInvalidArgumentError(`Unsupported event: ${event}`);
|
|
492
|
+
}
|
|
493
|
+
this.consoleListeners.delete(listener);
|
|
494
|
+
if (this.consoleListeners.size === 0) {
|
|
495
|
+
this.removeAllConsoleTaps();
|
|
496
|
+
}
|
|
497
|
+
return this;
|
|
498
|
+
}
|
|
499
|
+
// ---------------- MAIN APIs ----------------
|
|
500
|
+
targetId() {
|
|
501
|
+
return this._targetId;
|
|
502
|
+
}
|
|
503
|
+
/**
|
|
504
|
+
* Send a CDP command through the main session.
|
|
505
|
+
* Allows external consumers to execute arbitrary Chrome DevTools Protocol commands.
|
|
506
|
+
*
|
|
507
|
+
* @param method - The CDP method name (e.g., "Page.enable", "Runtime.evaluate")
|
|
508
|
+
* @param params - Optional parameters for the CDP command
|
|
509
|
+
* @returns Promise resolving to the typed CDP response
|
|
510
|
+
*
|
|
511
|
+
* @example
|
|
512
|
+
* // Enable the Runtime domain
|
|
513
|
+
* await page.sendCDP("Runtime.enable");
|
|
514
|
+
*
|
|
515
|
+
* @example
|
|
516
|
+
* // Evaluate JavaScript with typed response
|
|
517
|
+
* const result = await page.sendCDP<Protocol.Runtime.EvaluateResponse>(
|
|
518
|
+
* "Runtime.evaluate",
|
|
519
|
+
* { expression: "1 + 1" }
|
|
520
|
+
* );
|
|
521
|
+
*/
|
|
522
|
+
sendCDP(method, params) {
|
|
523
|
+
return this.mainSession.send(method, params);
|
|
524
|
+
}
|
|
525
|
+
/** Seed the cached URL before navigation events converge. */
|
|
526
|
+
seedCurrentUrl(url) {
|
|
527
|
+
if (!url)
|
|
528
|
+
return;
|
|
529
|
+
try {
|
|
530
|
+
const normalized = String(url).trim();
|
|
531
|
+
if (!normalized)
|
|
532
|
+
return;
|
|
533
|
+
this._currentUrl = normalized;
|
|
534
|
+
}
|
|
535
|
+
catch {
|
|
536
|
+
// ignore invalid url seeds
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
mainFrameId() {
|
|
540
|
+
return this.registry.mainFrameId();
|
|
541
|
+
}
|
|
542
|
+
mainFrame() {
|
|
543
|
+
return this.mainFrameWrapper;
|
|
544
|
+
}
|
|
545
|
+
/**
|
|
546
|
+
* Close this top-level page (tab). Best-effort via Target.closeTarget.
|
|
547
|
+
*/
|
|
548
|
+
async close() {
|
|
549
|
+
try {
|
|
550
|
+
await this.conn.send("Target.closeTarget", { targetId: this._targetId });
|
|
551
|
+
}
|
|
552
|
+
catch {
|
|
553
|
+
// ignore
|
|
554
|
+
}
|
|
555
|
+
const deadline = Date.now() + 2000;
|
|
556
|
+
while (Date.now() < deadline) {
|
|
557
|
+
try {
|
|
558
|
+
const targets = await this.conn.getTargets();
|
|
559
|
+
if (!targets.some((t) => t.targetId === this._targetId)) {
|
|
560
|
+
this.networkManager.dispose();
|
|
561
|
+
return;
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
catch {
|
|
565
|
+
// ignore and retry
|
|
566
|
+
}
|
|
567
|
+
await new Promise((r) => setTimeout(r, 25));
|
|
568
|
+
}
|
|
569
|
+
this.networkManager.dispose();
|
|
570
|
+
this.removeAllConsoleTaps();
|
|
571
|
+
this.consoleListeners.clear();
|
|
572
|
+
}
|
|
573
|
+
getFullFrameTree() {
|
|
574
|
+
return this.asProtocolFrameTree(this.mainFrameId());
|
|
575
|
+
}
|
|
576
|
+
asProtocolFrameTree(rootMainFrameId) {
|
|
577
|
+
return this.registry.asProtocolFrameTree(rootMainFrameId);
|
|
578
|
+
}
|
|
579
|
+
ensureOrdinal(frameId) {
|
|
580
|
+
const hit = this.frameOrdinals.get(frameId);
|
|
581
|
+
if (hit !== undefined)
|
|
582
|
+
return hit;
|
|
583
|
+
const ord = this.nextOrdinal++;
|
|
584
|
+
this.frameOrdinals.set(frameId, ord);
|
|
585
|
+
return ord;
|
|
586
|
+
}
|
|
587
|
+
/** Public getter for snapshot code / handlers. */
|
|
588
|
+
getOrdinal(frameId) {
|
|
589
|
+
return this.ensureOrdinal(frameId);
|
|
590
|
+
}
|
|
591
|
+
listAllFrameIds() {
|
|
592
|
+
return this.registry.listAllFrames();
|
|
593
|
+
}
|
|
594
|
+
ensureConsoleTaps() {
|
|
595
|
+
if (this.consoleListeners.size === 0)
|
|
596
|
+
return;
|
|
597
|
+
this.installConsoleTap(this.mainSession);
|
|
598
|
+
for (const session of this.sessions.values()) {
|
|
599
|
+
this.installConsoleTap(session);
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
installConsoleTap(session) {
|
|
603
|
+
const key = this.sessionKey(session);
|
|
604
|
+
if (this.consoleHandlers.has(key))
|
|
605
|
+
return;
|
|
606
|
+
void session.send("Runtime.enable").catch(() => { });
|
|
607
|
+
const handler = (evt) => {
|
|
608
|
+
this.emitConsole(evt);
|
|
609
|
+
};
|
|
610
|
+
session.on("Runtime.consoleAPICalled", handler);
|
|
611
|
+
this.consoleHandlers.set(key, handler);
|
|
612
|
+
}
|
|
613
|
+
sessionKey(session) {
|
|
614
|
+
return session.id ?? "__root__";
|
|
615
|
+
}
|
|
616
|
+
resolveSessionByKey(key) {
|
|
617
|
+
if (this.mainSession.id) {
|
|
618
|
+
if (this.mainSession.id === key)
|
|
619
|
+
return this.mainSession;
|
|
620
|
+
}
|
|
621
|
+
else if (key === "__root__") {
|
|
622
|
+
return this.mainSession;
|
|
623
|
+
}
|
|
624
|
+
return this.sessions.get(key);
|
|
625
|
+
}
|
|
626
|
+
teardownConsoleTap(key) {
|
|
627
|
+
const handler = this.consoleHandlers.get(key);
|
|
628
|
+
if (!handler)
|
|
629
|
+
return;
|
|
630
|
+
const session = this.resolveSessionByKey(key);
|
|
631
|
+
session?.off("Runtime.consoleAPICalled", handler);
|
|
632
|
+
this.consoleHandlers.delete(key);
|
|
633
|
+
}
|
|
634
|
+
removeAllConsoleTaps() {
|
|
635
|
+
for (const key of [...this.consoleHandlers.keys()]) {
|
|
636
|
+
this.teardownConsoleTap(key);
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
emitConsole(evt) {
|
|
640
|
+
if (this.consoleListeners.size === 0)
|
|
641
|
+
return;
|
|
642
|
+
const message = new ConsoleMessage(evt, this);
|
|
643
|
+
const listeners = [...this.consoleListeners];
|
|
644
|
+
for (const listener of listeners) {
|
|
645
|
+
try {
|
|
646
|
+
listener(message);
|
|
647
|
+
}
|
|
648
|
+
catch (error) {
|
|
649
|
+
v3Logger({
|
|
650
|
+
category: "page",
|
|
651
|
+
message: "Console listener threw",
|
|
652
|
+
level: 2,
|
|
653
|
+
auxiliary: {
|
|
654
|
+
error: { value: String(error), type: "string" },
|
|
655
|
+
type: { value: evt.type, type: "string" },
|
|
656
|
+
},
|
|
657
|
+
});
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
// -------- Convenience APIs delegated to the current main frame --------
|
|
662
|
+
/**
|
|
663
|
+
* Navigate the page; optionally wait for a lifecycle state.
|
|
664
|
+
* Waits on the **current** main frame and follows root swaps during navigation.
|
|
665
|
+
*/
|
|
666
|
+
async goto(url, options) {
|
|
667
|
+
const waitUntil = options?.waitUntil ?? "domcontentloaded";
|
|
668
|
+
const timeout = options?.timeoutMs ?? 15000;
|
|
669
|
+
const navigationCommandId = this.beginNavigationCommand();
|
|
670
|
+
const tracker = new NavigationResponseTracker({
|
|
671
|
+
page: this,
|
|
672
|
+
session: this.mainSession,
|
|
673
|
+
navigationCommandId,
|
|
674
|
+
});
|
|
675
|
+
const watcher = new LifecycleWatcher({
|
|
676
|
+
page: this,
|
|
677
|
+
mainSession: this.mainSession,
|
|
678
|
+
networkManager: this.networkManager,
|
|
679
|
+
waitUntil,
|
|
680
|
+
timeoutMs: timeout,
|
|
681
|
+
navigationCommandId,
|
|
682
|
+
});
|
|
683
|
+
try {
|
|
684
|
+
// Route to API if available
|
|
685
|
+
if (this.apiClient) {
|
|
686
|
+
const result = await this.apiClient.goto(url, { waitUntil: options?.waitUntil }, this.mainFrameId());
|
|
687
|
+
this._currentUrl = url;
|
|
688
|
+
if (isSerializableResponse(result)) {
|
|
689
|
+
return Response.fromSerializable(result, {
|
|
690
|
+
page: this,
|
|
691
|
+
session: this.mainSession,
|
|
692
|
+
});
|
|
693
|
+
}
|
|
694
|
+
return result;
|
|
695
|
+
}
|
|
696
|
+
const response = await this.mainSession.send("Page.navigate", { url });
|
|
697
|
+
this._currentUrl = url;
|
|
698
|
+
if (response?.loaderId) {
|
|
699
|
+
watcher.setExpectedLoaderId(response.loaderId);
|
|
700
|
+
tracker.setExpectedLoaderId(response.loaderId);
|
|
701
|
+
}
|
|
702
|
+
await watcher.wait();
|
|
703
|
+
return await tracker.navigationCompleted();
|
|
704
|
+
}
|
|
705
|
+
finally {
|
|
706
|
+
watcher.dispose();
|
|
707
|
+
tracker.dispose();
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
/**
|
|
711
|
+
* Reload the page; optionally wait for a lifecycle state.
|
|
712
|
+
*/
|
|
713
|
+
async reload(options) {
|
|
714
|
+
const waitUntil = options?.waitUntil;
|
|
715
|
+
const timeout = options?.timeoutMs ?? 15000;
|
|
716
|
+
const navigationCommandId = this.beginNavigationCommand();
|
|
717
|
+
const tracker = new NavigationResponseTracker({
|
|
718
|
+
page: this,
|
|
719
|
+
session: this.mainSession,
|
|
720
|
+
navigationCommandId,
|
|
721
|
+
});
|
|
722
|
+
tracker.expectNavigationWithoutKnownLoader();
|
|
723
|
+
const watcher = waitUntil
|
|
724
|
+
? new LifecycleWatcher({
|
|
725
|
+
page: this,
|
|
726
|
+
mainSession: this.mainSession,
|
|
727
|
+
networkManager: this.networkManager,
|
|
728
|
+
waitUntil,
|
|
729
|
+
timeoutMs: timeout,
|
|
730
|
+
navigationCommandId,
|
|
731
|
+
})
|
|
732
|
+
: null;
|
|
733
|
+
try {
|
|
734
|
+
await this.mainSession.send("Page.reload", {
|
|
735
|
+
ignoreCache: options?.ignoreCache ?? false,
|
|
736
|
+
});
|
|
737
|
+
if (watcher) {
|
|
738
|
+
await watcher.wait();
|
|
739
|
+
}
|
|
740
|
+
return await tracker.navigationCompleted();
|
|
741
|
+
}
|
|
742
|
+
finally {
|
|
743
|
+
watcher?.dispose();
|
|
744
|
+
tracker.dispose();
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
/**
|
|
748
|
+
* Navigate back in history if possible; optionally wait for a lifecycle state.
|
|
749
|
+
*/
|
|
750
|
+
async goBack(options) {
|
|
751
|
+
const { entries, currentIndex } = await this.mainSession.send("Page.getNavigationHistory");
|
|
752
|
+
const prev = entries[currentIndex - 1];
|
|
753
|
+
if (!prev)
|
|
754
|
+
return null; // nothing to do
|
|
755
|
+
const waitUntil = options?.waitUntil;
|
|
756
|
+
const timeout = options?.timeoutMs ?? 15000;
|
|
757
|
+
const navigationCommandId = this.beginNavigationCommand();
|
|
758
|
+
const tracker = new NavigationResponseTracker({
|
|
759
|
+
page: this,
|
|
760
|
+
session: this.mainSession,
|
|
761
|
+
navigationCommandId,
|
|
762
|
+
});
|
|
763
|
+
tracker.expectNavigationWithoutKnownLoader();
|
|
764
|
+
const watcher = waitUntil
|
|
765
|
+
? new LifecycleWatcher({
|
|
766
|
+
page: this,
|
|
767
|
+
mainSession: this.mainSession,
|
|
768
|
+
networkManager: this.networkManager,
|
|
769
|
+
waitUntil,
|
|
770
|
+
timeoutMs: timeout,
|
|
771
|
+
navigationCommandId,
|
|
772
|
+
})
|
|
773
|
+
: null;
|
|
774
|
+
try {
|
|
775
|
+
await this.mainSession.send("Page.navigateToHistoryEntry", {
|
|
776
|
+
entryId: prev.id,
|
|
777
|
+
});
|
|
778
|
+
this._currentUrl = prev.url ?? this._currentUrl;
|
|
779
|
+
if (watcher) {
|
|
780
|
+
await watcher.wait();
|
|
781
|
+
}
|
|
782
|
+
return await tracker.navigationCompleted();
|
|
783
|
+
}
|
|
784
|
+
finally {
|
|
785
|
+
watcher?.dispose();
|
|
786
|
+
tracker.dispose();
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
/**
|
|
790
|
+
* Navigate forward in history if possible; optionally wait for a lifecycle state.
|
|
791
|
+
*/
|
|
792
|
+
async goForward(options) {
|
|
793
|
+
const { entries, currentIndex } = await this.mainSession.send("Page.getNavigationHistory");
|
|
794
|
+
const next = entries[currentIndex + 1];
|
|
795
|
+
if (!next)
|
|
796
|
+
return null; // nothing to do
|
|
797
|
+
const waitUntil = options?.waitUntil;
|
|
798
|
+
const timeout = options?.timeoutMs ?? 15000;
|
|
799
|
+
const navigationCommandId = this.beginNavigationCommand();
|
|
800
|
+
const tracker = new NavigationResponseTracker({
|
|
801
|
+
page: this,
|
|
802
|
+
session: this.mainSession,
|
|
803
|
+
navigationCommandId,
|
|
804
|
+
});
|
|
805
|
+
tracker.expectNavigationWithoutKnownLoader();
|
|
806
|
+
const watcher = waitUntil
|
|
807
|
+
? new LifecycleWatcher({
|
|
808
|
+
page: this,
|
|
809
|
+
mainSession: this.mainSession,
|
|
810
|
+
networkManager: this.networkManager,
|
|
811
|
+
waitUntil,
|
|
812
|
+
timeoutMs: timeout,
|
|
813
|
+
navigationCommandId,
|
|
814
|
+
})
|
|
815
|
+
: null;
|
|
816
|
+
try {
|
|
817
|
+
await this.mainSession.send("Page.navigateToHistoryEntry", {
|
|
818
|
+
entryId: next.id,
|
|
819
|
+
});
|
|
820
|
+
this._currentUrl = next.url ?? this._currentUrl;
|
|
821
|
+
if (watcher) {
|
|
822
|
+
await watcher.wait();
|
|
823
|
+
}
|
|
824
|
+
return await tracker.navigationCompleted();
|
|
825
|
+
}
|
|
826
|
+
finally {
|
|
827
|
+
watcher?.dispose();
|
|
828
|
+
tracker.dispose();
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
/**
|
|
832
|
+
* Return the current page URL (synchronous, cached from navigation events).
|
|
833
|
+
*/
|
|
834
|
+
url() {
|
|
835
|
+
return this._currentUrl;
|
|
836
|
+
}
|
|
837
|
+
beginNavigationCommand() {
|
|
838
|
+
const id = ++this.navigationCommandSeq;
|
|
839
|
+
this.latestNavigationCommandId = id;
|
|
840
|
+
return id;
|
|
841
|
+
}
|
|
842
|
+
isCurrentNavigationCommand(id) {
|
|
843
|
+
return this.latestNavigationCommandId === id;
|
|
844
|
+
}
|
|
845
|
+
/**
|
|
846
|
+
* Return the current page title.
|
|
847
|
+
* Prefers reading from the active document via Runtime.evaluate to reflect dynamic changes.
|
|
848
|
+
* Falls back to navigation history title if evaluation is unavailable.
|
|
849
|
+
*/
|
|
850
|
+
async title() {
|
|
851
|
+
try {
|
|
852
|
+
await this.mainSession.send("Runtime.enable").catch(() => { });
|
|
853
|
+
const ctxId = await this.mainWorldExecutionContextId();
|
|
854
|
+
const { result } = await this.mainSession.send("Runtime.evaluate", {
|
|
855
|
+
expression: "document.title",
|
|
856
|
+
contextId: ctxId,
|
|
857
|
+
returnByValue: true,
|
|
858
|
+
});
|
|
859
|
+
return String(result?.value ?? "");
|
|
860
|
+
}
|
|
861
|
+
catch {
|
|
862
|
+
// Fallback: use navigation history entry title
|
|
863
|
+
try {
|
|
864
|
+
const { entries, currentIndex } = await this.mainSession.send("Page.getNavigationHistory");
|
|
865
|
+
return entries[currentIndex]?.title ?? "";
|
|
866
|
+
}
|
|
867
|
+
catch {
|
|
868
|
+
return "";
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
/**
|
|
873
|
+
* Capture a screenshot with Playwright-style options.
|
|
874
|
+
*
|
|
875
|
+
* @param options Optional screenshot configuration.
|
|
876
|
+
* @param options.animations Control CSS/Web animations during capture. Use
|
|
877
|
+
* "disabled" to fast-forward finite animations and pause infinite ones.
|
|
878
|
+
* @param options.caret Either hide the text caret (default) or leave it
|
|
879
|
+
* visible via "initial".
|
|
880
|
+
* @param options.clip Restrict capture to a specific rectangle (in CSS
|
|
881
|
+
* pixels). Cannot be combined with `fullPage`.
|
|
882
|
+
* @param options.fullPage Capture the full scrollable page instead of the
|
|
883
|
+
* current viewport.
|
|
884
|
+
* @param options.mask Array of locators that should be covered with an
|
|
885
|
+
* overlay while the screenshot is taken.
|
|
886
|
+
* @param options.maskColor CSS color used for the mask overlay (default
|
|
887
|
+
* `#FF00FF`).
|
|
888
|
+
* @param options.omitBackground Make the default page background transparent
|
|
889
|
+
* (PNG only).
|
|
890
|
+
* @param options.path File path to write the screenshot to. The file extension
|
|
891
|
+
* determines the image type when `type` is not explicitly provided.
|
|
892
|
+
* @param options.quality JPEG quality (0–100). Only applies when
|
|
893
|
+
* `type === "jpeg"`.
|
|
894
|
+
* @param options.scale Render scale: use "css" for one pixel per CSS pixel,
|
|
895
|
+
* otherwise the default "device" leverages the current device pixel ratio.
|
|
896
|
+
* @param options.style Additional CSS text injected into every frame before
|
|
897
|
+
* capture (removed afterwards).
|
|
898
|
+
* @param options.timeout Maximum capture duration in milliseconds before a
|
|
899
|
+
* timeout error is thrown.
|
|
900
|
+
* @param options.type Image format (`"png"` by default).
|
|
901
|
+
*/
|
|
902
|
+
async screenshot(options) {
|
|
903
|
+
const opts = options ?? {};
|
|
904
|
+
const type = opts.type ?? "png";
|
|
905
|
+
if (type !== "png" && type !== "jpeg") {
|
|
906
|
+
throw new StagehandInvalidArgumentError(`screenshot: unsupported image type "${type}"`);
|
|
907
|
+
}
|
|
908
|
+
if (opts.fullPage && opts.clip) {
|
|
909
|
+
throw new StagehandInvalidArgumentError("screenshot: clip and fullPage cannot be used together");
|
|
910
|
+
}
|
|
911
|
+
if (type === "png" && typeof opts.quality === "number") {
|
|
912
|
+
throw new StagehandInvalidArgumentError('screenshot: quality option is only valid for type="jpeg"');
|
|
913
|
+
}
|
|
914
|
+
const caretMode = opts.caret ?? "hide";
|
|
915
|
+
const animationsMode = opts.animations ?? "allow";
|
|
916
|
+
const scaleMode = opts.scale ?? "device";
|
|
917
|
+
const frames = collectFramesForScreenshot(this);
|
|
918
|
+
const clip = opts.clip ? normalizeScreenshotClip(opts.clip) : undefined;
|
|
919
|
+
const captureScale = await computeScreenshotScale(this, scaleMode);
|
|
920
|
+
const maskLocators = (opts.mask ?? []).filter((locator) => Boolean(locator));
|
|
921
|
+
const cleanupTasks = [];
|
|
922
|
+
const exec = async () => {
|
|
923
|
+
try {
|
|
924
|
+
if (opts.omitBackground) {
|
|
925
|
+
cleanupTasks.push(await setTransparentBackground(this.mainSession));
|
|
926
|
+
}
|
|
927
|
+
if (animationsMode === "disabled") {
|
|
928
|
+
cleanupTasks.push(await disableAnimations(frames));
|
|
929
|
+
}
|
|
930
|
+
if (caretMode === "hide") {
|
|
931
|
+
cleanupTasks.push(await hideCaret(frames));
|
|
932
|
+
}
|
|
933
|
+
if (opts.style && opts.style.trim()) {
|
|
934
|
+
cleanupTasks.push(await applyStyleToFrames(frames, opts.style, "custom"));
|
|
935
|
+
}
|
|
936
|
+
if (maskLocators.length > 0) {
|
|
937
|
+
cleanupTasks.push(await applyMaskOverlays(maskLocators, opts.maskColor ?? "#FF00FF"));
|
|
938
|
+
}
|
|
939
|
+
const buffer = await this.mainFrameWrapper.screenshot({
|
|
940
|
+
fullPage: opts.fullPage,
|
|
941
|
+
clip,
|
|
942
|
+
type,
|
|
943
|
+
quality: type === "jpeg" ? opts.quality : undefined,
|
|
944
|
+
scale: captureScale,
|
|
945
|
+
});
|
|
946
|
+
if (opts.path) {
|
|
947
|
+
await fs.writeFile(opts.path, buffer);
|
|
948
|
+
}
|
|
949
|
+
return buffer;
|
|
950
|
+
}
|
|
951
|
+
finally {
|
|
952
|
+
await runScreenshotCleanups(cleanupTasks);
|
|
953
|
+
}
|
|
954
|
+
};
|
|
955
|
+
return withScreenshotTimeout(opts.timeout, exec);
|
|
956
|
+
}
|
|
957
|
+
/**
|
|
958
|
+
* Create a locator bound to the current main frame.
|
|
959
|
+
*/
|
|
960
|
+
locator(selector) {
|
|
961
|
+
return this.mainFrameWrapper.locator(selector);
|
|
962
|
+
}
|
|
963
|
+
/**
|
|
964
|
+
* Deep locator that supports cross-iframe traversal.
|
|
965
|
+
* - Recognizes '>>' hop notation to enter iframe contexts.
|
|
966
|
+
* - Supports deep XPath that includes iframe steps (e.g., '/html/body/iframe[2]//div').
|
|
967
|
+
* Returns a Locator scoped to the appropriate frame.
|
|
968
|
+
*/
|
|
969
|
+
deepLocator(selector) {
|
|
970
|
+
return deepLocatorFromPage(this, this.mainFrameWrapper, selector);
|
|
971
|
+
}
|
|
972
|
+
/**
|
|
973
|
+
* Frame locator similar to Playwright: targets iframe elements and scopes
|
|
974
|
+
* subsequent locators to that frame. Supports chaining.
|
|
975
|
+
*/
|
|
976
|
+
frameLocator(selector) {
|
|
977
|
+
return new FrameLocator(this, selector);
|
|
978
|
+
}
|
|
979
|
+
/**
|
|
980
|
+
* List all frames belonging to this page as Frame objects bound to their owning sessions.
|
|
981
|
+
* The list is ordered by a stable ordinal assigned during the page lifetime.
|
|
982
|
+
*/
|
|
983
|
+
frames() {
|
|
984
|
+
const ids = this.listAllFrameIds();
|
|
985
|
+
const withOrd = ids.map((id) => ({ id, ord: this.getOrdinal(id) }));
|
|
986
|
+
withOrd.sort((a, b) => a.ord - b.ord);
|
|
987
|
+
return withOrd.map(({ id }) => this.frameForId(id));
|
|
988
|
+
}
|
|
989
|
+
/**
|
|
990
|
+
* Wait until the page reaches a lifecycle state on the current main frame.
|
|
991
|
+
* Mirrors Playwright's API signatures.
|
|
992
|
+
*/
|
|
993
|
+
async waitForLoadState(state, timeoutMs) {
|
|
994
|
+
await this.waitForMainLoadState(state, timeoutMs ?? 15000);
|
|
995
|
+
}
|
|
996
|
+
/**
|
|
997
|
+
* Wait for a specified amount of time.
|
|
998
|
+
*
|
|
999
|
+
* @param ms The number of milliseconds to wait.
|
|
1000
|
+
*/
|
|
1001
|
+
async waitForTimeout(ms) {
|
|
1002
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
1003
|
+
}
|
|
1004
|
+
/**
|
|
1005
|
+
* Wait for an element matching the selector to appear in the DOM.
|
|
1006
|
+
* Uses MutationObserver for efficiency
|
|
1007
|
+
* Pierces shadow DOM by default.
|
|
1008
|
+
* Supports iframe hop notation with '>>' (e.g., 'iframe#checkout >> .submit-btn').
|
|
1009
|
+
*
|
|
1010
|
+
* @param selector CSS selector to wait for (supports '>>' for iframe hops)
|
|
1011
|
+
* @param options
|
|
1012
|
+
* @param options.state Element state to wait for: 'attached' | 'detached' | 'visible' | 'hidden' (default: 'visible')
|
|
1013
|
+
* @param options.timeout Maximum time to wait in milliseconds (default: 30000)
|
|
1014
|
+
* @param options.pierceShadow Whether to search inside shadow DOM (default: true)
|
|
1015
|
+
* @returns True when the condition is met
|
|
1016
|
+
* @throws Error if timeout is reached before the condition is met
|
|
1017
|
+
*/
|
|
1018
|
+
async waitForSelector(selector, options) {
|
|
1019
|
+
const timeout = options?.timeout ?? 30000;
|
|
1020
|
+
const state = options?.state ?? "visible";
|
|
1021
|
+
const pierceShadow = options?.pierceShadow ?? true;
|
|
1022
|
+
const startTime = Date.now();
|
|
1023
|
+
const root = this.mainFrameWrapper;
|
|
1024
|
+
const { frame: targetFrame, selector: finalSelector } = await resolveLocatorTarget(this, root, selector);
|
|
1025
|
+
const elapsed = Date.now() - startTime;
|
|
1026
|
+
const remainingTimeout = Math.max(0, timeout - elapsed);
|
|
1027
|
+
const expression = buildLocatorInvocation("waitForSelector", [
|
|
1028
|
+
JSON.stringify(finalSelector),
|
|
1029
|
+
JSON.stringify(state),
|
|
1030
|
+
String(remainingTimeout),
|
|
1031
|
+
String(pierceShadow),
|
|
1032
|
+
]);
|
|
1033
|
+
return targetFrame.evaluate(expression);
|
|
1034
|
+
}
|
|
1035
|
+
/**
|
|
1036
|
+
* Evaluate a function or expression in the current main frame's main world.
|
|
1037
|
+
* - If a string is provided, it is treated as a JS expression.
|
|
1038
|
+
* - If a function is provided, it is stringified and invoked with the optional argument.
|
|
1039
|
+
* - The return value should be JSON-serializable. Non-serializable objects will
|
|
1040
|
+
* best-effort serialize via JSON.stringify inside the page context.
|
|
1041
|
+
*/
|
|
1042
|
+
async evaluate(pageFunctionOrExpression, arg) {
|
|
1043
|
+
await this.mainSession.send("Runtime.enable").catch(() => { });
|
|
1044
|
+
const ctxId = await this.mainWorldExecutionContextId();
|
|
1045
|
+
const isString = typeof pageFunctionOrExpression === "string";
|
|
1046
|
+
let expression;
|
|
1047
|
+
if (isString) {
|
|
1048
|
+
expression = String(pageFunctionOrExpression);
|
|
1049
|
+
}
|
|
1050
|
+
else {
|
|
1051
|
+
const fnSrc = pageFunctionOrExpression.toString();
|
|
1052
|
+
const argJson = JSON.stringify(arg);
|
|
1053
|
+
expression = `(() => {
|
|
1054
|
+
const __fn = ${fnSrc};
|
|
1055
|
+
const __arg = ${argJson};
|
|
1056
|
+
try {
|
|
1057
|
+
const __res = __fn(__arg);
|
|
1058
|
+
return Promise.resolve(__res).then(v => {
|
|
1059
|
+
try { return JSON.parse(JSON.stringify(v)); } catch { return v; }
|
|
1060
|
+
});
|
|
1061
|
+
} catch (e) { throw e; }
|
|
1062
|
+
})()`;
|
|
1063
|
+
}
|
|
1064
|
+
const { result, exceptionDetails } = await this.mainSession.send("Runtime.evaluate", {
|
|
1065
|
+
expression,
|
|
1066
|
+
contextId: ctxId,
|
|
1067
|
+
returnByValue: true,
|
|
1068
|
+
awaitPromise: true,
|
|
1069
|
+
});
|
|
1070
|
+
if (exceptionDetails) {
|
|
1071
|
+
const msg = exceptionDetails.text ||
|
|
1072
|
+
exceptionDetails.exception?.description ||
|
|
1073
|
+
"Evaluation failed";
|
|
1074
|
+
throw new StagehandEvalError(msg);
|
|
1075
|
+
}
|
|
1076
|
+
return result?.value;
|
|
1077
|
+
}
|
|
1078
|
+
/**
|
|
1079
|
+
* Force the page viewport to an exact CSS size and device scale factor.
|
|
1080
|
+
* Ensures screenshots match width x height pixels when deviceScaleFactor = 1.
|
|
1081
|
+
*/
|
|
1082
|
+
// @logAction("Page.setViewportSize") // disabled because it's pretty noisy, can always re-enable if needed for debugging
|
|
1083
|
+
async setViewportSize(width, height, options) {
|
|
1084
|
+
const dsf = Math.max(0.01, options?.deviceScaleFactor ?? 1);
|
|
1085
|
+
await this.mainSession
|
|
1086
|
+
.send("Emulation.setDeviceMetricsOverride", {
|
|
1087
|
+
width,
|
|
1088
|
+
height,
|
|
1089
|
+
deviceScaleFactor: dsf,
|
|
1090
|
+
mobile: false,
|
|
1091
|
+
screenWidth: width,
|
|
1092
|
+
screenHeight: height,
|
|
1093
|
+
positionX: 0,
|
|
1094
|
+
positionY: 0,
|
|
1095
|
+
scale: 1,
|
|
1096
|
+
})
|
|
1097
|
+
.catch(() => { });
|
|
1098
|
+
// Best-effort ensure visible size in headless
|
|
1099
|
+
await this.mainSession
|
|
1100
|
+
.send("Emulation.setVisibleSize", { width, height })
|
|
1101
|
+
.catch(() => { });
|
|
1102
|
+
}
|
|
1103
|
+
/**
|
|
1104
|
+
* Click at absolute page coordinates (CSS pixels).
|
|
1105
|
+
* Dispatches mouseMoved → mousePressed → mouseReleased via CDP Input domain
|
|
1106
|
+
* on the top-level page target's session. Coordinates are relative to the
|
|
1107
|
+
* viewport origin (top-left). Does not scroll.
|
|
1108
|
+
*/
|
|
1109
|
+
async click(x, y, options) {
|
|
1110
|
+
const button = options?.button ?? "left";
|
|
1111
|
+
const clickCount = options?.clickCount ?? 1;
|
|
1112
|
+
let xpathResult;
|
|
1113
|
+
if (options?.returnXpath) {
|
|
1114
|
+
// Resolve the deepest node at the given coordinates and compute absolute XPath efficiently
|
|
1115
|
+
try {
|
|
1116
|
+
const hit = await resolveXpathForLocation(this, x, y);
|
|
1117
|
+
if (hit) {
|
|
1118
|
+
v3Logger({
|
|
1119
|
+
category: "page",
|
|
1120
|
+
message: "click resolved hit",
|
|
1121
|
+
level: 2,
|
|
1122
|
+
auxiliary: {
|
|
1123
|
+
frameId: { value: String(hit.frameId), type: "string" },
|
|
1124
|
+
backendNodeId: {
|
|
1125
|
+
value: String(hit.backendNodeId),
|
|
1126
|
+
type: "string",
|
|
1127
|
+
},
|
|
1128
|
+
x: { value: String(x), type: "integer" },
|
|
1129
|
+
y: { value: String(y), type: "integer" },
|
|
1130
|
+
},
|
|
1131
|
+
});
|
|
1132
|
+
xpathResult = hit.absoluteXPath;
|
|
1133
|
+
v3Logger({
|
|
1134
|
+
category: "page",
|
|
1135
|
+
message: `click resolved xpath`,
|
|
1136
|
+
level: 2,
|
|
1137
|
+
auxiliary: {
|
|
1138
|
+
xpath: { value: String(xpathResult ?? ""), type: "string" },
|
|
1139
|
+
},
|
|
1140
|
+
});
|
|
1141
|
+
}
|
|
1142
|
+
}
|
|
1143
|
+
catch {
|
|
1144
|
+
// best-effort; fall through if any step fails
|
|
1145
|
+
}
|
|
1146
|
+
}
|
|
1147
|
+
// Synthesize a simple mouse move + press + release sequence.
|
|
1148
|
+
// Fire events without waiting between them to keep multi-clicks tight.
|
|
1149
|
+
await this.updateCursor(x, y);
|
|
1150
|
+
const dispatches = [];
|
|
1151
|
+
dispatches.push(this.mainSession.send("Input.dispatchMouseEvent", {
|
|
1152
|
+
type: "mouseMoved",
|
|
1153
|
+
x,
|
|
1154
|
+
y,
|
|
1155
|
+
button: "none",
|
|
1156
|
+
}));
|
|
1157
|
+
for (let i = 1; i <= clickCount; i++) {
|
|
1158
|
+
dispatches.push(this.mainSession.send("Input.dispatchMouseEvent", {
|
|
1159
|
+
type: "mousePressed",
|
|
1160
|
+
x,
|
|
1161
|
+
y,
|
|
1162
|
+
button,
|
|
1163
|
+
clickCount: i,
|
|
1164
|
+
}));
|
|
1165
|
+
dispatches.push(this.mainSession.send("Input.dispatchMouseEvent", {
|
|
1166
|
+
type: "mouseReleased",
|
|
1167
|
+
x,
|
|
1168
|
+
y,
|
|
1169
|
+
button,
|
|
1170
|
+
clickCount: i,
|
|
1171
|
+
}));
|
|
1172
|
+
}
|
|
1173
|
+
await Promise.all(dispatches);
|
|
1174
|
+
return xpathResult ?? "";
|
|
1175
|
+
}
|
|
1176
|
+
/**
|
|
1177
|
+
* Hover at absolute page coordinates (CSS pixels).
|
|
1178
|
+
* Dispatches mouseMoved via CDP Input domain on the top-level page target's
|
|
1179
|
+
* session.
|
|
1180
|
+
*/
|
|
1181
|
+
async hover(x, y, options) {
|
|
1182
|
+
let xpathResult;
|
|
1183
|
+
if (options?.returnXpath) {
|
|
1184
|
+
try {
|
|
1185
|
+
const hit = await resolveXpathForLocation(this, x, y);
|
|
1186
|
+
if (hit) {
|
|
1187
|
+
v3Logger({
|
|
1188
|
+
category: "page",
|
|
1189
|
+
message: "hover resolved hit",
|
|
1190
|
+
level: 2,
|
|
1191
|
+
auxiliary: {
|
|
1192
|
+
frameId: { value: String(hit.frameId), type: "string" },
|
|
1193
|
+
backendNodeId: {
|
|
1194
|
+
value: String(hit.backendNodeId),
|
|
1195
|
+
type: "string",
|
|
1196
|
+
},
|
|
1197
|
+
x: { value: String(x), type: "integer" },
|
|
1198
|
+
y: { value: String(y), type: "integer" },
|
|
1199
|
+
},
|
|
1200
|
+
});
|
|
1201
|
+
xpathResult = hit.absoluteXPath;
|
|
1202
|
+
}
|
|
1203
|
+
}
|
|
1204
|
+
catch {
|
|
1205
|
+
v3Logger({
|
|
1206
|
+
category: "page",
|
|
1207
|
+
message: "Failed to resolve xpath for hover",
|
|
1208
|
+
level: 2,
|
|
1209
|
+
auxiliary: {
|
|
1210
|
+
x: { value: String(x), type: "integer" },
|
|
1211
|
+
y: { value: String(y), type: "integer" },
|
|
1212
|
+
},
|
|
1213
|
+
});
|
|
1214
|
+
}
|
|
1215
|
+
}
|
|
1216
|
+
await this.updateCursor(x, y);
|
|
1217
|
+
await this.mainSession.send("Input.dispatchMouseEvent", {
|
|
1218
|
+
type: "mouseMoved",
|
|
1219
|
+
x,
|
|
1220
|
+
y,
|
|
1221
|
+
button: "none",
|
|
1222
|
+
});
|
|
1223
|
+
return xpathResult ?? "";
|
|
1224
|
+
}
|
|
1225
|
+
async scroll(x, y, deltaX, deltaY, options) {
|
|
1226
|
+
let xpathResult;
|
|
1227
|
+
if (options?.returnXpath) {
|
|
1228
|
+
try {
|
|
1229
|
+
const hit = await resolveXpathForLocation(this, x, y);
|
|
1230
|
+
if (hit)
|
|
1231
|
+
xpathResult = hit.absoluteXPath;
|
|
1232
|
+
}
|
|
1233
|
+
catch {
|
|
1234
|
+
// best-effort
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1237
|
+
await this.updateCursor(x, y);
|
|
1238
|
+
await this.mainSession.send("Input.dispatchMouseEvent", {
|
|
1239
|
+
type: "mouseMoved",
|
|
1240
|
+
x,
|
|
1241
|
+
y,
|
|
1242
|
+
button: "none",
|
|
1243
|
+
});
|
|
1244
|
+
// Synthesize a simple mouse move + press + release sequence
|
|
1245
|
+
await this.mainSession.send("Input.dispatchMouseEvent", {
|
|
1246
|
+
type: "mouseWheel",
|
|
1247
|
+
x,
|
|
1248
|
+
y,
|
|
1249
|
+
button: "none",
|
|
1250
|
+
deltaX,
|
|
1251
|
+
deltaY,
|
|
1252
|
+
});
|
|
1253
|
+
return xpathResult ?? "";
|
|
1254
|
+
}
|
|
1255
|
+
/**
|
|
1256
|
+
* Drag from (fromX, fromY) to (toX, toY) using mouse events.
|
|
1257
|
+
* Sends mouseMoved → mousePressed → mouseMoved (steps) → mouseReleased.
|
|
1258
|
+
*/
|
|
1259
|
+
async dragAndDrop(fromX, fromY, toX, toY, options) {
|
|
1260
|
+
const button = options?.button ?? "left";
|
|
1261
|
+
const steps = Math.max(1, Math.floor(options?.steps ?? 1));
|
|
1262
|
+
const delay = Math.max(0, options?.delay ?? 0);
|
|
1263
|
+
const sleep = (ms) => new Promise((r) => (ms > 0 ? setTimeout(r, ms) : r()));
|
|
1264
|
+
const buttonMask = (b) => {
|
|
1265
|
+
switch (b) {
|
|
1266
|
+
case "left":
|
|
1267
|
+
return 1;
|
|
1268
|
+
case "right":
|
|
1269
|
+
return 2;
|
|
1270
|
+
case "middle":
|
|
1271
|
+
return 4;
|
|
1272
|
+
default:
|
|
1273
|
+
return 1;
|
|
1274
|
+
}
|
|
1275
|
+
};
|
|
1276
|
+
let fromXpath;
|
|
1277
|
+
let toXpath;
|
|
1278
|
+
if (options?.returnXpath) {
|
|
1279
|
+
try {
|
|
1280
|
+
const start = await resolveXpathForLocation(this, fromX, fromY);
|
|
1281
|
+
if (start)
|
|
1282
|
+
fromXpath = start.absoluteXPath;
|
|
1283
|
+
}
|
|
1284
|
+
catch {
|
|
1285
|
+
//
|
|
1286
|
+
}
|
|
1287
|
+
try {
|
|
1288
|
+
const end = await resolveXpathForLocation(this, toX, toY);
|
|
1289
|
+
if (end)
|
|
1290
|
+
toXpath = end.absoluteXPath;
|
|
1291
|
+
}
|
|
1292
|
+
catch {
|
|
1293
|
+
//
|
|
1294
|
+
}
|
|
1295
|
+
}
|
|
1296
|
+
// Move to start
|
|
1297
|
+
await this.updateCursor(fromX, fromY);
|
|
1298
|
+
await this.mainSession.send("Input.dispatchMouseEvent", {
|
|
1299
|
+
type: "mouseMoved",
|
|
1300
|
+
x: fromX,
|
|
1301
|
+
y: fromY,
|
|
1302
|
+
button: "none",
|
|
1303
|
+
});
|
|
1304
|
+
// Press
|
|
1305
|
+
await this.mainSession.send("Input.dispatchMouseEvent", {
|
|
1306
|
+
type: "mousePressed",
|
|
1307
|
+
x: fromX,
|
|
1308
|
+
y: fromY,
|
|
1309
|
+
button,
|
|
1310
|
+
buttons: buttonMask(button),
|
|
1311
|
+
clickCount: 1,
|
|
1312
|
+
});
|
|
1313
|
+
// Intermediate moves
|
|
1314
|
+
for (let i = 1; i <= steps; i++) {
|
|
1315
|
+
const t = i / steps;
|
|
1316
|
+
const x = fromX + (toX - fromX) * t;
|
|
1317
|
+
const y = fromY + (toY - fromY) * t;
|
|
1318
|
+
await this.updateCursor(x, y);
|
|
1319
|
+
await this.mainSession.send("Input.dispatchMouseEvent", {
|
|
1320
|
+
type: "mouseMoved",
|
|
1321
|
+
x,
|
|
1322
|
+
y,
|
|
1323
|
+
button,
|
|
1324
|
+
buttons: buttonMask(button),
|
|
1325
|
+
});
|
|
1326
|
+
if (delay)
|
|
1327
|
+
await sleep(delay);
|
|
1328
|
+
}
|
|
1329
|
+
// Release at end
|
|
1330
|
+
await this.updateCursor(toX, toY);
|
|
1331
|
+
await this.mainSession.send("Input.dispatchMouseEvent", {
|
|
1332
|
+
type: "mouseReleased",
|
|
1333
|
+
x: toX,
|
|
1334
|
+
y: toY,
|
|
1335
|
+
button,
|
|
1336
|
+
buttons: buttonMask(button),
|
|
1337
|
+
clickCount: 1,
|
|
1338
|
+
});
|
|
1339
|
+
return [fromXpath ?? "", toXpath ?? ""];
|
|
1340
|
+
}
|
|
1341
|
+
/**
|
|
1342
|
+
* Type a string by dispatching keyDown/keyUp events per character.
|
|
1343
|
+
* Focus must already be on the desired element. Uses CDP Input.dispatchKeyEvent
|
|
1344
|
+
* and never falls back to Input.insertText. Optional delay applies between
|
|
1345
|
+
* successive characters.
|
|
1346
|
+
*/
|
|
1347
|
+
async type(text, options) {
|
|
1348
|
+
const delay = Math.max(0, options?.delay ?? 0);
|
|
1349
|
+
const withMistakes = !!options?.withMistakes;
|
|
1350
|
+
const sleep = (ms) => new Promise((r) => (ms > 0 ? setTimeout(r, ms) : r()));
|
|
1351
|
+
const keyStroke = async (ch, override) => {
|
|
1352
|
+
if (override) {
|
|
1353
|
+
const base = {
|
|
1354
|
+
type: "keyDown",
|
|
1355
|
+
key: override.key,
|
|
1356
|
+
code: override.code,
|
|
1357
|
+
windowsVirtualKeyCode: override.windowsVirtualKeyCode,
|
|
1358
|
+
};
|
|
1359
|
+
await this.mainSession.send("Input.dispatchKeyEvent", base);
|
|
1360
|
+
await this.mainSession.send("Input.dispatchKeyEvent", {
|
|
1361
|
+
...base,
|
|
1362
|
+
type: "keyUp",
|
|
1363
|
+
});
|
|
1364
|
+
return;
|
|
1365
|
+
}
|
|
1366
|
+
// Printable character: include key, code, and text for maximum compatibility
|
|
1367
|
+
// Some sites (like Wordle) check event.key rather than relying on text input
|
|
1368
|
+
const isLetter = /^[a-zA-Z]$/.test(ch);
|
|
1369
|
+
const isDigit = /^[0-9]$/.test(ch);
|
|
1370
|
+
let key = ch;
|
|
1371
|
+
let code = "";
|
|
1372
|
+
let windowsVirtualKeyCode;
|
|
1373
|
+
if (isLetter) {
|
|
1374
|
+
// For letters, key is the character, code is KeyX where X is uppercase
|
|
1375
|
+
key = ch;
|
|
1376
|
+
code = `Key${ch.toUpperCase()}`;
|
|
1377
|
+
windowsVirtualKeyCode = ch.toUpperCase().charCodeAt(0);
|
|
1378
|
+
}
|
|
1379
|
+
else if (isDigit) {
|
|
1380
|
+
key = ch;
|
|
1381
|
+
code = `Digit${ch}`;
|
|
1382
|
+
windowsVirtualKeyCode = ch.charCodeAt(0);
|
|
1383
|
+
}
|
|
1384
|
+
else if (ch === " ") {
|
|
1385
|
+
key = " ";
|
|
1386
|
+
code = "Space";
|
|
1387
|
+
windowsVirtualKeyCode = 32;
|
|
1388
|
+
}
|
|
1389
|
+
const down = {
|
|
1390
|
+
type: "keyDown",
|
|
1391
|
+
key,
|
|
1392
|
+
code: code || undefined,
|
|
1393
|
+
text: ch,
|
|
1394
|
+
unmodifiedText: ch,
|
|
1395
|
+
windowsVirtualKeyCode,
|
|
1396
|
+
};
|
|
1397
|
+
await this.mainSession.send("Input.dispatchKeyEvent", down);
|
|
1398
|
+
await this.mainSession.send("Input.dispatchKeyEvent", {
|
|
1399
|
+
type: "keyUp",
|
|
1400
|
+
key,
|
|
1401
|
+
code: code || undefined,
|
|
1402
|
+
windowsVirtualKeyCode,
|
|
1403
|
+
});
|
|
1404
|
+
};
|
|
1405
|
+
const pressBackspace = async () => keyStroke("\b", {
|
|
1406
|
+
key: "Backspace",
|
|
1407
|
+
code: "Backspace",
|
|
1408
|
+
windowsVirtualKeyCode: 8,
|
|
1409
|
+
});
|
|
1410
|
+
const randomPrintable = (avoid) => {
|
|
1411
|
+
const pool = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 .,;:'\"!?@#$%^&*()-_=+[]{}<>/\\|`~";
|
|
1412
|
+
let c = avoid;
|
|
1413
|
+
while (c === avoid) {
|
|
1414
|
+
c = pool[Math.floor(Math.random() * pool.length)];
|
|
1415
|
+
}
|
|
1416
|
+
return c;
|
|
1417
|
+
};
|
|
1418
|
+
for (const ch of text) {
|
|
1419
|
+
// Control keys that we explicitly map
|
|
1420
|
+
if (ch === "\n" || ch === "\r") {
|
|
1421
|
+
await keyStroke(ch, {
|
|
1422
|
+
key: "Enter",
|
|
1423
|
+
code: "Enter",
|
|
1424
|
+
windowsVirtualKeyCode: 13,
|
|
1425
|
+
});
|
|
1426
|
+
}
|
|
1427
|
+
else if (ch === "\t") {
|
|
1428
|
+
await keyStroke(ch, {
|
|
1429
|
+
key: "Tab",
|
|
1430
|
+
code: "Tab",
|
|
1431
|
+
windowsVirtualKeyCode: 9,
|
|
1432
|
+
});
|
|
1433
|
+
}
|
|
1434
|
+
else {
|
|
1435
|
+
if (withMistakes && Math.random() < 0.12) {
|
|
1436
|
+
// Type a wrong character, then backspace to correct
|
|
1437
|
+
const wrong = randomPrintable(ch);
|
|
1438
|
+
await keyStroke(wrong);
|
|
1439
|
+
if (delay)
|
|
1440
|
+
await sleep(delay);
|
|
1441
|
+
await pressBackspace();
|
|
1442
|
+
if (delay)
|
|
1443
|
+
await sleep(delay);
|
|
1444
|
+
}
|
|
1445
|
+
await keyStroke(ch);
|
|
1446
|
+
}
|
|
1447
|
+
if (delay)
|
|
1448
|
+
await sleep(delay);
|
|
1449
|
+
}
|
|
1450
|
+
}
|
|
1451
|
+
/**
|
|
1452
|
+
* Press a single key or key combination (keyDown then keyUp).
|
|
1453
|
+
* For printable characters, uses the text path on keyDown; for named keys, sets key/code/VK.
|
|
1454
|
+
* Supports key combinations with modifiers like "Cmd+A", "Ctrl+C", "Shift+Tab", etc.
|
|
1455
|
+
*/
|
|
1456
|
+
async keyPress(key, options) {
|
|
1457
|
+
const delay = Math.max(0, options?.delay ?? 0);
|
|
1458
|
+
const sleep = (ms) => new Promise((r) => (ms > 0 ? setTimeout(r, ms) : r()));
|
|
1459
|
+
// Split key combination by + but handle the special case of "+" key itself
|
|
1460
|
+
function split(keyString) {
|
|
1461
|
+
// Special case: if the entire string is just "+", return it as-is
|
|
1462
|
+
if (keyString === "+") {
|
|
1463
|
+
return ["+"];
|
|
1464
|
+
}
|
|
1465
|
+
const keys = [];
|
|
1466
|
+
let building = "";
|
|
1467
|
+
for (const char of keyString) {
|
|
1468
|
+
if (char === "+" && building) {
|
|
1469
|
+
keys.push(building);
|
|
1470
|
+
building = "";
|
|
1471
|
+
}
|
|
1472
|
+
else {
|
|
1473
|
+
building += char;
|
|
1474
|
+
}
|
|
1475
|
+
}
|
|
1476
|
+
if (building) {
|
|
1477
|
+
keys.push(building);
|
|
1478
|
+
}
|
|
1479
|
+
return keys;
|
|
1480
|
+
}
|
|
1481
|
+
const tokens = split(key);
|
|
1482
|
+
const mainKey = tokens[tokens.length - 1];
|
|
1483
|
+
const modifierKeys = tokens.slice(0, -1);
|
|
1484
|
+
try {
|
|
1485
|
+
for (const modKey of modifierKeys) {
|
|
1486
|
+
await this.keyDown(modKey);
|
|
1487
|
+
}
|
|
1488
|
+
await this.keyDown(mainKey);
|
|
1489
|
+
if (delay)
|
|
1490
|
+
await sleep(delay);
|
|
1491
|
+
await this.keyUp(mainKey);
|
|
1492
|
+
for (let i = modifierKeys.length - 1; i >= 0; i--) {
|
|
1493
|
+
await this.keyUp(modifierKeys[i]);
|
|
1494
|
+
}
|
|
1495
|
+
}
|
|
1496
|
+
catch (error) {
|
|
1497
|
+
// Clear stuck modifiers on error to prevent affecting subsequent keyPress calls
|
|
1498
|
+
this._pressedModifiers.clear();
|
|
1499
|
+
throw error;
|
|
1500
|
+
}
|
|
1501
|
+
}
|
|
1502
|
+
async snapshot(options) {
|
|
1503
|
+
try {
|
|
1504
|
+
const { combinedTree, combinedXpathMap, combinedUrlMap } = await captureHybridSnapshot(this, {
|
|
1505
|
+
pierceShadow: true,
|
|
1506
|
+
includeIframes: options?.includeIframes,
|
|
1507
|
+
});
|
|
1508
|
+
return {
|
|
1509
|
+
formattedTree: combinedTree,
|
|
1510
|
+
xpathMap: combinedXpathMap,
|
|
1511
|
+
urlMap: combinedUrlMap,
|
|
1512
|
+
};
|
|
1513
|
+
}
|
|
1514
|
+
catch (err) {
|
|
1515
|
+
throw new StagehandSnapshotError(err);
|
|
1516
|
+
}
|
|
1517
|
+
}
|
|
1518
|
+
// Track pressed modifier keys
|
|
1519
|
+
_pressedModifiers = new Set();
|
|
1520
|
+
/** Press a key down without releasing it */
|
|
1521
|
+
async keyDown(key) {
|
|
1522
|
+
const normalizedKey = this.normalizeModifierKey(key);
|
|
1523
|
+
const modifierKeys = ["Alt", "Control", "Meta", "Shift"];
|
|
1524
|
+
if (modifierKeys.includes(normalizedKey)) {
|
|
1525
|
+
this._pressedModifiers.add(normalizedKey);
|
|
1526
|
+
}
|
|
1527
|
+
let modifiers = 0;
|
|
1528
|
+
if (this._pressedModifiers.has("Alt"))
|
|
1529
|
+
modifiers |= 1;
|
|
1530
|
+
if (this._pressedModifiers.has("Control"))
|
|
1531
|
+
modifiers |= 2;
|
|
1532
|
+
if (this._pressedModifiers.has("Meta"))
|
|
1533
|
+
modifiers |= 4;
|
|
1534
|
+
if (this._pressedModifiers.has("Shift"))
|
|
1535
|
+
modifiers |= 8;
|
|
1536
|
+
const named = this.getNamedKeys();
|
|
1537
|
+
if (normalizedKey.length === 1) {
|
|
1538
|
+
const hasNonShiftModifier = this._pressedModifiers.has("Alt") ||
|
|
1539
|
+
this._pressedModifiers.has("Control") ||
|
|
1540
|
+
this._pressedModifiers.has("Meta");
|
|
1541
|
+
if (hasNonShiftModifier) {
|
|
1542
|
+
// For accelerators (e.g., Cmd/Ctrl/Alt + key), do not send text. Use rawKeyDown with key/code/VK.
|
|
1543
|
+
const desc = this.describePrintableKey(normalizedKey);
|
|
1544
|
+
const macCommands = this.isMacOS()
|
|
1545
|
+
? this.macCommandsFor(desc.code ?? "")
|
|
1546
|
+
: [];
|
|
1547
|
+
const req = {
|
|
1548
|
+
type: "rawKeyDown",
|
|
1549
|
+
modifiers,
|
|
1550
|
+
key: desc.key,
|
|
1551
|
+
...(desc.code ? { code: desc.code } : {}),
|
|
1552
|
+
...(typeof desc.vk === "number"
|
|
1553
|
+
? { windowsVirtualKeyCode: desc.vk }
|
|
1554
|
+
: {}),
|
|
1555
|
+
...(macCommands.length ? { commands: macCommands } : {}),
|
|
1556
|
+
};
|
|
1557
|
+
await this.mainSession.send("Input.dispatchKeyEvent", req);
|
|
1558
|
+
}
|
|
1559
|
+
else {
|
|
1560
|
+
// Typing path (no non-Shift modifiers): send text to generate input
|
|
1561
|
+
await this.mainSession.send("Input.dispatchKeyEvent", {
|
|
1562
|
+
type: "keyDown",
|
|
1563
|
+
text: normalizedKey,
|
|
1564
|
+
unmodifiedText: normalizedKey,
|
|
1565
|
+
modifiers,
|
|
1566
|
+
});
|
|
1567
|
+
}
|
|
1568
|
+
return;
|
|
1569
|
+
}
|
|
1570
|
+
const entry = named[normalizedKey] ?? null;
|
|
1571
|
+
if (entry) {
|
|
1572
|
+
const macCommands = this.isMacOS() ? this.macCommandsFor(entry.code) : [];
|
|
1573
|
+
const includeText = !!entry.text && modifiers === 0;
|
|
1574
|
+
const keyDown = {
|
|
1575
|
+
type: includeText ? "keyDown" : "rawKeyDown",
|
|
1576
|
+
key: entry.key,
|
|
1577
|
+
code: entry.code,
|
|
1578
|
+
windowsVirtualKeyCode: entry.vk,
|
|
1579
|
+
modifiers,
|
|
1580
|
+
...(includeText
|
|
1581
|
+
? {
|
|
1582
|
+
text: entry.text,
|
|
1583
|
+
unmodifiedText: entry.unmodifiedText ?? entry.text,
|
|
1584
|
+
}
|
|
1585
|
+
: {}),
|
|
1586
|
+
...(macCommands.length ? { commands: macCommands } : {}),
|
|
1587
|
+
};
|
|
1588
|
+
await this.mainSession.send("Input.dispatchKeyEvent", keyDown);
|
|
1589
|
+
return;
|
|
1590
|
+
}
|
|
1591
|
+
// Fallback: send with key property only
|
|
1592
|
+
await this.mainSession.send("Input.dispatchKeyEvent", {
|
|
1593
|
+
type: "keyDown",
|
|
1594
|
+
key: normalizedKey,
|
|
1595
|
+
modifiers,
|
|
1596
|
+
});
|
|
1597
|
+
}
|
|
1598
|
+
/** Release a pressed key */
|
|
1599
|
+
async keyUp(key) {
|
|
1600
|
+
const normalizedKey = this.normalizeModifierKey(key);
|
|
1601
|
+
let modifiers = 0;
|
|
1602
|
+
if (this._pressedModifiers.has("Alt"))
|
|
1603
|
+
modifiers |= 1;
|
|
1604
|
+
if (this._pressedModifiers.has("Control"))
|
|
1605
|
+
modifiers |= 2;
|
|
1606
|
+
if (this._pressedModifiers.has("Meta"))
|
|
1607
|
+
modifiers |= 4;
|
|
1608
|
+
if (this._pressedModifiers.has("Shift"))
|
|
1609
|
+
modifiers |= 8;
|
|
1610
|
+
const modifierKeys = ["Alt", "Control", "Meta", "Shift"];
|
|
1611
|
+
if (modifierKeys.includes(normalizedKey)) {
|
|
1612
|
+
this._pressedModifiers.delete(normalizedKey);
|
|
1613
|
+
}
|
|
1614
|
+
const named = this.getNamedKeys();
|
|
1615
|
+
if (normalizedKey.length === 1) {
|
|
1616
|
+
const desc = this.describePrintableKey(normalizedKey);
|
|
1617
|
+
await this.mainSession.send("Input.dispatchKeyEvent", {
|
|
1618
|
+
type: "keyUp",
|
|
1619
|
+
key: desc.key,
|
|
1620
|
+
code: desc.code,
|
|
1621
|
+
windowsVirtualKeyCode: typeof desc.vk === "number" ? desc.vk : undefined,
|
|
1622
|
+
modifiers,
|
|
1623
|
+
});
|
|
1624
|
+
return;
|
|
1625
|
+
}
|
|
1626
|
+
const entry = named[normalizedKey] ?? null;
|
|
1627
|
+
if (entry) {
|
|
1628
|
+
await this.mainSession.send("Input.dispatchKeyEvent", {
|
|
1629
|
+
type: "keyUp",
|
|
1630
|
+
key: entry.key,
|
|
1631
|
+
code: entry.code,
|
|
1632
|
+
windowsVirtualKeyCode: entry.vk,
|
|
1633
|
+
modifiers,
|
|
1634
|
+
});
|
|
1635
|
+
return;
|
|
1636
|
+
}
|
|
1637
|
+
// Fallback: send with key property only
|
|
1638
|
+
await this.mainSession.send("Input.dispatchKeyEvent", {
|
|
1639
|
+
type: "keyUp",
|
|
1640
|
+
key: normalizedKey,
|
|
1641
|
+
modifiers,
|
|
1642
|
+
});
|
|
1643
|
+
}
|
|
1644
|
+
/** Normalize key names to match CDP expectations */
|
|
1645
|
+
normalizeModifierKey(key) {
|
|
1646
|
+
const lower = key.toLowerCase();
|
|
1647
|
+
switch (lower) {
|
|
1648
|
+
// Modifier keys
|
|
1649
|
+
case "cmd":
|
|
1650
|
+
case "command":
|
|
1651
|
+
case "controlormeta":
|
|
1652
|
+
// On Mac, Cmd is Meta; elsewhere map to Control for common shortcuts
|
|
1653
|
+
return this.isMacOS() ? "Meta" : "Control";
|
|
1654
|
+
case "win":
|
|
1655
|
+
case "windows":
|
|
1656
|
+
return "Meta";
|
|
1657
|
+
case "ctrl":
|
|
1658
|
+
case "control":
|
|
1659
|
+
return "Control";
|
|
1660
|
+
case "option":
|
|
1661
|
+
case "alt":
|
|
1662
|
+
return "Alt";
|
|
1663
|
+
case "shift":
|
|
1664
|
+
return "Shift";
|
|
1665
|
+
case "meta":
|
|
1666
|
+
return "Meta";
|
|
1667
|
+
// Action keys
|
|
1668
|
+
case "enter":
|
|
1669
|
+
case "return":
|
|
1670
|
+
return "Enter";
|
|
1671
|
+
case "esc":
|
|
1672
|
+
case "escape":
|
|
1673
|
+
return "Escape";
|
|
1674
|
+
case "backspace":
|
|
1675
|
+
return "Backspace";
|
|
1676
|
+
case "tab":
|
|
1677
|
+
return "Tab";
|
|
1678
|
+
case "space":
|
|
1679
|
+
case "spacebar":
|
|
1680
|
+
return " ";
|
|
1681
|
+
case "delete":
|
|
1682
|
+
case "del":
|
|
1683
|
+
return "Delete";
|
|
1684
|
+
// Arrow keys
|
|
1685
|
+
case "left":
|
|
1686
|
+
case "arrowleft":
|
|
1687
|
+
return "ArrowLeft";
|
|
1688
|
+
case "right":
|
|
1689
|
+
case "arrowright":
|
|
1690
|
+
return "ArrowRight";
|
|
1691
|
+
case "up":
|
|
1692
|
+
case "arrowup":
|
|
1693
|
+
return "ArrowUp";
|
|
1694
|
+
case "down":
|
|
1695
|
+
case "arrowdown":
|
|
1696
|
+
return "ArrowDown";
|
|
1697
|
+
// Navigation keys
|
|
1698
|
+
case "home":
|
|
1699
|
+
return "Home";
|
|
1700
|
+
case "end":
|
|
1701
|
+
return "End";
|
|
1702
|
+
case "pageup":
|
|
1703
|
+
case "pgup":
|
|
1704
|
+
return "PageUp";
|
|
1705
|
+
case "pagedown":
|
|
1706
|
+
case "pgdn":
|
|
1707
|
+
return "PageDown";
|
|
1708
|
+
default:
|
|
1709
|
+
return key;
|
|
1710
|
+
}
|
|
1711
|
+
}
|
|
1712
|
+
/**
|
|
1713
|
+
* Get the map of named keys with their properties
|
|
1714
|
+
*/
|
|
1715
|
+
getNamedKeys() {
|
|
1716
|
+
return {
|
|
1717
|
+
Enter: {
|
|
1718
|
+
key: "Enter",
|
|
1719
|
+
code: "Enter",
|
|
1720
|
+
vk: 13,
|
|
1721
|
+
text: "\r",
|
|
1722
|
+
unmodifiedText: "\r",
|
|
1723
|
+
},
|
|
1724
|
+
Tab: { key: "Tab", code: "Tab", vk: 9 },
|
|
1725
|
+
Backspace: { key: "Backspace", code: "Backspace", vk: 8 },
|
|
1726
|
+
Escape: { key: "Escape", code: "Escape", vk: 27 },
|
|
1727
|
+
Delete: { key: "Delete", code: "Delete", vk: 46 },
|
|
1728
|
+
ArrowLeft: { key: "ArrowLeft", code: "ArrowLeft", vk: 37 },
|
|
1729
|
+
ArrowUp: { key: "ArrowUp", code: "ArrowUp", vk: 38 },
|
|
1730
|
+
ArrowRight: { key: "ArrowRight", code: "ArrowRight", vk: 39 },
|
|
1731
|
+
ArrowDown: { key: "ArrowDown", code: "ArrowDown", vk: 40 },
|
|
1732
|
+
Home: { key: "Home", code: "Home", vk: 36 },
|
|
1733
|
+
End: { key: "End", code: "End", vk: 35 },
|
|
1734
|
+
PageUp: { key: "PageUp", code: "PageUp", vk: 33 },
|
|
1735
|
+
PageDown: { key: "PageDown", code: "PageDown", vk: 34 },
|
|
1736
|
+
// Modifier keys
|
|
1737
|
+
Alt: { key: "Alt", code: "AltLeft", vk: 18 },
|
|
1738
|
+
Control: { key: "Control", code: "ControlLeft", vk: 17 },
|
|
1739
|
+
Meta: { key: "Meta", code: "MetaLeft", vk: 91 },
|
|
1740
|
+
Shift: { key: "Shift", code: "ShiftLeft", vk: 16 },
|
|
1741
|
+
};
|
|
1742
|
+
}
|
|
1743
|
+
/**
|
|
1744
|
+
* Minimal description for printable keys (letters/digits/space) to provide code and VK.
|
|
1745
|
+
* Used when non-Shift modifiers are pressed to avoid sending text while keeping accelerator info.
|
|
1746
|
+
*/
|
|
1747
|
+
describePrintableKey(ch) {
|
|
1748
|
+
const shiftDown = this._pressedModifiers.has("Shift");
|
|
1749
|
+
const isLetter = /^[a-zA-Z]$/.test(ch);
|
|
1750
|
+
const isDigit = /^[0-9]$/.test(ch);
|
|
1751
|
+
if (isLetter) {
|
|
1752
|
+
const upper = ch.toUpperCase();
|
|
1753
|
+
return {
|
|
1754
|
+
key: shiftDown ? upper : upper.toLowerCase(),
|
|
1755
|
+
code: `Key${upper}`,
|
|
1756
|
+
vk: upper.charCodeAt(0), // 'A'..'Z' => 65..90
|
|
1757
|
+
};
|
|
1758
|
+
}
|
|
1759
|
+
if (isDigit) {
|
|
1760
|
+
return {
|
|
1761
|
+
key: ch,
|
|
1762
|
+
code: `Digit${ch}`,
|
|
1763
|
+
vk: ch.charCodeAt(0), // '0'..'9' => 48..57
|
|
1764
|
+
};
|
|
1765
|
+
}
|
|
1766
|
+
if (ch === " ") {
|
|
1767
|
+
return { key: " ", code: "Space", vk: 32 };
|
|
1768
|
+
}
|
|
1769
|
+
// Fallback: just return the character as-is; VK best-effort from ASCII
|
|
1770
|
+
return {
|
|
1771
|
+
key: shiftDown ? ch.toUpperCase() : ch,
|
|
1772
|
+
vk: ch.toUpperCase().charCodeAt(0),
|
|
1773
|
+
};
|
|
1774
|
+
}
|
|
1775
|
+
isMacOS() {
|
|
1776
|
+
try {
|
|
1777
|
+
return process.platform === "darwin";
|
|
1778
|
+
}
|
|
1779
|
+
catch {
|
|
1780
|
+
return false;
|
|
1781
|
+
}
|
|
1782
|
+
}
|
|
1783
|
+
/**
|
|
1784
|
+
* Return Chromium mac editing commands (without trailing ':') for a given code like 'KeyA'
|
|
1785
|
+
* Only used on macOS to trigger system editing shortcuts (e.g., selectAll, copy, paste...).
|
|
1786
|
+
*/
|
|
1787
|
+
macCommandsFor(code) {
|
|
1788
|
+
if (!this.isMacOS())
|
|
1789
|
+
return [];
|
|
1790
|
+
const parts = [];
|
|
1791
|
+
if (this._pressedModifiers.has("Shift"))
|
|
1792
|
+
parts.push("Shift");
|
|
1793
|
+
if (this._pressedModifiers.has("Control"))
|
|
1794
|
+
parts.push("Control");
|
|
1795
|
+
if (this._pressedModifiers.has("Alt"))
|
|
1796
|
+
parts.push("Alt");
|
|
1797
|
+
if (this._pressedModifiers.has("Meta"))
|
|
1798
|
+
parts.push("Meta");
|
|
1799
|
+
parts.push(code);
|
|
1800
|
+
const shortcut = parts.join("+");
|
|
1801
|
+
const table = {
|
|
1802
|
+
"Meta+KeyA": "selectAll:",
|
|
1803
|
+
"Meta+KeyC": "copy:",
|
|
1804
|
+
"Meta+KeyX": "cut:",
|
|
1805
|
+
"Meta+KeyV": "paste:",
|
|
1806
|
+
"Meta+KeyZ": "undo:",
|
|
1807
|
+
};
|
|
1808
|
+
const value = table[shortcut];
|
|
1809
|
+
if (!value)
|
|
1810
|
+
return [];
|
|
1811
|
+
const list = Array.isArray(value) ? value : [value];
|
|
1812
|
+
return list
|
|
1813
|
+
.filter((c) => !c.startsWith("insert"))
|
|
1814
|
+
.map((c) => c.substring(0, c.length - 1));
|
|
1815
|
+
}
|
|
1816
|
+
// ---- Page-level lifecycle waiter that follows main frame id swaps ----
|
|
1817
|
+
/** Resolve the main-world execution context for the current main frame. */
|
|
1818
|
+
async mainWorldExecutionContextId() {
|
|
1819
|
+
return executionContexts.waitForMainWorld(this.mainSession, this.mainFrameId(), 1000);
|
|
1820
|
+
}
|
|
1821
|
+
async isMainLoadStateReady(state) {
|
|
1822
|
+
try {
|
|
1823
|
+
const ctxId = await this.mainWorldExecutionContextId();
|
|
1824
|
+
const { result } = await this.mainSession.send("Runtime.evaluate", {
|
|
1825
|
+
expression: "document.readyState",
|
|
1826
|
+
contextId: ctxId,
|
|
1827
|
+
returnByValue: true,
|
|
1828
|
+
});
|
|
1829
|
+
const readyState = String(result?.value ?? "");
|
|
1830
|
+
if (state === "domcontentloaded") {
|
|
1831
|
+
return readyState === "interactive" || readyState === "complete";
|
|
1832
|
+
}
|
|
1833
|
+
return readyState === "complete";
|
|
1834
|
+
}
|
|
1835
|
+
catch {
|
|
1836
|
+
return false;
|
|
1837
|
+
}
|
|
1838
|
+
}
|
|
1839
|
+
/**
|
|
1840
|
+
* Wait until the **current** main frame reaches a lifecycle state.
|
|
1841
|
+
* - Fast path via `document.readyState`.
|
|
1842
|
+
* - Event path listens at the session level and compares incoming `frameId`
|
|
1843
|
+
* to `mainFrameId()` **at event time** to follow root swaps.
|
|
1844
|
+
*/
|
|
1845
|
+
async waitForMainLoadState(state, timeoutMs = 15000) {
|
|
1846
|
+
await this.mainSession
|
|
1847
|
+
.send("Page.setLifecycleEventsEnabled", { enabled: true })
|
|
1848
|
+
.catch(() => { });
|
|
1849
|
+
// Fast path: check the *current* main frame's readyState.
|
|
1850
|
+
if ((state === "domcontentloaded" || state === "load") &&
|
|
1851
|
+
(await this.isMainLoadStateReady(state))) {
|
|
1852
|
+
return;
|
|
1853
|
+
}
|
|
1854
|
+
const wanted = LIFECYCLE_NAME[state];
|
|
1855
|
+
return new Promise((resolve, reject) => {
|
|
1856
|
+
let done = false;
|
|
1857
|
+
let timer = null;
|
|
1858
|
+
let pollTimer = null;
|
|
1859
|
+
let pollInFlight = false;
|
|
1860
|
+
const off = () => {
|
|
1861
|
+
this.mainSession.off("Page.lifecycleEvent", onLifecycle);
|
|
1862
|
+
this.mainSession.off("Page.domContentEventFired", onDomContent);
|
|
1863
|
+
this.mainSession.off("Page.loadEventFired", onLoad);
|
|
1864
|
+
};
|
|
1865
|
+
const clearPollTimer = () => {
|
|
1866
|
+
if (pollTimer) {
|
|
1867
|
+
clearTimeout(pollTimer);
|
|
1868
|
+
pollTimer = null;
|
|
1869
|
+
}
|
|
1870
|
+
};
|
|
1871
|
+
const finish = () => {
|
|
1872
|
+
if (done)
|
|
1873
|
+
return;
|
|
1874
|
+
done = true;
|
|
1875
|
+
if (timer) {
|
|
1876
|
+
clearTimeout(timer);
|
|
1877
|
+
timer = null;
|
|
1878
|
+
}
|
|
1879
|
+
clearPollTimer();
|
|
1880
|
+
off();
|
|
1881
|
+
resolve();
|
|
1882
|
+
};
|
|
1883
|
+
const onLifecycle = (evt) => {
|
|
1884
|
+
if (evt.name !== wanted)
|
|
1885
|
+
return;
|
|
1886
|
+
// Compare against the *current* main frame id when the event arrives.
|
|
1887
|
+
if (evt.frameId === this.mainFrameId())
|
|
1888
|
+
finish();
|
|
1889
|
+
};
|
|
1890
|
+
const onDomContent = () => {
|
|
1891
|
+
if (state === "domcontentloaded")
|
|
1892
|
+
finish();
|
|
1893
|
+
};
|
|
1894
|
+
const onLoad = () => {
|
|
1895
|
+
if (state === "load")
|
|
1896
|
+
finish();
|
|
1897
|
+
};
|
|
1898
|
+
this.mainSession.on("Page.lifecycleEvent", onLifecycle);
|
|
1899
|
+
// Backups for sites that don't emit lifecycle consistently
|
|
1900
|
+
this.mainSession.on("Page.domContentEventFired", onDomContent);
|
|
1901
|
+
this.mainSession.on("Page.loadEventFired", onLoad);
|
|
1902
|
+
// Fallback polling closes lifecycle-event races in remote environments
|
|
1903
|
+
// where readyState has advanced but the corresponding event was missed.
|
|
1904
|
+
const pollReadyState = async () => {
|
|
1905
|
+
if (done || pollInFlight)
|
|
1906
|
+
return;
|
|
1907
|
+
pollInFlight = true;
|
|
1908
|
+
try {
|
|
1909
|
+
if (done)
|
|
1910
|
+
return;
|
|
1911
|
+
if ((state === "domcontentloaded" || state === "load") &&
|
|
1912
|
+
(await this.isMainLoadStateReady(state))) {
|
|
1913
|
+
finish();
|
|
1914
|
+
return;
|
|
1915
|
+
}
|
|
1916
|
+
}
|
|
1917
|
+
finally {
|
|
1918
|
+
pollInFlight = false;
|
|
1919
|
+
}
|
|
1920
|
+
if (!done) {
|
|
1921
|
+
clearPollTimer();
|
|
1922
|
+
pollTimer = setTimeout(() => {
|
|
1923
|
+
void pollReadyState();
|
|
1924
|
+
}, 100);
|
|
1925
|
+
}
|
|
1926
|
+
};
|
|
1927
|
+
void pollReadyState();
|
|
1928
|
+
timer = setTimeout(() => {
|
|
1929
|
+
if (done)
|
|
1930
|
+
return;
|
|
1931
|
+
done = true;
|
|
1932
|
+
clearPollTimer();
|
|
1933
|
+
off();
|
|
1934
|
+
reject(new Error(`waitForMainLoadState(${state}) timed out after ${timeoutMs}ms`));
|
|
1935
|
+
}, timeoutMs);
|
|
1936
|
+
});
|
|
1937
|
+
}
|
|
1938
|
+
};
|
|
1939
|
+
})();
|
|
1940
|
+
export { Page };
|
|
1941
|
+
//# sourceMappingURL=page.js.map
|