@handstage/core 0.0.2 → 0.0.3
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/v3/index.js +4 -4
- package/dist/v3/launch/local.js +1 -3
- package/dist/v3/logger.js +1 -1
- package/dist/v3/shutdown/cleanupLocal.js +2 -6
- package/dist/v3/shutdown/supervisor.js +6 -12
- package/dist/v3/shutdown/supervisorClient.js +3 -5
- package/dist/v3/types/public/logs.js +1 -1
- package/dist/v3/types/public/sdkErrors.js +47 -54
- package/dist/v3/understudy/a11y/snapshot/a11yTree.js +1 -3
- package/dist/v3/understudy/a11y/snapshot/activeElement.js +4 -12
- package/dist/v3/understudy/a11y/snapshot/capture.js +1 -3
- package/dist/v3/understudy/a11y/snapshot/coordinateResolver.js +2 -6
- package/dist/v3/understudy/a11y/snapshot/domTree.js +5 -5
- package/dist/v3/understudy/a11y/snapshot/focusSelectors.js +5 -5
- package/dist/v3/understudy/cdp.js +291 -42
- package/dist/v3/understudy/context.js +441 -84
- package/dist/v3/understudy/cookies.js +1 -1
- package/dist/v3/understudy/deepLocator.js +2 -5
- package/dist/v3/understudy/executionContextRegistry.js +14 -1
- package/dist/v3/understudy/fileUploadUtils.js +5 -5
- package/dist/v3/understudy/frame.js +2 -2
- package/dist/v3/understudy/frameLocator.js +7 -22
- package/dist/v3/understudy/frameRegistry.js +0 -29
- package/dist/v3/understudy/initScripts.js +4 -4
- package/dist/v3/understudy/lifecycleWatcher.js +1 -3
- package/dist/v3/understudy/locator.js +17 -40
- package/dist/v3/understudy/navigationResponseTracker.js +1 -1
- package/dist/v3/understudy/page.js +22 -47
- package/dist/v3/understudy/response.js +2 -2
- package/dist/v3/understudy/screenshotUtils.js +22 -39
- package/dist/v3/v3.js +217 -124
- package/dist/version.js +1 -1
- package/package.json +9 -29
- package/src/v3/index.ts +4 -4
- package/src/v3/launch/local.ts +1 -3
- package/src/v3/logger.ts +1 -1
- package/src/v3/shutdown/cleanupLocal.ts +2 -6
- package/src/v3/shutdown/supervisor.ts +6 -12
- package/src/v3/shutdown/supervisorClient.ts +3 -5
- package/src/v3/types/private/internal.ts +13 -1
- package/src/v3/types/public/context.ts +8 -0
- package/src/v3/types/public/index.ts +1 -0
- package/src/v3/types/public/logs.ts +1 -1
- package/src/v3/types/public/options.ts +14 -12
- package/src/v3/types/public/page.ts +1 -5
- package/src/v3/types/public/sdkErrors.ts +47 -57
- package/src/v3/understudy/a11y/snapshot/a11yTree.ts +1 -3
- package/src/v3/understudy/a11y/snapshot/activeElement.ts +6 -14
- package/src/v3/understudy/a11y/snapshot/capture.ts +1 -3
- package/src/v3/understudy/a11y/snapshot/coordinateResolver.ts +3 -7
- package/src/v3/understudy/a11y/snapshot/domTree.ts +5 -5
- package/src/v3/understudy/a11y/snapshot/focusSelectors.ts +5 -5
- package/src/v3/understudy/cdp.ts +411 -47
- package/src/v3/understudy/context.ts +524 -84
- package/src/v3/understudy/cookies.ts +1 -1
- package/src/v3/understudy/deepLocator.ts +2 -5
- package/src/v3/understudy/executionContextRegistry.ts +16 -2
- package/src/v3/understudy/fileUploadUtils.ts +5 -5
- package/src/v3/understudy/frame.ts +2 -3
- package/src/v3/understudy/frameLocator.ts +7 -22
- package/src/v3/understudy/frameRegistry.ts +0 -34
- package/src/v3/understudy/initScripts.ts +4 -4
- package/src/v3/understudy/lifecycleWatcher.ts +1 -3
- package/src/v3/understudy/locator.ts +22 -47
- package/src/v3/understudy/navigationResponseTracker.ts +1 -1
- package/src/v3/understudy/page.ts +27 -52
- package/src/v3/understudy/response.ts +2 -2
- package/src/v3/understudy/screenshotUtils.ts +25 -40
- package/src/v3/v3.ts +242 -128
- package/src/version.ts +1 -1
- package/src/v3/cli.js +0 -13
package/dist/v3/index.js
CHANGED
|
@@ -3,11 +3,11 @@ import * as PublicApi from "./types/public/index";
|
|
|
3
3
|
import { V3 } from "./v3";
|
|
4
4
|
export { maybeRunShutdownSupervisorFromArgv as __internalMaybeRunShutdownSupervisorFromArgv } from "./shutdown/supervisor";
|
|
5
5
|
export * from "./types/public/index";
|
|
6
|
-
export { V3, V3 as
|
|
7
|
-
const
|
|
6
|
+
export { V3, V3 as Handstages } from "./v3";
|
|
7
|
+
const HandstagesDefault = {
|
|
8
8
|
...PublicApi,
|
|
9
9
|
V3,
|
|
10
|
-
|
|
10
|
+
Handstages: V3,
|
|
11
11
|
__internalMaybeRunShutdownSupervisorFromArgv: maybeRunShutdownSupervisorFromArgv,
|
|
12
12
|
};
|
|
13
|
-
export default
|
|
13
|
+
export default HandstagesDefault;
|
package/dist/v3/launch/local.js
CHANGED
package/dist/v3/logger.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
2
|
import { createConsoleLogger } from "./types/public/consoleLogger";
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* Handstages V3 per-instance log routing (AsyncLocalStorage).
|
|
5
5
|
*
|
|
6
6
|
* - `bindInstanceLogger` / `unbindInstanceLogger`: register the effective logger for an instance id.
|
|
7
7
|
* - `withInstanceLogContext`: run a function with that instance id on the async context.
|
|
@@ -12,9 +12,7 @@ export async function cleanupLocalBrowser(opts) {
|
|
|
12
12
|
try {
|
|
13
13
|
await opts.killChrome();
|
|
14
14
|
}
|
|
15
|
-
catch {
|
|
16
|
-
// best-effort
|
|
17
|
-
}
|
|
15
|
+
catch { }
|
|
18
16
|
}
|
|
19
17
|
if (opts.createdTempProfile &&
|
|
20
18
|
!opts.preserveUserDataDir &&
|
|
@@ -22,8 +20,6 @@ export async function cleanupLocalBrowser(opts) {
|
|
|
22
20
|
try {
|
|
23
21
|
fs.rmSync(opts.userDataDir, { recursive: true, force: true });
|
|
24
22
|
}
|
|
25
|
-
catch {
|
|
26
|
-
// ignore cleanup errors
|
|
27
|
-
}
|
|
23
|
+
catch { }
|
|
28
24
|
}
|
|
29
25
|
}
|
|
@@ -17,9 +17,7 @@ const exit = (code = 0) => {
|
|
|
17
17
|
try {
|
|
18
18
|
process.exit(code);
|
|
19
19
|
}
|
|
20
|
-
catch {
|
|
21
|
-
// ignore
|
|
22
|
-
}
|
|
20
|
+
catch { }
|
|
23
21
|
};
|
|
24
22
|
// Best-effort two-phase kill: SIGTERM first, then SIGKILL after timeout.
|
|
25
23
|
// Treat only ESRCH as "already gone"; other errors should not imply dead.
|
|
@@ -55,9 +53,7 @@ const politeKill = async (pid) => {
|
|
|
55
53
|
try {
|
|
56
54
|
process.kill(pid, "SIGKILL");
|
|
57
55
|
}
|
|
58
|
-
catch {
|
|
59
|
-
// best-effort
|
|
60
|
-
}
|
|
56
|
+
catch { }
|
|
61
57
|
};
|
|
62
58
|
let pidPollTimer = null;
|
|
63
59
|
// Local-only fallback: if Chrome dies while parent still lives, run cleanup and exit.
|
|
@@ -142,13 +138,11 @@ export const runShutdownSupervisor = (initialConfig) => {
|
|
|
142
138
|
// Stdin is the lifeline; losing it means parent is gone.
|
|
143
139
|
try {
|
|
144
140
|
process.stdin.resume();
|
|
145
|
-
process.stdin.on("end", () => onLifelineClosed("
|
|
146
|
-
process.stdin.on("close", () => onLifelineClosed("
|
|
147
|
-
process.stdin.on("error", () => onLifelineClosed("
|
|
148
|
-
}
|
|
149
|
-
catch {
|
|
150
|
-
// ignore
|
|
141
|
+
process.stdin.on("end", () => onLifelineClosed("Handstages process completed"));
|
|
142
|
+
process.stdin.on("close", () => onLifelineClosed("Handstages process completed"));
|
|
143
|
+
process.stdin.on("error", () => onLifelineClosed("Handstages process crashed or was killed"));
|
|
151
144
|
}
|
|
145
|
+
catch { }
|
|
152
146
|
};
|
|
153
147
|
export const maybeRunShutdownSupervisorFromArgv = (argv = process.argv.slice(2)) => {
|
|
154
148
|
const parsed = parseConfigFromArgv(argv);
|
|
@@ -24,7 +24,7 @@ const isSeaRuntime = () => {
|
|
|
24
24
|
}
|
|
25
25
|
};
|
|
26
26
|
// SEA: re-exec current binary with supervisor args.
|
|
27
|
-
// Non-SEA: execute
|
|
27
|
+
// Non-SEA: execute Handstages CLI entrypoint with supervisor args.
|
|
28
28
|
const resolveCliPath = () => `${moduleDir}/../cli.js`;
|
|
29
29
|
const resolveSupervisorCommand = (config) => {
|
|
30
30
|
const baseArgs = ["--supervisor", serializeConfigArg(config)];
|
|
@@ -55,7 +55,7 @@ const serializeConfigArg = (config) => `--supervisor-config=${JSON.stringify({
|
|
|
55
55
|
export function startShutdownSupervisor(config, opts) {
|
|
56
56
|
const resolved = resolveSupervisorCommand(config);
|
|
57
57
|
if (!resolved) {
|
|
58
|
-
opts?.onError?.(new ShutdownSupervisorResolveError("Shutdown supervisor entry missing (expected
|
|
58
|
+
opts?.onError?.(new ShutdownSupervisorResolveError("Shutdown supervisor entry missing (expected Handstages CLI entrypoint)."), "resolve");
|
|
59
59
|
return null;
|
|
60
60
|
}
|
|
61
61
|
const child = spawn(resolved.command, resolved.args, {
|
|
@@ -80,9 +80,7 @@ export function startShutdownSupervisor(config, opts) {
|
|
|
80
80
|
try {
|
|
81
81
|
child.kill("SIGTERM");
|
|
82
82
|
}
|
|
83
|
-
catch {
|
|
84
|
-
// ignore
|
|
85
|
-
}
|
|
83
|
+
catch { }
|
|
86
84
|
};
|
|
87
85
|
return { stop };
|
|
88
86
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Avoid .js extension so bundlers resolve TS source
|
|
2
|
-
import {
|
|
3
|
-
export class
|
|
2
|
+
import { HANDSTAGES_VERSION } from "../../../version";
|
|
3
|
+
export class HandstagesError extends Error {
|
|
4
4
|
cause;
|
|
5
5
|
constructor(message, cause) {
|
|
6
6
|
super(message);
|
|
@@ -10,146 +10,139 @@ export class StagehandError extends Error {
|
|
|
10
10
|
}
|
|
11
11
|
}
|
|
12
12
|
}
|
|
13
|
-
export class
|
|
13
|
+
export class HandstagesDefaultError extends HandstagesError {
|
|
14
14
|
constructor(error) {
|
|
15
|
-
if (error instanceof Error || error instanceof
|
|
16
|
-
super(`\nHey! We're sorry you ran into an error. \
|
|
15
|
+
if (error instanceof Error || error instanceof HandstagesError) {
|
|
16
|
+
super(`\nHey! We're sorry you ran into an error. \nHandstages version: ${HANDSTAGES_VERSION} \nIf you need help, please open a Github issue or reach out to us on Discord: https://handstages.dev/discord\n\nFull error:\n${error.message}`);
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
|
-
export class
|
|
20
|
+
export class HandstagesEnvironmentError extends HandstagesError {
|
|
21
21
|
constructor(currentEnvironment, requiredEnvironment, feature) {
|
|
22
22
|
super(`You seem to be setting the current environment to ${currentEnvironment}.` +
|
|
23
23
|
`Ensure the environment is set to ${requiredEnvironment} if you want to use ${feature}.`);
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
|
-
export class MissingEnvironmentVariableError extends
|
|
26
|
+
export class MissingEnvironmentVariableError extends HandstagesError {
|
|
27
27
|
constructor(missingEnvironmentVariable, feature) {
|
|
28
28
|
super(`${missingEnvironmentVariable} is required to use ${feature}.` +
|
|
29
29
|
`Please set ${missingEnvironmentVariable} in your environment.`);
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
|
-
export class UnsupportedModelError extends
|
|
32
|
+
export class UnsupportedModelError extends HandstagesError {
|
|
33
33
|
constructor(supportedModels, feature) {
|
|
34
34
|
const message = feature
|
|
35
35
|
? `${feature} requires a valid model.`
|
|
36
36
|
: `Unsupported model.`;
|
|
37
37
|
const guidance = `\n\nPlease use the provider/model format (e.g., "openai/gpt-4o", "anthropic/claude-sonnet-4-5", "google/gemini-3-flash-preview").` +
|
|
38
|
-
`\n\nFor a complete list of supported models and providers, see: https://docs.
|
|
38
|
+
`\n\nFor a complete list of supported models and providers, see: https://docs.handstages.dev/v3/configuration/models#configuration-setup`;
|
|
39
39
|
super(`${message}${guidance}`);
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
|
-
export class UnsupportedModelProviderError extends
|
|
42
|
+
export class UnsupportedModelProviderError extends HandstagesError {
|
|
43
43
|
constructor(supportedProviders, feature) {
|
|
44
44
|
super(feature
|
|
45
45
|
? `${feature} requires one of the following model providers: ${supportedProviders}`
|
|
46
46
|
: `please use one of the supported model providers: ${supportedProviders}`);
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
|
-
export class UnsupportedAISDKModelProviderError extends
|
|
49
|
+
export class UnsupportedAISDKModelProviderError extends HandstagesError {
|
|
50
50
|
constructor(provider, supportedProviders) {
|
|
51
51
|
super(`${provider} is not currently supported for aiSDK. please use one of the supported model providers: ${supportedProviders}`);
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
|
-
export class InvalidAISDKModelFormatError extends
|
|
54
|
+
export class InvalidAISDKModelFormatError extends HandstagesError {
|
|
55
55
|
constructor(modelName) {
|
|
56
56
|
super(`${modelName} does not follow correct format for specifying aiSDK models. Please define your model as 'provider/model-name'. For example: \`model: 'openai/gpt-4o-mini'\``);
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
|
-
export class
|
|
60
|
-
constructor(prop) {
|
|
61
|
-
super(`You seem to be calling \`${prop}\` on a page in an uninitialized \`Stagehand\` object. ` +
|
|
62
|
-
`Ensure you are running \`await stagehand.init()\` on the Stagehand object before ` +
|
|
63
|
-
`referencing the \`page\` object.`);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
export class CaptchaTimeoutError extends StagehandError {
|
|
59
|
+
export class CaptchaTimeoutError extends HandstagesError {
|
|
67
60
|
constructor() {
|
|
68
61
|
super("Captcha timeout");
|
|
69
62
|
}
|
|
70
63
|
}
|
|
71
|
-
export class MissingLLMConfigurationError extends
|
|
64
|
+
export class MissingLLMConfigurationError extends HandstagesError {
|
|
72
65
|
constructor() {
|
|
73
66
|
super("No LLM API key or LLM Client configured. An LLM API key or a custom LLM Client " +
|
|
74
67
|
"is required to use act, extract, or observe.");
|
|
75
68
|
}
|
|
76
69
|
}
|
|
77
|
-
export class HandlerNotInitializedError extends
|
|
70
|
+
export class HandlerNotInitializedError extends HandstagesError {
|
|
78
71
|
constructor(handlerType) {
|
|
79
72
|
super(`${handlerType} handler not initialized`);
|
|
80
73
|
}
|
|
81
74
|
}
|
|
82
|
-
export class
|
|
75
|
+
export class HandstagesInvalidArgumentError extends HandstagesError {
|
|
83
76
|
constructor(message) {
|
|
84
77
|
super(`InvalidArgumentError: ${message}`);
|
|
85
78
|
}
|
|
86
79
|
}
|
|
87
|
-
export class CookieValidationError extends
|
|
80
|
+
export class CookieValidationError extends HandstagesError {
|
|
88
81
|
constructor(message) {
|
|
89
82
|
super(message);
|
|
90
83
|
}
|
|
91
84
|
}
|
|
92
|
-
export class CookieSetError extends
|
|
85
|
+
export class CookieSetError extends HandstagesError {
|
|
93
86
|
constructor(message) {
|
|
94
87
|
super(message);
|
|
95
88
|
}
|
|
96
89
|
}
|
|
97
|
-
export class
|
|
90
|
+
export class HandstagesElementNotFoundError extends HandstagesError {
|
|
98
91
|
constructor(xpaths) {
|
|
99
92
|
super(`Could not find an element for the given xPath(s): ${xpaths}`);
|
|
100
93
|
}
|
|
101
94
|
}
|
|
102
|
-
export class AgentScreenshotProviderError extends
|
|
95
|
+
export class AgentScreenshotProviderError extends HandstagesError {
|
|
103
96
|
constructor(message) {
|
|
104
97
|
super(`ScreenshotProviderError: ${message}`);
|
|
105
98
|
}
|
|
106
99
|
}
|
|
107
|
-
export class
|
|
100
|
+
export class HandstagesMissingArgumentError extends HandstagesError {
|
|
108
101
|
constructor(message) {
|
|
109
102
|
super(`MissingArgumentError: ${message}`);
|
|
110
103
|
}
|
|
111
104
|
}
|
|
112
|
-
export class CreateChatCompletionResponseError extends
|
|
105
|
+
export class CreateChatCompletionResponseError extends HandstagesError {
|
|
113
106
|
constructor(message) {
|
|
114
107
|
super(`CreateChatCompletionResponseError: ${message}`);
|
|
115
108
|
}
|
|
116
109
|
}
|
|
117
|
-
export class
|
|
110
|
+
export class HandstagesEvalError extends HandstagesError {
|
|
118
111
|
constructor(message) {
|
|
119
|
-
super(`
|
|
112
|
+
super(`HandstagesEvalError: ${message}`);
|
|
120
113
|
}
|
|
121
114
|
}
|
|
122
|
-
export class
|
|
115
|
+
export class HandstagesDomProcessError extends HandstagesError {
|
|
123
116
|
constructor(message) {
|
|
124
117
|
super(`Error Processing Dom: ${message}`);
|
|
125
118
|
}
|
|
126
119
|
}
|
|
127
|
-
export class
|
|
120
|
+
export class HandstagesLocatorError extends HandstagesError {
|
|
128
121
|
constructor(action, selector, message) {
|
|
129
122
|
super(`Error ${action} Element with selector: ${selector} Reason: ${message}`);
|
|
130
123
|
}
|
|
131
124
|
}
|
|
132
|
-
export class
|
|
125
|
+
export class HandstagesClickError extends HandstagesError {
|
|
133
126
|
constructor(message, selector) {
|
|
134
127
|
super(`Error Clicking Element with selector: ${selector} Reason: ${message}`);
|
|
135
128
|
}
|
|
136
129
|
}
|
|
137
|
-
export class LLMResponseError extends
|
|
130
|
+
export class LLMResponseError extends HandstagesError {
|
|
138
131
|
constructor(primitive, message) {
|
|
139
132
|
super(`${primitive} LLM response error: ${message}`);
|
|
140
133
|
}
|
|
141
134
|
}
|
|
142
|
-
export class
|
|
135
|
+
export class HandstagesIframeError extends HandstagesError {
|
|
143
136
|
constructor(frameUrl, message) {
|
|
144
137
|
super(`Unable to resolve frameId for iframe with URL: ${frameUrl} Full error: ${message}`);
|
|
145
138
|
}
|
|
146
139
|
}
|
|
147
|
-
export class ContentFrameNotFoundError extends
|
|
140
|
+
export class ContentFrameNotFoundError extends HandstagesError {
|
|
148
141
|
constructor(selector) {
|
|
149
142
|
super(`Unable to obtain a content frame for selector: ${selector}`);
|
|
150
143
|
}
|
|
151
144
|
}
|
|
152
|
-
export class XPathResolutionError extends
|
|
145
|
+
export class XPathResolutionError extends HandstagesError {
|
|
153
146
|
constructor(xpath) {
|
|
154
147
|
super(`XPath "${xpath}" does not resolve in the current page or frames`);
|
|
155
148
|
}
|
|
@@ -170,76 +163,76 @@ ${JSON.stringify(issues, null, 2)}`);
|
|
|
170
163
|
this.name = "ZodSchemaValidationError";
|
|
171
164
|
}
|
|
172
165
|
}
|
|
173
|
-
export class
|
|
166
|
+
export class HandstagesInitError extends HandstagesError {
|
|
174
167
|
constructor(message) {
|
|
175
168
|
super(message);
|
|
176
169
|
}
|
|
177
170
|
}
|
|
178
|
-
export class
|
|
171
|
+
export class HandstagesShadowRootMissingError extends HandstagesError {
|
|
179
172
|
constructor(detail) {
|
|
180
173
|
super(`No shadow root present on the resolved host` +
|
|
181
174
|
(detail ? `: ${detail}` : ""));
|
|
182
175
|
}
|
|
183
176
|
}
|
|
184
|
-
export class
|
|
177
|
+
export class HandstagesShadowSegmentEmptyError extends HandstagesError {
|
|
185
178
|
constructor() {
|
|
186
179
|
super(`Empty selector segment after shadow-DOM hop ("//")`);
|
|
187
180
|
}
|
|
188
181
|
}
|
|
189
|
-
export class
|
|
182
|
+
export class HandstagesShadowSegmentNotFoundError extends HandstagesError {
|
|
190
183
|
constructor(segment, hint) {
|
|
191
184
|
super(`Shadow segment '${segment}' matched no element inside shadow root` +
|
|
192
185
|
(hint ? ` ${hint}` : ""));
|
|
193
186
|
}
|
|
194
187
|
}
|
|
195
|
-
export class ElementNotVisibleError extends
|
|
188
|
+
export class ElementNotVisibleError extends HandstagesError {
|
|
196
189
|
constructor(selector) {
|
|
197
190
|
super(`Element not visible (no box model): ${selector}`);
|
|
198
191
|
}
|
|
199
192
|
}
|
|
200
|
-
export class ResponseBodyError extends
|
|
193
|
+
export class ResponseBodyError extends HandstagesError {
|
|
201
194
|
constructor(message) {
|
|
202
195
|
super(`Failed to retrieve response body: ${message}`);
|
|
203
196
|
}
|
|
204
197
|
}
|
|
205
|
-
export class ResponseParseError extends
|
|
198
|
+
export class ResponseParseError extends HandstagesError {
|
|
206
199
|
constructor(message) {
|
|
207
200
|
super(`Failed to parse response: ${message}`);
|
|
208
201
|
}
|
|
209
202
|
}
|
|
210
|
-
export class TimeoutError extends
|
|
203
|
+
export class TimeoutError extends HandstagesError {
|
|
211
204
|
constructor(operation, timeoutMs) {
|
|
212
205
|
super(`${operation} timed out after ${timeoutMs}ms`);
|
|
213
206
|
}
|
|
214
207
|
}
|
|
215
|
-
export class PageNotFoundError extends
|
|
208
|
+
export class PageNotFoundError extends HandstagesError {
|
|
216
209
|
constructor(identifier) {
|
|
217
210
|
super(`No Page found for ${identifier}`);
|
|
218
211
|
}
|
|
219
212
|
}
|
|
220
|
-
export class ConnectionTimeoutError extends
|
|
213
|
+
export class ConnectionTimeoutError extends HandstagesError {
|
|
221
214
|
constructor(message) {
|
|
222
215
|
super(`Connection timeout: ${message}`);
|
|
223
216
|
}
|
|
224
217
|
}
|
|
225
|
-
export class
|
|
218
|
+
export class HandstagesClosedError extends HandstagesError {
|
|
226
219
|
constructor() {
|
|
227
|
-
super("
|
|
220
|
+
super("Handstages session was closed");
|
|
228
221
|
}
|
|
229
222
|
}
|
|
230
|
-
export class
|
|
223
|
+
export class CDPConnectionClosedError extends HandstagesError {
|
|
231
224
|
constructor(reason) {
|
|
232
225
|
super(`CDP connection closed: ${reason}`);
|
|
233
226
|
}
|
|
234
227
|
}
|
|
235
|
-
export class
|
|
228
|
+
export class HandstagesSetExtraHTTPHeadersError extends HandstagesError {
|
|
236
229
|
failures;
|
|
237
230
|
constructor(failures) {
|
|
238
231
|
super(`setExtraHTTPHeaders failed for ${failures.length} session(s): ${failures.join(", ")}`);
|
|
239
232
|
this.failures = failures;
|
|
240
233
|
}
|
|
241
234
|
}
|
|
242
|
-
export class
|
|
235
|
+
export class HandstagesSnapshotError extends HandstagesError {
|
|
243
236
|
constructor(cause) {
|
|
244
237
|
const suffix = cause instanceof Error
|
|
245
238
|
? `: ${cause.message}`
|
|
@@ -249,7 +242,7 @@ export class StagehandSnapshotError extends StagehandError {
|
|
|
249
242
|
super(`error taking snapshot${suffix}`, cause);
|
|
250
243
|
}
|
|
251
244
|
}
|
|
252
|
-
export class UnderstudyCommandException extends
|
|
245
|
+
export class UnderstudyCommandException extends HandstagesError {
|
|
253
246
|
constructor(message, cause) {
|
|
254
247
|
super(message, cause);
|
|
255
248
|
this.name = "UnderstudyCommandException";
|
|
@@ -39,9 +39,7 @@ export async function computeActiveElementXpath(page) {
|
|
|
39
39
|
break;
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
|
-
catch {
|
|
43
|
-
//
|
|
44
|
-
}
|
|
42
|
+
catch { }
|
|
45
43
|
}
|
|
46
44
|
if (!focusedFrameId)
|
|
47
45
|
focusedFrameId = page.mainFrameId();
|
|
@@ -78,9 +76,7 @@ export async function computeActiveElementXpath(page) {
|
|
|
78
76
|
try {
|
|
79
77
|
await focusedSession.send("Runtime.releaseObject", { objectId });
|
|
80
78
|
}
|
|
81
|
-
catch {
|
|
82
|
-
//
|
|
83
|
-
}
|
|
79
|
+
catch { }
|
|
84
80
|
const xp = result?.value || "";
|
|
85
81
|
return typeof xp === "string" && xp ? xp : null;
|
|
86
82
|
}
|
|
@@ -88,9 +84,7 @@ export async function computeActiveElementXpath(page) {
|
|
|
88
84
|
try {
|
|
89
85
|
await focusedSession.send("Runtime.releaseObject", { objectId });
|
|
90
86
|
}
|
|
91
|
-
catch {
|
|
92
|
-
//
|
|
93
|
-
}
|
|
87
|
+
catch { }
|
|
94
88
|
return null;
|
|
95
89
|
}
|
|
96
90
|
})();
|
|
@@ -111,9 +105,7 @@ export async function computeActiveElementXpath(page) {
|
|
|
111
105
|
prefix = prefix ? prefixXPath(prefix, xp) : normalizeXPath(xp);
|
|
112
106
|
}
|
|
113
107
|
}
|
|
114
|
-
catch {
|
|
115
|
-
//
|
|
116
|
-
}
|
|
108
|
+
catch { }
|
|
117
109
|
cur = parent;
|
|
118
110
|
}
|
|
119
111
|
return prefix ? prefixXPath(prefix, leafXPath) : normalizeXPath(leafXPath);
|
|
@@ -42,9 +42,7 @@ export async function resolveXpathForLocation(page, x, y) {
|
|
|
42
42
|
sx = Number(result?.value?.sx ?? 0);
|
|
43
43
|
sy = Number(result?.value?.sy ?? 0);
|
|
44
44
|
}
|
|
45
|
-
catch {
|
|
46
|
-
//
|
|
47
|
-
}
|
|
45
|
+
catch { }
|
|
48
46
|
const xi = Math.max(0, Math.floor(curX + sx));
|
|
49
47
|
const yi = Math.max(0, Math.floor(curY + sy));
|
|
50
48
|
let res;
|
|
@@ -110,9 +108,7 @@ export async function resolveXpathForLocation(page, x, y) {
|
|
|
110
108
|
.catch(() => { });
|
|
111
109
|
}
|
|
112
110
|
}
|
|
113
|
-
catch {
|
|
114
|
-
//
|
|
115
|
-
}
|
|
111
|
+
catch { }
|
|
116
112
|
curX = Math.max(0, curX - left);
|
|
117
113
|
curY = Math.max(0, curY - top);
|
|
118
114
|
curFrameId = matchedChild;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { HandstagesDomProcessError } from "../../../types/public/sdkErrors";
|
|
2
2
|
import { buildChildXPathSegments, joinXPath, normalizeXPath, } from "./xpathUtils";
|
|
3
3
|
// starting from infinite depth (-1), exponentially shrink down to 1
|
|
4
4
|
const DOM_DEPTH_ATTEMPTS = [-1, 256, 128, 64, 32, 16, 8, 4, 2, 1];
|
|
@@ -37,7 +37,7 @@ export function collectDomTraversalTargets(node) {
|
|
|
37
37
|
}
|
|
38
38
|
/**
|
|
39
39
|
* Rehydrate a truncated DOM tree by repeatedly calling DOM.describeNode with
|
|
40
|
-
* decreasing depths. Any non-CBOR failure is surfaced as a
|
|
40
|
+
* decreasing depths. Any non-CBOR failure is surfaced as a HandstagesDomProcessError.
|
|
41
41
|
*/
|
|
42
42
|
export async function hydrateDomTree(session, root, pierce) {
|
|
43
43
|
const stack = [root];
|
|
@@ -86,12 +86,12 @@ export async function hydrateDomTree(session, root, pierce) {
|
|
|
86
86
|
continue;
|
|
87
87
|
}
|
|
88
88
|
const identifier = nodeId ?? backendId ?? "unknown";
|
|
89
|
-
throw new
|
|
89
|
+
throw new HandstagesDomProcessError(`Failed to expand DOM node ${identifier}: ${String(err)}`);
|
|
90
90
|
}
|
|
91
91
|
}
|
|
92
92
|
if (!expanded) {
|
|
93
93
|
const identifier = nodeId ?? backendId ?? "unknown";
|
|
94
|
-
throw new
|
|
94
|
+
throw new HandstagesDomProcessError(`Unable to expand DOM node ${identifier} after describeNode depth retries`);
|
|
95
95
|
}
|
|
96
96
|
}
|
|
97
97
|
for (const child of collectDomTraversalTargets(node)) {
|
|
@@ -123,7 +123,7 @@ export async function getDomTreeWithFallback(session, pierce) {
|
|
|
123
123
|
throw err;
|
|
124
124
|
}
|
|
125
125
|
}
|
|
126
|
-
throw new
|
|
126
|
+
throw new HandstagesDomProcessError(lastCborMessage
|
|
127
127
|
? `CDP DOM.getDocument failed after adaptive depth retries: ${lastCborMessage}`
|
|
128
128
|
: "CDP DOM.getDocument failed after adaptive depth retries.");
|
|
129
129
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { HandstagesIframeError } from "../../../types/public/sdkErrors";
|
|
2
2
|
import { executionContexts } from "../../executionContextRegistry";
|
|
3
3
|
import { buildLocatorInvocation } from "../../locatorInvocation";
|
|
4
4
|
import { prefixXPath } from "./xpathUtils";
|
|
@@ -59,7 +59,7 @@ export async function resolveFocusFrameAndTail(page, absoluteXPath, parentByFram
|
|
|
59
59
|
const parentSess = page.getSessionForFrame(ctxFrameId);
|
|
60
60
|
const objectId = await resolveObjectIdForXPath(parentSess, selectorForIframe, ctxFrameId);
|
|
61
61
|
if (!objectId)
|
|
62
|
-
throw new
|
|
62
|
+
throw new HandstagesIframeError(selectorForIframe, "Failed to resolve iframe element by XPath");
|
|
63
63
|
try {
|
|
64
64
|
await parentSess.send("DOM.enable").catch(() => { });
|
|
65
65
|
const desc = await parentSess.send("DOM.describeNode", { objectId });
|
|
@@ -76,7 +76,7 @@ export async function resolveFocusFrameAndTail(page, absoluteXPath, parentByFram
|
|
|
76
76
|
catch { }
|
|
77
77
|
}
|
|
78
78
|
if (!childFrameId)
|
|
79
|
-
throw new
|
|
79
|
+
throw new HandstagesIframeError(selectorForIframe, "Could not map iframe to child frameId");
|
|
80
80
|
absPrefix = prefixXPath(absPrefix || "/", selectorForIframe);
|
|
81
81
|
ctxFrameId = childFrameId;
|
|
82
82
|
}
|
|
@@ -108,7 +108,7 @@ export async function resolveCssFocusFrameAndTail(page, rawSelector, parentByFra
|
|
|
108
108
|
const parentSess = page.getSessionForFrame(ctxFrameId);
|
|
109
109
|
const objectId = await resolveObjectIdForCss(parentSess, parts[i], ctxFrameId);
|
|
110
110
|
if (!objectId)
|
|
111
|
-
throw new
|
|
111
|
+
throw new HandstagesIframeError(parts[i], "Failed to resolve iframe via CSS hop");
|
|
112
112
|
try {
|
|
113
113
|
await parentSess.send("DOM.enable").catch(() => { });
|
|
114
114
|
const desc = await parentSess.send("DOM.describeNode", { objectId });
|
|
@@ -125,7 +125,7 @@ export async function resolveCssFocusFrameAndTail(page, rawSelector, parentByFra
|
|
|
125
125
|
catch { }
|
|
126
126
|
}
|
|
127
127
|
if (!childFrameId)
|
|
128
|
-
throw new
|
|
128
|
+
throw new HandstagesIframeError(parts[i], "Could not map CSS iframe hop to child frameId");
|
|
129
129
|
ctxFrameId = childFrameId;
|
|
130
130
|
}
|
|
131
131
|
finally {
|