(()=>{const __name=(target)=>target;((w, version2, schemaVersions, maxEventsPerBatch = 50, maxKeepaliveBatchBytes = 50 * 1024, maxReplayBodyBytes = 128 * 1024, maxReplayEventsPerChunk = 100, maxReplayTotalBytes = 5 * 1024 * 1024, maxReplayChunks = 50, maxReplayDurationMs = 10 * 60 * 1e3, replayFlushIntervalMs = 2e3) => {
const existing = w.__lovableEvents || {};
if (existing.__userAppEventsSdkVersion) return;
const d = w.document;
const nav = w.navigator || {};
const perf = w.performance || { now: /* @__PURE__ */ __name(() => Date.now(), "now") };
const loc = w.location || { pathname: "", href: "" };
const isInternalPath = /* @__PURE__ */ __name((path) => path === "/__codex_token_check" || path.startsWith("/__l5e/"), "isInternalPath");
if (isInternalPath(loc.pathname)) return;
const script = d && d.currentScript;
const artifact = script ? {
kind: script.getAttribute("data-artifact-kind") || null,
id: script.getAttribute("data-artifact-id") || null,
commit_sha: script.getAttribute("data-commit-sha") || null,
context_token: script.getAttribute("data-context-token") || null
} : {};
const replayMode = script?.getAttribute("data-replay") || null;
const trackUrl = script?.getAttribute("data-track-url") || "/__l5e/trackevents";
const replayUrl = script?.getAttribute("data-replay-url") || "/__l5e/replay";
const replayScriptUrl = script?.getAttribute("data-replay-script-url") || "/__l5e/rrweb-record.js";
const parseSampleRate = /* @__PURE__ */ __name((value) => {
const rate = typeof value === "string" ? Number(value) : 0;
if (!Number.isFinite(rate) || rate <= 0) return 0;
return rate >= 1 ? 1 : rate;
}, "parseSampleRate");
const replaySampleRate = parseSampleRate(script?.getAttribute("data-replay-sample-rate") || null);
const randomId = /* @__PURE__ */ __name(() => w.crypto && typeof w.crypto.randomUUID === "function" ? w.crypto.randomUUID() : String(Date.now()) + "-" + Math.random().toString(16).slice(2), "randomId");
const storageGetOrCreate = /* @__PURE__ */ __name((storage, key) => {
try {
if (!storage) return { value: randomId(), created: true };
let value = storage.getItem(key);
if (!value) {
value = randomId();
storage.setItem(key, value);
return { value, created: true };
}
return { value, created: false };
} catch {
return { value: randomId(), created: true };
}
}, "storageGetOrCreate");
const rollingSessionTimeoutMs = 30 * 60 * 1e3;
const rollingSessionStorageKey = "__lovable_session";
const readRollingSession = /* @__PURE__ */ __name((storage, key) => {
try {
const raw2 = storage?.getItem(key);
if (!raw2) return null;
const parsed = JSON.parse(raw2);
const record = parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
const value = record?.value;
const expiresAt = record?.expires_at;
if (typeof value !== "string" || !value || typeof expiresAt !== "number" || !Number.isFinite(expiresAt)) {
return null;
}
return { value, expiresAt };
} catch {
return null;
}
}, "readRollingSession");
const writeRollingSession = /* @__PURE__ */ __name((storage, key, value, expiresAt) => {
try {
storage?.setItem(key, JSON.stringify({ value, expires_at: expiresAt }));
} catch {
}
}, "writeRollingSession");
const loadRollingSession = /* @__PURE__ */ __name((storage, key) => {
const now = Date.now();
const expiresAt = now + rollingSessionTimeoutMs;
const existingSession = readRollingSession(storage, key);
if (existingSession && existingSession.expiresAt > now) {
writeRollingSession(storage, key, existingSession.value, expiresAt);
return { value: existingSession.value, expiresAt, created: false };
}
const value = randomId();
writeRollingSession(storage, key, value, expiresAt);
return { value, expiresAt, created: true };
}, "loadRollingSession");
const anonymousIdentity = storageGetOrCreate(w.localStorage, "__lovable_anonymous_id");
const sessionIdentity = loadRollingSession(w.localStorage, rollingSessionStorageKey);
const anonymousId = anonymousIdentity.value;
let sessionId = sessionIdentity.value;
let sessionExpiresAt = sessionIdentity.expiresAt;
let appUserId = null;
let pageViewId = randomId();
const unitIntervalFor = /* @__PURE__ */ __name((value) => {
let hash = 2166136261;
for (let index = 0; index < value.length; index++) {
hash ^= value.charCodeAt(index);
hash = Math.imul(hash, 16777619);
}
return (hash >>> 0) / 4294967296;
}, "unitIntervalFor");
const isReplaySampledIn = replaySampleRate > 0 && unitIntervalFor(sessionId) < replaySampleRate;
let replayId = null;
let replayEventCount = 0;
let replayStartedAt = 0;
let replayFinalized = false;
let stopReplayRecorder = null;
let replayChunkSequence = 0;
let replayUploadedBytes = 0;
let replayFlushTimer = null;
let replayDurationTimer = null;
let replayRecorderLoading = false;
const replayQueue = [];
const replayMaskTextSelector = [
"[data-lovable-mask]",
"[data-sensitive]",
"[data-private]",
"[data-auth]",
"[data-payment]",
"[contenteditable]",
"[autocomplete]",
"[name*='email' i]",
"[name*='phone' i]",
"[name*='address' i]",
"[name*='token' i]",
"[name*='secret' i]"
].join(",");
const replayBlockSelector = [
"canvas",
"embed",
"iframe",
"object",
"video",
"[data-lovable-block]",
".rr-block",
"[data-payment]",
"[data-auth]",
"[data-private]"
].join(",");
const replayIgnoreSelector = "[data-lovable-ignore],.rrweb-ignore";
const maskReplayText = /* @__PURE__ */ __name((text) => text.replace(/[^\s]/gu, "*"), "maskReplayText");
const queue = [];
let flushTimer = null;
const batchSize = Math.max(1, maxEventsPerBatch);
const projectEventNamePattern = /^project\.[a-z][a-z0-9_]{0,63}(\.[a-z][a-z0-9_]{0,63})*$/u;
const schemaVersionFor = /* @__PURE__ */ __name((eventName) => {
const schemaVersion = schemaVersions[eventName];
if (typeof schemaVersion === "number" && schemaVersion > 0) return schemaVersion;
return projectEventNamePattern.test(eventName) ? 1 : null;
}, "schemaVersionFor");
const byteLength = /* @__PURE__ */ __name((value) => {
const TextEncoderCtor = typeof TextEncoder === "function" ? TextEncoder : null;
return TextEncoderCtor ? new TextEncoderCtor().encode(value).length : value.length;
}, "byteLength");
const createBatchBody = /* @__PURE__ */ __name((events) => JSON.stringify({
envelope_schema_version: 1,
batch_id: randomId(),
sent_at: (/* @__PURE__ */ new Date()).toISOString(),
sdk: { name: "lovable-user-app-events", version: version2 },
artifact,
events
}), "createBatchBody");
const transmitBatchBody = /* @__PURE__ */ __name((body) => {
const BlobCtor = w.Blob || (typeof Blob === "function" ? Blob : null);
if (nav.sendBeacon && BlobCtor) {
const ok = nav.sendBeacon(trackUrl, new BlobCtor([body], { type: "application/json" }));
if (ok) return;
}
const fetchFn = w.fetch || (typeof fetch === "function" ? fetch : null);
if (!fetchFn) return;
fetchFn(trackUrl, {
method: "POST",
headers: { "content-type": "application/json" },
body,
keepalive: true
}).catch(() => {
});
}, "transmitBatchBody");
const sendBatch = /* @__PURE__ */ __name((events) => {
let start = 0;
while (start < events.length) {
let end = events.length;
let body = createBatchBody(events.slice(start, end));
while (end - start > 1 && byteLength(body) > maxKeepaliveBatchBytes) {
end = start + Math.max(1, Math.floor((end - start) / 2));
body = createBatchBody(events.slice(start, end));
}
transmitBatchBody(body);
start = end;
}
}, "sendBatch");
const createReplayChunkBody = /* @__PURE__ */ __name((events, chunkID, chunkSequence) => {
if (!replayId) return null;
return JSON.stringify({
envelope_schema_version: 1,
replay_schema_version: 1,
replay_id: replayId,
chunk_id: chunkID,
chunk_sequence: chunkSequence,
sent_at: (/* @__PURE__ */ new Date()).toISOString(),
sdk: { name: "lovable-user-app-events", version: version2 },
artifact,
anonymous_id: anonymousId,
session_id: sessionId,
page_view_id: pageViewId,
events
});
}, "createReplayChunkBody");
const canSendReplayEvent = /* @__PURE__ */ __name((event) => {
const body = createReplayChunkBody([event], "00000000-0000-4000-8000-000000000000", replayChunkSequence);
return !!body && byteLength(body) <= maxReplayBodyBytes;
}, "canSendReplayEvent");
const transmitReplayChunkBody = /* @__PURE__ */ __name((body, preferKeepalive = false) => {
const fetchFn = w.fetch || (typeof fetch === "function" ? fetch : null);
if (!fetchFn) return;
const bodyBytes = byteLength(body);
const useKeepalive = preferKeepalive && bodyBytes <= maxKeepaliveBatchBytes;
fetchFn(replayUrl, {
method: "POST",
headers: { "content-type": "application/json" },
body,
...useKeepalive ? { keepalive: true } : {}
}).then((response) => {
if (!response.ok) {
stopReplayRecording("upload_failed", true);
}
}).catch(() => {
stopReplayRecording("upload_failed", true);
});
}, "transmitReplayChunkBody");
const replayDurationMs = /* @__PURE__ */ __name(() => Math.max(0, perf.now() - replayStartedAt), "replayDurationMs");
const clearReplayFlushTimer = /* @__PURE__ */ __name(() => {
if (!replayFlushTimer) return;
const clearTimer = w.clearTimeout || (typeof clearTimeout === "function" ? clearTimeout : null);
if (clearTimer) clearTimer(replayFlushTimer);
replayFlushTimer = null;
}, "clearReplayFlushTimer");
const clearReplayDurationTimer = /* @__PURE__ */ __name(() => {
if (!replayDurationTimer) return;
const clearTimer = w.clearTimeout || (typeof clearTimeout === "function" ? clearTimeout : null);
if (clearTimer) clearTimer(replayDurationTimer);
replayDurationTimer = null;
}, "clearReplayDurationTimer");
const stopReplayRecorderSafely = /* @__PURE__ */ __name(() => {
if (!stopReplayRecorder) return;
try {
stopReplayRecorder();
} catch {
stopReplayRecorder = null;
}
stopReplayRecorder = null;
}, "stopReplayRecorderSafely");
const emitReplayMetadataFor = /* @__PURE__ */ __name((targetReplayId, status, reason, eventCount, durationMs, chunkCount, uploadedBytes) => {
enqueue("lovable.session_replay", {
replay_id: targetReplayId,
status,
reason,
recorder: "rrweb",
sample_rate: replaySampleRate,
event_count: eventCount,
duration_ms: durationMs,
chunk_count: chunkCount,
uploaded_bytes: uploadedBytes
});
}, "emitReplayMetadataFor");
const emitReplayMetadata = /* @__PURE__ */ __name((status, reason) => {
if (!replayId) return;
emitReplayMetadataFor(
replayId,
status,
reason,
replayEventCount,
replayDurationMs(),
replayChunkSequence,
replayUploadedBytes
);
}, "emitReplayMetadata");
const stopReplayRecording = /* @__PURE__ */ __name((reason, dropQueuedEvents = false) => {
if (!replayId || replayFinalized) return;
stopReplayRecorderSafely();
clearReplayDurationTimer();
if (dropQueuedEvents) {
replayQueue.length = 0;
clearReplayFlushTimer();
}
emitReplayMetadata("stopped", reason);
replayFinalized = true;
}, "stopReplayRecording");
const flushReplay = /* @__PURE__ */ __name((preferKeepalive = false) => {
clearReplayFlushTimer();
if (!replayId || replayQueue.length === 0) return;
while (!replayFinalized && replayQueue.length > 0) {
let count2 = Math.min(replayQueue.length, maxReplayEventsPerChunk);
const chunkID = randomId();
const chunkSequence = replayChunkSequence;
let body = createReplayChunkBody(replayQueue.slice(0, count2), chunkID, chunkSequence);
while (body && count2 > 1 && byteLength(body) > maxReplayBodyBytes) {
count2 = Math.max(1, Math.floor(count2 / 2));
body = createReplayChunkBody(replayQueue.slice(0, count2), chunkID, chunkSequence);
}
if (!body) return;
const bodyBytes = byteLength(body);
if (bodyBytes > maxReplayBodyBytes) {
replayQueue.shift();
replayEventCount = Math.max(0, replayEventCount - 1);
continue;
}
if (replayChunkSequence >= maxReplayChunks || replayUploadedBytes + bodyBytes > maxReplayTotalBytes) {
stopReplayRecording(replayChunkSequence >= maxReplayChunks ? "chunk_limit" : "size_limit", true);
return;
}
replayQueue.splice(0, count2);
replayChunkSequence++;
replayUploadedBytes += bodyBytes;
transmitReplayChunkBody(body, preferKeepalive);
if (replayFinalized) return;
if (replayChunkSequence >= maxReplayChunks) {
stopReplayRecording("chunk_limit", true);
return;
}
}
}, "flushReplay");
const scheduleReplayFlush = /* @__PURE__ */ __name(() => {
if (replayFlushTimer) return;
const setTimer = w.setTimeout || (typeof setTimeout === "function" ? setTimeout : null);
if (!setTimer) {
flushReplay();
return;
}
replayFlushTimer = setTimer(flushReplay, replayFlushIntervalMs);
}, "scheduleReplayFlush");
const clearFlushTimer = /* @__PURE__ */ __name(() => {
if (!flushTimer) return;
const clearTimer = w.clearTimeout || (typeof clearTimeout === "function" ? clearTimeout : null);
if (clearTimer) clearTimer(flushTimer);
flushTimer = null;
}, "clearFlushTimer");
const flush = /* @__PURE__ */ __name(() => {
clearFlushTimer();
if (queue.length === 0) return;
const events = queue.splice(0, batchSize);
sendBatch(events);
if (queue.length > 0) scheduleFlush();
}, "flush");
const scheduleFlush = /* @__PURE__ */ __name(() => {
if (flushTimer) return;
const setTimer = w.setTimeout || (typeof setTimeout === "function" ? setTimeout : null);
if (!setTimer) {
flush();
return;
}
flushTimer = setTimer(flush, 250);
}, "scheduleFlush");
const rotatePageViewId = /* @__PURE__ */ __name(() => {
pageViewId = randomId();
return pageViewId;
}, "rotatePageViewId");
const shouldFlushImmediately = /* @__PURE__ */ __name((eventName) => eventName === "lovable.client_error" || eventName === "lovable.resource_error", "shouldFlushImmediately");
const refreshSession = /* @__PURE__ */ __name(() => {
const now = Date.now();
const expiresAt = now + rollingSessionTimeoutMs;
if (sessionExpiresAt > now) {
sessionExpiresAt = expiresAt;
writeRollingSession(w.localStorage, rollingSessionStorageKey, sessionId, sessionExpiresAt);
return false;
}
const sharedSession = readRollingSession(w.localStorage, rollingSessionStorageKey);
if (sharedSession && sharedSession.expiresAt > now) {
sessionId = sharedSession.value;
sessionExpiresAt = expiresAt;
writeRollingSession(w.localStorage, rollingSessionStorageKey, sessionId, sessionExpiresAt);
return false;
}
sessionId = randomId();
sessionExpiresAt = expiresAt;
writeRollingSession(w.localStorage, rollingSessionStorageKey, sessionId, sessionExpiresAt);
return true;
}, "refreshSession");
const queueEvent = /* @__PURE__ */ __name((eventName, eventSchemaVersion, properties = {}) => {
const activeReplayId = replayId && !replayFinalized ? replayId : null;
const eventId = randomId();
const event = {
event_id: eventId,
event_name: eventName,
event_schema_version: eventSchemaVersion,
event_time: (/* @__PURE__ */ new Date()).toISOString(),
anonymous_id: anonymousId,
session_id: sessionId,
page_view_id: pageViewId,
properties
};
if (activeReplayId) event.replay_id = activeReplayId;
if (shouldFlushImmediately(eventName)) {
queue.unshift(event);
} else {
queue.push(event);
}
if (shouldFlushImmediately(eventName) || queue.length >= batchSize) {
flush();
} else {
scheduleFlush();
}
return eventId;
}, "queueEvent");
const enqueue = /* @__PURE__ */ __name((eventName, properties = {}) => {
const eventSchemaVersion = typeof eventName === "string" ? schemaVersionFor(eventName) : null;
if (eventSchemaVersion === null) return null;
if (eventName !== "lovable.session_started" && refreshSession()) {
const sessionStartedSchemaVersion = schemaVersionFor("lovable.session_started");
if (sessionStartedSchemaVersion !== null) {
queueEvent("lovable.session_started", sessionStartedSchemaVersion, {
reason: "new_session",
is_new_anonymous_id: false
});
}
}
return queueEvent(eventName, eventSchemaVersion, properties);
}, "enqueue");
let lastPageViewPath = loc.pathname;
const track = /* @__PURE__ */ __name((eventName, properties = {}) => {
if (eventName === "lovable.page_viewed") {
rotatePageViewId();
if (typeof properties.url_path === "string") lastPageViewPath = properties.url_path;
}
return enqueue(eventName, properties);
}, "track");
const pathFromUrl = /* @__PURE__ */ __name((value) => {
try {
return new URL(value, loc.href).pathname;
} catch {
return null;
}
}, "pathFromUrl");
const hostFromUrl = /* @__PURE__ */ __name((value) => {
try {
return new URL(value, loc.href).host.replace(/^www\./iu, "");
} catch {
return null;
}
}, "hostFromUrl");
const serializeThrowable = /* @__PURE__ */ __name((value) => {
const throwable = value && typeof value === "object" ? value : null;
const stringifyPrimitive = /* @__PURE__ */ __name((input) => {
if (typeof input === "string") return input;
if (typeof input === "number" || typeof input === "boolean" || typeof input === "bigint") return String(input);
return null;
}, "stringifyPrimitive");
const stack = stringifyPrimitive(throwable?.stack);
return {
message: stringifyPrimitive(throwable?.message) ?? stringifyPrimitive(value) ?? "Unknown error",
name: stringifyPrimitive(throwable?.name),
stack: stack ? stack.slice(0, 8e3) : null
};
}, "serializeThrowable");
const emitPageView = /* @__PURE__ */ __name((navigationType, rotatePageView = true) => {
if (rotatePageView) rotatePageViewId();
const pagePath = loc.pathname;
const properties = {
url_path: pagePath,
navigation_type: navigationType
};
if (typeof d?.referrer === "string" && d.referrer) {
properties.referrer_host = hostFromUrl(d.referrer) ?? "";
properties.referrer_path = pathFromUrl(d.referrer) ?? "";
}
lastPageViewPath = pagePath;
enqueue("lovable.page_viewed", properties);
}, "emitPageView");
const emitPageViewIfPathChanged = /* @__PURE__ */ __name((navigationType) => {
if (loc.pathname === lastPageViewPath) return;
emitPageView(navigationType);
}, "emitPageViewIfPathChanged");
const startReplayRecording = /* @__PURE__ */ __name(() => {
const record = replayMode === "rrweb" && isReplaySampledIn && w.rrweb && typeof w.rrweb.record === "function" ? w.rrweb.record : null;
if (!record || replayId) return;
replayId = randomId();
replayStartedAt = perf.now();
replayFinalized = false;
replayChunkSequence = 0;
replayUploadedBytes = 0;
try {
const stop = record({
emit(event) {
if (replayFinalized) return;
if (!event || typeof event !== "object") return;
if (replayDurationMs() >= maxReplayDurationMs) {
stopReplayRecording("duration_limit", true);
return;
}
if (!canSendReplayEvent(event)) return;
replayEventCount += 1;
replayQueue.push(event);
if (replayQueue.length >= maxReplayEventsPerChunk) {
flushReplay();
} else {
scheduleReplayFlush();
}
},
blockClass: "rr-block",
blockSelector: replayBlockSelector,
collectFonts: false,
ignoreClass: "rrweb-ignore",
ignoreSelector: replayIgnoreSelector,
inlineImages: false,
maskAllInputs: true,
maskInputFn: maskReplayText,
maskInputOptions: {
checkbox: false,
color: false,
date: true,
"datetime-local": true,
email: true,
month: true,
number: true,
password: true,
radio: false,
range: false,
search: true,
select: true,
tel: true,
text: true,
textarea: true,
time: true,
url: true,
week: true
},
maskTextClass: "rr-mask",
maskTextFn: maskReplayText,
maskTextSelector: replayMaskTextSelector,
recordCanvas: false,
recordCrossOriginIframes: false
});
if (typeof stop === "function") stopReplayRecorder = stop;
const setTimer = w.setTimeout || (typeof setTimeout === "function" ? setTimeout : null);
if (setTimer) {
replayDurationTimer = setTimer(() => stopReplayRecording("duration_limit", true), maxReplayDurationMs);
}
emitReplayMetadata("started", "recorder_available");
} catch {
emitReplayMetadata("stopped", "recorder_start_failed");
replayId = null;
replayEventCount = 0;
replayStartedAt = 0;
replayFinalized = false;
stopReplayRecorder = null;
clearReplayDurationTimer();
}
}, "startReplayRecording");
const ensureReplayRecorder = /* @__PURE__ */ __name(() => {
if (replayMode !== "rrweb" || !isReplaySampledIn || replayId || replayRecorderLoading) return;
if (w.rrweb && typeof w.rrweb.record === "function") {
startReplayRecording();
return;
}
const head = d?.head;
if (!d?.createElement || !head?.appendChild) return;
const recorderScript = d.createElement("script");
replayRecorderLoading = true;
recorderScript.async = true;
recorderScript.src = replayScriptUrl;
recorderScript.onload = () => {
replayRecorderLoading = false;
if (!w.rrweb || typeof w.rrweb.record !== "function") {
emitReplayMetadataFor(randomId(), "stopped", "recorder_script_failed", 0, 0, 0, 0);
return;
}
startReplayRecording();
};
recorderScript.onerror = () => {
replayRecorderLoading = false;
emitReplayMetadataFor(randomId(), "stopped", "recorder_script_failed", 0, 0, 0, 0);
};
head.appendChild(recorderScript);
}, "ensureReplayRecorder");
const finalizeReplayRecording = /* @__PURE__ */ __name((reason) => {
if (!replayId || replayFinalized) return;
stopReplayRecorderSafely();
clearReplayDurationTimer();
flushReplay(true);
if (!replayFinalized) stopReplayRecording(reason);
}, "finalizeReplayRecording");
const stopReplayRecordingOnRuntimeError = /* @__PURE__ */ __name((event) => {
if (!replayId || replayFinalized) return;
const errorEvent = event && typeof event === "object" ? event : null;
const errorRecord = errorEvent?.error && typeof errorEvent.error === "object" ? errorEvent.error : null;
const filename = typeof errorEvent?.filename === "string" ? errorEvent.filename : "";
const stack = typeof errorRecord?.stack === "string" ? errorRecord.stack : "";
const isRecorderError = filename.includes("/__l5e/rrweb-record") || stack.includes("/__l5e/rrweb-record");
if (isRecorderError) {
stopReplayRecording("recorder_runtime_error", true);
}
}, "stopReplayRecordingOnRuntimeError");
const webVitalRating = /* @__PURE__ */ __name((metric, value) => {
const thresholds = {
CLS: [0.1, 0.25],
FCP: [1800, 3e3],
INP: [200, 500],
LCP: [2500, 4e3],
TTFB: [800, 1800]
};
const threshold = thresholds[metric];
if (!threshold) return "good";
if (value <= threshold[0]) return "good";
return value <= threshold[1] ? "needs-improvement" : "poor";
}, "webVitalRating");
const webVitalUnit = /* @__PURE__ */ __name((metric) => metric === "CLS" ? "score" : "millisecond", "webVitalUnit");
const emitWebVital = /* @__PURE__ */ __name((metric, value, delta = value, id2 = randomId()) => {
if (!Number.isFinite(value) || value < 0) return;
enqueue("lovable.web_vital", {
metric,
value,
unit: webVitalUnit(metric),
delta,
rating: webVitalRating(metric, value),
id: id2,
navigation_type: "initial_load"
});
}, "emitWebVital");
const performanceEntryValue = /* @__PURE__ */ __name((entry, key) => {
const value = entry[key];
return typeof value === "number" && Number.isFinite(value) ? value : null;
}, "performanceEntryValue");
const observePerformanceEntries = /* @__PURE__ */ __name((entryType, callback) => {
const ObserverCtor = w.PerformanceObserver;
if (!ObserverCtor) return false;
const supportedEntryTypes = ObserverCtor.supportedEntryTypes;
if (Array.isArray(supportedEntryTypes) && !supportedEntryTypes.includes(entryType)) return false;
try {
const observer = new ObserverCtor((list) => {
const entries = typeof list.getEntries === "function" ? list.getEntries() : [];
for (const entry of entries) {
if (entry && typeof entry === "object") callback(entry);
}
});
observer.observe(
entryType === "event" ? { type: entryType, buffered: true, durationThreshold: 40 } : { type: entryType, buffered: true }
);
return true;
} catch {
return false;
}
}, "observePerformanceEntries");
const observeWebVitals = /* @__PURE__ */ __name(() => {
let fcpReported = false;
let latestLcp = null;
let clsValue = 0;
let maxInp = 0;
let finalized = false;
const metricIds = {};
const reportedValues = {};
const metricId = /* @__PURE__ */ __name((metric) => {
metricIds[metric] = metricIds[metric] || randomId();
return metricIds[metric];
}, "metricId");
const reportMetric = /* @__PURE__ */ __name((metric, value) => {
if (reportedValues[metric] === value) return;
const previousValue = reportedValues[metric];
reportedValues[metric] = value;
emitWebVital(metric, value, previousValue === void 0 ? value : value - previousValue, metricId(metric));
}, "reportMetric");
const navigationEntries = typeof perf.getEntriesByType === "function" ? perf.getEntriesByType("navigation") : [];
const navigationEntry = navigationEntries[0] && typeof navigationEntries[0] === "object" ? navigationEntries[0] : null;
const responseStart = navigationEntry ? performanceEntryValue(navigationEntry, "responseStart") : null;
const requestStart = navigationEntry ? performanceEntryValue(navigationEntry, "requestStart") : null;
const fetchStart = navigationEntry ? performanceEntryValue(navigationEntry, "fetchStart") : null;
const ttfbStart = requestStart ?? fetchStart;
if (responseStart !== null && ttfbStart !== null && responseStart >= ttfbStart) {
emitWebVital("TTFB", responseStart - ttfbStart);
}
observePerformanceEntries("paint", (entry) => {
if (fcpReported || entry.name !== "first-contentful-paint") return;
const startTime = performanceEntryValue(entry, "startTime");
if (startTime === null) return;
fcpReported = true;
emitWebVital("FCP", startTime);
});
observePerformanceEntries("largest-contentful-paint", (entry) => {
latestLcp = performanceEntryValue(entry, "startTime") ?? performanceEntryValue(entry, "renderTime") ?? performanceEntryValue(entry, "loadTime") ?? latestLcp;
});
const clsObserverStarted = observePerformanceEntries("layout-shift", (entry) => {
if (entry.hadRecentInput === true) return;
const value = performanceEntryValue(entry, "value");
if (value !== null) clsValue += value;
});
observePerformanceEntries("event", (entry) => {
const interactionId = performanceEntryValue(entry, "interactionId");
if (interactionId === null || interactionId <= 0) return;
const duration = performanceEntryValue(entry, "duration");
if (duration !== null && duration > maxInp) maxInp = duration;
});
return (final = false) => {
if (finalized) return;
if (latestLcp !== null) reportMetric("LCP", latestLcp);
if (clsObserverStarted) reportMetric("CLS", clsValue);
if (maxInp > 0) reportMetric("INP", maxInp);
if (final) finalized = true;
};
}, "observeWebVitals");
const patchHistory = /* @__PURE__ */ __name((method, navigationType) => {
const historyObject = w.history;
const original = historyObject && historyObject[method];
if (!historyObject || typeof original !== "function") return;
historyObject[method] = function(...args) {
const result = original.apply(this, args);
emitPageViewIfPathChanged(navigationType);
return result;
};
}, "patchHistory");
const normalizeCaptureExceptionOptions = /* @__PURE__ */ __name((options) => {
const record = options && typeof options === "object" && !Array.isArray(options) ? options : {};
const mechanism = typeof record.mechanism === "string" ? record.mechanism : "manual";
const severity = typeof record.severity === "string" ? record.severity : "error";
return {
mechanism: ["manual", "onerror", "unhandledrejection", "react_error_boundary"].includes(mechanism) ? mechanism : "manual",
handled: typeof record.handled === "boolean" ? record.handled : true,
severity: ["error", "warning", "info"].includes(severity) ? severity : "error"
};
}, "normalizeCaptureExceptionOptions");
w.__lovableEvents = Object.assign(existing, {
__userAppEventsSdkVersion: version2,
track,
flush,
identify(identity) {
const identityRecord = identity && typeof identity === "object" ? identity : null;
appUserId = typeof identityRecord?.user_id === "string" ? identityRecord.user_id : null;
},
getIdentity() {
return { anonymous_id: anonymousId, app_user_id_hash_available: !!appUserId };
},
getReplay() {
return { replay_id: replayId, active: !!replayId && !replayFinalized, event_count: replayEventCount };
},
resetIdentity() {
appUserId = null;
},
captureException(error, context = {}, options = {}) {
const throwable = serializeThrowable(error);
const captureOptions = normalizeCaptureExceptionOptions(options);
const captureContext = context && typeof context === "object" && !Array.isArray(context) ? context : {};
enqueue("lovable.client_error", {
occurrence_id: randomId(),
...throwable,
...captureOptions,
context: captureContext
});
},
startSpan(name, attributes = {}) {
const startTime = (/* @__PURE__ */ new Date()).toISOString();
const start = perf.now();
return {
end(status = "ok") {
enqueue("lovable.frontend_span", {
name,
start_time: startTime,
status,
duration_ms: Math.max(0, perf.now() - start),
attributes
});
}
};
}
});
if (w.addEventListener) {
w.addEventListener("error", stopReplayRecordingOnRuntimeError, true);
}
ensureReplayRecorder();
const finalizeWebVitals = observeWebVitals();
if (w.addEventListener) {
w.addEventListener(
"error",
(event) => {
const errorEvent = event && typeof event === "object" ? event : null;
const target = errorEvent?.target && typeof errorEvent.target === "object" ? errorEvent.target : null;
let resourceUrl = null;
if (target && target !== w) {
if (typeof target.src === "string") {
resourceUrl = target.src;
} else if (typeof target.href === "string") {
resourceUrl = target.href;
}
}
if (resourceUrl !== null) {
const resourceType = typeof target?.tagName === "string" ? target.tagName.toLowerCase() : "unknown";
enqueue("lovable.resource_error", {
resource_type: resourceType,
url_host: hostFromUrl(resourceUrl) ?? "",
failure_type: "load_error",
element: resourceType,
url_path: pathFromUrl(resourceUrl),
mechanism: "resource_load",
handled: false,
severity: "error"
});
return;
}
const throwable = serializeThrowable(errorEvent?.error || errorEvent?.message);
enqueue("lovable.client_error", {
occurrence_id: randomId(),
...throwable,
filename: typeof errorEvent?.filename === "string" ? pathFromUrl(errorEvent.filename) : null,
lineno: typeof errorEvent?.lineno === "number" ? errorEvent.lineno : null,
colno: typeof errorEvent?.colno === "number" ? errorEvent.colno : null,
mechanism: "onerror",
handled: false,
severity: "error"
});
},
true
);
w.addEventListener("unhandledrejection", (event) => {
const rejectionEvent = event && typeof event === "object" ? event : null;
const throwable = serializeThrowable(rejectionEvent?.reason);
enqueue("lovable.client_error", {
occurrence_id: randomId(),
...throwable,
mechanism: "unhandledrejection",
handled: false,
severity: "error"
});
});
w.addEventListener("pagehide", () => {
finalizeWebVitals(true);
finalizeReplayRecording("pagehide");
flush();
});
w.addEventListener("popstate", () => emitPageViewIfPathChanged("popstate"));
w.addEventListener("hashchange", () => emitPageView("hashchange"));
}
if (d && typeof d.addEventListener === "function") {
d.addEventListener("visibilitychange", () => {
if (d.visibilityState === "hidden") {
finalizeWebVitals();
flushReplay(true);
flush();
}
});
}
patchHistory("pushState", "push_state");
patchHistory("replaceState", "replace_state");
if (sessionIdentity.created) {
enqueue("lovable.session_started", {
reason: "new_session",
is_new_anonymous_id: anonymousIdentity.created
});
}
emitPageView("initial_load", false);
})(window, "0.1.1-replay-recorder-fix", {"lovable.session_started":1,"lovable.page_viewed":1,"lovable.client_error":1,"lovable.frontend_span":1,"lovable.interaction":1,"lovable.form_submitted":1,"lovable.resource_error":1,"lovable.session_replay":1,"lovable.web_vital":1}, 50, 51200, 131072, 100, 5242880, 50, 600000, 2000);})();