Spaces:
Sleeping
Sleeping
| const TELEMETRY_ENDPOINT = "/telemetry"; | |
| function send(event) { | |
| try { | |
| navigator.sendBeacon(TELEMETRY_ENDPOINT, JSON.stringify(event)); | |
| } catch {} | |
| } | |
| /** Fire-and-forget client events (same channel as initTelemetry). */ | |
| export function sendTelemetry(event) { | |
| send(event); | |
| } | |
| export function initTelemetry() { | |
| import("web-vitals/attribution").then(({ onCLS, onLCP, onINP }) => { | |
| onCLS((metric) => { | |
| if (metric.value > 0.05) { | |
| send({ | |
| type: "cls", | |
| value: metric.value, | |
| target: metric.attribution?.largestShiftTarget || null, | |
| sources: metric.attribution?.largestShiftSource || null, | |
| }); | |
| } | |
| }); | |
| onLCP((metric) => { | |
| send({ | |
| type: "lcp", | |
| value: metric.value, | |
| element: metric.attribution?.element || null, | |
| url: metric.attribution?.url || null, | |
| }); | |
| }); | |
| onINP((metric) => { | |
| if (metric.value > 200) { | |
| send({ | |
| type: "inp", | |
| value: metric.value, | |
| target: metric.attribution?.interactionTarget || null, | |
| }); | |
| } | |
| }); | |
| }).catch(() => {}); | |
| const watchIds = ["tab-bar", "action-bar"]; | |
| const observer = new ResizeObserver((entries) => { | |
| for (const entry of entries) { | |
| const id = entry.target.dataset?.watchId || entry.target.className; | |
| const rect = entry.target.getBoundingClientRect(); | |
| send({ type: "resize", id, width: Math.round(rect.width), height: Math.round(rect.height) }); | |
| } | |
| }); | |
| requestAnimationFrame(() => { | |
| for (const id of watchIds) { | |
| const el = document.querySelector(`[data-watch-id="${id}"]`) || document.querySelector(`.${id}`); | |
| if (el) observer.observe(el); | |
| } | |
| }); | |
| try { | |
| const perfObs = new PerformanceObserver((list) => { | |
| for (const entry of list.getEntries()) { | |
| if (entry.duration > 200) { | |
| send({ type: "slow_interaction", name: entry.name, duration: Math.round(entry.duration) }); | |
| } | |
| } | |
| }); | |
| perfObs.observe({ type: "event", buffered: true, durationThreshold: 100 }); | |
| } catch {} | |
| } | |