"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 }); })();