@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/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