Skip to content

feat(pwa): Web Push on @profullstack/notifications, key served at run time - #533

Merged
ralyodio merged 1 commit into
mainfrom
feat/notifications-pkg
Sep 24, 2026
Merged

ralyodio merged 1 commit into
mainfrom
feat/notifications-pkg

Conversation

@ralyodio

Copy link
Copy Markdown
Contributor

Moves app.moshcode.sh's Web Push off web-push and onto @profullstack/notifications@0.1.0.

Why: on pairux.com push broke silently because the VAPID public key was compiled into the client and was empty in production. Here the key was rendered into the dashboard's data-vapid; now the browser fetches it at run time and says why when push can't work.

Changes (apps/pwa only)

  • src/lib/deliver.mjs: sendPushToMany replaces webpush.sendNotification. The payload is the same, the key format is the same (no regeneration), 404/410 subscriptions are still deleted (onGone), and web-push's default 4-week TTL is kept.
  • GET /api/push/vapid-public-key: vapidPublicKeyResponse(...). Returns 200 { publicKey }, or 503 when the keys are missing.
  • public/push.js: now an ES module using @profullstack/notifications/client (served from node_modules at /vendor/notifications-client.js, like xterm). It fetches the key at subscribe time. When push can't work here, it shows the pushSupport() reason (HTTPS, iOS Home Screen, blocked) under the button.
  • /push/subscribe takes PushSubscription.toJSON(), validated by parseSubscription. The old flat shape still works. /push/unsubscribe also answers DELETE, which is what the package client sends.
  • Config: the existing VAPID_PUBLIC / VAPID_PRIVATE still work, and VAPID_PUBLIC_KEY / VAPID_PRIVATE_KEY are also accepted.
  • Both lockfiles were updated (pnpm for CI, package-lock kept in step).

Tests: new test/push-notifications.test.mjs covers:

  • serving the key endpoint
  • the key no longer appearing in the dashboard HTML
  • both subscription shapes, plus rejection of bad input
  • DELETE and POST unsubscribe
  • an encrypted VAPID send with the right headers and TTL
  • deleting subscriptions that return 404/410

Full suite: 3343 tests, 3339 pass, 0 fail, 4 skipped (baseline on main: 3338 tests, 3334 pass, 0 fail).

🤖 Generated with Claude Code

… time

- drop web-push; approvals are sent with sendPushToMany (same VAPID key
  format, no key regeneration), 404/410 subscriptions are still deleted,
  and web-push's 4-week TTL is kept
- GET /api/push/vapid-public-key serves the public key at run time (503
  when unset) instead of rendering it into the dashboard
- public/push.js runs on @profullstack/notifications/client (served from
  node_modules at /vendor/notifications-client.js): it fetches the key
  when subscribing and shows pushSupport()'s reason when push cannot work
- /push/subscribe takes PushSubscription.toJSON() (validated with
  parseSubscription) and still the old flat shape; /push/unsubscribe also
  answers DELETE
- VAPID_PUBLIC / VAPID_PRIVATE keep working; VAPID_PUBLIC_KEY /
  VAPID_PRIVATE_KEY are accepted too

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@socket-security

Copy link
Copy Markdown
Contributor

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Added@​profullstack/​notifications@​0.1.0751009388100

View full report

@github-actions

Copy link
Copy Markdown

ThreatCrush Security Scan

0 finding(s) in the 11 file(s) this pull request changes.

Nothing in the files this pull request changes.

101 pre-existing finding(s) elsewhere in the repository — **HIGH/CRITICAL**: 8 | **MEDIUM**: 82 | **LOW**: 11

Not introduced by this pull request. The full set is in the Security tab.

Severity Rule Location
HIGH js-ssrf-outbound-request apps/pwa/public/sw.js:45
HIGH tls-verification-disabled apps/pwa/src/lib/moshpit-gateway.mjs:299
HIGH sh-remote-script-execution install.sh:86
HIGH sh-remote-script-execution install.sh:90
HIGH sh-remote-script-execution install.sh:258
HIGH sh-remote-script-execution install.sh:269
HIGH sh-remote-script-execution install.sh:275
HIGH tls-verification-disabled src/dns.mjs:766
MEDIUM sql-template-interpolation apps/pwa/src/lib/moshpit-certs.mjs:44
MEDIUM sql-template-interpolation apps/pwa/src/lib/moshpit-certs.mjs:82
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:139
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:153
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:179
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:373
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:377
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:422
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:671
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:867
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:869
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:928

…and 81 more. Full results in the Security tab.

Snippets are redacted; ThreatCrush never prints matched credential material.

@ralyodio
ralyodio merged commit 2500d80 into main Sep 24, 2026
6 checks passed
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