# 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.