feat(notifications): Web Push for the web app, client side (#202) #489
Closed
jared
wants to merge 1 commits from
feat/web-push into lotus
pull from: feat/web-push
merge into: :lotus
:lotus
:feat/web-push
:fix/call-theme-before-ready
:fix/dfn-worklet-file
:test/lotus-feature-e2e
:fix/own-presence-display
:fix/sso-uia-desktop
:seasonal/lunar
:seasonal/newyear
:seasonal/christmas
:chore/build-hygiene
:fix/status-save-speed
:chore/typing-hygiene
:feat/settings-search
:feat/settings-pages
:chore/security-deps
:feat/settings-quick-wins
:feat/data-export
:feat/stale-sessions
:feat/landscape-call
:feat/expected-devices
:feat/oauth-detect
:chore/ec-0.28
:chore/sdk-44
:feat/key-upload-recovery
:feat/keychain-session
:feat/vimeo-events
:feat/widget-always-on-screen
:feat/call-summary-details
:feat/widget-popout
:fix/ios-long-press
:chore/any-cleanup
:chore/soundboard-mic-mix
:fix/phone-call-controls
:fix/a11y-axe-findings
:fix/copy-and-reddit-context
:feat/about-build-info
:fix/schedule-24h
:fix/connecting-strip
:fix/ui-polish-batch
:fix/outbox-multi-tab
:fix/widget-share-hardening
:fix/side-panel-width
:fix/topic-markdown
:fix/acl-ip-literals-default
:feat/decorations-host
:fix/call-disconnected-bar
:fix/linux-update-verify
:perf/lazy-settings
:fix/dnd-busy-presence
:fix/threads-stay-unread
:fix/private-note-wording
:fix/audio-output-frame-ids
:fix/pip-minimise
:fix/translate-unavailable-copy
:fix/status-expiry-account-data
:ci/reseed-bundle-budget
:fix/close-no-tray
:fix/soundboard-not-permitted
:fix/denoise-state-notice
:docs/features-catchup
:fix/desktop-settings-section
:fix/dev-denoise-theme
:fix/pwa-manifest
:fix/translate-feedback
:fix/consent-retry-snooze
:fix/strip-metadata-packs
:fix/preview-deceptive-links
:fix/embed-ogurl-provider
:fix/settingtile-nesting
:fix/shortcuts-dialog
:fix/forward-encryption-warning
:fix/compress-alpha-anim
:fix/screenshare-double-toast
:fix/sw-reply-checks
:fix/pip-default-position
:fix/inapp-toast-permission
:fix/mute-timers-account-data
:fix/policy-dedupe
:fix/nudge-dismissed-strip
:fix/kuma-plain-text
:fix/rejoin-dm
:fix/search-edit-dupes
:fix/room-filter-empty
:fix/emoji-board-escape
:fix/call-failed-retry
:fix/share-links-lotus
:fix/poll-vote-local-echo
:fix/scheduled-from-server
:fix/delayed-restart-dedupe
:fix/decline-references-notification
:fix/stall-watchdog
:fix/filtered-timeline-double-count
:fix/call-listener-limit
:fix/voice-room-no-room-ping
:fix/reactions-collapse-loop
:fix/group-call-permission
:fix/dialog-enter-closes
:fix/delivery-status-live
:fix/room-upgrade-lotus-state
:fix/quiet-hours-tick
:fix/logout-wipe-leftovers
:fix/inter-font-name
:fix/retention-floor-grace
:fix/firefox-persist-hang
:fix/phantom-ring-after-reload
:fix/local-room-names-rest
:fix/missed-call-voice-rooms
:fix/animated-bg-compositor
:fix/link-safety-bypasses
:fix/e2e-register-403
:fix/local-room-names-everywhere
:fix/collapsible-messages
:fix/logout-volume-residue
:fix/enter-newline-device-local
:fix/dnd-restore-status
:fix/presence-sticky
:fix/location-confirm
:fix/reminders-stick
:fix/voice-full-distinct-users
:fix/presence-pagehide-status
:fix/gif-card-aspect
:deps/npm-audit-fixes
:security-nudge
:linux-package-updates
:audit-brace-expansion
:server-status-banner
:desktop-keychain-mirror
:desktop-call-origin
:clock-skew-lag
:offline-outbox
:desktop-lotus-links
:poll-ui
:calls-open-in-browser
:screenshare-prompt
:call-origin-split
:update-packages
:sw-fix
:read-me-update
:image-path-changes
:dm-calls
:fix-2469
:renovate/element-hq-element-call-embedded-0.x
:renovate/npm-i18next-http-backend-vulnerability
:renovate/npm-vite-vulnerability
:dev
:docs-update
:more-theme
:fix-257
:imporve-thread-reply
:revert-2402-improve-menu-congestion
:mxidColor-toggle
:update-sw-main-msg
No Reviewers
Labels
Clear labels
a11y
area: appearance
area: auth-session
area: build-ci
area: calls
area: desktop
area: media
area: messaging
area: mobile
area: moderation
area: navigation
area: notifications
area: settings
area: threads
bug
dependencies
docs
duplicate
enhancement
help wanted
invalid
needs-human-review
performance
planning
priority: critical
priority: high
priority: low
priority: medium
qa
question
research
security
tech-debt
ux
wontfix
Accessibility: keyboard, screen reader, contrast, motion
Client area: appearance
Client area: auth-session
Client area: build-ci
Client area: calls
Client area: desktop
Client area: media
Client area: messaging
Client area: mobile
Client area: moderation
Client area: navigation
Client area: notifications
Client area: settings
Client area: threads
Something is not working
Third-party package versions and advisories
README / LOTUS_* docs wrong or missing
This issue or pull request already exists
New feature
Need some help
Something is wrong
Re-render storms, leaks, heavy work on hot paths
Data loss, security hole, or crash on a main path
Broken feature or serious usability problem
Minor issue or polish
Wrong behaviour in an edge case or notable degradation
Manual QA: shipped, needs a human in a real environment
More information is needed
XSS, unsafe URLs, data leaks, auth/session
Code health, dead code, fragile patterns
Usability or visual inconsistency
This won't be fixed
No labels
Milestone
No items
No Milestone
Projects
Clear projects
No projects
No Assignees
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: LotusGuild/cinny#489
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Client half of #202: notifications in the web app while no Lotus tab is open.
Safe to merge on its own. Nothing registers until
config.jsongets awebPushentry for the homeserver, so today it only adds an unusedpushlistener. The server half (a Sygnal push gateway) is planned on #202 and needs approval before anything is deployed.Flow
Synapse sends an HTTP pusher request to the gateway (Sygnal, webpush kind). Sygnal signs it with VAPID and sends it through the browser's push service (FCM / Mozilla / Apple / WNS), encrypted to this browser's subscription. The service worker's
pushhandler then shows the notification.Changes
src/sw.tspushhandler:unread;/direct/or/home/;getPendingClick), so it lands in the right room instead of the home page. This also applies to the existing in-app OS notifications.src/swPush.ts: a pure function from the payload to a notification, using Sygnal webpush's flattened fields. It follows the in-app OS notification rules:room/room:threadtag, so a push and the page's own notification replace each other instead of stacking;src/app/hooks/useWebPush.ts, plus pure helpers inutils/webPush.ts:pushkeyis the p256dh key,datahas{url, endpoint, auth, events_only: true, default_payload: {user_id}}, andappend: true;useClientConfig):webPush: { "<server name>": { gatewayUrl, appId, vapidPublicKey } }. It's per homeserver likestatusPages, so accounts on other homeservers never register. Malformed entries are ignored, and the gateway URL must be https.Tests
swPush.test.ts: 11 tests:webPush.test.ts: 7 tests:/pushers/setbody;swReply,swShare,settingsandsettingsSync: 43/43. prettier and eslint are clean. Localtscshows only the 5 errors from stale local deps, none in these files; CI typechecks with the lockfile.🤖 Generated with Claude Code
https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA
Background notifications while no Lotus tab is open. Inert until config.json lists a push gateway for the account's homeserver (`webPush: { "<server>": { gatewayUrl, appId, vapidPublicKey } }`). - sw.ts: `push` handler. Shows the notification unless a Lotus tab is focused (the in-app toast covers that), silently during pause / quiet hours (prefs mirrored from the page into Cache Storage), updates the app badge. Clicks forward the room so the page can tell DMs apart; a click with no tab open is held until the new window asks for it. - swPush.ts: pure payload → notification (Sygnal webpush fields). Same conventions as the in-app OS notifications: logo icon, room / room:thread tag, invites to the invites page, calls with their own tag, never any text from encrypted rooms, Reply only where the worker can send it. - useWebPush: subscribes this browser with the gateway's VAPID key and registers an HTTP pusher (pushkey = p256dh, endpoint + auth in data, events_only, our user_id in default_payload); removes it again when turned off. Never in the desktop app. - Settings → Notifications → "Notify when Lotus is closed" (web, only when a gateway is configured; device-local, on by default). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKAPull request closed