@opensteer/browser-core 0.7.0 → 0.7.2

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
@@ -2843,7 +2843,287 @@ function sleep(ms) {
2843
2843
  return new Promise((resolve) => setTimeout(resolve, ms));
2844
2844
  }
2845
2845
 
2846
+ // src/post-load-tracker.ts
2847
+ var DEFAULT_POST_LOAD_TRACKER_QUIET_WINDOW_MS = 400;
2848
+ var DEFAULT_ACTION_BOUNDARY_POLL_INTERVAL_MS = 100;
2849
+ function isRecord(value) {
2850
+ return typeof value === "object" && value !== null;
2851
+ }
2852
+ function readFiniteNumber(value) {
2853
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
2854
+ }
2855
+ function readNonNegativeNumber(value) {
2856
+ const parsed = readFiniteNumber(value);
2857
+ return parsed === void 0 || parsed < 0 ? 0 : parsed;
2858
+ }
2859
+ function normalizePostLoadTrackerState(value) {
2860
+ if (!isRecord(value)) {
2861
+ return void 0;
2862
+ }
2863
+ const installedAt = readFiniteNumber(value.installedAt);
2864
+ const lastMutationAt = readFiniteNumber(value.lastMutationAt);
2865
+ const lastNetworkActivityAt = readFiniteNumber(value.lastNetworkActivityAt);
2866
+ const now = readFiniteNumber(value.now);
2867
+ const readyState = typeof value.readyState === "string" ? value.readyState : void 0;
2868
+ if (installedAt === void 0 || lastMutationAt === void 0 || lastNetworkActivityAt === void 0 || now === void 0 || readyState === void 0) {
2869
+ return void 0;
2870
+ }
2871
+ return {
2872
+ installedAt,
2873
+ lastMutationAt,
2874
+ lastNetworkActivityAt,
2875
+ now,
2876
+ pendingFetches: readNonNegativeNumber(value.pendingFetches),
2877
+ pendingTimeouts: readNonNegativeNumber(value.pendingTimeouts),
2878
+ pendingXhrs: readNonNegativeNumber(value.pendingXhrs),
2879
+ readyState
2880
+ };
2881
+ }
2882
+ function buildPostLoadTrackerInstallScript() {
2883
+ return `(() => {
2884
+ const globalObject = globalThis;
2885
+ if (globalObject.__opensteerActionBoundaryTrackerInstalled) {
2886
+ return true;
2887
+ }
2888
+
2889
+ const tracker = {
2890
+ installedAt: performance.now(),
2891
+ lastMutationAt: performance.now(),
2892
+ lastNetworkActivityAt: performance.now(),
2893
+ pendingFetches: 0,
2894
+ pendingTimeouts: 0,
2895
+ pendingXhrs: 0,
2896
+ readyState: document.readyState,
2897
+ timeoutIds: new Set(),
2898
+ };
2899
+ globalObject.__opensteerActionBoundaryTrackerInstalled = true;
2900
+ globalObject.__opensteerActionBoundaryTracker = tracker;
2901
+
2902
+ const markMutation = () => {
2903
+ tracker.lastMutationAt = performance.now();
2904
+ tracker.readyState = document.readyState;
2905
+ };
2906
+ const markNetwork = () => {
2907
+ tracker.lastNetworkActivityAt = performance.now();
2908
+ tracker.readyState = document.readyState;
2909
+ };
2910
+
2911
+ const startObserver = () => {
2912
+ const target = document.documentElement ?? document;
2913
+ if (!(target instanceof Node)) {
2914
+ return;
2915
+ }
2916
+ const observer = new MutationObserver(markMutation);
2917
+ observer.observe(target, {
2918
+ subtree: true,
2919
+ childList: true,
2920
+ characterData: true,
2921
+ attributes: true,
2922
+ });
2923
+ markMutation();
2924
+ };
2925
+
2926
+ if (document.documentElement) {
2927
+ startObserver();
2928
+ } else {
2929
+ document.addEventListener("DOMContentLoaded", startObserver, { once: true });
2930
+ }
2931
+
2932
+ document.addEventListener("readystatechange", markMutation);
2933
+ addEventListener("load", markMutation, { once: true });
2934
+
2935
+ const nativeSetTimeout = globalObject.setTimeout.bind(globalObject);
2936
+ const nativeClearTimeout = globalObject.clearTimeout.bind(globalObject);
2937
+ globalObject.setTimeout = function(callback, delay, ...args) {
2938
+ tracker.pendingTimeouts += 1;
2939
+ markNetwork();
2940
+ let handle;
2941
+ const wrapped =
2942
+ typeof callback === "function"
2943
+ ? (...callbackArgs) => {
2944
+ if (tracker.timeoutIds.delete(handle)) {
2945
+ tracker.pendingTimeouts = Math.max(0, tracker.pendingTimeouts - 1);
2946
+ }
2947
+ try {
2948
+ return callback(...callbackArgs);
2949
+ } finally {
2950
+ markMutation();
2951
+ }
2952
+ }
2953
+ : callback;
2954
+ handle = nativeSetTimeout(wrapped, delay, ...args);
2955
+ tracker.timeoutIds.add(handle);
2956
+ return handle;
2957
+ };
2958
+ globalObject.clearTimeout = function(handle) {
2959
+ if (tracker.timeoutIds.delete(handle)) {
2960
+ tracker.pendingTimeouts = Math.max(0, tracker.pendingTimeouts - 1);
2961
+ }
2962
+ return nativeClearTimeout(handle);
2963
+ };
2964
+
2965
+ if (typeof globalObject.fetch === "function") {
2966
+ const nativeFetch = globalObject.fetch.bind(globalObject);
2967
+ globalObject.fetch = (...args) => {
2968
+ tracker.pendingFetches += 1;
2969
+ markNetwork();
2970
+ return nativeFetch(...args)
2971
+ .finally(() => {
2972
+ tracker.pendingFetches = Math.max(0, tracker.pendingFetches - 1);
2973
+ markNetwork();
2974
+ });
2975
+ };
2976
+ }
2977
+
2978
+ if (typeof globalObject.XMLHttpRequest === "function") {
2979
+ const NativeXMLHttpRequest = globalObject.XMLHttpRequest;
2980
+ const nativeSend = NativeXMLHttpRequest.prototype.send;
2981
+ NativeXMLHttpRequest.prototype.send = function(...args) {
2982
+ tracker.pendingXhrs += 1;
2983
+ markNetwork();
2984
+ const finalize = () => {
2985
+ this.removeEventListener("loadend", finalize);
2986
+ tracker.pendingXhrs = Math.max(0, tracker.pendingXhrs - 1);
2987
+ markNetwork();
2988
+ };
2989
+ this.addEventListener("loadend", finalize, { once: true });
2990
+ return nativeSend.apply(this, args);
2991
+ };
2992
+ }
2993
+
2994
+ return true;
2995
+ })()`;
2996
+ }
2997
+ function buildPostLoadTrackerReadExpression() {
2998
+ return `(() => {
2999
+ const tracker = globalThis.__opensteerActionBoundaryTracker;
3000
+ if (!tracker) {
3001
+ return null;
3002
+ }
3003
+
3004
+ return {
3005
+ installedAt: Number(tracker.installedAt ?? 0),
3006
+ lastMutationAt: Number(tracker.lastMutationAt ?? 0),
3007
+ lastNetworkActivityAt: Number(tracker.lastNetworkActivityAt ?? 0),
3008
+ now: Number(performance.now()),
3009
+ pendingFetches: Number(tracker.pendingFetches ?? 0),
3010
+ pendingTimeouts: Number(tracker.pendingTimeouts ?? 0),
3011
+ pendingXhrs: Number(tracker.pendingXhrs ?? 0),
3012
+ readyState: String(document.readyState),
3013
+ };
3014
+ })()`;
3015
+ }
3016
+ function postLoadTrackerIsSettled(tracker, quietWindowMs = DEFAULT_POST_LOAD_TRACKER_QUIET_WINDOW_MS) {
3017
+ if (!tracker) {
3018
+ return false;
3019
+ }
3020
+ if (tracker.readyState !== "complete") {
3021
+ return false;
3022
+ }
3023
+ if (tracker.pendingFetches > 0 || tracker.pendingTimeouts > 0 || tracker.pendingXhrs > 0) {
3024
+ return false;
3025
+ }
3026
+ const lastActivityAt = Math.max(
3027
+ tracker.installedAt,
3028
+ tracker.lastMutationAt,
3029
+ tracker.lastNetworkActivityAt
3030
+ );
3031
+ return tracker.now - lastActivityAt >= quietWindowMs;
3032
+ }
3033
+
3034
+ // src/action-boundary.ts
3035
+ var CROSS_DOCUMENT_INTERACTION_TIMEOUT_MS = 3e4;
3036
+ var CROSS_DOCUMENT_DETECTION_WINDOW_MS = 500;
3037
+ async function waitForActionBoundary(input) {
3038
+ if (input.timeoutMs <= 0) {
3039
+ return {
3040
+ trigger: "dom-action",
3041
+ crossDocument: false,
3042
+ bootstrapSettled: false,
3043
+ timedOutPhase: "bootstrap"
3044
+ };
3045
+ }
3046
+ const deadline = Date.now() + input.timeoutMs;
3047
+ const crossDocumentDetectionDeadline = input.snapshot === void 0 ? void 0 : Math.min(deadline, Date.now() + CROSS_DOCUMENT_DETECTION_WINDOW_MS);
3048
+ const pollIntervalMs = input.pollIntervalMs ?? DEFAULT_ACTION_BOUNDARY_POLL_INTERVAL_MS;
3049
+ let trigger = "dom-action";
3050
+ let crossDocument = false;
3051
+ let waitedForNavigationContentLoaded = false;
3052
+ while (Date.now() < deadline) {
3053
+ input.throwBackgroundError();
3054
+ if (input.isPageClosed()) {
3055
+ return {
3056
+ trigger,
3057
+ crossDocument,
3058
+ bootstrapSettled: true
3059
+ };
3060
+ }
3061
+ if (input.signal?.aborted) {
3062
+ if (isTimeoutAbort(input.signal.reason) && Date.now() >= deadline) {
3063
+ return {
3064
+ trigger,
3065
+ crossDocument,
3066
+ bootstrapSettled: false,
3067
+ timedOutPhase: "bootstrap"
3068
+ };
3069
+ }
3070
+ throw abortError(input.signal);
3071
+ }
3072
+ const currentDocumentRef = input.getCurrentMainFrameDocumentRef();
3073
+ if (input.snapshot !== void 0 && currentDocumentRef !== void 0 && currentDocumentRef !== input.snapshot.documentRef) {
3074
+ trigger = "navigation";
3075
+ crossDocument = true;
3076
+ if (!waitedForNavigationContentLoaded) {
3077
+ waitedForNavigationContentLoaded = true;
3078
+ const remaining = Math.max(0, deadline - Date.now());
3079
+ if (remaining > 0) {
3080
+ await input.waitForNavigationContentLoaded(remaining);
3081
+ }
3082
+ }
3083
+ }
3084
+ if (!crossDocument && crossDocumentDetectionDeadline !== void 0 && Date.now() >= crossDocumentDetectionDeadline) {
3085
+ return {
3086
+ trigger,
3087
+ crossDocument,
3088
+ bootstrapSettled: true
3089
+ };
3090
+ }
3091
+ if (crossDocument && postLoadTrackerIsSettled(await input.readTrackerState())) {
3092
+ return {
3093
+ trigger,
3094
+ crossDocument,
3095
+ bootstrapSettled: true
3096
+ };
3097
+ }
3098
+ await delay(Math.min(pollIntervalMs, Math.max(0, deadline - Date.now())));
3099
+ }
3100
+ return {
3101
+ trigger,
3102
+ crossDocument,
3103
+ bootstrapSettled: false,
3104
+ timedOutPhase: "bootstrap"
3105
+ };
3106
+ }
3107
+ function abortError(signal) {
3108
+ return signal.reason ?? new DOMException("The operation was aborted", "AbortError");
3109
+ }
3110
+ async function delay(ms) {
3111
+ if (ms <= 0) {
3112
+ return;
3113
+ }
3114
+ await new Promise((resolve) => {
3115
+ setTimeout(resolve, ms);
3116
+ });
3117
+ }
3118
+ function isTimeoutAbort(reason) {
3119
+ return typeof reason === "object" && reason !== null && "code" in reason && reason.code === "timeout";
3120
+ }
3121
+
2846
3122
  exports.BrowserCoreError = BrowserCoreError;
3123
+ exports.CROSS_DOCUMENT_DETECTION_WINDOW_MS = CROSS_DOCUMENT_DETECTION_WINDOW_MS;
3124
+ exports.CROSS_DOCUMENT_INTERACTION_TIMEOUT_MS = CROSS_DOCUMENT_INTERACTION_TIMEOUT_MS;
3125
+ exports.DEFAULT_ACTION_BOUNDARY_POLL_INTERVAL_MS = DEFAULT_ACTION_BOUNDARY_POLL_INTERVAL_MS;
3126
+ exports.DEFAULT_POST_LOAD_TRACKER_QUIET_WINDOW_MS = DEFAULT_POST_LOAD_TRACKER_QUIET_WINDOW_MS;
2847
3127
  exports.DEFAULT_VISUAL_STABILITY_SETTLE_MS = DEFAULT_VISUAL_STABILITY_SETTLE_MS;
2848
3128
  exports.DEFAULT_VISUAL_STABILITY_TIMEOUT_MS = DEFAULT_VISUAL_STABILITY_TIMEOUT_MS;
2849
3129
  exports.DOM_SNAPSHOT_COMPUTED_STYLE_NAMES = DOM_SNAPSHOT_COMPUTED_STYLE_NAMES;
@@ -2853,6 +3133,8 @@ exports.bodyPayloadFromUtf8 = bodyPayloadFromUtf8;
2853
3133
  exports.brand = brand;
2854
3134
  exports.buildCdpShadowBoundaryIndex = buildCdpShadowBoundaryIndex;
2855
3135
  exports.buildDomSnapshotFromCdpCapture = buildDomSnapshotFromCdpCapture;
3136
+ exports.buildPostLoadTrackerInstallScript = buildPostLoadTrackerInstallScript;
3137
+ exports.buildPostLoadTrackerReadExpression = buildPostLoadTrackerReadExpression;
2856
3138
  exports.closedPageError = closedPageError;
2857
3139
  exports.closedSessionError = closedSessionError;
2858
3140
  exports.createBodyPayload = createBodyPayload;
@@ -2899,7 +3181,9 @@ exports.mergeBrowserCapabilities = mergeBrowserCapabilities;
2899
3181
  exports.nextDocumentEpoch = nextDocumentEpoch;
2900
3182
  exports.noBrowserCapabilities = noBrowserCapabilities;
2901
3183
  exports.normalizeCdpShadowRootType = normalizeCdpShadowRootType;
3184
+ exports.normalizePostLoadTrackerState = normalizePostLoadTrackerState;
2902
3185
  exports.parseCdpStringTable = parseCdpStringTable;
3186
+ exports.postLoadTrackerIsSettled = postLoadTrackerIsSettled;
2903
3187
  exports.quadBounds = quadBounds;
2904
3188
  exports.rareCdpIntegerValue = rareCdpIntegerValue;
2905
3189
  exports.rareCdpStringValue = rareCdpStringValue;
@@ -2909,6 +3193,7 @@ exports.serializeDocumentEpoch = serializeDocumentEpoch;
2909
3193
  exports.serializeRef = serializeRef;
2910
3194
  exports.staleNodeRefError = staleNodeRefError;
2911
3195
  exports.unsupportedCapabilityError = unsupportedCapabilityError;
3196
+ exports.waitForActionBoundary = waitForActionBoundary;
2912
3197
  exports.waitForCdpVisualStability = waitForCdpVisualStability;
2913
3198
  //# sourceMappingURL=index.cjs.map
2914
3199
  //# sourceMappingURL=index.cjs.map