PageSourceSearch

https://netmaispalmas.com.br/__l5e/events.js

js netmaispalmas.com.br collected 2026-10-08 12:29:16 UTC 65,760 bytes, 1,521 lines download raw bytes

1(()=>{const __name=(target)=>target;((w, version, schemaVersions, maxEventsPerBatch = 50, maxBatchBodyBytes = 50 * 1024, maxReplayBodyBytes = 512 * 1024, maxReplayEventsPerChunk = 100, maxReplayTotalBytes = 5 * 1024 * 1024, maxReplayChunks = 50, maxReplayDurationMs = 10 * 60 * 1e3, replayFlushIntervalMs = 2e3) => {
2  const existing = w.__lovableEvents || {};
3  if (existing.__userAppEventsSdkVersion) return;
4  const d = w.document;
5  const nav = w.navigator || {};
6  const automated = nav.webdriver === true || !!w.Cypress || !!w.__nightmare;
7  const perf = w.performance || { now: /* @__PURE__ */ __name(() => Date.now(), "now") };
8  const loc = w.location || { pathname: "", href: "", search: "" };
9  const resolveSetTimer = /* @__PURE__ */ __name(() => w.setTimeout || (typeof setTimeout === "function" ? setTimeout : null), "resolveSetTimer");
10  const resolveClearTimer = /* @__PURE__ */ __name(() => w.clearTimeout || (typeof clearTimeout === "function" ? clearTimeout : null), "resolveClearTimer");
11  const isInternalPath = /* @__PURE__ */ __name((path) => path === "/__codex_token_check" || path.startsWith("/__l5e/"), "isInternalPath");
12  if (isInternalPath(loc.pathname)) return;
13  const script = d && d.currentScript;
14  const artifact = script ? {
15    kind: script.getAttribute("data-artifact-kind") || null,
16    id: script.getAttribute("data-artifact-id") || null,
17    commit_sha: script.getAttribute("data-commit-sha") || null,
18    context_token: script.getAttribute("data-context-token") || null
19  } : {};
20  const replayMode = script?.getAttribute("data-replay") || null;
21  const trackUrl = script?.getAttribute("data-track-url") || "/__l5e/trackevents";
22  const replayUrl = script?.getAttribute("data-replay-url") || "/__l5e/replay";
23  const replayScriptUrl = script?.getAttribute("data-replay-script-url") || "/__l5e/rrweb-record.js";
24  const parseSampleRate = /* @__PURE__ */ __name((value) => {
25    const rate = typeof value === "string" ? Number(value) : 0;
26    if (!Number.isFinite(rate) || rate <= 0) return 0;
27    return rate >= 1 ? 1 : rate;
28  }, "parseSampleRate");
29  const replaySampleRate = parseSampleRate(script?.getAttribute("data-replay-sample-rate") || null);
30  const replayCrashSampleRate = parseSampleRate(script?.getAttribute("data-replay-crash-sample-rate") || null);
31  const autocaptureEnabled = script?.getAttribute("data-autocapture") === "1";
32  const randomId = /* @__PURE__ */ __name(() => w.crypto && typeof w.crypto.randomUUID === "function" ? w.crypto.randomUUID() : String(Date.now()) + "-" + Math.random().toString(16).slice(2), "randomId");
33  const randomTraceHex = /* @__PURE__ */ __name((byteCount) => {
34    const bytes = new Uint8Array(byteCount);
35    if (w.crypto && typeof w.crypto.getRandomValues === "function") {
36      w.crypto.getRandomValues(bytes);
37    } else {
38      for (let index = 0; index < bytes.length; index++) {
39        bytes[index] = Math.floor(Math.random() * 256);
40      }
41    }
42    if (bytes.every((byte) => byte === 0)) bytes[bytes.length - 1] = 1;
43    return Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
44  }, "randomTraceHex");
45  const createTraceContext = /* @__PURE__ */ __name(() => ({
46    traceId: randomTraceHex(16),
47    rootSpanId: randomTraceHex(8)
48  }), "createTraceContext");
49  const sessionId = randomId();
50  let appUserId = null;
51  let pageViewId = randomId();
52  let capturedClicks = 0;
53  let traceContext = createTraceContext();
54  let engagementAccruedMs = 0;
55  let engagementSegmentStart = null;
56  const ENGAGEMENT_EMIT_DELAYS_MS = [1e4, 3e4, 6e4, 3e5];
57  let engagementEmitStep = 0;
58  let engagementTimer = null;
59  const ENGAGEMENT_ACCRUAL_STOP_MS = 144e5;
60  let engagementReportedMs = 0;
61  let engagementCapped = false;
62  const ENGAGEMENT_UNFOCUSED_GRACE_MS = 18e5;
63  let engagementUnfocusedTimer = null;
64  let engagementUnfocusedSpentMs = 0;
65  let engagementUnfocusedArmedAt = 0;
66  let engagementStoppedUnfocused = false;
67  const unitIntervalFor = /* @__PURE__ */ __name((value) => {
68    let hash = 2166136261;
69    for (let index = 0; index < value.length; index++) {
70      hash ^= value.charCodeAt(index);
71      hash = Math.imul(hash, 16777619);
72    }
73    return (hash >>> 0) / 4294967296;
74  }, "unitIntervalFor");
75  const replaySamplingValue = unitIntervalFor(sessionId);
76  const isReplaySampledIn = replaySampleRate > 0 && replaySamplingValue < replaySampleRate;
77  const isReplayCrashSampledIn = replayCrashSampleRate > 0 && replaySamplingValue < replayCrashSampleRate;
78  const isReplayRecordingAllowed = isReplaySampledIn || isReplayCrashSampledIn;
79  const replayEffectiveSampleRate = isReplaySampledIn ? replaySampleRate : replayCrashSampleRate;
80  let replayId = null;
81  let replayEventCount = 0;
82  let replayStartedAt = 0;
83  let replayFinalized = false;
84  let stopReplayRecorder = null;
85  let replayChunkSequence = 0;
86  let replayThrottledChunks = 0;
87  let replayChunksInFlight = 0;
88  let replayBudgetStopReason = null;
89  let replayUploadedBytes = 0;
90  let replayFlushTimer = null;
91  let replayDurationTimer = null;
92  let replayRecorderActive = false;
93  let replayRecorderLoading = false;
94  let replayHasFullSnapshot = false;
95  let replayUploadEnabled = isReplaySampledIn;
96  let replayCaptureReason = isReplaySampledIn ? "sampled" : null;
97  let replayTriggerEventId = null;
98  let replayTriggerEventName = null;
99  let replayCaptureMetadataEmitted = false;
100  const replayQueue = [];
101  const maxReplayBufferedEvents = Math.max(maxReplayEventsPerChunk, maxReplayEventsPerChunk * maxReplayChunks);
102  const replayMaskTextSelector = [
103    "[data-lovable-mask]",
104    "[data-sensitive]",
105    "[data-private]",
106    "[data-auth]",
107    "[data-payment]",
108    "[contenteditable]",
109    "[autocomplete]",
110    "[name*='email' i]",
111    "[name*='phone' i]",
112    "[name*='address' i]",
113    "[name*='token' i]",
114    "[name*='secret' i]"
115  ].join(",");
116  const replayBlockSelector = [
117    "canvas",
118    "embed",
119    "iframe",
120    "object",
121    "video",
122    "[data-lovable-block]",
123    ".rr-block",
124    "[data-payment]",
125    "[data-auth]",
126    "[data-private]"
127  ].join(",");
128  const replayIgnoreSelector = "[data-lovable-ignore],.rrweb-ignore";
129  const maskReplayText = /* @__PURE__ */ __name((text) => text.replace(/[^\s]/gu, "*"), "maskReplayText");
130  const queue = [];
131  let flushTimer = null;
132  let sendingDisabled = false;
133  let sendRejectionReported = false;
134  let sendDisabledReported = false;
135  let unloadingPage = false;
136  let immediateErrorFlushes = 0;
137  let errorEventsSeen = 0;
138  const batchSize = Math.max(1, maxEventsPerBatch);
139  const maxImmediateErrorFlushes = 5;
140  const maxErrorEventsPerPageLoad = 200;
141  const projectEventNamePattern = /^project\.[a-z][a-z0-9_]{0,63}(\.[a-z][a-z0-9_]{0,63})*$/u;
142  const schemaVersionFor = /* @__PURE__ */ __name((eventName) => {
143    const schemaVersion = schemaVersions[eventName];
144    if (typeof schemaVersion === "number" && schemaVersion > 0) return schemaVersion;
145    return projectEventNamePattern.test(eventName) ? 1 : null;
146  }, "schemaVersionFor");
147  const textEncoder = typeof TextEncoder === "function" ? new TextEncoder() : null;
148  const byteLength = /* @__PURE__ */ __name((value) => textEncoder ? textEncoder.encode(value).length : value.length, "byteLength");
149  const createBatchBody = /* @__PURE__ */ __name((events) => JSON.stringify({
150    envelope_schema_version: 1,
151    batch_id: randomId(),
152    sent_at: (/* @__PURE__ */ new Date()).toISOString(),
153    sdk: { name: "lovable-user-app-events", version },
154    automated,
155    artifact,
156    events
157  }), "createBatchBody");
158  const report2 = /* @__PURE__ */ __name((message3) => {
159    const consoleRef = w.console;
160    if (consoleRef && typeof consoleRef.debug === "function") consoleRef.debug(`[lovable-analytics] ${message3}`);
161  }, "report");
162  const applyRejectedBatchStatus = /* @__PURE__ */ __name((status, routeMarker) => {
163    if ((status === 403 || status === 404) && routeMarker === "rejected") {
164      sendingDisabled = true;
165      queue.length = 0;
166      if (!sendDisabledReported) {
167        sendDisabledReported = true;
168        report2(`events disabled for this page load (HTTP ${status})`);
169      }
170      return;
171    }
172    if (sendRejectionReported) return;
173    sendRejectionReported = true;
174    report2(`event batch rejected (HTTP ${status})`);
175  }, "applyRejectedBatchStatus");
176  const keepalivePoolBytes = 64 * 1024;
177  const eventsKeepaliveReserveBytes = 16 * 1024;
178  let keepaliveBytesInFlight = 0;
179  let beaconBytesInFlight = 0;
180  const releaseBeaconBytes = /* @__PURE__ */ __name(() => {
181    keepaliveBytesInFlight -= beaconBytesInFlight;
182    beaconBytesInFlight = 0;
183  }, "releaseBeaconBytes");
184  const send = /* @__PURE__ */ __name((url, body, options) => {
185    const bodyBytes = byteLength(body);
186    const keepaliveLimitBytes = keepalivePoolBytes - (options.reserveBytes || 0);
187    const allowKeepalive = !!options.keepalive && keepaliveBytesInFlight + bodyBytes <= keepaliveLimitBytes;
188    if (allowKeepalive) keepaliveBytesInFlight += bodyBytes;
189    let charged = allowKeepalive;
190    const release = /* @__PURE__ */ __name(() => {
191      if (!charged) return;
192      charged = false;
193      keepaliveBytesInFlight -= bodyBytes;
194    }, "release");
195    const BlobCtor = w.Blob || (typeof Blob === "function" ? Blob : null);
196    if (allowKeepalive && options.beacon && nav.sendBeacon && BlobCtor) {
197      try {
198        const ok = nav.sendBeacon(url, new BlobCtor([body], { type: "application/json" }));
199        if (ok) {
200          beaconBytesInFlight += bodyBytes;
201          charged = false;
202          return;
203        }
204      } catch {
205      }
206    }
207    const fetchFn = w.fetch || (typeof fetch === "function" ? fetch : null);
208    if (!fetchFn) {
209      release();
210      options.onNetworkError?.();
211      return;
212    }
213    try {
214      Promise.resolve(
215        fetchFn(url, {
216          method: "POST",
217          headers: { "content-type": "application/json" },
218          body,
219          ...allowKeepalive ? { keepalive: true } : {}
220        })
221      ).then(
222        (response) => {
223          release();
224          options.onResponse?.(response);
225        },
226        () => {
227          release();
228          options.onNetworkError?.();
229        }
230      ).catch(() => {
231      });
232    } catch {
233      release();
234      options.onNetworkError?.();
235    }
236  }, "send");
237  const sendBatch = /* @__PURE__ */ __name((allEvents, unloading) => {
238    const events = allEvents.filter((event) => {
239      try {
240        JSON.stringify(event);
241        return true;
242      } catch {
243        return false;
244      }
245    });
246    let start = 0;
247    while (start < events.length) {
248      let end = events.length;
249      let body = createBatchBody(events.slice(start, end));
250      const remaining = keepalivePoolBytes - keepaliveBytesInFlight;
251      const splitLimit = unloading && remaining >= eventsKeepaliveReserveBytes ? Math.min(maxBatchBodyBytes, remaining) : maxBatchBodyBytes;
252      while (end - start > 1 && byteLength(body) > splitLimit) {
253        end = start + Math.max(1, Math.floor((end - start) / 2));
254        body = createBatchBody(events.slice(start, end));
255      }
256      send(trackUrl, body, {
257        keepalive: true,
258        beacon: unloading,
259        onResponse: /* @__PURE__ */ __name((response) => {
260          if (!response || response.ok !== false) return;
261          applyRejectedBatchStatus(response.status, response.headers?.get?.("x-lovable-events") ?? null);
262        }, "onResponse")
263      });
264      start = end;
265    }
266  }, "sendBatch");
267  const createReplayChunkBody = /* @__PURE__ */ __name((events, chunkID, chunkSequence) => {
268    if (!replayId) return null;
269    return JSON.stringify({
270      envelope_schema_version: 1,
271      replay_schema_version: 1,
272      replay_id: replayId,
273      chunk_id: chunkID,
274      chunk_sequence: chunkSequence,
275      sent_at: (/* @__PURE__ */ new Date()).toISOString(),
276      sdk: { name: "lovable-user-app-events", version },
277      automated,
278      artifact,
279      session_id: sessionId,
280      page_view_id: pageViewId,
281      events
282    });
283  }, "createReplayChunkBody");
284  const canSendReplayEvent = /* @__PURE__ */ __name((event) => {
285    const body = createReplayChunkBody([event], "00000000-0000-4000-8000-000000000000", replayChunkSequence);
286    return !!body && byteLength(body) <= maxReplayBodyBytes;
287  }, "canSendReplayEvent");
288  const replayEventType = /* @__PURE__ */ __name((event) => {
289    const record = event && typeof event === "object" ? event : null;
290    return typeof record?.type === "number" ? record.type : null;
291  }, "replayEventType");
292  const replayDurationMs = /* @__PURE__ */ __name(() => Math.max(0, perf.now() - replayStartedAt), "replayDurationMs");
293  const clearReplayFlushTimer = /* @__PURE__ */ __name(() => {
294    if (!replayFlushTimer) return;
295    const clearTimer = resolveClearTimer();
296    if (clearTimer) clearTimer(replayFlushTimer);
297    replayFlushTimer = null;
298  }, "clearReplayFlushTimer");
299  const clearReplayDurationTimer = /* @__PURE__ */ __name(() => {
300    if (!replayDurationTimer) return;
301    const clearTimer = resolveClearTimer();
302    if (clearTimer) clearTimer(replayDurationTimer);
303    replayDurationTimer = null;
304  }, "clearReplayDurationTimer");
305  const stopReplayRecorderSafely = /* @__PURE__ */ __name(() => {
306    try {
307      stopReplayRecorder?.();
308    } catch {
309    } finally {
310      stopReplayRecorder = null;
311      replayRecorderActive = false;
312    }
313  }, "stopReplayRecorderSafely");
314  const replayErrorStageFor = /* @__PURE__ */ __name((reason) => {
315    switch (reason) {
316      case "recorder_script_failed":
317        return "recorder_script";
318      case "recorder_start_failed":
319        return "recorder_start";
320      case "recorder_runtime_error":
321        return "recorder_runtime";
322      case "missing_full_snapshot":
323      case "full_snapshot_too_large":
324        return "snapshot";
325      case "upload_failed":
326        return "upload";
327      default:
328        return null;
329    }
330  }, "replayErrorStageFor");
331  const emitReplayErrorFor = /* @__PURE__ */ __name((targetReplayId, reason, eventCount, durationMs, chunkCount, uploadedBytes) => {
332    const stage = replayErrorStageFor(reason);
333    if (!stage) return;
334    enqueue("lovable.replay_error", {
335      replay_id: targetReplayId,
336      reason,
337      stage,
338      recorder: "rrweb",
339      sample_rate: replayEffectiveSampleRate,
340      event_count: eventCount,
341      duration_ms: durationMs,
342      chunk_count: chunkCount,
343      uploaded_bytes: uploadedBytes
344    });
345  }, "emitReplayErrorFor");
346  const replayCaptureProperties = /* @__PURE__ */ __name(() => !replayCaptureReason || replayCaptureReason === "sampled" ? {} : {
347    capture_reason: replayCaptureReason,
348    trigger_event_id: replayTriggerEventId,
349    trigger_event_name: replayTriggerEventName
350  }, "replayCaptureProperties");
351  const emitReplayMetadataFor = /* @__PURE__ */ __name((targetReplayId, status, reason, eventCount, durationMs, chunkCount, uploadedBytes) => {
352    enqueue("lovable.session_replay", {
353      replay_id: targetReplayId,
354      status,
355      reason,
356      recorder: "rrweb",
357      sample_rate: replayEffectiveSampleRate,
358      event_count: eventCount,
359      duration_ms: durationMs,
360      chunk_count: chunkCount,
361      uploaded_bytes: uploadedBytes,
362      ...replayCaptureProperties()
363    });
364    emitReplayErrorFor(targetReplayId, reason, eventCount, durationMs, chunkCount, uploadedBytes);
365  }, "emitReplayMetadataFor");
366  const emitReplayMetadata = /* @__PURE__ */ __name((status, reason) => {
367    if (!replayId) return;
368    emitReplayMetadataFor(
369      replayId,
370      status,
371      reason,
372      replayEventCount,
373      replayDurationMs(),
374      replayChunkSequence,
375      replayUploadedBytes
376    );
377  }, "emitReplayMetadata");
378  const shouldEmitReplayLifecycleMetadata = /* @__PURE__ */ __name(() => replayUploadEnabled || replayCaptureReason === "sampled", "shouldEmitReplayLifecycleMetadata");
379  const emitReplayMetadataOrErrorFor = /* @__PURE__ */ __name((targetReplayId, status, reason, eventCount, durationMs, chunkCount, uploadedBytes) => {
380    if (shouldEmitReplayLifecycleMetadata()) {
381      emitReplayMetadataFor(targetReplayId, status, reason, eventCount, durationMs, chunkCount, uploadedBytes);
382    } else {
383      emitReplayErrorFor(targetReplayId, reason, eventCount, durationMs, chunkCount, uploadedBytes);
384    }
385  }, "emitReplayMetadataOrErrorFor");
386  const stopReplayRecording = /* @__PURE__ */ __name((reason, dropQueuedEvents = false) => {
387    if (!replayId || replayFinalized) return;
388    stopReplayRecorderSafely();
389    clearReplayDurationTimer();
390    if (dropQueuedEvents) {
391      replayQueue.length = 0;
392      clearReplayFlushTimer();
393    }
394    if (shouldEmitReplayLifecycleMetadata()) {
395      emitReplayMetadata("stopped", reason);
396    }
397    replayFinalized = true;
398  }, "stopReplayRecording");
399  const stopReplayAtDurationLimit = /* @__PURE__ */ __name(() => {
400    if (!replayId || replayFinalized) return;
401    if (!replayUploadEnabled) {
402      stopReplayRecorderSafely();
403      clearReplayDurationTimer();
404      return;
405    }
406    stopReplayRecording("duration_limit", true);
407  }, "stopReplayAtDurationLimit");
408  const markReplayCapturedByClientError = /* @__PURE__ */ __name((triggerEventId) => {
409    if (!replayId || replayFinalized || replayCaptureReason === "client_error") return;
410    replayUploadEnabled = true;
411    replayCaptureReason = "client_error";
412    replayTriggerEventId = triggerEventId;
413    replayTriggerEventName = "lovable.client_error";
414    emitReplayCaptureMetadataIfReady();
415  }, "markReplayCapturedByClientError");
416  const hasReplayDataToCapture = /* @__PURE__ */ __name(() => replayQueue.length > 0 || replayChunkSequence > 0 || replayUploadedBytes > 0, "hasReplayDataToCapture");
417  const emitReplayCaptureMetadataIfReady = /* @__PURE__ */ __name(() => {
418    if (!replayId || replayFinalized || replayCaptureReason !== "client_error" || replayCaptureMetadataEmitted || !replayHasFullSnapshot || !hasReplayDataToCapture()) {
419      return false;
420    }
421    replayCaptureMetadataEmitted = true;
422    emitReplayMetadata("captured", "client_error");
423    flushReplay(true);
424    return true;
425  }, "emitReplayCaptureMetadataIfReady");
426  const endReplayOnSpentBudget = /* @__PURE__ */ __name((reason) => {
427    if (replayChunksInFlight > 0) {
428      replayBudgetStopReason = reason;
429      return;
430    }
431    stopReplayRecording(reason, true);
432  }, "endReplayOnSpentBudget");
433  const settleReplayChunk = /* @__PURE__ */ __name(() => {
434    replayChunksInFlight--;
435    if (replayFinalized || replayChunksInFlight > 0 || !replayBudgetStopReason) return;
436    const reason = replayBudgetStopReason;
437    replayBudgetStopReason = null;
438    if (replayThrottledChunks > 0) scheduleReplayFlush();
439    else stopReplayRecording(reason, true);
440  }, "settleReplayChunk");
441  const flushReplay = /* @__PURE__ */ __name((preferKeepalive = false) => {
442    clearReplayFlushTimer();
443    if (!replayUploadEnabled || !replayId || replayQueue.length === 0 || !replayHasFullSnapshot) return;
444    while (!replayFinalized && replayQueue.length > 0) {
445      let count2 = Math.min(replayQueue.length, maxReplayEventsPerChunk);
446      const chunkID = randomId();
447      const chunkSequence = replayChunkSequence;
448      let body = createReplayChunkBody(replayQueue.slice(0, count2), chunkID, chunkSequence);
449      while (body && count2 > 1 && byteLength(body) > maxReplayBodyBytes) {
450        count2 = Math.max(1, Math.floor(count2 / 2));
451        body = createReplayChunkBody(replayQueue.slice(0, count2), chunkID, chunkSequence);
452      }
453      if (!body) return;
454      const bodyBytes = byteLength(body);
455      if (bodyBytes > maxReplayBodyBytes) {
456        replayQueue.shift();
457        replayEventCount = Math.max(0, replayEventCount - 1);
458        continue;
459      }
460      const chunksStored = replayChunkSequence - replayThrottledChunks;
461      if (chunksStored >= maxReplayChunks || replayUploadedBytes + bodyBytes > maxReplayTotalBytes) {
462        endReplayOnSpentBudget(chunksStored >= maxReplayChunks ? "chunk_limit" : "size_limit");
463        return;
464      }
465      replayQueue.splice(0, count2);
466      replayChunkSequence++;
467      replayUploadedBytes += bodyBytes;
468      replayChunksInFlight++;
469      send(replayUrl, body, {
470        keepalive: preferKeepalive,
471        reserveBytes: eventsKeepaliveReserveBytes,
472        onResponse: /* @__PURE__ */ __name((response) => {
473          const throttled = response?.status === 429;
474          if (throttled) {
475            replayThrottledChunks++;
476            replayUploadedBytes -= bodyBytes;
477            replayEventCount = Math.max(0, replayEventCount - count2);
478          }
479          settleReplayChunk();
480          if (throttled || response && response.ok !== false) return;
481          const marker = response?.headers?.get?.("x-lovable-events");
482          const reason = marker === "unavailable" ? "upload_unavailable" : marker === "rejected" ? "upload_rejected" : "upload_failed";
483          stopReplayRecording(reason, true);
484        }, "onResponse"),
485        onNetworkError: /* @__PURE__ */ __name(() => {
486          stopReplayRecording("upload_failed", true);
487          settleReplayChunk();
488        }, "onNetworkError")
489      });
490      if (replayFinalized) return;
491      if (replayChunkSequence - replayThrottledChunks >= maxReplayChunks) {
492        endReplayOnSpentBudget("chunk_limit");
493        return;
494      }
495    }
496  }, "flushReplay");
497  const scheduleReplayFlush = /* @__PURE__ */ __name(() => {
498    if (replayFlushTimer) return;
499    const setTimer = resolveSetTimer();
500    if (!setTimer) {
501      flushReplay();
502      return;
503    }
504    replayFlushTimer = setTimer(flushReplay, replayFlushIntervalMs);
505  }, "scheduleReplayFlush");
506  const clearFlushTimer = /* @__PURE__ */ __name(() => {
507    if (!flushTimer) return;
508    const clearTimer = resolveClearTimer();
509    if (clearTimer) clearTimer(flushTimer);
510    flushTimer = null;
511  }, "clearFlushTimer");
512  const flush = /* @__PURE__ */ __name((unloading = false) => {
513    clearFlushTimer();
514    if (sendingDisabled || queue.length === 0) return;
515    const events = queue.splice(0, batchSize);
516    sendBatch(events, unloading || unloadingPage);
517    if (queue.length > 0) scheduleFlush();
518  }, "flush");
519  const scheduleFlush = /* @__PURE__ */ __name(() => {
520    if (flushTimer || sendingDisabled) return;
521    const setTimer = resolveSetTimer();
522    if (!setTimer) {
523      flush();
524      return;
525    }
526    flushTimer = setTimer(flush, 250);
527  }, "scheduleFlush");
528  const startEngagementSegment = /* @__PURE__ */ __name(() => {
529    if (engagementSegmentStart === null) engagementSegmentStart = perf.now();
530  }, "startEngagementSegment");
531  const stopEngagementSegment = /* @__PURE__ */ __name(() => {
532    engagementSegmentStart = null;
533  }, "stopEngagementSegment");
534  const clearEngagementTimer = /* @__PURE__ */ __name(() => {
535    const clearTimer = resolveClearTimer();
536    if (engagementTimer !== null && clearTimer) clearTimer(engagementTimer);
537    engagementTimer = null;
538  }, "clearEngagementTimer");
539  const takeEngagementDelta = /* @__PURE__ */ __name(() => {
540    if (engagementSegmentStart !== null) {
541      const nowMs = perf.now();
542      engagementAccruedMs += nowMs - engagementSegmentStart;
543      engagementSegmentStart = nowMs;
544    }
545    const delta = Math.round(engagementAccruedMs);
546    engagementAccruedMs = 0;
547    return delta;
548  }, "takeEngagementDelta");
549  const emitEngagement = /* @__PURE__ */ __name((reason) => {
550    const delta = takeEngagementDelta();
551    if (delta <= 0) return;
552    engagementReportedMs += delta;
553    const capping = engagementReportedMs >= ENGAGEMENT_ACCRUAL_STOP_MS;
554    if (capping) {
555      engagementCapped = true;
556      stopEngagementSegment();
557      clearEngagementTimer();
558    }
559    enqueue("lovable.page_engagement", { reason: capping ? "capped" : reason, engagement_time_ms: delta });
560  }, "emitEngagement");
561  const scheduleEngagementEmit = /* @__PURE__ */ __name(() => {
562    clearEngagementTimer();
563    const setTimer = resolveSetTimer();
564    if (!setTimer) return;
565    const delay = ENGAGEMENT_EMIT_DELAYS_MS[Math.min(engagementEmitStep, ENGAGEMENT_EMIT_DELAYS_MS.length - 1)];
566    engagementTimer = setTimer(() => {
567      engagementEmitStep++;
568      emitEngagement("threshold");
569      if (engagementCapped) return;
570      scheduleEngagementEmit();
571    }, delay);
572  }, "scheduleEngagementEmit");
573  const clearUnfocusedTimer = /* @__PURE__ */ __name(() => {
574    const clearTimer = resolveClearTimer();
575    if (engagementUnfocusedTimer !== null) {
576      if (clearTimer) clearTimer(engagementUnfocusedTimer);
577      engagementUnfocusedSpentMs += Math.max(0, perf.now() - engagementUnfocusedArmedAt);
578    }
579    engagementUnfocusedTimer = null;
580  }, "clearUnfocusedTimer");
581  const resetUnfocusedGrace = /* @__PURE__ */ __name(() => {
582    clearUnfocusedTimer();
583    engagementUnfocusedSpentMs = 0;
584  }, "resetUnfocusedGrace");
585  const scheduleUnfocusedStop = /* @__PURE__ */ __name(() => {
586    if (engagementUnfocusedTimer !== null) return;
587    if (!d || d.visibilityState === "hidden" || d.hasFocus?.() !== false) return;
588    const setTimer = resolveSetTimer();
589    if (!setTimer) return;
590    engagementUnfocusedArmedAt = perf.now();
591    engagementUnfocusedTimer = setTimer(
592      () => {
593        engagementUnfocusedTimer = null;
594        engagementUnfocusedSpentMs = ENGAGEMENT_UNFOCUSED_GRACE_MS;
595        engagementStoppedUnfocused = true;
596        emitEngagement("unfocused");
597        stopEngagementSegment();
598        clearEngagementTimer();
599      },
600      Math.max(0, ENGAGEMENT_UNFOCUSED_GRACE_MS - engagementUnfocusedSpentMs)
601    );
602  }, "scheduleUnfocusedStop");
603  const resumeEngagementMeasurement = /* @__PURE__ */ __name(() => {
604    if (d && d.visibilityState === "hidden") return;
605    if (engagementStoppedUnfocused) return;
606    if (engagementCapped) return;
607    startEngagementSegment();
608    engagementEmitStep = 0;
609    scheduleEngagementEmit();
610    scheduleUnfocusedStop();
611  }, "resumeEngagementMeasurement");
612  const rotatePageViewId = /* @__PURE__ */ __name(() => {
613    emitEngagement("navigation");
614    engagementReportedMs = 0;
615    engagementCapped = false;
616    resumeEngagementMeasurement();
617    pageViewId = randomId();
618    traceContext = createTraceContext();
619    capturedClicks = 0;
620    return pageViewId;
621  }, "rotatePageViewId");
622  const traceFieldsFor = /* @__PURE__ */ __name((eventName) => {
623    if (eventName === "lovable.page_viewed") {
624      return {
625        trace_id: traceContext.traceId,
626        span_id: traceContext.rootSpanId
627      };
628    }
629    return {
630      trace_id: traceContext.traceId,
631      span_id: randomTraceHex(8),
632      parent_span_id: traceContext.rootSpanId
633    };
634  }, "traceFieldsFor");
635  const isErrorEventName = /* @__PURE__ */ __name((eventName) => eventName === "lovable.client_error" || eventName === "lovable.resource_error" || eventName === "lovable.replay_error", "isErrorEventName");
636  const queueEvent = /* @__PURE__ */ __name((eventName, eventSchemaVersion, properties = {}) => {
637    if (sendingDisabled) return null;
638    if (isErrorEventName(eventName) && ++errorEventsSeen > maxErrorEventsPerPageLoad) {
639      if (eventName === "lovable.client_error") markReplayCapturedByClientError(null);
640      return null;
641    }
642    const flushNow = eventName === "lovable.client_error" && immediateErrorFlushes < maxImmediateErrorFlushes;
643    if (flushNow) immediateErrorFlushes++;
644    const eventId = randomId();
645    const activeReplayId = replayId && !replayFinalized && (replayUploadEnabled || eventName === "lovable.client_error") ? replayId : null;
646    const event = {
647      event_id: eventId,
648      event_name: eventName,
649      event_schema_version: eventSchemaVersion,
650      event_time: (/* @__PURE__ */ new Date()).toISOString(),
651      session_id: sessionId,
652      page_view_id: pageViewId,
653      ...traceFieldsFor(eventName),
654      properties
655    };
656    if (activeReplayId) event.replay_id = activeReplayId;
657    if (flushNow) {
658      queue.unshift(event);
659    } else {
660      queue.push(event);
661    }
662    if (eventName === "lovable.client_error") markReplayCapturedByClientError(eventId);
663    if (flushNow || queue.length >= batchSize) {
664      flush();
665    } else {
666      scheduleFlush();
667    }
668    return eventId;
669  }, "queueEvent");
670  const enqueue = /* @__PURE__ */ __name((eventName, properties = {}) => {
671    const eventSchemaVersion = typeof eventName === "string" ? schemaVersionFor(eventName) : null;
672    if (eventSchemaVersion === null) return null;
673    return queueEvent(eventName, eventSchemaVersion, properties);
674  }, "enqueue");
675  let lastPageViewPath = loc.pathname;
676  const track = /* @__PURE__ */ __name((eventName, properties = {}) => {
677    if (eventName === "lovable.page_viewed") {
678      rotatePageViewId();
679      if (typeof properties.url_path === "string") lastPageViewPath = properties.url_path;
680    }
681    return enqueue(eventName, properties);
682  }, "track");
683  const pathFromUrl = /* @__PURE__ */ __name((value) => {
684    try {
685      return new URL(value, loc.href).pathname;
686    } catch {
687      return null;
688    }
689  }, "pathFromUrl");
690  const hostFromUrl = /* @__PURE__ */ __name((value) => {
691    try {
692      return new URL(value, loc.href).host.replace(/^www\./iu, "");
693    } catch {
694      return null;
695    }
696  }, "hostFromUrl");
697  const campaignKeys = [
698    ["utm_source", "campaign_source"],
699    ["utm_medium", "campaign_medium"],
700    ["utm_campaign", "campaign_name"],
701    ["utm_term", "campaign_term"],
702    ["utm_content", "campaign_content"]
703  ];
704  const clickIDKeys = ["gclid", "dclid", "gbraid", "wbraid", "msclkid", "ttclid", "twclid", "li_fat_id", "fbclid"];
705  const maxCampaignBytes = 128;
706  const campaignPropertiesFrom = /* @__PURE__ */ __name((search) => {
707    const properties = {};
708    try {
709      if (typeof search !== "string" || !search) return properties;
710      const params = new URLSearchParams(search.replace(/;/gu, "&"));
711      for (const [key, property] of campaignKeys) {
712        const raw2 = params.get(key);
713        if (typeof raw2 !== "string") continue;
714        const value = raw2.trim();
715        if (value && byteLength(value) <= maxCampaignBytes) properties[property] = value;
716      }
717      const present = clickIDKeys.filter((key) => {
718        const raw2 = params.get(key);
719        return typeof raw2 === "string" && raw2.trim() !== "";
720      });
721      if (present.length > 0) properties.campaign_click_id_types = present;
722    } catch {
723      return {};
724    }
725    return properties;
726  }, "campaignPropertiesFrom");
727  const truncateToJSONBytes = /* @__PURE__ */ __name((input, maxBytes) => {
728    let result = input;
729    while (result && byteLength(JSON.stringify(result)) > maxBytes) {
730      result = result.slice(0, Math.floor(result.length * 0.8));
731    }
732    return result;
733  }, "truncateToJSONBytes");
734  const truncateToChars = /* @__PURE__ */ __name((value, maxChars) => {
735    if (typeof value !== "string") return null;
736    const collapsed = value.replace(/\s+/gu, " ").trim();
737    if (!collapsed) return null;
738    if (collapsed.length <= maxChars) return collapsed;
739    const points = Array.from(collapsed);
740    return points.length > maxChars ? points.slice(0, maxChars).join("") : collapsed;
741  }, "truncateToChars");
742  const urlPathMaxLength = 2048;
743  const currentUrlPath = /* @__PURE__ */ __name(() => truncateToChars(loc.pathname || "/", urlPathMaxLength) || "/", "currentUrlPath");
744  const serializeThrowable = /* @__PURE__ */ __name((value) => {
745    const throwable = value && typeof value === "object" ? value : null;
746    const stringifyPrimitive = /* @__PURE__ */ __name((input) => {
747      if (typeof input === "string") return input;
748      if (typeof input === "number" || typeof input === "boolean" || typeof input === "bigint") return String(input);
749      return null;
750    }, "stringifyPrimitive");
751    const stack = stringifyPrimitive(throwable?.stack);
752    const message3 = stringifyPrimitive(throwable?.message) ?? stringifyPrimitive(value) ?? "Unknown error";
753    return {
754      message: truncateToJSONBytes(message3.slice(0, 2e3), 2048),
755      name: stringifyPrimitive(throwable?.name),
756      stack: stack ? truncateToJSONBytes(stack.slice(0, 8e3), 8192) : null
757    };
758  }, "serializeThrowable");
759  const quickReturnMs = 1e3;
760  const loopWindowMs = 1e4;
761  const loopQuickReturns = 10;
762  const lastAtPath = /* @__PURE__ */ new Map();
763  const quickReturnTimes = [];
764  const markAtPath = /* @__PURE__ */ __name((path, now) => {
765    for (const [seenPath, at] of lastAtPath) if (now - at >= quickReturnMs) lastAtPath.delete(seenPath);
766    lastAtPath.set(path, now);
767  }, "markAtPath");
768  const emitPageView = /* @__PURE__ */ __name((navigationType, rotatePageView = true) => {
769    if (rotatePageView) rotatePageViewId();
770    const pagePath = loc.pathname;
771    const properties = {
772      url_path: pagePath,
773      navigation_type: navigationType
774    };
775    if (typeof d?.referrer === "string" && d.referrer) {
776      properties.referrer_host = hostFromUrl(d.referrer) ?? "";
777      properties.referrer_path = pathFromUrl(d.referrer) ?? "";
778    }
779    Object.assign(properties, campaignPropertiesFrom(loc.search));
780    lastPageViewPath = pagePath;
781    markAtPath(pagePath, perf.now());
782    enqueue("lovable.page_viewed", properties);
783  }, "emitPageView");
784  const emitPageViewIfPathChanged = /* @__PURE__ */ __name((navigationType) => {
785    if (loc.pathname === lastPageViewPath) return;
786    emitPageView(navigationType);
787  }, "emitPageViewIfPathChanged");
788  const emitReplaceStatePageView = /* @__PURE__ */ __name(() => {
789    const path = loc.pathname;
790    if (path === lastPageViewPath) return;
791    const now = perf.now();
792    const at = lastAtPath.get(path);
793    if (at !== void 0 && now - at < quickReturnMs) {
794      quickReturnTimes.push(now);
795      if (quickReturnTimes.length > loopQuickReturns + 1) quickReturnTimes.shift();
796      if (quickReturnTimes.length > loopQuickReturns && now - quickReturnTimes[0] < loopWindowMs) {
797        lastPageViewPath = path;
798        markAtPath(path, now);
799        return;
800      }
801    }
802    emitPageView("replace_state");
803  }, "emitReplaceStatePageView");
804  const startReplayRecording = /* @__PURE__ */ __name(() => {
805    const record = replayMode === "rrweb" && isReplayRecordingAllowed && w.rrweb && typeof w.rrweb.record === "function" ? w.rrweb.record : null;
806    if (!record || replayId) return;
807    replayId = randomId();
808    replayStartedAt = perf.now();
809    replayFinalized = false;
810    replayChunkSequence = 0;
811    replayThrottledChunks = 0;
812    replayChunksInFlight = 0;
813    replayBudgetStopReason = null;
814    replayUploadedBytes = 0;
815    replayRecorderActive = false;
816    replayHasFullSnapshot = false;
817    replayUploadEnabled = isReplaySampledIn;
818    replayCaptureReason = isReplaySampledIn ? "sampled" : null;
819    replayTriggerEventId = null;
820    replayTriggerEventName = null;
821    replayCaptureMetadataEmitted = false;
822    try {
823      const stop = record({
824        emit(event) {
825          if (replayFinalized) return;
826          if (!event || typeof event !== "object") return;
827          if (replayDurationMs() >= maxReplayDurationMs) {
828            stopReplayAtDurationLimit();
829            return;
830          }
831          const eventType = replayEventType(event);
832          if (!canSendReplayEvent(event)) {
833            if (eventType === 2 && !replayHasFullSnapshot) {
834              stopReplayRecording("full_snapshot_too_large", true);
835            }
836            return;
837          }
838          if (eventType === 3 && !replayHasFullSnapshot) return;
839          if (eventType === 2) replayHasFullSnapshot = true;
840          replayEventCount += 1;
841          replayQueue.push(event);
842          while (!replayUploadEnabled && replayQueue.length > maxReplayBufferedEvents) {
843            const removableIndex = replayQueue.findIndex((queuedEvent) => replayEventType(queuedEvent) !== 2);
844            replayQueue.splice(removableIndex >= 0 ? removableIndex : 0, 1);
845            replayEventCount = Math.max(0, replayEventCount - 1);
846          }
847          if (emitReplayCaptureMetadataIfReady()) return;
848          if (!replayUploadEnabled) return;
849          if (replayQueue.length >= maxReplayEventsPerChunk) {
850            flushReplay();
851          } else {
852            scheduleReplayFlush();
853          }
854        },
855        blockClass: "rr-block",
856        blockSelector: replayBlockSelector,
857        collectFonts: false,
858        ignoreClass: "rrweb-ignore",
859        ignoreSelector: replayIgnoreSelector,
860        inlineImages: false,
861        maskAllInputs: true,
862        maskInputFn: maskReplayText,
863        maskInputOptions: {
864          checkbox: false,
865          color: false,
866          date: true,
867          "datetime-local": true,
868          email: true,
869          month: true,
870          number: true,
871          password: true,
872          radio: false,
873          range: false,
874          search: true,
875          select: true,
876          tel: true,
877          text: true,
878          textarea: true,
879          time: true,
880          url: true,
881          week: true
882        },
883        maskTextClass: "rr-mask",
884        maskTextFn: maskReplayText,
885        maskTextSelector: replayMaskTextSelector,
886        recordAfter: "load",
887        recordCanvas: false,
888        recordCrossOriginIframes: false
889      });
890      if (replayFinalized) {
891        if (typeof stop === "function") {
892          try {
893            stop();
894          } catch {
895          }
896        }
897        return;
898      }
899      replayRecorderActive = true;
900      if (typeof stop === "function") stopReplayRecorder = stop;
901      const setTimer = resolveSetTimer();
902      if (setTimer && typeof record.takeFullSnapshot === "function") {
903        setTimer(() => {
904          if (!replayId || replayFinalized) return;
905          try {
906            record.takeFullSnapshot?.(false);
907          } catch {
908          }
909        }, 1e3);
910      }
911      if (setTimer) {
912        replayDurationTimer = setTimer(stopReplayAtDurationLimit, maxReplayDurationMs);
913      }
914      if (shouldEmitReplayLifecycleMetadata()) {
915        emitReplayMetadata("started", "recorder_available");
916      }
917    } catch {
918      if (replayId) {
919        emitReplayMetadataOrErrorFor(
920          replayId,
921          "stopped",
922          "recorder_start_failed",
923          replayEventCount,
924          replayDurationMs(),
925          replayChunkSequence,
926          replayUploadedBytes
927        );
928      }
929      replayId = null;
930      replayEventCount = 0;
931      replayStartedAt = 0;
932      replayFinalized = false;
933      replayHasFullSnapshot = false;
934      replayUploadEnabled = isReplaySampledIn;
935      replayCaptureReason = isReplaySampledIn ? "sampled" : null;
936      replayTriggerEventId = null;
937      replayTriggerEventName = null;
938      stopReplayRecorder = null;
939      replayRecorderActive = false;
940      clearReplayDurationTimer();
941    }
942  }, "startReplayRecording");
943  const ensureReplayRecorder = /* @__PURE__ */ __name(() => {
944    if (replayMode !== "rrweb" || !isReplayRecordingAllowed || replayId || replayRecorderLoading) return;
945    if (w.rrweb && typeof w.rrweb.record === "function") {
946      startReplayRecording();
947      return;
948    }
949    const head = d?.head;
950    if (!d?.createElement || !head?.appendChild) return;
951    const recorderScript = d.createElement("script");
952    replayRecorderLoading = true;
953    recorderScript.async = true;
954    recorderScript.src = replayScriptUrl;
955    recorderScript.onload = () => {
956      replayRecorderLoading = false;
957      if (!w.rrweb || typeof w.rrweb.record !== "function") {
958        emitReplayMetadataOrErrorFor(randomId(), "stopped", "recorder_script_failed", 0, 0, 0, 0);
959        return;
960      }
961      startReplayRecording();
962    };
963    recorderScript.onerror = () => {
964      replayRecorderLoading = false;
965      emitReplayMetadataOrErrorFor(randomId(), "stopped", "recorder_script_failed", 0, 0, 0, 0);
966    };
967    head.appendChild(recorderScript);
968  }, "ensureReplayRecorder");
969  const finalizeReplayRecording = /* @__PURE__ */ __name((reason) => {
970    if (!replayId || replayFinalized) return;
971    stopReplayRecorderSafely();
972    clearReplayDurationTimer();
973    if (!replayHasFullSnapshot) {
974      stopReplayRecording("missing_full_snapshot", true);
975      return;
976    }
977    flushReplay(true);
978    if (!replayFinalized) stopReplayRecording(reason);
979  }, "finalizeReplayRecording");
980  const stopReplayRecordingOnRuntimeError = /* @__PURE__ */ __name((event) => {
981    if (!replayId || replayFinalized) return;
982    const errorEvent = event && typeof event === "object" ? event : null;
983    const errorRecord = errorEvent?.error && typeof errorEvent.error === "object" ? errorEvent.error : null;
984    const filename = typeof errorEvent?.filename === "string" ? errorEvent.filename : "";
985    const stack = typeof errorRecord?.stack === "string" ? errorRecord.stack : "";
986    const isRecorderError = filename.includes("/__l5e/rrweb-record") || stack.includes("/__l5e/rrweb-record");
987    if (isRecorderError) {
988      stopReplayRecording("recorder_runtime_error", true);
989    }
990  }, "stopReplayRecordingOnRuntimeError");
991  const webVitalRating = /* @__PURE__ */ __name((metric, value) => {
992    const thresholds = {
993      CLS: [0.1, 0.25],
994      FCP: [1800, 3e3],
995      INP: [200, 500],
996      LCP: [2500, 4e3],
997      TTFB: [800, 1800]
998    };
999    const threshold = thresholds[metric];
1000    if (!threshold) return "good";
1001    if (value <= threshold[0]) return "good";
1002    return value <= threshold[1] ? "needs-improvement" : "poor";
1003  }, "webVitalRating");
1004  const webVitalUnit = /* @__PURE__ */ __name((metric) => metric === "CLS" ? "score" : "millisecond", "webVitalUnit");
1005  const performanceEntryValue = /* @__PURE__ */ __name((entry, key) => {
1006    const value = entry[key];
1007    return typeof value === "number" && Number.isFinite(value) ? value : null;
1008  }, "performanceEntryValue");
1009  const observePerformanceEntries = /* @__PURE__ */ __name((entryType, callback) => {
1010    const ObserverCtor = w.PerformanceObserver;
1011    if (!ObserverCtor) return false;
1012    const supportedEntryTypes = ObserverCtor.supportedEntryTypes;
1013    if (Array.isArray(supportedEntryTypes) && !supportedEntryTypes.includes(entryType)) return false;
1014    try {
1015      const observer = new ObserverCtor((list) => {
1016        const entries = typeof list.getEntries === "function" ? list.getEntries() : [];
1017        for (const entry of entries) {
1018          if (entry && typeof entry === "object") callback(entry);
1019        }
1020      });
1021      observer.observe(
1022        entryType === "event" ? { type: entryType, buffered: true, durationThreshold: 40 } : { type: entryType, buffered: true }
1023      );
1024      return true;
1025    } catch {
1026      return false;
1027    }
1028  }, "observePerformanceEntries");
1029  const observeWebVitals = /* @__PURE__ */ __name(() => {
1030    const urlPath = currentUrlPath();
1031    const emitWebVital = /* @__PURE__ */ __name((metric, value, delta = value, id2 = randomId()) => {
1032      if (!Number.isFinite(value) || value < 0) return;
1033      enqueue("lovable.web_vital", {
1034        url_path: urlPath,
1035        metric,
1036        value,
1037        unit: webVitalUnit(metric),
1038        delta,
1039        rating: webVitalRating(metric, value),
1040        id: id2,
1041        navigation_type: "initial_load"
1042      });
1043    }, "emitWebVital");
1044    let fcpReported = false;
1045    let latestLcp = null;
1046    let clsValue = 0;
1047    let maxInp = 0;
1048    let finalized = false;
1049    const metricIds = {};
1050    const reportedValues = {};
1051    const metricId = /* @__PURE__ */ __name((metric) => {
1052      metricIds[metric] = metricIds[metric] || randomId();
1053      return metricIds[metric];
1054    }, "metricId");
1055    const reportMetric = /* @__PURE__ */ __name((metric, value) => {
1056      if (reportedValues[metric] === value) return;
1057      const previousValue = reportedValues[metric];
1058      reportedValues[metric] = value;
1059      emitWebVital(metric, value, previousValue === void 0 ? value : value - previousValue, metricId(metric));
1060    }, "reportMetric");
1061    const navigationEntries = typeof perf.getEntriesByType === "function" ? perf.getEntriesByType("navigation") : [];
1062    const navigationEntry = navigationEntries[0] && typeof navigationEntries[0] === "object" ? navigationEntries[0] : null;
1063    const responseStart = navigationEntry ? performanceEntryValue(navigationEntry, "responseStart") : null;
1064    const requestStart = navigationEntry ? performanceEntryValue(navigationEntry, "requestStart") : null;
1065    const fetchStart = navigationEntry ? performanceEntryValue(navigationEntry, "fetchStart") : null;
1066    const ttfbStart = requestStart ?? fetchStart;
1067    if (responseStart !== null && ttfbStart !== null && responseStart >= ttfbStart) {
1068      emitWebVital("TTFB", responseStart - ttfbStart);
1069    }
1070    observePerformanceEntries("paint", (entry) => {
1071      if (fcpReported || entry.name !== "first-contentful-paint") return;
1072      const startTime = performanceEntryValue(entry, "startTime");
1073      if (startTime === null) return;
1074      fcpReported = true;
1075      emitWebVital("FCP", startTime);
1076    });
1077    observePerformanceEntries("largest-contentful-paint", (entry) => {
1078      latestLcp = performanceEntryValue(entry, "startTime") ?? performanceEntryValue(entry, "renderTime") ?? performanceEntryValue(entry, "loadTime") ?? latestLcp;
1079    });
1080    const clsObserverStarted = observePerformanceEntries("layout-shift", (entry) => {
1081      if (entry.hadRecentInput === true) return;
1082      const value = performanceEntryValue(entry, "value");
1083      if (value !== null) clsValue += value;
1084    });
1085    observePerformanceEntries("event", (entry) => {
1086      const interactionId = performanceEntryValue(entry, "interactionId");
1087      if (interactionId === null || interactionId <= 0) return;
1088      const duration = performanceEntryValue(entry, "duration");
1089      if (duration !== null && duration > maxInp) maxInp = duration;
1090    });
1091    return (final = false) => {
1092      if (finalized) return;
1093      if (latestLcp !== null) reportMetric("LCP", latestLcp);
1094      if (clsObserverStarted) reportMetric("CLS", clsValue);
1095      if (maxInp > 0) reportMetric("INP", maxInp);
1096      if (final) finalized = true;
1097    };
1098  }, "observeWebVitals");
1099  const patchHistory = /* @__PURE__ */ __name((method, emitAfterCall) => {
1100    const historyObject = w.history;
1101    const original = historyObject && historyObject[method];
1102    if (!historyObject || typeof original !== "function") return;
1103    historyObject[method] = function(...args) {
1104      const result = original.apply(this, args);
1105      emitAfterCall();
1106      return result;
1107    };
1108  }, "patchHistory");
1109  const normalizeCaptureExceptionOptions = /* @__PURE__ */ __name((options) => {
1110    const record = options && typeof options === "object" && !Array.isArray(options) ? options : {};
1111    const mechanism = typeof record.mechanism === "string" ? record.mechanism : "manual";
1112    const severity = typeof record.severity === "string" ? record.severity : "error";
1113    return {
1114      mechanism: ["manual", "onerror", "unhandledrejection", "react_error_boundary"].includes(mechanism) ? mechanism : "manual",
1115      handled: typeof record.handled === "boolean" ? record.handled : true,
1116      severity: ["error", "warning", "info"].includes(severity) ? severity : "error"
1117    };
1118  }, "normalizeCaptureExceptionOptions");
1119  w.__lovableEvents = Object.assign(existing, {
1120    __userAppEventsSdkVersion: version,
1121    track,
1122    flush: /* @__PURE__ */ __name(() => flush(), "flush"),
1123    identify(identity) {
1124      const identityRecord = identity && typeof identity === "object" ? identity : null;
1125      appUserId = typeof identityRecord?.user_id === "string" ? identityRecord.user_id : null;
1126    },
1127    getIdentity() {
1128      return { app_user_id_hash_available: !!appUserId };
1129    },
1130    getReplay() {
1131      return {
1132        replay_id: replayId,
1133        active: !!replayId && !replayFinalized && replayRecorderActive,
1134        event_count: replayEventCount
1135      };
1136    },
1137    resetIdentity() {
1138      appUserId = null;
1139    },
1140    captureException(error, context = {}, options = {}) {
1141      const throwable = serializeThrowable(error);
1142      const captureOptions = normalizeCaptureExceptionOptions(options);
1143      let captureContext = context && typeof context === "object" && !Array.isArray(context) ? context : {};
1144      try {
1145        if (byteLength(JSON.stringify(captureContext)) > 4096) captureContext = {};
1146      } catch {
1147        captureContext = {};
1148      }
1149      enqueue("lovable.client_error", {
1150        occurrence_id: randomId(),
1151        ...throwable,
1152        ...captureOptions,
1153        context: captureContext
1154      });
1155    },
1156    startSpan(name, attributes = {}) {
1157      const startTime = (/* @__PURE__ */ new Date()).toISOString();
1158      const start = perf.now();
1159      return {
1160        end(status = "ok") {
1161          enqueue("lovable.frontend_span", {
1162            name,
1163            start_time: startTime,
1164            status,
1165            duration_ms: Math.max(0, perf.now() - start),
1166            attributes
1167          });
1168        }
1169      };
1170    }
1171  });
1172  if (w.addEventListener) {
1173    w.addEventListener("error", stopReplayRecordingOnRuntimeError, true);
1174  }
1175  ensureReplayRecorder();
1176  const finalizeWebVitals = observeWebVitals();
1177  if (w.addEventListener) {
1178    w.addEventListener(
1179      "error",
1180      (event) => {
1181        const errorEvent = event && typeof event === "object" ? event : null;
1182        const target = errorEvent?.target && typeof errorEvent.target === "object" ? errorEvent.target : null;
1183        let resourceUrl = null;
1184        if (target && target !== w) {
1185          if (typeof target.src === "string") {
1186            resourceUrl = target.src;
1187          } else if (typeof target.href === "string") {
1188            resourceUrl = target.href;
1189          }
1190        }
1191        if (resourceUrl !== null) {
1192          const resourceType = typeof target?.tagName === "string" ? target.tagName.toLowerCase() : "unknown";
1193          enqueue("lovable.resource_error", {
1194            resource_type: resourceType,
1195            url_host: hostFromUrl(resourceUrl) ?? "",
1196            failure_type: "load_error",
1197            element: resourceType,
1198            url_path: pathFromUrl(resourceUrl),
1199            mechanism: "resource_load",
1200            handled: false,
1201            severity: "error"
1202          });
1203          return;
1204        }
1205        const throwable = serializeThrowable(errorEvent?.error || errorEvent?.message);
1206        enqueue("lovable.client_error", {
1207          occurrence_id: randomId(),
1208          ...throwable,
1209          filename: typeof errorEvent?.filename === "string" ? pathFromUrl(errorEvent.filename) : null,
1210          lineno: typeof errorEvent?.lineno === "number" ? errorEvent.lineno : null,
1211          colno: typeof errorEvent?.colno === "number" ? errorEvent.colno : null,
1212          mechanism: "onerror",
1213          handled: false,
1214          severity: "error"
1215        });
1216      },
1217      true
1218    );
1219    w.addEventListener("unhandledrejection", (event) => {
1220      const rejectionEvent = event && typeof event === "object" ? event : null;
1221      const throwable = serializeThrowable(rejectionEvent?.reason);
1222      enqueue("lovable.client_error", {
1223        occurrence_id: randomId(),
1224        ...throwable,
1225        mechanism: "unhandledrejection",
1226        handled: false,
1227        severity: "error"
1228      });
1229    });
1230    w.addEventListener("pagehide", () => {
1231      unloadingPage = true;
1232      finalizeWebVitals(true);
1233      finalizeReplayRecording("pagehide");
1234      emitEngagement("pagehide");
1235      stopEngagementSegment();
1236      clearEngagementTimer();
1237      clearUnfocusedTimer();
1238      flush(true);
1239    });
1240    w.addEventListener("blur", () => scheduleUnfocusedStop());
1241    w.addEventListener("focus", () => {
1242      resetUnfocusedGrace();
1243      if (!engagementStoppedUnfocused) return;
1244      engagementStoppedUnfocused = false;
1245      resumeEngagementMeasurement();
1246    });
1247    w.addEventListener("pageshow", (event) => {
1248      const persisted = event && typeof event === "object" ? event.persisted : false;
1249      if (persisted === true) {
1250        unloadingPage = false;
1251        releaseBeaconBytes();
1252        resetUnfocusedGrace();
1253        engagementStoppedUnfocused = false;
1254        resumeEngagementMeasurement();
1255      }
1256    });
1257    w.addEventListener("popstate", () => emitPageViewIfPathChanged("popstate"));
1258    w.addEventListener("hashchange", () => emitPageViewIfPathChanged("hashchange"));
1259    if (autocaptureEnabled) {
1260      const labelMaxLength = 64;
1261      const tagMaxLength = 64;
1262      const ownTextMaxLength = 200;
1263      const chainMaxDepth = 32;
1264      const clickCapPerPageView = 200;
1265      const optOutMaxDepth = 512;
1266      const pathMaxDepth = 32;
1267      const pathMaxLength = 1024;
1268      const valueBearingTags = {
1269        select: true,
1270        textarea: true,
1271        input: true
1272      };
1273      const interactiveTags = {
1274        button: true,
1275        a: true,
1276        input: true,
1277        select: true,
1278        textarea: true,
1279        summary: true
1280      };
1281      const interactiveRoles = {
1282        button: true,
1283        link: true,
1284        menuitem: true,
1285        menuitemcheckbox: true,
1286        menuitemradio: true,
1287        tab: true,
1288        switch: true,
1289        checkbox: true,
1290        radio: true,
1291        option: true
1292      };
1293      const landmarkTags = {
1294        header: true,
1295        footer: true,
1296        main: true,
1297        nav: true,
1298        aside: true,
1299        section: true,
1300        article: true,
1301        form: true
1302      };
1303      const jsxSourceKey = typeof Symbol !== "undefined" && typeof Symbol.for === "function" ? /* @__P
1303URE__ */ Symbol.for("__jsxSource__") : null;
1304      const asNode = /* @__PURE__ */ __name((value) => value && typeof value === "object" && typeof value.tagName === "string" ? value : null, "asNode");
1305      const knownTags = {};
1306      for (const tag of "html body div span main header footer nav aside section article form p a button input select textarea label fieldset legend optgroup option datalist output progress meter ul ol li dl dt dd table thead tbody tfoot tr td th caption col colgroup h1 h2 h3 h4 h5 h6 br hr pre blockquote figure figcaption small strong em b i u s q cite abbr code kbd samp var mark sub sup time address details summary dialog menu picture source track canvas iframe object embed param map area img video audio template slot noscript script style link meta title base head ins del ruby rt rp bdi bdo wbr data hgroup search fencedframe svg path g circle rect line polyline polygon ellipse text textpath tspan defs use symbol clippath mask pattern lineargradient radialgradient stop filter foreignobject marker image view desc animate animatetransform animatemotion set fegaussianblur feoffset feblend fecolormatrix fecomposite feflood femerge femergenode femorphology fetile feturbulence fedropshadow fedisplacementmap".split(" ")) {
1307        knownTags[tag] = true;
1308      }
1309      const knownRoles = {};
1310      for (const role of "button link menuitem menuitemcheckbox menuitemradio tab switch checkbox radio option combobox listbox textbox searchbox slider spinbutton treeitem gridcell row columnheader rowheader tooltip dialog alertdialog navigation main banner contentinfo complementary region form search article list listitem table grid tree menu menubar toolbar tabpanel tablist progressbar status alert log timer none presentation".split(" ")) {
1311        knownRoles[role] = true;
1312      }
1313      const knownInputTypes = {};
1314      for (const type of "button submit reset checkbox radio text password email number tel url search date time datetime-local month week color file range hidden image".split(" ")) {
1315        knownInputTypes[type] = true;
1316      }
1317      const knownAttrValue = /* @__PURE__ */ __name((value, vocabulary) => value !== null && vocabulary[value.toLowerCase()] === true ? value.toLowerCase() : null, "knownAttrValue");
1318      const tagOf = /* @__PURE__ */ __name((node) => {
1319        const tag = String(node.tagName).toLowerCase();
1320        return knownTags[tag] === true ? tag : "x";
1321      }, "tagOf");
1322      const attrOf = /* @__PURE__ */ __name((node, name) => {
1323        if (typeof node.getAttribute !== "function") return null;
1324        const value = node.getAttribute(name);
1325        return typeof value === "string" && value !== "" ? value : null;
1326      }, "attrOf");
1327      const hasAttr = /* @__PURE__ */ __name((node, name) => typeof node.getAttribute === "function" && typeof node.getAttribute(name) === "string", "hasAttr");
1328      const ownTextOf = /* @__PURE__ */ __name((node) => {
1329        if (valueBearingTags[tagOf(node)] === true) return null;
1330        const children = node.childNodes;
1331        if (!children || typeof children.length !== "number") return null;
1332        const list = children;
1333        let text = "";
1334        for (let index = 0; index < list.length; index++) {
1335          const child = list[index];
1336          if (child && child.nodeType === 3 && typeof child.nodeValue === "string") text += child.nodeValue;
1337          if (text.length > ownTextMaxLength) return null;
1338        }
1339        return text === "" ? null : text;
1340      }, "ownTextOf");
1341      const labelOf = /* @__PURE__ */ __name((node) => truncateToChars(
1342        attrOf(node, "aria-label") || attrOf(node, "title") || attrOf(node, "alt") || ownTextOf(node),
1343        labelMaxLength
1344      ), "labelOf");
1345      const nthOfType = /* @__PURE__ */ __name((parent, node, tag) => {
1346        const children = parent.children;
1347        if (!children || typeof children.length !== "number") return "";
1348        const list = children;
1349        let position = 0;
1350        let total = 0;
1351        for (let index = 0; index < list.length; index++) {
1352          const sibling = asNode(list[index]);
1353          if (!sibling || tagOf(sibling) !== tag) continue;
1354          total++;
1355          if (sibling === node) position = total;
1356        }
1357        return position > 0 ? ":" + position : "";
1358      }, "nthOfType");
1359      const pathOf = /* @__PURE__ */ __name((node) => {
1360        const segments = [];
1361        let current = node;
1362        for (let depth = 0; current && depth < pathMaxDepth; depth++) {
1363          const tag = tagOf(current);
1364          if (!tag || tag === "html") break;
1365          const parent = asNode(current.parentElement);
1366          segments.unshift(parent && tag !== "body" ? tag + nthOfType(parent, current, tag) : tag);
1367          if (tag === "body" || !parent) break;
1368          current = parent;
1369        }
1370        if (segments.length === 0) return null;
1371        let path = segments.join(">");
1372        while (path.length > pathMaxLength && segments.length > 1) {
1373          segments.shift();
1374          path = segments.join(">");
1375        }
1376        return path.length > pathMaxLength ? path.slice(path.length - pathMaxLength) : path;
1377      }, "pathOf");
1378      const componentNameOf = /* @__PURE__ */ __name((node) => {
1379        if (jsxSourceKey === null) return null;
1380        const source = node[jsxSourceKey];
1381        if (!source || typeof source !== "object") return null;
1382        const name = source.displayName;
1383        return typeof name === "string" && name !== "" ? name : null;
1384      }, "componentNameOf");
1385      const isInteractive = /* @__PURE__ */ __name((node) => {
1386        if (interactiveTags[tagOf(node)] === true) return true;
1387        const role = attrOf(node, "role");
1388        return role !== null && interactiveRoles[role.toLowerCase()] === true;
1389      }, "isInteractive");
1390      const chainFrom = /* @__PURE__ */ __name((event, maxDepth) => {
1391        const composed = typeof event.composedPath === "function" ? event.composedPath() : null;
1392        if (Array.isArray(composed)) {
1393          const nodes2 = [];
1394          for (const entry of composed) {
1395            if (nodes2.length >= maxDepth) return { nodes: nodes2, complete: false };
1396            const node2 = asNode(entry);
1397            if (node2) nodes2.push(node2);
1398          }
1399          return { nodes: nodes2, complete: true };
1400        }
1401        const nodes = [];
1402        let node = asNode(event.target);
1403        while (node) {
1404          if (nodes.length >= maxDepth) return { nodes, complete: false };
1405          nodes.push(node);
1406          node = asNode(node.parentElement);
1407        }
1408        return { nodes, complete: true };
1409      }, "chainFrom");
1410      const isPointerType = /* @__PURE__ */ __name((value) => value === "mouse" || value === "touch" || value === "pen", "isPointerType");
1411      const pointerTypeMaxAgeMs = 2e3;
1412      const forwardedClickMaxAgeMs = 300;
1413      let lastPointerType = "";
1414      let lastPointerAt = 0;
1415      const recentPointerType = /* @__PURE__ */ __name((maxAgeMs) => lastPointerType !== "" && perf.now() - lastPointerAt <= maxAgeMs ? lastPointerType : "", "recentPointerType");
1416      w.addEventListener(
1417        "pointerdown",
1418        (event) => {
1419          try {
1420            const pointerEvent = event;
1421            if (pointerEvent.isTrusted !== true) return;
1422            const pointerType = typeof pointerEvent.pointerType === "string" ? pointerEvent.pointerType : "";
1423            if (isPointerType(pointerType)) {
1424              lastPointerType = pointerType;
1425              lastPointerAt = perf.now();
1426            }
1427          } catch {
1428          }
1429        },
1430        true
1431      );
1432      const roundUnit = /* @__PURE__ */ __name((value) => Math.round(value * 1e3) / 1e3, "roundUnit");
1433      const numberOr = /* @__PURE__ */ __name((value) => typeof value === "number" && isFinite(value) ? value : null, "numberOr");
1434      w.addEventListener(
1435        "click",
1436        (event) => {
1437          try {
1438            if (!event || typeof event !== "object") return;
1439            const clickEvent = event;
1440            if (clickEvent.isTrusted !== true) return;
1441            if (capturedClicks >= clickCapPerPageView) return;
1442            const chain = chainFrom(clickEvent, optOutMaxDepth);
1443            if (!chain.complete) return;
1444            let element = null;
1445            let section = null;
1446            for (let depth = 0; depth < chain.nodes.length; depth++) {
1447              const node = chain.nodes[depth];
1448              if (hasAttr(node, "data-lov-no-capture")) return;
1449              if (depth >= chainMaxDepth) continue;
1450              if (element === null) {
1451                if (isInteractive(node)) element = node;
1452                continue;
1453              }
1454              if (section === null && landmarkTags[tagOf(node)] === true) section = node;
1455            }
1456            if (element === null) return;
1457            const pointerType = typeof clickEvent.pointerType === "string" ? clickEvent.pointerType : "";
1458            const detail = numberOr(clickEvent.detail) ?? 0;
1459            const forwarded = detail === 0 ? recentPointerType(forwardedClickMaxAgeMs) : "";
1460            const interactionType = isPointerType(pointerType) ? pointerType : forwarded || (detail === 0 ? "keyboard" : recentPointerType(pointerTypeMaxAgeMs) || "unknown");
1461            let offsetX = null;
1462            let offsetY = null;
1463            const clientX = numberOr(clickEvent.clientX);
1464            const clientY = numberOr(clickEvent.clientY);
1465            const rect = typeof element.getBoundingClientRect === "function" ? element.getBoundingClientRect() : null;
1466            if (interactionType !== "keyboard" && rect && clientX !== null && clientY !== null && rect.width > 0 && rect.height > 0) {
1467              offsetX = roundUnit(Math.min(1, Math.max(0, (clientX - rect.left) / rect.width)));
1468              offsetY = roundUnit(Math.min(1, Math.max(0, (clientY - rect.top) / rect.height)));
1469            }
1470            const viewport = w;
1471            enqueue("lovable.element_clicked", {
1472              // pathname only, and named url_path so the collector's path sanitizer
1473              // selects it as a second line of defence.
1474              url_path: currentUrlPath(),
1475              element_tag: tagOf(element),
1476              interaction_type: interactionType,
1477              element_role: knownAttrValue(attrOf(element, "role"), knownRoles),
1478              element_type: knownAttrValue(attrOf(element, "type"), knownInputTypes),
1479              element_label: labelOf(element),
1480              element_path: pathOf(element),
1481              component_name: truncateToChars(componentNameOf(element), tagMaxLength),
1482              section_tag: section ? truncateToChars(tagOf(section), tagMaxLength) : null,
1483              section_label: section ? truncateToChars(attrOf(section, "aria-label"), labelMaxLength) : null,
1484              offset_x: offsetX,
1485              offset_y: offsetY,
1486              viewport_width: numberOr(viewport.innerWidth),
1487              viewport_height: numberOr(viewport.innerHeight)
1488            });
1489            capturedClicks++;
1490          } catch {
1491          }
1492        },
1493        true
1494      );
1495    }
1496  }
1497  if (d && typeof d.addEventListener === "function") {
1498    d.addEventListener("visibilitychange", () => {
1499      if (d.visibilityState === "hidden") {
1500        unloadingPage = true;
1501        finalizeWebVitals();
1502        flushReplay(true);
1503        emitEngagement("hidden");
1504        stopEngagementSegment();
1505        clearEngagementTimer();
1506        clearUnfocusedTimer();
1507        flush(true);
1508        unloadingPage = false;
1509        return;
1510      }
1511      unloadingPage = false;
1512      releaseBeaconBytes();
1513      resumeEngagementMeasurement();
1514    });
1515  }
1516  patchHistory("pushState", () => emitPageViewIfPathChanged("push_state"));
1517  patchHistory("replaceState", emitReplaceStatePageView);
1518  enqueue("lovable.session_started", { reason: "new_session" });
1519  emitPageView("initial_load", false);
1520  resumeEngagementMeasurement();
1521})(window, "0.3.0-automated-flag", {"lovable.webmcp_tool_invoked":1,"lovable.session_started":1,"lovable.page_viewed":1,"lovable.client_error":1,"lovable.frontend_span":1,"lovable.interaction":1,"lovable.element_clicked":1,"lovable.form_submitted":1,"lovable.resource_error":1,"lovable.session_replay":1,"lovable.replay_error":1,"lovable.web_vital":1,"lovable.page_engagement":1}, 50, 51200, 524288, 100, 5242880, 50, 600000, 2000);})();

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.