1(function () { 2 if (!window.MetaTracking?.diagnostic_enabled || window.__MetaEventInspectorLoaded) return; 3 window.__MetaEventInspectorLoaded = true; 4 5 const diagnosticUrl = window.MetaTracking.diagnostic_url; 6 const tokenUrl = window.MetaTracking.queue_token_url; 7 if (!diagnosticUrl || !tokenUrl) return; 8 9 const buffer = []; 10 let flushTimer = null; 11 let authCache = null; 12 let flushing = false; 13 14 function uuid() { 15 if (window.crypto && typeof window.crypto.randomUUID === "function") return window.crypto.randomUUID(); 16 return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) { 17 const r = Math.random() * 16 | 0; 18 const v = c === "x" ? r : (r & 0x3 | 0x8); 19 return v.toString(16); 20 }); 21 } 22 23 function readCookie(name) { 24 const match = document.cookie.match(new RegExp("(?:^|; )" + name.replace(/[.$?*|{}()[\]\\/+^]/g, "\\$&") + "=([^;]*)")); 25 return match ? decodeURIComponent(match[1]) : ""; 26 } 27 28 let sessionId = readCookie("mt_diag_session"); 29 if (!/^[A-Za-z0-9._:-]{1,64}$/.test(sessionId)) { 30 sessionId = "diag_" + uuid().replace(/-/g, "").slice(0, 24); 31 document.cookie = `mt_diag_session=${encodeURIComponent(sessionId)}; path=/; max-age=7200; SameSite=Lax${location.protocol === "https:" ? "; Secure" : ""}`; 32 } 33 34 function clip(value, max = 250) { 35 return String(value == null ? "" : value).replace(/[\r\n\t]+/g, " ").slice(0, max); 36 } 37 38 function safeClasses(el) { 39 if (!el?.classList) return []; 40 return Array.from(el.classList).slice(0, 12).map((v) => clip(v, 80)); 41 } 42 43 function safeUrl(raw) { 44 try { 45 const url = new URL(raw, location.href); 46 const out = { origin: url.origin === location.origin ? "same-origin" : url.origin, path: url.pathname }; 47 const queryKeys = Array.from(url.searchParams.keys()).slice(0, 20); 48 if (queryKeys.length) out.query_keys = queryKeys; 49 ["wc-ajax", "rest_route", "action"].forEach((key) => { 50 if (url.searchParams.has(key)) out[key.replace("-", "_")] = clip(url.searchParams.get(key), 120); 51 }); 52 return out; 53 } catch (error) { 54 return { path: clip(raw, 300) }; 55 } 56 } 57 58 function safeForm(form) { 59 if (!(form instanceof HTMLFormElement)) return {}; 60 return { 61 id: clip(form.id, 100), 62 name: clip(form.getAttribute("name"), 100), 63 classes: safeClasses(form), 64 method: clip(form.method || "GET", 10).toUpperCase(), 65 action: safeUrl(form.action || location.href), 66 valid: typeof form.checkValidity === "function" ? form.checkValidity() : null, 67 input_count: form.querySelectorAll("input,select,textarea").length 68 }; 69 } 70 71 function requestHint(body) { 72 try { 73 if (body instanceof FormData) { 74 const hint = {}; 75 ["action", "form_id", "product_id", "add-to-cart", "variation_id"].forEach((key) => { 76 const value = body.get(key); 77 if (value != null && typeof value !== "object") hint[key.replace("-", "_")] = clip(value, 120); 78 }); 79 return hint; 80 } 81 if (body instanceof URLSearchParams) { 82 const hint = {}; 83 ["action", "form_id", "product_id", "add-to-cart", "variation_id"].forEach((key) => { 84 if (body.has(key)) hint[key.replace("-", "_")] = clip(body.get(key), 120); 85 }); 86 return hint; 87 } 88 if (typeof body === "string" && body.length < 5000) { 89 const params = new URLSearchParams(body); 90 const hint = {}; 91 ["action", "form_id", "product_id", "add-to-cart", "variation_id"].forEach((key) => { 92 if (params.has(key)) hint[key.replace("-", "_")] = clip(params.get(key), 120); 93 }); 94 return hint; 95 } 96 } catch (error) {} 97 return {}; 98 } 99 100 function interestingNetwork(method, rawUrl) {
101 const m = String(method || "GET").toUpperCase(); 102 let path = ""; 103 try { path = new URL(rawUrl, location.href).pathname + new URL(rawUrl, location.href).search; } catch (error) { path = String(rawUrl || ""); } 104 return ["POST", "PUT", "PATCH", "DELETE"].includes(m) || 105 /wc-ajax|\/wp-json\/wc\/|\/wc\/store\/|admin-ajax\.php|contact-form-7|wpforms|fluent|gravity|elementor/i.test(path); 106 } 107 108 function log(type, name, details = {}) { 109 buffer.push({ type: clip(type, 64), name: clip(name, 191), details }); 110 if (buffer.length >= 20) scheduleFlush(50); 111 else scheduleFlush(700); 112 } 113 114 function scheduleFlush(delay) { 115 if (flushTimer) return; 116 flushTimer = setTimeout(() => { 117 flushTimer = null; 118 flush(); 119 }, delay); 120 } 121 122 async function getAuth(force = false) { 123 if (!force && authCache && authCache.expiresAt > Date.now() + 60000) return authCache; 124 const response = await window.fetch(tokenUrl, { 125 method: "GET", 126 credentials: "same-origin", 127 cache: "no-store", 128 headers: { "Accept": "application/json", "X-Meta-Diagnostic-Internal": "1" } 129 }); 130 const data = await response.json().catch(() => ({})); 131 if (!response.ok || !data?.success) throw new Error("Diagnostic token request failed"); 132 authCache = { 133 timestamp: data.timestamp, 134 signature: data.signature, 135 expiresAt: Date.now() + Math.max(60000, Number(data.expires_in || 1800) * 1000) 136 }; 137 return authCache; 138 } 139 140 async function flush(forceAuth = false) { 141 if (flushing || !buffer.length) return; 142 flushing = true; 143 const items = buffer.splice(0, 50); 144 try { 145 const auth = await getAuth(forceAuth); 146 const response = await window.fetch(diagnosticUrl, { 147 method: "POST", 148 credentials: "same-origin", 149 cache: "no-store", 150 headers: { 151 "Content-Type": "application/json", 152 "Accept": "application/json", 153 "X-Meta-Timestamp": String(auth.timestamp), 154 "X-Meta-Signature": String(auth.signature), 155 "X-Meta-Diagnostic-Internal": "1" 156 }, 157 body: JSON.stringify({ session_id: sessionId, items }), 158 keepalive: true 159 }); 160 if ((response.status === 401 || response.status === 403) && !forceAuth) { 161 authCache = null; 162 buffer.unshift(...items); 163 flushing = false; 164 return flush(true); 165 } 166 if (!response.ok) throw new Error(`Diagnostic POST failed (${response.status})`); 167 } catch (error) { 168 // Keep a bounded local retry buffer; never block site behavior. 169 buffer.unshift(...items); 170 if (buffer.length > 200) buffer.splice(0, buffer.length - 200); 171 } finally { 172 flushing = false; 173 if (buffer.length) scheduleFlush(2000); 174 } 175 } 176 177 // Record initial page context and presence of data bridges. 178 function snapshot(reason) { 179 const summary = { 180 reason, 181 page: safeUrl(location.href), 182 body_classes: safeClasses(document.body), 183 events_enabled: Object.assign({}, window.MetaEventsEnabled || {}) 184 }; 185 ["meta-product-data", "meta-cart-data", "meta-order-data"].forEach((id) => { 186 const el = document.getElementById(id); 187 summary[id.replace(/-/g, "_")] = !!el; 188 if (el) { 189 try { 190 const data = JSON.parse(el.textContent || "{}"); 191 summary[id.replace(/-/g, "_") + "_summary"] = { 192 product_id: data.product_id || undefined, 193 order_id: data.order_id || undefined, 194 item_count: data.item_count || data.items?.length || undefined, 195 currency: data.currency || undefined, 196 total: data.total ?? data.totals?.grand_total ?? undefined 197 }; 198 } catch (error) { 199 summary[id.replace(/-/g, "_") + "_parse_error"] = true; 200 } 201 } 202 }); 203 log("page", "page_snapshot", summary); 204 } 205 206 document.addEventListener("click", function (event) { 207 const el = event.target?.closest?.("button,a,input[type=submit],input[type=button]"); 208 if (!el) return; 209 log("dom", "click", { 210 tag: el.tagName,
211 id: clip(el.id, 100), 212 classes: safeClasses(el), 213 text: clip(el.innerText || el.value || el.getAttribute("aria-label"), 100), 214 href: el.tagName === "A" ? safeUrl(el.href) : undefined, 215 data_product_id: clip(el.getAttribute("data-product_id") || el.dataset?.productId, 80) 216 }); 217 }, true); 218 219 document.addEventListener("submit", function (event) { 220 log("form", "submit", safeForm(event.target)); 221 }, true); 222 223 ["wpcf7invalid", "wpcf7spam", "wpcf7mailfailed", "wpcf7mailsent", "wpcf7submit"].forEach((eventName) => { 224 document.addEventListener(eventName, function (event) { 225 log("lead", eventName, { form: safeForm(event.target), contact_form_id: event.detail?.contactFormId || undefined }); 226 }); 227 }); 228 229 document.addEventListener("MetaTrackingReady", function () { 230 log("meta_tracking", "MetaTrackingReady", {}); 231 }); 232 233 // Observe jQuery events used by WooCommerce and common form integrations. 234 function bindJqueryEvents() { 235 if (!window.jQuery || window.__MetaDiagJqueryBound) return; 236 window.__MetaDiagJqueryBound = true; 237 const $ = window.jQuery; 238 239 $(document.body).on("adding_to_cart added_to_cart removed_from_cart updated_wc_div wc_fragments_refreshed init_checkout update_checkout updated_checkout checkout_error payment_method_selected", function (event, arg1, arg2, arg3) { 240 const details = {}; 241 if (arg3 && (arg3.jquery || arg3.nodeType)) { 242 const el = arg3.jquery ? arg3.get(0) : arg3; 243 details.element = { id: clip(el?.id, 100), classes: safeClasses(el), data_product_id: clip(el?.getAttribute?.("data-product_id"), 80) }; 244 } 245 log("jquery", event.type, details); 246 }); 247 248 $(document).on("found_variation reset_data submit_success submit_error", function (event, arg) { 249 const details = {}; 250 if (event.type === "found_variation" && arg) { 251 details.variation_id = arg.variation_id || undefined; 252 details.display_price = arg.display_price ?? undefined; 253 } 254 details.form = safeForm(event.target?.closest?.("form") || event.target); 255 log("jquery", event.type, details); 256 }); 257 } 258 259 bindJqueryEvents(); 260 let jqueryTries = 0; 261 const jqueryTimer = setInterval(() => { 262 bindJqueryEvents(); 263 jqueryTries++; 264 if (window.__MetaDiagJqueryBound || jqueryTries > 50) clearInterval(jqueryTimer); 265 }, 200); 266 267 // Wrap MetaQueue.enqueue so we can distinguish "trigger never fired" from "delivery failed". 268 function wrapMetaQueue() { 269 if (!window.MetaQueue?.enqueue || window.MetaQueue.__diagnosticWrapped) return false; 270 const original = window.MetaQueue.enqueue.bind(window.MetaQueue); 271 window.MetaQueue.enqueue = function (eventName, customData, options) { 272 log("meta_tracking", "enqueue_called", { 273 event_name: clip(eventName, 100), 274 event_id: clip(options?.event_id || "auto", 191), 275 custom_data_keys: customData && typeof customData === "object" ? Object.keys(customData).slice(0, 30) : [], 276 content_ids: Array.isArray(customData?.content_ids) ? customData.content_ids.slice(0, 20) : undefined, 277 value: typeof customData?.value === "number" ? customData.value : undefined, 278 currency: clip(customData?.currency, 20) 279 }); 280 try { 281 const result = original(eventName, customData, options); 282 if (result && typeof result.then === "function") { 283 result.then((payload) => log("meta_tracking", "enqueue_resolved", { 284 event_name: clip(eventName, 100), event_id: clip(payload?.event_id, 191) 285 })).catch((error) => log("meta_tracking", "enqueue_rejected", { 286 event_name: clip(eventName, 100), error: clip(error?.message, 200) 287 })); 288 } 289 return result; 290 } catch (error) { 291 log("meta_tracking", "enqueue_exception", { event_name: clip(eventName, 100), error: clip(error?.message, 200) }); 292 throw error; 293 } 294 }; 295 window.MetaQueue.__diagnosticWrapped = true; 296 return true; 297 } 298 299 if (!wrapMetaQueue()) { 300 let queueTries = 0; 301 const queueTimer = setInterval(() => { 302 queueTries++; 303 if (wrapMetaQueue() || queueTries > 50) clearInterval(queueTimer); 304 }, 100); 305 } 306 307 // Fetch instrumentation. Never read or log request/response bodies. 308 const nativeFetch = window.fetch.bind(window); 309 window.fetch = async function (input, init = {}) { 310 const rawUrl = typeof input === "string" ? input : (input?.url || ""); 311 const method = String(init?.method || input?.method || "GET").toUpperCase(); 312 const internal = init?.headers && ((init.headers instanceof Headers && init.headers.get("X-Meta-Diagnostic-Internal")) || (typeof init.headers === "object" && init.headers["X-Meta-Diagnostic-Internal"])); 313 const inspect = !internal && interestingNetwork(method, rawUrl); 314 const started = performance.now(); 315 if (inspect) log("network", "fetch_request", { method, url: safeUrl(rawUrl), hint: requestHint(init?.body) }); 316 try { 317 const response = await nativeFetch(input, init); 318 if (inspect) log("network", "fetch_response", { method, url: safeUrl(rawUrl), status: response.status, ok: response.ok, duration_ms: Math.round(performance.now() - started) }); 319 return response; 320 } catch (error) { 321 if (inspect) log("network", "fetch_error", { method, url: safeUrl(rawUrl), error: clip(error?.message, 200), duration_ms: Math.round(performance.now() - started) }); 322 throw error; 323 } 324 }; 325 326 // XHR instrumentation for classic WooCommerce and form plugins. 327 const NativeXHR = window.XMLHttpRequest;
328 if (NativeXHR?.prototype) { 329 const nativeOpen = NativeXHR.prototype.open; 330 const nativeSend = NativeXHR.prototype.send; 331 NativeXHR.prototype.open = function (method, url) { 332 this.__mtDiag = { method: String(method || "GET").toUpperCase(), url: String(url || ""), started: 0 }; 333 return nativeOpen.apply(this, arguments); 334 }; 335 NativeXHR.prototype.send = function (body) { 336 const meta = this.__mtDiag || { method: "GET", url: "" }; 337 const inspect = interestingNetwork(meta.method, meta.url) && !/meta-tracking\/v1\/diagnostic|meta-tracking\/v1\/queue-token/.test(meta.url); 338 meta.started = performance.now(); 339 if (inspect) log("network", "xhr_request", { method: meta.method, url: safeUrl(meta.url), hint: requestHint(body) }); 340 if (inspect) { 341 this.addEventListener("loadend", () => { 342 log("network", "xhr_response", { method: meta.method, url: safeUrl(meta.url), status: this.status, duration_ms: Math.round(performance.now() - meta.started) }); 343 }, { once: true }); 344 } 345 return nativeSend.apply(this, arguments); 346 }; 347 } 348 349 if (document.readyState === "loading") { 350 document.addEventListener("DOMContentLoaded", () => snapshot("DOMContentLoaded"), { once: true }); 351 } else { 352 snapshot("already_loaded"); 353 } 354 355 window.addEventListener("pageshow", () => snapshot("pageshow")); 356 window.addEventListener("beforeunload", () => { if (buffer.length) flush(); }); 357 358 log("diagnostic", "inspector_started", { session_id: sessionId, version: window.MetaTracking?.version || "" }); 359})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.