Files
suaveplan/openspec/archive/2026-05-25-enterprise-pwa/proposal.md
2026-05-27 23:29:53 +01:00

5.2 KiB

Proposal: Enterprise migration of @suaveplan/pwa

  • Status: PROPOSED
  • Package: @suaveplan/pwa
  • Tier: browser
  • Category / plugin: foundation / data
  • Source: upstream packages/browser/pwa (1.0.4)
  • Design: ./design.md
  • Spec delta: ./specs/pwa/spec.md

Summary

Migrate @suaveplan/pwa from ../suaveplan/packages/browser/pwa (1.0.4) to genesis at packages/foundation/data/pwa/ as version 0.1.0. The upstream package ships four managers (ServiceWorkerManager, SyncQueue, PushNotificationManager, InstallPromptManager) but relies heavily on vi.stubGlobal in tests (banned by CLAUDE rule 2), stores the sync queue in localStorage, has no Zod boundaries, no OTel, no typed errors, and no caching-strategy abstraction or manifest builder.

The genesis rewrite ships the full contract:

  • ServiceWorkerManager — registration, activation, update polling, skipWaiting, state-change listeners, injectable ServiceWorkerContainer seam.
  • SyncQueue — pluggable persistence (MemoryStore, IndexedDbStore, LocalStorageStore), Zod-validated entries, exponential-backoff retry, BackgroundSyncBridge for SyncManager.register() with tab-visibility fallback.
  • PushNotificationManager — permission + PushManager subscribe / unsubscribe, VAPID applicationServerKey decoding, convenience notification dispatch through the active registration.
  • InstallPromptManager — beforeinstallprompt capture, programmatic prompt(), appinstalled integration, dismiss persistence.
  • CachingStrategies — cacheFirst, networkFirst, staleWhileRevalidate, networkOnly, cacheOnly route-handlers + registerRoute(pattern, strategy) router suitable for use inside a SW global scope.
  • ManifestBuilder — fluent builder for the Web App Manifest (name, icons, shortcuts, related apps, share target, display, theme, orientation, scope) with Zod validation and toBlob() for inline registration.
  • UpdateController — coordinates skipWaiting + controllerchange reload across tabs via BroadcastChannel, exposes "update available" event.
  • VersionMigration — schema-versioned queue migration so older payloads in storage are upgraded on SyncQueue load.
  • PwaObservability — OTel counters + histograms covering SW install / activate / update, sync queue flush, push subscriptions, install-prompt acceptance.
  • PwaError + PWA_CODES — typed errors with metadata for HTTP status, severity, retryability, description.

Parity Checklist

Capability Upstream Migrated Notes
ServiceWorkerManager (register / unregister / checkForUpdate / skipWaiting / state / onStateChange) OK OK Plus injectable container seam, typed error on failure.
SyncQueue (enqueue / remove / getAll / size / clear / process) OK OK Pluggable store; default switched to IndexedDB; localStorage still available as a LocalStorageStore.
PushNotificationManager (isSupported / getPermission / requestPermission / subscribe / unsubscribe / getSubscription) OK OK Same surface; VAPID decoding extracted into a helper.
InstallPromptManager (listen / unlisten / prompt / dismiss / clearDismissed / state / onStateChange / reset) OK OK Plus persisted dismissal across sessions.
Constants (DEFAULT_*, SYNC_QUEUE_STORAGE_KEY, INSTALL_PROMPT_KEY) OK OK Preserved + extended (DEFAULT_RETRY_BACKOFF_FACTOR).
Subpath exports per module OK OK Expanded per new modules.
Caching strategies (cacheFirst, networkFirst, staleWhileRevalidate, …) none OK New.
Route router (registerRoute) none OK New.
Web App Manifest builder none OK New.
Update controller w/ cross-tab reload coordination none OK New.
Background-sync bridge (SyncManager.register()) none OK New, with visibility-change fallback.
Version migration on stored queue payloads none OK New, schema bump from v1 → vN.
Zod validation on SyncQueueEntry none OK New.
OTel counters + histograms none OK New.
PWA_CODES + PwaError none OK New 8-code registry.
vi.stubGlobal in tests yes none Replaced with happy-dom + in-memory seams.
// @ts-expect-error in tests 4 0 Removed; edge cases modelled as typed branches.

Impact

Affected dependents

No existing genesis package depends on @suaveplan/pwa today. Future consumers (the suaveplan webapp shell + service-worker bundle) will pick up the new subpath exports.

Risks / mitigations

  • IndexedDB on WSL2 + happy-dom — happy-dom ships fake-indexeddb-compatible IDB. We seam IDBFactory so unit tests run against a deterministic in-memory store injected by the test, and only the IDB-store-specific integration tests touch happy-dom's IDB.
  • PushManager / Notification absent in non-secure contexts — every entry point guards with feature detection and falls back to a typed PWA.PUSH_UNSUPPORTED error; the test seam supplies a real-shaped PushManager stand-in.
  • BroadcastChannel polyfill — happy-dom exposes a real BroadcastChannel, so the UpdateController cross-tab coordination is exercised in unit tests against the same primitive production uses.