()
| 450 | } |
| 451 | |
| 452 | const postTelemetry = async () => { |
| 453 | const latestStats = latestStatsRef.current; |
| 454 | const latestStatus = latestStatusRef.current; |
| 455 | const now = Date.now(); |
| 456 | if ( |
| 457 | !remote && |
| 458 | now - lastVisualArtifactSampleAtRef.current >= |
| 459 | VISUAL_ARTIFACT_TELEMETRY_INTERVAL_MS |
| 460 | ) { |
| 461 | lastVisualArtifactSampleAtRef.current = now; |
| 462 | const visualSample = await workerClientRef.current |
| 463 | ?.collectVisualArtifactSample?.(simulator.udid) |
| 464 | .catch(() => null); |
| 465 | if (visualSample) { |
| 466 | latestVisualArtifactRef.current = visualSample; |
| 467 | latestVisualArtifactSampleCountRef.current += 1; |
| 468 | } |
| 469 | } |
| 470 | const latestVisualArtifact = latestVisualArtifactRef.current; |
| 471 | const payload = { |
| 472 | ...latestStats, |
| 473 | appFps: latestFpsRef.current, |
| 474 | clientId: clientTelemetryIdRef.current, |
| 475 | focused: document.hasFocus(), |
| 476 | kind: "page", |
| 477 | pageFps: pageFpsRef.current, |
| 478 | status: latestStatus.state, |
| 479 | timestampMs: Date.now(), |
| 480 | udid: simulator.udid, |
| 481 | url: window.location.href, |
| 482 | userAgent: window.navigator.userAgent, |
| 483 | clientBundle: currentClientBundle(), |
| 484 | visualBadPixelRatio: latestVisualArtifact?.badPixelRatio, |
| 485 | visualMaxPixelDiff: latestVisualArtifact?.maxPixelDiff, |
| 486 | visualMaxTileDiff: latestVisualArtifact?.maxTileMeanDiff, |
| 487 | visualMeanDiff: latestVisualArtifact?.meanDiff, |
| 488 | visualSampleCount: latestVisualArtifactSampleCountRef.current, |
| 489 | visibilityState: document.visibilityState, |
| 490 | }; |
| 491 | workerClientRef.current?.sendStreamControl({ |
| 492 | clientId: clientTelemetryIdRef.current, |
| 493 | foreground: isViewerForeground(canvasVisibleRef.current), |
| 494 | }); |
| 495 | if ( |
| 496 | sendStreamClientStats(payload) || |
| 497 | remote || |
| 498 | streamTransport === "webrtc" || |
| 499 | streamTransport === "auto" |
| 500 | ) { |
| 501 | return; |
| 502 | } |
| 503 | void fetch(buildClientTelemetryUrl(), { |
| 504 | body: JSON.stringify(payload), |
| 505 | cache: "no-store", |
| 506 | headers: apiHeaders(), |
| 507 | method: "POST", |
| 508 | }).catch(() => { |
| 509 | // Diagnostic only; UI state should never depend on telemetry. |
no test coverage detected