Skip to content

[loop cycle 2] fix(notifications): forward service-worker showNotification to native toast#10

Merged
karem505 merged 1 commit into
masterfrom
whatrust-loop/cycle-2-sw-notification-shim
Jun 28, 2026
Merged

[loop cycle 2] fix(notifications): forward service-worker showNotification to native toast#10
karem505 merged 1 commit into
masterfrom
whatrust-loop/cycle-2-sw-notification-shim

Conversation

@karem505

Copy link
Copy Markdown
Owner

What

Fixes a class of missing notifications. WhatsApp Web raises some notifications through the service worker via ServiceWorkerRegistration.showNotification(...) (used when it treats the tab as backgrounded). The existing window.Notification shim only intercepts the page-side new Notification(...) constructor — so the service-worker path slipped past it and those notifications never reached the OS notification center.

How

In bridge.js (section 2b, right after the existing Notification shim), override the page-side ServiceWorkerRegistration.prototype.showNotification to forward through the same native notify command the constructor shim already uses, and stub getNotifications() to resolve to [] (we render native toasts, so there's no in-page Notification object to return).

  • Installed as a Tauri initialization_script, so it runs before any page JS → WhatsApp can't capture a pre-patch reference; prototype lookup at call time means instances created later are covered.
  • Origin-guarded (whole file is gated to https://web.whatsapp.com) and wrapped in its own try/catch, so it can never abort the rest of bridge.js.
  • Routes through commands::notify, inheriting its lock-screen and settings suppression unchanged.
  • Scope is honest: notifications fired from inside the service worker's own realm can't be reached by a page-injected script (documented in the comment).

Verification

Gate 1 — deterministic (cargo build --locked + cargo test): PASS (51 tests; bridge.js is embedded via include_str!).

Gate 2 — real-engine behavioral (PyGObject WebKitGTK 2.x harness, origin spoofed to web.whatsapp.com): PASS. With a __TAURI__.invoke recorder installed:

  • new Notification("DM from Sara",{body:"hey there"}) → 1 notify invoke ✅
  • reg.showNotification("Group: Family",{body:"3 new messages"}) → 1 notify invoke ✅
  • showNotification returns a Promise ✅ · getNotifications()[] ✅ · Notification.permission === "granted" ✅ (no regression to the existing path)

Gate 3 — generation-blind code review (separate feature-dev:code-reviewer): APPROVE, severity none, no must-fix. Confirmed: override timing prevents a pre-patch reference; both paths inherit identical Rust-side suppression; try/catch isolated; getNotifications stub redundant-but-harmless; tag-dedup absence is pre-existing (matches the window.Notification shim), not a regression.


🤖 PR-ONLY — do not auto-merge. Releasing whatRust is manual via a v* tag; this loop never merges, bumps the version, or tags a release. Opened by the whatrust-fix-loop (cycle 2/6).

…tive toast

WhatsApp Web raises some notifications through ServiceWorkerRegistration
.showNotification (used when the tab is treated as backgrounded), which the existing
window.Notification shim does not intercept — so those notifications never reached the
OS notification center. Override the page-side prototype method to forward through the
same native `notify` command (inheriting its lock/settings suppression), and stub
getNotifications to resolve to [] since we render native toasts rather than in-page
Notification objects.

The override is installed before any page script runs (Tauri initialization_script),
so WhatsApp cannot hold a pre-patch reference; it is origin-guarded and wrapped in its
own try/catch so it can never abort the rest of bridge.js. Page-context calls only —
notifications fired from inside the service worker's own realm are out of scope for an
injected page script.

Verified in a real WebKitGTK engine (origin spoofed to web.whatsapp.com): both
new Notification(...) and reg.showNotification(...) now produce exactly one native
notify with the right title/body; getNotifications resolves to []; the existing
Notification path and permission==="granted" are unaffected.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016o9cWBaPy4zU4BAurUVoTp
karem505 added a commit that referenced this pull request Jun 28, 2026
Bundles six loop-shipped fixes:
- perf(dnd): stream dropped files as base64 to cut peak memory on large videos (#9)
- fix(notifications): forward service-worker showNotification to the native toast (#10)
- feat(calls): expose a minimal window.chrome so WhatsApp enables call buttons (#11)
- fix(notifications): de-duplicate burst-repeated native toasts (#12)
- fix(dnd): route AVIF/HEIF photos as photos; broaden MIME labels (#13)
- fix(calls/capability): return a complete Chrome high-entropy client-hints set (#14)
Plus integration: SW notifications share the dedup window; base64_encode is test-only now.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016o9cWBaPy4zU4BAurUVoTp
@karem505 karem505 merged commit 3e2ec3b into master Jun 28, 2026
6 checks passed
@karem505 karem505 deleted the whatrust-loop/cycle-2-sw-notification-shim branch June 28, 2026 01:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant