@opensteer/browser-core 0.7.1 → 0.7.3

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.cjs CHANGED
@@ -1045,6 +1045,9 @@ var FakeBrowserCoreEngine = class {
1045
1045
  (pageRef) => clone(this.pageInfoFromState(this.requirePage(pageRef)))
1046
1046
  );
1047
1047
  }
1048
+ async drainEvents(input) {
1049
+ return this.drainQueuedEvents(input.pageRef);
1050
+ }
1048
1051
  async listFrames(input) {
1049
1052
  this.requireCapability("inspector.frameEnumeration");
1050
1053
  const page = this.requirePage(input.pageRef);
@@ -1068,9 +1071,30 @@ var FakeBrowserCoreEngine = class {
1068
1071
  const document = this.resolveDocumentInput(input);
1069
1072
  return clone(document.domSnapshot);
1070
1073
  }
1074
+ async getActionBoundarySnapshot(input) {
1075
+ this.requireCapability("inspector.frameEnumeration");
1076
+ const page = this.requirePage(input.pageRef);
1077
+ const mainFrameRef = Array.from(page.frameRefs).find(
1078
+ (frameRef) => this.requireFrame(frameRef).frameInfo.isMainFrame
1079
+ );
1080
+ if (mainFrameRef === void 0) {
1081
+ throw createBrowserCoreError(
1082
+ "operation-failed",
1083
+ `page ${input.pageRef} does not expose a main frame`
1084
+ );
1085
+ }
1086
+ const frame = this.requireFrame(mainFrameRef);
1087
+ return {
1088
+ pageRef: input.pageRef,
1089
+ documentRef: frame.frameInfo.documentRef,
1090
+ url: frame.frameInfo.url
1091
+ };
1092
+ }
1071
1093
  async waitForVisualStability(_input) {
1072
1094
  this.requireCapability("inspector.visualStability");
1073
1095
  }
1096
+ async waitForPostLoadQuiet(_input) {
1097
+ }
1074
1098
  async readText(input) {
1075
1099
  this.requireCapability("inspector.text");
1076
1100
  const document = this.requireLiveNode(input);
@@ -2843,7 +2867,360 @@ function sleep(ms) {
2843
2867
  return new Promise((resolve) => setTimeout(resolve, ms));
2844
2868
  }
2845
2869
 
2870
+ // src/post-load-tracker.ts
2871
+ var DEFAULT_POST_LOAD_TRACKER_QUIET_WINDOW_MS = 400;
2872
+ var DEFAULT_ACTION_BOUNDARY_POLL_INTERVAL_MS = 100;
2873
+ function isRecord(value) {
2874
+ return typeof value === "object" && value !== null;
2875
+ }
2876
+ function readFiniteNumber(value) {
2877
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
2878
+ }
2879
+ function readNonNegativeNumber(value) {
2880
+ const parsed = readFiniteNumber(value);
2881
+ return parsed === void 0 || parsed < 0 ? 0 : parsed;
2882
+ }
2883
+ function normalizePostLoadTrackerState(value) {
2884
+ if (!isRecord(value)) {
2885
+ return void 0;
2886
+ }
2887
+ const installedAt = readFiniteNumber(value.installedAt);
2888
+ const lastMutationAt = readFiniteNumber(value.lastMutationAt);
2889
+ const lastNetworkActivityAt = readFiniteNumber(value.lastNetworkActivityAt);
2890
+ const lastTrackedNetworkActivityAt = readFiniteNumber(value.lastTrackedNetworkActivityAt);
2891
+ const now = readFiniteNumber(value.now);
2892
+ const readyState = typeof value.readyState === "string" ? value.readyState : void 0;
2893
+ if (installedAt === void 0 || lastMutationAt === void 0 || lastNetworkActivityAt === void 0 || lastTrackedNetworkActivityAt === void 0 || now === void 0 || readyState === void 0) {
2894
+ return void 0;
2895
+ }
2896
+ return {
2897
+ installedAt,
2898
+ lastMutationAt,
2899
+ lastNetworkActivityAt,
2900
+ lastTrackedNetworkActivityAt,
2901
+ now,
2902
+ pendingFetches: readNonNegativeNumber(value.pendingFetches),
2903
+ pendingTimeouts: readNonNegativeNumber(value.pendingTimeouts),
2904
+ pendingXhrs: readNonNegativeNumber(value.pendingXhrs),
2905
+ trackedPendingFetches: readNonNegativeNumber(value.trackedPendingFetches),
2906
+ trackedPendingXhrs: readNonNegativeNumber(value.trackedPendingXhrs),
2907
+ collecting: value.collecting === true,
2908
+ readyState
2909
+ };
2910
+ }
2911
+ function buildPostLoadTrackerInstallScript() {
2912
+ return `(() => {
2913
+ const globalObject = globalThis;
2914
+ if (globalObject.__opensteerActionBoundaryTrackerInstalled) {
2915
+ return true;
2916
+ }
2917
+
2918
+ const tracker = {
2919
+ installedAt: performance.now(),
2920
+ lastMutationAt: performance.now(),
2921
+ lastNetworkActivityAt: performance.now(),
2922
+ lastTrackedNetworkActivityAt: performance.now(),
2923
+ pendingFetches: 0,
2924
+ pendingTimeouts: 0,
2925
+ pendingXhrs: 0,
2926
+ trackedPendingFetches: 0,
2927
+ trackedPendingXhrs: 0,
2928
+ collecting: true,
2929
+ readyState: document.readyState,
2930
+ };
2931
+ globalObject.__opensteerActionBoundaryTrackerInstalled = true;
2932
+ globalObject.__opensteerActionBoundaryTracker = tracker;
2933
+
2934
+ const markMutation = () => {
2935
+ tracker.lastMutationAt = performance.now();
2936
+ tracker.readyState = document.readyState;
2937
+ };
2938
+ const markNetwork = () => {
2939
+ tracker.lastNetworkActivityAt = performance.now();
2940
+ tracker.readyState = document.readyState;
2941
+ };
2942
+ const markTrackedNetwork = () => {
2943
+ tracker.lastTrackedNetworkActivityAt = performance.now();
2944
+ markNetwork();
2945
+ };
2946
+ const resetTracking = () => {
2947
+ const now = performance.now();
2948
+ tracker.lastTrackedNetworkActivityAt = now;
2949
+ tracker.trackedPendingFetches = 0;
2950
+ tracker.trackedPendingXhrs = 0;
2951
+ tracker.collecting = true;
2952
+ tracker.readyState = document.readyState;
2953
+ };
2954
+
2955
+ const startObserver = () => {
2956
+ const target = document.documentElement ?? document;
2957
+ if (!(target instanceof Node)) {
2958
+ return;
2959
+ }
2960
+ const observer = new MutationObserver(markMutation);
2961
+ observer.observe(target, {
2962
+ subtree: true,
2963
+ childList: true,
2964
+ characterData: true,
2965
+ attributes: true,
2966
+ });
2967
+ markMutation();
2968
+ };
2969
+
2970
+ if (document.documentElement) {
2971
+ startObserver();
2972
+ } else {
2973
+ document.addEventListener("DOMContentLoaded", startObserver, { once: true });
2974
+ }
2975
+
2976
+ document.addEventListener("readystatechange", markMutation);
2977
+ addEventListener("load", markMutation, { once: true });
2978
+
2979
+ if (typeof globalObject.fetch === "function") {
2980
+ const nativeFetch = globalObject.fetch.bind(globalObject);
2981
+ globalObject.fetch = (...args) => {
2982
+ const tracked = tracker.collecting === true;
2983
+ tracker.pendingFetches += 1;
2984
+ if (tracked) {
2985
+ tracker.trackedPendingFetches += 1;
2986
+ markTrackedNetwork();
2987
+ } else {
2988
+ markNetwork();
2989
+ }
2990
+ return nativeFetch(...args)
2991
+ .finally(() => {
2992
+ tracker.pendingFetches = Math.max(0, tracker.pendingFetches - 1);
2993
+ if (tracked) {
2994
+ tracker.trackedPendingFetches = Math.max(0, tracker.trackedPendingFetches - 1);
2995
+ markTrackedNetwork();
2996
+ } else {
2997
+ markNetwork();
2998
+ }
2999
+ });
3000
+ };
3001
+ }
3002
+
3003
+ if (typeof globalObject.XMLHttpRequest === "function") {
3004
+ const NativeXMLHttpRequest = globalObject.XMLHttpRequest;
3005
+ const nativeSend = NativeXMLHttpRequest.prototype.send;
3006
+ NativeXMLHttpRequest.prototype.send = function(...args) {
3007
+ const tracked = tracker.collecting === true;
3008
+ tracker.pendingXhrs += 1;
3009
+ if (tracked) {
3010
+ tracker.trackedPendingXhrs += 1;
3011
+ markTrackedNetwork();
3012
+ } else {
3013
+ markNetwork();
3014
+ }
3015
+ const finalize = () => {
3016
+ this.removeEventListener("loadend", finalize);
3017
+ tracker.pendingXhrs = Math.max(0, tracker.pendingXhrs - 1);
3018
+ if (tracked) {
3019
+ tracker.trackedPendingXhrs = Math.max(0, tracker.trackedPendingXhrs - 1);
3020
+ markTrackedNetwork();
3021
+ } else {
3022
+ markNetwork();
3023
+ }
3024
+ };
3025
+ this.addEventListener("loadend", finalize, { once: true });
3026
+ return nativeSend.apply(this, args);
3027
+ };
3028
+ }
3029
+
3030
+ tracker.beginObservation = () => {
3031
+ resetTracking();
3032
+ return true;
3033
+ };
3034
+ tracker.freezeObservation = () => {
3035
+ tracker.collecting = false;
3036
+ tracker.readyState = document.readyState;
3037
+ return true;
3038
+ };
3039
+
3040
+ return true;
3041
+ })()`;
3042
+ }
3043
+ function buildPostLoadTrackerBeginExpression() {
3044
+ return `(() => {
3045
+ const tracker = globalThis.__opensteerActionBoundaryTracker;
3046
+ if (!tracker || typeof tracker.beginObservation !== "function") {
3047
+ return false;
3048
+ }
3049
+ return tracker.beginObservation();
3050
+ })()`;
3051
+ }
3052
+ function buildPostLoadTrackerFreezeExpression() {
3053
+ return `(() => {
3054
+ const tracker = globalThis.__opensteerActionBoundaryTracker;
3055
+ if (!tracker || typeof tracker.freezeObservation !== "function") {
3056
+ return false;
3057
+ }
3058
+ return tracker.freezeObservation();
3059
+ })()`;
3060
+ }
3061
+ function buildPostLoadTrackerReadExpression() {
3062
+ return `(() => {
3063
+ const tracker = globalThis.__opensteerActionBoundaryTracker;
3064
+ if (!tracker) {
3065
+ return null;
3066
+ }
3067
+
3068
+ return {
3069
+ installedAt: Number(tracker.installedAt ?? 0),
3070
+ lastMutationAt: Number(tracker.lastMutationAt ?? 0),
3071
+ lastNetworkActivityAt: Number(tracker.lastNetworkActivityAt ?? 0),
3072
+ lastTrackedNetworkActivityAt: Number(tracker.lastTrackedNetworkActivityAt ?? 0),
3073
+ now: Number(performance.now()),
3074
+ pendingFetches: Number(tracker.pendingFetches ?? 0),
3075
+ pendingTimeouts: Number(tracker.pendingTimeouts ?? 0),
3076
+ pendingXhrs: Number(tracker.pendingXhrs ?? 0),
3077
+ trackedPendingFetches: Number(tracker.trackedPendingFetches ?? 0),
3078
+ trackedPendingXhrs: Number(tracker.trackedPendingXhrs ?? 0),
3079
+ collecting: tracker.collecting === true,
3080
+ readyState: String(document.readyState),
3081
+ };
3082
+ })()`;
3083
+ }
3084
+ function capturePostLoadTrackerSnapshot(tracker) {
3085
+ return {
3086
+ lastTrackedNetworkActivityAt: tracker.lastTrackedNetworkActivityAt,
3087
+ trackedPendingFetches: tracker.trackedPendingFetches,
3088
+ trackedPendingXhrs: tracker.trackedPendingXhrs
3089
+ };
3090
+ }
3091
+ function postLoadTrackerHasTrackedNetworkActivitySince(snapshot, tracker) {
3092
+ if (!tracker) {
3093
+ return false;
3094
+ }
3095
+ return tracker.trackedPendingFetches > snapshot.trackedPendingFetches || tracker.trackedPendingXhrs > snapshot.trackedPendingXhrs || tracker.lastTrackedNetworkActivityAt > snapshot.lastTrackedNetworkActivityAt;
3096
+ }
3097
+ function postLoadTrackerIsSettled(tracker, quietWindowMs = DEFAULT_POST_LOAD_TRACKER_QUIET_WINDOW_MS) {
3098
+ if (!tracker) {
3099
+ return false;
3100
+ }
3101
+ if (tracker.readyState !== "complete") {
3102
+ return false;
3103
+ }
3104
+ if (tracker.trackedPendingFetches > 0 || tracker.trackedPendingXhrs > 0) {
3105
+ return false;
3106
+ }
3107
+ const lastActivityAt = Math.max(
3108
+ tracker.installedAt,
3109
+ tracker.lastMutationAt,
3110
+ tracker.lastTrackedNetworkActivityAt
3111
+ );
3112
+ return tracker.now - lastActivityAt >= quietWindowMs;
3113
+ }
3114
+
3115
+ // src/action-boundary.ts
3116
+ var CROSS_DOCUMENT_INTERACTION_TIMEOUT_MS = 3e4;
3117
+ var CROSS_DOCUMENT_DETECTION_WINDOW_MS = 500;
3118
+ async function waitForActionBoundary(input) {
3119
+ if (input.timeoutMs <= 0) {
3120
+ return {
3121
+ trigger: "dom-action",
3122
+ crossDocument: false,
3123
+ bootstrapSettled: false,
3124
+ timedOutPhase: "bootstrap"
3125
+ };
3126
+ }
3127
+ const deadline = Date.now() + input.timeoutMs;
3128
+ const crossDocumentDetectionDeadline = input.snapshot === void 0 ? void 0 : Math.min(deadline, Date.now() + CROSS_DOCUMENT_DETECTION_WINDOW_MS);
3129
+ const pollIntervalMs = input.pollIntervalMs ?? DEFAULT_ACTION_BOUNDARY_POLL_INTERVAL_MS;
3130
+ let trigger = "dom-action";
3131
+ let crossDocument = false;
3132
+ let sameDocumentAsyncActivity = false;
3133
+ while (Date.now() < deadline) {
3134
+ input.throwBackgroundError();
3135
+ if (input.isPageClosed()) {
3136
+ return {
3137
+ trigger,
3138
+ crossDocument,
3139
+ bootstrapSettled: true
3140
+ };
3141
+ }
3142
+ if (input.signal?.aborted) {
3143
+ if (isTimeoutAbort(input.signal.reason) && Date.now() >= deadline) {
3144
+ return {
3145
+ trigger,
3146
+ crossDocument,
3147
+ bootstrapSettled: false,
3148
+ timedOutPhase: "bootstrap"
3149
+ };
3150
+ }
3151
+ throw abortError(input.signal);
3152
+ }
3153
+ const currentDocumentRef = input.getCurrentMainFrameDocumentRef();
3154
+ const currentPageUrl = input.getCurrentPageUrl?.();
3155
+ if (input.snapshot !== void 0 && currentDocumentRef !== void 0 && currentDocumentRef !== input.snapshot.documentRef) {
3156
+ trigger = "navigation";
3157
+ crossDocument = true;
3158
+ }
3159
+ if (!crossDocument && !sameDocumentAsyncActivity && input.snapshot?.tracker !== void 0 && postLoadTrackerHasTrackedNetworkActivitySince(
3160
+ input.snapshot.tracker,
3161
+ await input.readTrackerState()
3162
+ )) {
3163
+ trigger = "navigation";
3164
+ sameDocumentAsyncActivity = true;
3165
+ }
3166
+ if (!crossDocument && input.snapshot?.url !== void 0 && currentPageUrl !== void 0 && currentPageUrl !== input.snapshot.url && input.isCurrentMainFrameBootstrapSettled !== void 0 && !input.isCurrentMainFrameBootstrapSettled()) {
3167
+ trigger = "navigation";
3168
+ crossDocument = true;
3169
+ }
3170
+ if (!crossDocument && crossDocumentDetectionDeadline !== void 0 && Date.now() >= crossDocumentDetectionDeadline) {
3171
+ return {
3172
+ trigger,
3173
+ crossDocument,
3174
+ bootstrapSettled: true
3175
+ };
3176
+ }
3177
+ if (sameDocumentAsyncActivity) {
3178
+ return {
3179
+ trigger,
3180
+ crossDocument,
3181
+ bootstrapSettled: true
3182
+ };
3183
+ }
3184
+ if (crossDocument && input.isCurrentMainFrameBootstrapSettled !== void 0 && !input.isCurrentMainFrameBootstrapSettled()) {
3185
+ await delay(Math.min(pollIntervalMs, Math.max(0, deadline - Date.now())));
3186
+ continue;
3187
+ }
3188
+ if (crossDocument) {
3189
+ return {
3190
+ trigger,
3191
+ crossDocument,
3192
+ bootstrapSettled: true
3193
+ };
3194
+ }
3195
+ await delay(Math.min(pollIntervalMs, Math.max(0, deadline - Date.now())));
3196
+ }
3197
+ return {
3198
+ trigger,
3199
+ crossDocument,
3200
+ bootstrapSettled: false,
3201
+ timedOutPhase: "bootstrap"
3202
+ };
3203
+ }
3204
+ function abortError(signal) {
3205
+ return signal.reason ?? new DOMException("The operation was aborted", "AbortError");
3206
+ }
3207
+ async function delay(ms) {
3208
+ if (ms <= 0) {
3209
+ return;
3210
+ }
3211
+ await new Promise((resolve) => {
3212
+ setTimeout(resolve, ms);
3213
+ });
3214
+ }
3215
+ function isTimeoutAbort(reason) {
3216
+ return typeof reason === "object" && reason !== null && "code" in reason && reason.code === "timeout";
3217
+ }
3218
+
2846
3219
  exports.BrowserCoreError = BrowserCoreError;
3220
+ exports.CROSS_DOCUMENT_DETECTION_WINDOW_MS = CROSS_DOCUMENT_DETECTION_WINDOW_MS;
3221
+ exports.CROSS_DOCUMENT_INTERACTION_TIMEOUT_MS = CROSS_DOCUMENT_INTERACTION_TIMEOUT_MS;
3222
+ exports.DEFAULT_ACTION_BOUNDARY_POLL_INTERVAL_MS = DEFAULT_ACTION_BOUNDARY_POLL_INTERVAL_MS;
3223
+ exports.DEFAULT_POST_LOAD_TRACKER_QUIET_WINDOW_MS = DEFAULT_POST_LOAD_TRACKER_QUIET_WINDOW_MS;
2847
3224
  exports.DEFAULT_VISUAL_STABILITY_SETTLE_MS = DEFAULT_VISUAL_STABILITY_SETTLE_MS;
2848
3225
  exports.DEFAULT_VISUAL_STABILITY_TIMEOUT_MS = DEFAULT_VISUAL_STABILITY_TIMEOUT_MS;
2849
3226
  exports.DOM_SNAPSHOT_COMPUTED_STYLE_NAMES = DOM_SNAPSHOT_COMPUTED_STYLE_NAMES;
@@ -2853,6 +3230,11 @@ exports.bodyPayloadFromUtf8 = bodyPayloadFromUtf8;
2853
3230
  exports.brand = brand;
2854
3231
  exports.buildCdpShadowBoundaryIndex = buildCdpShadowBoundaryIndex;
2855
3232
  exports.buildDomSnapshotFromCdpCapture = buildDomSnapshotFromCdpCapture;
3233
+ exports.buildPostLoadTrackerBeginExpression = buildPostLoadTrackerBeginExpression;
3234
+ exports.buildPostLoadTrackerFreezeExpression = buildPostLoadTrackerFreezeExpression;
3235
+ exports.buildPostLoadTrackerInstallScript = buildPostLoadTrackerInstallScript;
3236
+ exports.buildPostLoadTrackerReadExpression = buildPostLoadTrackerReadExpression;
3237
+ exports.capturePostLoadTrackerSnapshot = capturePostLoadTrackerSnapshot;
2856
3238
  exports.closedPageError = closedPageError;
2857
3239
  exports.closedSessionError = closedSessionError;
2858
3240
  exports.createBodyPayload = createBodyPayload;
@@ -2899,7 +3281,10 @@ exports.mergeBrowserCapabilities = mergeBrowserCapabilities;
2899
3281
  exports.nextDocumentEpoch = nextDocumentEpoch;
2900
3282
  exports.noBrowserCapabilities = noBrowserCapabilities;
2901
3283
  exports.normalizeCdpShadowRootType = normalizeCdpShadowRootType;
3284
+ exports.normalizePostLoadTrackerState = normalizePostLoadTrackerState;
2902
3285
  exports.parseCdpStringTable = parseCdpStringTable;
3286
+ exports.postLoadTrackerHasTrackedNetworkActivitySince = postLoadTrackerHasTrackedNetworkActivitySince;
3287
+ exports.postLoadTrackerIsSettled = postLoadTrackerIsSettled;
2903
3288
  exports.quadBounds = quadBounds;
2904
3289
  exports.rareCdpIntegerValue = rareCdpIntegerValue;
2905
3290
  exports.rareCdpStringValue = rareCdpStringValue;
@@ -2909,6 +3294,7 @@ exports.serializeDocumentEpoch = serializeDocumentEpoch;
2909
3294
  exports.serializeRef = serializeRef;
2910
3295
  exports.staleNodeRefError = staleNodeRefError;
2911
3296
  exports.unsupportedCapabilityError = unsupportedCapabilityError;
3297
+ exports.waitForActionBoundary = waitForActionBoundary;
2912
3298
  exports.waitForCdpVisualStability = waitForCdpVisualStability;
2913
3299
  //# sourceMappingURL=index.cjs.map
2914
3300
  //# sourceMappingURL=index.cjs.map