This commit is contained in:
2026-08-05 21:39:14 -05:00
commit b8d7e732d5
13 changed files with 1791 additions and 0 deletions

182
page-probe.js Normal file
View File

@@ -0,0 +1,182 @@
"use strict";
(function initPageProbe() {
const EVENT_SOURCE = "S3_CAPTURE_PROBE";
let lastAudioResponseUrl = "";
function emit(kind, payload) {
try {
window.postMessage(
{
source: EVENT_SOURCE,
kind,
payload: payload || {}
},
"*"
);
} catch (error) {
// Ignore probe emission errors.
}
}
function safeString(value) {
return typeof value === "string" ? value : "";
}
function markLastAudioUrl(url, contentType) {
const maybeUrl = safeString(url);
const maybeType = safeString(contentType).toLowerCase();
if (!maybeUrl) {
return;
}
if (maybeType.startsWith("audio/") || maybeUrl.includes("audio_samples/")) {
lastAudioResponseUrl = maybeUrl;
}
}
function patchFetch() {
if (typeof window.fetch !== "function") {
return;
}
const currentFetch = window.fetch;
if (currentFetch.__s3CapturePatched) {
return;
}
const wrappedFetch = function wrappedFetch(input, init) {
const requestUrl =
typeof input === "string"
? input
: input && typeof input.url === "string"
? input.url
: "";
emit("fetch-request", { requestUrl });
return currentFetch.call(this, input, init).then(
(response) => {
const responseUrl = response && typeof response.url === "string" ? response.url : "";
const contentType = response && response.headers ? response.headers.get("content-type") : "";
markLastAudioUrl(responseUrl, contentType);
emit("fetch-response", {
requestUrl,
responseUrl,
status: response ? response.status : 0,
contentType: contentType || ""
});
return response;
},
(error) => {
emit("fetch-error", {
requestUrl,
error: error && error.message ? error.message : "fetch failed"
});
throw error;
}
);
};
wrappedFetch.__s3CapturePatched = true;
window.fetch = wrappedFetch;
}
function patchXhr() {
if (!window.XMLHttpRequest || !window.XMLHttpRequest.prototype) {
return;
}
const proto = window.XMLHttpRequest.prototype;
if (proto.open.__s3CapturePatched) {
return;
}
const originalOpen = proto.open;
const originalSend = proto.send;
proto.open = function patchedOpen(method, url) {
this.__s3CaptureRequestUrl = safeString(url);
emit("xhr-open", {
method: safeString(method),
requestUrl: this.__s3CaptureRequestUrl
});
return originalOpen.apply(this, arguments);
};
proto.open.__s3CapturePatched = true;
proto.send = function patchedSend() {
const xhr = this;
xhr.addEventListener(
"loadend",
function onLoadEnd() {
const responseUrl = safeString(xhr.responseURL);
const contentType = safeString(xhr.getResponseHeader("content-type"));
markLastAudioUrl(responseUrl || xhr.__s3CaptureRequestUrl, contentType);
emit("xhr-response", {
requestUrl: safeString(xhr.__s3CaptureRequestUrl),
responseUrl,
status: xhr.status || 0,
contentType
});
},
{ once: true }
);
return originalSend.apply(this, arguments);
};
}
function patchCreateObjectURL() {
if (!window.URL || typeof window.URL.createObjectURL !== "function") {
return;
}
const current = window.URL.createObjectURL;
if (current.__s3CapturePatched) {
return;
}
const wrapped = function wrappedCreateObjectURL(blob) {
const objectUrl = current.call(this, blob);
const blobType = blob && typeof blob.type === "string" ? blob.type : "";
const blobSize = blob && typeof blob.size === "number" ? blob.size : 0;
emit("blob-created", {
blobUrl: objectUrl,
blobType,
blobSize,
linkedUrl: lastAudioResponseUrl
});
return objectUrl;
};
wrapped.__s3CapturePatched = true;
window.URL.createObjectURL = wrapped;
}
function patchDecodeAudioData(ctor) {
if (!ctor || !ctor.prototype || typeof ctor.prototype.decodeAudioData !== "function") {
return;
}
const current = ctor.prototype.decodeAudioData;
if (current.__s3CapturePatched) {
return;
}
const wrapped = function wrappedDecodeAudioData(audioData) {
const byteLength =
audioData && typeof audioData.byteLength === "number" ? audioData.byteLength : 0;
emit("decode-audio-data", {
byteLength,
linkedUrl: lastAudioResponseUrl
});
return current.apply(this, arguments);
};
wrapped.__s3CapturePatched = true;
ctor.prototype.decodeAudioData = wrapped;
}
patchFetch();
patchXhr();
patchCreateObjectURL();
patchDecodeAudioData(window.AudioContext);
patchDecodeAudioData(window.OfflineAudioContext);
emit("probe-ready", { href: window.location.href });
})();