From bf621914e5c262593ba3cd8a9163bebf1bb089f5 Mon Sep 17 00:00:00 2001 From: Eli Mallon Date: Thu, 30 Jul 2026 16:11:39 -0700 Subject: [PATCH] fix: activate time-sync monkeypatch and raise drift notification to 1h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The time-sync feature computed a server clock offset and warned the user about drift, but initializeTimeSync() — the function that actually patches global Date to apply the offset — was never called anywhere in the codebase. This meant all timestamps (including chat message createdAt) used the raw, uncorrected system clock, causing messages to sort incorrectly when the user's clock was skewed. Changes: - Call initializeTimeSync() in js/app/src/polyfills.tsx, which runs before React mounts and before any chat message can be created. - Export initializeTimeSync from @streamplace/components barrel. - Add idempotency guard to initializeTimeSync to prevent double-patching. - Fix checkClockDrift to use OriginalDate instead of patched Date, so drift detection still measures the real system clock after the patch is active (otherwise it would always report ~0 drift). - Fix getSyncedDate to use OriginalDate.now() to avoid double-applying the offset once the monkeypatch is active. - Raise CLOCK_DRIFT_THRESHOLD_MS from 5s to 1h since auto-correction now handles smaller drifts; only notify the user for severe drift. - Update toast message to reflect that times are auto-corrected. --- js/app/src/polyfills.tsx | 6 ++++++ js/components/src/index.tsx | 4 ++++ js/components/src/time-sync/time-sync.ts | 17 +++++++++++------ js/components/src/time-sync/useTimeSync.tsx | 2 +- 4 files changed, 22 insertions(+), 7 deletions(-) diff --git a/js/app/src/polyfills.tsx b/js/app/src/polyfills.tsx index e69de29b..e213a2d7 100644 --- a/js/app/src/polyfills.tsx +++ b/js/app/src/polyfills.tsx @@ -0,0 +1,6 @@ +import { initializeTimeSync } from "@streamplace/components"; + +// Install the Date monkeypatch before React mounts so that all subsequent +// `new Date()` / `Date.now()` calls account for server clock offset. +// No-op on non-web platforms. +initializeTimeSync(); diff --git a/js/components/src/index.tsx b/js/components/src/index.tsx index 3ff10fed..0f119813 100644 --- a/js/components/src/index.tsx +++ b/js/components/src/index.tsx @@ -65,6 +65,10 @@ export * from "./components/share/sharesheet"; export * from "./components/keep-awake"; +// Time sync — installs a Date monkeypatch that corrects for server clock +// offset. Must be called once on web before any time-sensitive code runs. +export { initializeTimeSync } from "./time-sync"; + // Dashboard components export * as Dashboard from "./components/dashboard"; diff --git a/js/components/src/time-sync/time-sync.ts b/js/components/src/time-sync/time-sync.ts index bffb239c..fcf29cbe 100644 --- a/js/components/src/time-sync/time-sync.ts +++ b/js/components/src/time-sync/time-sync.ts @@ -3,8 +3,9 @@ import { Platform } from "react-native"; let timeOffset = 0; let hasWarned = false; let OriginalDate: DateConstructor = Date; +let isInitialized = false; -const CLOCK_DRIFT_THRESHOLD_MS = 5000; // 5 seconds +const CLOCK_DRIFT_THRESHOLD_MS = 60 * 60 * 1000; // 1 hour export function getTimeOffset(): number { return timeOffset; @@ -19,8 +20,8 @@ export function checkClockDrift(serverTime: string): { driftMs: number; driftSeconds: number; } { - const serverDate = new Date(serverTime); - const clientDate = new Date(); + const serverDate = new OriginalDate(serverTime); + const clientDate = new OriginalDate(); const drift = Math.abs(serverDate.getTime() - clientDate.getTime()); if (drift > CLOCK_DRIFT_THRESHOLD_MS) { @@ -55,11 +56,10 @@ export function syncTimeWithServer( } export function getSyncedDate(): Date { - const now = new Date(); if (timeOffset !== 0) { - return new Date(now.getTime() + timeOffset); + return new Date(OriginalDate.now() + timeOffset); } - return now; + return new OriginalDate(); } export function getSystemDate(): Date { @@ -71,6 +71,11 @@ export function getSystemTime(): number { } export function initializeTimeSync(): void { + if (isInitialized) { + return; + } + isInitialized = true; + if (Platform.OS !== "web") { return; } diff --git a/js/components/src/time-sync/useTimeSync.tsx b/js/components/src/time-sync/useTimeSync.tsx index dc0c3c23..929650dc 100644 --- a/js/components/src/time-sync/useTimeSync.tsx +++ b/js/components/src/time-sync/useTimeSync.tsx @@ -35,7 +35,7 @@ export function useTimeSync() { hasShownWarning.current = true; t.show( "Clock drift detected!", - `Your device clock is ${driftInfo.driftSeconds}s off from server time. Please sync your system clock to avoid issues.`, + `Your device clock is ${driftInfo.driftSeconds}s off from server time. Times have been auto-corrected, but please sync your system clock.`, { variant: "info", iconLeft: TriangleAlert, -- 2.51.2