@e2edev/web 0.11.0-canary-20260921180210

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 (101) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +5 -0
  3. package/README.md +112 -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 +76 -0
  10. package/dist/attempt-session.d.ts.map +1 -0
  11. package/dist/attempt-session.js +290 -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 +87 -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 +14 -0
  26. package/dist/cdp-selectors.d.ts.map +1 -0
  27. package/dist/cdp-selectors.js +48 -0
  28. package/dist/cdp-selectors.js.map +1 -0
  29. package/dist/dialogs.d.ts +37 -0
  30. package/dist/dialogs.d.ts.map +1 -0
  31. package/dist/dialogs.js +78 -0
  32. package/dist/dialogs.js.map +1 -0
  33. package/dist/engine.d.ts +26 -0
  34. package/dist/engine.d.ts.map +1 -0
  35. package/dist/engine.js +166 -0
  36. package/dist/engine.js.map +1 -0
  37. package/dist/evaluation.d.ts +11 -0
  38. package/dist/evaluation.d.ts.map +1 -0
  39. package/dist/evaluation.js +27 -0
  40. package/dist/evaluation.js.map +1 -0
  41. package/dist/index.d.ts +21 -0
  42. package/dist/index.d.ts.map +1 -0
  43. package/dist/index.js +14 -0
  44. package/dist/index.js.map +1 -0
  45. package/dist/install.d.ts +40 -0
  46. package/dist/install.d.ts.map +1 -0
  47. package/dist/install.js +117 -0
  48. package/dist/install.js.map +1 -0
  49. package/dist/locators.d.ts +74 -0
  50. package/dist/locators.d.ts.map +1 -0
  51. package/dist/locators.js +260 -0
  52. package/dist/locators.js.map +1 -0
  53. package/dist/observation-capture.d.ts +12 -0
  54. package/dist/observation-capture.d.ts.map +1 -0
  55. package/dist/observation-capture.js +93 -0
  56. package/dist/observation-capture.js.map +1 -0
  57. package/dist/observation.d.ts +63 -0
  58. package/dist/observation.d.ts.map +1 -0
  59. package/dist/observation.js +262 -0
  60. package/dist/observation.js.map +1 -0
  61. package/dist/observe.d.ts +51 -0
  62. package/dist/observe.d.ts.map +1 -0
  63. package/dist/observe.js +104 -0
  64. package/dist/observe.js.map +1 -0
  65. package/dist/operation-budget.d.ts +11 -0
  66. package/dist/operation-budget.d.ts.map +1 -0
  67. package/dist/operation-budget.js +40 -0
  68. package/dist/operation-budget.js.map +1 -0
  69. package/dist/protected-app.d.ts +32 -0
  70. package/dist/protected-app.d.ts.map +1 -0
  71. package/dist/protected-app.js +39 -0
  72. package/dist/protected-app.js.map +1 -0
  73. package/dist/read-node.d.ts +170 -0
  74. package/dist/read-node.d.ts.map +1 -0
  75. package/dist/read-node.js +823 -0
  76. package/dist/read-node.js.map +1 -0
  77. package/dist/refs.d.ts +43 -0
  78. package/dist/refs.d.ts.map +1 -0
  79. package/dist/refs.js +85 -0
  80. package/dist/refs.js.map +1 -0
  81. package/dist/route-pattern.d.ts +15 -0
  82. package/dist/route-pattern.d.ts.map +1 -0
  83. package/dist/route-pattern.js +68 -0
  84. package/dist/route-pattern.js.map +1 -0
  85. package/dist/support.d.ts +119 -0
  86. package/dist/support.d.ts.map +1 -0
  87. package/dist/support.js +299 -0
  88. package/dist/support.js.map +1 -0
  89. package/dist/surface.d.ts +257 -0
  90. package/dist/surface.d.ts.map +1 -0
  91. package/dist/surface.js +587 -0
  92. package/dist/surface.js.map +1 -0
  93. package/dist/video.d.ts +59 -0
  94. package/dist/video.d.ts.map +1 -0
  95. package/dist/video.js +115 -0
  96. package/dist/video.js.map +1 -0
  97. package/dist/web.d.ts +191 -0
  98. package/dist/web.d.ts.map +1 -0
  99. package/dist/web.js +354 -0
  100. package/dist/web.js.map +1 -0
  101. package/package.json +67 -0
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Semantic tree capture for one observation: the in-page walk, nested-document
3
+ * stitching, and element-handle bookkeeping the surface keeps per generation.
4
+ */
5
+ import type { ElementHandle, Frame } from 'playwright';
6
+ import { type NodeRef, type SemanticNode } from 'e2e/engine';
7
+ import { type RawNodeData } from './read-node.ts';
8
+ /**
9
+ * The id of every observation's root: the main document's element under one
10
+ * id the engine mints, stable across observations and navigations, so the
11
+ * harness can address the viewport (`perform(root, swipe)`) from an earlier
12
+ * observation. Outside the `n<number>` space stamped ids and located ids share.
13
+ */
14
+ export declare const ROOT_NODE_ID = "root";
15
+ /** A page or frame: anything one document's reader can be evaluated on. */
16
+ export type DocumentHost = Pick<Frame, 'evaluateHandle'>;
17
+ /** What one capture needs from the surface that owns the generation. */
18
+ export interface CaptureDeps {
19
+ readonly testIdAttribute: string;
20
+ /** The app's site; a child frame off it stays a boundary node. Undefined admits no child frame. */
21
+ readonly site: string | undefined;
22
+ /** Reserves a disjoint range before the reader can stamp any element, including on timeout. */
23
+ reserveIds(count: number): number;
24
+ /** Publishes one element handle under its id in the generation being built. */
25
+ commit(id: string, element: ElementHandle<Element>): void;
26
+ }
27
+ export interface CaptureOptions {
28
+ /** Enclosing frame selectors, outermost first; empty for the main document. */
29
+ readonly framePath: readonly string[];
30
+ /** Remaining node budget shared across every document of the observation. */
31
+ readonly budget: number;
32
+ /**
33
+ * Absolute time (epoch ms) by which the whole observation must be done.
34
+ * Every document's budget is derived from what remains of it, so the
35
+ * documents of one observation can never sum past the operation's budget.
36
+ */
37
+ readonly deadline: number;
38
+ readonly signal: AbortSignal;
39
+ }
40
+ /** One document's tree with what the capture knows about its completeness. */
41
+ export interface CapturedDocument {
42
+ readonly tree: SemanticNode;
43
+ /** Nodes captured across this document and every child document stitched in. */
44
+ readonly nodeCount: number;
45
+ /**
46
+ * True when nodes on screen are missing from `tree`: the node budget cut
47
+ * the walk short in this document or a child, or an on-site child frame's
48
+ * document was not read (no budget or time left, past the depth limit, or
49
+ * its capture failed). Off-site frames are left out by design and never
50
+ * count.
51
+ */
52
+ readonly truncated: boolean;
53
+ }
54
+ /**
55
+ * Captures one document's semantic tree, then descends into each observed
56
+ * iframe boundary node via its content frame and stitches the child
57
+ * document under it. Frame capture is best-effort: a detached or unloaded
58
+ * frame leaves its boundary node childless rather than failing the
59
+ * observation. The node budget is shared across all documents.
60
+ */
61
+ export declare function captureDocument(deps: CaptureDeps, host: DocumentHost, options: CaptureOptions): Promise<CapturedDocument>;
62
+ export declare function toSemanticNode(ref: NodeRef, raw: RawNodeData, children?: readonly SemanticNode[], framePath?: readonly string[]): SemanticNode;
63
+ //# sourceMappingURL=observation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"observation.d.ts","sourceRoot":"","sources":["../src/observation.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,KAAK,EAAY,MAAM,YAAY,CAAC;AACjE,OAAO,EAKL,KAAK,OAAO,EACZ,KAAK,YAAY,EAClB,MAAM,YAAY,CAAC;AACpB,OAAO,EAGL,KAAK,WAAW,EAEjB,MAAM,gBAAgB,CAAC;AAGxB;;;;;GAKG;AACH,eAAO,MAAM,YAAY,SAAS,CAAC;AAcnC,2EAA2E;AAC3E,MAAM,MAAM,YAAY,GAAG,IAAI,CAAC,KAAK,EAAE,gBAAgB,CAAC,CAAC;AAEzD,wEAAwE;AACxE,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,mGAAmG;IACnG,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,+FAA+F;IAC/F,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;IAClC,+EAA+E;IAC/E,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC;CAC3D;AAED,MAAM,WAAW,cAAc;IAC7B,+EAA+E;IAC/E,QAAQ,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,6EAA6E;IAC7E,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;CAC9B;AAED,8EAA8E;AAC9E,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAC5B,gFAAgF;IAChF,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B;;;;;;OAMG;IACH,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;CAC7B;AAKD;;;;;;GAMG;AACH,wBAAsB,eAAe,CACnC,IAAI,EAAE,WAAW,EACjB,IAAI,EAAE,YAAY,EAClB,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,gBAAgB,CAAC,CAoB3B;AAkMD,wBAAgB,cAAc,CAC5B,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,WAAW,EAChB,QAAQ,GAAE,SAAS,YAAY,EAAO,EACtC,SAAS,GAAE,SAAS,MAAM,EAAO,GAChC,YAAY,CAyBd"}
@@ -0,0 +1,262 @@
1
+ /**
2
+ * Semantic tree capture for one observation: the in-page walk, nested-document
3
+ * stitching, and element-handle bookkeeping the surface keeps per generation.
4
+ */
5
+ import { EngineError, sameSite, OBSERVED_NAME_LIMIT, OBSERVED_TEXT_LIMIT, } from 'e2e/engine';
6
+ import { readDocumentSemanticsFunction, SECURE_FIELD_SELECTOR, } from './read-node.js';
7
+ import { CaptureScope } from './capture-scope.js';
8
+ /**
9
+ * The id of every observation's root: the main document's element under one
10
+ * id the engine mints, stable across observations and navigations, so the
11
+ * harness can address the viewport (`perform(root, swipe)`) from an earlier
12
+ * observation. Outside the `n<number>` space stamped ids and located ids share.
13
+ */
14
+ export const ROOT_NODE_ID = 'root';
15
+ /** Nested iframe capture depth; deeper frames stay boundary nodes. */
16
+ const MAX_FRAME_DEPTH = 4;
17
+ /** Budget for capturing the main document, still capped by the observation deadline. */
18
+ const DOCUMENT_CAPTURE_TIMEOUT_MS = 15_000;
19
+ /**
20
+ * Budget for capturing one child document. A stalled frame (ads, trackers)
21
+ * must cost an observation a moment, not the context default timeout.
22
+ */
23
+ const FRAME_CAPTURE_TIMEOUT_MS = 3_000;
24
+ /**
25
+ * Captures one document's semantic tree, then descends into each observed
26
+ * iframe boundary node via its content frame and stitches the child
27
+ * document under it. Frame capture is best-effort: a detached or unloaded
28
+ * frame leaves its boundary node childless rather than failing the
29
+ * observation. The node budget is shared across all documents.
30
+ */
31
+ export async function captureDocument(deps, host, options) {
32
+ const { framePath, budget, signal } = options;
33
+ const cap = framePath.length === 0 ? DOCUMENT_CAPTURE_TIMEOUT_MS : FRAME_CAPTURE_TIMEOUT_MS;
34
+ const deadline = Math.min(options.deadline, Date.now() + cap);
35
+ const scope = new CaptureScope(deadline, signal);
36
+ // A child document's handles are published only once it captured whole; a
37
+ // frame that fails midway leaves no reachable ids behind.
38
+ const staged = [];
39
+ const stage = (id, element) => {
40
+ if (scope.own(element))
41
+ staged.push([id, element]);
42
+ };
43
+ return scope.run(async () => {
44
+ const captured = await captureInto(deps, scope, stage, host, framePath, budget, signal);
45
+ scope.check();
46
+ for (const [id, element] of staged) {
47
+ deps.commit(id, element);
48
+ scope.release(element);
49
+ }
50
+ return captured;
51
+ });
52
+ }
53
+ /** Reads one document and stages its child documents under the same capture owner. */
54
+ async function captureInto(deps, scope, stage, host, framePath, budget, signal) {
55
+ const captured = await scope.read(() => host.evaluateHandle(readDocumentSemanticsFunction, {
56
+ testIdAttribute: deps.testIdAttribute,
57
+ secureFieldSelector: SECURE_FIELD_SELECTOR,
58
+ mode: {
59
+ kind: 'tree',
60
+ maxNodes: budget,
61
+ idSeed: deps.reserveIds(budget),
62
+ nameLimit: OBSERVED_NAME_LIMIT,
63
+ textLimit: OBSERVED_TEXT_LIMIT,
64
+ },
65
+ }), (handle) => scope.own(handle));
66
+ // Property handles would keep earlier captures alive after their parent is disposed.
67
+ const { nodes, ids, truncated: walkTruncated } = await scope.read(() => captured.evaluate((observation) => ({
68
+ nodes: observation.nodes,
69
+ ids: observation.ids,
70
+ truncated: observation.truncated,
71
+ })));
72
+ if (!Array.isArray(ids) || ids.length !== nodes.length) {
73
+ throw new EngineError('ENGINE_FAILURE', 'observation ids do not align with its nodes', {
74
+ retryable: false,
75
+ });
76
+ }
77
+ // The main document's element is the observation root, under the minted
78
+ // id rather than the one stamped on it: a new document stamps a new
79
+ // number, the root's id must not change with it.
80
+ if (framePath.length === 0 && ids.length > 0)
81
+ ids[0] = ROOT_NODE_ID;
82
+ const elementsHandle = await scope.read(() => captured.getProperty('elements'), (handle) => scope.own(handle));
83
+ const elements = await collectElementHandles(scope, elementsHandle, nodes.length);
84
+ elements.forEach((element, index) => stage(ids[index], element));
85
+ let nodeCount = nodes.length;
86
+ let truncated = walkTruncated === true;
87
+ const frameChildren = new Map();
88
+ for (let index = 0; index < nodes.length; index += 1) {
89
+ const selector = nodes[index].frameSelector;
90
+ if (selector === undefined)
91
+ continue;
92
+ // A frame with no document (detached, never loaded) shows nothing, so
93
+ // nothing is missing from the tree.
94
+ const frame = await scope.read(() => elements[index].contentFrame().catch(() => null));
95
+ if (frame === null)
96
+ continue;
97
+ // Only frames on the app's site enter observations. Third-party
98
+ // frames (ads, trackers, embeds) are not the agent's to read or act
99
+ // on - and a stalled ad frame must not tax the capture. They stay
100
+ // boundary nodes by design, so leaving them out is not truncation.
101
+ if (!isOnSiteFrame(frame.url(), deps.site))
102
+ continue;
103
+ // From here the frame's document is content the model should see: any
104
+ // reason it is not read (depth, budget, deadline, a failed or timed-out
105
+ // capture) leaves the tree incomplete, and the snapshot must say so.
106
+ if (framePath.length >= MAX_FRAME_DEPTH) {
107
+ truncated = true;
108
+ continue;
109
+ }
110
+ const remaining = budget - nodeCount;
111
+ if (remaining <= 0 || Date.now() >= scope.deadline) {
112
+ truncated = true;
113
+ continue;
114
+ }
115
+ const child = await scope.read(() => captureDocument({ ...deps, commit: stage }, frame, {
116
+ framePath: [...framePath, selector],
117
+ budget: remaining,
118
+ deadline: scope.deadline,
119
+ signal,
120
+ }).catch(() => undefined));
121
+ if (child === undefined) {
122
+ truncated = true;
123
+ continue;
124
+ }
125
+ frameChildren.set(index, child.tree);
126
+ nodeCount += child.nodeCount;
127
+ truncated ||= child.truncated;
128
+ }
129
+ return { tree: assembleTree(nodes, ids, framePath, frameChildren), nodeCount, truncated };
130
+ }
131
+ /**
132
+ * True when a frame document is on the app's site.
133
+ *
134
+ * `about:blank` and `srcdoc` documents inherit their parent's origin, so they
135
+ * are the app's own content (consent managers, editors) and always allowed; the
136
+ * parent frame was already admitted to be captured at all.
137
+ *
138
+ * A `data:` document is *not* admitted, even though its bytes are written by the
139
+ * page that embeds it. It has an opaque origin rather than an inherited one, and
140
+ * navigation denies the scheme by name alongside `file:` and `javascript:`.
141
+ */
142
+ function isOnSiteFrame(url, site) {
143
+ if (url === '' || url === 'about:blank' || url === 'about:srcdoc')
144
+ return true;
145
+ if (site === undefined)
146
+ return false;
147
+ const protocol = URL.canParse(url) ? new URL(url).protocol : undefined;
148
+ return protocol !== 'data:' && sameSite(url, site);
149
+ }
150
+ /**
151
+ * Reads one element handle per observed node from the in-page element array.
152
+ * `asElement` types handles as `ElementHandle<Node>`, but the observation walk
153
+ * records `Element` nodes only, so the narrowing is safe by construction.
154
+ */
155
+ async function collectElementHandles(scope, elementsHandle, count) {
156
+ const properties = await scope.read(() => elementsHandle.getProperties(), (handles) => {
157
+ for (const handle of handles.values())
158
+ scope.own(handle);
159
+ });
160
+ const elements = [];
161
+ for (let index = 0; index < count; index += 1) {
162
+ const property = properties.get(String(index));
163
+ const element = (property?.asElement() ?? null);
164
+ if (element === null) {
165
+ // The in-page array outlived its document (a navigation committed while
166
+ // the handles were being read back). The capture is repeatable.
167
+ throw new EngineError('NODE_STALE', `observation node ${index} lost its element`, {
168
+ retryable: true,
169
+ });
170
+ }
171
+ elements.push(element);
172
+ }
173
+ return elements;
174
+ }
175
+ /**
176
+ * Rebuilds the observation tree from the depth-first node list. Descendants
177
+ * always follow their parent, so children are complete before a parent is
178
+ * built. Captured child documents attach under their iframe boundary nodes.
179
+ */
180
+ function assembleTree(nodes, ids, framePath, frameChildren) {
181
+ if (nodes.length === 0 || ids.length === 0) {
182
+ // An empty document is what a navigation in flight looks like; a real page
183
+ // always has nodes, so the capture is worth repeating.
184
+ throw new EngineError('NODE_STALE', 'observation produced no nodes', { retryable: true });
185
+ }
186
+ const childLists = nodes.map(() => []);
187
+ const built = [];
188
+ for (let index = nodes.length - 1; index >= 0; index -= 1) {
189
+ const raw = nodes[index];
190
+ const embedded = frameChildren.get(index);
191
+ // A child document measured its nodes against its own viewport. Shifted by
192
+ // the boundary element's box and clipped to it, every box in the tree is
193
+ // in the top-level viewport's CSS pixels, the space the screenshot and a
194
+ // point tap share, and a child that overflows its frame cannot claim a
195
+ // point over the page around it. The shift is the frame's border box; a
196
+ // bordered iframe is off by its border width, which is within a tap
197
+ // target. A frame under a CSS transform is not unwound: its boxes are
198
+ // where the untransformed frame would put them.
199
+ if (embedded !== undefined)
200
+ childLists[index].unshift(placeInFrame(embedded, raw.rect));
201
+ const node = toSemanticNode({ id: ids[index], revision: '' }, raw, childLists[index], framePath);
202
+ built[index] = node;
203
+ if (raw.parent >= 0)
204
+ childLists[raw.parent].unshift(node);
205
+ }
206
+ return built[0];
207
+ }
208
+ /** The tree with every box translated into the frame's space and clipped to its box; a box left empty by the clip is dropped. */
209
+ function placeInFrame(node, frame) {
210
+ const { rect, ...rest } = node;
211
+ const placed = rect === undefined ? undefined : clipRect(offsetRect(rect, frame), frame);
212
+ return {
213
+ ...rest,
214
+ ...(placed === undefined ? {} : { rect: placed }),
215
+ ...(node.children === undefined ? {} : { children: node.children.map((child) => placeInFrame(child, frame)) }),
216
+ };
217
+ }
218
+ function offsetRect(rect, by) {
219
+ return { x: rect.x + by.x, y: rect.y + by.y, width: rect.width, height: rect.height };
220
+ }
221
+ function clipRect(rect, bounds) {
222
+ const x = Math.max(rect.x, bounds.x);
223
+ const y = Math.max(rect.y, bounds.y);
224
+ const width = Math.min(rect.x + rect.width, bounds.x + bounds.width) - x;
225
+ const height = Math.min(rect.y + rect.height, bounds.y + bounds.height) - y;
226
+ return width > 0 && height > 0 ? { x, y, width, height } : undefined;
227
+ }
228
+ export function toSemanticNode(ref, raw, children = [], framePath = []) {
229
+ const states = {};
230
+ if (raw.states.checked !== null)
231
+ states['checked'] = raw.states.checked;
232
+ if (raw.states.disabled)
233
+ states['disabled'] = true;
234
+ if (raw.states.selected !== null)
235
+ states['selected'] = raw.states.selected;
236
+ if (raw.states.expanded !== null)
237
+ states['expanded'] = raw.states.expanded;
238
+ if (raw.states.pressed !== null)
239
+ states['pressed'] = raw.states.pressed;
240
+ if (raw.states.focused)
241
+ states['focused'] = true;
242
+ if (raw.states.hidden)
243
+ states['hidden'] = true;
244
+ if (raw.states.secure)
245
+ states['secure'] = true;
246
+ return {
247
+ ref,
248
+ ...(raw.role !== null ? { role: raw.role } : {}),
249
+ ...(raw.name !== null ? { name: raw.name } : {}),
250
+ ...(raw.text !== null ? { text: raw.text } : {}),
251
+ ...(raw.value !== null ? { value: raw.value } : {}),
252
+ ...(raw.testId !== null ? { testId: raw.testId } : {}),
253
+ inputPurpose: raw.inputPurpose,
254
+ states,
255
+ ...(raw.level !== null ? { level: raw.level } : {}),
256
+ attributes: raw.attributes,
257
+ rect: raw.rect,
258
+ ...(framePath.length > 0 ? { framePath } : {}),
259
+ ...(children.length > 0 ? { children } : {}),
260
+ };
261
+ }
262
+ //# sourceMappingURL=observation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"observation.js","sourceRoot":"","sources":["../src/observation.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EACL,WAAW,EACX,QAAQ,EACR,mBAAmB,EACnB,mBAAmB,GAGpB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,6BAA6B,EAC7B,qBAAqB,GAGtB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD;;;;;GAKG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,MAAM,CAAC;AAEnC,sEAAsE;AACtE,MAAM,eAAe,GAAG,CAAC,CAAC;AAE1B,wFAAwF;AACxF,MAAM,2BAA2B,GAAG,MAAM,CAAC;AAE3C;;;GAGG;AACH,MAAM,wBAAwB,GAAG,KAAK,CAAC;AAgDvC;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,IAAiB,EACjB,IAAkB,EAClB,OAAuB;IAEvB,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;IAC9C,MAAM,GAAG,GAAG,SAAS,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,2BAA2B,CAAC,CAAC,CAAC,wBAAwB,CAAC;IAC5F,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,GAAG,CAAC,CAAC;IAC9D,MAAM,KAAK,GAAG,IAAI,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IACjD,0EAA0E;IAC1E,0DAA0D;IAC1D,MAAM,MAAM,GAAgB,EAAE,CAAC;IAC/B,MAAM,KAAK,GAAG,CAAC,EAAU,EAAE,OAA+B,EAAQ,EAAE;QAClE,IAAI,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC;YAAE,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC;IACrD,CAAC,CAAC;IACF,OAAO,KAAK,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE;QAC1B,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;QACxF,KAAK,CAAC,KAAK,EAAE,CAAC;QACd,KAAK,MAAM,CAAC,EAAE,EAAE,OAAO,CAAC,IAAI,MAAM,EAAE,CAAC;YACnC,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;YACzB,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACzB,CAAC;QACD,OAAO,QAAQ,CAAC;IAClB,CAAC,CAAC,CAAC;AACL,CAAC;AAED,sFAAsF;AACtF,KAAK,UAAU,WAAW,CACxB,IAAiB,EACjB,KAAmB,EACnB,KAA4D,EAC5D,IAAkB,EAClB,SAA4B,EAC5B,MAAc,EACd,MAAmB;IAEnB,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC,6BAA6B,EAAE;QACzF,eAAe,EAAE,IAAI,CAAC,eAAe;QACrC,mBAAmB,EAAE,qBAAqB;QAC1C,IAAI,EAAE;YACJ,IAAI,EAAE,MAAe;YACrB,QAAQ,EAAE,MAAM;YAChB,MAAM,EAAE,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC;YAC/B,SAAS,EAAE,mBAAmB;YAC9B,SAAS,EAAE,mBAAmB;SAC/B;KACF,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;IACnC,qFAAqF;IACrF,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,aAAa,EAAE,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;QAC1G,KAAK,EAAE,WAAW,CAAC,KAAK;QACxB,GAAG,EAAE,WAAW,CAAC,GAAG;QACpB,SAAS,EAAE,WAAW,CAAC,SAAS;KACjC,CAAC,CAAC,CAAC,CAAC;IACL,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,MAAM,KAAK,KAAK,CAAC,MAAM,EAAE,CAAC;QACvD,MAAM,IAAI,WAAW,CAAC,gBAAgB,EAAE,6CAA6C,EAAE;YACrF,SAAS,EAAE,KAAK;SACjB,CAAC,CAAC;IACL,CAAC;IACD,wEAAwE;IACxE,oEAAoE;IACpE,iDAAiD;IACjD,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC;QAAE,GAAG,CAAC,CAAC,CAAC,GAAG,YAAY,CAAC;IACpE,MAAM,cAAc,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;IAC/G,MAAM,QAAQ,GAAG,MAAM,qBAAqB,CAAC,KAAK,EAAE,cAAc,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAClF,QAAQ,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAW,EAAE,OAAO,CAAC,CAAC,CAAC;IAC3E,IAAI,SAAS,GAAG,KAAK,CAAC,MAAM,CAAC;IAC7B,IAAI,SAAS,GAAG,aAAa,KAAK,IAAI,CAAC;IACvC,MAAM,aAAa,GAAG,IAAI,GAAG,EAAwB,CAAC;IACtD,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QACrD,MAAM,QAAQ,GAAG,KAAK,CAAC,KAAK,CAAE,CAAC,aAAa,CAAC;QAC7C,IAAI,QAAQ,KAAK,SAAS;YAAE,SAAS;QACrC,sEAAsE;QACtE,oCAAoC;QACpC,MAAM,KAAK,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAE,CAAC,YAAY,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;QACxF,IAAI,KAAK,KAAK,IAAI;YAAE,SAAS;QAC7B,gEAAgE;QAChE,oEAAoE;QACpE,kEAAkE;QAClE,mEAAmE;QACnE,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,GAAG,EAAE,EAAE,IAAI,CAAC,IAAI,CAAC;YAAE,SAAS;QACrD,sEAAsE;QACtE,wEAAwE;QACxE,qEAAqE;QACrE,IAAI,SAAS,CAAC,MAAM,IAAI,eAAe,EAAE,CAAC;YACxC,SAAS,GAAG,IAAI,CAAC;YACjB,SAAS;QACX,CAAC;QACD,MAAM,SAAS,GAAG,MAAM,GAAG,SAAS,CAAC;QACrC,IAAI,SAAS,IAAI,CAAC,IAAI,IAAI,CAAC,GAAG,EAAE,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;YACnD,SAAS,GAAG,IAAI,CAAC;YACjB,SAAS;QACX,CAAC;QACD,MAAM,KAAK,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,eAAe,CAAC,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE;YACtF,SAAS,EAAE,CAAC,GAAG,SAAS,EAAE,QAAQ,CAAC;YACnC,MAAM,EAAE,SAAS;YACjB,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,MAAM;SACP,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC;QAC3B,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,SAAS,GAAG,IAAI,CAAC;YACjB,SAAS;QACX,CAAC;QACD,aAAa,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QACrC,SAAS,IAAI,KAAK,CAAC,SAAS,CAAC;QAC7B,SAAS,KAAK,KAAK,CAAC,SAAS,CAAC;IAChC,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,YAAY,CAAC,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,aAAa,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC;AAC5F,CAAC;AAED;;;;;;;;;;GAUG;AACH,SAAS,aAAa,CAAC,GAAW,EAAE,IAAwB;IAC1D,IAAI,GAAG,KAAK,EAAE,IAAI,GAAG,KAAK,aAAa,IAAI,GAAG,KAAK,cAAc;QAAE,OAAO,IAAI,CAAC;IAC/E,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC;IACrC,MAAM,QAAQ,GAAG,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC;IACvE,OAAO,QAAQ,KAAK,OAAO,IAAI,QAAQ,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;AACrD,CAAC;AAED;;;;GAIG;AACH,KAAK,UAAU,qBAAqB,CAClC,KAAmB,EACnB,cAAwB,EACxB,KAAa;IAEb,MAAM,UAAU,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,cAAc,CAAC,aAAa,EAAE,EAAE,CAAC,OAAO,EAAE,EAAE;QACpF,KAAK,MAAM,MAAM,IAAI,OAAO,CAAC,MAAM,EAAE;YAAE,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAC3D,CAAC,CAAC,CAAC;IACH,MAAM,QAAQ,GAA6B,EAAE,CAAC;IAC9C,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,KAAK,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QAC9C,MAAM,QAAQ,GAAG,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QAC/C,MAAM,OAAO,GAAG,CAAC,QAAQ,EAAE,SAAS,EAAE,IAAI,IAAI,CAAkC,CAAC;QACjF,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;YACrB,wEAAwE;YACxE,gEAAgE;YAChE,MAAM,IAAI,WAAW,CAAC,YAAY,EAAE,oBAAoB,KAAK,mBAAmB,EAAE;gBAChF,SAAS,EAAE,IAAI;aAChB,CAAC,CAAC;QACL,CAAC;QACD,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACzB,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;;GAIG;AACH,SAAS,YAAY,CACnB,KAAiC,EACjC,GAAsB,EACtB,SAA4B,EAC5B,aAAgD;IAEhD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC3C,2EAA2E;QAC3E,uDAAuD;QACvD,MAAM,IAAI,WAAW,CAAC,YAAY,EAAE,+BAA+B,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5F,CAAC;IACD,MAAM,UAAU,GAAqB,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;IACzD,MAAM,KAAK,GAAmB,EAAE,CAAC;IACjC,KAAK,IAAI,KAAK,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QAC1D,MAAM,GAAG,GAAG,KAAK,CAAC,KAAK,CAAE,CAAC;QAC1B,MAAM,QAAQ,GAAG,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAC1C,2EAA2E;QAC3E,yEAAyE;QACzE,yEAAyE;QACzE,uEAAuE;QACvE,wEAAwE;QACxE,oEAAoE;QACpE,sEAAsE;QACtE,gDAAgD;QAChD,IAAI,QAAQ,KAAK,SAAS;YAAE,UAAU,CAAC,KAAK,CAAE,CAAC,OAAO,CAAC,YAAY,CAAC,QAAQ,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;QACzF,MAAM,IAAI,GAAG,cAAc,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC,KAAK,CAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,UAAU,CAAC,KAAK,CAAE,EAAE,SAAS,CAAC,CAAC;QACnG,KAAK,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC;QACpB,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC;YAAE,UAAU,CAAC,GAAG,CAAC,MAAM,CAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7D,CAAC;IACD,OAAO,KAAK,CAAC,CAAC,CAAE,CAAC;AACnB,CAAC;AAID,iIAAiI;AACjI,SAAS,YAAY,CAAC,IAAkB,EAAE,KAAW;IACnD,MAAM,EAAE,IAAI,EAAE,GAAG,IAAI,EAAE,GAAG,IAAI,CAAC;IAC/B,MAAM,MAAM,GAAG,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,KAAK,CAAC,CAAC;IACzF,OAAO;QACL,GAAG,IAAI;QACP,GAAG,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;QACjD,GAAG,CAAC,IAAI,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,YAAY,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC;KAC/G,CAAC;AACJ,CAAC;AAED,SAAS,UAAU,CAAC,IAAU,EAAE,EAAQ;IACtC,OAAO,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC;AACxF,CAAC;AAED,SAAS,QAAQ,CAAC,IAAU,EAAE,MAAY;IACxC,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;IACrC,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;IACrC,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACzE,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAC5E,OAAO,KAAK,GAAG,CAAC,IAAI,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;AACvE,CAAC;AAED,MAAM,UAAU,cAAc,CAC5B,GAAY,EACZ,GAAgB,EAChB,QAAQ,GAA4B,EAAE,EACtC,SAAS,GAAsB,EAAE;IAEjC,MAAM,MAAM,GAA4B,EAAE,CAAC;IAC3C,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO,KAAK,IAAI;QAAE,MAAM,CAAC,SAAS,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC;IACxE,IAAI,GAAG,CAAC,MAAM,CAAC,QAAQ;QAAE,MAAM,CAAC,UAAU,CAAC,GAAG,IAAI,CAAC;IACnD,IAAI,GAAG,CAAC,MAAM,CAAC,QAAQ,KAAK,IAAI;QAAE,MAAM,CAAC,UAAU,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC;IAC3E,IAAI,GAAG,CAAC,MAAM,CAAC,QAAQ,KAAK,IAAI;QAAE,MAAM,CAAC,UAAU,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC;IAC3E,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO,KAAK,IAAI;QAAE,MAAM,CAAC,SAAS,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC;IACxE,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO;QAAE,MAAM,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC;IACjD,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM;QAAE,MAAM,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC;IAC/C,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM;QAAE,MAAM,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC;IAC/C,OAAO;QACL,GAAG;QACH,GAAG,CAAC,GAAG,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAChD,GAAG,CAAC,GAAG,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAChD,GAAG,CAAC,GAAG,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAChD,GAAG,CAAC,GAAG,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACnD,GAAG,CAAC,GAAG,CAAC,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACtD,YAAY,EAAE,GAAG,CAAC,YAAY;QAC9B,MAAM;QACN,GAAG,CAAC,GAAG,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACnD,UAAU,EAAE,GAAG,CAAC,UAAU;QAC1B,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,GAAG,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC9C,GAAG,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC7C,CAAC;AACJ,CAAC"}
@@ -0,0 +1,51 @@
1
+ /** Masked pixel capture for an observation. */
2
+ import type { Locator, Page } from 'playwright';
3
+ import type { ObservationPixels, OperationContext, ViewportSize } from 'e2e/engine';
4
+ /**
5
+ * Two mask locators per frame Playwright can reach, covering every secure
6
+ * field: one through light DOM and open shadow roots, one through the closed
7
+ * roots the reader also walks. Sweeping every frame rather than only the
8
+ * frames an observation walked makes the masked set a superset of the observed
9
+ * secure set - the direction that is safe. Shared by the observation pixels
10
+ * and the artifact screenshot so both are redacted at the source by the same
11
+ * rule.
12
+ */
13
+ export declare function secureFieldMasks(page: Page): Locator[];
14
+ /** Screenshot options that apply the secure-field masks; empty when there is no frame to mask. */
15
+ export declare function maskOptions(masks: readonly Locator[]): Partial<{
16
+ mask: Locator[];
17
+ maskColor: string;
18
+ }>;
19
+ export interface PixelCapture {
20
+ readonly pixels: ObservationPixels;
21
+ readonly maskedRegionCount: number;
22
+ /** Every secure-field probe completed, independently of semantic capture. */
23
+ readonly maskingProven: boolean;
24
+ }
25
+ /**
26
+ * Captures masked viewport pixels.
27
+ *
28
+ * Secure fields are covered before the image leaves the engine and the covered
29
+ * regions are counted, so the runner can prove the image is at least as redacted
30
+ * as the tree (the runner's clearance check requires the masked set to be a
31
+ * superset of the observed secure set, which `secureFieldMasks` guarantees).
32
+ *
33
+ * `scale: 'css'` keeps the image in the CSS pixel space every observed node rect
34
+ * already uses, which is what lets the runner hit-test a point against the same
35
+ * tree.
36
+ */
37
+ export declare function capturePixels(page: Page, operation: OperationContext, viewport: ViewportSize): Promise<PixelCapture>;
38
+ /**
39
+ * Reads pixel dimensions out of PNG bytes.
40
+ *
41
+ * The dimensions reported with a screenshot must be the dimensions of the bytes
42
+ * the model actually receives: every coordinate it returns is relative to them,
43
+ * so a viewport value that disagrees with the capture displaces every point
44
+ * silently. PNG puts IHDR first, so width and height are at fixed offsets and no
45
+ * decoder is needed.
46
+ */
47
+ export declare function readPngSize(data: Uint8Array): {
48
+ width: number;
49
+ height: number;
50
+ } | null;
51
+ //# sourceMappingURL=observe.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"observe.d.ts","sourceRoot":"","sources":["../src/observe.ts"],"names":[],"mappings":"AAAA,+CAA+C;AAE/C,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,KAAK,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAepF;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,EAAE,CAOtD;AAED,kGAAkG;AAClG,wBAAgB,WAAW,CAAC,KAAK,EAAE,SAAS,OAAO,EAAE,GAAG,OAAO,CAAC;IAAE,IAAI,EAAE,OAAO,EAAE,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC,CAEtG;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAC;IACnC,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC,6EAA6E;IAC7E,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;CACjC;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,aAAa,CACjC,IAAI,EAAE,IAAI,EACV,SAAS,EAAE,gBAAgB,EAC3B,QAAQ,EAAE,YAAY,GACrB,OAAO,CAAC,YAAY,CAAC,CAkCvB;AAED;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,UAAU,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAStF"}
@@ -0,0 +1,104 @@
1
+ /** Masked pixel capture for an observation. */
2
+ import { CaptureScope } from './capture-scope.js';
3
+ import { CLOSED_SHADOW_SELECTOR_ENGINE, SECURE_FIELD_SELECTOR } from './read-node.js';
4
+ /**
5
+ * Budget for one masked screenshot, still capped by the operation timeout. A
6
+ * heavy page that cannot produce a frame promptly must cost the observation a
7
+ * moment, not the whole step: the caller degrades to tree-only input rather
8
+ * than failing.
9
+ */
10
+ const PIXEL_CAPTURE_TIMEOUT_MS = 10_000;
11
+ /** Opaque fill covering every masked region. */
12
+ const MASK_COLOR = '#000000';
13
+ /**
14
+ * Two mask locators per frame Playwright can reach, covering every secure
15
+ * field: one through light DOM and open shadow roots, one through the closed
16
+ * roots the reader also walks. Sweeping every frame rather than only the
17
+ * frames an observation walked makes the masked set a superset of the observed
18
+ * secure set - the direction that is safe. Shared by the observation pixels
19
+ * and the artifact screenshot so both are redacted at the source by the same
20
+ * rule.
21
+ */
22
+ export function secureFieldMasks(page) {
23
+ return page
24
+ .frames()
25
+ .flatMap((frame) => [
26
+ frame.locator(SECURE_FIELD_SELECTOR),
27
+ frame.locator(`${CLOSED_SHADOW_SELECTOR_ENGINE}=${SECURE_FIELD_SELECTOR}`),
28
+ ]);
29
+ }
30
+ /** Screenshot options that apply the secure-field masks; empty when there is no frame to mask. */
31
+ export function maskOptions(masks) {
32
+ return masks.length === 0 ? {} : { mask: [...masks], maskColor: MASK_COLOR };
33
+ }
34
+ /**
35
+ * Captures masked viewport pixels.
36
+ *
37
+ * Secure fields are covered before the image leaves the engine and the covered
38
+ * regions are counted, so the runner can prove the image is at least as redacted
39
+ * as the tree (the runner's clearance check requires the masked set to be a
40
+ * superset of the observed secure set, which `secureFieldMasks` guarantees).
41
+ *
42
+ * `scale: 'css'` keeps the image in the CSS pixel space every observed node rect
43
+ * already uses, which is what lets the runner hit-test a point against the same
44
+ * tree.
45
+ */
46
+ export async function capturePixels(page, operation, viewport) {
47
+ const deadline = Date.now() + operation.timeoutMs;
48
+ const scope = new CaptureScope(deadline, operation.signal);
49
+ return scope.run(async () => {
50
+ const masks = secureFieldMasks(page);
51
+ // A frame that detaches mid-sweep contributes nothing to the count, which can
52
+ // only push the observation toward withholding the image.
53
+ const counts = await scope.read(() => Promise.allSettled(masks.map((mask) => mask.count())));
54
+ const image = await scope.read(() => page.screenshot({
55
+ type: 'png',
56
+ scale: 'css',
57
+ animations: 'disabled',
58
+ caret: 'hide',
59
+ timeout: Math.max(1, Math.min(deadline - Date.now(), PIXEL_CAPTURE_TIMEOUT_MS)),
60
+ ...maskOptions(masks),
61
+ }));
62
+ const data = new Uint8Array(image);
63
+ // The bytes are the authority on their own size. `scale: 'css'` is asked for
64
+ // precisely so one image pixel is one CSS pixel, but the ratio is measured
65
+ // rather than assumed: if a capture ever comes back at device scale, reporting
66
+ // the viewport instead would displace every coordinate the model reads off it.
67
+ const size = readPngSize(data) ?? { width: viewport.width, height: viewport.height };
68
+ return {
69
+ pixels: {
70
+ data,
71
+ mediaType: 'image/png',
72
+ width: size.width,
73
+ height: size.height,
74
+ scale: viewport.width > 0 ? size.width / viewport.width : 1,
75
+ },
76
+ maskedRegionCount: counts.reduce((total, count) => total + (count.status === 'fulfilled' ? count.value : 0), 0),
77
+ maskingProven: masks.length > 0 && counts.every((count) => count.status === 'fulfilled'),
78
+ };
79
+ });
80
+ }
81
+ /**
82
+ * Reads pixel dimensions out of PNG bytes.
83
+ *
84
+ * The dimensions reported with a screenshot must be the dimensions of the bytes
85
+ * the model actually receives: every coordinate it returns is relative to them,
86
+ * so a viewport value that disagrees with the capture displaces every point
87
+ * silently. PNG puts IHDR first, so width and height are at fixed offsets and no
88
+ * decoder is needed.
89
+ */
90
+ export function readPngSize(data) {
91
+ if (data.byteLength < 24)
92
+ return null;
93
+ const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
94
+ if (view.getUint32(0) !== 0x89504e47 || view.getUint32(4) !== 0x0d0a1a0a)
95
+ return null;
96
+ if (view.getUint32(12) !== 0x49484452)
97
+ return null;
98
+ const width = view.getUint32(16);
99
+ const height = view.getUint32(20);
100
+ if (width === 0 || height === 0)
101
+ return null;
102
+ return { width, height };
103
+ }
104
+ //# sourceMappingURL=observe.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"observe.js","sourceRoot":"","sources":["../src/observe.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /** One deadline for connection recovery and the operation it precedes. */
2
+ import { EngineError } from 'e2e/engine';
3
+ export interface ConnectionBudget {
4
+ readonly timeoutMs: number;
5
+ readonly signal: AbortSignal;
6
+ }
7
+ /** Preserves the reason for an engine-owned deadline without relabeling caller cancellation. */
8
+ export declare function connectionAbort(signal: AbortSignal, label: string): EngineError;
9
+ /** Bounds the entire transition, aborts abandoned work, and never grants a fresh dispatch budget. */
10
+ export declare function withConnectionBudget<T>(budget: ConnectionBudget, label: string, work: (remaining: () => ConnectionBudget) => Promise<T>): Promise<T>;
11
+ //# sourceMappingURL=operation-budget.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"operation-budget.d.ts","sourceRoot":"","sources":["../src/operation-budget.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,OAAO,EAAE,WAAW,EAAa,MAAM,YAAY,CAAC;AAEpD,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;CAC9B;AAED,gGAAgG;AAChG,wBAAgB,eAAe,CAAC,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,GAAG,WAAW,CAI/E;AAED,qGAAqG;AACrG,wBAAsB,oBAAoB,CAAC,CAAC,EAC1C,MAAM,EAAE,gBAAgB,EACxB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,CAAC,SAAS,EAAE,MAAM,gBAAgB,KAAK,OAAO,CAAC,CAAC,CAAC,GACtD,OAAO,CAAC,CAAC,CAAC,CAwBZ"}
@@ -0,0 +1,40 @@
1
+ /** One deadline for connection recovery and the operation it precedes. */
2
+ import { EngineError, raceAbort } from 'e2e/engine';
3
+ /** Preserves the reason for an engine-owned deadline without relabeling caller cancellation. */
4
+ export function connectionAbort(signal, label) {
5
+ return signal.reason instanceof EngineError && signal.reason.code === 'OPERATION_TIMEOUT'
6
+ ? signal.reason
7
+ : new EngineError('CANCELLED', `${label} cancelled`, { retryable: false });
8
+ }
9
+ /** Bounds the entire transition, aborts abandoned work, and never grants a fresh dispatch budget. */
10
+ export async function withConnectionBudget(budget, label, work) {
11
+ const controller = new AbortController();
12
+ const signal = AbortSignal.any([budget.signal, controller.signal]);
13
+ const endsAt = Date.now() + budget.timeoutMs;
14
+ const timeout = () => new EngineError('OPERATION_TIMEOUT', `${label} timed out`, { retryable: false });
15
+ const timer = setTimeout(() => controller.abort(timeout()), Math.max(0, budget.timeoutMs));
16
+ const remaining = () => {
17
+ if (signal.aborted)
18
+ throw connectionAbort(signal, label);
19
+ const timeoutMs = endsAt - Date.now();
20
+ if (timeoutMs <= 0) {
21
+ controller.abort(timeout());
22
+ throw connectionAbort(signal, label);
23
+ }
24
+ return { signal, timeoutMs };
25
+ };
26
+ try {
27
+ return await raceAbort(() => work(remaining), signal, label);
28
+ }
29
+ catch (cause) {
30
+ if (budget.signal.aborted)
31
+ throw connectionAbort(budget.signal, label);
32
+ if (signal.aborted)
33
+ throw connectionAbort(signal, label);
34
+ throw cause;
35
+ }
36
+ finally {
37
+ clearTimeout(timer);
38
+ }
39
+ }
40
+ //# sourceMappingURL=operation-budget.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"operation-budget.js","sourceRoot":"","sources":["../src/operation-budget.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAOpD,gGAAgG;AAChG,MAAM,UAAU,eAAe,CAAC,MAAmB,EAAE,KAAa;IAChE,OAAO,MAAM,CAAC,MAAM,YAAY,WAAW,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,KAAK,mBAAmB;QACvF,CAAC,CAAC,MAAM,CAAC,MAAM;QACf,CAAC,CAAC,IAAI,WAAW,CAAC,WAAW,EAAE,GAAG,KAAK,YAAY,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC;AAC/E,CAAC;AAED,qGAAqG;AACrG,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,MAAwB,EACxB,KAAa,EACb,IAAuD;IAEvD,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,MAAM,MAAM,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC;IACnE,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC,SAAS,CAAC;IAC7C,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC,IAAI,WAAW,CAAC,mBAAmB,EAAE,GAAG,KAAK,YAAY,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC;IACvG,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC;IAC3F,MAAM,SAAS,GAAG,GAAqB,EAAE;QACvC,IAAI,MAAM,CAAC,OAAO;YAAE,MAAM,eAAe,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;QACzD,MAAM,SAAS,GAAG,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACtC,IAAI,SAAS,IAAI,CAAC,EAAE,CAAC;YACnB,UAAU,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;YAC5B,MAAM,eAAe,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;QACvC,CAAC;QACD,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;IAC/B,CAAC,CAAC;IACF,IAAI,CAAC;QACH,OAAO,MAAM,SAAS,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;IAC/D,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,MAAM,CAAC,MAAM,CAAC,OAAO;YAAE,MAAM,eAAe,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;QACvE,IAAI,MAAM,CAAC,OAAO;YAAE,MAAM,eAAe,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;QACzD,MAAM,KAAK,CAAC;IACd,CAAC;YAAS,CAAC;QACT,YAAY,CAAC,KAAK,CAAC,CAAC;IACtB,CAAC;AACH,CAAC"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Protected-preview access, scoped to the app's site: the configured headers
3
+ * ride only requests bound for the site, and basic-auth credentials answer
4
+ * a challenge wherever one is issued. The surface calls these on every
5
+ * context it creates; nothing here holds state.
6
+ */
7
+ import type { BrowserContext } from 'playwright';
8
+ import type { WebBasicAuth } from './surface.ts';
9
+ /** The credentials Playwright answers an HTTP authentication challenge with. */
10
+ export interface PlaywrightHttpCredential {
11
+ readonly username: string;
12
+ readonly password: string;
13
+ }
14
+ /** Header names lowercased, as Playwright reports a request's own headers. */
15
+ export declare function lowercaseNames(headers: Readonly<Record<string, string>>): Readonly<Record<string, string>>;
16
+ /**
17
+ * Adds the configured headers to every request bound for the app's site,
18
+ * via a context route that falls back to the network. A request for any
19
+ * other site is not routed at all; without a site there is no policy and
20
+ * nothing is routed. Nothing awaits a route handler, so a fallback that
21
+ * fails (the page closed under the request) is dropped rather than left to
22
+ * surface as an unhandled rejection.
23
+ */
24
+ export declare function installSiteHeaders(context: BrowserContext, site: string | undefined, headers: Readonly<Record<string, string>> | undefined): Promise<void>;
25
+ /**
26
+ * The basic-auth credentials a context answers a challenge with, as
27
+ * Playwright's own `httpCredentials` does: on a 401 from any origin. A site
28
+ * cannot be enumerated into the exact origins Playwright scopes by, and a
29
+ * challenge is answered only where one is issued.
30
+ */
31
+ export declare function httpCredentials(basicAuth: WebBasicAuth | undefined): PlaywrightHttpCredential | undefined;
32
+ //# sourceMappingURL=protected-app.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protected-app.d.ts","sourceRoot":"","sources":["../src/protected-app.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAEjD,gFAAgF;AAChF,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,8EAA8E;AAC9E,wBAAgB,cAAc,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAE1G;AAED;;;;;;;GAOG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,cAAc,EACvB,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,SAAS,GACpD,OAAO,CAAC,IAAI,CAAC,CAQf;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,YAAY,GAAG,SAAS,GAAG,wBAAwB,GAAG,SAAS,CAIzG"}