PageSourceSearch

https://kingtechcare.vn/wp-content/plugins/meta-tracking/assets/js/diagnostic/event-inspector.js?ver=2.1.3

js kingtechcare.vn collected 2026-10-07 22:57:01 UTC 16,670 bytes, 359 lines download raw bytes

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.