@orkestrel/browser 0.0.6 → 0.0.8

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.
@@ -1,5 +1,6 @@
1
- import { attempt, instanceOf, isArray, isBoolean, isFiniteNumber, isInstance, isInteger, isRecord, isString, parseArray, parseEnum, parseJSON } from "@orkestrel/contract";
1
+ import { attempt, instanceOf, isArray, isBoolean, isFiniteNumber, isFunction, isInstance, isInteger, isRecord, isString, parseArray, parseEnum, parseJSON } from "@orkestrel/contract";
2
2
  import { Emitter } from "@orkestrel/emitter";
3
+ import { createHTML, renderText } from "@orkestrel/html";
3
4
  //#region src/core/constants.ts
4
5
  /** Base64 alphabet, index-ordered, used to build {@link BASE64_LOOKUP}. */
5
6
  var BASE64_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
@@ -74,7 +75,7 @@ var BROWSER_MOUSE_BUTTON_MASKS = Object.freeze({
74
75
  /** Tool identity embedded in HAR 1.2 documents. */
75
76
  var BROWSER_HAR_CREATOR = Object.freeze({
76
77
  name: "@orkestrel/browser",
77
- version: "0.0.5"
78
+ version: "0.0.8"
78
79
  });
79
80
  /** Attribute used to tag temporary screenshot styles and masks. */
80
81
  var BROWSER_SCREENSHOT_ATTRIBUTE = "data-orkestrel-screenshot";
@@ -558,10 +559,10 @@ function createBrowserHAREntry(pending, duration, body, error) {
558
559
  cookies: [],
559
560
  headers: requestHeaders,
560
561
  queryString: query,
561
- postData: post === void 0 ? void 0 : {
562
+ ...post !== void 0 ? { postData: {
562
563
  mimeType: requestMime,
563
564
  text: post
564
- },
565
+ } } : {},
565
566
  headersSize: -1,
566
567
  bodySize: post === void 0 ? 0 : textToBytes(post).byteLength
567
568
  },
@@ -574,8 +575,10 @@ function createBrowserHAREntry(pending, duration, body, error) {
574
575
  content: {
575
576
  size,
576
577
  mimeType: response?.mime ?? "application/octet-stream",
577
- text,
578
- encoding: text === void 0 ? void 0 : "base64"
578
+ ...text !== void 0 ? {
579
+ text,
580
+ encoding: "base64"
581
+ } : {}
579
582
  },
580
583
  redirectURL: redirect,
581
584
  headersSize: -1,
@@ -1387,7 +1390,7 @@ function readBrowserCookiePartition(value) {
1387
1390
  if (!isRecord(value) || !isString(value["topLevelSite"])) return void 0;
1388
1391
  return {
1389
1392
  site: value["topLevelSite"],
1390
- ancestor: isBoolean(value["hasCrossSiteAncestor"]) ? value["hasCrossSiteAncestor"] : void 0
1393
+ ...isBoolean(value["hasCrossSiteAncestor"]) ? { ancestor: value["hasCrossSiteAncestor"] } : {}
1391
1394
  };
1392
1395
  }
1393
1396
  /**
@@ -1609,7 +1612,7 @@ function readBrowserDownloadProgress(value) {
1609
1612
  status,
1610
1613
  received: value["receivedBytes"],
1611
1614
  total: value["totalBytes"],
1612
- path: isString(value["filePath"]) ? value["filePath"] : void 0
1615
+ ...isString(value["filePath"]) ? { path: value["filePath"] } : {}
1613
1616
  }];
1614
1617
  }
1615
1618
  /**
@@ -2820,326 +2823,6 @@ function decodeBrowserSnapshot(value, styles = [], limit = BROWSER_SNAPSHOT_NODE
2820
2823
  };
2821
2824
  }
2822
2825
  /**
2823
- * Lazily walk every captured browser node in structural depth-first order.
2824
- *
2825
- * @remarks
2826
- * Iframe content documents are entered at their owner element. Orphaned or
2827
- * cyclic protocol nodes are still yielded once through an identity guard.
2828
- *
2829
- * @param snapshot - Captured browser snapshot
2830
- * @returns A lazy node generator
2831
- */
2832
- function* walkBrowserSnapshot(snapshot) {
2833
- const seeds = [];
2834
- for (const document of snapshot.documents) seeds.push(...document.nodes.filter((node) => node.parent === void 0));
2835
- for (const document of snapshot.documents) seeds.push(...document.nodes);
2836
- const visited = /* @__PURE__ */ new Set();
2837
- for (const seed of seeds) {
2838
- const stack = [seed];
2839
- while (stack.length > 0) {
2840
- const node = stack.pop();
2841
- if (node === void 0) break;
2842
- const identity = `${node.document}:${node.index}`;
2843
- if (visited.has(identity)) continue;
2844
- visited.add(identity);
2845
- yield node;
2846
- const children = childrenOfBrowserNode(snapshot, node);
2847
- for (let index = children.length - 1; index >= 0; index -= 1) {
2848
- const child = children[index];
2849
- if (child !== void 0) stack.push(child);
2850
- }
2851
- }
2852
- }
2853
- }
2854
- /**
2855
- * Lazily walk every captured node in structural breadth-first order.
2856
- *
2857
- * @param snapshot - Captured browser snapshot
2858
- * @returns A lazy breadth-first generator
2859
- */
2860
- function* walkBrowserSnapshotBreadthFirst(snapshot) {
2861
- const seeds = [];
2862
- for (const document of snapshot.documents) seeds.push(...document.nodes.filter((node) => node.parent === void 0));
2863
- for (const document of snapshot.documents) seeds.push(...document.nodes);
2864
- const visited = /* @__PURE__ */ new Set();
2865
- for (const seed of seeds) {
2866
- const queue = [seed];
2867
- let cursor = 0;
2868
- while (cursor < queue.length) {
2869
- const node = queue[cursor];
2870
- cursor += 1;
2871
- if (node === void 0) continue;
2872
- const identity = `${node.document}:${node.index}`;
2873
- if (visited.has(identity)) continue;
2874
- visited.add(identity);
2875
- yield node;
2876
- queue.push(...childrenOfBrowserNode(snapshot, node));
2877
- }
2878
- }
2879
- }
2880
- /**
2881
- * Lazily walk one captured browser-node subtree in depth-first order.
2882
- *
2883
- * @param snapshot - Captured browser snapshot
2884
- * @param root - Root node, included as the first result
2885
- * @returns A lazy subtree generator
2886
- */
2887
- function* walkBrowserNode(snapshot, root) {
2888
- const stack = [root];
2889
- const visited = /* @__PURE__ */ new Set();
2890
- while (stack.length > 0) {
2891
- const node = stack.pop();
2892
- if (node === void 0) break;
2893
- const identity = `${node.document}:${node.index}`;
2894
- if (visited.has(identity)) continue;
2895
- visited.add(identity);
2896
- yield node;
2897
- const children = childrenOfBrowserNode(snapshot, node);
2898
- for (let index = children.length - 1; index >= 0; index -= 1) {
2899
- const child = children[index];
2900
- if (child !== void 0) stack.push(child);
2901
- }
2902
- }
2903
- }
2904
- /**
2905
- * Lazily walk one captured browser-node subtree in breadth-first order.
2906
- *
2907
- * @param snapshot - Captured browser snapshot
2908
- * @param root - Root node, included as the first result
2909
- * @returns A lazy breadth-first subtree generator
2910
- */
2911
- function* walkBrowserNodeBreadthFirst(snapshot, root) {
2912
- const queue = [root];
2913
- const visited = /* @__PURE__ */ new Set();
2914
- let cursor = 0;
2915
- while (cursor < queue.length) {
2916
- const node = queue[cursor];
2917
- cursor += 1;
2918
- if (node === void 0) continue;
2919
- const identity = `${node.document}:${node.index}`;
2920
- if (visited.has(identity)) continue;
2921
- visited.add(identity);
2922
- yield node;
2923
- queue.push(...childrenOfBrowserNode(snapshot, node));
2924
- }
2925
- }
2926
- /**
2927
- * Lazily walk descendants of one captured node, excluding the node itself.
2928
- *
2929
- * @param snapshot - Captured browser snapshot
2930
- * @param root - Root whose descendants are required
2931
- * @returns A lazy descendant generator
2932
- */
2933
- function* descendantsOfBrowserNode(snapshot, root) {
2934
- let first = true;
2935
- for (const node of walkBrowserNode(snapshot, root)) {
2936
- if (first) {
2937
- first = false;
2938
- continue;
2939
- }
2940
- yield node;
2941
- }
2942
- }
2943
- /**
2944
- * Resolve the document containing a browser node.
2945
- *
2946
- * @param snapshot - Captured browser snapshot
2947
- * @param node - Node whose document is required
2948
- * @returns The containing document, or undefined
2949
- */
2950
- function documentOfBrowserNode(snapshot, node) {
2951
- return snapshot.documents.find((document) => document.index === node.document);
2952
- }
2953
- /**
2954
- * Return direct children of a captured browser node.
2955
- *
2956
- * @remarks
2957
- * Includes the root nodes of an iframe's linked content document. Shadow DOM
2958
- * and template content already carry flattened parent indexes from CDP.
2959
- *
2960
- * @param snapshot - Captured browser snapshot
2961
- * @param node - Parent node
2962
- * @returns Direct children in snapshot order
2963
- */
2964
- function childrenOfBrowserNode(snapshot, node) {
2965
- const document = documentOfBrowserNode(snapshot, node);
2966
- if (document === void 0) return [];
2967
- const children = document.nodes.filter((candidate) => candidate.parent === node.index);
2968
- if (node.content === void 0) return children;
2969
- const content = snapshot.documents.find((candidate) => candidate.index === node.content);
2970
- if (content === void 0) return children;
2971
- return [...children, ...content.nodes.filter((candidate) => candidate.parent === void 0)];
2972
- }
2973
- /**
2974
- * Resolve the structural parent of a captured browser node.
2975
- *
2976
- * @remarks
2977
- * An iframe content-document root resolves to its owning iframe node.
2978
- *
2979
- * @param snapshot - Captured browser snapshot
2980
- * @param node - Child node
2981
- * @returns Parent node, or undefined for a top-level document root
2982
- */
2983
- function parentOfBrowserNode(snapshot, node) {
2984
- const document = documentOfBrowserNode(snapshot, node);
2985
- if (document === void 0) return void 0;
2986
- return node.parent === void 0 ? findBrowserNode(snapshot, (candidate) => candidate.content === node.document) : document.nodes[node.parent];
2987
- }
2988
- /**
2989
- * Return every structural sibling except the supplied browser node.
2990
- *
2991
- * @param snapshot - Captured browser snapshot
2992
- * @param node - Node whose siblings are required
2993
- * @returns Siblings in structural order
2994
- */
2995
- function siblingsOfBrowserNode(snapshot, node) {
2996
- const parent = parentOfBrowserNode(snapshot, node);
2997
- return (parent === void 0 ? documentOfBrowserNode(snapshot, node)?.nodes.filter((candidate) => candidate.parent === void 0) ?? [] : childrenOfBrowserNode(snapshot, parent)).filter((candidate) => candidate.document !== node.document || candidate.index !== node.index);
2998
- }
2999
- /**
3000
- * Return structural siblings before the supplied browser node.
3001
- *
3002
- * @param snapshot - Captured browser snapshot
3003
- * @param node - Reference node
3004
- * @returns Earlier siblings in structural order
3005
- */
3006
- function precedingSiblingsOfBrowserNode(snapshot, node) {
3007
- const parent = parentOfBrowserNode(snapshot, node);
3008
- const candidates = parent === void 0 ? documentOfBrowserNode(snapshot, node)?.nodes.filter((candidate) => candidate.parent === void 0) ?? [] : childrenOfBrowserNode(snapshot, parent);
3009
- const index = candidates.findIndex((candidate) => candidate.document === node.document && candidate.index === node.index);
3010
- return index < 0 ? [] : candidates.slice(0, index);
3011
- }
3012
- /**
3013
- * Return structural siblings after the supplied browser node.
3014
- *
3015
- * @param snapshot - Captured browser snapshot
3016
- * @param node - Reference node
3017
- * @returns Later siblings in structural order
3018
- */
3019
- function followingSiblingsOfBrowserNode(snapshot, node) {
3020
- const parent = parentOfBrowserNode(snapshot, node);
3021
- const candidates = parent === void 0 ? documentOfBrowserNode(snapshot, node)?.nodes.filter((candidate) => candidate.parent === void 0) ?? [] : childrenOfBrowserNode(snapshot, parent);
3022
- const index = candidates.findIndex((candidate) => candidate.document === node.document && candidate.index === node.index);
3023
- return index < 0 ? [] : candidates.slice(index + 1);
3024
- }
3025
- /**
3026
- * Return the nearest-first ancestor chain for a captured browser node.
3027
- *
3028
- * @param snapshot - Captured browser snapshot
3029
- * @param node - Descendant node
3030
- * @returns Nearest-first ancestor list
3031
- */
3032
- function ancestorsOfBrowserNode(snapshot, node) {
3033
- const ancestors = [];
3034
- const visited = /* @__PURE__ */ new Set();
3035
- let current = node;
3036
- while (true) {
3037
- const parent = parentOfBrowserNode(snapshot, current);
3038
- if (parent === void 0) break;
3039
- const identity = `${parent.document}:${parent.index}`;
3040
- if (visited.has(identity)) break;
3041
- visited.add(identity);
3042
- ancestors.push(parent);
3043
- current = parent;
3044
- }
3045
- return ancestors;
3046
- }
3047
- /**
3048
- * Test whether one captured node is below another across frame boundaries.
3049
- *
3050
- * @param snapshot - Captured browser snapshot
3051
- * @param node - Candidate descendant
3052
- * @param ancestor - Candidate ancestor
3053
- * @returns Whether the relationship exists
3054
- */
3055
- function isBrowserNodeDescendant(snapshot, node, ancestor) {
3056
- return ancestorsOfBrowserNode(snapshot, node).some((candidate) => candidate.document === ancestor.document && candidate.index === ancestor.index);
3057
- }
3058
- /**
3059
- * Resolve the nearest common ancestor of two captured browser nodes.
3060
- *
3061
- * @param snapshot - Captured browser snapshot
3062
- * @param first - First node
3063
- * @param second - Second node
3064
- * @returns Common ancestor, or undefined
3065
- */
3066
- function commonAncestorOfBrowserNodes(snapshot, first, second) {
3067
- const firstAncestors = [first, ...ancestorsOfBrowserNode(snapshot, first)];
3068
- const secondAncestors = [second, ...ancestorsOfBrowserNode(snapshot, second)];
3069
- const identities = new Set(firstAncestors.map((node) => `${node.document}:${node.index}`));
3070
- return secondAncestors.find((node) => identities.has(`${node.document}:${node.index}`));
3071
- }
3072
- /**
3073
- * Compute the edge count between two captured browser nodes.
3074
- *
3075
- * @param snapshot - Captured browser snapshot
3076
- * @param first - First node
3077
- * @param second - Second node
3078
- * @returns Tree distance, or undefined when no common ancestor exists
3079
- */
3080
- function computeBrowserNodeDistance(snapshot, first, second) {
3081
- const common = commonAncestorOfBrowserNodes(snapshot, first, second);
3082
- if (common === void 0) return void 0;
3083
- const firstPath = [first, ...ancestorsOfBrowserNode(snapshot, first)];
3084
- const secondPath = [second, ...ancestorsOfBrowserNode(snapshot, second)];
3085
- const firstDistance = firstPath.findIndex((node) => node.document === common.document && node.index === common.index);
3086
- const secondDistance = secondPath.findIndex((node) => node.document === common.document && node.index === common.index);
3087
- if (firstDistance < 0 || secondDistance < 0) return void 0;
3088
- return firstDistance + secondDistance;
3089
- }
3090
- /**
3091
- * Find the first captured node satisfying a predicate.
3092
- *
3093
- * @param snapshot - Captured browser snapshot
3094
- * @param predicate - Node predicate
3095
- * @returns First matching node, or undefined
3096
- */
3097
- function findBrowserNode(snapshot, predicate) {
3098
- for (const node of walkBrowserSnapshot(snapshot)) if (predicate(node)) return node;
3099
- }
3100
- /**
3101
- * Find captured nodes satisfying a predicate.
3102
- *
3103
- * @param snapshot - Captured browser snapshot
3104
- * @param predicate - Node predicate
3105
- * @param limit - Optional maximum result count
3106
- * @returns Matching nodes in snapshot order
3107
- */
3108
- function findBrowserNodes(snapshot, predicate, limit) {
3109
- if (limit !== void 0 && (!isInteger(limit) || limit < 0)) throw new BrowserError("Browser node result limit must be a non-negative integer", void 0, { limit });
3110
- if (limit === 0) return [];
3111
- const found = [];
3112
- for (const node of walkBrowserSnapshot(snapshot)) {
3113
- if (!predicate(node)) continue;
3114
- found.push(node);
3115
- if (limit !== void 0 && found.length >= limit) break;
3116
- }
3117
- return found;
3118
- }
3119
- /**
3120
- * Find the first matching descendant beneath one captured node.
3121
- *
3122
- * @param snapshot - Captured browser snapshot
3123
- * @param root - Root whose descendants are searched
3124
- * @param predicate - Node predicate
3125
- * @returns First matching descendant, or undefined
3126
- */
3127
- function findBrowserDescendant(snapshot, root, predicate) {
3128
- for (const node of descendantsOfBrowserNode(snapshot, root)) if (predicate(node)) return node;
3129
- }
3130
- /**
3131
- * Find the nearest matching node from the candidate through its ancestors.
3132
- *
3133
- * @param snapshot - Captured browser snapshot
3134
- * @param node - Starting node, included in the search
3135
- * @param predicate - Node predicate
3136
- * @returns Closest matching node, or undefined
3137
- */
3138
- function closestBrowserNode(snapshot, node, predicate) {
3139
- if (predicate(node)) return node;
3140
- return ancestorsOfBrowserNode(snapshot, node).find(predicate);
3141
- }
3142
- /**
3143
2826
  * Read one captured node attribute.
3144
2827
  *
3145
2828
  * @param node - Captured browser node
@@ -3150,6 +2833,23 @@ function attributeOfBrowserNode(node, name) {
3150
2833
  return node.attributes[name];
3151
2834
  }
3152
2835
  /**
2836
+ * Test whether a browser-node matcher is a declarative query.
2837
+ *
2838
+ * @param value - Browser-node query or predicate
2839
+ * @returns Whether the matcher is a declarative query
2840
+ *
2841
+ * @example
2842
+ * ```ts
2843
+ * import { isBrowserNodeQuery } from '@src/core'
2844
+ *
2845
+ * isBrowserNodeQuery({ name: 'main' }) // true
2846
+ * isBrowserNodeQuery(() => true) // false
2847
+ * ```
2848
+ */
2849
+ function isBrowserNodeQuery(value) {
2850
+ return !isFunction(value);
2851
+ }
2852
+ /**
3153
2853
  * Test a captured node against a declarative query.
3154
2854
  *
3155
2855
  * @param node - Captured browser node
@@ -3177,36 +2877,6 @@ function isBrowserNodeVisible(node) {
3177
2877
  const bounds = node.layout?.bounds;
3178
2878
  return bounds !== void 0 && bounds[2] > 0 && bounds[3] > 0;
3179
2879
  }
3180
- /**
3181
- * Build a deterministic, serializable path for a captured browser node.
3182
- *
3183
- * @param snapshot - Captured browser snapshot
3184
- * @param node - Captured browser node
3185
- * @returns Frame-qualified structural path
3186
- */
3187
- function nodeToPath(snapshot, node) {
3188
- const document = documentOfBrowserNode(snapshot, node);
3189
- if (document === void 0) return `document:${node.document} > node:${node.index}`;
3190
- const chain = [...ancestorsOfBrowserNode(snapshot, node)].reverse();
3191
- chain.push(node);
3192
- const segments = [];
3193
- for (const current of chain) {
3194
- if (current.type !== 1) {
3195
- segments.push(`${current.name.toLowerCase()}:${current.index}`);
3196
- continue;
3197
- }
3198
- let ordinal = 1;
3199
- if (current.parent !== void 0) {
3200
- const owner = documentOfBrowserNode(snapshot, current);
3201
- for (const sibling of owner?.nodes ?? []) {
3202
- if (sibling.index >= current.index) break;
3203
- if (sibling.parent === current.parent && sibling.name === current.name) ordinal += 1;
3204
- }
3205
- }
3206
- segments.push(`${current.name.toLowerCase()}:${ordinal}`);
3207
- }
3208
- return `frame(${JSON.stringify(document.frame)}) > ${segments.join(" > ")}`;
3209
- }
3210
2880
  //#endregion
3211
2881
  //#region src/core/CDPClient.ts
3212
2882
  /**
@@ -3509,7 +3179,7 @@ var BrowserClock = class {
3509
3179
  #installed = false;
3510
3180
  #advancing = false;
3511
3181
  #budgetResolve;
3512
- #budgetHandler = () => this.#budgetResolve?.();
3182
+ #budgetHandler = this.#handleBudget.bind(this);
3513
3183
  constructor(frame) {
3514
3184
  this.#frame = frame;
3515
3185
  }
@@ -3609,6 +3279,9 @@ var BrowserClock = class {
3609
3279
  #idle() {
3610
3280
  if (this.#advancing) throw new BrowserError("Browser clock advance is already active");
3611
3281
  }
3282
+ #handleBudget() {
3283
+ this.#budgetResolve?.();
3284
+ }
3612
3285
  };
3613
3286
  //#endregion
3614
3287
  //#region src/core/BrowserCoverage.ts
@@ -3806,8 +3479,8 @@ var BrowserCookieManager = class {
3806
3479
  expires: cookie.expires,
3807
3480
  http: cookie.http,
3808
3481
  secure: cookie.secure,
3809
- site: cookie.site,
3810
- partition: cookie.partition
3482
+ ...cookie.site !== void 0 ? { site: cookie.site } : {},
3483
+ ...cookie.partition !== void 0 ? { partition: cookie.partition } : {}
3811
3484
  })) };
3812
3485
  if (this.#context !== void 0) restore["browserContextId"] = this.#context;
3813
3486
  const result = await this.#client.send("Storage.setCookies", restore);
@@ -3951,12 +3624,14 @@ var BrowserCodegen = class {
3951
3624
  #stopping;
3952
3625
  #shutdown;
3953
3626
  #emitter;
3627
+ #onBindingCalled = this.#handleBindingCalled.bind(this);
3628
+ #onFrameNavigated = this.#handleFrameNavigated.bind(this);
3954
3629
  constructor(client, sessionId, options) {
3955
3630
  this.#client = client;
3956
3631
  this.#sessionId = sessionId;
3957
3632
  this.#emitter = new Emitter({
3958
- on: options?.on,
3959
- error: options?.error
3633
+ ...options?.on !== void 0 ? { on: options.on } : {},
3634
+ ...options?.error !== void 0 ? { error: options.error } : {}
3960
3635
  });
3961
3636
  }
3962
3637
  get emitter() {
@@ -4051,19 +3726,19 @@ var BrowserCodegen = class {
4051
3726
  this.#actions = [];
4052
3727
  this.#emitter.destroy();
4053
3728
  }
4054
- #onBindingCalled = (params) => {
3729
+ #handleBindingCalled(params) {
4055
3730
  if (params["name"] !== "__orkestrelBrowserCodegen") return;
4056
3731
  const action = parseCodegenActionPayload(params["payload"]);
4057
3732
  if (action === void 0) return;
4058
3733
  this.#actions.push(action);
4059
3734
  this.#emitter.emit("action", action);
4060
- };
4061
- #onFrameNavigated = (params) => {
3735
+ }
3736
+ #handleFrameNavigated(params) {
4062
3737
  const action = readCodegenNavigateAction(params);
4063
3738
  if (action === void 0) return;
4064
3739
  this.#actions.push(action);
4065
3740
  this.#emitter.emit("action", action);
4066
- };
3741
+ }
4067
3742
  #unsubscribe() {
4068
3743
  this.#client.unsubscribe("Runtime.bindingCalled", this.#onBindingCalled, this.#sessionId);
4069
3744
  this.#client.unsubscribe("Page.frameNavigated", this.#onFrameNavigated, this.#sessionId);
@@ -4133,12 +3808,7 @@ var BrowserTracing = class {
4133
3808
  #active = false;
4134
3809
  #options;
4135
3810
  #completion;
4136
- #completeHandler = (params) => {
4137
- const completion = this.#completion;
4138
- if (completion === void 0) return;
4139
- if (isString(params["stream"])) completion.resolve(params["stream"]);
4140
- else completion.reject(new BrowserError("Browser trace did not return an IO stream"));
4141
- };
3811
+ #completeHandler = this.#handleComplete.bind(this);
4142
3812
  constructor(frame, writer) {
4143
3813
  this.#frame = frame;
4144
3814
  this.#writer = writer;
@@ -4214,6 +3884,12 @@ var BrowserTracing = class {
4214
3884
  clearTimeout(timer);
4215
3885
  }
4216
3886
  }
3887
+ #handleComplete(params) {
3888
+ const completion = this.#completion;
3889
+ if (completion === void 0) return;
3890
+ if (isString(params["stream"])) completion.resolve(params["stream"]);
3891
+ else completion.reject(new BrowserError("Browser trace did not return an IO stream"));
3892
+ }
4217
3893
  };
4218
3894
  //#endregion
4219
3895
  //#region src/core/BrowserDiagnostics.ts
@@ -4931,8 +4607,8 @@ var BrowserLocator = class BrowserLocator {
4931
4607
  let targetHandle;
4932
4608
  try {
4933
4609
  await target.wait({
4934
- timeout: options?.timeout,
4935
- strict: options?.strict,
4610
+ ...options?.timeout !== void 0 ? { timeout: options.timeout } : {},
4611
+ ...options?.strict !== void 0 ? { strict: options.strict } : {},
4936
4612
  state: "visible"
4937
4613
  });
4938
4614
  targetHandle = await target.frame.handle(compileLocatorExpression(target.query));
@@ -4955,8 +4631,8 @@ var BrowserLocator = class BrowserLocator {
4955
4631
  async #resolve(options, state) {
4956
4632
  validateBrowserActionOptions(options);
4957
4633
  await this.wait({
4958
- timeout: options?.timeout,
4959
- strict: options?.strict,
4634
+ ...options?.timeout !== void 0 ? { timeout: options.timeout } : {},
4635
+ ...options?.strict !== void 0 ? { strict: options.strict } : {},
4960
4636
  state
4961
4637
  });
4962
4638
  return await this.#frame.handle(compileLocatorExpression(this.#query));
@@ -4964,7 +4640,7 @@ var BrowserLocator = class BrowserLocator {
4964
4640
  async #point(handle, options, actionability) {
4965
4641
  if (options?.force !== true) await handle.call(compileActionabilityFunction({
4966
4642
  ...actionability,
4967
- position: options?.position
4643
+ ...options?.position !== void 0 ? { position: options.position } : {}
4968
4644
  }));
4969
4645
  const quad = await this.#quad(handle);
4970
4646
  if (options?.position === void 0) return quad.center;
@@ -5003,9 +4679,7 @@ var BrowserLocator = class BrowserLocator {
5003
4679
  case "enabled":
5004
4680
  expression = `(() => { const element = ${compileLocatorExpression(this.#query)}; return Boolean(element && !element.matches(':disabled')) })()`;
5005
4681
  break;
5006
- case "editable":
5007
- expression = `(() => { const element = ${compileLocatorExpression(this.#query)}; return Boolean(element && !element.matches(':disabled,[readonly]') && (element.isContentEditable || 'value' in element)) })()`;
5008
- break;
4682
+ case "editable": expression = `(() => { const element = ${compileLocatorExpression(this.#query)}; return Boolean(element && !element.matches(':disabled,[readonly]') && (element.isContentEditable || 'value' in element)) })()`;
5009
4683
  }
5010
4684
  return await this.#frame.evaluate(expression) === true;
5011
4685
  }
@@ -5038,29 +4712,29 @@ var BrowserSelectorManager = class {
5038
4712
  return new BrowserLocator(this.#frame, {
5039
4713
  selector: "role",
5040
4714
  value,
5041
- name: options?.name,
5042
- exact: options?.exact
4715
+ ...options?.name !== void 0 ? { name: options.name } : {},
4716
+ ...options?.exact !== void 0 ? { exact: options.exact } : {}
5043
4717
  });
5044
4718
  }
5045
4719
  text(value, options) {
5046
4720
  return new BrowserLocator(this.#frame, {
5047
4721
  selector: "text",
5048
4722
  value,
5049
- exact: options?.exact
4723
+ ...options?.exact !== void 0 ? { exact: options.exact } : {}
5050
4724
  });
5051
4725
  }
5052
4726
  label(value, options) {
5053
4727
  return new BrowserLocator(this.#frame, {
5054
4728
  selector: "label",
5055
4729
  value,
5056
- exact: options?.exact
4730
+ ...options?.exact !== void 0 ? { exact: options.exact } : {}
5057
4731
  });
5058
4732
  }
5059
4733
  placeholder(value, options) {
5060
4734
  return new BrowserLocator(this.#frame, {
5061
4735
  selector: "placeholder",
5062
4736
  value,
5063
- exact: options?.exact
4737
+ ...options?.exact !== void 0 ? { exact: options.exact } : {}
5064
4738
  });
5065
4739
  }
5066
4740
  test(value) {
@@ -5166,7 +4840,7 @@ var BrowserFrame = class {
5166
4840
  this.assert();
5167
4841
  const [title, html, text, currentUrl] = await Promise.all([
5168
4842
  this.#evaluate("document.title"),
5169
- this.#evaluate(guardEvaluateExpression("document.documentElement.outerHTML", BROWSER_RESULT_LIMIT)),
4843
+ this.#captureHTML(),
5170
4844
  this.#evaluate(guardEvaluateExpression("document.body ? document.body.innerText : \"\"", BROWSER_RESULT_LIMIT)),
5171
4845
  this.#evaluate("location.href")
5172
4846
  ]);
@@ -5179,6 +4853,11 @@ var BrowserFrame = class {
5179
4853
  text: requireBrowserString(text, "Document text")
5180
4854
  };
5181
4855
  }
4856
+ async article() {
4857
+ this.assert();
4858
+ const html = requireBrowserString(await this.#captureHTML(), "Document HTML");
4859
+ return renderText(createHTML(html).distill().document);
4860
+ }
5182
4861
  async click(selector, options) {
5183
4862
  this.assert();
5184
4863
  await this.#selectors.css(selector).click(options);
@@ -5239,6 +4918,9 @@ var BrowserFrame = class {
5239
4918
  update(url) {
5240
4919
  this.#url = url;
5241
4920
  }
4921
+ async #captureHTML() {
4922
+ return await this.#evaluate(guardEvaluateExpression("document.documentElement.outerHTML", BROWSER_RESULT_LIMIT));
4923
+ }
5242
4924
  async #evaluate(expression, timeout) {
5243
4925
  const session = await this.#sessionId();
5244
4926
  const params = {
@@ -5330,45 +5012,11 @@ var BrowserHARManager = class {
5330
5012
  #failure;
5331
5013
  #archive;
5332
5014
  #fallback = false;
5333
- #requestHandler = (request) => {
5334
- if (!this.#recording) return;
5335
- this.#pending.set(request.id, {
5336
- request,
5337
- started: request.walltime === void 0 ? Date.now() : request.walltime * 1e3,
5338
- response: void 0
5339
- });
5340
- };
5341
- #responseHandler = (response) => {
5342
- const pending = this.#pending.get(response.id);
5343
- if (pending === void 0) return;
5344
- this.#pending.set(response.id, {
5345
- request: pending.request,
5346
- started: pending.started,
5347
- response
5348
- });
5349
- };
5350
- #failureHandler = (failure) => {
5351
- const pending = this.#pending.get(failure.id);
5352
- if (pending === void 0) return;
5353
- this.#pending.delete(failure.id);
5354
- this.#entries.push(createBrowserHAREntry(pending, Math.max(0, Date.now() - pending.started), void 0, failure.error));
5355
- };
5356
- #finishHandler = (id) => this.#track(this.#complete(id));
5357
- #replayHandler = async (route) => {
5358
- const entry = this.#archive?.log.entries.find((candidate) => candidate.request.url === route.request.url && candidate.request.method === route.request.method);
5359
- if (entry === void 0 || entry.response.status === 0) {
5360
- if (this.#fallback) await route.continue();
5361
- else await route.abort("Failed");
5362
- return;
5363
- }
5364
- const body = entry.response.content.text === void 0 ? void 0 : entry.response.content.encoding === "base64" ? decodeBase64(entry.response.content.text) : entry.response.content.text;
5365
- await route.fulfill({
5366
- status: entry.response.status,
5367
- phrase: entry.response.statusText,
5368
- headers: browserHARHeadersToRecord(entry.response.headers),
5369
- body
5370
- });
5371
- };
5015
+ #requestHandler = this.#handleRequest.bind(this);
5016
+ #responseHandler = this.#handleResponse.bind(this);
5017
+ #failureHandler = this.#handleFailure.bind(this);
5018
+ #finishHandler = this.#handleFinish.bind(this);
5019
+ #replayHandler = this.#handleReplay.bind(this);
5372
5020
  constructor(network, writer) {
5373
5021
  this.#network = network;
5374
5022
  this.#writer = writer;
@@ -5447,6 +5095,47 @@ var BrowserHARManager = class {
5447
5095
  this.#entries.length = 0;
5448
5096
  this.#pending.clear();
5449
5097
  }
5098
+ #handleRequest(request) {
5099
+ if (!this.#recording) return;
5100
+ this.#pending.set(request.id, {
5101
+ request,
5102
+ started: request.walltime === void 0 ? Date.now() : request.walltime * 1e3,
5103
+ response: void 0
5104
+ });
5105
+ }
5106
+ #handleResponse(response) {
5107
+ const pending = this.#pending.get(response.id);
5108
+ if (pending === void 0) return;
5109
+ this.#pending.set(response.id, {
5110
+ request: pending.request,
5111
+ started: pending.started,
5112
+ response
5113
+ });
5114
+ }
5115
+ #handleFailure(failure) {
5116
+ const pending = this.#pending.get(failure.id);
5117
+ if (pending === void 0) return;
5118
+ this.#pending.delete(failure.id);
5119
+ this.#entries.push(createBrowserHAREntry(pending, Math.max(0, Date.now() - pending.started), void 0, failure.error));
5120
+ }
5121
+ #handleFinish(id) {
5122
+ this.#track(this.#complete(id));
5123
+ }
5124
+ async #handleReplay(route) {
5125
+ const entry = this.#archive?.log.entries.find((candidate) => candidate.request.url === route.request.url && candidate.request.method === route.request.method);
5126
+ if (entry === void 0 || entry.response.status === 0) {
5127
+ if (this.#fallback) await route.continue();
5128
+ else await route.abort("Failed");
5129
+ return;
5130
+ }
5131
+ const body = entry.response.content.text === void 0 ? void 0 : entry.response.content.encoding === "base64" ? decodeBase64(entry.response.content.text) : entry.response.content.text;
5132
+ await route.fulfill({
5133
+ status: entry.response.status,
5134
+ phrase: entry.response.statusText,
5135
+ headers: browserHARHeadersToRecord(entry.response.headers),
5136
+ ...body !== void 0 ? { body } : {}
5137
+ });
5138
+ }
5450
5139
  async #complete(id) {
5451
5140
  const pending = this.#pending.get(id);
5452
5141
  if (pending === void 0) return;
@@ -5596,54 +5285,17 @@ var BrowserNetworkManager = class {
5596
5285
  #fetch = false;
5597
5286
  #destroyed = false;
5598
5287
  #starting;
5599
- #requestHandler = (params) => {
5600
- const request = readBrowserRequest(params);
5601
- if (request !== void 0) this.#emitter.emit("request", request);
5602
- };
5603
- #responseHandler = (params) => {
5604
- const response = readBrowserResponse(params);
5605
- if (response !== void 0) this.#emitter.emit("response", response);
5606
- };
5607
- #failureHandler = (params) => {
5608
- const failure = readBrowserRequestFailure(params);
5609
- if (failure !== void 0) this.#emitter.emit("failure", failure);
5610
- };
5611
- #finishHandler = (params) => {
5612
- if (isString(params["requestId"])) this.#emitter.emit("finish", params["requestId"]);
5613
- };
5614
- #pausedHandler = (params) => {
5615
- this.#route(params).catch(() => void 0);
5616
- };
5617
- #authHandler = (params) => {
5618
- this.#authenticate(params).catch(() => void 0);
5619
- };
5620
- #socketHandler = (params) => {
5621
- if (!isString(params["requestId"]) || !isString(params["url"])) return;
5622
- const socket = new BrowserWebSocket(params["requestId"], params["url"]);
5623
- this.#sockets.set(socket.id, socket);
5624
- this.#emitter.emit("socket", socket);
5625
- };
5626
- #socketReceiveHandler = (params) => {
5627
- const socket = isString(params["requestId"]) ? this.#sockets.get(params["requestId"]) : void 0;
5628
- const frame = readBrowserWebSocketFrame(params);
5629
- if (socket !== void 0 && frame !== void 0) socket.receive(frame);
5630
- };
5631
- #socketTransmitHandler = (params) => {
5632
- const socket = isString(params["requestId"]) ? this.#sockets.get(params["requestId"]) : void 0;
5633
- const frame = readBrowserWebSocketFrame(params);
5634
- if (socket !== void 0 && frame !== void 0) socket.transmit(frame);
5635
- };
5636
- #socketErrorHandler = (params) => {
5637
- const socket = isString(params["requestId"]) ? this.#sockets.get(params["requestId"]) : void 0;
5638
- if (socket !== void 0 && isString(params["errorMessage"])) socket.fail(params["errorMessage"]);
5639
- };
5640
- #socketCloseHandler = (params) => {
5641
- if (!isString(params["requestId"])) return;
5642
- const socket = this.#sockets.get(params["requestId"]);
5643
- if (socket === void 0) return;
5644
- this.#sockets.delete(params["requestId"]);
5645
- socket.close(isFiniteNumber(params["timestamp"]) ? params["timestamp"] : Date.now() / 1e3);
5646
- };
5288
+ #requestHandler = this.#handleRequest.bind(this);
5289
+ #responseHandler = this.#handleResponse.bind(this);
5290
+ #failureHandler = this.#handleFailure.bind(this);
5291
+ #finishHandler = this.#handleFinish.bind(this);
5292
+ #pausedHandler = this.#handlePause.bind(this);
5293
+ #authHandler = this.#handleAuth.bind(this);
5294
+ #socketHandler = this.#handleSocket.bind(this);
5295
+ #socketReceiveHandler = this.#handleSocketReceive.bind(this);
5296
+ #socketTransmitHandler = this.#handleSocketTransmit.bind(this);
5297
+ #socketErrorHandler = this.#handleSocketError.bind(this);
5298
+ #socketCloseHandler = this.#handleSocketClose.bind(this);
5647
5299
  constructor(frame, writer) {
5648
5300
  this.#frame = frame;
5649
5301
  this.#emitter = new Emitter();
@@ -5773,29 +5425,77 @@ var BrowserNetworkManager = class {
5773
5425
  this.#emitter.destroy();
5774
5426
  if (failed) throw failure;
5775
5427
  }
5776
- async #begin() {
5777
- try {
5778
- await this.#subscribe();
5779
- await this.#frame.send("Network.enable");
5780
- this.#started = true;
5781
- await this.#configure();
5782
- } catch (error) {
5783
- this.#started = false;
5784
- this.#fetch = false;
5785
- await this.#frame.send("Fetch.disable").catch(() => void 0);
5786
- await this.#frame.send("Network.disable").catch(() => void 0);
5787
- await this.#unsubscribe().catch(() => void 0);
5788
- throw error;
5789
- }
5428
+ #handleRequest(params) {
5429
+ const request = readBrowserRequest(params);
5430
+ if (request !== void 0) this.#emitter.emit("request", request);
5790
5431
  }
5791
- async #configure() {
5792
- if (!(this.#routes.length > 0 || this.#credentials !== void 0)) {
5793
- if (this.#fetch) {
5794
- await this.#frame.send("Fetch.disable");
5795
- this.#fetch = false;
5796
- }
5797
- return;
5798
- }
5432
+ #handleResponse(params) {
5433
+ const response = readBrowserResponse(params);
5434
+ if (response !== void 0) this.#emitter.emit("response", response);
5435
+ }
5436
+ #handleFailure(params) {
5437
+ const failure = readBrowserRequestFailure(params);
5438
+ if (failure !== void 0) this.#emitter.emit("failure", failure);
5439
+ }
5440
+ #handleFinish(params) {
5441
+ if (isString(params["requestId"])) this.#emitter.emit("finish", params["requestId"]);
5442
+ }
5443
+ #handlePause(params) {
5444
+ this.#route(params).catch(() => void 0);
5445
+ }
5446
+ #handleAuth(params) {
5447
+ this.#authenticate(params).catch(() => void 0);
5448
+ }
5449
+ #handleSocket(params) {
5450
+ if (!isString(params["requestId"]) || !isString(params["url"])) return;
5451
+ const socket = new BrowserWebSocket(params["requestId"], params["url"]);
5452
+ this.#sockets.set(socket.id, socket);
5453
+ this.#emitter.emit("socket", socket);
5454
+ }
5455
+ #handleSocketReceive(params) {
5456
+ const socket = isString(params["requestId"]) ? this.#sockets.get(params["requestId"]) : void 0;
5457
+ const frame = readBrowserWebSocketFrame(params);
5458
+ if (socket !== void 0 && frame !== void 0) socket.receive(frame);
5459
+ }
5460
+ #handleSocketTransmit(params) {
5461
+ const socket = isString(params["requestId"]) ? this.#sockets.get(params["requestId"]) : void 0;
5462
+ const frame = readBrowserWebSocketFrame(params);
5463
+ if (socket !== void 0 && frame !== void 0) socket.transmit(frame);
5464
+ }
5465
+ #handleSocketError(params) {
5466
+ const socket = isString(params["requestId"]) ? this.#sockets.get(params["requestId"]) : void 0;
5467
+ if (socket !== void 0 && isString(params["errorMessage"])) socket.fail(params["errorMessage"]);
5468
+ }
5469
+ #handleSocketClose(params) {
5470
+ if (!isString(params["requestId"])) return;
5471
+ const socket = this.#sockets.get(params["requestId"]);
5472
+ if (socket === void 0) return;
5473
+ this.#sockets.delete(params["requestId"]);
5474
+ socket.close(isFiniteNumber(params["timestamp"]) ? params["timestamp"] : Date.now() / 1e3);
5475
+ }
5476
+ async #begin() {
5477
+ try {
5478
+ await this.#subscribe();
5479
+ await this.#frame.send("Network.enable");
5480
+ this.#started = true;
5481
+ await this.#configure();
5482
+ } catch (error) {
5483
+ this.#started = false;
5484
+ this.#fetch = false;
5485
+ await this.#frame.send("Fetch.disable").catch(() => void 0);
5486
+ await this.#frame.send("Network.disable").catch(() => void 0);
5487
+ await this.#unsubscribe().catch(() => void 0);
5488
+ throw error;
5489
+ }
5490
+ }
5491
+ async #configure() {
5492
+ if (!(this.#routes.length > 0 || this.#credentials !== void 0)) {
5493
+ if (this.#fetch) {
5494
+ await this.#frame.send("Fetch.disable");
5495
+ this.#fetch = false;
5496
+ }
5497
+ return;
5498
+ }
5799
5499
  await this.#frame.send("Fetch.enable", {
5800
5500
  patterns: this.#routes.map((definition) => ({
5801
5501
  urlPattern: definition.query.url ?? "*",
@@ -5876,21 +5576,8 @@ var BrowserNetworkManager = class {
5876
5576
  var BrowserNavigationManager = class {
5877
5577
  #page;
5878
5578
  #waits = /* @__PURE__ */ new Map();
5879
- #navigateHandler = (url) => {
5880
- for (const [id, wait] of this.#waits) {
5881
- if (!matchesBrowserURL(url, wait.pattern)) continue;
5882
- clearTimeout(wait.timer);
5883
- this.#waits.delete(id);
5884
- wait.resolve(url);
5885
- }
5886
- };
5887
- #closeHandler = () => {
5888
- for (const [id, wait] of this.#waits) {
5889
- clearTimeout(wait.timer);
5890
- this.#waits.delete(id);
5891
- wait.reject(new BrowserError("Browser URL wait ended because the page closed"));
5892
- }
5893
- };
5579
+ #navigateHandler = this.#handleNavigate.bind(this);
5580
+ #closeHandler = this.#handleClose.bind(this);
5894
5581
  constructor(page) {
5895
5582
  this.#page = page;
5896
5583
  this.#page.emitter.on("navigate", this.#navigateHandler);
@@ -5925,6 +5612,21 @@ var BrowserNavigationManager = class {
5925
5612
  timeout
5926
5613
  });
5927
5614
  }
5615
+ #handleNavigate(url) {
5616
+ for (const [id, wait] of this.#waits) {
5617
+ if (!matchesBrowserURL(url, wait.pattern)) continue;
5618
+ clearTimeout(wait.timer);
5619
+ this.#waits.delete(id);
5620
+ wait.resolve(url);
5621
+ }
5622
+ }
5623
+ #handleClose() {
5624
+ for (const [id, wait] of this.#waits) {
5625
+ clearTimeout(wait.timer);
5626
+ this.#waits.delete(id);
5627
+ wait.reject(new BrowserError("Browser URL wait ended because the page closed"));
5628
+ }
5629
+ }
5928
5630
  #timeout(options) {
5929
5631
  const timeout = options?.timeout ?? 3e4;
5930
5632
  validateBrowserTimeout(timeout);
@@ -5942,9 +5644,7 @@ var BrowserScriptManager = class {
5942
5644
  #scripts = /* @__PURE__ */ new Map();
5943
5645
  #subscribed = false;
5944
5646
  #destroyed = false;
5945
- #bindingHandler = (params) => {
5946
- this.#call(params).catch(() => void 0);
5947
- };
5647
+ #bindingHandler = this.#handleBinding.bind(this);
5948
5648
  constructor(frame) {
5949
5649
  this.#frame = frame;
5950
5650
  }
@@ -6040,11 +5740,197 @@ var BrowserScriptManager = class {
6040
5740
  });
6041
5741
  }
6042
5742
  }
5743
+ #handleBinding(params) {
5744
+ this.#call(params).catch(() => void 0);
5745
+ }
6043
5746
  #assert() {
6044
5747
  if (this.#destroyed) throw new BrowserError("Browser script manager is destroyed");
6045
5748
  }
6046
5749
  };
6047
5750
  //#endregion
5751
+ //#region src/core/BrowserSnapshot.ts
5752
+ /** A navigable, serializable browser DOM snapshot. */
5753
+ var BrowserSnapshot = class {
5754
+ #owners;
5755
+ documents;
5756
+ styles;
5757
+ constructor(input) {
5758
+ this.documents = Object.freeze([...input.documents]);
5759
+ this.styles = Object.freeze([...input.styles]);
5760
+ }
5761
+ walk(options) {
5762
+ return options?.order === "breadth" ? this.#breadth(options.root) : this.#depth(options?.root);
5763
+ }
5764
+ *descendants(node) {
5765
+ let first = true;
5766
+ for (const descendant of this.#depth(node)) {
5767
+ if (first) {
5768
+ first = false;
5769
+ continue;
5770
+ }
5771
+ yield descendant;
5772
+ }
5773
+ }
5774
+ document(node) {
5775
+ return this.documents.find((document) => document.index === node.document);
5776
+ }
5777
+ children(node) {
5778
+ const document = this.document(node);
5779
+ if (document === void 0) return [];
5780
+ const children = document.nodes.filter((candidate) => candidate.parent === node.index);
5781
+ if (node.content === void 0) return children;
5782
+ const content = this.documents.find((candidate) => candidate.index === node.content);
5783
+ if (content === void 0) return children;
5784
+ return [...children, ...content.nodes.filter((candidate) => candidate.parent === void 0)];
5785
+ }
5786
+ parent(node) {
5787
+ const document = this.document(node);
5788
+ if (document === void 0) return void 0;
5789
+ return node.parent === void 0 ? this.#owner(node.document) : document.nodes[node.parent];
5790
+ }
5791
+ siblings(node, relation) {
5792
+ const candidates = this.#candidates(node);
5793
+ const index = candidates.findIndex((candidate) => candidate.document === node.document && candidate.index === node.index);
5794
+ if (relation === "preceding") return index < 0 ? [] : candidates.slice(0, index);
5795
+ if (relation === "following") return index < 0 ? [] : candidates.slice(index + 1);
5796
+ return candidates.filter((candidate) => candidate.document !== node.document || candidate.index !== node.index);
5797
+ }
5798
+ ancestors(node) {
5799
+ const ancestors = [];
5800
+ const visited = /* @__PURE__ */ new Set();
5801
+ let current = node;
5802
+ while (true) {
5803
+ const parent = this.parent(current);
5804
+ if (parent === void 0) break;
5805
+ const identity = this.#identity(parent);
5806
+ if (visited.has(identity)) break;
5807
+ visited.add(identity);
5808
+ ancestors.push(parent);
5809
+ current = parent;
5810
+ }
5811
+ return ancestors;
5812
+ }
5813
+ common(first, second) {
5814
+ const firstAncestors = this.#chain(first);
5815
+ const secondAncestors = this.#chain(second);
5816
+ const identities = new Set(firstAncestors.map((node) => this.#identity(node)));
5817
+ return secondAncestors.find((node) => identities.has(this.#identity(node)));
5818
+ }
5819
+ distance(first, second) {
5820
+ const common = this.common(first, second);
5821
+ if (common === void 0) return void 0;
5822
+ const identity = this.#identity(common);
5823
+ const firstDistance = this.#chain(first).findIndex((node) => this.#identity(node) === identity);
5824
+ const secondDistance = this.#chain(second).findIndex((node) => this.#identity(node) === identity);
5825
+ if (firstDistance < 0 || secondDistance < 0) return void 0;
5826
+ return firstDistance + secondDistance;
5827
+ }
5828
+ find(query) {
5829
+ for (const node of this.walk()) if (this.#match(node, query)) return node;
5830
+ }
5831
+ filter(query, limit) {
5832
+ if (limit !== void 0 && (!isInteger(limit) || limit < 0)) throw new BrowserError("Browser node result limit must be a non-negative integer", void 0, { limit });
5833
+ if (limit === 0) return [];
5834
+ const found = [];
5835
+ for (const node of this.walk()) {
5836
+ if (!this.#match(node, query)) continue;
5837
+ found.push(node);
5838
+ if (limit !== void 0 && found.length >= limit) break;
5839
+ }
5840
+ return found;
5841
+ }
5842
+ closest(node, query) {
5843
+ if (this.#match(node, query)) return node;
5844
+ for (const ancestor of this.ancestors(node)) if (this.#match(ancestor, query)) return ancestor;
5845
+ }
5846
+ path(node) {
5847
+ const document = this.document(node);
5848
+ if (document === void 0) return `document:${node.document} > node:${node.index}`;
5849
+ const chain = [...this.ancestors(node)].reverse();
5850
+ chain.push(node);
5851
+ const segments = [];
5852
+ for (const current of chain) {
5853
+ if (current.type !== 1) {
5854
+ segments.push(`${current.name.toLowerCase()}:${current.index}`);
5855
+ continue;
5856
+ }
5857
+ let ordinal = 1;
5858
+ if (current.parent !== void 0) {
5859
+ const owner = this.document(current);
5860
+ for (const sibling of owner?.nodes ?? []) {
5861
+ if (sibling.index >= current.index) break;
5862
+ if (sibling.parent === current.parent && sibling.name === current.name) ordinal += 1;
5863
+ }
5864
+ }
5865
+ segments.push(`${current.name.toLowerCase()}:${ordinal}`);
5866
+ }
5867
+ return `frame(${JSON.stringify(document.frame)}) > ${segments.join(" > ")}`;
5868
+ }
5869
+ #roots() {
5870
+ const roots = [];
5871
+ for (const document of this.documents) roots.push(...document.nodes.filter((node) => node.parent === void 0));
5872
+ for (const document of this.documents) roots.push(...document.nodes);
5873
+ return roots;
5874
+ }
5875
+ #owner(document) {
5876
+ const owners = this.#owners;
5877
+ if (owners !== void 0) return owners.get(document);
5878
+ const index = /* @__PURE__ */ new Map();
5879
+ for (const node of this.walk()) if (node.content !== void 0 && !index.has(node.content)) index.set(node.content, node);
5880
+ this.#owners = index;
5881
+ return index.get(document);
5882
+ }
5883
+ *#depth(root) {
5884
+ const visited = /* @__PURE__ */ new Set();
5885
+ for (const seed of root === void 0 ? this.#roots() : [root]) {
5886
+ const stack = [seed];
5887
+ while (stack.length > 0) {
5888
+ const node = stack.pop();
5889
+ if (node === void 0) break;
5890
+ const identity = this.#identity(node);
5891
+ if (visited.has(identity)) continue;
5892
+ visited.add(identity);
5893
+ yield node;
5894
+ const children = this.children(node);
5895
+ for (let index = children.length - 1; index >= 0; index -= 1) {
5896
+ const child = children[index];
5897
+ if (child !== void 0) stack.push(child);
5898
+ }
5899
+ }
5900
+ }
5901
+ }
5902
+ *#breadth(root) {
5903
+ const visited = /* @__PURE__ */ new Set();
5904
+ for (const seed of root === void 0 ? this.#roots() : [root]) {
5905
+ const queue = [seed];
5906
+ let cursor = 0;
5907
+ while (cursor < queue.length) {
5908
+ const node = queue[cursor];
5909
+ cursor += 1;
5910
+ if (node === void 0) continue;
5911
+ const identity = this.#identity(node);
5912
+ if (visited.has(identity)) continue;
5913
+ visited.add(identity);
5914
+ yield node;
5915
+ queue.push(...this.children(node));
5916
+ }
5917
+ }
5918
+ }
5919
+ #candidates(node) {
5920
+ const parent = this.parent(node);
5921
+ return parent === void 0 ? this.document(node)?.nodes.filter((candidate) => candidate.parent === void 0) ?? [] : this.children(parent);
5922
+ }
5923
+ #chain(node) {
5924
+ return [node, ...this.ancestors(node)];
5925
+ }
5926
+ #match(node, query) {
5927
+ return isBrowserNodeQuery(query) ? matchesBrowserNode(node, query) : query(node);
5928
+ }
5929
+ #identity(node) {
5930
+ return `${node.document}:${node.index}`;
5931
+ }
5932
+ };
5933
+ //#endregion
6048
5934
  //#region src/core/BrowserWorker.ts
6049
5935
  /**
6050
5936
  * Dedicated, shared, or service worker attached through a flattened target session.
@@ -6135,129 +6021,21 @@ var BrowserPage = class BrowserPage extends BrowserFrame {
6135
6021
  #loadResolve;
6136
6022
  #loadReject;
6137
6023
  #responses;
6138
- #navigationResponseHandler = (response) => {
6139
- if (response.frame === this.id) this.#responses?.push(response);
6140
- };
6141
- #destroyHandler = (params) => {
6142
- if (!isString(params["targetId"]) || params["targetId"] !== this.#targetId) return;
6143
- this.#closed = true;
6144
- this.#release().catch(() => void 0);
6145
- };
6146
- #loadHandler = (params) => {
6147
- if (this.#loadEvents.includes("Page.navigatedWithinDocument")) {
6148
- const frame = params["frameId"];
6149
- if (isString(frame) && frame === this.id) {
6150
- this.#sameDocument = true;
6151
- this.#resolveLoad();
6152
- return;
6153
- }
6154
- }
6155
- if (this.#loadEvents.includes("Page.frameNavigated")) {
6156
- const frame = params["frame"];
6157
- if (isRecord(frame) && frame["id"] === this.id) this.#resolveLoad();
6158
- return;
6159
- }
6160
- if (this.#loadEvents.includes("Page.loadEventFired") || this.#loadEvents.includes("Page.domContentEventFired")) this.#resolveLoad();
6161
- };
6162
- #frameAttachedHandler = (params) => {
6163
- const frame = params["frameId"];
6164
- const parent = params["parentFrameId"];
6165
- if (!isString(frame)) return;
6166
- this.#emitter.emit("attach", new BrowserFrame(this.#client, (id) => this.#resolveFrameSession(id), frame, "about:blank", isString(parent) ? parent : void 0));
6167
- };
6168
- #frameNavigatedHandler = (params) => {
6169
- const frame = params["frame"];
6170
- if (!isRecord(frame) || !isString(frame["id"]) || !isString(frame["url"])) return;
6171
- if (frame["id"] === this.id) {
6172
- this.update(frame["url"]);
6173
- this.#emitter.emit("navigate", frame["url"]);
6174
- }
6175
- };
6176
- #frameDetachedHandler = (params) => {
6177
- const frame = params["frameId"];
6178
- if (!isString(frame)) return;
6179
- this.#frameSessions.delete(frame);
6180
- this.#emitter.emit("detach", frame);
6181
- };
6182
- #dialogHandler = (params) => {
6183
- const category = params["type"];
6184
- if (category !== "alert" && category !== "confirm" && category !== "prompt" && category !== "beforeunload" || !isString(params["message"])) return;
6185
- this.#emitter.emit("dialog", new BrowserDialog(this, category, params["message"], isString(params["defaultPrompt"]) ? params["defaultPrompt"] : ""));
6186
- };
6187
- #chooserHandler = (params) => {
6188
- const backend = params["backendNodeId"];
6189
- const mode = params["mode"];
6190
- if (!isInteger(backend)) return;
6191
- this.#emitter.emit("chooser", new BrowserFileChooser(this, backend, mode === "selectMultiple"));
6192
- };
6193
- #consoleHandler = (params) => {
6194
- const message = readBrowserConsoleMessage(params);
6195
- if (message !== void 0) this.#emitter.emit("console", message);
6196
- };
6197
- #errorHandler = (params) => {
6198
- const error = readBrowserPageError(params);
6199
- if (error !== void 0) this.#emitter.emit("error", error);
6200
- };
6201
- #crashHandler = () => this.#emitter.emit("crash");
6202
- #downloadHandler = (params) => {
6203
- const start = readBrowserDownloadStart(params);
6204
- if (start === void 0 || start.frame !== this.id && !this.#frameSessions.has(start.frame)) return;
6205
- const download = new BrowserDownload(this.#client, start.id, start.url, start.name, this.#contextId);
6206
- this.#downloads.set(start.id, download);
6207
- this.#emitter.emit("download", download);
6208
- };
6209
- #downloadProgressHandler = (params) => {
6210
- const decoded = readBrowserDownloadProgress(params);
6211
- if (decoded === void 0) return;
6212
- const [id, progress] = decoded;
6213
- const download = this.#downloads.get(id);
6214
- if (download === void 0) return;
6215
- download.update(progress);
6216
- if (progress.status !== "pending") this.#downloads.delete(id);
6217
- };
6218
- #attachedHandler = (params) => {
6219
- const target = params["targetInfo"];
6220
- const session = params["sessionId"];
6221
- if (!isRecord(target) || !isString(target["targetId"]) || !isString(session)) return;
6222
- const category = target["type"];
6223
- if (category === "worker" || category === "service_worker" || category === "shared_worker") {
6224
- this.#attachWorker(session, target["targetId"], isString(target["url"]) ? target["url"] : "", category);
6225
- return;
6226
- }
6227
- if (category === "page") {
6228
- this.#attachPopup(session, target["targetId"], isString(target["url"]) ? target["url"] : "about:blank");
6229
- return;
6230
- }
6231
- if (category !== "iframe") return;
6232
- const frame = target["targetId"];
6233
- const attempt = this.#enableFrameSession(session);
6234
- this.#frameSessions.set(frame, attempt);
6235
- this.#frameIds.set(session, frame);
6236
- attempt.catch(() => {
6237
- if (this.#frameSessions.get(frame) === attempt) this.#frameSessions.delete(frame);
6238
- if (this.#frameIds.get(session) === frame) this.#frameIds.delete(session);
6239
- this.#detachChild(session);
6240
- });
6241
- };
6242
- #detachedHandler = (params) => {
6243
- const session = params["sessionId"];
6244
- const target = params["targetId"];
6245
- if (isString(target)) {
6246
- const worker = this.#workers.get(target);
6247
- if (worker !== void 0) {
6248
- worker.detach();
6249
- this.#workers.delete(target);
6250
- }
6251
- const popup = this.#popups.get(target);
6252
- if (popup !== void 0) {
6253
- this.#popups.delete(target);
6254
- popup.destroy().catch(() => void 0);
6255
- }
6256
- }
6257
- const frame = isString(target) ? target : isString(session) ? this.#frameIds.get(session) : void 0;
6258
- if (frame !== void 0) this.#frameSessions.delete(frame);
6259
- if (isString(session)) this.#frameIds.delete(session);
6260
- };
6024
+ #navigationResponseHandler = this.#handleNavigationResponse.bind(this);
6025
+ #destroyHandler = this.#handleDestroy.bind(this);
6026
+ #loadHandler = this.#handleLoad.bind(this);
6027
+ #frameAttachedHandler = this.#handleFrameAttached.bind(this);
6028
+ #frameNavigatedHandler = this.#handleFrameNavigated.bind(this);
6029
+ #frameDetachedHandler = this.#handleFrameDetached.bind(this);
6030
+ #dialogHandler = this.#handleDialog.bind(this);
6031
+ #chooserHandler = this.#handleChooser.bind(this);
6032
+ #consoleHandler = this.#handleConsole.bind(this);
6033
+ #errorHandler = this.#handleError.bind(this);
6034
+ #crashHandler = this.#handleCrash.bind(this);
6035
+ #downloadHandler = this.#handleDownload.bind(this);
6036
+ #downloadProgressHandler = this.#handleDownloadProgress.bind(this);
6037
+ #attachedHandler = this.#handleAttached.bind(this);
6038
+ #detachedHandler = this.#handleDetached.bind(this);
6261
6039
  constructor(client, targetId, sessionId, writer, url, frameId, contextId, opener) {
6262
6040
  super(client, sessionId, frameId ?? targetId, url ?? "about:blank", void 0, void 0, false);
6263
6041
  this.#client = client;
@@ -6441,11 +6219,11 @@ var BrowserPage = class BrowserPage extends BrowserFrame {
6441
6219
  async snapshot(options) {
6442
6220
  this.assert();
6443
6221
  const styles = options?.styles ?? [];
6444
- return decodeBrowserSnapshot(await this.request("DOMSnapshot.captureSnapshot", {
6222
+ return new BrowserSnapshot(decodeBrowserSnapshot(await this.request("DOMSnapshot.captureSnapshot", {
6445
6223
  computedStyles: [...styles],
6446
6224
  includePaintOrder: options?.paint ?? false,
6447
6225
  includeDOMRects: options?.rects ?? false
6448
- }), styles, options?.limit ?? 1e5);
6226
+ }), styles, options?.limit ?? 1e5));
6449
6227
  }
6450
6228
  async codegen(options) {
6451
6229
  this.assert();
@@ -6717,6 +6495,131 @@ var BrowserPage = class BrowserPage extends BrowserFrame {
6717
6495
  await this.request("Page.stopLoading", void 0, timeout);
6718
6496
  } catch {}
6719
6497
  }
6498
+ #handleNavigationResponse(response) {
6499
+ if (response.frame === this.id) this.#responses?.push(response);
6500
+ }
6501
+ #handleDestroy(params) {
6502
+ if (!isString(params["targetId"]) || params["targetId"] !== this.#targetId) return;
6503
+ this.#closed = true;
6504
+ this.#release().catch(() => void 0);
6505
+ }
6506
+ #handleLoad(params) {
6507
+ if (this.#loadEvents.includes("Page.navigatedWithinDocument")) {
6508
+ const frame = params["frameId"];
6509
+ if (isString(frame) && frame === this.id) {
6510
+ this.#sameDocument = true;
6511
+ this.#resolveLoad();
6512
+ return;
6513
+ }
6514
+ }
6515
+ if (this.#loadEvents.includes("Page.frameNavigated")) {
6516
+ const frame = params["frame"];
6517
+ if (isRecord(frame) && frame["id"] === this.id) this.#resolveLoad();
6518
+ return;
6519
+ }
6520
+ if (this.#loadEvents.includes("Page.loadEventFired") || this.#loadEvents.includes("Page.domContentEventFired")) this.#resolveLoad();
6521
+ }
6522
+ #handleFrameAttached(params) {
6523
+ const frame = params["frameId"];
6524
+ const parent = params["parentFrameId"];
6525
+ if (!isString(frame)) return;
6526
+ this.#emitter.emit("attach", new BrowserFrame(this.#client, (id) => this.#resolveFrameSession(id), frame, "about:blank", isString(parent) ? parent : void 0));
6527
+ }
6528
+ #handleFrameNavigated(params) {
6529
+ const frame = params["frame"];
6530
+ if (!isRecord(frame) || !isString(frame["id"]) || !isString(frame["url"])) return;
6531
+ if (frame["id"] === this.id) {
6532
+ this.update(frame["url"]);
6533
+ this.#emitter.emit("navigate", frame["url"]);
6534
+ }
6535
+ }
6536
+ #handleFrameDetached(params) {
6537
+ const frame = params["frameId"];
6538
+ if (!isString(frame)) return;
6539
+ this.#frameSessions.delete(frame);
6540
+ this.#emitter.emit("detach", frame);
6541
+ }
6542
+ #handleDialog(params) {
6543
+ const category = params["type"];
6544
+ if (category !== "alert" && category !== "confirm" && category !== "prompt" && category !== "beforeunload" || !isString(params["message"])) return;
6545
+ this.#emitter.emit("dialog", new BrowserDialog(this, category, params["message"], isString(params["defaultPrompt"]) ? params["defaultPrompt"] : ""));
6546
+ }
6547
+ #handleChooser(params) {
6548
+ const backend = params["backendNodeId"];
6549
+ const mode = params["mode"];
6550
+ if (!isInteger(backend)) return;
6551
+ this.#emitter.emit("chooser", new BrowserFileChooser(this, backend, mode === "selectMultiple"));
6552
+ }
6553
+ #handleConsole(params) {
6554
+ const message = readBrowserConsoleMessage(params);
6555
+ if (message !== void 0) this.#emitter.emit("console", message);
6556
+ }
6557
+ #handleError(params) {
6558
+ const error = readBrowserPageError(params);
6559
+ if (error !== void 0) this.#emitter.emit("error", error);
6560
+ }
6561
+ #handleCrash() {
6562
+ this.#emitter.emit("crash");
6563
+ }
6564
+ #handleDownload(params) {
6565
+ const start = readBrowserDownloadStart(params);
6566
+ if (start === void 0 || start.frame !== this.id && !this.#frameSessions.has(start.frame)) return;
6567
+ const download = new BrowserDownload(this.#client, start.id, start.url, start.name, this.#contextId);
6568
+ this.#downloads.set(start.id, download);
6569
+ this.#emitter.emit("download", download);
6570
+ }
6571
+ #handleDownloadProgress(params) {
6572
+ const decoded = readBrowserDownloadProgress(params);
6573
+ if (decoded === void 0) return;
6574
+ const [id, progress] = decoded;
6575
+ const download = this.#downloads.get(id);
6576
+ if (download === void 0) return;
6577
+ download.update(progress);
6578
+ if (progress.status !== "pending") this.#downloads.delete(id);
6579
+ }
6580
+ #handleAttached(params) {
6581
+ const target = params["targetInfo"];
6582
+ const session = params["sessionId"];
6583
+ if (!isRecord(target) || !isString(target["targetId"]) || !isString(session)) return;
6584
+ const category = target["type"];
6585
+ if (category === "worker" || category === "service_worker" || category === "shared_worker") {
6586
+ this.#attachWorker(session, target["targetId"], isString(target["url"]) ? target["url"] : "", category);
6587
+ return;
6588
+ }
6589
+ if (category === "page") {
6590
+ this.#attachPopup(session, target["targetId"], isString(target["url"]) ? target["url"] : "about:blank");
6591
+ return;
6592
+ }
6593
+ if (category !== "iframe") return;
6594
+ const frame = target["targetId"];
6595
+ const attempt = this.#enableFrameSession(session);
6596
+ this.#frameSessions.set(frame, attempt);
6597
+ this.#frameIds.set(session, frame);
6598
+ attempt.catch(() => {
6599
+ if (this.#frameSessions.get(frame) === attempt) this.#frameSessions.delete(frame);
6600
+ if (this.#frameIds.get(session) === frame) this.#frameIds.delete(session);
6601
+ this.#detachChild(session);
6602
+ });
6603
+ }
6604
+ #handleDetached(params) {
6605
+ const session = params["sessionId"];
6606
+ const target = params["targetId"];
6607
+ if (isString(target)) {
6608
+ const worker = this.#workers.get(target);
6609
+ if (worker !== void 0) {
6610
+ worker.detach();
6611
+ this.#workers.delete(target);
6612
+ }
6613
+ const popup = this.#popups.get(target);
6614
+ if (popup !== void 0) {
6615
+ this.#popups.delete(target);
6616
+ popup.destroy().catch(() => void 0);
6617
+ }
6618
+ }
6619
+ const frame = isString(target) ? target : isString(session) ? this.#frameIds.get(session) : void 0;
6620
+ if (frame !== void 0) this.#frameSessions.delete(frame);
6621
+ if (isString(session)) this.#frameIds.delete(session);
6622
+ }
6720
6623
  #waitForLoadEvent(condition, timeout) {
6721
6624
  const eventName = condition === "commit" ? "Page.frameNavigated" : condition === "domcontentloaded" ? "Page.domContentEventFired" : "Page.loadEventFired";
6722
6625
  const deferred = Promise.withResolvers();
@@ -6818,8 +6721,8 @@ var BrowserStorageManager = class {
6818
6721
  expires: cookie.expires,
6819
6722
  http: cookie.http,
6820
6723
  secure: cookie.secure,
6821
- site: cookie.site,
6822
- partition: cookie.partition
6724
+ ...cookie.site !== void 0 ? { site: cookie.site } : {},
6725
+ ...cookie.partition !== void 0 ? { partition: cookie.partition } : {}
6823
6726
  })),
6824
6727
  origins: storage
6825
6728
  };
@@ -6967,7 +6870,7 @@ var BrowserContext = class {
6967
6870
  try {
6968
6871
  const viewport = options?.viewport ?? this.#viewport;
6969
6872
  page = await this.#attach(targetId, options?.url ?? "about:blank", viewport);
6970
- if (options?.url !== void 0 && options.url !== "about:blank") await page.navigate(options.url, { timeout: options.timeout });
6873
+ if (options?.url !== void 0 && options.url !== "about:blank") await page.navigate(options.url, { ...options.timeout !== void 0 ? { timeout: options.timeout } : {} });
6971
6874
  if (this.#closed) throw new BrowserError("Browser context closed during page creation");
6972
6875
  this.#pages.set(targetId, page);
6973
6876
  this.#emitter.emit("page", page);
@@ -7203,7 +7106,24 @@ var BrowserContext = class {
7203
7106
  function createCDPClient(options) {
7204
7107
  return new CDPClient(options);
7205
7108
  }
7109
+ /**
7110
+ * Create a navigable browser snapshot from decoded serializable data.
7111
+ *
7112
+ * @param input - Captured documents and computed-style names
7113
+ * @returns A {@link BrowserSnapshotInterface}
7114
+ *
7115
+ * @example
7116
+ * ```ts
7117
+ * import { createBrowserSnapshot, decodeBrowserSnapshot } from '@src/core'
7118
+ *
7119
+ * const snapshot = createBrowserSnapshot(decodeBrowserSnapshot(captured, ['display']))
7120
+ * snapshot.find({ name: 'main' })
7121
+ * ```
7122
+ */
7123
+ function createBrowserSnapshot(input) {
7124
+ return new BrowserSnapshot(input);
7125
+ }
7206
7126
  //#endregion
7207
- export { BASE64_CHARS, BASE64_LOOKUP, BROWSER_CODEGEN_BINDING_NAME, BROWSER_CODEGEN_SOURCE, BROWSER_DEFAULT_TIMEOUT_MS, BROWSER_DEFAULT_VIEWPORT_HEIGHT, BROWSER_DEFAULT_VIEWPORT_WIDTH, BROWSER_FRAME_WORLD_NAME, BROWSER_HAR_CREATOR, BROWSER_KEY_MODIFIERS, BROWSER_MOUSE_BUTTON_MASKS, BROWSER_RESULT_LIMIT, BROWSER_RESULT_LIMIT_PATTERN, BROWSER_RESULT_LIMIT_SENTINEL_PREFIX, BROWSER_SCREENSHOT_ATTRIBUTE, BROWSER_SNAPSHOT_NODE_LIMIT, BROWSER_STABLE_FRAME_COUNT, BROWSER_STOP_LOADING_TIMEOUT_MS, BROWSER_TEST_ID_ATTRIBUTE, BROWSER_WAIT_POLL_INTERVAL_MS, BrowserAccessibility, BrowserClock, BrowserCodegen, BrowserContext, BrowserCookieManager, BrowserCoverage, BrowserDiagnostics, BrowserDialog, BrowserDownload, BrowserEmulationManager, BrowserError, BrowserFileChooser, BrowserFrame, BrowserHARManager, BrowserHandle, BrowserKeyboard, BrowserLocator, BrowserMouse, BrowserNavigationManager, BrowserNetworkManager, BrowserPage, BrowserPerformance, BrowserPermissionManager, BrowserResultLimitError, BrowserRoute, BrowserScriptManager, BrowserSelectorError, BrowserSelectorManager, BrowserStorageManager, BrowserTouch, BrowserTracing, BrowserWebSocket, BrowserWorker, CDPClient, CDPConnectionError, CDPError, CDPTimeoutError, ancestorsOfBrowserNode, attributeOfBrowserNode, browserHARHeadersToRecord, browserHeadersToProtocol, browserPDFToParams, browserScreenshotToParams, bytesToText, childrenOfBrowserNode, closestBrowserNode, commonAncestorOfBrowserNodes, compileActionabilityFunction, compileAttachedLocatorWaitExpression, compileAttachedWaitExpression, compileBrowserBindingCleanup, compileBrowserBindingResult, compileBrowserBindingSource, compileClickExpression, compileCodegenScript, compileDetachedLocatorWaitExpression, compileDetachedWaitExpression, compileFillExpression, compileFunctionWaitExpression, compileHiddenLocatorWaitExpression, compileHiddenWaitExpression, compileLocatorExpression, compileLocatorListExpression, compileScreenshotCleanupExpression, compileScreenshotPreparationExpression, compileSelectExpression, compileStorageClearExpression, compileStorageReadExpression, compileStorageRestoreExpression, compileVisibleLocatorWaitExpression, compileVisibleWaitExpression, computeBrowserButtons, computeBrowserModifiers, computeBrowserNodeDistance, concatBytes, cookieToProtocol, createBrowserHAREntry, createCDPClient, decodeBase64, decodeBrowserAttributes, decodeBrowserSnapshot, decodeRareBooleanData, decodeRareIntegerData, decodeRareStringData, descendantsOfBrowserNode, documentOfBrowserNode, encodeBase64, findBrowserDescendant, findBrowserNode, findBrowserNodes, followingSiblingsOfBrowserNode, guardEvaluateExpression, isBrowserError, isBrowserNodeDescendant, isBrowserNodeVisible, isBrowserResultLimitError, isBrowserSelectorError, isCDPConnectionError, isCDPError, isCDPTimeoutError, keyToBrowserInput, matchesBrowserCookieURL, matchesBrowserNode, matchesBrowserRoute, matchesBrowserURL, mediaToFeatures, nodeToPath, normalizeCodegenActions, parentOfBrowserNode, parseBrowserChord, parseCodegenActionPayload, precedingSiblingsOfBrowserNode, readBrowserAXString, readBrowserAXValue, readBrowserAccessibility, readBrowserBindingCall, readBrowserConsoleMessage, readBrowserCookie, readBrowserCookiePartition, readBrowserCookies, readBrowserCoverageRanges, readBrowserDownloadProgress, readBrowserDownloadStart, readBrowserFrames, readBrowserHeaders, readBrowserMetrics, readBrowserPageError, readBrowserProfile, readBrowserProfileFrame, readBrowserQuad, readBrowserRect, readBrowserRemoteValue, readBrowserRequest, readBrowserRequestFailure, readBrowserResponse, readBrowserResponseRecord, readBrowserScriptCoverage, readBrowserScriptIdentifier, readBrowserSecurity, readBrowserStack, readBrowserStorageEntries, readBrowserStorageOrigin, readBrowserStreamChunk, readBrowserStyleCoverage, readBrowserTiming, readBrowserTimingRange, readBrowserWebSocketFrame, readCodegenNavigateAction, readEvaluationResult, readNumberArray, readSnapshotString, requireBrowserString, siblingsOfBrowserNode, textToBytes, validateBrowserAccessibilityOptions, validateBrowserActionOptions, validateBrowserContextOptions, validateBrowserEmulationOptions, validateBrowserHAR, validateBrowserPoint, validateBrowserRange, validateBrowserTimeout, validateBrowserViewport, walkBrowserNode, walkBrowserNodeBreadthFirst, walkBrowserSnapshot, walkBrowserSnapshotBreadthFirst };
7127
+ export { BASE64_CHARS, BASE64_LOOKUP, BROWSER_CODEGEN_BINDING_NAME, BROWSER_CODEGEN_SOURCE, BROWSER_DEFAULT_TIMEOUT_MS, BROWSER_DEFAULT_VIEWPORT_HEIGHT, BROWSER_DEFAULT_VIEWPORT_WIDTH, BROWSER_FRAME_WORLD_NAME, BROWSER_HAR_CREATOR, BROWSER_KEY_MODIFIERS, BROWSER_MOUSE_BUTTON_MASKS, BROWSER_RESULT_LIMIT, BROWSER_RESULT_LIMIT_PATTERN, BROWSER_RESULT_LIMIT_SENTINEL_PREFIX, BROWSER_SCREENSHOT_ATTRIBUTE, BROWSER_SNAPSHOT_NODE_LIMIT, BROWSER_STABLE_FRAME_COUNT, BROWSER_STOP_LOADING_TIMEOUT_MS, BROWSER_TEST_ID_ATTRIBUTE, BROWSER_WAIT_POLL_INTERVAL_MS, BrowserAccessibility, BrowserClock, BrowserCodegen, BrowserContext, BrowserCookieManager, BrowserCoverage, BrowserDiagnostics, BrowserDialog, BrowserDownload, BrowserEmulationManager, BrowserError, BrowserFileChooser, BrowserFrame, BrowserHARManager, BrowserHandle, BrowserKeyboard, BrowserLocator, BrowserMouse, BrowserNavigationManager, BrowserNetworkManager, BrowserPage, BrowserPerformance, BrowserPermissionManager, BrowserResultLimitError, BrowserRoute, BrowserScriptManager, BrowserSelectorError, BrowserSelectorManager, BrowserSnapshot, BrowserStorageManager, BrowserTouch, BrowserTracing, BrowserWebSocket, BrowserWorker, CDPClient, CDPConnectionError, CDPError, CDPTimeoutError, attributeOfBrowserNode, browserHARHeadersToRecord, browserHeadersToProtocol, browserPDFToParams, browserScreenshotToParams, bytesToText, compileActionabilityFunction, compileAttachedLocatorWaitExpression, compileAttachedWaitExpression, compileBrowserBindingCleanup, compileBrowserBindingResult, compileBrowserBindingSource, compileClickExpression, compileCodegenScript, compileDetachedLocatorWaitExpression, compileDetachedWaitExpression, compileFillExpression, compileFunctionWaitExpression, compileHiddenLocatorWaitExpression, compileHiddenWaitExpression, compileLocatorExpression, compileLocatorListExpression, compileScreenshotCleanupExpression, compileScreenshotPreparationExpression, compileSelectExpression, compileStorageClearExpression, compileStorageReadExpression, compileStorageRestoreExpression, compileVisibleLocatorWaitExpression, compileVisibleWaitExpression, computeBrowserButtons, computeBrowserModifiers, concatBytes, cookieToProtocol, createBrowserHAREntry, createBrowserSnapshot, createCDPClient, decodeBase64, decodeBrowserAttributes, decodeBrowserSnapshot, decodeRareBooleanData, decodeRareIntegerData, decodeRareStringData, encodeBase64, guardEvaluateExpression, isBrowserError, isBrowserNodeQuery, isBrowserNodeVisible, isBrowserResultLimitError, isBrowserSelectorError, isCDPConnectionError, isCDPError, isCDPTimeoutError, keyToBrowserInput, matchesBrowserCookieURL, matchesBrowserNode, matchesBrowserRoute, matchesBrowserURL, mediaToFeatures, normalizeCodegenActions, parseBrowserChord, parseCodegenActionPayload, readBrowserAXString, readBrowserAXValue, readBrowserAccessibility, readBrowserBindingCall, readBrowserConsoleMessage, readBrowserCookie, readBrowserCookiePartition, readBrowserCookies, readBrowserCoverageRanges, readBrowserDownloadProgress, readBrowserDownloadStart, readBrowserFrames, readBrowserHeaders, readBrowserMetrics, readBrowserPageError, readBrowserProfile, readBrowserProfileFrame, readBrowserQuad, readBrowserRect, readBrowserRemoteValue, readBrowserRequest, readBrowserRequestFailure, readBrowserResponse, readBrowserResponseRecord, readBrowserScriptCoverage, readBrowserScriptIdentifier, readBrowserSecurity, readBrowserStack, readBrowserStorageEntries, readBrowserStorageOrigin, readBrowserStreamChunk, readBrowserStyleCoverage, readBrowserTiming, readBrowserTimingRange, readBrowserWebSocketFrame, readCodegenNavigateAction, readEvaluationResult, readNumberArray, readSnapshotString, requireBrowserString, textToBytes, validateBrowserAccessibilityOptions, validateBrowserActionOptions, validateBrowserContextOptions, validateBrowserEmulationOptions, validateBrowserHAR, validateBrowserPoint, validateBrowserRange, validateBrowserTimeout, validateBrowserViewport };
7208
7128
 
7209
7129
  //# sourceMappingURL=index.js.map