@e2e-dev/web 0.11.0-canary-20260928184528

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (121) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +5 -0
  3. package/README.md +138 -0
  4. package/dist/.build.json +1 -0
  5. package/dist/actions.d.ts +23 -0
  6. package/dist/actions.d.ts.map +1 -0
  7. package/dist/actions.js +174 -0
  8. package/dist/actions.js.map +1 -0
  9. package/dist/attempt-session.d.ts +77 -0
  10. package/dist/attempt-session.d.ts.map +1 -0
  11. package/dist/attempt-session.js +293 -0
  12. package/dist/attempt-session.js.map +1 -0
  13. package/dist/browser-connection.d.ts +34 -0
  14. package/dist/browser-connection.d.ts.map +1 -0
  15. package/dist/browser-connection.js +86 -0
  16. package/dist/browser-connection.js.map +1 -0
  17. package/dist/capture-scope.d.ts +21 -0
  18. package/dist/capture-scope.d.ts.map +1 -0
  19. package/dist/capture-scope.js +61 -0
  20. package/dist/capture-scope.js.map +1 -0
  21. package/dist/cdp-recovery.d.ts +29 -0
  22. package/dist/cdp-recovery.d.ts.map +1 -0
  23. package/dist/cdp-recovery.js +84 -0
  24. package/dist/cdp-recovery.js.map +1 -0
  25. package/dist/cdp-selectors.d.ts +15 -0
  26. package/dist/cdp-selectors.d.ts.map +1 -0
  27. package/dist/cdp-selectors.js +52 -0
  28. package/dist/cdp-selectors.js.map +1 -0
  29. package/dist/closed-shadow.d.ts +64 -0
  30. package/dist/closed-shadow.d.ts.map +1 -0
  31. package/dist/closed-shadow.js +142 -0
  32. package/dist/closed-shadow.js.map +1 -0
  33. package/dist/dialogs.d.ts +38 -0
  34. package/dist/dialogs.d.ts.map +1 -0
  35. package/dist/dialogs.js +87 -0
  36. package/dist/dialogs.js.map +1 -0
  37. package/dist/engine.d.ts +26 -0
  38. package/dist/engine.d.ts.map +1 -0
  39. package/dist/engine.js +176 -0
  40. package/dist/engine.js.map +1 -0
  41. package/dist/evaluation.d.ts +18 -0
  42. package/dist/evaluation.d.ts.map +1 -0
  43. package/dist/evaluation.js +35 -0
  44. package/dist/evaluation.js.map +1 -0
  45. package/dist/in-page/read-semantics.d.ts +28 -0
  46. package/dist/in-page/read-semantics.d.ts.map +1 -0
  47. package/dist/in-page/read-semantics.js +1178 -0
  48. package/dist/in-page/read-semantics.js.map +1 -0
  49. package/dist/index.d.ts +22 -0
  50. package/dist/index.d.ts.map +1 -0
  51. package/dist/index.js +14 -0
  52. package/dist/index.js.map +1 -0
  53. package/dist/install.d.ts +40 -0
  54. package/dist/install.d.ts.map +1 -0
  55. package/dist/install.js +117 -0
  56. package/dist/install.js.map +1 -0
  57. package/dist/label-selector.d.ts +37 -0
  58. package/dist/label-selector.d.ts.map +1 -0
  59. package/dist/label-selector.js +53 -0
  60. package/dist/label-selector.js.map +1 -0
  61. package/dist/locators.d.ts +76 -0
  62. package/dist/locators.d.ts.map +1 -0
  63. package/dist/locators.js +289 -0
  64. package/dist/locators.js.map +1 -0
  65. package/dist/observation-capture.d.ts +12 -0
  66. package/dist/observation-capture.d.ts.map +1 -0
  67. package/dist/observation-capture.js +93 -0
  68. package/dist/observation-capture.js.map +1 -0
  69. package/dist/observation.d.ts +63 -0
  70. package/dist/observation.d.ts.map +1 -0
  71. package/dist/observation.js +280 -0
  72. package/dist/observation.js.map +1 -0
  73. package/dist/observe.d.ts +51 -0
  74. package/dist/observe.d.ts.map +1 -0
  75. package/dist/observe.js +105 -0
  76. package/dist/observe.js.map +1 -0
  77. package/dist/operation-budget.d.ts +11 -0
  78. package/dist/operation-budget.d.ts.map +1 -0
  79. package/dist/operation-budget.js +40 -0
  80. package/dist/operation-budget.js.map +1 -0
  81. package/dist/protected-app.d.ts +32 -0
  82. package/dist/protected-app.d.ts.map +1 -0
  83. package/dist/protected-app.js +39 -0
  84. package/dist/protected-app.js.map +1 -0
  85. package/dist/provider.d.ts +158 -0
  86. package/dist/provider.d.ts.map +1 -0
  87. package/dist/provider.js +311 -0
  88. package/dist/provider.js.map +1 -0
  89. package/dist/read-node.d.ts +152 -0
  90. package/dist/read-node.d.ts.map +1 -0
  91. package/dist/read-node.js +42 -0
  92. package/dist/read-node.js.map +1 -0
  93. package/dist/refs.d.ts +43 -0
  94. package/dist/refs.d.ts.map +1 -0
  95. package/dist/refs.js +85 -0
  96. package/dist/refs.js.map +1 -0
  97. package/dist/route-pattern.d.ts +13 -0
  98. package/dist/route-pattern.d.ts.map +1 -0
  99. package/dist/route-pattern.js +55 -0
  100. package/dist/route-pattern.js.map +1 -0
  101. package/dist/selector-engines.d.ts +6 -0
  102. package/dist/selector-engines.d.ts.map +1 -0
  103. package/dist/selector-engines.js +8 -0
  104. package/dist/selector-engines.js.map +1 -0
  105. package/dist/support.d.ts +147 -0
  106. package/dist/support.d.ts.map +1 -0
  107. package/dist/support.js +366 -0
  108. package/dist/support.js.map +1 -0
  109. package/dist/surface.d.ts +313 -0
  110. package/dist/surface.d.ts.map +1 -0
  111. package/dist/surface.js +691 -0
  112. package/dist/surface.js.map +1 -0
  113. package/dist/video.d.ts +59 -0
  114. package/dist/video.d.ts.map +1 -0
  115. package/dist/video.js +116 -0
  116. package/dist/video.js.map +1 -0
  117. package/dist/web.d.ts +191 -0
  118. package/dist/web.d.ts.map +1 -0
  119. package/dist/web.js +382 -0
  120. package/dist/web.js.map +1 -0
  121. package/package.json +67 -0
@@ -0,0 +1,158 @@
1
+ /**
2
+ * The seam a hosted browser service plugs into: a `BrowserProvider` leases a
3
+ * browser and hands back the CDP endpoint to attach to. In `worker` scope the
4
+ * engine leases one browser per worker slot in `prepare`, attaches each from
5
+ * its worker, and releases them all in `finish`; in `attempt` scope it leases
6
+ * a fresh browser in every `startAttempt` and releases it in `endAttempt`.
7
+ * Nothing here knows any vendor: a cloud browser service, a browser farm, or
8
+ * a Chrome on a machine down the hall are each one small provider in user code.
9
+ */
10
+ import { type EngineAttemptContext, type EngineCleanupContext, type EngineFinishInfo, type EngineInitInfo, type EnginePrepareInfo, type EnginePrepareResult } from 'e2e/engine';
11
+ /**
12
+ * How long a lease lives. `worker` (the default) is one browser per worker
13
+ * slot, acquired in `prepare` and released in `finish`; `attempt` is a fresh
14
+ * browser per attempt, acquired in `startAttempt` and released in
15
+ * `endAttempt`, reconnected through the lease's `reconnectEndpoint` after a
16
+ * transport drop.
17
+ */
18
+ export type BrowserProviderScope = 'worker' | 'attempt';
19
+ /** What the engine asks a provider for: one browser for one worker slot, or for one attempt, of a run. */
20
+ export interface BrowserRequest {
21
+ /** The run id, for naming the session at the provider. */
22
+ readonly runId: string;
23
+ /** The target the browser serves. */
24
+ readonly targetName: string;
25
+ /** Worker slot the browser serves, `0` to `slots - 1`; in `worker` scope `slots` leases are acquired at once. */
26
+ readonly slot: number;
27
+ /** Worker slots the run uses for this target, in all. */
28
+ readonly slots: number;
29
+ /** Present only for a per-attempt lease. */
30
+ readonly attemptId?: string | undefined;
31
+ /** The run's environment: where a provider reads its token from, never `process.env`. */
32
+ readonly env: Readonly<Record<string, string | undefined>>;
33
+ /** Aborts on interrupt, and when the attempt that needs the browser is cancelled or exceeds its budget. */
34
+ readonly signal: AbortSignal;
35
+ /** Reports one line of progress to the run's reporter (a session URL to watch); discarded in a worker process. */
36
+ readonly log: (line: string) => void;
37
+ }
38
+ /**
39
+ * One leased browser, as `acquire` returns it and `release` gets it back.
40
+ * JSON data only: a lease travels from the runner process to the worker that
41
+ * attaches to it through the environment.
42
+ */
43
+ export interface BrowserLease {
44
+ /**
45
+ * The provider's handle on the lease (a session id); named in progress
46
+ * lines and handed back to `release`. A provider may keep further fields on
47
+ * the object it returns: `release` gets that same object, while only the
48
+ * fields declared here travel to the worker.
49
+ */
50
+ readonly id: string;
51
+ /** `ws://`, `wss://`, or `http://` DevTools endpoint to attach to over CDP. */
52
+ readonly cdpEndpoint: string;
53
+ /**
54
+ * Endpoint to reattach to the same browser after a transport drop, when it
55
+ * differs from `cdpEndpoint`; only meaningful for a per-attempt lease.
56
+ */
57
+ readonly reconnectEndpoint?: string | undefined;
58
+ }
59
+ /** Handed to `release`, once per lease. */
60
+ export interface BrowserReleaseContext {
61
+ readonly runId: string;
62
+ readonly targetName: string;
63
+ /** The run's environment, the same `acquire` saw. */
64
+ readonly env: Readonly<Record<string, string | undefined>>;
65
+ /** Aborts when the cleanup budget is spent. */
66
+ readonly signal: AbortSignal;
67
+ readonly log: (line: string) => void;
68
+ }
69
+ /**
70
+ * A source of hosted browsers. In `worker` scope `acquire` is called once per
71
+ * worker slot, for every slot at once, in the runner process; a worker whose
72
+ * browser drops calls it again, from its own process, for a replacement. In
73
+ * `attempt` scope every `startAttempt` calls it from the worker. `release`
74
+ * is called exactly once per lease, by the process that acquired it, also
75
+ * after an `acquire` of another slot failed. A provider must not rely on
76
+ * runner-process state to serve a request from a worker.
77
+ */
78
+ export interface BrowserProvider {
79
+ /** Label in progress lines and error messages. */
80
+ readonly name: string;
81
+ /** How long a lease lives; `worker` when absent. */
82
+ readonly scope?: BrowserProviderScope | undefined;
83
+ acquire(request: BrowserRequest): Promise<BrowserLease>;
84
+ release(lease: BrowserLease, context: BrowserReleaseContext): Promise<void>;
85
+ }
86
+ /** Narrows an intended provider, or names what it is missing. */
87
+ export declare function asBrowserProvider(browser: object): BrowserProvider;
88
+ /**
89
+ * Browsers a provider leases for one target, on both sides of the worker
90
+ * boundary. In the runner, `prepare` leases one per slot, all at once (hosted
91
+ * browsers start in parallel and are billed from the moment they do), and
92
+ * holds every lease granted for `finish` before the outcome is known, so a
93
+ * slot that fails to lease fails the run and the others are still released.
94
+ * In a worker, `init` reads the slot's lease from the environment; a browser
95
+ * that drops is replaced by a lease the worker acquires itself, and
96
+ * per-attempt leases come and go with the attempt. Each lease is released
97
+ * exactly once, by the side that acquired it.
98
+ */
99
+ export declare class LeasedBrowsers {
100
+ private readonly provider;
101
+ readonly scope: BrowserProviderScope;
102
+ /** Leases granted so far, per target, filled as each `acquire` settles. */
103
+ private readonly held;
104
+ private run;
105
+ /** The lease the worker's shared browser attaches to, and whether `endpoint` has handed it out yet. */
106
+ private current;
107
+ private attached;
108
+ private attempt;
109
+ /** The attempt whose lease is being acquired or held; a lease that arrives for any other attempt is released, not committed. */
110
+ private opened;
111
+ /** This worker's tenure, replaced by `init` and `dispose`; a replacement lease that arrives for an earlier one is released, not committed. */
112
+ private tenure;
113
+ constructor(provider: BrowserProvider);
114
+ /**
115
+ * Leases one browser per worker slot the run will use, in `worker` scope,
116
+ * and hands the leases to the workers through the environment; `attempt`
117
+ * scope leases per attempt instead and hands over the slot count alone. A
118
+ * target nothing runs on leases nothing.
119
+ */
120
+ prepare(info: EnginePrepareInfo): Promise<EnginePrepareResult>;
121
+ /** Releases what `prepare` leased for the target, every lease before the first failure is reported. */
122
+ finish(info: EngineFinishInfo): Promise<void>;
123
+ /**
124
+ * Records the run this worker serves and, in `worker` scope, the lease its
125
+ * slot was handed. A missing hand-off is a broken invariant: the runner
126
+ * prepares every target before it starts a worker, and caps the slots at
127
+ * the workers `prepare` reported.
128
+ */
129
+ init(info: EngineInitInfo): void;
130
+ /**
131
+ * The endpoint the worker's shared browser attaches to, in `worker` scope:
132
+ * the slot's lease the first time, and a replacement the worker leases
133
+ * itself every time after, since the connection only asks again once the
134
+ * browser it had dropped. A dead lease is released by the side that
135
+ * acquired it: the worker here, best effort, or the runner in `finish`. A
136
+ * replacement that arrives once the attempt was cancelled or the worker
137
+ * disposed is given straight back and never committed.
138
+ */
139
+ endpoint(signal: AbortSignal): Promise<string>;
140
+ /**
141
+ * Leases a fresh browser for the attempt, in `attempt` scope; `endAttempt`
142
+ * releases it on every path. A lease that arrives once the attempt was
143
+ * cancelled or already ended (a provider that ignored the abort) is given
144
+ * straight back and never committed, so a retry never finds it.
145
+ */
146
+ startAttempt(context: EngineAttemptContext): Promise<BrowserLease>;
147
+ /** Releases the attempt's lease, when one was granted; idempotent, and safe after a failed `startAttempt`. */
148
+ endAttempt(context: EngineCleanupContext): Promise<void>;
149
+ /** Releases the replacement lease the worker acquired for itself; what `prepare` leased is the runner's to release. */
150
+ dispose(context: EngineCleanupContext): Promise<void>;
151
+ private requireRun;
152
+ /** One `acquire`, its result checked field by field; a failure is named after the provider. */
153
+ private acquire;
154
+ /** One `release` from the worker, bounded by the cleanup budget; a failure is a cleanup error named after the provider. */
155
+ private release;
156
+ private releaseContext;
157
+ }
158
+ //# sourceMappingURL=provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,311 @@
1
+ /**
2
+ * The seam a hosted browser service plugs into: a `BrowserProvider` leases a
3
+ * browser and hands back the CDP endpoint to attach to. In `worker` scope the
4
+ * engine leases one browser per worker slot in `prepare`, attaches each from
5
+ * its worker, and releases them all in `finish`; in `attempt` scope it leases
6
+ * a fresh browser in every `startAttempt` and releases it in `endAttempt`.
7
+ * Nothing here knows any vendor: a cloud browser service, a browser farm, or
8
+ * a Chrome on a machine down the hall are each one small provider in user code.
9
+ */
10
+ import { createHash } from 'node:crypto';
11
+ import { ConfigurationError, EngineError, obj, raceAbort, } from 'e2e/engine';
12
+ import { message } from './support.js';
13
+ const SCOPES = new Set(['worker', 'attempt']);
14
+ /** Narrows an intended provider, or names what it is missing. */
15
+ export function asBrowserProvider(browser) {
16
+ const candidate = browser;
17
+ if (typeof candidate.name !== 'string' || candidate.name.trim() === '') {
18
+ throw new ConfigurationError('INVALID_CONFIG', 'web: a `browser` provider needs a non-empty `name`');
19
+ }
20
+ for (const member of ['acquire', 'release']) {
21
+ if (typeof candidate[member] !== 'function') {
22
+ throw new ConfigurationError('INVALID_CONFIG', `web: browser provider "${candidate.name}" must implement ${member}()`);
23
+ }
24
+ }
25
+ if (candidate.scope !== undefined && (typeof candidate.scope !== 'string' || !SCOPES.has(candidate.scope))) {
26
+ throw new ConfigurationError('INVALID_CONFIG', `web: browser provider "${candidate.name}" has scope ${JSON.stringify(candidate.scope)}; use "worker" or "attempt"`);
27
+ }
28
+ return browser;
29
+ }
30
+ function isNonEmptyString(value) {
31
+ return typeof value === 'string' && value.trim() !== '';
32
+ }
33
+ /** A lease as a provider returned it or as JSON parsed it back, checked field by field: the engine trusts nothing it did not write. */
34
+ function isBrowserLease(value) {
35
+ if (typeof value !== 'object' || value === null)
36
+ return false;
37
+ const { id, cdpEndpoint, reconnectEndpoint } = value;
38
+ return isNonEmptyString(id) && isNonEmptyString(cdpEndpoint) && (reconnectEndpoint === undefined || isNonEmptyString(reconnectEndpoint));
39
+ }
40
+ /**
41
+ * The most the serialized hand-off of one target may occupy in a worker's
42
+ * environment: a lease comes from third-party code, and an oversized
43
+ * environment fails the worker spawn with an opaque error.
44
+ */
45
+ const MAX_HANDOFF_ENV_BYTES = 16 * 1024;
46
+ /**
47
+ * The environment variable a target's hand-off travels to the workers in:
48
+ * the name made environment-safe for reading, plus a digest of the exact
49
+ * name so `web-a` and `web.a` never share a key.
50
+ */
51
+ function handoffVariable(targetName) {
52
+ const readable = targetName.replace(/[^A-Za-z0-9]/g, '_').toUpperCase();
53
+ const digest = createHash('sha256').update(targetName).digest('hex').slice(0, 8).toUpperCase();
54
+ return `E2E_WEB_BROWSERS_${readable}_${digest}`;
55
+ }
56
+ /** Serializes the hand-off for the environment: declared lease fields only, bounded. */
57
+ function encodeHandoff(handoff) {
58
+ const encoded = JSON.stringify({
59
+ slots: handoff.slots,
60
+ leases: handoff.leases.map((lease) => obj({ id: lease.id, cdpEndpoint: lease.cdpEndpoint, reconnectEndpoint: lease.reconnectEndpoint })),
61
+ });
62
+ const bytes = Buffer.byteLength(encoded);
63
+ if (bytes > MAX_HANDOFF_ENV_BYTES) {
64
+ throw new EngineError('ENGINE_FAILURE', `the browser leases take ${bytes} bytes; the worker environment carries at most ${MAX_HANDOFF_ENV_BYTES}`, { retryable: false });
65
+ }
66
+ return encoded;
67
+ }
68
+ /** The hand-off a `prepare` left in the environment, or `undefined` when there is none it can read. */
69
+ function decodeHandoff(raw) {
70
+ if (raw === undefined)
71
+ return undefined;
72
+ try {
73
+ const parsed = JSON.parse(raw);
74
+ if (typeof parsed !== 'object' || parsed === null)
75
+ return undefined;
76
+ const { slots, leases } = parsed;
77
+ if (Number.isInteger(slots) && slots >= 0 && Array.isArray(leases) && leases.every(isBrowserLease)) {
78
+ return { slots: slots, leases };
79
+ }
80
+ }
81
+ catch {
82
+ // Not ours to read.
83
+ }
84
+ return undefined;
85
+ }
86
+ /** Runs every task, then reports the first failure: nothing is skipped because a sibling failed. */
87
+ async function allOrFirstFailure(tasks, describe) {
88
+ // `async` so a task that throws before its first await is a rejection like any other, not an escape.
89
+ const settled = await Promise.allSettled(tasks.map(async (task) => task()));
90
+ const failed = settled.find((result) => result.status === 'rejected');
91
+ if (failed !== undefined) {
92
+ if (failed.reason instanceof EngineError)
93
+ throw failed.reason;
94
+ throw new EngineError('ENGINE_FAILURE', `${describe}: ${message(failed.reason)}`, { retryable: false, cause: failed.reason });
95
+ }
96
+ return settled.flatMap((result) => (result.status === 'fulfilled' ? [result.value] : []));
97
+ }
98
+ const discard = () => undefined;
99
+ /**
100
+ * Browsers a provider leases for one target, on both sides of the worker
101
+ * boundary. In the runner, `prepare` leases one per slot, all at once (hosted
102
+ * browsers start in parallel and are billed from the moment they do), and
103
+ * holds every lease granted for `finish` before the outcome is known, so a
104
+ * slot that fails to lease fails the run and the others are still released.
105
+ * In a worker, `init` reads the slot's lease from the environment; a browser
106
+ * that drops is replaced by a lease the worker acquires itself, and
107
+ * per-attempt leases come and go with the attempt. Each lease is released
108
+ * exactly once, by the side that acquired it.
109
+ */
110
+ export class LeasedBrowsers {
111
+ provider;
112
+ scope;
113
+ /** Leases granted so far, per target, filled as each `acquire` settles. */
114
+ held = new Map();
115
+ run;
116
+ /** The lease the worker's shared browser attaches to, and whether `endpoint` has handed it out yet. */
117
+ current;
118
+ attached = false;
119
+ attempt;
120
+ /** The attempt whose lease is being acquired or held; a lease that arrives for any other attempt is released, not committed. */
121
+ opened;
122
+ /** This worker's tenure, replaced by `init` and `dispose`; a replacement lease that arrives for an earlier one is released, not committed. */
123
+ tenure = {};
124
+ constructor(provider) {
125
+ this.provider = provider;
126
+ this.scope = provider.scope ?? 'worker';
127
+ }
128
+ // --- runner side ---
129
+ /**
130
+ * Leases one browser per worker slot the run will use, in `worker` scope,
131
+ * and hands the leases to the workers through the environment; `attempt`
132
+ * scope leases per attempt instead and hands over the slot count alone. A
133
+ * target nothing runs on leases nothing.
134
+ */
135
+ async prepare(info) {
136
+ if (info.slots === 0)
137
+ return {};
138
+ const variable = handoffVariable(info.targetName);
139
+ if (this.scope === 'attempt')
140
+ return { env: { [variable]: encodeHandoff({ slots: info.slots, leases: [] }) } };
141
+ const { provider } = this;
142
+ const held = [];
143
+ this.held.set(info.targetName, held);
144
+ info.log(`leasing ${info.slots} browser(s) from ${provider.name}`);
145
+ const leases = await allOrFirstFailure(Array.from({ length: info.slots }, (_, slot) => async () => {
146
+ const lease = await this.acquire({
147
+ runId: info.runId,
148
+ targetName: info.targetName,
149
+ slot,
150
+ slots: info.slots,
151
+ env: info.env,
152
+ signal: info.signal,
153
+ log: (line) => info.log(`${provider.name} (${slot + 1} of ${info.slots}): ${line}`),
154
+ });
155
+ held.push(lease);
156
+ info.log(`${provider.name}: leased ${lease.id}`);
157
+ return lease;
158
+ }), `browser provider "${provider.name}" could not lease a browser`);
159
+ return { workers: leases.length, env: { [variable]: encodeHandoff({ slots: leases.length, leases }) } };
160
+ }
161
+ /** Releases what `prepare` leased for the target, every lease before the first failure is reported. */
162
+ async finish(info) {
163
+ const { provider } = this;
164
+ const leases = this.held.get(info.targetName);
165
+ this.held.delete(info.targetName);
166
+ if (leases === undefined || leases.length === 0)
167
+ return;
168
+ const context = { runId: info.runId, targetName: info.targetName, env: info.env, signal: info.signal, log: (line) => info.log(`${provider.name}: ${line}`) };
169
+ await allOrFirstFailure(leases.map((lease) => () => provider.release(lease, context)), `browser provider "${provider.name}" could not release a browser`);
170
+ info.log(`${provider.name}: released ${leases.length} browser(s)`);
171
+ }
172
+ // --- worker side ---
173
+ /**
174
+ * Records the run this worker serves and, in `worker` scope, the lease its
175
+ * slot was handed. A missing hand-off is a broken invariant: the runner
176
+ * prepares every target before it starts a worker, and caps the slots at
177
+ * the workers `prepare` reported.
178
+ */
179
+ init(info) {
180
+ const { provider } = this;
181
+ this.current = undefined;
182
+ this.attached = false;
183
+ this.tenure = {};
184
+ const handoff = decodeHandoff(info.env[handoffVariable(info.targetName)]);
185
+ if (handoff === undefined) {
186
+ throw new EngineError('ENGINE_FAILURE', `browser provider "${provider.name}" prepared nothing for target "${info.targetName}"; the runner must prepare the target before a worker starts`, { retryable: false });
187
+ }
188
+ this.run = { runId: info.runId, targetName: info.targetName, env: info.env, slot: info.workerSlot, slots: handoff.slots };
189
+ if (this.scope === 'attempt')
190
+ return;
191
+ const lease = handoff.leases[info.workerSlot];
192
+ if (lease === undefined) {
193
+ throw new EngineError('ENGINE_FAILURE', `worker slot ${info.workerSlot} is outside the ${handoff.leases.length} browser(s) "${provider.name}" leased; the runner must cap the target at the engine's reported workers`, { retryable: false });
194
+ }
195
+ this.current = { lease, owned: false };
196
+ }
197
+ /**
198
+ * The endpoint the worker's shared browser attaches to, in `worker` scope:
199
+ * the slot's lease the first time, and a replacement the worker leases
200
+ * itself every time after, since the connection only asks again once the
201
+ * browser it had dropped. A dead lease is released by the side that
202
+ * acquired it: the worker here, best effort, or the runner in `finish`. A
203
+ * replacement that arrives once the attempt was cancelled or the worker
204
+ * disposed is given straight back and never committed.
205
+ */
206
+ async endpoint(signal) {
207
+ const run = this.requireRun();
208
+ const previous = this.current;
209
+ if (previous !== undefined && !this.attached) {
210
+ this.attached = true;
211
+ return previous.lease.cdpEndpoint;
212
+ }
213
+ const { tenure } = this;
214
+ const lease = await this.acquire({ runId: run.runId, targetName: run.targetName, slot: run.slot, slots: run.slots, env: run.env, signal, log: discard });
215
+ if (signal.aborted || this.tenure !== tenure) {
216
+ await this.provider.release(lease, this.releaseContext(run, signal)).catch(discard);
217
+ throw new EngineError('CANCELLED', `browser lease from "${this.provider.name}" arrived after the worker gave up; released`, { retryable: false });
218
+ }
219
+ this.current = { lease, owned: true };
220
+ this.attached = true;
221
+ if (previous?.owned === true)
222
+ await this.provider.release(previous.lease, this.releaseContext(run, signal)).catch(discard);
223
+ return lease.cdpEndpoint;
224
+ }
225
+ /**
226
+ * Leases a fresh browser for the attempt, in `attempt` scope; `endAttempt`
227
+ * releases it on every path. A lease that arrives once the attempt was
228
+ * cancelled or already ended (a provider that ignored the abort) is given
229
+ * straight back and never committed, so a retry never finds it.
230
+ */
231
+ async startAttempt(context) {
232
+ const run = this.requireRun();
233
+ const opened = {};
234
+ this.opened = opened;
235
+ const lease = await this.acquire({
236
+ runId: run.runId,
237
+ targetName: run.targetName,
238
+ slot: run.slot,
239
+ slots: run.slots,
240
+ attemptId: context.attemptId,
241
+ env: run.env,
242
+ signal: context.signal,
243
+ log: discard,
244
+ });
245
+ if (context.signal.aborted || this.opened !== opened) {
246
+ await this.provider.release(lease, this.releaseContext(run, context.signal)).catch(discard);
247
+ throw new EngineError('CANCELLED', `browser lease from "${this.provider.name}" arrived after the attempt ended; released`, { retryable: false });
248
+ }
249
+ this.attempt = lease;
250
+ return lease;
251
+ }
252
+ /** Releases the attempt's lease, when one was granted; idempotent, and safe after a failed `startAttempt`. */
253
+ async endAttempt(context) {
254
+ const lease = this.attempt;
255
+ this.attempt = undefined;
256
+ this.opened = undefined;
257
+ if (lease === undefined)
258
+ return;
259
+ await this.release(lease, context);
260
+ }
261
+ /** Releases the replacement lease the worker acquired for itself; what `prepare` leased is the runner's to release. */
262
+ async dispose(context) {
263
+ const current = this.current;
264
+ this.current = undefined;
265
+ this.attached = false;
266
+ this.tenure = {};
267
+ if (current === undefined || !current.owned)
268
+ return;
269
+ await this.release(current.lease, context);
270
+ }
271
+ requireRun() {
272
+ if (this.run === undefined) {
273
+ throw new EngineError('ENGINE_FAILURE', `browser provider "${this.provider.name}" was asked for a browser before init`, { retryable: false });
274
+ }
275
+ return this.run;
276
+ }
277
+ /** One `acquire`, its result checked field by field; a failure is named after the provider. */
278
+ async acquire(request) {
279
+ const { provider } = this;
280
+ let lease;
281
+ try {
282
+ lease = await provider.acquire(request);
283
+ }
284
+ catch (cause) {
285
+ if (request.signal.aborted) {
286
+ throw new EngineError('CANCELLED', `browser lease from "${provider.name}" cancelled`, { retryable: false, cause });
287
+ }
288
+ throw new EngineError('ENGINE_FAILURE', `browser provider "${provider.name}" could not lease a browser: ${message(cause)}`, { retryable: false, cause });
289
+ }
290
+ if (!isBrowserLease(lease)) {
291
+ throw new EngineError('ENGINE_FAILURE', `browser provider "${provider.name}" returned a lease without an id and a cdpEndpoint`, { retryable: false });
292
+ }
293
+ return lease;
294
+ }
295
+ /** One `release` from the worker, bounded by the cleanup budget; a failure is a cleanup error named after the provider. */
296
+ async release(lease, budget) {
297
+ const run = this.requireRun();
298
+ try {
299
+ await raceAbort(this.provider.release(lease, this.releaseContext(run, budget.signal)), budget.signal, `releasing browser ${lease.id}`);
300
+ }
301
+ catch (cause) {
302
+ if (cause instanceof EngineError)
303
+ throw cause;
304
+ throw new EngineError('ENGINE_FAILURE', `browser provider "${this.provider.name}" could not release browser ${lease.id}: ${message(cause)}`, { retryable: false, cause });
305
+ }
306
+ }
307
+ releaseContext(run, signal) {
308
+ return { runId: run.runId, targetName: run.targetName, env: run.env, signal, log: discard };
309
+ }
310
+ }
311
+ //# sourceMappingURL=provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.js","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,152 @@
1
+ /**
2
+ * The wire types of the in-page semantic reader and the page functions
3
+ * assembled from its source for locator.evaluate, locator.evaluateAll, and
4
+ * page.evaluate. The reader itself lives in `in-page/read-semantics.ts`; it is
5
+ * serialized into the page, so every page function here is built from its
6
+ * source with `new Function` and stays free of module-scope captures.
7
+ */
8
+ /**
9
+ * The one definition of a secure field.
10
+ *
11
+ * It is a selector rather than a predicate because it has to be applied from
12
+ * two sides that cannot share code: the in-page reader matches elements
13
+ * against it to mark nodes `secure`, and the engine hands the same string to
14
+ * the screenshot masker. One string means the tree's redaction and the image's
15
+ * redaction cannot describe different sets of elements, which is what the
16
+ * runner's pixel-clearance check relies on.
17
+ */
18
+ export declare const SECURE_FIELD_SELECTOR = "input[type=\"password\" i]";
19
+ export interface RawNodeData {
20
+ role: string | null;
21
+ name: string | null;
22
+ /**
23
+ * Every label a person or a tool may call this control by: its `aria-label`,
24
+ * each `aria-labelledby` target, and each associated `<label>`, read as an
25
+ * accessible name (aria-hidden dropped). Null for a node with none. An exact
26
+ * label query matches any one of them, as Playwright's `getByLabel` does,
27
+ * rather than the combined or overridden `name`.
28
+ */
29
+ labels: string[] | null;
30
+ text: string | null;
31
+ value: string | null;
32
+ /** Text selected inside the focused field or editing host; null when unfocused, collapsed, or secure. */
33
+ selection: string | null;
34
+ inputPurpose: 'username' | 'password' | 'one-time-code' | 'generic-secret' | 'none';
35
+ states: {
36
+ checked: boolean | null;
37
+ disabled: boolean;
38
+ selected: boolean | null;
39
+ expanded: boolean | null;
40
+ pressed: boolean | null;
41
+ focused: boolean;
42
+ hidden: boolean;
43
+ secure: boolean;
44
+ };
45
+ /** Heading level of a heading: `aria-level`, else the digit of `h1` through `h6`; null for anything else. */
46
+ level: number | null;
47
+ attributes: Record<string, string>;
48
+ /** Value of the project's test-id attribute, when the element carries one. */
49
+ testId: string | null;
50
+ rect: {
51
+ x: number;
52
+ y: number;
53
+ width: number;
54
+ height: number;
55
+ };
56
+ }
57
+ /** One observed node plus its position in the flattened depth-first tree. */
58
+ export interface RawObservedNode extends RawNodeData {
59
+ /** Index of the nearest included ancestor, or -1 for the root. */
60
+ parent: number;
61
+ /** Unique CSS selector of this `<iframe>` element; set only for iframes. */
62
+ frameSelector?: string;
63
+ }
64
+ /** One walked document. */
65
+ interface RawObservation {
66
+ nodes: RawObservedNode[];
67
+ /** True when the node budget stopped the walk before the document was read whole. */
68
+ truncated: boolean;
69
+ /** Live element handles positionally aligned with `nodes`. */
70
+ elements: Element[];
71
+ /**
72
+ * Node ids positionally aligned with `nodes`. An id is stamped on the element
73
+ * the first time an observation includes it and read back on every later
74
+ * one, so the same element keeps the same id for as long as it lives in the
75
+ * document: two looks at an unchanged screen name its nodes identically, and
76
+ * an update can list exactly what changed. A re-created element (a framework
77
+ * re-mount, a new document) is a new node and gets a fresh id.
78
+ */
79
+ ids: string[];
80
+ }
81
+ export type SemanticMode = {
82
+ kind: 'node';
83
+ } | {
84
+ kind: 'tree';
85
+ maxNodes: number;
86
+ /**
87
+ * First numeric id available to nodes seen for the first time. The caller
88
+ * reserves maxNodes ids before execution, so an abandoned reader cannot
89
+ * collide with later captures or locator resolution.
90
+ */
91
+ idSeed: number;
92
+ /** Cuts each node's name at this length; the caller owns the contract value. */
93
+ nameLimit: number;
94
+ /** Cuts each node's text at this length; the caller owns the contract value. */
95
+ textLimit: number;
96
+ };
97
+ /**
98
+ * What a node read reports for an element no longer in its document. A
99
+ * detached element has no boxes, so everything else it would report (hidden,
100
+ * no labels) describes nothing on screen; its current value is still its own.
101
+ */
102
+ export interface DetachedNodeData {
103
+ readonly detached: true;
104
+ readonly value: string | null;
105
+ }
106
+ /** Result of one read, selected by the mode discriminant. */
107
+ export type SemanticResult<Mode extends SemanticMode> = Mode extends {
108
+ kind: 'node';
109
+ } ? RawNodeData | DetachedNodeData : RawObservation;
110
+ /** Options for a single-node read, shared by `evaluate` and `evaluateAll` callers. */
111
+ interface NodeReadOptions {
112
+ readonly testIdAttribute: string;
113
+ readonly secureFieldSelector: string;
114
+ readonly mode: {
115
+ readonly kind: 'node';
116
+ };
117
+ }
118
+ /** Options for one document's tree walk. */
119
+ interface TreeReadOptions {
120
+ readonly testIdAttribute: string;
121
+ readonly secureFieldSelector: string;
122
+ readonly mode: Extract<SemanticMode, {
123
+ kind: 'tree';
124
+ }>;
125
+ }
126
+ /**
127
+ * Walks a whole document from its root element in one in-page call. Built
128
+ * from the reader's source like the batch reader below, so the caller
129
+ * evaluates it directly on a page or frame instead of first resolving a
130
+ * `:root` locator - one fewer protocol round trip per document per capture.
131
+ */
132
+ export declare const readDocumentSemanticsFunction: (options: TreeReadOptions) => RawObservation;
133
+ /**
134
+ * Reads every matched element in one in-page round trip. A page function
135
+ * cannot close over module scope, so the batch function is assembled from the
136
+ * reader's own source (the same source `evaluate` sends) and is a
137
+ * self-contained function Playwright serializes and calls with the elements.
138
+ */
139
+ export declare const readManySemanticsFunction: (elements: Element[], options: NodeReadOptions) => (RawNodeData | DetachedNodeData)[];
140
+ /**
141
+ * Reads every handle the caller already holds in one round trip, so what is
142
+ * read and what is later acted on are the same elements by construction rather
143
+ * than by a second lookup. Evaluated on the first handle so the read runs in
144
+ * the frame the handles belong to; `page.evaluate` would reject handles taken
145
+ * inside an iframe.
146
+ */
147
+ export declare const readHandlesSemanticsFunction: (first: Element, arg: {
148
+ elements: Element[];
149
+ options: NodeReadOptions;
150
+ }) => (RawNodeData | DetachedNodeData)[];
151
+ export {};
152
+ //# sourceMappingURL=read-node.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"read-node.d.ts","sourceRoot":"","sources":["../src/read-node.ts"],"names":[],"mappings":"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"}