@opensteer/browser-core 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/index.cjs +2914 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +1135 -0
- package/dist/index.d.ts +1135 -0
- package/dist/index.js +2846 -0
- package/dist/index.js.map +1 -0
- package/package.json +38 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,2846 @@
|
|
|
1
|
+
// src/brand.ts
|
|
2
|
+
function brand(value) {
|
|
3
|
+
return value;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
// src/identity.ts
|
|
7
|
+
function normalizeRef(prefix, value) {
|
|
8
|
+
const trimmed = value.trim();
|
|
9
|
+
if (trimmed.length === 0) {
|
|
10
|
+
throw new TypeError(`${prefix} reference cannot be empty`);
|
|
11
|
+
}
|
|
12
|
+
const canonicalPrefix = `${prefix}:`;
|
|
13
|
+
if (trimmed.startsWith(canonicalPrefix)) {
|
|
14
|
+
if (trimmed.length === canonicalPrefix.length) {
|
|
15
|
+
throw new TypeError(`${prefix} reference must include an identifier`);
|
|
16
|
+
}
|
|
17
|
+
return trimmed;
|
|
18
|
+
}
|
|
19
|
+
if (trimmed.includes(":")) {
|
|
20
|
+
throw new TypeError(
|
|
21
|
+
`${prefix} reference "${trimmed}" must either omit a prefix or use ${canonicalPrefix}`
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
return `${canonicalPrefix}${trimmed}`;
|
|
25
|
+
}
|
|
26
|
+
function hasPrefix(prefix, value) {
|
|
27
|
+
return value.startsWith(`${prefix}:`) && value.length > prefix.length + 1;
|
|
28
|
+
}
|
|
29
|
+
function createStringRef(prefix, value) {
|
|
30
|
+
return brand(normalizeRef(prefix, value));
|
|
31
|
+
}
|
|
32
|
+
function createSessionRef(value) {
|
|
33
|
+
return createStringRef("session", value);
|
|
34
|
+
}
|
|
35
|
+
function createPageRef(value) {
|
|
36
|
+
return createStringRef("page", value);
|
|
37
|
+
}
|
|
38
|
+
function createFrameRef(value) {
|
|
39
|
+
return createStringRef("frame", value);
|
|
40
|
+
}
|
|
41
|
+
function createDocumentRef(value) {
|
|
42
|
+
return createStringRef("document", value);
|
|
43
|
+
}
|
|
44
|
+
function createNodeRef(value) {
|
|
45
|
+
return createStringRef("node", value);
|
|
46
|
+
}
|
|
47
|
+
function createNetworkRequestId(value) {
|
|
48
|
+
return createStringRef("request", value);
|
|
49
|
+
}
|
|
50
|
+
function createDownloadRef(value) {
|
|
51
|
+
return createStringRef("download", value);
|
|
52
|
+
}
|
|
53
|
+
function createDialogRef(value) {
|
|
54
|
+
return createStringRef("dialog", value);
|
|
55
|
+
}
|
|
56
|
+
function createChooserRef(value) {
|
|
57
|
+
return createStringRef("chooser", value);
|
|
58
|
+
}
|
|
59
|
+
function createWorkerRef(value) {
|
|
60
|
+
return createStringRef("worker", value);
|
|
61
|
+
}
|
|
62
|
+
function isSessionRef(value) {
|
|
63
|
+
return hasPrefix("session", value);
|
|
64
|
+
}
|
|
65
|
+
function isPageRef(value) {
|
|
66
|
+
return hasPrefix("page", value);
|
|
67
|
+
}
|
|
68
|
+
function isFrameRef(value) {
|
|
69
|
+
return hasPrefix("frame", value);
|
|
70
|
+
}
|
|
71
|
+
function isDocumentRef(value) {
|
|
72
|
+
return hasPrefix("document", value);
|
|
73
|
+
}
|
|
74
|
+
function isNodeRef(value) {
|
|
75
|
+
return hasPrefix("node", value);
|
|
76
|
+
}
|
|
77
|
+
function isNetworkRequestId(value) {
|
|
78
|
+
return hasPrefix("request", value);
|
|
79
|
+
}
|
|
80
|
+
function isDownloadRef(value) {
|
|
81
|
+
return hasPrefix("download", value);
|
|
82
|
+
}
|
|
83
|
+
function isDialogRef(value) {
|
|
84
|
+
return hasPrefix("dialog", value);
|
|
85
|
+
}
|
|
86
|
+
function isChooserRef(value) {
|
|
87
|
+
return hasPrefix("chooser", value);
|
|
88
|
+
}
|
|
89
|
+
function isWorkerRef(value) {
|
|
90
|
+
return hasPrefix("worker", value);
|
|
91
|
+
}
|
|
92
|
+
function serializeRef(ref) {
|
|
93
|
+
return ref;
|
|
94
|
+
}
|
|
95
|
+
function createDocumentEpoch(value) {
|
|
96
|
+
if (!Number.isInteger(value) || value < 0) {
|
|
97
|
+
throw new RangeError(
|
|
98
|
+
`document epoch must be a non-negative integer, received ${String(value)}`
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
return brand(value);
|
|
102
|
+
}
|
|
103
|
+
function nextDocumentEpoch(epoch) {
|
|
104
|
+
return createDocumentEpoch(epoch + 1);
|
|
105
|
+
}
|
|
106
|
+
function serializeDocumentEpoch(epoch) {
|
|
107
|
+
return epoch;
|
|
108
|
+
}
|
|
109
|
+
function createNodeLocator(documentRef, documentEpoch, nodeRef) {
|
|
110
|
+
return { documentRef, documentEpoch, nodeRef };
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// src/geometry.ts
|
|
114
|
+
function assertFinite(value, name) {
|
|
115
|
+
if (!Number.isFinite(value)) {
|
|
116
|
+
throw new TypeError(`${name} must be a finite number`);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
function assertNonNegative(value, name) {
|
|
120
|
+
assertFinite(value, name);
|
|
121
|
+
if (value < 0) {
|
|
122
|
+
throw new RangeError(`${name} must be greater than or equal to 0`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
function createScale(value, name) {
|
|
126
|
+
if (!Number.isFinite(value) || value <= 0) {
|
|
127
|
+
throw new RangeError(`${name} must be greater than 0`);
|
|
128
|
+
}
|
|
129
|
+
return brand(value);
|
|
130
|
+
}
|
|
131
|
+
function createPoint(x, y) {
|
|
132
|
+
assertFinite(x, "point.x");
|
|
133
|
+
assertFinite(y, "point.y");
|
|
134
|
+
return { x, y };
|
|
135
|
+
}
|
|
136
|
+
function createSize(width, height) {
|
|
137
|
+
assertNonNegative(width, "size.width");
|
|
138
|
+
assertNonNegative(height, "size.height");
|
|
139
|
+
return { width, height };
|
|
140
|
+
}
|
|
141
|
+
function createRect(x, y, width, height) {
|
|
142
|
+
assertFinite(x, "rect.x");
|
|
143
|
+
assertFinite(y, "rect.y");
|
|
144
|
+
assertNonNegative(width, "rect.width");
|
|
145
|
+
assertNonNegative(height, "rect.height");
|
|
146
|
+
return { x, y, width, height };
|
|
147
|
+
}
|
|
148
|
+
function createScrollOffset(x, y) {
|
|
149
|
+
assertFinite(x, "scrollOffset.x");
|
|
150
|
+
assertFinite(y, "scrollOffset.y");
|
|
151
|
+
return { x, y };
|
|
152
|
+
}
|
|
153
|
+
function createQuad(points) {
|
|
154
|
+
return points;
|
|
155
|
+
}
|
|
156
|
+
function rectToQuad(rect) {
|
|
157
|
+
return createQuad([
|
|
158
|
+
createPoint(rect.x, rect.y),
|
|
159
|
+
createPoint(rect.x + rect.width, rect.y),
|
|
160
|
+
createPoint(rect.x + rect.width, rect.y + rect.height),
|
|
161
|
+
createPoint(rect.x, rect.y + rect.height)
|
|
162
|
+
]);
|
|
163
|
+
}
|
|
164
|
+
function quadBounds(quad) {
|
|
165
|
+
const xs = quad.map((point) => point.x);
|
|
166
|
+
const ys = quad.map((point) => point.y);
|
|
167
|
+
const minX = Math.min(...xs);
|
|
168
|
+
const maxX = Math.max(...xs);
|
|
169
|
+
const minY = Math.min(...ys);
|
|
170
|
+
const maxY = Math.max(...ys);
|
|
171
|
+
return createRect(minX, minY, maxX - minX, maxY - minY);
|
|
172
|
+
}
|
|
173
|
+
function rectContainsPoint(rect, point) {
|
|
174
|
+
return point.x >= rect.x && point.x <= rect.x + rect.width && point.y >= rect.y && point.y <= rect.y + rect.height;
|
|
175
|
+
}
|
|
176
|
+
function createDevicePixelRatio(value) {
|
|
177
|
+
return createScale(value, "devicePixelRatio");
|
|
178
|
+
}
|
|
179
|
+
function createPageScaleFactor(value) {
|
|
180
|
+
return createScale(value, "pageScaleFactor");
|
|
181
|
+
}
|
|
182
|
+
function createPageZoomFactor(value) {
|
|
183
|
+
return createScale(value, "pageZoomFactor");
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// src/network.ts
|
|
187
|
+
function createHeaderEntry(name, value) {
|
|
188
|
+
return { name, value };
|
|
189
|
+
}
|
|
190
|
+
function createBodyPayload(bytes, options = {}) {
|
|
191
|
+
return {
|
|
192
|
+
bytes,
|
|
193
|
+
encoding: options.encoding ?? "identity",
|
|
194
|
+
truncated: options.truncated ?? false,
|
|
195
|
+
capturedByteLength: bytes.byteLength,
|
|
196
|
+
...options.mimeType === void 0 ? {} : { mimeType: options.mimeType },
|
|
197
|
+
...options.charset === void 0 ? {} : { charset: options.charset },
|
|
198
|
+
...options.originalByteLength === void 0 ? {} : { originalByteLength: options.originalByteLength }
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
function bodyPayloadFromUtf8(value, options = {}) {
|
|
202
|
+
return createBodyPayload(new TextEncoder().encode(value), {
|
|
203
|
+
...options.mimeType === void 0 ? {} : { mimeType: options.mimeType },
|
|
204
|
+
...options.encoding === void 0 ? {} : { encoding: options.encoding },
|
|
205
|
+
...options.truncated === void 0 ? {} : { truncated: options.truncated },
|
|
206
|
+
...options.originalByteLength === void 0 ? {} : { originalByteLength: options.originalByteLength },
|
|
207
|
+
charset: "utf-8"
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
function matchesNetworkRecordFilters(record, filters) {
|
|
211
|
+
if (filters.url !== void 0 && !includesCaseInsensitive(record.url, filters.url)) {
|
|
212
|
+
return false;
|
|
213
|
+
}
|
|
214
|
+
let parsedUrl;
|
|
215
|
+
const getParsedUrl = () => {
|
|
216
|
+
parsedUrl ??= new URL(record.url);
|
|
217
|
+
return parsedUrl;
|
|
218
|
+
};
|
|
219
|
+
if (filters.hostname !== void 0) {
|
|
220
|
+
const hostname = getParsedUrl().hostname;
|
|
221
|
+
if (!includesCaseInsensitive(hostname, filters.hostname)) {
|
|
222
|
+
return false;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
if (filters.path !== void 0) {
|
|
226
|
+
const path = getParsedUrl().pathname;
|
|
227
|
+
if (!includesCaseInsensitive(path, filters.path)) {
|
|
228
|
+
return false;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
if (filters.method !== void 0 && !includesCaseInsensitive(record.method, filters.method)) {
|
|
232
|
+
return false;
|
|
233
|
+
}
|
|
234
|
+
if (filters.status !== void 0 && !includesCaseInsensitive(
|
|
235
|
+
record.status === void 0 ? "" : String(record.status),
|
|
236
|
+
filters.status
|
|
237
|
+
)) {
|
|
238
|
+
return false;
|
|
239
|
+
}
|
|
240
|
+
if (filters.resourceType !== void 0 && record.resourceType !== filters.resourceType) {
|
|
241
|
+
return false;
|
|
242
|
+
}
|
|
243
|
+
return true;
|
|
244
|
+
}
|
|
245
|
+
function includesCaseInsensitive(value, query) {
|
|
246
|
+
return value.toLowerCase().includes(query.toLowerCase());
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// src/snapshots.ts
|
|
250
|
+
function findDomSnapshotNode(snapshot, snapshotNodeId) {
|
|
251
|
+
return snapshot.nodes.find((node) => node.snapshotNodeId === snapshotNodeId);
|
|
252
|
+
}
|
|
253
|
+
function findDomSnapshotNodeByRef(snapshot, nodeRef) {
|
|
254
|
+
return snapshot.nodes.find((node) => node.nodeRef === nodeRef);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// src/storage.ts
|
|
258
|
+
function parseUrl(value) {
|
|
259
|
+
try {
|
|
260
|
+
return new URL(value);
|
|
261
|
+
} catch {
|
|
262
|
+
return null;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
function isLocalHostname(hostname) {
|
|
266
|
+
return hostname === "localhost" || hostname.endsWith(".localhost");
|
|
267
|
+
}
|
|
268
|
+
function normalizeCookiePath(path) {
|
|
269
|
+
if (path.length === 0) {
|
|
270
|
+
return "/";
|
|
271
|
+
}
|
|
272
|
+
return path.startsWith("/") ? path : `/${path}`;
|
|
273
|
+
}
|
|
274
|
+
function pathMatchesCookiePath(requestPath, cookiePath) {
|
|
275
|
+
const normalizedRequestPath = requestPath.length === 0 ? "/" : requestPath;
|
|
276
|
+
const normalizedCookiePath = normalizeCookiePath(cookiePath);
|
|
277
|
+
if (normalizedRequestPath === normalizedCookiePath) {
|
|
278
|
+
return true;
|
|
279
|
+
}
|
|
280
|
+
if (!normalizedRequestPath.startsWith(normalizedCookiePath)) {
|
|
281
|
+
return false;
|
|
282
|
+
}
|
|
283
|
+
if (normalizedCookiePath.endsWith("/")) {
|
|
284
|
+
return true;
|
|
285
|
+
}
|
|
286
|
+
return normalizedRequestPath.charAt(normalizedCookiePath.length) === "/";
|
|
287
|
+
}
|
|
288
|
+
function filterCookieRecords(cookies, urls) {
|
|
289
|
+
const parsed = urls.map(parseUrl).filter((url) => url !== null);
|
|
290
|
+
if (parsed.length === 0) {
|
|
291
|
+
return [...cookies];
|
|
292
|
+
}
|
|
293
|
+
return cookies.filter((cookie) => {
|
|
294
|
+
return parsed.some((url) => {
|
|
295
|
+
let domain = cookie.domain;
|
|
296
|
+
if (!domain.startsWith(".")) {
|
|
297
|
+
domain = `.${domain}`;
|
|
298
|
+
}
|
|
299
|
+
if (!`.${url.hostname}`.endsWith(domain)) {
|
|
300
|
+
return false;
|
|
301
|
+
}
|
|
302
|
+
if (!pathMatchesCookiePath(url.pathname, cookie.path)) {
|
|
303
|
+
return false;
|
|
304
|
+
}
|
|
305
|
+
if (url.protocol !== "https:" && !isLocalHostname(url.hostname) && cookie.secure) {
|
|
306
|
+
return false;
|
|
307
|
+
}
|
|
308
|
+
return true;
|
|
309
|
+
});
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// src/capabilities.ts
|
|
314
|
+
function noBrowserCapabilities() {
|
|
315
|
+
return {
|
|
316
|
+
executor: {
|
|
317
|
+
sessionLifecycle: false,
|
|
318
|
+
pageLifecycle: false,
|
|
319
|
+
navigation: false,
|
|
320
|
+
pointerInput: false,
|
|
321
|
+
keyboardInput: false,
|
|
322
|
+
touchInput: false,
|
|
323
|
+
screenshots: false,
|
|
324
|
+
executionControl: {
|
|
325
|
+
pause: false,
|
|
326
|
+
resume: false,
|
|
327
|
+
freeze: false
|
|
328
|
+
}
|
|
329
|
+
},
|
|
330
|
+
inspector: {
|
|
331
|
+
pageEnumeration: false,
|
|
332
|
+
frameEnumeration: false,
|
|
333
|
+
html: false,
|
|
334
|
+
domSnapshot: false,
|
|
335
|
+
visualStability: false,
|
|
336
|
+
text: false,
|
|
337
|
+
attributes: false,
|
|
338
|
+
hitTest: false,
|
|
339
|
+
viewportMetrics: false,
|
|
340
|
+
network: false,
|
|
341
|
+
networkBodies: false,
|
|
342
|
+
cookies: false,
|
|
343
|
+
localStorage: false,
|
|
344
|
+
sessionStorage: false,
|
|
345
|
+
indexedDb: false
|
|
346
|
+
},
|
|
347
|
+
transport: {
|
|
348
|
+
sessionHttp: false
|
|
349
|
+
},
|
|
350
|
+
instrumentation: {
|
|
351
|
+
initScripts: false,
|
|
352
|
+
routing: false
|
|
353
|
+
},
|
|
354
|
+
events: {
|
|
355
|
+
pageLifecycle: false,
|
|
356
|
+
dialog: false,
|
|
357
|
+
download: false,
|
|
358
|
+
chooser: false,
|
|
359
|
+
worker: false,
|
|
360
|
+
console: false,
|
|
361
|
+
pageError: false,
|
|
362
|
+
websocket: false,
|
|
363
|
+
eventStream: false,
|
|
364
|
+
executionState: false
|
|
365
|
+
}
|
|
366
|
+
};
|
|
367
|
+
}
|
|
368
|
+
function allBrowserCapabilities() {
|
|
369
|
+
return mergeBrowserCapabilities(noBrowserCapabilities(), {
|
|
370
|
+
executor: {
|
|
371
|
+
sessionLifecycle: true,
|
|
372
|
+
pageLifecycle: true,
|
|
373
|
+
navigation: true,
|
|
374
|
+
pointerInput: true,
|
|
375
|
+
keyboardInput: true,
|
|
376
|
+
touchInput: true,
|
|
377
|
+
screenshots: true,
|
|
378
|
+
executionControl: {
|
|
379
|
+
pause: true,
|
|
380
|
+
resume: true,
|
|
381
|
+
freeze: true
|
|
382
|
+
}
|
|
383
|
+
},
|
|
384
|
+
inspector: {
|
|
385
|
+
pageEnumeration: true,
|
|
386
|
+
frameEnumeration: true,
|
|
387
|
+
html: true,
|
|
388
|
+
domSnapshot: true,
|
|
389
|
+
visualStability: true,
|
|
390
|
+
text: true,
|
|
391
|
+
attributes: true,
|
|
392
|
+
hitTest: true,
|
|
393
|
+
viewportMetrics: true,
|
|
394
|
+
network: true,
|
|
395
|
+
networkBodies: true,
|
|
396
|
+
cookies: true,
|
|
397
|
+
localStorage: true,
|
|
398
|
+
sessionStorage: true,
|
|
399
|
+
indexedDb: true
|
|
400
|
+
},
|
|
401
|
+
transport: {
|
|
402
|
+
sessionHttp: true
|
|
403
|
+
},
|
|
404
|
+
instrumentation: {
|
|
405
|
+
initScripts: true,
|
|
406
|
+
routing: true
|
|
407
|
+
},
|
|
408
|
+
events: {
|
|
409
|
+
pageLifecycle: true,
|
|
410
|
+
dialog: true,
|
|
411
|
+
download: true,
|
|
412
|
+
chooser: true,
|
|
413
|
+
worker: true,
|
|
414
|
+
console: true,
|
|
415
|
+
pageError: true,
|
|
416
|
+
websocket: true,
|
|
417
|
+
eventStream: true,
|
|
418
|
+
executionState: true
|
|
419
|
+
}
|
|
420
|
+
});
|
|
421
|
+
}
|
|
422
|
+
function mergeBrowserCapabilities(base, override) {
|
|
423
|
+
return {
|
|
424
|
+
executor: {
|
|
425
|
+
...base.executor,
|
|
426
|
+
...override.executor,
|
|
427
|
+
executionControl: {
|
|
428
|
+
...base.executor.executionControl,
|
|
429
|
+
...override.executor?.executionControl
|
|
430
|
+
}
|
|
431
|
+
},
|
|
432
|
+
inspector: {
|
|
433
|
+
...base.inspector,
|
|
434
|
+
...override.inspector
|
|
435
|
+
},
|
|
436
|
+
transport: {
|
|
437
|
+
...base.transport,
|
|
438
|
+
...override.transport
|
|
439
|
+
},
|
|
440
|
+
instrumentation: {
|
|
441
|
+
...base.instrumentation,
|
|
442
|
+
...override.instrumentation
|
|
443
|
+
},
|
|
444
|
+
events: {
|
|
445
|
+
...base.events,
|
|
446
|
+
...override.events
|
|
447
|
+
}
|
|
448
|
+
};
|
|
449
|
+
}
|
|
450
|
+
function hasCapability(capabilities, path) {
|
|
451
|
+
switch (path) {
|
|
452
|
+
case "executor.sessionLifecycle":
|
|
453
|
+
return capabilities.executor.sessionLifecycle;
|
|
454
|
+
case "executor.pageLifecycle":
|
|
455
|
+
return capabilities.executor.pageLifecycle;
|
|
456
|
+
case "executor.navigation":
|
|
457
|
+
return capabilities.executor.navigation;
|
|
458
|
+
case "executor.pointerInput":
|
|
459
|
+
return capabilities.executor.pointerInput;
|
|
460
|
+
case "executor.keyboardInput":
|
|
461
|
+
return capabilities.executor.keyboardInput;
|
|
462
|
+
case "executor.touchInput":
|
|
463
|
+
return capabilities.executor.touchInput;
|
|
464
|
+
case "executor.screenshots":
|
|
465
|
+
return capabilities.executor.screenshots;
|
|
466
|
+
case "executor.executionControl.pause":
|
|
467
|
+
return capabilities.executor.executionControl.pause;
|
|
468
|
+
case "executor.executionControl.resume":
|
|
469
|
+
return capabilities.executor.executionControl.resume;
|
|
470
|
+
case "executor.executionControl.freeze":
|
|
471
|
+
return capabilities.executor.executionControl.freeze;
|
|
472
|
+
case "inspector.pageEnumeration":
|
|
473
|
+
return capabilities.inspector.pageEnumeration;
|
|
474
|
+
case "inspector.frameEnumeration":
|
|
475
|
+
return capabilities.inspector.frameEnumeration;
|
|
476
|
+
case "inspector.html":
|
|
477
|
+
return capabilities.inspector.html;
|
|
478
|
+
case "inspector.domSnapshot":
|
|
479
|
+
return capabilities.inspector.domSnapshot;
|
|
480
|
+
case "inspector.visualStability":
|
|
481
|
+
return capabilities.inspector.visualStability;
|
|
482
|
+
case "inspector.text":
|
|
483
|
+
return capabilities.inspector.text;
|
|
484
|
+
case "inspector.attributes":
|
|
485
|
+
return capabilities.inspector.attributes;
|
|
486
|
+
case "inspector.hitTest":
|
|
487
|
+
return capabilities.inspector.hitTest;
|
|
488
|
+
case "inspector.viewportMetrics":
|
|
489
|
+
return capabilities.inspector.viewportMetrics;
|
|
490
|
+
case "inspector.network":
|
|
491
|
+
return capabilities.inspector.network;
|
|
492
|
+
case "inspector.networkBodies":
|
|
493
|
+
return capabilities.inspector.networkBodies;
|
|
494
|
+
case "inspector.cookies":
|
|
495
|
+
return capabilities.inspector.cookies;
|
|
496
|
+
case "inspector.localStorage":
|
|
497
|
+
return capabilities.inspector.localStorage;
|
|
498
|
+
case "inspector.sessionStorage":
|
|
499
|
+
return capabilities.inspector.sessionStorage;
|
|
500
|
+
case "inspector.indexedDb":
|
|
501
|
+
return capabilities.inspector.indexedDb;
|
|
502
|
+
case "transport.sessionHttp":
|
|
503
|
+
return capabilities.transport.sessionHttp;
|
|
504
|
+
case "instrumentation.initScripts":
|
|
505
|
+
return capabilities.instrumentation.initScripts;
|
|
506
|
+
case "instrumentation.routing":
|
|
507
|
+
return capabilities.instrumentation.routing;
|
|
508
|
+
case "events.pageLifecycle":
|
|
509
|
+
return capabilities.events.pageLifecycle;
|
|
510
|
+
case "events.dialog":
|
|
511
|
+
return capabilities.events.dialog;
|
|
512
|
+
case "events.download":
|
|
513
|
+
return capabilities.events.download;
|
|
514
|
+
case "events.chooser":
|
|
515
|
+
return capabilities.events.chooser;
|
|
516
|
+
case "events.worker":
|
|
517
|
+
return capabilities.events.worker;
|
|
518
|
+
case "events.console":
|
|
519
|
+
return capabilities.events.console;
|
|
520
|
+
case "events.pageError":
|
|
521
|
+
return capabilities.events.pageError;
|
|
522
|
+
case "events.websocket":
|
|
523
|
+
return capabilities.events.websocket;
|
|
524
|
+
case "events.eventStream":
|
|
525
|
+
return capabilities.events.eventStream;
|
|
526
|
+
case "events.executionState":
|
|
527
|
+
return capabilities.events.executionState;
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
// src/errors.ts
|
|
532
|
+
var BrowserCoreError = class extends Error {
|
|
533
|
+
code;
|
|
534
|
+
retriable;
|
|
535
|
+
capability;
|
|
536
|
+
details;
|
|
537
|
+
constructor(code, message, options = {}) {
|
|
538
|
+
super(message, { cause: options.cause });
|
|
539
|
+
this.name = "BrowserCoreError";
|
|
540
|
+
this.code = code;
|
|
541
|
+
this.retriable = options.retriable ?? false;
|
|
542
|
+
this.capability = options.capability;
|
|
543
|
+
this.details = options.details;
|
|
544
|
+
}
|
|
545
|
+
};
|
|
546
|
+
function isBrowserCoreError(value) {
|
|
547
|
+
return value instanceof BrowserCoreError;
|
|
548
|
+
}
|
|
549
|
+
function createBrowserCoreError(code, message, options = {}) {
|
|
550
|
+
return new BrowserCoreError(code, message, options);
|
|
551
|
+
}
|
|
552
|
+
function unsupportedCapabilityError(capability) {
|
|
553
|
+
return new BrowserCoreError(
|
|
554
|
+
"unsupported-capability",
|
|
555
|
+
`capability ${capability} is not supported by this backend`,
|
|
556
|
+
{
|
|
557
|
+
capability,
|
|
558
|
+
details: { capability }
|
|
559
|
+
}
|
|
560
|
+
);
|
|
561
|
+
}
|
|
562
|
+
function staleNodeRefError(input) {
|
|
563
|
+
return new BrowserCoreError(
|
|
564
|
+
"stale-node-ref",
|
|
565
|
+
`node ${input.nodeRef} is stale for ${input.documentRef} at epoch ${input.documentEpoch}`,
|
|
566
|
+
{
|
|
567
|
+
details: {
|
|
568
|
+
nodeRef: input.nodeRef,
|
|
569
|
+
documentRef: input.documentRef,
|
|
570
|
+
documentEpoch: input.documentEpoch
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
);
|
|
574
|
+
}
|
|
575
|
+
function closedSessionError(sessionRef) {
|
|
576
|
+
return new BrowserCoreError("session-closed", `session ${sessionRef} is closed`, {
|
|
577
|
+
details: { sessionRef }
|
|
578
|
+
});
|
|
579
|
+
}
|
|
580
|
+
function closedPageError(pageRef) {
|
|
581
|
+
return new BrowserCoreError("page-closed", `page ${pageRef} is closed`, {
|
|
582
|
+
details: { pageRef }
|
|
583
|
+
});
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
// src/fake-engine.ts
|
|
587
|
+
function clone(value) {
|
|
588
|
+
return structuredClone(value);
|
|
589
|
+
}
|
|
590
|
+
function titleFromUrl(url) {
|
|
591
|
+
try {
|
|
592
|
+
const parsed = new URL(url);
|
|
593
|
+
if (parsed.hostname.length === 0) {
|
|
594
|
+
return url;
|
|
595
|
+
}
|
|
596
|
+
return parsed.hostname;
|
|
597
|
+
} catch {
|
|
598
|
+
return url;
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
function buildTransportKey(request) {
|
|
602
|
+
return `${request.method.toUpperCase()} ${request.url}`;
|
|
603
|
+
}
|
|
604
|
+
function stripFragment(url) {
|
|
605
|
+
const hashIndex = url.indexOf("#");
|
|
606
|
+
return hashIndex === -1 ? url : url.slice(0, hashIndex);
|
|
607
|
+
}
|
|
608
|
+
function originFromUrl(url) {
|
|
609
|
+
try {
|
|
610
|
+
return new URL(url).origin;
|
|
611
|
+
} catch {
|
|
612
|
+
return void 0;
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
var FakeBrowserCoreEngine = class {
|
|
616
|
+
capabilities;
|
|
617
|
+
sessions = /* @__PURE__ */ new Map();
|
|
618
|
+
pages = /* @__PURE__ */ new Map();
|
|
619
|
+
frames = /* @__PURE__ */ new Map();
|
|
620
|
+
documents = /* @__PURE__ */ new Map();
|
|
621
|
+
retiredDocuments = /* @__PURE__ */ new Set();
|
|
622
|
+
pageCounter = 0;
|
|
623
|
+
frameCounter = 0;
|
|
624
|
+
documentCounter = 0;
|
|
625
|
+
nodeCounter = 0;
|
|
626
|
+
requestCounter = 0;
|
|
627
|
+
sessionCounter = 0;
|
|
628
|
+
stepCounter = 0;
|
|
629
|
+
eventCounter = 0;
|
|
630
|
+
timestampMs;
|
|
631
|
+
constructor(options = {}) {
|
|
632
|
+
this.capabilities = options.capabilities ?? allBrowserCapabilities();
|
|
633
|
+
this.timestampMs = options.timestampSeedMs ?? 17e11;
|
|
634
|
+
if (options.initialPages && options.initialPages.length > 0) {
|
|
635
|
+
const sessionRef = createSessionRef(`seed-${++this.sessionCounter}`);
|
|
636
|
+
const storage = this.createDefaultStorage(sessionRef);
|
|
637
|
+
this.sessions.set(sessionRef, {
|
|
638
|
+
sessionRef,
|
|
639
|
+
pageRefs: /* @__PURE__ */ new Set(),
|
|
640
|
+
cookies: [],
|
|
641
|
+
storage,
|
|
642
|
+
transportResponses: /* @__PURE__ */ new Map()
|
|
643
|
+
});
|
|
644
|
+
for (const page of options.initialPages) {
|
|
645
|
+
void this.createPageInternal(sessionRef, {
|
|
646
|
+
...page.url === void 0 ? {} : { url: page.url },
|
|
647
|
+
...page.title === void 0 ? {} : { title: page.title },
|
|
648
|
+
...page.viewportSize === void 0 ? {} : { viewportSize: page.viewportSize }
|
|
649
|
+
});
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
enqueueStepEvents(pageRef, events) {
|
|
654
|
+
const page = this.requirePage(pageRef);
|
|
655
|
+
for (const event of events) {
|
|
656
|
+
this.assertEventCapability(event.kind);
|
|
657
|
+
page.queuedEvents.push(clone(event));
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
advanceDocumentEpoch(documentRef) {
|
|
661
|
+
const document = this.requireDocument(documentRef);
|
|
662
|
+
const nextEpoch = nextDocumentEpoch(document.documentEpoch);
|
|
663
|
+
this.rebuildDocumentState(documentRef, {
|
|
664
|
+
documentRef,
|
|
665
|
+
documentEpoch: nextEpoch,
|
|
666
|
+
url: document.url,
|
|
667
|
+
title: titleFromUrl(document.url)
|
|
668
|
+
});
|
|
669
|
+
return nextEpoch;
|
|
670
|
+
}
|
|
671
|
+
seedCookies(sessionRef, cookies) {
|
|
672
|
+
const session = this.requireSession(sessionRef);
|
|
673
|
+
session.cookies = cookies.map((cookie) => clone(cookie));
|
|
674
|
+
}
|
|
675
|
+
seedTransportResponse(sessionRef, request, response) {
|
|
676
|
+
const session = this.requireSession(sessionRef);
|
|
677
|
+
session.transportResponses.set(buildTransportKey(request), clone(response));
|
|
678
|
+
}
|
|
679
|
+
async addInitScript(input) {
|
|
680
|
+
if (!hasCapability(this.capabilities, "instrumentation.initScripts")) {
|
|
681
|
+
throw unsupportedCapabilityError("instrumentation.initScripts");
|
|
682
|
+
}
|
|
683
|
+
this.requireSession(input.sessionRef);
|
|
684
|
+
return {
|
|
685
|
+
registrationId: `fake-init-script-${String(++this.stepCounter)}`,
|
|
686
|
+
sessionRef: input.sessionRef,
|
|
687
|
+
...input.pageRef === void 0 ? {} : { pageRef: input.pageRef }
|
|
688
|
+
};
|
|
689
|
+
}
|
|
690
|
+
async registerRoute(input) {
|
|
691
|
+
if (!hasCapability(this.capabilities, "instrumentation.routing")) {
|
|
692
|
+
throw unsupportedCapabilityError("instrumentation.routing");
|
|
693
|
+
}
|
|
694
|
+
this.requireSession(input.sessionRef);
|
|
695
|
+
return {
|
|
696
|
+
routeId: `fake-route-${String(++this.stepCounter)}`,
|
|
697
|
+
sessionRef: input.sessionRef,
|
|
698
|
+
...input.pageRef === void 0 ? {} : { pageRef: input.pageRef },
|
|
699
|
+
urlPattern: input.urlPattern
|
|
700
|
+
};
|
|
701
|
+
}
|
|
702
|
+
async createSession() {
|
|
703
|
+
this.requireCapability("executor.sessionLifecycle");
|
|
704
|
+
const sessionRef = createSessionRef(`fake-${++this.sessionCounter}`);
|
|
705
|
+
this.sessions.set(sessionRef, {
|
|
706
|
+
sessionRef,
|
|
707
|
+
pageRefs: /* @__PURE__ */ new Set(),
|
|
708
|
+
cookies: [],
|
|
709
|
+
storage: this.createDefaultStorage(sessionRef),
|
|
710
|
+
transportResponses: /* @__PURE__ */ new Map()
|
|
711
|
+
});
|
|
712
|
+
return sessionRef;
|
|
713
|
+
}
|
|
714
|
+
async closeSession(input) {
|
|
715
|
+
this.requireCapability("executor.sessionLifecycle");
|
|
716
|
+
const session = this.requireSession(input.sessionRef);
|
|
717
|
+
for (const pageRef of session.pageRefs) {
|
|
718
|
+
this.destroyPage(pageRef);
|
|
719
|
+
}
|
|
720
|
+
this.sessions.delete(input.sessionRef);
|
|
721
|
+
}
|
|
722
|
+
async createPage(input) {
|
|
723
|
+
this.requireCapability("executor.pageLifecycle");
|
|
724
|
+
const session = this.requireSession(input.sessionRef);
|
|
725
|
+
const page = this.createPageInternal(session.sessionRef, {
|
|
726
|
+
...input.openerPageRef === void 0 ? {} : { openerPageRef: input.openerPageRef },
|
|
727
|
+
...input.url === void 0 ? {} : { url: input.url }
|
|
728
|
+
});
|
|
729
|
+
const events = [];
|
|
730
|
+
const pageCreatedEvent = this.maybeCreateEvent({
|
|
731
|
+
kind: "page-created",
|
|
732
|
+
sessionRef: session.sessionRef,
|
|
733
|
+
pageRef: page.pageInfo.pageRef
|
|
734
|
+
});
|
|
735
|
+
if (pageCreatedEvent) {
|
|
736
|
+
events.push(pageCreatedEvent);
|
|
737
|
+
}
|
|
738
|
+
if (input.openerPageRef) {
|
|
739
|
+
const popupOpenedEvent = this.maybeCreateEvent({
|
|
740
|
+
kind: "popup-opened",
|
|
741
|
+
sessionRef: session.sessionRef,
|
|
742
|
+
pageRef: page.pageInfo.pageRef,
|
|
743
|
+
openerPageRef: input.openerPageRef
|
|
744
|
+
});
|
|
745
|
+
if (popupOpenedEvent) {
|
|
746
|
+
events.push(popupOpenedEvent);
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
return this.createStepResult(session.sessionRef, page.pageInfo.pageRef, {
|
|
750
|
+
frameRef: page.frameInfo.frameRef,
|
|
751
|
+
documentRef: page.frameInfo.documentRef,
|
|
752
|
+
documentEpoch: page.frameInfo.documentEpoch,
|
|
753
|
+
events,
|
|
754
|
+
data: clone(page.pageInfo)
|
|
755
|
+
});
|
|
756
|
+
}
|
|
757
|
+
async closePage(input) {
|
|
758
|
+
this.requireCapability("executor.pageLifecycle");
|
|
759
|
+
const page = this.requirePage(input.pageRef);
|
|
760
|
+
const frameInfo = this.getMainFrameInfo(page.pageRef);
|
|
761
|
+
const sessionRef = page.sessionRef;
|
|
762
|
+
this.destroyPage(page.pageRef);
|
|
763
|
+
const pageClosedEvent = this.maybeCreateEvent({
|
|
764
|
+
kind: "page-closed",
|
|
765
|
+
sessionRef,
|
|
766
|
+
pageRef: page.pageRef
|
|
767
|
+
});
|
|
768
|
+
return this.createStepResult(sessionRef, page.pageRef, {
|
|
769
|
+
frameRef: frameInfo.frameRef,
|
|
770
|
+
documentRef: frameInfo.documentRef,
|
|
771
|
+
documentEpoch: frameInfo.documentEpoch,
|
|
772
|
+
events: pageClosedEvent ? [pageClosedEvent] : [],
|
|
773
|
+
data: void 0
|
|
774
|
+
});
|
|
775
|
+
}
|
|
776
|
+
async activatePage(input) {
|
|
777
|
+
this.requireCapability("executor.pageLifecycle");
|
|
778
|
+
const page = this.requirePage(input.pageRef);
|
|
779
|
+
const mainFrame = this.getMainFrameInfo(page.pageRef);
|
|
780
|
+
return this.createStepResult(page.sessionRef, page.pageRef, {
|
|
781
|
+
frameRef: mainFrame.frameRef,
|
|
782
|
+
documentRef: mainFrame.documentRef,
|
|
783
|
+
documentEpoch: mainFrame.documentEpoch,
|
|
784
|
+
events: this.drainQueuedEvents(page.pageRef),
|
|
785
|
+
data: clone(this.pageInfoFromState(page))
|
|
786
|
+
});
|
|
787
|
+
}
|
|
788
|
+
async navigate(input) {
|
|
789
|
+
return this.performNavigation(input.pageRef, input.url, {
|
|
790
|
+
forceNewDocument: false,
|
|
791
|
+
recordHistory: true,
|
|
792
|
+
...input.referrer === void 0 ? {} : { referrer: input.referrer }
|
|
793
|
+
});
|
|
794
|
+
}
|
|
795
|
+
async reload(input) {
|
|
796
|
+
const page = this.requirePage(input.pageRef);
|
|
797
|
+
const pageInfo = this.pageInfoFromState(page);
|
|
798
|
+
return this.performNavigation(input.pageRef, pageInfo.url, {
|
|
799
|
+
forceNewDocument: true,
|
|
800
|
+
recordHistory: false
|
|
801
|
+
});
|
|
802
|
+
}
|
|
803
|
+
async goBack(input) {
|
|
804
|
+
this.requireCapability("executor.navigation");
|
|
805
|
+
const page = this.requirePage(input.pageRef);
|
|
806
|
+
const mainFrame = this.getMainFrameInfo(page.pageRef);
|
|
807
|
+
if (page.historyIndex === 0) {
|
|
808
|
+
return this.createStepResult(page.sessionRef, page.pageRef, {
|
|
809
|
+
frameRef: mainFrame.frameRef,
|
|
810
|
+
documentRef: mainFrame.documentRef,
|
|
811
|
+
documentEpoch: mainFrame.documentEpoch,
|
|
812
|
+
events: this.drainQueuedEvents(page.pageRef),
|
|
813
|
+
data: false
|
|
814
|
+
});
|
|
815
|
+
}
|
|
816
|
+
page.historyIndex -= 1;
|
|
817
|
+
const url = page.history[page.historyIndex];
|
|
818
|
+
const result = await this.performNavigation(input.pageRef, url, {
|
|
819
|
+
forceNewDocument: false,
|
|
820
|
+
recordHistory: false
|
|
821
|
+
});
|
|
822
|
+
return {
|
|
823
|
+
...result,
|
|
824
|
+
data: true
|
|
825
|
+
};
|
|
826
|
+
}
|
|
827
|
+
async goForward(input) {
|
|
828
|
+
this.requireCapability("executor.navigation");
|
|
829
|
+
const page = this.requirePage(input.pageRef);
|
|
830
|
+
const mainFrame = this.getMainFrameInfo(page.pageRef);
|
|
831
|
+
if (page.historyIndex >= page.history.length - 1) {
|
|
832
|
+
return this.createStepResult(page.sessionRef, page.pageRef, {
|
|
833
|
+
frameRef: mainFrame.frameRef,
|
|
834
|
+
documentRef: mainFrame.documentRef,
|
|
835
|
+
documentEpoch: mainFrame.documentEpoch,
|
|
836
|
+
events: this.drainQueuedEvents(page.pageRef),
|
|
837
|
+
data: false
|
|
838
|
+
});
|
|
839
|
+
}
|
|
840
|
+
page.historyIndex += 1;
|
|
841
|
+
const url = page.history[page.historyIndex];
|
|
842
|
+
const result = await this.performNavigation(input.pageRef, url, {
|
|
843
|
+
forceNewDocument: false,
|
|
844
|
+
recordHistory: false
|
|
845
|
+
});
|
|
846
|
+
return {
|
|
847
|
+
...result,
|
|
848
|
+
data: true
|
|
849
|
+
};
|
|
850
|
+
}
|
|
851
|
+
async stopLoading(input) {
|
|
852
|
+
this.requireCapability("executor.navigation");
|
|
853
|
+
const page = this.requirePage(input.pageRef);
|
|
854
|
+
const mainFrame = this.getMainFrameInfo(page.pageRef);
|
|
855
|
+
return this.createStepResult(page.sessionRef, page.pageRef, {
|
|
856
|
+
frameRef: mainFrame.frameRef,
|
|
857
|
+
documentRef: mainFrame.documentRef,
|
|
858
|
+
documentEpoch: mainFrame.documentEpoch,
|
|
859
|
+
events: this.drainQueuedEvents(page.pageRef),
|
|
860
|
+
data: void 0
|
|
861
|
+
});
|
|
862
|
+
}
|
|
863
|
+
async mouseMove(input) {
|
|
864
|
+
this.requireCapability("executor.pointerInput");
|
|
865
|
+
const page = this.requirePage(input.pageRef);
|
|
866
|
+
const mainFrame = this.getMainFrameInfo(page.pageRef);
|
|
867
|
+
return this.createStepResult(page.sessionRef, page.pageRef, {
|
|
868
|
+
frameRef: mainFrame.frameRef,
|
|
869
|
+
documentRef: mainFrame.documentRef,
|
|
870
|
+
documentEpoch: mainFrame.documentEpoch,
|
|
871
|
+
events: this.drainQueuedEvents(page.pageRef),
|
|
872
|
+
data: void 0
|
|
873
|
+
});
|
|
874
|
+
}
|
|
875
|
+
async mouseClick(input) {
|
|
876
|
+
this.requireCapability("executor.pointerInput");
|
|
877
|
+
const page = this.requirePage(input.pageRef);
|
|
878
|
+
const hitTest = await this.hitTest({
|
|
879
|
+
pageRef: input.pageRef,
|
|
880
|
+
point: input.point,
|
|
881
|
+
coordinateSpace: input.coordinateSpace
|
|
882
|
+
});
|
|
883
|
+
const mainFrame = this.getMainFrameInfo(page.pageRef);
|
|
884
|
+
return this.createStepResult(page.sessionRef, page.pageRef, {
|
|
885
|
+
frameRef: mainFrame.frameRef,
|
|
886
|
+
documentRef: mainFrame.documentRef,
|
|
887
|
+
documentEpoch: mainFrame.documentEpoch,
|
|
888
|
+
events: this.drainQueuedEvents(page.pageRef),
|
|
889
|
+
data: hitTest
|
|
890
|
+
});
|
|
891
|
+
}
|
|
892
|
+
async mouseScroll(input) {
|
|
893
|
+
this.requireCapability("executor.pointerInput");
|
|
894
|
+
const page = this.requirePage(input.pageRef);
|
|
895
|
+
const mainFrame = this.getMainFrame(page.pageRef);
|
|
896
|
+
const nextScroll = createScrollOffset(
|
|
897
|
+
page.viewportMetrics.scrollOffset.x + input.delta.x,
|
|
898
|
+
page.viewportMetrics.scrollOffset.y + input.delta.y
|
|
899
|
+
);
|
|
900
|
+
page.viewportMetrics = {
|
|
901
|
+
...page.viewportMetrics,
|
|
902
|
+
scrollOffset: nextScroll,
|
|
903
|
+
layoutViewport: {
|
|
904
|
+
...page.viewportMetrics.layoutViewport,
|
|
905
|
+
origin: createPoint(nextScroll.x, nextScroll.y)
|
|
906
|
+
},
|
|
907
|
+
visualViewport: {
|
|
908
|
+
...page.viewportMetrics.visualViewport,
|
|
909
|
+
origin: createPoint(nextScroll.x, nextScroll.y)
|
|
910
|
+
}
|
|
911
|
+
};
|
|
912
|
+
this.rebuildDocumentState(mainFrame.frameInfo.documentRef, {
|
|
913
|
+
documentRef: mainFrame.frameInfo.documentRef,
|
|
914
|
+
documentEpoch: mainFrame.frameInfo.documentEpoch,
|
|
915
|
+
url: mainFrame.frameInfo.url,
|
|
916
|
+
title: titleFromUrl(mainFrame.frameInfo.url)
|
|
917
|
+
});
|
|
918
|
+
return this.createStepResult(page.sessionRef, page.pageRef, {
|
|
919
|
+
frameRef: mainFrame.frameInfo.frameRef,
|
|
920
|
+
documentRef: mainFrame.frameInfo.documentRef,
|
|
921
|
+
documentEpoch: mainFrame.frameInfo.documentEpoch,
|
|
922
|
+
events: this.drainQueuedEvents(page.pageRef),
|
|
923
|
+
data: void 0
|
|
924
|
+
});
|
|
925
|
+
}
|
|
926
|
+
async keyPress(input) {
|
|
927
|
+
this.requireCapability("executor.keyboardInput");
|
|
928
|
+
const page = this.requirePage(input.pageRef);
|
|
929
|
+
const mainFrame = this.getMainFrameInfo(page.pageRef);
|
|
930
|
+
return this.createStepResult(page.sessionRef, page.pageRef, {
|
|
931
|
+
frameRef: mainFrame.frameRef,
|
|
932
|
+
documentRef: mainFrame.documentRef,
|
|
933
|
+
documentEpoch: mainFrame.documentEpoch,
|
|
934
|
+
events: this.drainQueuedEvents(page.pageRef),
|
|
935
|
+
data: void 0
|
|
936
|
+
});
|
|
937
|
+
}
|
|
938
|
+
async textInput(input) {
|
|
939
|
+
this.requireCapability("executor.keyboardInput");
|
|
940
|
+
const page = this.requirePage(input.pageRef);
|
|
941
|
+
const mainFrame = this.getMainFrameInfo(page.pageRef);
|
|
942
|
+
return this.createStepResult(page.sessionRef, page.pageRef, {
|
|
943
|
+
frameRef: mainFrame.frameRef,
|
|
944
|
+
documentRef: mainFrame.documentRef,
|
|
945
|
+
documentEpoch: mainFrame.documentEpoch,
|
|
946
|
+
events: this.drainQueuedEvents(page.pageRef),
|
|
947
|
+
data: void 0
|
|
948
|
+
});
|
|
949
|
+
}
|
|
950
|
+
async captureScreenshot(input) {
|
|
951
|
+
this.requireCapability("executor.screenshots");
|
|
952
|
+
const page = this.requirePage(input.pageRef);
|
|
953
|
+
const mainFrame = this.getMainFrameInfo(page.pageRef);
|
|
954
|
+
const targetSize = input.fullPage ? page.viewportMetrics.contentSize : page.viewportMetrics.visualViewport.size;
|
|
955
|
+
const payload = bodyPayloadFromUtf8(
|
|
956
|
+
JSON.stringify({
|
|
957
|
+
pageRef: page.pageRef,
|
|
958
|
+
url: mainFrame.url,
|
|
959
|
+
format: input.format ?? "webp",
|
|
960
|
+
includeCursor: input.includeCursor ?? false
|
|
961
|
+
}),
|
|
962
|
+
{ mimeType: `image/${input.format ?? "webp"}` }
|
|
963
|
+
);
|
|
964
|
+
const artifact = {
|
|
965
|
+
pageRef: page.pageRef,
|
|
966
|
+
frameRef: mainFrame.frameRef,
|
|
967
|
+
documentRef: mainFrame.documentRef,
|
|
968
|
+
documentEpoch: mainFrame.documentEpoch,
|
|
969
|
+
payload,
|
|
970
|
+
format: input.format ?? "webp",
|
|
971
|
+
size: targetSize,
|
|
972
|
+
coordinateSpace: input.clipSpace ?? "layout-viewport-css",
|
|
973
|
+
...input.clip === void 0 ? {} : { clip: input.clip }
|
|
974
|
+
};
|
|
975
|
+
return this.createStepResult(page.sessionRef, page.pageRef, {
|
|
976
|
+
frameRef: mainFrame.frameRef,
|
|
977
|
+
documentRef: mainFrame.documentRef,
|
|
978
|
+
documentEpoch: mainFrame.documentEpoch,
|
|
979
|
+
events: this.drainQueuedEvents(page.pageRef),
|
|
980
|
+
data: artifact
|
|
981
|
+
});
|
|
982
|
+
}
|
|
983
|
+
async setExecutionState(input) {
|
|
984
|
+
const page = this.requirePage(input.pageRef);
|
|
985
|
+
const pausedChanged = input.paused !== void 0 && input.paused !== page.paused;
|
|
986
|
+
const frozenChanged = input.frozen !== void 0 && input.frozen !== page.frozen;
|
|
987
|
+
const nextPaused = input.paused ?? page.paused;
|
|
988
|
+
const nextFrozen = input.frozen ?? page.frozen;
|
|
989
|
+
if (pausedChanged) {
|
|
990
|
+
this.requireCapability(
|
|
991
|
+
nextPaused ? "executor.executionControl.pause" : "executor.executionControl.resume"
|
|
992
|
+
);
|
|
993
|
+
}
|
|
994
|
+
if (frozenChanged) {
|
|
995
|
+
this.requireCapability("executor.executionControl.freeze");
|
|
996
|
+
}
|
|
997
|
+
page.paused = nextPaused;
|
|
998
|
+
page.frozen = nextFrozen;
|
|
999
|
+
const mainFrame = this.getMainFrameInfo(page.pageRef);
|
|
1000
|
+
const events = this.drainQueuedEvents(page.pageRef);
|
|
1001
|
+
if (pausedChanged) {
|
|
1002
|
+
const executionEvent = this.maybeCreateEvent({
|
|
1003
|
+
kind: nextPaused ? "paused" : "resumed",
|
|
1004
|
+
sessionRef: page.sessionRef,
|
|
1005
|
+
pageRef: page.pageRef,
|
|
1006
|
+
frameRef: mainFrame.frameRef,
|
|
1007
|
+
documentRef: mainFrame.documentRef,
|
|
1008
|
+
documentEpoch: mainFrame.documentEpoch
|
|
1009
|
+
});
|
|
1010
|
+
if (executionEvent) {
|
|
1011
|
+
events.push(executionEvent);
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
if (frozenChanged && nextFrozen) {
|
|
1015
|
+
const frozenEvent = this.maybeCreateEvent({
|
|
1016
|
+
kind: "frozen",
|
|
1017
|
+
sessionRef: page.sessionRef,
|
|
1018
|
+
pageRef: page.pageRef,
|
|
1019
|
+
frameRef: mainFrame.frameRef,
|
|
1020
|
+
documentRef: mainFrame.documentRef,
|
|
1021
|
+
documentEpoch: mainFrame.documentEpoch
|
|
1022
|
+
});
|
|
1023
|
+
if (frozenEvent) {
|
|
1024
|
+
events.push(frozenEvent);
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
return this.createStepResult(page.sessionRef, page.pageRef, {
|
|
1028
|
+
frameRef: mainFrame.frameRef,
|
|
1029
|
+
documentRef: mainFrame.documentRef,
|
|
1030
|
+
documentEpoch: mainFrame.documentEpoch,
|
|
1031
|
+
events,
|
|
1032
|
+
data: {
|
|
1033
|
+
paused: page.paused,
|
|
1034
|
+
frozen: page.frozen
|
|
1035
|
+
}
|
|
1036
|
+
});
|
|
1037
|
+
}
|
|
1038
|
+
async listPages(input) {
|
|
1039
|
+
this.requireCapability("inspector.pageEnumeration");
|
|
1040
|
+
const session = this.requireSession(input.sessionRef);
|
|
1041
|
+
return Array.from(
|
|
1042
|
+
session.pageRefs,
|
|
1043
|
+
(pageRef) => clone(this.pageInfoFromState(this.requirePage(pageRef)))
|
|
1044
|
+
);
|
|
1045
|
+
}
|
|
1046
|
+
async listFrames(input) {
|
|
1047
|
+
this.requireCapability("inspector.frameEnumeration");
|
|
1048
|
+
const page = this.requirePage(input.pageRef);
|
|
1049
|
+
return Array.from(page.frameRefs, (frameRef) => clone(this.requireFrame(frameRef).frameInfo));
|
|
1050
|
+
}
|
|
1051
|
+
async getPageInfo(input) {
|
|
1052
|
+
this.requireCapability("inspector.pageEnumeration");
|
|
1053
|
+
return clone(this.pageInfoFromState(this.requirePage(input.pageRef)));
|
|
1054
|
+
}
|
|
1055
|
+
async getFrameInfo(input) {
|
|
1056
|
+
this.requireCapability("inspector.frameEnumeration");
|
|
1057
|
+
return clone(this.requireFrame(input.frameRef).frameInfo);
|
|
1058
|
+
}
|
|
1059
|
+
async getHtmlSnapshot(input) {
|
|
1060
|
+
this.requireCapability("inspector.html");
|
|
1061
|
+
const document = this.resolveDocumentInput(input);
|
|
1062
|
+
return clone(document.htmlSnapshot);
|
|
1063
|
+
}
|
|
1064
|
+
async getDomSnapshot(input) {
|
|
1065
|
+
this.requireCapability("inspector.domSnapshot");
|
|
1066
|
+
const document = this.resolveDocumentInput(input);
|
|
1067
|
+
return clone(document.domSnapshot);
|
|
1068
|
+
}
|
|
1069
|
+
async waitForVisualStability(_input) {
|
|
1070
|
+
this.requireCapability("inspector.visualStability");
|
|
1071
|
+
}
|
|
1072
|
+
async readText(input) {
|
|
1073
|
+
this.requireCapability("inspector.text");
|
|
1074
|
+
const document = this.requireLiveNode(input);
|
|
1075
|
+
return clone(document.nodeText.get(input.nodeRef) ?? null);
|
|
1076
|
+
}
|
|
1077
|
+
async readAttributes(input) {
|
|
1078
|
+
this.requireCapability("inspector.attributes");
|
|
1079
|
+
const document = this.requireLiveNode(input);
|
|
1080
|
+
return clone(document.nodeAttributes.get(input.nodeRef) ?? []);
|
|
1081
|
+
}
|
|
1082
|
+
async hitTest(input) {
|
|
1083
|
+
this.requireCapability("inspector.hitTest");
|
|
1084
|
+
const page = this.requirePage(input.pageRef);
|
|
1085
|
+
const mainFrame = this.getMainFrameInfo(page.pageRef);
|
|
1086
|
+
const document = this.requireDocument(mainFrame.documentRef);
|
|
1087
|
+
const resolvedPoint = this.resolvePoint(
|
|
1088
|
+
page.viewportMetrics,
|
|
1089
|
+
input.point,
|
|
1090
|
+
input.coordinateSpace
|
|
1091
|
+
);
|
|
1092
|
+
const key = this.hitTestKey(resolvedPoint, input.ignorePointerEventsNone ?? false);
|
|
1093
|
+
const hit = document.hitTests.get(key);
|
|
1094
|
+
if (hit) {
|
|
1095
|
+
return clone({
|
|
1096
|
+
inputPoint: input.point,
|
|
1097
|
+
inputCoordinateSpace: input.coordinateSpace,
|
|
1098
|
+
...hit
|
|
1099
|
+
});
|
|
1100
|
+
}
|
|
1101
|
+
return {
|
|
1102
|
+
inputPoint: input.point,
|
|
1103
|
+
inputCoordinateSpace: input.coordinateSpace,
|
|
1104
|
+
resolvedPoint,
|
|
1105
|
+
resolvedCoordinateSpace: "document-css",
|
|
1106
|
+
pageRef: page.pageRef,
|
|
1107
|
+
frameRef: mainFrame.frameRef,
|
|
1108
|
+
documentRef: mainFrame.documentRef,
|
|
1109
|
+
documentEpoch: mainFrame.documentEpoch,
|
|
1110
|
+
obscured: false,
|
|
1111
|
+
pointerEventsSkipped: false
|
|
1112
|
+
};
|
|
1113
|
+
}
|
|
1114
|
+
async getViewportMetrics(input) {
|
|
1115
|
+
this.requireCapability("inspector.viewportMetrics");
|
|
1116
|
+
return clone(this.requirePage(input.pageRef).viewportMetrics);
|
|
1117
|
+
}
|
|
1118
|
+
async getNetworkRecords(input) {
|
|
1119
|
+
this.requireCapability("inspector.network");
|
|
1120
|
+
input.signal?.throwIfAborted?.();
|
|
1121
|
+
const session = this.requireSession(input.sessionRef);
|
|
1122
|
+
const records = [];
|
|
1123
|
+
const includeBodies = input.includeBodies ?? false;
|
|
1124
|
+
const pageRefs = input.pageRef === void 0 ? Array.from(session.pageRefs) : [input.pageRef];
|
|
1125
|
+
const requestIds = input.requestIds === void 0 ? void 0 : new Set(input.requestIds);
|
|
1126
|
+
for (const pageRef of pageRefs) {
|
|
1127
|
+
const page = this.requirePage(pageRef);
|
|
1128
|
+
const mainFrame = this.getMainFrame(page.pageRef);
|
|
1129
|
+
const document = this.requireDocument(mainFrame.frameInfo.documentRef);
|
|
1130
|
+
records.push(
|
|
1131
|
+
...document.networkRecords.filter(
|
|
1132
|
+
(record) => (requestIds === void 0 || requestIds.has(record.requestId)) && matchesNetworkRecordFilters(record, input)
|
|
1133
|
+
).map((record) => clone(record))
|
|
1134
|
+
);
|
|
1135
|
+
}
|
|
1136
|
+
if (!includeBodies) {
|
|
1137
|
+
return records.map(
|
|
1138
|
+
({ requestBody: _requestBody, responseBody: _responseBody, ...record }) => ({
|
|
1139
|
+
...record
|
|
1140
|
+
})
|
|
1141
|
+
);
|
|
1142
|
+
}
|
|
1143
|
+
this.requireCapability("inspector.networkBodies");
|
|
1144
|
+
return records;
|
|
1145
|
+
}
|
|
1146
|
+
async getCookies(input) {
|
|
1147
|
+
this.requireCapability("inspector.cookies");
|
|
1148
|
+
const session = this.requireSession(input.sessionRef);
|
|
1149
|
+
const cookies = input.urls && input.urls.length > 0 ? filterCookieRecords(session.cookies, input.urls) : session.cookies;
|
|
1150
|
+
return cookies.map((cookie) => clone(cookie));
|
|
1151
|
+
}
|
|
1152
|
+
async setCookies(input) {
|
|
1153
|
+
const session = this.requireSession(input.sessionRef);
|
|
1154
|
+
const merged = new Map(
|
|
1155
|
+
session.cookies.map((cookie) => [
|
|
1156
|
+
`${cookie.name}\0${cookie.domain}\0${cookie.path}`,
|
|
1157
|
+
clone(cookie)
|
|
1158
|
+
])
|
|
1159
|
+
);
|
|
1160
|
+
for (const cookie of input.cookies) {
|
|
1161
|
+
merged.set(`${cookie.name}\0${cookie.domain}\0${cookie.path}`, clone(cookie));
|
|
1162
|
+
}
|
|
1163
|
+
session.cookies = [...merged.values()];
|
|
1164
|
+
}
|
|
1165
|
+
async getStorageSnapshot(input) {
|
|
1166
|
+
const session = this.requireSession(input.sessionRef);
|
|
1167
|
+
this.requireCapability("inspector.localStorage");
|
|
1168
|
+
if (input.includeSessionStorage ?? true) {
|
|
1169
|
+
this.requireCapability("inspector.sessionStorage");
|
|
1170
|
+
}
|
|
1171
|
+
if (input.includeIndexedDb ?? true) {
|
|
1172
|
+
this.requireCapability("inspector.indexedDb");
|
|
1173
|
+
}
|
|
1174
|
+
const snapshot = clone(session.storage);
|
|
1175
|
+
return {
|
|
1176
|
+
sessionRef: snapshot.sessionRef,
|
|
1177
|
+
capturedAt: snapshot.capturedAt,
|
|
1178
|
+
origins: snapshot.origins.map((origin) => ({
|
|
1179
|
+
origin: origin.origin,
|
|
1180
|
+
localStorage: origin.localStorage,
|
|
1181
|
+
...(input.includeIndexedDb ?? true) && origin.indexedDb ? { indexedDb: origin.indexedDb } : {}
|
|
1182
|
+
})),
|
|
1183
|
+
...input.includeSessionStorage ?? true ? { sessionStorage: snapshot.sessionStorage ?? [] } : {}
|
|
1184
|
+
};
|
|
1185
|
+
}
|
|
1186
|
+
async evaluatePage(input) {
|
|
1187
|
+
const page = this.requirePage(input.pageRef);
|
|
1188
|
+
const mainFrame = this.getMainFrameInfo(page.pageRef);
|
|
1189
|
+
const value = await Promise.resolve().then(() => {
|
|
1190
|
+
const evaluated = (0, eval)(input.script);
|
|
1191
|
+
if (typeof evaluated === "function") {
|
|
1192
|
+
return evaluated(...input.args ?? []);
|
|
1193
|
+
}
|
|
1194
|
+
return evaluated;
|
|
1195
|
+
});
|
|
1196
|
+
return this.createStepResult(page.sessionRef, page.pageRef, {
|
|
1197
|
+
frameRef: mainFrame.frameRef,
|
|
1198
|
+
documentRef: mainFrame.documentRef,
|
|
1199
|
+
documentEpoch: mainFrame.documentEpoch,
|
|
1200
|
+
events: this.drainQueuedEvents(page.pageRef),
|
|
1201
|
+
data: clone(value)
|
|
1202
|
+
});
|
|
1203
|
+
}
|
|
1204
|
+
async executeRequest(input) {
|
|
1205
|
+
this.requireCapability("transport.sessionHttp");
|
|
1206
|
+
input.signal?.throwIfAborted?.();
|
|
1207
|
+
const session = this.requireSession(input.sessionRef);
|
|
1208
|
+
const key = buildTransportKey(input.request);
|
|
1209
|
+
const seededResponse = session.transportResponses.get(key);
|
|
1210
|
+
const response = seededResponse ?? {
|
|
1211
|
+
url: input.request.url,
|
|
1212
|
+
status: 200,
|
|
1213
|
+
statusText: "OK",
|
|
1214
|
+
headers: [createHeaderEntry("content-type", "text/plain; charset=utf-8")],
|
|
1215
|
+
body: bodyPayloadFromUtf8(`${input.request.method.toUpperCase()} ${input.request.url}`, {
|
|
1216
|
+
mimeType: "text/plain"
|
|
1217
|
+
}),
|
|
1218
|
+
redirected: false
|
|
1219
|
+
};
|
|
1220
|
+
const requestId = createNetworkRequestId(`transport-${++this.requestCounter}`);
|
|
1221
|
+
const transportRecord = {
|
|
1222
|
+
kind: "http",
|
|
1223
|
+
requestId,
|
|
1224
|
+
sessionRef: input.sessionRef,
|
|
1225
|
+
method: input.request.method.toUpperCase(),
|
|
1226
|
+
url: input.request.url,
|
|
1227
|
+
requestHeaders: input.request.headers ?? [],
|
|
1228
|
+
responseHeaders: response.headers,
|
|
1229
|
+
status: response.status,
|
|
1230
|
+
statusText: response.statusText,
|
|
1231
|
+
resourceType: "fetch",
|
|
1232
|
+
navigationRequest: false,
|
|
1233
|
+
captureState: "complete",
|
|
1234
|
+
requestBodyState: input.request.body === void 0 ? "skipped" : "complete",
|
|
1235
|
+
responseBodyState: response.body === void 0 ? "skipped" : "complete",
|
|
1236
|
+
...input.request.body === void 0 ? { requestBodySkipReason: "not-present" } : {},
|
|
1237
|
+
...response.body === void 0 ? { responseBodySkipReason: "not-present" } : {},
|
|
1238
|
+
...input.request.body === void 0 ? {} : { requestBody: input.request.body },
|
|
1239
|
+
...response.body === void 0 ? {} : { responseBody: response.body }
|
|
1240
|
+
};
|
|
1241
|
+
for (const pageRef of session.pageRefs) {
|
|
1242
|
+
const mainFrame = this.getMainFrame(pageRef);
|
|
1243
|
+
this.requireDocument(mainFrame.frameInfo.documentRef).networkRecords.push(transportRecord);
|
|
1244
|
+
break;
|
|
1245
|
+
}
|
|
1246
|
+
return this.createStepResult(input.sessionRef, void 0, {
|
|
1247
|
+
events: [],
|
|
1248
|
+
data: clone(response)
|
|
1249
|
+
});
|
|
1250
|
+
}
|
|
1251
|
+
createPageInternal(sessionRef, options) {
|
|
1252
|
+
const session = this.requireSession(sessionRef);
|
|
1253
|
+
const pageRef = createPageRef(`fake-${++this.pageCounter}`);
|
|
1254
|
+
const frameRef = createFrameRef(`fake-${++this.frameCounter}`);
|
|
1255
|
+
const documentRef = createDocumentRef(`fake-${++this.documentCounter}`);
|
|
1256
|
+
const documentEpoch = createDocumentEpoch(0);
|
|
1257
|
+
const url = options.url ?? "about:blank";
|
|
1258
|
+
const title = options.title ?? titleFromUrl(url);
|
|
1259
|
+
const viewportSize = options.viewportSize ?? createSize(1280, 720);
|
|
1260
|
+
const page = {
|
|
1261
|
+
pageRef,
|
|
1262
|
+
sessionRef,
|
|
1263
|
+
frameRefs: /* @__PURE__ */ new Set([frameRef]),
|
|
1264
|
+
queuedEvents: [],
|
|
1265
|
+
history: [url],
|
|
1266
|
+
historyIndex: 0,
|
|
1267
|
+
lifecycleState: "open",
|
|
1268
|
+
paused: false,
|
|
1269
|
+
frozen: false,
|
|
1270
|
+
viewportMetrics: {
|
|
1271
|
+
layoutViewport: {
|
|
1272
|
+
origin: createPoint(0, 0),
|
|
1273
|
+
size: viewportSize
|
|
1274
|
+
},
|
|
1275
|
+
visualViewport: {
|
|
1276
|
+
origin: createPoint(0, 0),
|
|
1277
|
+
offsetWithinLayoutViewport: createScrollOffset(0, 0),
|
|
1278
|
+
size: viewportSize
|
|
1279
|
+
},
|
|
1280
|
+
scrollOffset: createScrollOffset(0, 0),
|
|
1281
|
+
contentSize: createSize(1280, 2400),
|
|
1282
|
+
devicePixelRatio: createDevicePixelRatio(2),
|
|
1283
|
+
pageScaleFactor: createPageScaleFactor(1),
|
|
1284
|
+
pageZoomFactor: createPageZoomFactor(1)
|
|
1285
|
+
},
|
|
1286
|
+
...options.openerPageRef === void 0 ? {} : { openerPageRef: options.openerPageRef }
|
|
1287
|
+
};
|
|
1288
|
+
const frameInfo = {
|
|
1289
|
+
frameRef,
|
|
1290
|
+
pageRef,
|
|
1291
|
+
documentRef,
|
|
1292
|
+
documentEpoch,
|
|
1293
|
+
url,
|
|
1294
|
+
isMainFrame: true
|
|
1295
|
+
};
|
|
1296
|
+
this.pages.set(pageRef, page);
|
|
1297
|
+
this.frames.set(frameRef, { frameInfo });
|
|
1298
|
+
session.pageRefs.add(pageRef);
|
|
1299
|
+
this.rebuildDocumentStateForFrame(pageRef, frameRef, {
|
|
1300
|
+
documentRef,
|
|
1301
|
+
documentEpoch,
|
|
1302
|
+
url,
|
|
1303
|
+
title
|
|
1304
|
+
});
|
|
1305
|
+
session.storage = this.seedDefaultSessionStorage(session.storage, pageRef, frameRef, url);
|
|
1306
|
+
return {
|
|
1307
|
+
pageInfo: this.pageInfoFromState(page, url, title),
|
|
1308
|
+
frameInfo
|
|
1309
|
+
};
|
|
1310
|
+
}
|
|
1311
|
+
pageInfoFromState(page, url, title) {
|
|
1312
|
+
const mainFrame = this.getMainFrameInfo(page.pageRef);
|
|
1313
|
+
return {
|
|
1314
|
+
pageRef: page.pageRef,
|
|
1315
|
+
sessionRef: page.sessionRef,
|
|
1316
|
+
url: url ?? mainFrame.url,
|
|
1317
|
+
title: title ?? titleFromUrl(mainFrame.url),
|
|
1318
|
+
lifecycleState: page.lifecycleState,
|
|
1319
|
+
...page.openerPageRef === void 0 ? {} : { openerPageRef: page.openerPageRef }
|
|
1320
|
+
};
|
|
1321
|
+
}
|
|
1322
|
+
createDefaultStorage(sessionRef) {
|
|
1323
|
+
return {
|
|
1324
|
+
sessionRef,
|
|
1325
|
+
capturedAt: this.timestampMs,
|
|
1326
|
+
origins: [
|
|
1327
|
+
{
|
|
1328
|
+
origin: "https://example.com",
|
|
1329
|
+
localStorage: [
|
|
1330
|
+
{ key: "theme", value: "dark" },
|
|
1331
|
+
{ key: "draft", value: "hello" }
|
|
1332
|
+
],
|
|
1333
|
+
indexedDb: [
|
|
1334
|
+
{
|
|
1335
|
+
name: "app-db",
|
|
1336
|
+
version: 1,
|
|
1337
|
+
objectStores: [
|
|
1338
|
+
{
|
|
1339
|
+
name: "messages",
|
|
1340
|
+
keyPath: "id",
|
|
1341
|
+
autoIncrement: false,
|
|
1342
|
+
indexes: [],
|
|
1343
|
+
records: [
|
|
1344
|
+
{
|
|
1345
|
+
key: "1",
|
|
1346
|
+
value: { id: "1", text: "hello" }
|
|
1347
|
+
}
|
|
1348
|
+
]
|
|
1349
|
+
}
|
|
1350
|
+
]
|
|
1351
|
+
}
|
|
1352
|
+
]
|
|
1353
|
+
}
|
|
1354
|
+
],
|
|
1355
|
+
sessionStorage: []
|
|
1356
|
+
};
|
|
1357
|
+
}
|
|
1358
|
+
seedDefaultSessionStorage(storage, pageRef, frameRef, url) {
|
|
1359
|
+
const origin = originFromUrl(url);
|
|
1360
|
+
if (origin === void 0) {
|
|
1361
|
+
return storage;
|
|
1362
|
+
}
|
|
1363
|
+
if (storage.sessionStorage?.some(
|
|
1364
|
+
(snapshot) => snapshot.pageRef === pageRef && snapshot.frameRef === frameRef && snapshot.origin === origin
|
|
1365
|
+
)) {
|
|
1366
|
+
return storage;
|
|
1367
|
+
}
|
|
1368
|
+
return {
|
|
1369
|
+
...storage,
|
|
1370
|
+
sessionStorage: [
|
|
1371
|
+
...storage.sessionStorage ?? [],
|
|
1372
|
+
{
|
|
1373
|
+
pageRef,
|
|
1374
|
+
frameRef,
|
|
1375
|
+
origin,
|
|
1376
|
+
entries: [{ key: "csrf", value: "token-123" }]
|
|
1377
|
+
}
|
|
1378
|
+
]
|
|
1379
|
+
};
|
|
1380
|
+
}
|
|
1381
|
+
async performNavigation(pageRef, url, options) {
|
|
1382
|
+
this.requireCapability("executor.navigation");
|
|
1383
|
+
const page = this.requirePage(pageRef);
|
|
1384
|
+
const mainFrame = this.getMainFrame(page.pageRef);
|
|
1385
|
+
const currentFrameInfo = mainFrame.frameInfo;
|
|
1386
|
+
const currentDocument = this.requireDocument(currentFrameInfo.documentRef);
|
|
1387
|
+
const sameDocument = !options.forceNewDocument && stripFragment(currentFrameInfo.url) === stripFragment(url);
|
|
1388
|
+
const title = titleFromUrl(url);
|
|
1389
|
+
const requestBody = options.referrer === void 0 ? void 0 : bodyPayloadFromUtf8(options.referrer, { mimeType: "text/plain" });
|
|
1390
|
+
const requestHeaders = options.referrer === void 0 ? [] : [createHeaderEntry("referer", options.referrer)];
|
|
1391
|
+
let nextDocumentRef = currentFrameInfo.documentRef;
|
|
1392
|
+
let nextDocumentEpoch2 = currentFrameInfo.documentEpoch;
|
|
1393
|
+
if (sameDocument) {
|
|
1394
|
+
currentDocument.url = url;
|
|
1395
|
+
currentDocument.htmlSnapshot = {
|
|
1396
|
+
...currentDocument.htmlSnapshot,
|
|
1397
|
+
url,
|
|
1398
|
+
capturedAt: this.nextTimestamp()
|
|
1399
|
+
};
|
|
1400
|
+
currentDocument.domSnapshot = {
|
|
1401
|
+
...currentDocument.domSnapshot,
|
|
1402
|
+
url,
|
|
1403
|
+
capturedAt: this.nextTimestamp()
|
|
1404
|
+
};
|
|
1405
|
+
mainFrame.frameInfo = {
|
|
1406
|
+
...currentFrameInfo,
|
|
1407
|
+
url
|
|
1408
|
+
};
|
|
1409
|
+
} else {
|
|
1410
|
+
nextDocumentRef = createDocumentRef(`fake-${++this.documentCounter}`);
|
|
1411
|
+
nextDocumentEpoch2 = createDocumentEpoch(0);
|
|
1412
|
+
mainFrame.frameInfo = {
|
|
1413
|
+
...currentFrameInfo,
|
|
1414
|
+
url,
|
|
1415
|
+
documentRef: nextDocumentRef,
|
|
1416
|
+
documentEpoch: nextDocumentEpoch2
|
|
1417
|
+
};
|
|
1418
|
+
this.rebuildDocumentStateForFrame(page.pageRef, currentFrameInfo.frameRef, {
|
|
1419
|
+
documentRef: nextDocumentRef,
|
|
1420
|
+
documentEpoch: nextDocumentEpoch2,
|
|
1421
|
+
url,
|
|
1422
|
+
title
|
|
1423
|
+
});
|
|
1424
|
+
this.retireDocument(currentFrameInfo.documentRef);
|
|
1425
|
+
const requestId = createNetworkRequestId(`fake-${++this.requestCounter}`);
|
|
1426
|
+
const responseBody = bodyPayloadFromUtf8(`<html><title>${title}</title></html>`, {
|
|
1427
|
+
mimeType: "text/html"
|
|
1428
|
+
});
|
|
1429
|
+
this.requireDocument(nextDocumentRef).networkRecords.push({
|
|
1430
|
+
kind: "http",
|
|
1431
|
+
requestId,
|
|
1432
|
+
sessionRef: page.sessionRef,
|
|
1433
|
+
pageRef: page.pageRef,
|
|
1434
|
+
frameRef: currentFrameInfo.frameRef,
|
|
1435
|
+
documentRef: nextDocumentRef,
|
|
1436
|
+
method: "GET",
|
|
1437
|
+
url,
|
|
1438
|
+
requestHeaders,
|
|
1439
|
+
responseHeaders: [
|
|
1440
|
+
createHeaderEntry("content-type", "text/html; charset=utf-8"),
|
|
1441
|
+
createHeaderEntry("set-cookie", "session=abc"),
|
|
1442
|
+
createHeaderEntry("set-cookie", "theme=dark")
|
|
1443
|
+
],
|
|
1444
|
+
status: 200,
|
|
1445
|
+
statusText: "OK",
|
|
1446
|
+
resourceType: "document",
|
|
1447
|
+
navigationRequest: true,
|
|
1448
|
+
captureState: "complete",
|
|
1449
|
+
requestBodyState: requestBody === void 0 ? "skipped" : "complete",
|
|
1450
|
+
responseBodyState: "complete",
|
|
1451
|
+
...requestBody === void 0 ? { requestBodySkipReason: "not-present" } : {},
|
|
1452
|
+
timing: {
|
|
1453
|
+
requestStartMs: this.timestampMs,
|
|
1454
|
+
responseStartMs: this.timestampMs + 5,
|
|
1455
|
+
responseEndMs: this.timestampMs + 10
|
|
1456
|
+
},
|
|
1457
|
+
transfer: {
|
|
1458
|
+
encodedBodyBytes: responseBody.capturedByteLength,
|
|
1459
|
+
decodedBodyBytes: responseBody.capturedByteLength,
|
|
1460
|
+
transferSizeBytes: responseBody.capturedByteLength + 256
|
|
1461
|
+
},
|
|
1462
|
+
...requestBody === void 0 ? {} : { requestBody },
|
|
1463
|
+
responseBody
|
|
1464
|
+
});
|
|
1465
|
+
}
|
|
1466
|
+
if (options.recordHistory) {
|
|
1467
|
+
page.history = [...page.history.slice(0, page.historyIndex + 1), url];
|
|
1468
|
+
page.historyIndex = page.history.length - 1;
|
|
1469
|
+
}
|
|
1470
|
+
const pageInfo = this.pageInfoFromState(page, url, title);
|
|
1471
|
+
return this.createStepResult(page.sessionRef, page.pageRef, {
|
|
1472
|
+
frameRef: mainFrame.frameInfo.frameRef,
|
|
1473
|
+
documentRef: nextDocumentRef,
|
|
1474
|
+
documentEpoch: nextDocumentEpoch2,
|
|
1475
|
+
events: this.drainQueuedEvents(page.pageRef),
|
|
1476
|
+
data: {
|
|
1477
|
+
pageInfo,
|
|
1478
|
+
mainFrame: clone(mainFrame.frameInfo)
|
|
1479
|
+
}
|
|
1480
|
+
});
|
|
1481
|
+
}
|
|
1482
|
+
createDocumentSnapshot(pageRef, frameRef, documentRef, documentEpoch, url, title) {
|
|
1483
|
+
const bodyRect = createRect(0, 0, 1280, 2400);
|
|
1484
|
+
const buttonRect = createRect(16, 16, 160, 48);
|
|
1485
|
+
const obscuredRect = createRect(240, 16, 160, 48);
|
|
1486
|
+
const titleRect = createRect(16, 96, 220, 32);
|
|
1487
|
+
const buttonRef = createNodeRef(`fake-${++this.nodeCounter}`);
|
|
1488
|
+
const obscuredRef = createNodeRef(`fake-${++this.nodeCounter}`);
|
|
1489
|
+
const documentNodeRef = createNodeRef(`fake-${++this.nodeCounter}`);
|
|
1490
|
+
const htmlNodeRef = createNodeRef(`fake-${++this.nodeCounter}`);
|
|
1491
|
+
const bodyNodeRef = createNodeRef(`fake-${++this.nodeCounter}`);
|
|
1492
|
+
const titleRef = createNodeRef(`fake-${++this.nodeCounter}`);
|
|
1493
|
+
const hiddenPanelRef = createNodeRef(`fake-${++this.nodeCounter}`);
|
|
1494
|
+
const shadowHostRef = createNodeRef(`fake-${++this.nodeCounter}`);
|
|
1495
|
+
const shadowActionRef = createNodeRef(`fake-${++this.nodeCounter}`);
|
|
1496
|
+
const nestedShadowHostRef = createNodeRef(`fake-${++this.nodeCounter}`);
|
|
1497
|
+
const nestedShadowActionRef = createNodeRef(`fake-${++this.nodeCounter}`);
|
|
1498
|
+
const nodes = [
|
|
1499
|
+
{
|
|
1500
|
+
snapshotNodeId: 1,
|
|
1501
|
+
nodeRef: documentNodeRef,
|
|
1502
|
+
childSnapshotNodeIds: [2],
|
|
1503
|
+
nodeType: 9,
|
|
1504
|
+
nodeName: "#document",
|
|
1505
|
+
nodeValue: "",
|
|
1506
|
+
attributes: []
|
|
1507
|
+
},
|
|
1508
|
+
{
|
|
1509
|
+
snapshotNodeId: 2,
|
|
1510
|
+
nodeRef: htmlNodeRef,
|
|
1511
|
+
parentSnapshotNodeId: 1,
|
|
1512
|
+
childSnapshotNodeIds: [3],
|
|
1513
|
+
nodeType: 1,
|
|
1514
|
+
nodeName: "HTML",
|
|
1515
|
+
nodeValue: "",
|
|
1516
|
+
attributes: []
|
|
1517
|
+
},
|
|
1518
|
+
{
|
|
1519
|
+
snapshotNodeId: 3,
|
|
1520
|
+
nodeRef: bodyNodeRef,
|
|
1521
|
+
parentSnapshotNodeId: 2,
|
|
1522
|
+
childSnapshotNodeIds: [4, 5, 6, 7, 8, 9, 10, 11],
|
|
1523
|
+
nodeType: 1,
|
|
1524
|
+
nodeName: "BODY",
|
|
1525
|
+
nodeValue: "",
|
|
1526
|
+
attributes: [],
|
|
1527
|
+
layout: {
|
|
1528
|
+
rect: bodyRect,
|
|
1529
|
+
quad: rectToQuad(bodyRect),
|
|
1530
|
+
paintOrder: 1
|
|
1531
|
+
}
|
|
1532
|
+
},
|
|
1533
|
+
{
|
|
1534
|
+
snapshotNodeId: 4,
|
|
1535
|
+
nodeRef: buttonRef,
|
|
1536
|
+
parentSnapshotNodeId: 3,
|
|
1537
|
+
childSnapshotNodeIds: [],
|
|
1538
|
+
nodeType: 1,
|
|
1539
|
+
nodeName: "BUTTON",
|
|
1540
|
+
nodeValue: "",
|
|
1541
|
+
textContent: "Continue",
|
|
1542
|
+
attributes: [
|
|
1543
|
+
{ name: "id", value: "continue" },
|
|
1544
|
+
{ name: "type", value: "button" }
|
|
1545
|
+
],
|
|
1546
|
+
layout: {
|
|
1547
|
+
rect: buttonRect,
|
|
1548
|
+
quad: rectToQuad(buttonRect),
|
|
1549
|
+
paintOrder: 2
|
|
1550
|
+
}
|
|
1551
|
+
},
|
|
1552
|
+
{
|
|
1553
|
+
snapshotNodeId: 5,
|
|
1554
|
+
nodeRef: obscuredRef,
|
|
1555
|
+
parentSnapshotNodeId: 3,
|
|
1556
|
+
childSnapshotNodeIds: [],
|
|
1557
|
+
nodeType: 1,
|
|
1558
|
+
nodeName: "DIV",
|
|
1559
|
+
nodeValue: "",
|
|
1560
|
+
textContent: "Overlay",
|
|
1561
|
+
attributes: [{ name: "id", value: "overlay" }],
|
|
1562
|
+
layout: {
|
|
1563
|
+
rect: obscuredRect,
|
|
1564
|
+
quad: rectToQuad(obscuredRect),
|
|
1565
|
+
paintOrder: 3
|
|
1566
|
+
}
|
|
1567
|
+
},
|
|
1568
|
+
{
|
|
1569
|
+
snapshotNodeId: 6,
|
|
1570
|
+
nodeRef: titleRef,
|
|
1571
|
+
parentSnapshotNodeId: 3,
|
|
1572
|
+
childSnapshotNodeIds: [],
|
|
1573
|
+
nodeType: 1,
|
|
1574
|
+
nodeName: "H1",
|
|
1575
|
+
nodeValue: "",
|
|
1576
|
+
textContent: "Snapshot Heading",
|
|
1577
|
+
attributes: [{ name: "id", value: "snapshot-title" }],
|
|
1578
|
+
layout: {
|
|
1579
|
+
rect: titleRect,
|
|
1580
|
+
quad: rectToQuad(titleRect),
|
|
1581
|
+
paintOrder: 4
|
|
1582
|
+
}
|
|
1583
|
+
},
|
|
1584
|
+
{
|
|
1585
|
+
snapshotNodeId: 7,
|
|
1586
|
+
nodeRef: hiddenPanelRef,
|
|
1587
|
+
parentSnapshotNodeId: 3,
|
|
1588
|
+
childSnapshotNodeIds: [],
|
|
1589
|
+
nodeType: 1,
|
|
1590
|
+
nodeName: "DIV",
|
|
1591
|
+
nodeValue: "",
|
|
1592
|
+
textContent: "Hidden panel",
|
|
1593
|
+
computedStyle: {
|
|
1594
|
+
display: "none"
|
|
1595
|
+
},
|
|
1596
|
+
attributes: [{ name: "id", value: "hidden-panel" }]
|
|
1597
|
+
},
|
|
1598
|
+
{
|
|
1599
|
+
snapshotNodeId: 8,
|
|
1600
|
+
nodeRef: shadowHostRef,
|
|
1601
|
+
parentSnapshotNodeId: 3,
|
|
1602
|
+
childSnapshotNodeIds: [],
|
|
1603
|
+
nodeType: 1,
|
|
1604
|
+
nodeName: "DIV",
|
|
1605
|
+
nodeValue: "",
|
|
1606
|
+
textContent: "",
|
|
1607
|
+
attributes: [{ name: "id", value: "shadow-host" }]
|
|
1608
|
+
},
|
|
1609
|
+
{
|
|
1610
|
+
snapshotNodeId: 9,
|
|
1611
|
+
nodeRef: shadowActionRef,
|
|
1612
|
+
parentSnapshotNodeId: 3,
|
|
1613
|
+
childSnapshotNodeIds: [],
|
|
1614
|
+
shadowHostNodeRef: shadowHostRef,
|
|
1615
|
+
nodeType: 1,
|
|
1616
|
+
nodeName: "BUTTON",
|
|
1617
|
+
nodeValue: "",
|
|
1618
|
+
textContent: "Shadow Action",
|
|
1619
|
+
attributes: [{ name: "id", value: "shadow-action" }]
|
|
1620
|
+
},
|
|
1621
|
+
{
|
|
1622
|
+
snapshotNodeId: 10,
|
|
1623
|
+
nodeRef: nestedShadowHostRef,
|
|
1624
|
+
parentSnapshotNodeId: 3,
|
|
1625
|
+
childSnapshotNodeIds: [],
|
|
1626
|
+
nodeType: 1,
|
|
1627
|
+
nodeName: "DIV",
|
|
1628
|
+
nodeValue: "",
|
|
1629
|
+
textContent: "",
|
|
1630
|
+
attributes: [{ name: "id", value: "nested-shadow-host" }]
|
|
1631
|
+
},
|
|
1632
|
+
{
|
|
1633
|
+
snapshotNodeId: 11,
|
|
1634
|
+
nodeRef: nestedShadowActionRef,
|
|
1635
|
+
parentSnapshotNodeId: 3,
|
|
1636
|
+
childSnapshotNodeIds: [],
|
|
1637
|
+
shadowHostNodeRef: nestedShadowHostRef,
|
|
1638
|
+
nodeType: 1,
|
|
1639
|
+
nodeName: "BUTTON",
|
|
1640
|
+
nodeValue: "",
|
|
1641
|
+
textContent: "Nested Shadow",
|
|
1642
|
+
attributes: [{ name: "id", value: "nested-shadow-action" }]
|
|
1643
|
+
}
|
|
1644
|
+
];
|
|
1645
|
+
const domSnapshot = {
|
|
1646
|
+
pageRef,
|
|
1647
|
+
frameRef,
|
|
1648
|
+
documentRef,
|
|
1649
|
+
documentEpoch,
|
|
1650
|
+
url,
|
|
1651
|
+
capturedAt: this.timestampMs,
|
|
1652
|
+
rootSnapshotNodeId: 1,
|
|
1653
|
+
shadowDomMode: "flattened",
|
|
1654
|
+
geometryCoordinateSpace: "document-css",
|
|
1655
|
+
nodes
|
|
1656
|
+
};
|
|
1657
|
+
const nodeText = /* @__PURE__ */ new Map([
|
|
1658
|
+
[buttonRef, "Continue"],
|
|
1659
|
+
[obscuredRef, "Overlay"],
|
|
1660
|
+
[titleRef, "Snapshot Heading"],
|
|
1661
|
+
[hiddenPanelRef, "Hidden panel"],
|
|
1662
|
+
[shadowHostRef, ""],
|
|
1663
|
+
[shadowActionRef, "Shadow Action"],
|
|
1664
|
+
[nestedShadowHostRef, ""],
|
|
1665
|
+
[nestedShadowActionRef, "Nested Shadow"],
|
|
1666
|
+
[documentNodeRef, null],
|
|
1667
|
+
[htmlNodeRef, null],
|
|
1668
|
+
[bodyNodeRef, null]
|
|
1669
|
+
]);
|
|
1670
|
+
const nodeAttributes = /* @__PURE__ */ new Map([
|
|
1671
|
+
[buttonRef, nodes[3].attributes],
|
|
1672
|
+
[obscuredRef, nodes[4].attributes],
|
|
1673
|
+
[titleRef, nodes[5].attributes],
|
|
1674
|
+
[hiddenPanelRef, nodes[6].attributes],
|
|
1675
|
+
[shadowHostRef, nodes[7].attributes],
|
|
1676
|
+
[shadowActionRef, nodes[8].attributes],
|
|
1677
|
+
[nestedShadowHostRef, nodes[9].attributes],
|
|
1678
|
+
[nestedShadowActionRef, nodes[10].attributes],
|
|
1679
|
+
[documentNodeRef, []],
|
|
1680
|
+
[htmlNodeRef, []],
|
|
1681
|
+
[bodyNodeRef, []]
|
|
1682
|
+
]);
|
|
1683
|
+
const nodeRects = /* @__PURE__ */ new Map([
|
|
1684
|
+
[buttonRef, buttonRect],
|
|
1685
|
+
[obscuredRef, obscuredRect],
|
|
1686
|
+
[titleRef, titleRect],
|
|
1687
|
+
[bodyNodeRef, bodyRect]
|
|
1688
|
+
]);
|
|
1689
|
+
const hitTests = /* @__PURE__ */ new Map([
|
|
1690
|
+
[
|
|
1691
|
+
this.hitTestKey(createPoint(20, 20), false),
|
|
1692
|
+
{
|
|
1693
|
+
resolvedPoint: createPoint(20, 20),
|
|
1694
|
+
resolvedCoordinateSpace: "document-css",
|
|
1695
|
+
pageRef,
|
|
1696
|
+
frameRef,
|
|
1697
|
+
documentRef,
|
|
1698
|
+
documentEpoch,
|
|
1699
|
+
nodeRef: buttonRef,
|
|
1700
|
+
targetQuad: rectToQuad(buttonRect),
|
|
1701
|
+
obscured: false,
|
|
1702
|
+
pointerEventsSkipped: false
|
|
1703
|
+
}
|
|
1704
|
+
],
|
|
1705
|
+
[
|
|
1706
|
+
this.hitTestKey(createPoint(260, 20), false),
|
|
1707
|
+
{
|
|
1708
|
+
resolvedPoint: createPoint(260, 20),
|
|
1709
|
+
resolvedCoordinateSpace: "document-css",
|
|
1710
|
+
pageRef,
|
|
1711
|
+
frameRef,
|
|
1712
|
+
documentRef,
|
|
1713
|
+
documentEpoch,
|
|
1714
|
+
nodeRef: obscuredRef,
|
|
1715
|
+
targetQuad: rectToQuad(obscuredRect),
|
|
1716
|
+
obscured: true,
|
|
1717
|
+
pointerEventsSkipped: false
|
|
1718
|
+
}
|
|
1719
|
+
],
|
|
1720
|
+
[
|
|
1721
|
+
this.hitTestKey(createPoint(20, 20), true),
|
|
1722
|
+
{
|
|
1723
|
+
resolvedPoint: createPoint(20, 20),
|
|
1724
|
+
resolvedCoordinateSpace: "document-css",
|
|
1725
|
+
pageRef,
|
|
1726
|
+
frameRef,
|
|
1727
|
+
documentRef,
|
|
1728
|
+
documentEpoch,
|
|
1729
|
+
nodeRef: buttonRef,
|
|
1730
|
+
targetQuad: rectToQuad(buttonRect),
|
|
1731
|
+
obscured: false,
|
|
1732
|
+
pointerEventsSkipped: true
|
|
1733
|
+
}
|
|
1734
|
+
]
|
|
1735
|
+
]);
|
|
1736
|
+
return {
|
|
1737
|
+
htmlSnapshot: {
|
|
1738
|
+
pageRef,
|
|
1739
|
+
frameRef,
|
|
1740
|
+
documentRef,
|
|
1741
|
+
documentEpoch,
|
|
1742
|
+
url,
|
|
1743
|
+
capturedAt: this.timestampMs,
|
|
1744
|
+
html: `<html><head><title>${title}</title></head><body><button id="continue" type="button">Continue</button><div id="overlay">Overlay</div><h1 id="snapshot-title">Snapshot Heading</h1><div id="hidden-panel" style="display:none">Hidden panel</div><div id="shadow-host"></div><button id="shadow-action">Shadow Action</button><div id="nested-shadow-host"></div><button id="nested-shadow-action">Nested Shadow</button></body></html>`
|
|
1745
|
+
},
|
|
1746
|
+
domSnapshot,
|
|
1747
|
+
nodeText,
|
|
1748
|
+
nodeAttributes,
|
|
1749
|
+
nodeRects,
|
|
1750
|
+
hitTests,
|
|
1751
|
+
networkRecords: []
|
|
1752
|
+
};
|
|
1753
|
+
}
|
|
1754
|
+
rebuildDocumentStateForFrame(pageRef, frameRef, input) {
|
|
1755
|
+
const nextState = this.createDocumentSnapshot(
|
|
1756
|
+
pageRef,
|
|
1757
|
+
frameRef,
|
|
1758
|
+
input.documentRef,
|
|
1759
|
+
input.documentEpoch,
|
|
1760
|
+
input.url,
|
|
1761
|
+
input.title
|
|
1762
|
+
);
|
|
1763
|
+
this.retiredDocuments.delete(input.documentRef);
|
|
1764
|
+
this.documents.set(input.documentRef, {
|
|
1765
|
+
pageRef,
|
|
1766
|
+
frameRef,
|
|
1767
|
+
documentRef: input.documentRef,
|
|
1768
|
+
documentEpoch: input.documentEpoch,
|
|
1769
|
+
url: input.url,
|
|
1770
|
+
...nextState
|
|
1771
|
+
});
|
|
1772
|
+
}
|
|
1773
|
+
rebuildDocumentState(documentRef, input) {
|
|
1774
|
+
const existing = this.requireDocument(documentRef);
|
|
1775
|
+
this.rebuildDocumentStateForFrame(existing.pageRef, existing.frameRef, input);
|
|
1776
|
+
const frame = this.requireFrame(existing.frameRef);
|
|
1777
|
+
frame.frameInfo = {
|
|
1778
|
+
...frame.frameInfo,
|
|
1779
|
+
documentRef: input.documentRef,
|
|
1780
|
+
documentEpoch: input.documentEpoch,
|
|
1781
|
+
url: input.url
|
|
1782
|
+
};
|
|
1783
|
+
}
|
|
1784
|
+
resolveDocumentInput(input) {
|
|
1785
|
+
if (input.frameRef && input.documentRef) {
|
|
1786
|
+
throw createBrowserCoreError(
|
|
1787
|
+
"invalid-argument",
|
|
1788
|
+
"provide either frameRef or documentRef, not both"
|
|
1789
|
+
);
|
|
1790
|
+
}
|
|
1791
|
+
if (input.documentRef) {
|
|
1792
|
+
return this.requireDocument(input.documentRef);
|
|
1793
|
+
}
|
|
1794
|
+
if (input.frameRef) {
|
|
1795
|
+
return this.requireDocument(this.requireFrame(input.frameRef).frameInfo.documentRef);
|
|
1796
|
+
}
|
|
1797
|
+
throw createBrowserCoreError("invalid-argument", "either frameRef or documentRef is required");
|
|
1798
|
+
}
|
|
1799
|
+
requireLiveNode(input) {
|
|
1800
|
+
if (this.retiredDocuments.has(input.documentRef)) {
|
|
1801
|
+
throw staleNodeRefError(input);
|
|
1802
|
+
}
|
|
1803
|
+
const document = this.requireDocument(input.documentRef);
|
|
1804
|
+
if (document.documentEpoch !== input.documentEpoch) {
|
|
1805
|
+
throw staleNodeRefError(input);
|
|
1806
|
+
}
|
|
1807
|
+
const node = findDomSnapshotNodeByRef(document.domSnapshot, input.nodeRef);
|
|
1808
|
+
if (!node) {
|
|
1809
|
+
throw staleNodeRefError(input);
|
|
1810
|
+
}
|
|
1811
|
+
return document;
|
|
1812
|
+
}
|
|
1813
|
+
resolvePoint(metrics, point, coordinateSpace) {
|
|
1814
|
+
switch (coordinateSpace) {
|
|
1815
|
+
case "document-css":
|
|
1816
|
+
return point;
|
|
1817
|
+
case "layout-viewport-css":
|
|
1818
|
+
case "visual-viewport-css":
|
|
1819
|
+
return createPoint(point.x + metrics.scrollOffset.x, point.y + metrics.scrollOffset.y);
|
|
1820
|
+
case "computer-display-css":
|
|
1821
|
+
throw createBrowserCoreError(
|
|
1822
|
+
"unsupported-capability",
|
|
1823
|
+
`coordinate space ${coordinateSpace} is not supported by the fake engine`,
|
|
1824
|
+
{
|
|
1825
|
+
details: {
|
|
1826
|
+
coordinateSpace
|
|
1827
|
+
}
|
|
1828
|
+
}
|
|
1829
|
+
);
|
|
1830
|
+
case "window":
|
|
1831
|
+
case "screen":
|
|
1832
|
+
case "device-pixel":
|
|
1833
|
+
return createPoint(
|
|
1834
|
+
point.x / metrics.devicePixelRatio + metrics.scrollOffset.x,
|
|
1835
|
+
point.y / metrics.devicePixelRatio + metrics.scrollOffset.y
|
|
1836
|
+
);
|
|
1837
|
+
}
|
|
1838
|
+
throw createBrowserCoreError(
|
|
1839
|
+
"invalid-argument",
|
|
1840
|
+
`coordinate space ${coordinateSpace} is not supported by the fake engine`
|
|
1841
|
+
);
|
|
1842
|
+
}
|
|
1843
|
+
hitTestKey(point, ignorePointerEventsNone) {
|
|
1844
|
+
return `${Math.round(point.x)}:${Math.round(point.y)}:${ignorePointerEventsNone ? "ignore" : "respect"}`;
|
|
1845
|
+
}
|
|
1846
|
+
requireCapability(path) {
|
|
1847
|
+
if (!hasCapability(this.capabilities, path)) {
|
|
1848
|
+
throw unsupportedCapabilityError(path);
|
|
1849
|
+
}
|
|
1850
|
+
}
|
|
1851
|
+
assertEventCapability(kind) {
|
|
1852
|
+
const capability = this.eventCapabilityForKind(kind);
|
|
1853
|
+
if (!hasCapability(this.capabilities, capability)) {
|
|
1854
|
+
throw unsupportedCapabilityError(capability);
|
|
1855
|
+
}
|
|
1856
|
+
}
|
|
1857
|
+
eventCapabilityForKind(kind) {
|
|
1858
|
+
switch (kind) {
|
|
1859
|
+
case "page-created":
|
|
1860
|
+
case "popup-opened":
|
|
1861
|
+
case "page-closed":
|
|
1862
|
+
return "events.pageLifecycle";
|
|
1863
|
+
case "dialog-opened":
|
|
1864
|
+
return "events.dialog";
|
|
1865
|
+
case "download-started":
|
|
1866
|
+
case "download-finished":
|
|
1867
|
+
return "events.download";
|
|
1868
|
+
case "chooser-opened":
|
|
1869
|
+
return "events.chooser";
|
|
1870
|
+
case "worker-created":
|
|
1871
|
+
case "worker-destroyed":
|
|
1872
|
+
return "events.worker";
|
|
1873
|
+
case "console":
|
|
1874
|
+
return "events.console";
|
|
1875
|
+
case "page-error":
|
|
1876
|
+
return "events.pageError";
|
|
1877
|
+
case "websocket-opened":
|
|
1878
|
+
case "websocket-frame":
|
|
1879
|
+
case "websocket-closed":
|
|
1880
|
+
return "events.websocket";
|
|
1881
|
+
case "event-stream-message":
|
|
1882
|
+
return "events.eventStream";
|
|
1883
|
+
case "paused":
|
|
1884
|
+
case "resumed":
|
|
1885
|
+
case "frozen":
|
|
1886
|
+
return "events.executionState";
|
|
1887
|
+
}
|
|
1888
|
+
}
|
|
1889
|
+
createEvent(value) {
|
|
1890
|
+
this.assertEventCapability(value.kind);
|
|
1891
|
+
return {
|
|
1892
|
+
...value,
|
|
1893
|
+
eventId: `event:${++this.eventCounter}`,
|
|
1894
|
+
timestamp: this.nextTimestamp()
|
|
1895
|
+
};
|
|
1896
|
+
}
|
|
1897
|
+
maybeCreateEvent(value) {
|
|
1898
|
+
if (!hasCapability(this.capabilities, this.eventCapabilityForKind(value.kind))) {
|
|
1899
|
+
return void 0;
|
|
1900
|
+
}
|
|
1901
|
+
return this.createEvent(value);
|
|
1902
|
+
}
|
|
1903
|
+
createStepResult(sessionRef, pageRef, input) {
|
|
1904
|
+
const startedAt = this.nextTimestamp();
|
|
1905
|
+
const completedAt = this.nextTimestamp();
|
|
1906
|
+
return {
|
|
1907
|
+
stepId: `step:${++this.stepCounter}`,
|
|
1908
|
+
sessionRef,
|
|
1909
|
+
startedAt,
|
|
1910
|
+
completedAt,
|
|
1911
|
+
durationMs: completedAt - startedAt,
|
|
1912
|
+
events: input.events.map((event) => clone(event)),
|
|
1913
|
+
data: clone(input.data),
|
|
1914
|
+
...pageRef === void 0 ? {} : { pageRef },
|
|
1915
|
+
...input.frameRef === void 0 ? {} : { frameRef: input.frameRef },
|
|
1916
|
+
...input.documentRef === void 0 ? {} : { documentRef: input.documentRef },
|
|
1917
|
+
...input.documentEpoch === void 0 ? {} : { documentEpoch: input.documentEpoch }
|
|
1918
|
+
};
|
|
1919
|
+
}
|
|
1920
|
+
drainQueuedEvents(pageRef) {
|
|
1921
|
+
const page = this.requirePage(pageRef);
|
|
1922
|
+
const events = page.queuedEvents.splice(0, page.queuedEvents.length);
|
|
1923
|
+
return events.map((event) => clone(event));
|
|
1924
|
+
}
|
|
1925
|
+
requireSession(sessionRef) {
|
|
1926
|
+
const session = this.sessions.get(sessionRef);
|
|
1927
|
+
if (!session) {
|
|
1928
|
+
throw closedSessionError(sessionRef);
|
|
1929
|
+
}
|
|
1930
|
+
return session;
|
|
1931
|
+
}
|
|
1932
|
+
requirePage(pageRef) {
|
|
1933
|
+
const page = this.pages.get(pageRef);
|
|
1934
|
+
if (!page || page.lifecycleState === "closed") {
|
|
1935
|
+
throw closedPageError(pageRef);
|
|
1936
|
+
}
|
|
1937
|
+
return page;
|
|
1938
|
+
}
|
|
1939
|
+
requireFrame(frameRef) {
|
|
1940
|
+
const frame = this.frames.get(frameRef);
|
|
1941
|
+
if (!frame) {
|
|
1942
|
+
throw createBrowserCoreError("not-found", `frame ${frameRef} was not found`, {
|
|
1943
|
+
details: { frameRef }
|
|
1944
|
+
});
|
|
1945
|
+
}
|
|
1946
|
+
return frame;
|
|
1947
|
+
}
|
|
1948
|
+
requireDocument(documentRef) {
|
|
1949
|
+
const document = this.documents.get(documentRef);
|
|
1950
|
+
if (!document) {
|
|
1951
|
+
throw createBrowserCoreError("not-found", `document ${documentRef} was not found`, {
|
|
1952
|
+
details: { documentRef }
|
|
1953
|
+
});
|
|
1954
|
+
}
|
|
1955
|
+
return document;
|
|
1956
|
+
}
|
|
1957
|
+
getMainFrame(pageRef) {
|
|
1958
|
+
const page = this.requirePage(pageRef);
|
|
1959
|
+
const mainFrameRef = Array.from(page.frameRefs).find(
|
|
1960
|
+
(frameRef) => this.requireFrame(frameRef).frameInfo.isMainFrame
|
|
1961
|
+
);
|
|
1962
|
+
if (!mainFrameRef) {
|
|
1963
|
+
throw createBrowserCoreError("operation-failed", `page ${pageRef} has no main frame`);
|
|
1964
|
+
}
|
|
1965
|
+
return this.requireFrame(mainFrameRef);
|
|
1966
|
+
}
|
|
1967
|
+
getMainFrameInfo(pageRef) {
|
|
1968
|
+
return clone(this.getMainFrame(pageRef).frameInfo);
|
|
1969
|
+
}
|
|
1970
|
+
destroyPage(pageRef) {
|
|
1971
|
+
const page = this.requirePage(pageRef);
|
|
1972
|
+
page.lifecycleState = "closed";
|
|
1973
|
+
this.pages.delete(pageRef);
|
|
1974
|
+
const session = this.requireSession(page.sessionRef);
|
|
1975
|
+
session.pageRefs.delete(pageRef);
|
|
1976
|
+
for (const frameRef of page.frameRefs) {
|
|
1977
|
+
const frame = this.frames.get(frameRef);
|
|
1978
|
+
if (!frame) {
|
|
1979
|
+
continue;
|
|
1980
|
+
}
|
|
1981
|
+
this.documents.delete(frame.frameInfo.documentRef);
|
|
1982
|
+
this.frames.delete(frameRef);
|
|
1983
|
+
}
|
|
1984
|
+
}
|
|
1985
|
+
retireDocument(documentRef) {
|
|
1986
|
+
this.documents.delete(documentRef);
|
|
1987
|
+
this.retiredDocuments.add(documentRef);
|
|
1988
|
+
}
|
|
1989
|
+
nextTimestamp() {
|
|
1990
|
+
return this.timestampMs += 5;
|
|
1991
|
+
}
|
|
1992
|
+
};
|
|
1993
|
+
function createFakeBrowserCoreEngine(options = {}) {
|
|
1994
|
+
const capabilities = options.capabilities ?? allBrowserCapabilities();
|
|
1995
|
+
return new FakeBrowserCoreEngine({ ...options, capabilities });
|
|
1996
|
+
}
|
|
1997
|
+
|
|
1998
|
+
// src/cdp-dom-snapshot.ts
|
|
1999
|
+
var DOM_SNAPSHOT_COMPUTED_STYLE_NAMES = [
|
|
2000
|
+
"display",
|
|
2001
|
+
"visibility",
|
|
2002
|
+
"opacity",
|
|
2003
|
+
"position",
|
|
2004
|
+
"cursor",
|
|
2005
|
+
"overflow-x",
|
|
2006
|
+
"overflow-y"
|
|
2007
|
+
];
|
|
2008
|
+
function parseCdpStringTable(strings, index) {
|
|
2009
|
+
if (index === void 0 || index < 0) {
|
|
2010
|
+
return "";
|
|
2011
|
+
}
|
|
2012
|
+
return strings[index] ?? "";
|
|
2013
|
+
}
|
|
2014
|
+
function rareCdpStringValue(strings, data, index) {
|
|
2015
|
+
if (!data) {
|
|
2016
|
+
return void 0;
|
|
2017
|
+
}
|
|
2018
|
+
const matchIndex = data.index.findIndex((candidate) => candidate === index);
|
|
2019
|
+
if (matchIndex === -1) {
|
|
2020
|
+
return void 0;
|
|
2021
|
+
}
|
|
2022
|
+
return parseCdpStringTable(strings, data.value[matchIndex]);
|
|
2023
|
+
}
|
|
2024
|
+
function rareCdpIntegerValue(data, index) {
|
|
2025
|
+
if (!data) {
|
|
2026
|
+
return void 0;
|
|
2027
|
+
}
|
|
2028
|
+
const matchIndex = data.index.findIndex((candidate) => candidate === index);
|
|
2029
|
+
if (matchIndex === -1) {
|
|
2030
|
+
return void 0;
|
|
2031
|
+
}
|
|
2032
|
+
return data.value[matchIndex];
|
|
2033
|
+
}
|
|
2034
|
+
function normalizeCdpShadowRootType(value) {
|
|
2035
|
+
switch (value) {
|
|
2036
|
+
case "open":
|
|
2037
|
+
case "closed":
|
|
2038
|
+
return value;
|
|
2039
|
+
case "user-agent":
|
|
2040
|
+
case "user_agent":
|
|
2041
|
+
return "user-agent";
|
|
2042
|
+
default:
|
|
2043
|
+
return void 0;
|
|
2044
|
+
}
|
|
2045
|
+
}
|
|
2046
|
+
function buildCdpShadowBoundaryIndex(root) {
|
|
2047
|
+
const byBackendNodeId = /* @__PURE__ */ new Map();
|
|
2048
|
+
const visit = (node, boundary) => {
|
|
2049
|
+
if (node.backendNodeId !== void 0) {
|
|
2050
|
+
byBackendNodeId.set(node.backendNodeId, boundary);
|
|
2051
|
+
}
|
|
2052
|
+
for (const child of node.children ?? []) {
|
|
2053
|
+
visit(child, boundary);
|
|
2054
|
+
}
|
|
2055
|
+
for (const shadowRoot of node.shadowRoots ?? []) {
|
|
2056
|
+
const normalizedShadowRootType = normalizeCdpShadowRootType(shadowRoot.shadowRootType);
|
|
2057
|
+
const shadowBoundary = {
|
|
2058
|
+
...node.backendNodeId === void 0 ? {} : { shadowHostBackendNodeId: node.backendNodeId },
|
|
2059
|
+
...normalizedShadowRootType === void 0 ? {} : { shadowRootType: normalizedShadowRootType }
|
|
2060
|
+
};
|
|
2061
|
+
if (shadowRoot.backendNodeId !== void 0) {
|
|
2062
|
+
byBackendNodeId.set(shadowRoot.backendNodeId, shadowBoundary);
|
|
2063
|
+
}
|
|
2064
|
+
for (const child of shadowRoot.children ?? []) {
|
|
2065
|
+
visit(child, shadowBoundary);
|
|
2066
|
+
}
|
|
2067
|
+
}
|
|
2068
|
+
if (node.contentDocument) {
|
|
2069
|
+
visit(node.contentDocument, {});
|
|
2070
|
+
}
|
|
2071
|
+
};
|
|
2072
|
+
visit(root, {});
|
|
2073
|
+
return byBackendNodeId;
|
|
2074
|
+
}
|
|
2075
|
+
function buildDomSnapshotFromCdpCapture(document, captured, nodeRefResolver, contentDocRefResolver) {
|
|
2076
|
+
const parentIndexes = captured.rawDocument.nodes.parentIndex ?? [];
|
|
2077
|
+
const childIndexes = /* @__PURE__ */ new Map();
|
|
2078
|
+
for (let index = 0; index < parentIndexes.length; index += 1) {
|
|
2079
|
+
const parentIndex = parentIndexes[index];
|
|
2080
|
+
if (parentIndex === void 0 || parentIndex < 0) {
|
|
2081
|
+
continue;
|
|
2082
|
+
}
|
|
2083
|
+
const children = childIndexes.get(parentIndex) ?? [];
|
|
2084
|
+
children.push(index);
|
|
2085
|
+
childIndexes.set(parentIndex, children);
|
|
2086
|
+
}
|
|
2087
|
+
const layoutByNodeIndex = decodeLayoutByNodeIndex(captured.rawDocument, captured.strings);
|
|
2088
|
+
const aggregatedTextByNodeIndex = buildAggregatedTextIndex(
|
|
2089
|
+
captured.rawDocument,
|
|
2090
|
+
captured.shadowBoundariesByBackendNodeId,
|
|
2091
|
+
captured.strings
|
|
2092
|
+
);
|
|
2093
|
+
const rootNodeIndex = findRootNodeIndex(parentIndexes);
|
|
2094
|
+
const nodes = [];
|
|
2095
|
+
const nodeCount = captured.rawDocument.nodes.nodeType?.length ?? 0;
|
|
2096
|
+
for (let index = 0; index < nodeCount; index += 1) {
|
|
2097
|
+
const backendNodeId = captured.rawDocument.nodes.backendNodeId?.[index];
|
|
2098
|
+
const nodeRef = backendNodeId === void 0 ? void 0 : nodeRefResolver(backendNodeId);
|
|
2099
|
+
const rawAttributes = captured.rawDocument.nodes.attributes?.[index] ?? [];
|
|
2100
|
+
const attributes = [];
|
|
2101
|
+
for (let pairIndex = 0; pairIndex < rawAttributes.length; pairIndex += 2) {
|
|
2102
|
+
const nameIndex = rawAttributes[pairIndex];
|
|
2103
|
+
const valueIndex = rawAttributes[pairIndex + 1];
|
|
2104
|
+
if (nameIndex === void 0 || valueIndex === void 0) {
|
|
2105
|
+
continue;
|
|
2106
|
+
}
|
|
2107
|
+
attributes.push({
|
|
2108
|
+
name: parseCdpStringTable(captured.strings, nameIndex),
|
|
2109
|
+
value: parseCdpStringTable(captured.strings, valueIndex)
|
|
2110
|
+
});
|
|
2111
|
+
}
|
|
2112
|
+
const directShadowRootType = rareCdpStringValue(
|
|
2113
|
+
captured.strings,
|
|
2114
|
+
captured.rawDocument.nodes.shadowRootType,
|
|
2115
|
+
index
|
|
2116
|
+
);
|
|
2117
|
+
const normalizedShadowRootType = normalizeCdpShadowRootType(directShadowRootType);
|
|
2118
|
+
const shadowBoundary = backendNodeId === void 0 ? void 0 : captured.shadowBoundariesByBackendNodeId.get(backendNodeId);
|
|
2119
|
+
const shadowHostNodeRef = shadowBoundary?.shadowHostBackendNodeId === void 0 ? void 0 : nodeRefResolver(shadowBoundary.shadowHostBackendNodeId);
|
|
2120
|
+
const contentDocumentIndex = rareCdpIntegerValue(
|
|
2121
|
+
captured.rawDocument.nodes.contentDocumentIndex,
|
|
2122
|
+
index
|
|
2123
|
+
);
|
|
2124
|
+
const contentDocumentRef = contentDocumentIndex === void 0 ? void 0 : contentDocRefResolver(contentDocumentIndex);
|
|
2125
|
+
const layout = layoutByNodeIndex.get(index);
|
|
2126
|
+
const textContent = aggregatedTextByNodeIndex.get(index);
|
|
2127
|
+
const computedStyle = layout?.computedStyle ?? decodeInlineComputedStyle(attributes);
|
|
2128
|
+
nodes.push({
|
|
2129
|
+
snapshotNodeId: index + 1,
|
|
2130
|
+
...nodeRef === void 0 ? {} : { nodeRef },
|
|
2131
|
+
...parentIndexes[index] === void 0 || parentIndexes[index] < 0 ? {} : { parentSnapshotNodeId: parentIndexes[index] + 1 },
|
|
2132
|
+
childSnapshotNodeIds: (childIndexes.get(index) ?? []).map((childIndex) => childIndex + 1),
|
|
2133
|
+
...normalizedShadowRootType === void 0 ? {} : { shadowRootType: normalizedShadowRootType },
|
|
2134
|
+
...shadowHostNodeRef === void 0 ? {} : { shadowHostNodeRef },
|
|
2135
|
+
...contentDocumentRef === void 0 ? {} : { contentDocumentRef },
|
|
2136
|
+
nodeType: captured.rawDocument.nodes.nodeType?.[index] ?? 0,
|
|
2137
|
+
nodeName: parseCdpStringTable(captured.strings, captured.rawDocument.nodes.nodeName?.[index]),
|
|
2138
|
+
nodeValue: parseCdpStringTable(
|
|
2139
|
+
captured.strings,
|
|
2140
|
+
captured.rawDocument.nodes.nodeValue?.[index]
|
|
2141
|
+
),
|
|
2142
|
+
...textContent === void 0 || textContent.length === 0 ? {} : { textContent },
|
|
2143
|
+
...computedStyle === void 0 ? {} : { computedStyle },
|
|
2144
|
+
attributes,
|
|
2145
|
+
...layout?.rect === void 0 ? {} : {
|
|
2146
|
+
layout: {
|
|
2147
|
+
rect: layout.rect,
|
|
2148
|
+
quad: rectToQuad(layout.rect),
|
|
2149
|
+
...layout.paintOrder === void 0 ? {} : { paintOrder: layout.paintOrder }
|
|
2150
|
+
}
|
|
2151
|
+
}
|
|
2152
|
+
});
|
|
2153
|
+
}
|
|
2154
|
+
return {
|
|
2155
|
+
pageRef: document.pageRef,
|
|
2156
|
+
frameRef: document.frameRef,
|
|
2157
|
+
documentRef: document.documentRef,
|
|
2158
|
+
...document.parentDocumentRef === void 0 ? {} : { parentDocumentRef: document.parentDocumentRef },
|
|
2159
|
+
documentEpoch: document.documentEpoch,
|
|
2160
|
+
url: document.url,
|
|
2161
|
+
capturedAt: captured.capturedAt,
|
|
2162
|
+
rootSnapshotNodeId: rootNodeIndex + 1,
|
|
2163
|
+
shadowDomMode: "preserved",
|
|
2164
|
+
geometryCoordinateSpace: "document-css",
|
|
2165
|
+
nodes
|
|
2166
|
+
};
|
|
2167
|
+
}
|
|
2168
|
+
function findRootNodeIndex(parentIndexes) {
|
|
2169
|
+
const explicitRootIndex = parentIndexes.findIndex(
|
|
2170
|
+
(parentIndex) => parentIndex === void 0 || parentIndex < 0
|
|
2171
|
+
);
|
|
2172
|
+
return explicitRootIndex >= 0 ? explicitRootIndex : 0;
|
|
2173
|
+
}
|
|
2174
|
+
function decodeLayoutByNodeIndex(document, strings) {
|
|
2175
|
+
const byNodeIndex = /* @__PURE__ */ new Map();
|
|
2176
|
+
for (let layoutIndex = 0; layoutIndex < document.layout.nodeIndex.length; layoutIndex += 1) {
|
|
2177
|
+
const nodeIndex = document.layout.nodeIndex[layoutIndex];
|
|
2178
|
+
if (nodeIndex === void 0) {
|
|
2179
|
+
continue;
|
|
2180
|
+
}
|
|
2181
|
+
const bounds = document.layout.bounds[layoutIndex];
|
|
2182
|
+
const styleIndexes = document.layout.styles?.[layoutIndex];
|
|
2183
|
+
byNodeIndex.set(nodeIndex, {
|
|
2184
|
+
...bounds === void 0 ? {} : {
|
|
2185
|
+
rect: createRect(bounds[0] ?? 0, bounds[1] ?? 0, bounds[2] ?? 0, bounds[3] ?? 0)
|
|
2186
|
+
},
|
|
2187
|
+
...document.layout.paintOrders?.[layoutIndex] === void 0 ? {} : { paintOrder: document.layout.paintOrders[layoutIndex] },
|
|
2188
|
+
...styleIndexes === void 0 ? {} : { computedStyle: decodeComputedStyle(styleIndexes, strings) }
|
|
2189
|
+
});
|
|
2190
|
+
}
|
|
2191
|
+
return byNodeIndex;
|
|
2192
|
+
}
|
|
2193
|
+
function decodeComputedStyle(styleIndexes, strings) {
|
|
2194
|
+
const styleEntries = DOM_SNAPSHOT_COMPUTED_STYLE_NAMES.reduce(
|
|
2195
|
+
(out, propertyName, propertyIndex) => {
|
|
2196
|
+
const value = parseCdpStringTable(strings, styleIndexes[propertyIndex]);
|
|
2197
|
+
if (value.length > 0) {
|
|
2198
|
+
out[propertyName] = value;
|
|
2199
|
+
}
|
|
2200
|
+
return out;
|
|
2201
|
+
},
|
|
2202
|
+
{}
|
|
2203
|
+
);
|
|
2204
|
+
return {
|
|
2205
|
+
...styleEntries.display === void 0 ? {} : { display: styleEntries.display },
|
|
2206
|
+
...styleEntries.visibility === void 0 ? {} : { visibility: styleEntries.visibility },
|
|
2207
|
+
...styleEntries.opacity === void 0 ? {} : { opacity: styleEntries.opacity },
|
|
2208
|
+
...styleEntries.position === void 0 ? {} : { position: styleEntries.position },
|
|
2209
|
+
...styleEntries.cursor === void 0 ? {} : { cursor: styleEntries.cursor },
|
|
2210
|
+
...styleEntries["overflow-x"] === void 0 ? {} : { overflowX: styleEntries["overflow-x"] },
|
|
2211
|
+
...styleEntries["overflow-y"] === void 0 ? {} : { overflowY: styleEntries["overflow-y"] }
|
|
2212
|
+
};
|
|
2213
|
+
}
|
|
2214
|
+
function decodeInlineComputedStyle(attributes) {
|
|
2215
|
+
const styleAttribute = attributes.find((attribute) => attribute.name === "style")?.value;
|
|
2216
|
+
if (styleAttribute === void 0 || styleAttribute.trim().length === 0) {
|
|
2217
|
+
return void 0;
|
|
2218
|
+
}
|
|
2219
|
+
const styleEntries = /* @__PURE__ */ new Map();
|
|
2220
|
+
for (const declaration of styleAttribute.split(";")) {
|
|
2221
|
+
const separatorIndex = declaration.indexOf(":");
|
|
2222
|
+
if (separatorIndex <= 0) {
|
|
2223
|
+
continue;
|
|
2224
|
+
}
|
|
2225
|
+
const propertyName = declaration.slice(0, separatorIndex).trim().toLowerCase();
|
|
2226
|
+
const propertyValue = declaration.slice(separatorIndex + 1).trim();
|
|
2227
|
+
if (propertyName.length === 0 || propertyValue.length === 0) {
|
|
2228
|
+
continue;
|
|
2229
|
+
}
|
|
2230
|
+
styleEntries.set(propertyName, propertyValue);
|
|
2231
|
+
}
|
|
2232
|
+
const display = styleEntries.get("display");
|
|
2233
|
+
const visibility = styleEntries.get("visibility");
|
|
2234
|
+
const opacity = styleEntries.get("opacity");
|
|
2235
|
+
const position = styleEntries.get("position");
|
|
2236
|
+
const cursor = styleEntries.get("cursor");
|
|
2237
|
+
const overflow = styleEntries.get("overflow");
|
|
2238
|
+
const overflowX = styleEntries.get("overflow-x") ?? overflow;
|
|
2239
|
+
const overflowY = styleEntries.get("overflow-y") ?? overflow;
|
|
2240
|
+
const computedStyle = {
|
|
2241
|
+
...display === void 0 ? {} : { display },
|
|
2242
|
+
...visibility === void 0 ? {} : { visibility },
|
|
2243
|
+
...opacity === void 0 ? {} : { opacity },
|
|
2244
|
+
...position === void 0 ? {} : { position },
|
|
2245
|
+
...cursor === void 0 ? {} : { cursor },
|
|
2246
|
+
...overflowX === void 0 ? {} : { overflowX },
|
|
2247
|
+
...overflowY === void 0 ? {} : { overflowY }
|
|
2248
|
+
};
|
|
2249
|
+
return Object.keys(computedStyle).length === 0 ? void 0 : computedStyle;
|
|
2250
|
+
}
|
|
2251
|
+
function buildAggregatedTextIndex(document, shadowBoundariesByBackendNodeId, strings) {
|
|
2252
|
+
const parentIndexes = document.nodes.parentIndex ?? [];
|
|
2253
|
+
const backendNodeIds = document.nodes.backendNodeId ?? [];
|
|
2254
|
+
const childIndexes = /* @__PURE__ */ new Map();
|
|
2255
|
+
for (let index = 0; index < parentIndexes.length; index += 1) {
|
|
2256
|
+
const parentIndex = parentIndexes[index];
|
|
2257
|
+
if (parentIndex === void 0 || parentIndex < 0) {
|
|
2258
|
+
continue;
|
|
2259
|
+
}
|
|
2260
|
+
const children = childIndexes.get(parentIndex) ?? [];
|
|
2261
|
+
children.push(index);
|
|
2262
|
+
childIndexes.set(parentIndex, children);
|
|
2263
|
+
}
|
|
2264
|
+
const layoutTextByNodeIndex = /* @__PURE__ */ new Map();
|
|
2265
|
+
for (let layoutIndex = 0; layoutIndex < document.layout.nodeIndex.length; layoutIndex += 1) {
|
|
2266
|
+
const nodeIndex = document.layout.nodeIndex[layoutIndex];
|
|
2267
|
+
if (nodeIndex === void 0) {
|
|
2268
|
+
continue;
|
|
2269
|
+
}
|
|
2270
|
+
const text = parseCdpStringTable(strings, document.layout.text[layoutIndex]);
|
|
2271
|
+
if (text.length > 0) {
|
|
2272
|
+
layoutTextByNodeIndex.set(nodeIndex, text);
|
|
2273
|
+
}
|
|
2274
|
+
}
|
|
2275
|
+
const shadowHostBackendNodeIdByNodeIndex = /* @__PURE__ */ new Map();
|
|
2276
|
+
const resolveShadowHostBackendNodeId = (index) => {
|
|
2277
|
+
const existing = shadowHostBackendNodeIdByNodeIndex.get(index);
|
|
2278
|
+
if (existing !== void 0) {
|
|
2279
|
+
return existing;
|
|
2280
|
+
}
|
|
2281
|
+
const backendNodeId = backendNodeIds[index];
|
|
2282
|
+
const directShadowHostBackendNodeId = backendNodeId === void 0 ? void 0 : shadowBoundariesByBackendNodeId.get(backendNodeId)?.shadowHostBackendNodeId;
|
|
2283
|
+
if (directShadowHostBackendNodeId !== void 0) {
|
|
2284
|
+
shadowHostBackendNodeIdByNodeIndex.set(index, directShadowHostBackendNodeId);
|
|
2285
|
+
return directShadowHostBackendNodeId;
|
|
2286
|
+
}
|
|
2287
|
+
const parentIndex = parentIndexes[index];
|
|
2288
|
+
if (parentIndex === void 0 || parentIndex < 0) {
|
|
2289
|
+
shadowHostBackendNodeIdByNodeIndex.set(index, null);
|
|
2290
|
+
return null;
|
|
2291
|
+
}
|
|
2292
|
+
const inheritedShadowHostBackendNodeId = resolveShadowHostBackendNodeId(parentIndex);
|
|
2293
|
+
shadowHostBackendNodeIdByNodeIndex.set(index, inheritedShadowHostBackendNodeId);
|
|
2294
|
+
return inheritedShadowHostBackendNodeId;
|
|
2295
|
+
};
|
|
2296
|
+
const memo = /* @__PURE__ */ new Map();
|
|
2297
|
+
const visit = (index) => {
|
|
2298
|
+
const existing = memo.get(index);
|
|
2299
|
+
if (existing !== void 0) {
|
|
2300
|
+
return existing;
|
|
2301
|
+
}
|
|
2302
|
+
const nodeType = document.nodes.nodeType?.[index] ?? 0;
|
|
2303
|
+
const ownText = readOwnNodeText(document, strings, layoutTextByNodeIndex, index);
|
|
2304
|
+
if (nodeType === 3 || nodeType === 4) {
|
|
2305
|
+
memo.set(index, ownText);
|
|
2306
|
+
return ownText;
|
|
2307
|
+
}
|
|
2308
|
+
if (nodeType === 8 || nodeType === 10) {
|
|
2309
|
+
memo.set(index, "");
|
|
2310
|
+
return "";
|
|
2311
|
+
}
|
|
2312
|
+
let text = ownText;
|
|
2313
|
+
const currentShadowHostBackendNodeId = resolveShadowHostBackendNodeId(index);
|
|
2314
|
+
for (const childIndex of childIndexes.get(index) ?? []) {
|
|
2315
|
+
if (resolveShadowHostBackendNodeId(childIndex) !== currentShadowHostBackendNodeId) {
|
|
2316
|
+
continue;
|
|
2317
|
+
}
|
|
2318
|
+
text += visit(childIndex);
|
|
2319
|
+
}
|
|
2320
|
+
memo.set(index, text);
|
|
2321
|
+
return text;
|
|
2322
|
+
};
|
|
2323
|
+
const aggregated = /* @__PURE__ */ new Map();
|
|
2324
|
+
const nodeCount = document.nodes.nodeType?.length ?? 0;
|
|
2325
|
+
for (let index = 0; index < nodeCount; index += 1) {
|
|
2326
|
+
const text = visit(index);
|
|
2327
|
+
if (text.length > 0) {
|
|
2328
|
+
aggregated.set(index, text);
|
|
2329
|
+
}
|
|
2330
|
+
}
|
|
2331
|
+
return aggregated;
|
|
2332
|
+
}
|
|
2333
|
+
function readOwnNodeText(document, strings, layoutTextByNodeIndex, index) {
|
|
2334
|
+
return rareCdpStringValue(strings, document.nodes.textValue, index) || rareCdpStringValue(strings, document.nodes.inputValue, index) || (document.nodes.nodeType?.[index] === 3 || document.nodes.nodeType?.[index] === 4 ? parseCdpStringTable(strings, document.nodes.nodeValue?.[index]) || layoutTextByNodeIndex.get(index) || "" : "");
|
|
2335
|
+
}
|
|
2336
|
+
|
|
2337
|
+
// src/cdp-visual-stability.ts
|
|
2338
|
+
var DEFAULT_VISUAL_STABILITY_TIMEOUT_MS = 3e4;
|
|
2339
|
+
var DEFAULT_VISUAL_STABILITY_SETTLE_MS = 750;
|
|
2340
|
+
var FRAME_EVALUATE_GRACE_MS = 200;
|
|
2341
|
+
var TRANSIENT_CONTEXT_RETRY_DELAY_MS = 25;
|
|
2342
|
+
var STEALTH_WORLD_NAME = "__opensteer_wait__";
|
|
2343
|
+
var FRAME_OWNER_VISIBILITY_FUNCTION = `function() {
|
|
2344
|
+
if (!(this instanceof HTMLElement)) return false;
|
|
2345
|
+
|
|
2346
|
+
var rect = this.getBoundingClientRect();
|
|
2347
|
+
if (rect.width <= 0 || rect.height <= 0) return false;
|
|
2348
|
+
if (
|
|
2349
|
+
rect.bottom <= 0 ||
|
|
2350
|
+
rect.right <= 0 ||
|
|
2351
|
+
rect.top >= window.innerHeight ||
|
|
2352
|
+
rect.left >= window.innerWidth
|
|
2353
|
+
) {
|
|
2354
|
+
return false;
|
|
2355
|
+
}
|
|
2356
|
+
|
|
2357
|
+
var style = window.getComputedStyle(this);
|
|
2358
|
+
if (
|
|
2359
|
+
style.display === 'none' ||
|
|
2360
|
+
style.visibility === 'hidden' ||
|
|
2361
|
+
Number(style.opacity) === 0
|
|
2362
|
+
) {
|
|
2363
|
+
return false;
|
|
2364
|
+
}
|
|
2365
|
+
|
|
2366
|
+
return true;
|
|
2367
|
+
}`;
|
|
2368
|
+
async function waitForCdpVisualStability(cdp, options = {}) {
|
|
2369
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_VISUAL_STABILITY_TIMEOUT_MS;
|
|
2370
|
+
const settleMs = options.settleMs ?? DEFAULT_VISUAL_STABILITY_SETTLE_MS;
|
|
2371
|
+
const scope = options.scope ?? "main-frame";
|
|
2372
|
+
if (timeoutMs <= 0) {
|
|
2373
|
+
return;
|
|
2374
|
+
}
|
|
2375
|
+
const runtime = new StealthCdpRuntime(cdp);
|
|
2376
|
+
if (scope === "visible-frames") {
|
|
2377
|
+
await runtime.waitForVisibleFramesVisualStability(timeoutMs, settleMs);
|
|
2378
|
+
return;
|
|
2379
|
+
}
|
|
2380
|
+
await runtime.waitForMainFrameVisualStability(timeoutMs, settleMs);
|
|
2381
|
+
}
|
|
2382
|
+
function buildStabilityScript(timeout, settleMs) {
|
|
2383
|
+
return `new Promise(function(resolve) {
|
|
2384
|
+
var deadline = Date.now() + ${timeout};
|
|
2385
|
+
var resolved = false;
|
|
2386
|
+
var timer = null;
|
|
2387
|
+
var observers = [];
|
|
2388
|
+
var observedShadowRoots = [];
|
|
2389
|
+
var fonts = document.fonts;
|
|
2390
|
+
var fontsReady = !fonts || fonts.status === 'loaded';
|
|
2391
|
+
var lastRelevantMutationAt = Date.now();
|
|
2392
|
+
|
|
2393
|
+
function clearObservers() {
|
|
2394
|
+
for (var i = 0; i < observers.length; i++) {
|
|
2395
|
+
observers[i].disconnect();
|
|
2396
|
+
}
|
|
2397
|
+
observers = [];
|
|
2398
|
+
}
|
|
2399
|
+
|
|
2400
|
+
function done() {
|
|
2401
|
+
if (resolved) return;
|
|
2402
|
+
resolved = true;
|
|
2403
|
+
if (timer) clearTimeout(timer);
|
|
2404
|
+
if (safetyTimer) clearTimeout(safetyTimer);
|
|
2405
|
+
clearObservers();
|
|
2406
|
+
resolve();
|
|
2407
|
+
}
|
|
2408
|
+
|
|
2409
|
+
function isElementVisiblyIntersectingViewport(element) {
|
|
2410
|
+
if (!(element instanceof Element)) return false;
|
|
2411
|
+
|
|
2412
|
+
var rect = element.getBoundingClientRect();
|
|
2413
|
+
var inViewport =
|
|
2414
|
+
rect.width > 0 &&
|
|
2415
|
+
rect.height > 0 &&
|
|
2416
|
+
rect.bottom > 0 &&
|
|
2417
|
+
rect.right > 0 &&
|
|
2418
|
+
rect.top < window.innerHeight &&
|
|
2419
|
+
rect.left < window.innerWidth;
|
|
2420
|
+
|
|
2421
|
+
if (!inViewport) return false;
|
|
2422
|
+
|
|
2423
|
+
var style = window.getComputedStyle(element);
|
|
2424
|
+
if (style.visibility === 'hidden' || style.display === 'none') {
|
|
2425
|
+
return false;
|
|
2426
|
+
}
|
|
2427
|
+
if (Number(style.opacity) === 0) {
|
|
2428
|
+
return false;
|
|
2429
|
+
}
|
|
2430
|
+
|
|
2431
|
+
return true;
|
|
2432
|
+
}
|
|
2433
|
+
|
|
2434
|
+
function resolveRelevantElement(node) {
|
|
2435
|
+
if (!node) return null;
|
|
2436
|
+
if (node instanceof Element) return node;
|
|
2437
|
+
if (typeof ShadowRoot !== 'undefined' && node instanceof ShadowRoot) {
|
|
2438
|
+
return node.host instanceof Element ? node.host : null;
|
|
2439
|
+
}
|
|
2440
|
+
var parentElement = node.parentElement;
|
|
2441
|
+
return parentElement instanceof Element ? parentElement : null;
|
|
2442
|
+
}
|
|
2443
|
+
|
|
2444
|
+
function isNodeVisiblyRelevant(node) {
|
|
2445
|
+
var element = resolveRelevantElement(node);
|
|
2446
|
+
if (!element) return false;
|
|
2447
|
+
return isElementVisiblyIntersectingViewport(element);
|
|
2448
|
+
}
|
|
2449
|
+
|
|
2450
|
+
function hasRelevantMutation(records) {
|
|
2451
|
+
for (var i = 0; i < records.length; i++) {
|
|
2452
|
+
var record = records[i];
|
|
2453
|
+
if (isNodeVisiblyRelevant(record.target)) return true;
|
|
2454
|
+
|
|
2455
|
+
var addedNodes = record.addedNodes;
|
|
2456
|
+
for (var j = 0; j < addedNodes.length; j++) {
|
|
2457
|
+
if (isNodeVisiblyRelevant(addedNodes[j])) return true;
|
|
2458
|
+
}
|
|
2459
|
+
|
|
2460
|
+
var removedNodes = record.removedNodes;
|
|
2461
|
+
for (var k = 0; k < removedNodes.length; k++) {
|
|
2462
|
+
if (isNodeVisiblyRelevant(removedNodes[k])) return true;
|
|
2463
|
+
}
|
|
2464
|
+
}
|
|
2465
|
+
|
|
2466
|
+
return false;
|
|
2467
|
+
}
|
|
2468
|
+
|
|
2469
|
+
function scheduleCheck() {
|
|
2470
|
+
if (resolved) return;
|
|
2471
|
+
if (timer) clearTimeout(timer);
|
|
2472
|
+
|
|
2473
|
+
var remaining = deadline - Date.now();
|
|
2474
|
+
if (remaining <= 0) {
|
|
2475
|
+
done();
|
|
2476
|
+
return;
|
|
2477
|
+
}
|
|
2478
|
+
|
|
2479
|
+
var checkDelay = Math.min(120, Math.max(16, ${settleMs}));
|
|
2480
|
+
timer = setTimeout(checkNow, checkDelay);
|
|
2481
|
+
}
|
|
2482
|
+
|
|
2483
|
+
function observeMutations(target) {
|
|
2484
|
+
if (!target) return;
|
|
2485
|
+
var observer = new MutationObserver(function(records) {
|
|
2486
|
+
if (!hasRelevantMutation(records)) return;
|
|
2487
|
+
lastRelevantMutationAt = Date.now();
|
|
2488
|
+
scheduleCheck();
|
|
2489
|
+
});
|
|
2490
|
+
observer.observe(target, {
|
|
2491
|
+
childList: true,
|
|
2492
|
+
subtree: true,
|
|
2493
|
+
attributes: true,
|
|
2494
|
+
characterData: true
|
|
2495
|
+
});
|
|
2496
|
+
observers.push(observer);
|
|
2497
|
+
}
|
|
2498
|
+
|
|
2499
|
+
function hasObservedShadowRoot(root) {
|
|
2500
|
+
for (var i = 0; i < observedShadowRoots.length; i++) {
|
|
2501
|
+
if (observedShadowRoots[i] === root) return true;
|
|
2502
|
+
}
|
|
2503
|
+
return false;
|
|
2504
|
+
}
|
|
2505
|
+
|
|
2506
|
+
function observeOpenShadowRoots() {
|
|
2507
|
+
if (!document.documentElement || !document.createTreeWalker) return;
|
|
2508
|
+
var walker = document.createTreeWalker(
|
|
2509
|
+
document.documentElement,
|
|
2510
|
+
NodeFilter.SHOW_ELEMENT
|
|
2511
|
+
);
|
|
2512
|
+
while (walker.nextNode()) {
|
|
2513
|
+
var current = walker.currentNode;
|
|
2514
|
+
if (!(current instanceof Element)) continue;
|
|
2515
|
+
var shadowRoot = current.shadowRoot;
|
|
2516
|
+
if (!shadowRoot || shadowRoot.mode !== 'open') continue;
|
|
2517
|
+
if (hasObservedShadowRoot(shadowRoot)) continue;
|
|
2518
|
+
observedShadowRoots.push(shadowRoot);
|
|
2519
|
+
observeMutations(shadowRoot);
|
|
2520
|
+
}
|
|
2521
|
+
}
|
|
2522
|
+
|
|
2523
|
+
function checkViewportImages(root) {
|
|
2524
|
+
var images = root.querySelectorAll('img');
|
|
2525
|
+
for (var i = 0; i < images.length; i++) {
|
|
2526
|
+
var img = images[i];
|
|
2527
|
+
if (!isElementVisiblyIntersectingViewport(img)) continue;
|
|
2528
|
+
if (!img.complete) return false;
|
|
2529
|
+
}
|
|
2530
|
+
return true;
|
|
2531
|
+
}
|
|
2532
|
+
|
|
2533
|
+
function getAnimationTarget(effect) {
|
|
2534
|
+
if (!effect) return null;
|
|
2535
|
+
var target = effect.target;
|
|
2536
|
+
if (target instanceof Element) return target;
|
|
2537
|
+
|
|
2538
|
+
if (target && target.element instanceof Element) {
|
|
2539
|
+
return target.element;
|
|
2540
|
+
}
|
|
2541
|
+
|
|
2542
|
+
return null;
|
|
2543
|
+
}
|
|
2544
|
+
|
|
2545
|
+
function hasRunningVisibleFiniteAnimations() {
|
|
2546
|
+
if (typeof document.getAnimations !== 'function') return false;
|
|
2547
|
+
var animations = document.getAnimations();
|
|
2548
|
+
|
|
2549
|
+
for (var i = 0; i < animations.length; i++) {
|
|
2550
|
+
var animation = animations[i];
|
|
2551
|
+
if (!animation || animation.playState !== 'running') continue;
|
|
2552
|
+
var effect = animation.effect;
|
|
2553
|
+
if (!effect || typeof effect.getComputedTiming !== 'function') continue;
|
|
2554
|
+
var timing = effect.getComputedTiming();
|
|
2555
|
+
var endTime = timing && typeof timing.endTime === 'number'
|
|
2556
|
+
? timing.endTime
|
|
2557
|
+
: Number.POSITIVE_INFINITY;
|
|
2558
|
+
if (Number.isFinite(endTime) && endTime > 0) {
|
|
2559
|
+
var target = getAnimationTarget(effect);
|
|
2560
|
+
if (!target) continue;
|
|
2561
|
+
if (!isElementVisiblyIntersectingViewport(target)) continue;
|
|
2562
|
+
return true;
|
|
2563
|
+
}
|
|
2564
|
+
}
|
|
2565
|
+
|
|
2566
|
+
return false;
|
|
2567
|
+
}
|
|
2568
|
+
|
|
2569
|
+
function isVisuallyReady() {
|
|
2570
|
+
if (!fontsReady) return false;
|
|
2571
|
+
if (!checkViewportImages(document)) return false;
|
|
2572
|
+
if (hasRunningVisibleFiniteAnimations()) return false;
|
|
2573
|
+
return true;
|
|
2574
|
+
}
|
|
2575
|
+
|
|
2576
|
+
function checkNow() {
|
|
2577
|
+
if (Date.now() >= deadline) {
|
|
2578
|
+
done();
|
|
2579
|
+
return;
|
|
2580
|
+
}
|
|
2581
|
+
|
|
2582
|
+
observeOpenShadowRoots();
|
|
2583
|
+
|
|
2584
|
+
if (!isVisuallyReady()) {
|
|
2585
|
+
scheduleCheck();
|
|
2586
|
+
return;
|
|
2587
|
+
}
|
|
2588
|
+
|
|
2589
|
+
if (Date.now() - lastRelevantMutationAt >= ${settleMs}) {
|
|
2590
|
+
done();
|
|
2591
|
+
return;
|
|
2592
|
+
}
|
|
2593
|
+
|
|
2594
|
+
scheduleCheck();
|
|
2595
|
+
}
|
|
2596
|
+
|
|
2597
|
+
observeMutations(document.documentElement);
|
|
2598
|
+
observeOpenShadowRoots();
|
|
2599
|
+
|
|
2600
|
+
if (fonts && fonts.ready && typeof fonts.ready.then === 'function') {
|
|
2601
|
+
fonts.ready.then(function() {
|
|
2602
|
+
fontsReady = true;
|
|
2603
|
+
scheduleCheck();
|
|
2604
|
+
}, function() {
|
|
2605
|
+
fontsReady = true;
|
|
2606
|
+
scheduleCheck();
|
|
2607
|
+
});
|
|
2608
|
+
}
|
|
2609
|
+
|
|
2610
|
+
var safetyTimer = setTimeout(done, ${timeout});
|
|
2611
|
+
|
|
2612
|
+
scheduleCheck();
|
|
2613
|
+
})`;
|
|
2614
|
+
}
|
|
2615
|
+
var StealthCdpRuntime = class {
|
|
2616
|
+
constructor(session) {
|
|
2617
|
+
this.session = session;
|
|
2618
|
+
}
|
|
2619
|
+
contextsByFrame = /* @__PURE__ */ new Map();
|
|
2620
|
+
async waitForMainFrameVisualStability(timeoutMs, settleMs) {
|
|
2621
|
+
const frameRecords = await this.getFrameRecords();
|
|
2622
|
+
const mainFrame = frameRecords[0];
|
|
2623
|
+
if (!mainFrame) {
|
|
2624
|
+
return;
|
|
2625
|
+
}
|
|
2626
|
+
await this.waitForFrameVisualStability(mainFrame.frameId, timeoutMs, settleMs, true);
|
|
2627
|
+
}
|
|
2628
|
+
async waitForVisibleFramesVisualStability(timeoutMs, settleMs) {
|
|
2629
|
+
const deadline = Date.now() + timeoutMs;
|
|
2630
|
+
while (true) {
|
|
2631
|
+
const remaining = Math.max(0, deadline - Date.now());
|
|
2632
|
+
if (remaining === 0) {
|
|
2633
|
+
return;
|
|
2634
|
+
}
|
|
2635
|
+
const frameIds = await this.collectVisibleFrameIds();
|
|
2636
|
+
if (frameIds.length === 0) {
|
|
2637
|
+
return;
|
|
2638
|
+
}
|
|
2639
|
+
await Promise.all(
|
|
2640
|
+
frameIds.map(async (frameId) => {
|
|
2641
|
+
try {
|
|
2642
|
+
await this.waitForFrameVisualStability(frameId, remaining, settleMs, false);
|
|
2643
|
+
} catch (error) {
|
|
2644
|
+
if (isIgnorableFrameError(error)) {
|
|
2645
|
+
return;
|
|
2646
|
+
}
|
|
2647
|
+
throw error;
|
|
2648
|
+
}
|
|
2649
|
+
})
|
|
2650
|
+
);
|
|
2651
|
+
const currentFrameIds = await this.collectVisibleFrameIds();
|
|
2652
|
+
if (sameFrameIds(frameIds, currentFrameIds)) {
|
|
2653
|
+
return;
|
|
2654
|
+
}
|
|
2655
|
+
}
|
|
2656
|
+
}
|
|
2657
|
+
async getFrameRecords() {
|
|
2658
|
+
const treeResult = await this.session.send("Page.getFrameTree");
|
|
2659
|
+
const records = [];
|
|
2660
|
+
walkFrameTree(treeResult.frameTree, null, records);
|
|
2661
|
+
return records;
|
|
2662
|
+
}
|
|
2663
|
+
async collectVisibleFrameIds() {
|
|
2664
|
+
const frameRecords = await this.getFrameRecords();
|
|
2665
|
+
if (frameRecords.length === 0) {
|
|
2666
|
+
return [];
|
|
2667
|
+
}
|
|
2668
|
+
const visibleFrameIds = [];
|
|
2669
|
+
for (const frameRecord of frameRecords) {
|
|
2670
|
+
if (!frameRecord.parentFrameId) {
|
|
2671
|
+
visibleFrameIds.push(frameRecord.frameId);
|
|
2672
|
+
continue;
|
|
2673
|
+
}
|
|
2674
|
+
try {
|
|
2675
|
+
const parentContextId = await this.ensureFrameContextId(frameRecord.parentFrameId);
|
|
2676
|
+
if (await this.isFrameOwnerVisible(frameRecord.frameId, parentContextId)) {
|
|
2677
|
+
visibleFrameIds.push(frameRecord.frameId);
|
|
2678
|
+
}
|
|
2679
|
+
} catch (error) {
|
|
2680
|
+
if (isIgnorableFrameError(error)) {
|
|
2681
|
+
continue;
|
|
2682
|
+
}
|
|
2683
|
+
throw error;
|
|
2684
|
+
}
|
|
2685
|
+
}
|
|
2686
|
+
return visibleFrameIds;
|
|
2687
|
+
}
|
|
2688
|
+
async ensureFrameContextId(frameId) {
|
|
2689
|
+
const existing = this.contextsByFrame.get(frameId);
|
|
2690
|
+
if (existing !== void 0) {
|
|
2691
|
+
return existing;
|
|
2692
|
+
}
|
|
2693
|
+
const world = await this.session.send("Page.createIsolatedWorld", {
|
|
2694
|
+
frameId,
|
|
2695
|
+
worldName: STEALTH_WORLD_NAME
|
|
2696
|
+
});
|
|
2697
|
+
this.contextsByFrame.set(frameId, world.executionContextId);
|
|
2698
|
+
return world.executionContextId;
|
|
2699
|
+
}
|
|
2700
|
+
async waitForFrameVisualStability(frameId, timeoutMs, settleMs, retryTransientContextErrors) {
|
|
2701
|
+
if (timeoutMs <= 0) {
|
|
2702
|
+
return;
|
|
2703
|
+
}
|
|
2704
|
+
const script = buildStabilityScript(timeoutMs, settleMs);
|
|
2705
|
+
if (!retryTransientContextErrors) {
|
|
2706
|
+
let contextId = await this.ensureFrameContextId(frameId);
|
|
2707
|
+
try {
|
|
2708
|
+
await this.evaluateWithGuard(contextId, script, timeoutMs);
|
|
2709
|
+
} catch (error) {
|
|
2710
|
+
if (!isMissingExecutionContextError(error)) {
|
|
2711
|
+
throw error;
|
|
2712
|
+
}
|
|
2713
|
+
this.contextsByFrame.delete(frameId);
|
|
2714
|
+
contextId = await this.ensureFrameContextId(frameId);
|
|
2715
|
+
await this.evaluateWithGuard(contextId, script, timeoutMs);
|
|
2716
|
+
}
|
|
2717
|
+
return;
|
|
2718
|
+
}
|
|
2719
|
+
const deadline = Date.now() + timeoutMs;
|
|
2720
|
+
while (true) {
|
|
2721
|
+
const remaining = Math.max(0, deadline - Date.now());
|
|
2722
|
+
if (remaining === 0) {
|
|
2723
|
+
return;
|
|
2724
|
+
}
|
|
2725
|
+
const contextId = await this.ensureFrameContextId(frameId);
|
|
2726
|
+
try {
|
|
2727
|
+
await this.evaluateWithGuard(contextId, script, remaining);
|
|
2728
|
+
return;
|
|
2729
|
+
} catch (error) {
|
|
2730
|
+
if (!isTransientExecutionContextError(error)) {
|
|
2731
|
+
throw error;
|
|
2732
|
+
}
|
|
2733
|
+
this.contextsByFrame.delete(frameId);
|
|
2734
|
+
await sleep(Math.min(TRANSIENT_CONTEXT_RETRY_DELAY_MS, Math.max(0, deadline - Date.now())));
|
|
2735
|
+
}
|
|
2736
|
+
}
|
|
2737
|
+
}
|
|
2738
|
+
async evaluateWithGuard(contextId, script, timeoutMs) {
|
|
2739
|
+
const guardedPromise = this.evaluateScript(contextId, script).then(() => ({ kind: "resolved" })).catch((error) => ({ kind: "rejected", error }));
|
|
2740
|
+
const timeoutPromise = new Promise((resolve) => {
|
|
2741
|
+
setTimeout(() => resolve({ kind: "timeout" }), timeoutMs + FRAME_EVALUATE_GRACE_MS);
|
|
2742
|
+
});
|
|
2743
|
+
const outcome = await Promise.race([guardedPromise, timeoutPromise]);
|
|
2744
|
+
if (outcome.kind === "rejected") {
|
|
2745
|
+
throw outcome.error;
|
|
2746
|
+
}
|
|
2747
|
+
}
|
|
2748
|
+
async evaluateScript(contextId, script) {
|
|
2749
|
+
const evaluated = await this.session.send("Runtime.evaluate", {
|
|
2750
|
+
contextId,
|
|
2751
|
+
expression: script,
|
|
2752
|
+
returnByValue: true,
|
|
2753
|
+
awaitPromise: true
|
|
2754
|
+
});
|
|
2755
|
+
if (evaluated.exceptionDetails) {
|
|
2756
|
+
throw new Error(formatCdpException(evaluated.exceptionDetails));
|
|
2757
|
+
}
|
|
2758
|
+
}
|
|
2759
|
+
async isFrameOwnerVisible(frameId, executionContextId) {
|
|
2760
|
+
const frameOwner = await this.session.send("DOM.getFrameOwner", {
|
|
2761
|
+
frameId
|
|
2762
|
+
});
|
|
2763
|
+
if (frameOwner.backendNodeId === void 0) {
|
|
2764
|
+
return false;
|
|
2765
|
+
}
|
|
2766
|
+
const resolved = await this.session.send("DOM.resolveNode", {
|
|
2767
|
+
backendNodeId: frameOwner.backendNodeId,
|
|
2768
|
+
executionContextId
|
|
2769
|
+
});
|
|
2770
|
+
const objectId = resolved.object?.objectId;
|
|
2771
|
+
if (!objectId) {
|
|
2772
|
+
return false;
|
|
2773
|
+
}
|
|
2774
|
+
try {
|
|
2775
|
+
const callResult = await this.session.send("Runtime.callFunctionOn", {
|
|
2776
|
+
objectId,
|
|
2777
|
+
functionDeclaration: FRAME_OWNER_VISIBILITY_FUNCTION,
|
|
2778
|
+
returnByValue: true
|
|
2779
|
+
});
|
|
2780
|
+
if (callResult.exceptionDetails) {
|
|
2781
|
+
throw new Error(formatCdpException(callResult.exceptionDetails));
|
|
2782
|
+
}
|
|
2783
|
+
return callResult.result.value === true;
|
|
2784
|
+
} finally {
|
|
2785
|
+
await this.releaseObject(objectId);
|
|
2786
|
+
}
|
|
2787
|
+
}
|
|
2788
|
+
async releaseObject(objectId) {
|
|
2789
|
+
await this.session.send("Runtime.releaseObject", {
|
|
2790
|
+
objectId
|
|
2791
|
+
}).catch(() => void 0);
|
|
2792
|
+
}
|
|
2793
|
+
};
|
|
2794
|
+
function walkFrameTree(node, parentFrameId, records) {
|
|
2795
|
+
const frameId = node.frame?.id;
|
|
2796
|
+
if (!frameId) {
|
|
2797
|
+
return;
|
|
2798
|
+
}
|
|
2799
|
+
records.push({
|
|
2800
|
+
frameId,
|
|
2801
|
+
parentFrameId
|
|
2802
|
+
});
|
|
2803
|
+
for (const child of node.childFrames ?? []) {
|
|
2804
|
+
walkFrameTree(child, frameId, records);
|
|
2805
|
+
}
|
|
2806
|
+
}
|
|
2807
|
+
function sameFrameIds(before, after) {
|
|
2808
|
+
if (before.length !== after.length) {
|
|
2809
|
+
return false;
|
|
2810
|
+
}
|
|
2811
|
+
return before.every((frameId) => after.includes(frameId));
|
|
2812
|
+
}
|
|
2813
|
+
function formatCdpException(details) {
|
|
2814
|
+
return details.exception?.description || details.text || "CDP runtime evaluation failed.";
|
|
2815
|
+
}
|
|
2816
|
+
function isIgnorableFrameError(error) {
|
|
2817
|
+
if (!(error instanceof Error)) {
|
|
2818
|
+
return false;
|
|
2819
|
+
}
|
|
2820
|
+
const message = error.message;
|
|
2821
|
+
return message.includes("Frame with the given id was not found") || message.includes("No frame for given id found") || isTransientExecutionContextError(error);
|
|
2822
|
+
}
|
|
2823
|
+
function isTransientExecutionContextError(error) {
|
|
2824
|
+
if (!(error instanceof Error)) {
|
|
2825
|
+
return false;
|
|
2826
|
+
}
|
|
2827
|
+
const message = error.message;
|
|
2828
|
+
return message.includes("Execution context was destroyed") || message.includes("Cannot find context with specified id") || message.includes("Cannot find execution context");
|
|
2829
|
+
}
|
|
2830
|
+
function isMissingExecutionContextError(error) {
|
|
2831
|
+
if (!(error instanceof Error)) {
|
|
2832
|
+
return false;
|
|
2833
|
+
}
|
|
2834
|
+
const message = error.message;
|
|
2835
|
+
return message.includes("Cannot find context with specified id") || message.includes("Cannot find execution context");
|
|
2836
|
+
}
|
|
2837
|
+
function sleep(ms) {
|
|
2838
|
+
if (ms <= 0) {
|
|
2839
|
+
return Promise.resolve();
|
|
2840
|
+
}
|
|
2841
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
2842
|
+
}
|
|
2843
|
+
|
|
2844
|
+
export { BrowserCoreError, DEFAULT_VISUAL_STABILITY_SETTLE_MS, DEFAULT_VISUAL_STABILITY_TIMEOUT_MS, DOM_SNAPSHOT_COMPUTED_STYLE_NAMES, FakeBrowserCoreEngine, allBrowserCapabilities, bodyPayloadFromUtf8, brand, buildCdpShadowBoundaryIndex, buildDomSnapshotFromCdpCapture, closedPageError, closedSessionError, createBodyPayload, createBrowserCoreError, createChooserRef, createDevicePixelRatio, createDialogRef, createDocumentEpoch, createDocumentRef, createDownloadRef, createFakeBrowserCoreEngine, createFrameRef, createHeaderEntry, createNetworkRequestId, createNodeLocator, createNodeRef, createPageRef, createPageScaleFactor, createPageZoomFactor, createPoint, createQuad, createRect, createScrollOffset, createSessionRef, createSize, createWorkerRef, filterCookieRecords, findDomSnapshotNode, findDomSnapshotNodeByRef, hasCapability, isBrowserCoreError, isChooserRef, isDialogRef, isDocumentRef, isDownloadRef, isFrameRef, isNetworkRequestId, isNodeRef, isPageRef, isSessionRef, isWorkerRef, matchesNetworkRecordFilters, mergeBrowserCapabilities, nextDocumentEpoch, noBrowserCapabilities, normalizeCdpShadowRootType, parseCdpStringTable, quadBounds, rareCdpIntegerValue, rareCdpStringValue, rectContainsPoint, rectToQuad, serializeDocumentEpoch, serializeRef, staleNodeRefError, unsupportedCapabilityError, waitForCdpVisualStability };
|
|
2845
|
+
//# sourceMappingURL=index.js.map
|
|
2846
|
+
//# sourceMappingURL=index.js.map
|