[codex] fix PWA push reliability - #42
Conversation
Deploying with
|
| Status | Preview URL | Commit | Alias | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! | https://pr-42-sable.justin-tech.workers.dev | aff6ffd | pr-42 |
Fri, 12 Jun 2026 17:37:44 GMT |
| function navigateToServiceWorkerUrl(navigate: ReturnType<typeof useNavigate>, url: string): void { | ||
| try { | ||
| const target = new URL(url, window.location.origin); | ||
| if (target.origin === window.location.origin) { | ||
| navigate(`${target.pathname}${target.search}${target.hash}`); | ||
| return; | ||
| } | ||
| } catch { | ||
| // Fall through to browser navigation for malformed/relative strings. | ||
| } | ||
| window.location.assign(url); | ||
| } |
There was a problem hiding this comment.
The fallback window.location.assign(url) will navigate to any scheme/origin when navigateUrl comes from a service worker message (ultimately push payload data). This can enable cross-origin redirects or potentially dangerous schemes (e.g. javascript:/data:) on notification click/in-app fallback.
| if (document.visibilityState === 'visible' && navigator.onLine) { | ||
| if (!phase3AdaptiveBackoffJitter || now >= suppressHeartbeatUntilRef.current) { | ||
| const result = pushSessionNow('heartbeat'); | ||
| if (phase3AdaptiveBackoffJitter && result === 'sent') { | ||
| heartbeatFailuresRef.current = 0; | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
phase3AdaptiveBackoffJitter uses heartbeatFailuresRef.current to compute exponential backoff, but heartbeatFailuresRef is never incremented. As a result, the adaptive backoff/jitter path behaves the same as the fixed-interval heartbeat.
| useEffect(() => { | ||
| if (!phase2VisibleHeartbeat) return undefined; | ||
|
|
||
| heartbeatFailuresRef.current = 0; | ||
| suppressHeartbeatUntilRef.current = 0; |
There was a problem hiding this comment.
The new sessionSync strategy logic (foreground debounce + heartbeat + adaptive backoff/jitter) in this hook is non-trivial but has no unit tests. There are already Vitest tests for other hooks (e.g. useClientConfig.test.ts, useRoomNavigate.test.ts), so adding focused fake-timer tests here would help prevent regressions in the push reliability work.
Description
Fixes mobile PWA push reliability issues where stale service-worker visibility state could suppress OS notifications after iOS backgrounding. The SW now requires a fresh nonce-based visible-client acknowledgement before suppressing an OS push, sends a generic in-app fallback banner when the app is visible but sync is unhealthy, and buffers sanitized push telemetry until the page can drain it into Sentry.
This also restores the phased foreground SW session refresh behavior from upstream SableClient#573, keeps the current foreground sync retry behavior, and adds opt-in client support for WebKit Declarative Web Push fallback payloads. The declarative path only advertises/handles payloads; the push gateway must still emit the declarative JSON.
Related upstream research:
sessionSyncbehavior here.Fixes #
Type of change
Checklist:
AI disclosure:
Codex implemented the service-worker visibility confirmation handshake, push telemetry buffering, visible-sync-unhealthy in-app fallback handling, declarative Web Push fallback mapping, pusher metadata opt-in, restored
sessionSyncforeground session refresh, documentation, changeset, and focused tests under user direction.Validation
pnpm lint && pnpm fmt:check && pnpm typecheck && pnpm test:run && pnpm knip && pnpm buildNote: lint exits successfully with existing unrelated warnings in
ClientConfigLoader,usePresenceSync,CallWidgetDriver.test, andmediaTransport.test.